From 2ebf8756a4c1023e45e4bd98367f384836cb464a Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Mon, 2 Nov 2020 17:41:28 -0600 Subject: [PATCH] [RFC] add prettier to eslint (#8595) --- .eslintrc.js | 231 +++-- .prettierignore | 1 + .prettierrc.yml | 3 + .../account-import-strategies/index.js | 6 +- app/scripts/background.js | 91 +- app/scripts/contentscript.js | 75 +- app/scripts/controllers/alert.js | 31 +- app/scripts/controllers/app-state.js | 29 +- app/scripts/controllers/cached-balances.js | 16 +- app/scripts/controllers/detect-tokens.js | 47 +- app/scripts/controllers/ens/ens.js | 8 +- app/scripts/controllers/ens/index.js | 13 +- .../controllers/incoming-transactions.js | 119 ++- .../controllers/network/contract-addresses.js | 12 +- .../controllers/network/createInfuraClient.js | 4 +- .../network/createJsonRpcClient.js | 14 +- .../network/createMetamaskMiddleware.js | 7 +- app/scripts/controllers/network/enums.js | 36 +- .../controllers/network/middleware/pending.js | 4 +- app/scripts/controllers/network/network.js | 81 +- app/scripts/controllers/network/util.js | 32 +- app/scripts/controllers/onboarding.js | 9 +- app/scripts/controllers/permissions/enums.js | 5 +- app/scripts/controllers/permissions/index.js | 270 ++--- .../controllers/permissions/permissionsLog.js | 80 +- .../permissionsMethodMiddleware.js | 11 +- .../permissions/restrictedMethods.js | 17 +- app/scripts/controllers/preferences.js | 154 +-- app/scripts/controllers/swaps.js | 196 ++-- app/scripts/controllers/threebox.js | 64 +- app/scripts/controllers/token-rates.js | 34 +- app/scripts/controllers/transactions/index.js | 338 +++--- .../lib/tx-state-history-helpers.js | 14 +- .../controllers/transactions/lib/util.js | 21 +- .../transactions/pending-tx-tracker.js | 55 +- .../controllers/transactions/tx-gas-utils.js | 23 +- .../transactions/tx-state-manager.js | 102 +- app/scripts/first-time-state.js | 1 - app/scripts/lib/ComposableObservableStore.js | 11 +- app/scripts/lib/account-tracker.js | 60 +- app/scripts/lib/buy-eth-url.js | 8 +- app/scripts/lib/cleanErrorStack.js | 6 +- app/scripts/lib/createLoggerMiddleware.js | 8 +- app/scripts/lib/createOnboardingMiddleware.js | 11 +- app/scripts/lib/createOriginMiddleware.js | 8 +- app/scripts/lib/createStreamSink.js | 8 +- app/scripts/lib/createTabIdMiddleware.js | 8 +- app/scripts/lib/decrypt-message-manager.js | 78 +- .../lib/encryption-public-key-manager.js | 65 +- .../lib/ens-ipfs/contracts/registry.js | 109 +- .../lib/ens-ipfs/contracts/resolver.js | 236 ++++- app/scripts/lib/ens-ipfs/resolver.js | 30 +- app/scripts/lib/ens-ipfs/setup.js | 31 +- app/scripts/lib/extractEthjsErrorMessage.js | 8 +- app/scripts/lib/fetch-with-timeout.js | 2 +- app/scripts/lib/freezeGlobals.js | 12 +- .../lib/get-first-preferred-lang-code.js | 16 +- app/scripts/lib/getObjStructure.js | 4 +- app/scripts/lib/local-store.js | 13 +- app/scripts/lib/message-manager.js | 53 +- app/scripts/lib/migrator/index.js | 22 +- app/scripts/lib/network-store.js | 12 +- app/scripts/lib/nodeify.js | 2 +- app/scripts/lib/notification-manager.js | 20 +- app/scripts/lib/personal-message-manager.js | 73 +- app/scripts/lib/random-id.js | 2 +- .../createMethodMiddleware.js | 4 +- .../rpc-method-middleware/handlers/index.js | 4 +- .../handlers/log-web3-usage.js | 5 +- app/scripts/lib/seed-phrase-verifier.js | 13 +- app/scripts/lib/setupFetchDebugging.js | 15 +- app/scripts/lib/setupSentry.js | 38 +- app/scripts/lib/setupWeb3.js | 19 +- app/scripts/lib/stream-utils.js | 17 +- app/scripts/lib/typed-message-manager.js | 110 +- app/scripts/lib/util.js | 29 +- app/scripts/metamask-controller.js | 976 ++++++++++++------ app/scripts/migrations/002.js | 5 +- app/scripts/migrations/003.js | 2 +- app/scripts/migrations/004.js | 2 +- app/scripts/migrations/005.js | 4 +- app/scripts/migrations/006.js | 4 +- app/scripts/migrations/007.js | 4 +- app/scripts/migrations/008.js | 4 +- app/scripts/migrations/009.js | 4 +- app/scripts/migrations/010.js | 4 +- app/scripts/migrations/011.js | 4 +- app/scripts/migrations/012.js | 4 +- app/scripts/migrations/013.js | 4 +- app/scripts/migrations/014.js | 4 +- app/scripts/migrations/015.js | 4 +- app/scripts/migrations/016.js | 8 +- app/scripts/migrations/017.js | 4 +- app/scripts/migrations/018.js | 14 +- app/scripts/migrations/019.js | 72 +- app/scripts/migrations/020.js | 8 +- app/scripts/migrations/021.js | 5 +- app/scripts/migrations/022.js | 7 +- app/scripts/migrations/023.js | 15 +- app/scripts/migrations/024.js | 27 +- app/scripts/migrations/025.js | 20 +- app/scripts/migrations/026.js | 21 +- app/scripts/migrations/027.js | 8 +- app/scripts/migrations/028.js | 13 +- app/scripts/migrations/029.js | 16 +- app/scripts/migrations/030.js | 19 +- app/scripts/migrations/031.js | 10 +- app/scripts/migrations/032.js | 4 +- app/scripts/migrations/033.js | 4 +- app/scripts/migrations/034.js | 9 +- app/scripts/migrations/035.js | 9 +- app/scripts/migrations/036.js | 4 +- app/scripts/migrations/037.js | 8 +- app/scripts/migrations/038.js | 4 +- app/scripts/migrations/039.js | 11 +- app/scripts/migrations/040.js | 4 +- app/scripts/migrations/041.js | 7 +- app/scripts/migrations/042.js | 4 +- app/scripts/migrations/043.js | 4 +- app/scripts/migrations/044.js | 9 +- app/scripts/migrations/045.js | 9 +- app/scripts/migrations/046.js | 4 +- app/scripts/migrations/047.js | 4 +- app/scripts/migrations/048.js | 49 +- app/scripts/migrations/fail-tx.js | 6 +- app/scripts/migrations/template.js | 4 +- app/scripts/phishing-detect.js | 37 +- app/scripts/platforms/extension.js | 69 +- app/scripts/ui.js | 36 +- babel.config.js | 5 +- development/announcer.js | 5 +- development/build/display.js | 30 +- development/build/etc.js | 26 +- development/build/index.js | 35 +- development/build/manifest.js | 90 +- development/build/scripts.js | 266 +++-- development/build/static.js | 74 +- development/build/styles.js | 74 +- development/build/task.js | 51 +- development/metamaskbot-build-announce.js | 77 +- development/mock-3box.js | 23 +- development/sentry-publish.js | 42 +- development/show-deps-install-scripts.js | 4 +- development/sourcemap-validator.js | 55 +- development/static-server.js | 23 +- development/verify-locale-strings.js | 75 +- package.json | 1 + shared/modules/metametrics.js | 28 +- test/e2e/address-book.spec.js | 145 ++- test/e2e/benchmark.js | 65 +- test/e2e/ethereum-on.spec.js | 66 +- test/e2e/fixture-server.js | 14 +- test/e2e/from-import-ui.spec.js | 189 +++- test/e2e/ganache.js | 7 +- test/e2e/helpers.js | 16 +- test/e2e/incremental-security.spec.js | 97 +- test/e2e/metamask-responsive-ui.spec.js | 120 ++- test/e2e/metamask-ui.spec.js | 899 ++++++++++++---- test/e2e/mock-3box/server.js | 5 +- test/e2e/permissions.spec.js | 94 +- test/e2e/send-edit.spec.js | 88 +- test/e2e/signature-request.spec.js | 71 +- test/e2e/tests/localization.spec.js | 7 +- test/e2e/tests/personal-sign.spec.js | 23 +- test/e2e/tests/simple-send.spec.js | 23 +- test/e2e/threebox.spec.js | 139 ++- test/e2e/webdriver/chrome.js | 20 +- test/e2e/webdriver/driver.js | 108 +- test/e2e/webdriver/firefox.js | 29 +- test/e2e/webdriver/index.js | 28 +- test/lib/createTxMeta.js | 2 +- test/lib/mock-encryptor.js | 16 +- test/lib/render-helpers.js | 10 +- test/lib/wait-until-called.js | 2 +- test/stub/provider.js | 50 +- test/unit-global/frozenPromise.js | 1 - test/unit/actions/set_account_label_test.js | 6 +- test/unit/actions/tx_test.js | 13 +- test/unit/actions/warning_test.js | 6 +- .../app/account-import-strategies.spec.js | 35 +- test/unit/app/buy-eth-url.spec.js | 7 +- test/unit/app/cleanErrorStack.spec.js | 7 +- .../app/controllers/cached-balances-test.js | 41 +- .../app/controllers/detect-tokens-test.js | 98 +- .../app/controllers/ens-controller-test.js | 7 +- .../controllers/incoming-transactions-test.js | 834 ++++++++++----- .../controllers/metamask-controller-test.js | 415 +++++--- .../network/network-controller-test.js | 40 +- .../network/pending-middleware-test.js | 93 +- test/unit/app/controllers/network/stubs.js | 265 ++--- .../app/controllers/permissions/helpers.js | 59 +- .../unit/app/controllers/permissions/mocks.js | 66 +- .../permissions-controller-test.js | 602 ++++++----- .../permissions-log-controller-test.js | 205 ++-- .../permissions-middleware-test.js | 405 ++++---- .../permissions/restricted-methods-test.js | 91 +- .../preferences-controller-test.js | 364 ++++--- test/unit/app/controllers/swaps-test.js | 284 ++--- .../transactions/pending-tx-tracker-test.js | 336 ++++-- .../transactions/tx-controller-test.js | 600 ++++++++--- .../transactions/tx-gas-util-test.js | 26 +- .../tx-state-history-helpers-test.js | 75 +- .../transactions/tx-state-manager-test.js | 458 ++++++-- .../controllers/transactions/tx-utils-test.js | 87 +- test/unit/app/fetch-with-timeout.test.js | 4 +- test/unit/app/message-manager-test.js | 55 +- test/unit/app/nodeify-test.js | 8 +- .../unit/app/personal-message-manager-test.js | 55 +- test/unit/app/seed-phrase-verifier-test.js | 23 +- test/unit/app/typed-message-manager.spec.js | 69 +- test/unit/app/util-test.js | 91 +- test/unit/localhostState.js | 1 - test/unit/migrations/021-test.js | 6 +- test/unit/migrations/022-test.js | 28 +- test/unit/migrations/023-test.js | 67 +- test/unit/migrations/024-test.js | 44 +- test/unit/migrations/025-test.js | 38 +- test/unit/migrations/026-test.js | 30 +- test/unit/migrations/027-test.js | 33 +- test/unit/migrations/028-test.js | 72 +- test/unit/migrations/029-test.js | 31 +- test/unit/migrations/030-test.js | 37 +- test/unit/migrations/031-test.js | 54 +- test/unit/migrations/033-test.js | 15 +- test/unit/migrations/034-test.js | 80 +- test/unit/migrations/035-test.js | 14 +- test/unit/migrations/036-test.js | 74 +- test/unit/migrations/037-test.js | 39 +- test/unit/migrations/038-test.js | 36 +- test/unit/migrations/039-test.js | 362 +++---- test/unit/migrations/040-test.js | 30 +- test/unit/migrations/041-test.js | 21 +- test/unit/migrations/042-test.js | 18 +- test/unit/migrations/043-test.js | 9 +- test/unit/migrations/044-test.js | 8 +- test/unit/migrations/045-test.js | 20 +- test/unit/migrations/046-test.js | 8 +- test/unit/migrations/047-test.js | 8 +- test/unit/migrations/048-test.js | 69 +- test/unit/migrations/migrations-test.js | 237 ++++- test/unit/migrations/migrator-test.js | 27 +- test/unit/migrations/template-test.js | 6 +- .../responsive/components/dropdown-test.js | 5 +- test/unit/ui/app/actions.spec.js | 378 ++++--- test/unit/ui/app/reducers/app.spec.js | 10 +- test/unit/ui/app/reducers/metamask.spec.js | 287 +++-- .../ui/etherscan-prefix-for-network.spec.js | 2 - .../account-list-item/account-list-item.js | 9 +- .../tests/account-list-item-component.test.js | 90 +- .../account-menu/account-menu.component.js | 157 ++- .../account-menu/account-menu.container.js | 8 +- .../account-menu/tests/account-menu.test.js | 29 +- .../add-token-button.component.js | 2 +- ui/app/components/app/alerts/alerts.js | 16 +- .../invalid-custom-network-alert.js | 47 +- .../tests/unconnected-account-alert.test.js | 25 +- .../unconnected-account-alert.js | 27 +- .../app/app-header/app-header.component.js | 95 +- .../app/app-header/tests/app-header.test.js | 14 +- .../app/asset-list-item/asset-list-item.js | 60 +- .../components/app/asset-list/asset-list.js | 23 +- .../confirm-detail-row.component.js | 91 +- .../confirm-detail-row.component.test.js | 44 +- ...onfirm-page-container-content.component.js | 76 +- ...onfirm-page-container-summary.component.js | 48 +- ...onfirm-page-container-warning.component.js | 2 +- ...confirm-page-container-header.component.js | 65 +- ...irm-page-container-navigation.component.js | 23 +- .../confirm-page-container.component.js | 126 ++- .../connected-accounts-list-item.component.js | 27 +- ...nnected-accounts-list-options.component.js | 39 +- .../connected-accounts-list.component.js | 70 +- ...onnected-accounts-permissions.component.js | 37 +- .../connected-sites-list.component.js | 32 +- .../connected-status-indicator.component.js | 37 +- .../connected-status-indicator.container.js | 4 +- .../contact-list/contact-list.component.js | 39 +- .../recipient-group.component.js | 69 +- .../app/dropdowns/components/dropdown.js | 16 +- .../components/network-dropdown-icon.js | 54 +- .../app/dropdowns/network-dropdown.js | 206 ++-- .../app/dropdowns/simple-dropdown.js | 17 +- .../app/dropdowns/tests/dropdown.test.js | 4 +- .../tests/network-dropdown-icon.test.js | 6 +- .../dropdowns/tests/network-dropdown.test.js | 48 +- .../advanced-gas-inputs.component.js | 101 +- .../advanced-gas-inputs.container.js | 14 +- .../advanced-gas-input-component.test.js | 24 +- .../advanced-tab-content.component.js | 55 +- .../advanced-tab-content-component.test.js | 70 +- .../basic-tab-content.component.js | 33 +- .../tests/basic-tab-content-component.test.js | 38 +- .../gas-modal-page-container.component.js | 125 ++- .../gas-modal-page-container.container.js | 123 ++- ...gas-modal-page-container-component.test.js | 104 +- ...gas-modal-page-container-container.test.js | 111 +- .../gas-price-button-group.component.js | 107 +- .../gas-price-button-group-component.test.js | 194 ++-- .../gas-price-chart.component.js | 30 +- .../gas-price-chart/gas-price-chart.utils.js | 189 +++- .../tests/gas-price-chart.component.test.js | 99 +- .../gas-slider/gas-slider.component.js | 12 +- .../home-notification.component.js | 105 +- .../app/info-box/info-box.component.js | 23 +- .../app/info-box/tests/info-box.test.js | 1 - .../loading-network-screen.component.js | 38 +- .../loading-network-screen.container.js | 20 +- .../app/menu-bar/account-options-menu.js | 96 +- ui/app/components/app/menu-bar/menu-bar.js | 36 +- .../app/menu-bar/tests/menu-bar.test.js | 4 +- ui/app/components/app/menu-droppo.js | 54 +- .../modal-content/modal-content.component.js | 20 +- .../tests/modal-content.component.test.js | 27 +- .../components/app/modal/modal.component.js | 71 +- .../app/modal/tests/modal.component.test.js | 5 +- .../account-details-modal.component.js | 34 +- .../account-details-modal.container.js | 6 +- .../account-modal-container.component.js | 16 +- .../account-modal-container.container.js | 9 +- .../add-to-addressbook-modal.component.js | 8 +- .../add-to-addressbook-modal.container.js | 12 +- .../cancel-transaction-gas-fee.component.js | 2 +- ...ncel-transaction-gas-fee.component.test.js | 16 +- .../cancel-transaction.component.js | 8 +- .../cancel-transaction.container.js | 15 +- .../cancel-transaction.component.test.js | 28 +- .../confirm-delete-network.component.js | 11 +- .../tests/confirm-delete-network.test.js | 20 +- .../confirm-remove-account.component.js | 26 +- .../tests/confirm-remove-account.test.js | 11 +- .../confirm-reset-account.component.js | 5 +- .../tests/confirm-reset-account.test.js | 14 +- .../deposit-ether-modal.component.js | 25 +- .../deposit-ether-modal.container.js | 11 +- .../edit-approval-permission.component.js | 69 +- .../export-private-key-modal.component.js | 97 +- .../export-private-key-modal.container.js | 31 +- ui/app/components/app/modals/fade-modal.js | 60 +- .../hide-token-confirmation-modal.js | 18 +- .../loading-network-error.component.js | 9 +- .../metametrics-opt-in-modal.component.js | 72 +- .../metametrics-opt-in-modal.container.js | 3 +- .../tests/metametrics-opt-in-modal.test.js | 17 +- ui/app/components/app/modals/modal.js | 16 +- .../new-account-modal.component.js | 15 +- .../new-account-modal.container.js | 38 +- .../modals/qr-scanner/qr-scanner.component.js | 71 +- .../reject-transactions.component.js | 4 +- .../tests/reject-transactions.test.js | 19 +- .../tests/account-details-modal.test.js | 19 +- .../tests/transaction-confirmed.test.js | 3 +- .../transaction-confirmed.component.js | 11 +- .../multiple-notifications.component.js | 6 +- .../network-display.component.js | 65 +- ui/app/components/app/network.js | 84 +- ...ission-page-container-content.component.js | 80 +- .../permission-page-container.component.js | 32 +- .../permission-page-container.container.js | 4 +- .../permissions-connect-footer.component.js | 12 +- .../permissions-connect-header.component.js | 16 +- .../selected-account.component.js | 19 +- .../tests/selected-account-component.test.js | 17 +- .../app/sidebars/sidebar.component.js | 23 +- .../sidebars/tests/sidebars-component.test.js | 17 +- .../signature-request-original.component.js | 169 ++- .../signature-request-original.container.js | 11 +- .../signature-request-footer.component.js | 10 +- .../signature-request-header.component.js | 8 +- .../signature-request-message.component.js | 31 +- .../signature-request.component.js | 40 +- .../signature-request.container.js | 21 +- .../tests/signature-request.test.js | 6 +- ui/app/components/app/tab-bar/tab-bar.js | 4 +- .../app/tests/signature-request.test.js | 11 +- .../components/app/token-cell/token-cell.js | 35 +- .../app/token-cell/token-cell.test.js | 2 +- .../components/app/token-list/token-list.js | 2 +- ...transaction-activity-log.component.test.js | 61 +- ...transaction-activity-log.container.test.js | 5 +- .../transaction-activity-log.util.test.js | 219 ++-- ...transaction-activity-log-icon.component.js | 12 +- .../transaction-activity-log.component.js | 112 +- .../transaction-activity-log.container.js | 24 +- .../transaction-activity-log.util.js | 46 +- .../transaction-breakdown.component.test.js | 5 +- ...ransaction-breakdown-row.component.test.js | 27 +- .../transaction-breakdown-row.component.js | 10 +- .../transaction-breakdown.component.js | 126 ++- .../transaction-breakdown.container.js | 16 +- .../app/transaction-icon/transaction-icon.js | 3 +- ...transaction-list-item-details.component.js | 133 +-- ...transaction-list-item-details.container.js | 14 +- .../transaction-list-item.component.js | 117 ++- .../transaction-list.component.js | 188 ++-- .../transaction-status.component.test.js | 33 +- .../transaction-status.component.js | 16 +- ...erenced-currency-display.component.test.js | 14 +- ...-preferenced-currency-display.component.js | 26 +- ...eferenced-currency-input.component.test.js | 8 +- ...er-preferenced-currency-input.component.js | 2 +- .../user-preferenced-token-input.component.js | 2 +- .../user-preferenced-token-input.container.js | 4 +- .../app/wallet-overview/eth-overview.js | 85 +- .../app/wallet-overview/token-overview.js | 85 +- .../app/wallet-overview/wallet-overview.js | 8 +- .../account-mismatch-warning.component.js | 6 +- .../alert-circle-icon.component.js | 6 +- .../alert-circle-icon.stories.js | 12 +- ui/app/components/ui/alert/index.js | 12 +- .../components/ui/alert/tests/alert.test.js | 4 +- .../ui/breadcrumbs/breadcrumbs.component.js | 14 +- .../tests/breadcrumbs.component.test.js | 22 +- .../ui/button-group/button-group.component.js | 68 +- .../ui/button-group/button-group.stories.js | 46 +- .../tests/button-group-component.test.js | 18 +- .../components/ui/button/button.component.js | 15 +- ui/app/components/ui/button/button.stories.js | 1 - ui/app/components/ui/card/card.component.js | 10 +- .../ui/card/tests/card.component.test.js | 5 +- .../ui/check-box/check-box.component.js | 19 +- .../ui/check-box/check-box.stories.js | 6 +- ui/app/components/ui/check-box/index.js | 7 +- .../ui/circle-icon/circle-icon.component.js | 9 +- .../currency-display.component.js | 21 +- .../tests/currency-display.component.test.js | 12 +- .../currency-input.component.js | 66 +- .../currency-input.container.js | 6 +- .../tests/currency-input.component.test.js | 49 +- .../tests/currency-input.container.test.js | 28 +- ui/app/components/ui/dialog/index.js | 4 +- ui/app/components/ui/dropdown/dropdown.js | 29 +- .../ui/dropdown/dropdown.stories.js | 53 +- .../ui/editable-label/editable-label.js | 49 +- .../error-message/error-message.component.js | 9 +- .../tests/error-message.component.test.js | 28 +- .../export-text-container.component.js | 2 +- .../hex-to-decimal.component.js | 8 +- .../tests/hex-to-decimal.component.test.js | 18 +- .../components/ui/icon-border/icon-border.js | 4 +- .../components/ui/icon-button/icon-button.js | 18 +- .../icon-with-fallback.component.js | 33 +- .../ui/icon-with-label/icon-with-label.js | 2 +- .../ui/icon/approve-icon.component.js | 6 +- .../components/ui/icon/copy-icon.component.js | 6 +- ui/app/components/ui/icon/icon.stories.js | 31 +- .../components/ui/icon/info-icon.component.js | 10 +- .../ui/icon/interaction-icon.component.js | 6 +- .../ui/icon/overview-buy-icon.component.js | 20 +- .../ui/icon/overview-send-icon.component.js | 10 +- .../components/ui/icon/paper-airplane-icon.js | 3 +- .../preloader/preloader-icon.component.js | 5 +- .../ui/icon/receive-icon.component.js | 15 +- .../components/ui/icon/send-icon.component.js | 15 +- .../components/ui/icon/sign-icon.component.js | 31 +- .../ui/icon/sun-check-icon.component.js | 10 +- .../ui/icon/swap-icon-for-list.component.js | 27 +- .../components/ui/icon/swap-icon.component.js | 10 +- .../blockieIdenticon.component.js | 11 +- .../ui/identicon/identicon.component.js | 45 +- .../ui/identicon/identicon.container.js | 4 +- .../ui/identicon/identicon.stories.js | 12 +- .../tests/identicon.component.test.js | 31 +- .../ui/info-tooltip/info-tooltip.js | 7 +- .../ui/info-tooltip/info-tooltip.stories.js | 20 +- .../ui/jazzicon/jazzicon.component.js | 18 +- ui/app/components/ui/list-item/index.js | 1 - .../ui/list-item/list-item.component.js | 46 +- .../ui/list-item/list-item.stories.js | 54 +- .../ui/list-item/tests/list-item.test.js | 20 +- .../loading-screen.component.js | 14 +- .../ui/lock-icon/lock-icon.component.js | 2 +- .../components/ui/mascot/mascot.component.js | 54 +- ui/app/components/ui/mascot/mascot.stories.js | 26 +- ui/app/components/ui/menu/menu-item.js | 27 +- ui/app/components/ui/menu/menu.js | 20 +- ui/app/components/ui/menu/menu.stories.js | 28 +- .../ui/metafox-logo/metafox-logo.component.js | 12 +- .../tests/metafox-logo.component.test.js | 29 +- .../page-container-content.component.js | 10 +- .../page-container-footer.component.js | 24 +- .../page-container-footer.component.test.js | 34 +- .../page-container-header.component.js | 104 +- .../page-container-header.component.test.js | 13 +- .../page-container.component.js | 39 +- .../ui/popover/popover.component.js | 67 +- .../components/ui/popover/popover.stories.js | 33 +- .../ui/pulse-loader/pulse-loader.js | 2 +- .../ui/pulse-loader/pulse-loader.stories.js | 2 +- ui/app/components/ui/qr-code/qr-code.js | 46 +- .../ui/readonly-input/readonly-input.js | 2 +- .../ui/search-icon/search-icon.component.js | 9 +- .../sender-to-recipient.component.js | 137 ++- ui/app/components/ui/site-icon/site-icon.js | 2 +- .../ui/snackbar/snackbar.component.js | 6 +- .../ui/spinner/spinner.component.js | 107 +- .../components/ui/tabs/tab/tab.component.js | 14 +- ui/app/components/ui/tabs/tabs.component.js | 55 +- ui/app/components/ui/tabs/tabs.stories.js | 29 +- .../ui/text-field/text-field.component.js | 29 +- .../ui/text-field/text-field.stories.js | 45 +- .../ui/token-balance/token-balance.js | 2 +- .../token-currency-display.component.js | 7 +- .../tests/token-input.component.test.js | 30 +- .../ui/token-input/token-input.component.js | 63 +- .../ui/token-input/token-input.container.js | 6 +- ui/app/components/ui/tooltip/tooltip.js | 19 +- .../tests/unit-input.component.test.js | 42 +- .../ui/unit-input/unit-input.component.js | 35 +- ui/app/components/ui/url-icon/url-icon.js | 7 +- ui/app/contexts/i18n.js | 18 +- ui/app/contexts/metametrics.js | 121 ++- ui/app/contexts/metametrics.new.js | 91 +- ui/app/ducks/alerts/invalid-custom-network.js | 5 +- ui/app/ducks/alerts/unconnected-account.js | 5 +- ui/app/ducks/app/app.js | 10 +- .../confirm-transaction.duck.js | 147 ++- .../confirm-transaction.duck.test.js | 108 +- ui/app/ducks/gas/gas-duck.test.js | 513 +++++---- ui/app/ducks/gas/gas.duck.js | 313 +++--- ui/app/ducks/history/history.js | 3 +- ui/app/ducks/locale/locale.js | 2 +- ui/app/ducks/metamask/metamask.js | 15 +- ui/app/ducks/send/send-duck.test.js | 10 +- ui/app/ducks/send/send.duck.js | 14 +- ui/app/ducks/swaps/swaps.js | 265 +++-- ui/app/helpers/constants/connected-sites.js | 3 +- ui/app/helpers/constants/routes.js | 15 +- ui/app/helpers/constants/swaps.js | 6 +- .../authenticated/authenticated.component.js | 4 +- .../authenticated/authenticated.container.js | 4 +- .../feature-toggled-route.js | 3 +- .../initialized/initialized.component.js | 10 +- .../initialized/initialized.container.js | 4 +- .../tests/with-modal-props.test.js | 9 +- .../with-modal-props/with-modal-props.js | 2 +- ui/app/helpers/utils/common.util.js | 6 +- ui/app/helpers/utils/confirm-tx.util.js | 55 +- ui/app/helpers/utils/confirm-tx.util.test.js | 70 +- ui/app/helpers/utils/conversion-util.js | 161 ++- ui/app/helpers/utils/conversion-util.test.js | 150 ++- ui/app/helpers/utils/conversions.util.js | 59 +- ui/app/helpers/utils/fetch-with-cache.js | 19 +- ui/app/helpers/utils/fetch-with-cache.test.js | 40 +- ui/app/helpers/utils/formatters.js | 2 +- .../helpers/utils/gas-time-estimates.util.js | 70 +- ui/app/helpers/utils/i18n-helper.js | 48 +- ui/app/helpers/utils/i18n-helper.test.js | 102 +- ui/app/helpers/utils/switch-direction.js | 3 +- ui/app/helpers/utils/token-util.js | 63 +- ui/app/helpers/utils/transactions.util.js | 59 +- .../helpers/utils/transactions.util.test.js | 9 +- ui/app/helpers/utils/util.js | 176 ++-- ui/app/helpers/utils/util.test.js | 36 +- .../hooks/tests/useCancelTransaction.test.js | 38 +- ui/app/hooks/tests/useCurrencyDisplay.test.js | 6 +- .../hooks/tests/useRetryTransaction.test.js | 13 +- ui/app/hooks/tests/useTokenData.test.js | 33 +- .../hooks/tests/useTokenDisplayValue.test.js | 4 +- .../tests/useTransactionDisplayData.test.js | 85 +- .../tests/useUserPreferencedCurrency.test.js | 19 +- ui/app/hooks/useCancelTransaction.js | 44 +- ui/app/hooks/useCopyToClipboard.js | 2 +- ui/app/hooks/useCurrencyDisplay.js | 31 +- ui/app/hooks/useCurrentAsset.js | 13 +- ui/app/hooks/useEqualityCheck.js | 2 +- ui/app/hooks/useEthFiatAmount.js | 24 +- ui/app/hooks/useI18nContext.js | 2 +- ui/app/hooks/useMethodData.js | 11 +- ui/app/hooks/useMetricEvent.js | 41 +- ui/app/hooks/usePrevious.js | 2 +- ui/app/hooks/useRetryTransaction.js | 45 +- ui/app/hooks/useShouldShowSpeedUp.js | 2 +- ui/app/hooks/useSwappedTokenValue.js | 48 +- ui/app/hooks/useSwapsEthToken.js | 7 +- ui/app/hooks/useTimeout.js | 2 +- ui/app/hooks/useTokenData.js | 2 +- ui/app/hooks/useTokenDisplayValue.js | 23 +- ui/app/hooks/useTokenFiatAmount.js | 34 +- ui/app/hooks/useTokenTracker.js | 40 +- ui/app/hooks/useTokensToSearch.js | 114 +- ui/app/hooks/useTransactionDisplayData.js | 71 +- ui/app/hooks/useTransactionTimeRemaining.js | 37 +- ui/app/hooks/useUserPreferencedCurrency.js | 25 +- ui/app/pages/add-token/add-token.component.js | 59 +- ui/app/pages/add-token/add-token.container.js | 4 +- .../pages/add-token/tests/add-token.test.js | 30 +- .../token-list-placeholder.component.js | 6 +- .../token-list/token-list.component.js | 87 +- .../token-search/token-search.component.js | 11 +- ui/app/pages/asset/asset.js | 6 +- .../asset/components/asset-breadcrumb.js | 15 +- .../asset/components/asset-navigation.js | 8 +- ui/app/pages/asset/components/native-asset.js | 6 +- ui/app/pages/asset/components/token-asset.js | 19 +- .../pages/asset/components/token-options.js | 59 +- .../confirm-add-suggested-token.component.js | 119 ++- .../confirm-add-suggested-token.container.js | 7 +- .../confirm-add-token.component.js | 98 +- .../confirm-add-token.container.js | 4 +- .../confirm-approve-content.component.js | 171 +-- .../pages/confirm-approve/confirm-approve.js | 83 +- .../confirm-approve/confirm-approve.util.js | 22 +- .../confirm-decrypt-message.component.js | 150 ++- .../confirm-decrypt-message.container.js | 12 +- .../confirm-deploy-contract.component.js | 31 +- ...confirm-encryption-public-key.component.js | 57 +- ...confirm-encryption-public-key.container.js | 8 +- .../confirm-send-ether.component.js | 10 +- .../confirm-send-ether.container.js | 34 +- .../confirm-send-token.component.js | 8 +- .../confirm-send-token.container.js | 43 +- ...onfirm-token-transaction-base.component.js | 49 +- ...onfirm-token-transaction-base.container.js | 35 +- .../confirm-transaction-base.component.js | 365 ++++--- .../confirm-transaction-base.container.js | 113 +- ...confirm-transaction-base.component.test.js | 5 +- .../confirm-transaction-switch.component.js | 8 +- .../confirm-transaction-switch.container.js | 8 +- ui/app/pages/confirm-transaction/conf-tx.js | 85 +- .../confirm-transaction.component.js | 129 +-- .../confirm-transaction.container.js | 25 +- .../connected-accounts.component.js | 21 +- .../connected-accounts.container.js | 24 +- .../connected-sites.component.js | 85 +- .../connected-sites.container.js | 26 +- .../connect-hardware/account-list.js | 310 +++--- .../create-account/connect-hardware/index.js | 95 +- .../connect-hardware/select-hardware.js | 84 +- .../create-account.component.js | 41 +- .../create-account/import-account/index.js | 14 +- .../create-account/import-account/json.js | 34 +- .../import-account/private-key.js | 31 +- .../create-account/new-account.component.js | 6 +- .../create-account/new-account.container.js | 20 +- .../tests/create-account.test.js | 4 +- ui/app/pages/error/error.component.js | 48 +- .../create-password.component.js | 11 +- .../create-password.container.js | 4 +- .../import-with-seed-phrase.component.js | 117 ++- .../import-with-seed-phrase.container.js | 3 +- .../import-with-seed-phrase.component.test.js | 2 +- .../new-account/new-account.component.js | 49 +- .../unique-image/unique-image.component.js | 20 +- .../end-of-flow/end-of-flow.component.js | 45 +- .../end-of-flow/end-of-flow.container.js | 6 +- .../end-of-flow/tests/end-of-flow.test.js | 4 +- .../first-time-flow-switch.component.js | 2 +- .../tests/first-time-flow-switch.test.js | 36 +- .../first-time-flow.component.js | 32 +- .../first-time-flow.container.js | 20 +- .../metametrics-opt-in.component.js | 140 ++- .../metametrics-opt-in.container.js | 8 +- .../tests/metametrics-opt-in.test.js | 7 +- .../onboarding-initiator-util.js | 38 +- .../confirm-seed-phrase.component.js | 119 ++- .../confirm-seed-phrase.container.js | 3 +- .../draggable-seed.component.js | 61 +- .../reveal-seed-phrase.component.js | 106 +- .../reveal-seed-phrase.container.js | 3 +- .../tests/reveal-seed-phrase.test.js | 15 +- .../seed-phrase/seed-phrase.component.js | 25 +- .../confirm-seed-phrase-component.test.js | 36 +- .../select-action/select-action.component.js | 24 +- .../select-action/tests/select-action.test.js | 12 +- .../welcome/tests/welcome.test.js | 27 +- .../welcome/welcome.component.js | 21 +- ui/app/pages/home/home.component.js | 143 ++- ui/app/pages/home/home.container.js | 39 +- ui/app/pages/index.js | 16 +- ui/app/pages/keychains/restore-vault.js | 63 +- ui/app/pages/keychains/reveal-seed.js | 77 +- .../pages/keychains/tests/reveal-seed.test.js | 10 +- ui/app/pages/lock/lock.component.js | 4 +- ui/app/pages/lock/lock.container.js | 4 +- ui/app/pages/lock/tests/lock.test.js | 12 +- .../mobile-sync/mobile-sync.component.js | 163 ++- .../mobile-sync/mobile-sync.container.js | 17 +- .../choose-account.component.js | 174 ++-- .../permissions-connect.component.js | 161 +-- .../permissions-connect.container.js | 37 +- .../permissions-redirect.component.js | 30 +- ui/app/pages/routes/routes.component.js | 156 ++- ui/app/pages/routes/routes.container.js | 12 +- .../add-recipient/add-recipient.component.js | 71 +- .../add-recipient/add-recipient.container.js | 8 +- .../add-recipient/add-recipient.js | 20 +- .../add-recipient/ens-input.component.js | 88 +- .../add-recipient/ens-input.container.js | 20 +- .../tests/add-recipient-component.test.js | 75 +- .../tests/add-recipient-container.test.js | 11 +- .../tests/add-recipient-utils.test.js | 57 +- .../amount-max-button.component.js | 18 +- .../amount-max-button.container.js | 14 +- .../amount-max-button.utils.js | 23 +- .../tests/amount-max-button-component.test.js | 37 +- .../tests/amount-max-button-container.test.js | 26 +- .../tests/amount-max-button-utils.test.js | 34 +- .../send-amount-row.component.js | 46 +- .../send-amount-row.container.js | 13 +- .../tests/send-amount-row-component.test.js | 102 +- .../tests/send-amount-row-container.test.js | 34 +- .../send-asset-row.component.js | 105 +- .../send-asset-row.container.js | 4 +- .../send-content/send-content.component.js | 32 +- .../send-content/send-content.container.js | 32 +- .../gas-fee-display.component.js | 52 +- .../tests/gas-fee-display.component.test.js | 20 +- .../send-gas-row/send-gas-row.component.js | 40 +- .../send-gas-row/send-gas-row.container.js | 28 +- .../tests/send-gas-row-component.test.js | 36 +- .../tests/send-gas-row-container.test.js | 47 +- .../send-hex-data-row.component.js | 4 +- .../send-hex-data-row.container.js | 10 +- .../send-row-error-message.component.js | 18 +- .../send-row-error-message.container.js | 2 +- .../send-row-error-message-component.test.js | 11 +- .../send-row-error-message-container.test.js | 15 +- .../send-row-wrapper.component.js | 51 +- .../tests/send-row-wrapper-component.test.js | 77 +- .../tests/send-content-component.test.js | 115 ++- .../send/send-footer/send-footer.component.js | 76 +- .../send/send-footer/send-footer.container.js | 12 +- .../send/send-footer/send-footer.utils.js | 50 +- .../tests/send-footer-component.test.js | 96 +- .../tests/send-footer-container.test.js | 115 ++- .../tests/send-footer-utils.test.js | 26 +- .../send/send-header/send-header.component.js | 6 +- .../send/send-header/send-header.container.js | 4 +- .../tests/send-header-component.test.js | 17 +- ui/app/pages/send/send.component.js | 70 +- ui/app/pages/send/send.constants.js | 28 +- ui/app/pages/send/send.container.js | 54 +- ui/app/pages/send/send.utils.js | 139 ++- .../pages/send/tests/send-component.test.js | 104 +- .../pages/send/tests/send-container.test.js | 46 +- ui/app/pages/send/tests/send-utils.test.js | 272 +++-- .../advanced-tab/advanced-tab.component.js | 182 ++-- .../advanced-tab/advanced-tab.container.js | 23 +- .../pages/settings/alerts-tab/alerts-tab.js | 22 +- .../add-contact/add-contact.component.js | 40 +- .../add-contact/add-contact.container.js | 11 +- .../contact-list-tab.component.js | 49 +- .../contact-list-tab.container.js | 22 +- .../edit-contact/edit-contact.component.js | 57 +- .../edit-contact/edit-contact.container.js | 34 +- .../my-accounts/my-accounts.component.js | 11 +- .../my-accounts/my-accounts.container.js | 5 +- .../view-contact/view-contact.component.js | 15 +- .../view-contact/view-contact.container.js | 24 +- .../settings/info-tab/info-tab.component.js | 35 +- .../network-form/network-form.component.js | 128 ++- .../networks-tab/networks-tab.component.js | 185 ++-- .../networks-tab/networks-tab.constants.js | 4 +- .../networks-tab/networks-tab.container.js | 63 +- .../security-tab/security-tab.component.js | 45 +- .../security-tab/security-tab.container.js | 15 +- .../security-tab/tests/security-tab.test.js | 12 +- .../settings-tab/settings-tab.component.js | 50 +- .../settings-tab/settings-tab.container.js | 8 +- .../settings-tab/tests/settings-tab.test.js | 10 +- ui/app/pages/settings/settings.component.js | 182 ++-- ui/app/pages/settings/settings.container.js | 14 +- .../actionable-message/actionable-message.js | 16 +- .../actionable-message.stories.js | 20 +- .../swaps/awaiting-swap/awaiting-swap.js | 99 +- .../awaiting-swap/quotes-timeout-icon.js | 15 +- .../swaps/awaiting-swap/swap-failure-icon.js | 15 +- .../swaps/awaiting-swap/swap-success-icon.js | 15 +- .../view-on-ether-scan-link.js | 6 +- ui/app/pages/swaps/build-quote/build-quote.js | 250 +++-- .../swaps/build-quote/build-quote.stories.js | 148 ++- .../swaps/countdown-timer/countdown-timer.js | 41 +- .../countdown-timer.stories.js | 30 +- .../dropdown-input-pair.js | 61 +- .../dropdown-input-pair.stories.js | 134 ++- .../dropdown-search-list.js | 90 +- .../dropdown-search-list.stories.js | 129 ++- .../exchange-rate-display.js | 70 +- ui/app/pages/swaps/fee-card/fee-card.js | 49 +- .../pages/swaps/fee-card/fee-card.stories.js | 25 +- ui/app/pages/swaps/index.js | 233 +++-- ui/app/pages/swaps/intro-popup/intro-popup.js | 38 +- .../loading-swaps-quotes/aggregator-logo.js | 13 +- .../background-animation.js | 188 +++- .../loading-swaps-quotes-stories-metadata.js | 42 +- .../loading-swaps-quotes.js | 127 ++- .../main-quote-summary/main-quote-summary.js | 47 +- .../main-quote-summary.stories.js | 9 +- .../main-quote-summary/quote-backdrop.js | 77 +- .../item-list/item-list.component.js | 172 +-- .../list-item-search.component.js | 16 +- .../searchable-item-list.js | 17 +- .../select-quote-popover/mock-quote-data.js | 2 +- .../quote-details/quote-details.js | 32 +- .../select-quote-popover.js | 46 +- .../sort-list/sort-list.js | 90 +- .../slippage-buttons/slippage-buttons.js | 106 +- .../slippage-buttons.stories.js | 4 +- .../pages/swaps/swaps-footer/swaps-footer.js | 15 +- .../pages/swaps/swaps-util-test-constants.js | 238 +++-- ui/app/pages/swaps/swaps.util.js | 256 +++-- ui/app/pages/swaps/swaps.util.test.js | 69 +- ui/app/pages/swaps/view-quote/view-quote.js | 290 +++--- .../unlock-page/tests/unlock-page.test.js | 13 +- .../unlock-page/unlock-page.component.js | 37 +- .../unlock-page/unlock-page.container.js | 21 +- ui/app/selectors/confirm-transaction.js | 110 +- ui/app/selectors/custom-gas.js | 208 ++-- ui/app/selectors/first-time-flow.js | 2 +- ui/app/selectors/permissions.js | 147 ++- ui/app/selectors/selectors.js | 204 ++-- ui/app/selectors/send.js | 72 +- .../tests/confirm-transaction.test.js | 15 +- ui/app/selectors/tests/custom-gas.test.js | 18 +- ui/app/selectors/tests/permissions.test.js | 369 ++++--- ui/app/selectors/tests/selectors.test.js | 57 +- .../tests/send-selectors-test-data.js | 301 +++--- ui/app/selectors/tests/send.test.js | 374 +++---- ui/app/selectors/tests/transactions.test.js | 37 +- ui/app/selectors/transactions.js | 131 ++- ui/app/store/actionConstants.js | 6 +- ui/app/store/actions.js | 831 ++++++++------- ui/app/store/store.js | 12 +- ui/index.js | 74 +- ui/lib/account-link.js | 7 +- ui/lib/etherscan-prefix-for-network.js | 5 +- ui/lib/icon-factory.js | 19 +- ui/lib/is-mobile-view.js | 3 +- ui/lib/local-storage-helpers.js | 4 +- ui/lib/shallow-with-context.js | 2 +- ui/lib/test-timeout.js | 2 +- ui/lib/tx-helper.js | 34 +- ui/lib/webcam-utils.js | 16 +- yarn.lock | 19 + 834 files changed, 26946 insertions(+), 17377 deletions(-) create mode 100644 .prettierrc.yml diff --git a/.eslintrc.js b/.eslintrc.js index 68392f022..35541a9ba 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,19 +2,19 @@ module.exports = { root: true, parser: '@babel/eslint-parser', parserOptions: { - 'sourceType': 'module', - 'ecmaVersion': 2017, - 'ecmaFeatures': { - 'experimentalObjectRestSpread': true, - 'impliedStrict': true, - 'modules': true, - 'blockBindings': true, - 'arrowFunctions': true, - 'objectLiteralShorthandMethods': true, - 'objectLiteralShorthandProperties': true, - 'templateStrings': true, - 'classes': true, - 'jsx': true, + sourceType: 'module', + ecmaVersion: 2017, + ecmaFeatures: { + experimentalObjectRestSpread: true, + impliedStrict: true, + modules: true, + blockBindings: true, + arrowFunctions: true, + objectLiteralShorthandMethods: true, + objectLiteralShorthandProperties: true, + templateStrings: true, + classes: true, + jsx: true, }, }, @@ -28,6 +28,9 @@ module.exports = { 'coverage/', 'app/scripts/chromereload.js', 'app/vendor/**', + 'test/e2e/send-eth-with-private-key-test/**', + 'nyc_output/**', + '.vscode/**', ], extends: [ @@ -38,11 +41,7 @@ module.exports = { 'plugin:react-hooks/recommended', ], - plugins: [ - '@babel', - 'react', - 'import', - ], + plugins: ['@babel', 'react', 'import', 'prettier'], globals: { document: 'readonly', @@ -50,6 +49,67 @@ module.exports = { }, rules: { + // Prettier changes and reasoning + + 'prettier/prettier': 'error', + + // Our usage of spaces before *named* function parens is unusual, and + // doesn't match the prettier spec. prettier does not offer an option + // to configure this + 'space-before-function-paren': [ + 'error', + { anonymous: 'always', named: 'never' }, + ], + // Our eslint config has the default setting for this as error. This + // include beforeBlockComment: true, but in order to match the prettier + // spec you have to enable before and after blocks, objects and arrays + // https://github.com/prettier/eslint-config-prettier#lines-around-comment + 'lines-around-comment': [ + 'error', + { + beforeBlockComment: true, + afterLineComment: false, + allowBlockStart: true, + allowBlockEnd: true, + allowObjectStart: true, + allowObjectEnd: true, + allowArrayStart: true, + allowArrayEnd: true, + }, + ], + // Prettier has some opinions on mixed-operators, and there is ongoing work + // to make the output code clear. It is better today then it was when the first + // PR to add prettier. That being said, the workaround for keeping this rule enabled + // requires breaking parts of operations into different variables -- which I believe + // to be worse. https://github.com/prettier/eslint-config-prettier#no-mixed-operators + 'no-mixed-operators': 'off', + // Prettier wraps single line functions with ternaries, etc in parens by default, but + // if the line is long enough it breaks it into a separate line and removes the parens. + // The second behavior conflicts with this rule. There is some guides on the repo about + // how you can keep it enabled: + // https://github.com/prettier/eslint-config-prettier#no-confusing-arrow + // However, in practice this conflicts with prettier adding parens around short lines, + // when autofixing in vscode and others. + 'no-confusing-arrow': 'off', + // There is no configuration in prettier for how it stylizes regexes, which conflicts + // with wrap-regex. + 'wrap-regex': 'off', + // Prettier handles all indentation automagically. it can be configured here + // https://prettier.io/docs/en/options.html#tab-width but the default matches our + // style. + indent: 'off', + // This rule conflicts with the way that prettier breaks code across multiple lines when + // it exceeds the maximum length. Prettier optimizes for readability while simultaneously + // maximizing the amount of code per line. + 'function-paren-newline': 'off', + // This rule throws an error when there is a line break in an arrow function declaration + // but prettier breaks arrow function declarations to be as readable as possible while + // still conforming to the width rules. + 'implicit-arrow-linebreak': 'off', + // This rule would result in an increase in white space in lines with generator functions, + // which impacts prettier's goal of maximizing code per line and readability. There is no + // current workaround. + 'generator-star-spacing': 'off', 'default-param-last': 'off', 'require-atomic-updates': 'off', 'import/no-unassigned-import': 'off', @@ -57,29 +117,32 @@ module.exports = { 'react/no-unused-prop-types': 'error', 'react/no-unused-state': 'error', 'react/jsx-boolean-value': 'error', - 'react/jsx-curly-brace-presence': ['error', { 'props': 'never', 'children': 'never' }], + 'react/jsx-curly-brace-presence': [ + 'error', + { props: 'never', children: 'never' }, + ], 'react/jsx-equals-spacing': 'error', 'react/no-deprecated': 'error', 'react/default-props-match-prop-types': 'error', - 'react/jsx-closing-tag-location': 'error', + 'react/jsx-closing-tag-location': [ + 'error', + { selfClosing: 'tag-aligned', nonEmpty: 'tag-aligned' }, + ], 'react/jsx-no-duplicate-props': 'error', 'react/jsx-closing-bracket-location': 'error', 'react/jsx-first-prop-new-line': ['error', 'multiline'], - 'react/jsx-max-props-per-line': ['error', { 'maximum': 1, 'when': 'multiline' }], - 'react/jsx-tag-spacing': ['error', { - 'closingSlash': 'never', - 'beforeSelfClosing': 'always', - 'afterOpening': 'never', - }], - 'react/jsx-wrap-multilines': ['error', { - 'declaration': 'parens-new-line', - 'assignment': 'parens-new-line', - 'return': 'parens-new-line', - 'arrow': 'parens-new-line', - 'condition': 'parens-new-line', - 'logical': 'parens-new-line', - 'prop': 'parens-new-line', - }], + 'react/jsx-max-props-per-line': [ + 'error', + { maximum: 1, when: 'multiline' }, + ], + 'react/jsx-tag-spacing': [ + 'error', + { + closingSlash: 'never', + beforeSelfClosing: 'always', + afterOpening: 'never', + }, + ], 'no-invalid-this': 'off', '@babel/no-invalid-this': 'error', @@ -93,67 +156,59 @@ module.exports = { 'node/no-unpublished-import': 'off', 'node/no-unpublished-require': 'off', }, - - overrides: [{ - files: [ - 'test/e2e/**/*.js', - ], - rules: { - 'mocha/no-hooks-for-single-case': 'off', + overrides: [ + { + files: ['test/e2e/**/*.js'], + rules: { + 'mocha/no-hooks-for-single-case': 'off', + }, }, - }, { - files: [ - 'app/scripts/migrations/*.js', - '*.stories.js', - ], - rules: { - 'import/no-anonymous-default-export': ['error', { 'allowObject': true }], + { + files: ['app/scripts/migrations/*.js', '*.stories.js'], + rules: { + 'import/no-anonymous-default-export': ['error', { allowObject: true }], + }, }, - }, { - files: [ - 'app/scripts/migrations/*.js', - ], - rules: { - 'node/global-require': 'off', + { + files: ['app/scripts/migrations/*.js'], + rules: { + 'node/global-require': 'off', + }, }, - }, { - files: [ - 'test/**/*-test.js', - 'test/**/*.spec.js', - ], - rules: { - // Mocha will re-assign `this` in a test context - '@babel/no-invalid-this': 'off', + { + files: ['test/**/*-test.js', 'test/**/*.spec.js'], + rules: { + // Mocha will re-assign `this` in a test context + '@babel/no-invalid-this': 'off', + }, }, - }, { - files: [ - 'development/**/*.js', - 'test/e2e/benchmark.js', - 'test/helper.js', - ], - rules: { - 'node/no-process-exit': 'off', - 'node/shebang': 'off', + { + files: ['development/**/*.js', 'test/e2e/benchmark.js', 'test/helper.js'], + rules: { + 'node/no-process-exit': 'off', + 'node/shebang': 'off', + }, }, - }, { - files: [ - '.eslintrc.js', - 'babel.config.js', - 'nyc.config.js', - 'stylelint.config.js', - 'development/**/*.js', - 'test/e2e/**/*.js', - 'test/env.js', - 'test/setup.js', - ], - parserOptions: { - sourceType: 'script', + { + files: [ + '.eslintrc.js', + 'babel.config.js', + 'nyc.config.js', + 'stylelint.config.js', + 'development/**/*.js', + 'test/e2e/**/*.js', + 'test/env.js', + 'test/setup.js', + ], + parserOptions: { + sourceType: 'script', + }, }, - }], + ], settings: { - 'react': { - 'version': 'detect', + react: { + version: 'detect', }, }, } diff --git a/.prettierignore b/.prettierignore index c2dd4a632..5428362b5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,3 +6,4 @@ coverage/ app/vendor/** .nyc_output/** .vscode/** +test/e2e/send-eth-with-private-key-test/** diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 000000000..0d65e758a --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,3 @@ +singleQuote: true +semi: false +trailingComma: all diff --git a/app/scripts/account-import-strategies/index.js b/app/scripts/account-import-strategies/index.js index 9a7bc2f8e..743cc59ba 100644 --- a/app/scripts/account-import-strategies/index.js +++ b/app/scripts/account-import-strategies/index.js @@ -4,8 +4,7 @@ import importers from 'ethereumjs-wallet/thirdparty' import ethUtil from 'ethereumjs-util' const accountImporter = { - - importAccount (strategy, args) { + importAccount(strategy, args) { try { const importer = this.strategies[strategy] const privateKeyHex = importer(...args) @@ -43,10 +42,9 @@ const accountImporter = { return walletToPrivateKey(wallet) }, }, - } -function walletToPrivateKey (wallet) { +function walletToPrivateKey(wallet) { const privateKeyBuffer = wallet.getPrivateKey() return ethUtil.bufferToHex(privateKeyBuffer) } diff --git a/app/scripts/background.js b/app/scripts/background.js index 32aaec4af..035400019 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -60,9 +60,7 @@ const requestAccountTabIds = {} // state persistence const inTest = process.env.IN_TEST === 'true' -const localStore = inTest - ? new ReadOnlyNetworkStore() - : new LocalStore() +const localStore = inTest ? new ReadOnlyNetworkStore() : new LocalStore() let versionedData if (inTest || process.env.METAMASK_DEBUG) { @@ -143,7 +141,7 @@ initialize().catch(log.error) * Initializes the MetaMask controller, and sets up all platform configuration. * @returns {Promise} - Setup complete. */ -async function initialize () { +async function initialize() { const initState = await loadStateFromPersistence() const initLangCode = await getFirstPreferredLangCode() await setupController(initState, initLangCode) @@ -159,15 +157,15 @@ async function initialize () { * Migrates that data schema in case it was last loaded on an older version. * @returns {Promise} - Last data emitted from previous instance of MetaMask. */ -async function loadStateFromPersistence () { +async function loadStateFromPersistence() { // migrations const migrator = new Migrator({ migrations }) migrator.on('error', console.warn) // read from disk // first from preferred, async API: - versionedData = (await localStore.get()) || - migrator.generateInitialState(firstTimeState) + versionedData = + (await localStore.get()) || migrator.generateInitialState(firstTimeState) // check if somehow state is empty // this should never happen but new error reporting suggests that it has @@ -219,7 +217,7 @@ async function loadStateFromPersistence () { * @param {string} initLangCode - The region code for the language preferred by the current user. * @returns {Promise} - After setup is complete. */ -function setupController (initState, initLangCode) { +function setupController(initState, initLangCode) { // // MetaMask Controller // @@ -249,7 +247,9 @@ function setupController (initState, initLangCode) { setupEnsIpfsResolver({ getCurrentNetwork: controller.getCurrentNetwork, - getIpfsGateway: controller.preferencesController.getIpfsGateway.bind(controller.preferencesController), + getIpfsGateway: controller.preferencesController.getIpfsGateway.bind( + controller.preferencesController, + ), provider: controller.provider, }) @@ -269,12 +269,12 @@ function setupController (initState, initLangCode) { * @param {Object} state - The state object as emitted by the MetaMaskController. * @returns {VersionedData} - The state object wrapped in an object that includes a metadata key. */ - function versionifyData (state) { + function versionifyData(state) { versionedData.data = state return versionedData } - async function persistData (state) { + async function persistData(state) { if (!state) { throw new Error('MetaMask - updated state is missing') } @@ -303,12 +303,14 @@ function setupController (initState, initLangCode) { [ENVIRONMENT_TYPE_FULLSCREEN]: true, } - const metamaskBlockedPorts = [ - 'trezor-connect', - ] + const metamaskBlockedPorts = ['trezor-connect'] const isClientOpenStatus = () => { - return popupIsOpen || Boolean(Object.keys(openMetamaskTabsIDs).length) || notificationIsOpen + return ( + popupIsOpen || + Boolean(Object.keys(openMetamaskTabsIDs).length) || + notificationIsOpen + ) } /** @@ -323,7 +325,7 @@ function setupController (initState, initLangCode) { * This method identifies trusted (MetaMask) interfaces, and connects them differently from untrusted (web pages). * @param {Port} remotePort - The port provided by a new context. */ - function connectRemote (remotePort) { + function connectRemote(remotePort) { const processName = remotePort.name const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName] @@ -381,7 +383,7 @@ function setupController (initState, initLangCode) { } // communication with page or other extension - function connectExternal (remotePort) { + function connectExternal(remotePort) { const portStream = new PortStream(remotePort) controller.setupUntrustedCommunication(portStream, remotePort.sender) } @@ -404,18 +406,30 @@ function setupController (initState, initLangCode) { * Updates the Web Extension's "badge" number, on the little fox in the toolbar. * The number reflects the current number of pending transactions or message signatures needing user approval. */ - function updateBadge () { + function updateBadge() { let label = '' const unapprovedTxCount = controller.txController.getUnapprovedTxCount() const { unapprovedMsgCount } = controller.messageManager const { unapprovedPersonalMsgCount } = controller.personalMessageManager const { unapprovedDecryptMsgCount } = controller.decryptMessageManager - const { unapprovedEncryptionPublicKeyMsgCount } = controller.encryptionPublicKeyManager + const { + unapprovedEncryptionPublicKeyMsgCount, + } = controller.encryptionPublicKeyManager const { unapprovedTypedMessagesCount } = controller.typedMessageManager - const pendingPermissionRequests = Object.keys(controller.permissionsController.permissions.state.permissionsRequests).length - const waitingForUnlockCount = controller.appStateController.waitingForUnlock.length - const count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgCount + unapprovedDecryptMsgCount + unapprovedEncryptionPublicKeyMsgCount + - unapprovedTypedMessagesCount + pendingPermissionRequests + waitingForUnlockCount + const pendingPermissionRequests = Object.keys( + controller.permissionsController.permissions.state.permissionsRequests, + ).length + const waitingForUnlockCount = + controller.appStateController.waitingForUnlock.length + const count = + unapprovedTxCount + + unapprovedMsgCount + + unapprovedPersonalMsgCount + + unapprovedDecryptMsgCount + + unapprovedEncryptionPublicKeyMsgCount + + unapprovedTypedMessagesCount + + pendingPermissionRequests + + waitingForUnlockCount if (count) { label = String(count) } @@ -433,9 +447,11 @@ function setupController (initState, initLangCode) { /** * Opens the browser popup for user confirmation */ -async function triggerUi () { +async function triggerUi() { const tabs = await platform.getActiveTabs() - const currentlyActiveMetamaskTab = Boolean(tabs.find((tab) => openMetamaskTabsIDs[tab.id])) + const currentlyActiveMetamaskTab = Boolean( + tabs.find((tab) => openMetamaskTabsIDs[tab.id]), + ) if (!popupIsOpen && !currentlyActiveMetamaskTab) { await notificationManager.showPopup() } @@ -445,23 +461,24 @@ async function triggerUi () { * Opens the browser popup for user confirmation of watchAsset * then it waits until user interact with the UI */ -async function openPopup () { +async function openPopup() { await triggerUi() - await new Promise( - (resolve) => { - const interval = setInterval(() => { - if (!notificationIsOpen) { - clearInterval(interval) - resolve() - } - }, 1000) - }, - ) + await new Promise((resolve) => { + const interval = setInterval(() => { + if (!notificationIsOpen) { + clearInterval(interval) + resolve() + } + }, 1000) + }) } // On first install, open a new tab with MetaMask extension.runtime.onInstalled.addListener(({ reason }) => { - if (reason === 'install' && !(process.env.METAMASK_DEBUG || process.env.IN_TEST)) { + if ( + reason === 'install' && + !(process.env.METAMASK_DEBUG || process.env.IN_TEST) + ) { platform.openExtensionInBrowser() } }) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index d85aca3f2..c7aa76cbb 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -9,7 +9,10 @@ import PortStream from 'extension-port-stream' const fs = require('fs') const path = require('path') -const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js'), 'utf8') +const inpageContent = fs.readFileSync( + path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js'), + 'utf8', +) const inpageSuffix = `//# sourceURL=${extension.runtime.getURL('inpage.js')}\n` const inpageBundle = inpageContent + inpageSuffix @@ -30,7 +33,7 @@ if (shouldInjectProvider()) { * * @param {string} content - Code to be executed in the current document */ -function injectScript (content) { +function injectScript(content) { try { const container = document.head || document.documentElement const scriptTag = document.createElement('script') @@ -47,7 +50,7 @@ function injectScript (content) { * Sets up the stream communication and submits site metadata * */ -async function start () { +async function start() { await setupStreams() await domIsReady() } @@ -57,7 +60,7 @@ async function start () { * browser extension and local per-page browser context. * */ -async function setupStreams () { +async function setupStreams() { // the transport-specific streams for communication between inpage and background const pageStream = new LocalMessageDuplexStream({ name: 'contentscript', @@ -73,17 +76,11 @@ async function setupStreams () { const extensionMux = new ObjectMultiplex() extensionMux.setMaxListeners(25) - pump( - pageMux, - pageStream, - pageMux, - (err) => logStreamDisconnectWarning('MetaMask Inpage Multiplex', err), + pump(pageMux, pageStream, pageMux, (err) => + logStreamDisconnectWarning('MetaMask Inpage Multiplex', err), ) - pump( - extensionMux, - extensionStream, - extensionMux, - (err) => logStreamDisconnectWarning('MetaMask Background Multiplex', err), + pump(extensionMux, extensionStream, extensionMux, (err) => + logStreamDisconnectWarning('MetaMask Background Multiplex', err), ) // forward communication across inpage-background for these channels only @@ -95,14 +92,14 @@ async function setupStreams () { phishingStream.once('data', redirectToPhishingWarning) } -function forwardTrafficBetweenMuxers (channelName, muxA, muxB) { +function forwardTrafficBetweenMuxers(channelName, muxA, muxB) { const channelA = muxA.createStream(channelName) const channelB = muxB.createStream(channelName) - pump( - channelA, - channelB, - channelA, - (err) => logStreamDisconnectWarning(`MetaMask muxed traffic for channel "${channelName}" failed.`, err), + pump(channelA, channelB, channelA, (err) => + logStreamDisconnectWarning( + `MetaMask muxed traffic for channel "${channelName}" failed.`, + err, + ), ) } @@ -112,7 +109,7 @@ function forwardTrafficBetweenMuxers (channelName, muxA, muxB) { * @param {string} remoteLabel - Remote stream name * @param {Error} err - Stream connection error */ -function logStreamDisconnectWarning (remoteLabel, err) { +function logStreamDisconnectWarning(remoteLabel, err) { let warningMsg = `MetamaskContentscript - lost connection to ${remoteLabel}` if (err) { warningMsg += `\n${err.stack}` @@ -125,9 +122,13 @@ function logStreamDisconnectWarning (remoteLabel, err) { * * @returns {boolean} {@code true} - if the provider should be injected */ -function shouldInjectProvider () { - return doctypeCheck() && suffixCheck() && - documentElementCheck() && !blockedDomainCheck() +function shouldInjectProvider() { + return ( + doctypeCheck() && + suffixCheck() && + documentElementCheck() && + !blockedDomainCheck() + ) } /** @@ -135,7 +136,7 @@ function shouldInjectProvider () { * * @returns {boolean} {@code true} - if the doctype is html or if none exists */ -function doctypeCheck () { +function doctypeCheck() { const { doctype } = window.document if (doctype) { return doctype.name === 'html' @@ -152,11 +153,8 @@ function doctypeCheck () { * * @returns {boolean} - whether or not the extension of the current document is prohibited */ -function suffixCheck () { - const prohibitedTypes = [ - /\.xml$/u, - /\.pdf$/u, - ] +function suffixCheck() { + const prohibitedTypes = [/\.xml$/u, /\.pdf$/u] const currentUrl = window.location.pathname for (let i = 0; i < prohibitedTypes.length; i++) { if (prohibitedTypes[i].test(currentUrl)) { @@ -171,7 +169,7 @@ function suffixCheck () { * * @returns {boolean} {@code true} - if the documentElement is an html node or if none exists */ -function documentElementCheck () { +function documentElementCheck() { const documentElement = document.documentElement.nodeName if (documentElement) { return documentElement.toLowerCase() === 'html' @@ -184,7 +182,7 @@ function documentElementCheck () { * * @returns {boolean} {@code true} - if the current domain is blocked */ -function blockedDomainCheck () { +function blockedDomainCheck() { const blockedDomains = [ 'uscourts.gov', 'dropbox.com', @@ -201,7 +199,10 @@ function blockedDomainCheck () { let currentRegex for (let i = 0; i < blockedDomains.length; i++) { const blockedDomain = blockedDomains[i].replace('.', '\\.') - currentRegex = new RegExp(`(?:https?:\\/\\/)(?:(?!${blockedDomain}).)*$`, 'u') + currentRegex = new RegExp( + `(?:https?:\\/\\/)(?:(?!${blockedDomain}).)*$`, + 'u', + ) if (!currentRegex.test(currentUrl)) { return true } @@ -212,7 +213,7 @@ function blockedDomainCheck () { /** * Redirects the current page to a phishing information page */ -function redirectToPhishingWarning () { +function redirectToPhishingWarning() { console.log('MetaMask - routing to Phishing Warning component') const extensionURL = extension.runtime.getURL('phishing.html') window.location.href = `${extensionURL}#${querystring.stringify({ @@ -224,11 +225,13 @@ function redirectToPhishingWarning () { /** * Returns a promise that resolves when the DOM is loaded (does not wait for images to load) */ -async function domIsReady () { +async function domIsReady() { // already loaded if (['interactive', 'complete'].includes(document.readyState)) { return undefined } // wait for load - return new Promise((resolve) => window.addEventListener('DOMContentLoaded', resolve, { once: true })) + return new Promise((resolve) => + window.addEventListener('DOMContentLoaded', resolve, { once: true }), + ) } diff --git a/app/scripts/controllers/alert.js b/app/scripts/controllers/alert.js index dd8dc66fe..a2dd3a7db 100644 --- a/app/scripts/controllers/alert.js +++ b/app/scripts/controllers/alert.js @@ -21,14 +21,13 @@ export const ALERT_TYPES = { } const defaultState = { - alertEnabledness: Object.keys(ALERT_TYPES) - .reduce( - (alertEnabledness, alertType) => { - alertEnabledness[alertType] = true - return alertEnabledness - }, - {}, - ), + alertEnabledness: Object.keys(ALERT_TYPES).reduce( + (alertEnabledness, alertType) => { + alertEnabledness[alertType] = true + return alertEnabledness + }, + {}, + ), unconnectedAccountAlertShownOrigins: {}, } @@ -37,12 +36,11 @@ const defaultState = { * alert related state */ export default class AlertController { - /** * @constructor * @param {AlertControllerOptions} [opts] - Controller configuration parameters */ - constructor (opts = {}) { + constructor(opts = {}) { const { initState, preferencesStore } = opts const state = { ...defaultState, @@ -56,14 +54,17 @@ export default class AlertController { preferencesStore.subscribe(({ selectedAddress }) => { const currentState = this.store.getState() - if (currentState.unconnectedAccountAlertShownOrigins && this.selectedAddress !== selectedAddress) { + if ( + currentState.unconnectedAccountAlertShownOrigins && + this.selectedAddress !== selectedAddress + ) { this.selectedAddress = selectedAddress this.store.updateState({ unconnectedAccountAlertShownOrigins: {} }) } }) } - setAlertEnabledness (alertId, enabledness) { + setAlertEnabledness(alertId, enabledness) { let { alertEnabledness } = this.store.getState() alertEnabledness = { ...alertEnabledness } alertEnabledness[alertId] = enabledness @@ -74,9 +75,11 @@ export default class AlertController { * Sets the "switch to connected" alert as shown for the given origin * @param {string} origin - The origin the alert has been shown for */ - setUnconnectedAccountAlertShown (origin) { + setUnconnectedAccountAlertShown(origin) { let { unconnectedAccountAlertShownOrigins } = this.store.getState() - unconnectedAccountAlertShownOrigins = { ...unconnectedAccountAlertShownOrigins } + unconnectedAccountAlertShownOrigins = { + ...unconnectedAccountAlertShownOrigins, + } unconnectedAccountAlertShownOrigins[origin] = true this.store.updateState({ unconnectedAccountAlertShownOrigins }) } diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index edfe1c5b6..cafe30609 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -2,12 +2,11 @@ import EventEmitter from 'events' import ObservableStore from 'obs-store' export default class AppStateController extends EventEmitter { - /** * @constructor * @param opts */ - constructor (opts = {}) { + constructor(opts = {}) { const { addUnlockListener, isUnlocked, @@ -23,7 +22,8 @@ export default class AppStateController extends EventEmitter { timeoutMinutes: 0, connectedStatusPopoverHasBeenShown: true, swapsWelcomeMessageHasBeenShown: false, - defaultHomeActiveTabName: null, ...initState, + defaultHomeActiveTabName: null, + ...initState, }) this.timer = null @@ -53,7 +53,7 @@ export default class AppStateController extends EventEmitter { * @returns {Promise} A promise that resolves when the extension is * unlocked, or immediately if the extension is already unlocked. */ - getUnlockPromise (shouldShowUnlockRequest) { + getUnlockPromise(shouldShowUnlockRequest) { return new Promise((resolve) => { if (this.isUnlocked()) { resolve() @@ -72,7 +72,7 @@ export default class AppStateController extends EventEmitter { * @param {boolean} shouldShowUnlockRequest - Whether the extension notification * popup should be opened. */ - waitForUnlock (resolve, shouldShowUnlockRequest) { + waitForUnlock(resolve, shouldShowUnlockRequest) { this.waitingForUnlock.push({ resolve }) this.emit('updateBadge') if (shouldShowUnlockRequest) { @@ -83,7 +83,7 @@ export default class AppStateController extends EventEmitter { /** * Drains the waitingForUnlock queue, resolving all the related Promises. */ - handleUnlock () { + handleUnlock() { if (this.waitingForUnlock.length > 0) { while (this.waitingForUnlock.length > 0) { this.waitingForUnlock.shift().resolve() @@ -96,7 +96,7 @@ export default class AppStateController extends EventEmitter { * Sets the default home tab * @param {string} [defaultHomeActiveTabName] - the tab name */ - setDefaultHomeActiveTabName (defaultHomeActiveTabName) { + setDefaultHomeActiveTabName(defaultHomeActiveTabName) { this.store.updateState({ defaultHomeActiveTabName, }) @@ -105,7 +105,7 @@ export default class AppStateController extends EventEmitter { /** * Record that the user has seen the connected status info popover */ - setConnectedStatusPopoverHasBeenShown () { + setConnectedStatusPopoverHasBeenShown() { this.store.updateState({ connectedStatusPopoverHasBeenShown: true, }) @@ -114,7 +114,7 @@ export default class AppStateController extends EventEmitter { /** * Record that the user has seen the swap screen welcome message */ - setSwapsWelcomeMessageHasBeenShown () { + setSwapsWelcomeMessageHasBeenShown() { this.store.updateState({ swapsWelcomeMessageHasBeenShown: true, }) @@ -124,7 +124,7 @@ export default class AppStateController extends EventEmitter { * Sets the last active time to the current time * @returns {void} */ - setLastActiveTime () { + setLastActiveTime() { this._resetTimer() } @@ -134,7 +134,7 @@ export default class AppStateController extends EventEmitter { * @returns {void} * @private */ - _setInactiveTimeout (timeoutMinutes) { + _setInactiveTimeout(timeoutMinutes) { this.store.updateState({ timeoutMinutes, }) @@ -151,7 +151,7 @@ export default class AppStateController extends EventEmitter { * @returns {void} * @private */ - _resetTimer () { + _resetTimer() { const { timeoutMinutes } = this.store.getState() if (this.timer) { @@ -162,6 +162,9 @@ export default class AppStateController extends EventEmitter { return } - this.timer = setTimeout(() => this.onInactiveTimeout(), timeoutMinutes * 60 * 1000) + this.timer = setTimeout( + () => this.onInactiveTimeout(), + timeoutMinutes * 60 * 1000, + ) } } diff --git a/app/scripts/controllers/cached-balances.js b/app/scripts/controllers/cached-balances.js index 87ca28662..084f54cf1 100644 --- a/app/scripts/controllers/cached-balances.js +++ b/app/scripts/controllers/cached-balances.js @@ -12,13 +12,12 @@ import ObservableStore from 'obs-store' * a cache of account balances in local storage */ export default class CachedBalancesController { - /** * Creates a new controller instance * * @param {CachedBalancesOptions} [opts] Controller configuration parameters */ - constructor (opts = {}) { + constructor(opts = {}) { const { accountTracker, getNetwork } = opts this.accountTracker = accountTracker @@ -37,15 +36,18 @@ export default class CachedBalancesController { * @param {Object} obj - The the recently updated accounts object for the current network * @returns {Promise} */ - async updateCachedBalances ({ accounts }) { + async updateCachedBalances({ accounts }) { const network = await this.getNetwork() - const balancesToCache = await this._generateBalancesToCache(accounts, network) + const balancesToCache = await this._generateBalancesToCache( + accounts, + network, + ) this.store.updateState({ cachedBalances: balancesToCache, }) } - _generateBalancesToCache (newAccounts, currentNetwork) { + _generateBalancesToCache(newAccounts, currentNetwork) { const { cachedBalances } = this.store.getState() const currentNetworkBalancesToCache = { ...cachedBalances[currentNetwork] } @@ -68,7 +70,7 @@ export default class CachedBalancesController { * Removes cachedBalances */ - clearCachedBalances () { + clearCachedBalances() { this.store.updateState({ cachedBalances: {} }) } @@ -80,7 +82,7 @@ export default class CachedBalancesController { * @private * */ - _registerUpdates () { + _registerUpdates() { const update = this.updateCachedBalances.bind(this) this.accountTracker.store.subscribe(update) } diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index 26e8cd081..6c1c213a6 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -6,20 +6,25 @@ import { MAINNET } from './network/enums' // By default, poll every 3 minutes const DEFAULT_INTERVAL = 180 * 1000 -const SINGLE_CALL_BALANCES_ADDRESS = '0xb1f8e55c7f64d203c1400b9d8555d050f94adf39' +const SINGLE_CALL_BALANCES_ADDRESS = + '0xb1f8e55c7f64d203c1400b9d8555d050f94adf39' /** * A controller that polls for token exchange * rates based on a user's current token list */ export default class DetectTokensController { - /** * Creates a DetectTokensController * * @param {Object} [config] - Options to configure controller */ - constructor ({ interval = DEFAULT_INTERVAL, preferences, network, keyringMemStore } = {}) { + constructor({ + interval = DEFAULT_INTERVAL, + preferences, + network, + keyringMemStore, + } = {}) { this.preferences = preferences this.interval = interval this.network = network @@ -29,7 +34,7 @@ export default class DetectTokensController { /** * For each token in eth-contract-metadata, find check selectedAddress balance. */ - async detectNewTokens () { + async detectNewTokens() { if (!this.isActive) { return } @@ -40,7 +45,10 @@ export default class DetectTokensController { const tokensToDetect = [] this.web3.setProvider(this._network._provider) for (const contractAddress in contracts) { - if (contracts[contractAddress].erc20 && !(this.tokenAddresses.includes(contractAddress.toLowerCase()))) { + if ( + contracts[contractAddress].erc20 && + !this.tokenAddresses.includes(contractAddress.toLowerCase()) + ) { tokensToDetect.push(contractAddress) } } @@ -49,20 +57,29 @@ export default class DetectTokensController { try { result = await this._getTokenBalances(tokensToDetect) } catch (error) { - warn(`MetaMask - DetectTokensController single call balance fetch failed`, error) + warn( + `MetaMask - DetectTokensController single call balance fetch failed`, + error, + ) return } tokensToDetect.forEach((tokenAddress, index) => { const balance = result[index] if (balance && !balance.isZero()) { - this._preferences.addToken(tokenAddress, contracts[tokenAddress].symbol, contracts[tokenAddress].decimals) + this._preferences.addToken( + tokenAddress, + contracts[tokenAddress].symbol, + contracts[tokenAddress].decimals, + ) } }) } - async _getTokenBalances (tokens) { - const ethContract = this.web3.eth.contract(SINGLE_CALL_BALANCES_ABI).at(SINGLE_CALL_BALANCES_ADDRESS) + async _getTokenBalances(tokens) { + const ethContract = this.web3.eth + .contract(SINGLE_CALL_BALANCES_ABI) + .at(SINGLE_CALL_BALANCES_ADDRESS) return new Promise((resolve, reject) => { ethContract.balances([this.selectedAddress], tokens, (error, result) => { if (error) { @@ -78,7 +95,7 @@ export default class DetectTokensController { * in case of address change or user session initialization. * */ - restartTokenDetection () { + restartTokenDetection() { if (!(this.isActive && this.selectedAddress)) { return } @@ -90,7 +107,7 @@ export default class DetectTokensController { /** * @type {Number} */ - set interval (interval) { + set interval(interval) { this._handle && clearInterval(this._handle) if (!interval) { return @@ -104,7 +121,7 @@ export default class DetectTokensController { * In setter when selectedAddress is changed, detectNewTokens and restart polling * @type {Object} */ - set preferences (preferences) { + set preferences(preferences) { if (!preferences) { return } @@ -129,7 +146,7 @@ export default class DetectTokensController { /** * @type {Object} */ - set network (network) { + set network(network) { if (!network) { return } @@ -141,7 +158,7 @@ export default class DetectTokensController { * In setter when isUnlocked is updated to true, detectNewTokens and restart polling * @type {Object} */ - set keyringMemStore (keyringMemStore) { + set keyringMemStore(keyringMemStore) { if (!keyringMemStore) { return } @@ -160,7 +177,7 @@ export default class DetectTokensController { * Internal isActive state * @type {Object} */ - get isActive () { + get isActive() { return this.isOpen && this.isUnlocked } /* eslint-enable accessor-pairs */ diff --git a/app/scripts/controllers/ens/ens.js b/app/scripts/controllers/ens/ens.js index 5a1a4dc81..f29d46aaa 100644 --- a/app/scripts/controllers/ens/ens.js +++ b/app/scripts/controllers/ens/ens.js @@ -2,22 +2,22 @@ import EthJsEns from 'ethjs-ens' import ensNetworkMap from 'ethereum-ens-network-map' export default class Ens { - static getNetworkEnsSupport (network) { + static getNetworkEnsSupport(network) { return Boolean(ensNetworkMap[network]) } - constructor ({ network, provider } = {}) { + constructor({ network, provider } = {}) { this._ethJsEns = new EthJsEns({ network, provider, }) } - lookup (ensName) { + lookup(ensName) { return this._ethJsEns.lookup(ensName) } - reverse (address) { + reverse(address) { return this._ethJsEns.reverse(address) } } diff --git a/app/scripts/controllers/ens/index.js b/app/scripts/controllers/ens/index.js index 26fde22c6..766aeeb88 100644 --- a/app/scripts/controllers/ens/index.js +++ b/app/scripts/controllers/ens/index.js @@ -8,7 +8,7 @@ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' const ZERO_X_ERROR_ADDRESS = '0x' export default class EnsController { - constructor ({ ens, provider, networkStore } = {}) { + constructor({ ens, provider, networkStore } = {}) { const initState = { ensResolutionsByAddress: {}, } @@ -38,11 +38,11 @@ export default class EnsController { }) } - reverseResolveAddress (address) { + reverseResolveAddress(address) { return this._reverseResolveAddress(ethUtil.toChecksumAddress(address)) } - async _reverseResolveAddress (address) { + async _reverseResolveAddress(address) { if (!this._ens) { return undefined } @@ -68,7 +68,10 @@ export default class EnsController { return undefined } - if (registeredAddress === ZERO_ADDRESS || registeredAddress === ZERO_X_ERROR_ADDRESS) { + if ( + registeredAddress === ZERO_ADDRESS || + registeredAddress === ZERO_X_ERROR_ADDRESS + ) { return undefined } @@ -80,7 +83,7 @@ export default class EnsController { return domain } - _updateResolutionsByAddress (address, domain) { + _updateResolutionsByAddress(address, domain) { const oldState = this.store.getState() this.store.putState({ ensResolutionsByAddress: { diff --git a/app/scripts/controllers/incoming-transactions.js b/app/scripts/controllers/incoming-transactions.js index 6e50b6774..eabfe8f6d 100644 --- a/app/scripts/controllers/incoming-transactions.js +++ b/app/scripts/controllers/incoming-transactions.js @@ -40,13 +40,8 @@ const etherscanSupportedNetworks = [ ] export default class IncomingTransactionsController { - - constructor (opts = {}) { - const { - blockTracker, - networkController, - preferencesController, - } = opts + constructor(opts = {}) { + const { blockTracker, networkController, preferencesController } = opts this.blockTracker = blockTracker this.networkController = networkController this.preferencesController = preferencesController @@ -68,38 +63,51 @@ export default class IncomingTransactionsController { [MAINNET]: null, [RINKEBY]: null, [ROPSTEN]: null, - }, ...opts.initState, + }, + ...opts.initState, } this.store = new ObservableStore(initState) - this.preferencesController.store.subscribe(pairwise((prevState, currState) => { - const { featureFlags: { showIncomingTransactions: prevShowIncomingTransactions } = {} } = prevState - const { featureFlags: { showIncomingTransactions: currShowIncomingTransactions } = {} } = currState + this.preferencesController.store.subscribe( + pairwise((prevState, currState) => { + const { + featureFlags: { + showIncomingTransactions: prevShowIncomingTransactions, + } = {}, + } = prevState + const { + featureFlags: { + showIncomingTransactions: currShowIncomingTransactions, + } = {}, + } = currState - if (currShowIncomingTransactions === prevShowIncomingTransactions) { - return - } + if (currShowIncomingTransactions === prevShowIncomingTransactions) { + return + } - if (prevShowIncomingTransactions && !currShowIncomingTransactions) { - this.stop() - return - } + if (prevShowIncomingTransactions && !currShowIncomingTransactions) { + this.stop() + return + } - this.start() - })) + this.start() + }), + ) - this.preferencesController.store.subscribe(pairwise(async (prevState, currState) => { - const { selectedAddress: prevSelectedAddress } = prevState - const { selectedAddress: currSelectedAddress } = currState + this.preferencesController.store.subscribe( + pairwise(async (prevState, currState) => { + const { selectedAddress: prevSelectedAddress } = prevState + const { selectedAddress: currSelectedAddress } = currState - if (currSelectedAddress === prevSelectedAddress) { - return - } + if (currSelectedAddress === prevSelectedAddress) { + return + } - await this._update({ - address: currSelectedAddress, - }) - })) + await this._update({ + address: currSelectedAddress, + }) + }), + ) this.networkController.on('networkDidChange', async () => { const address = this.preferencesController.getSelectedAddress() @@ -109,7 +117,7 @@ export default class IncomingTransactionsController { }) } - start () { + start() { const { featureFlags = {} } = this.preferencesController.store.getState() const { showIncomingTransactions } = featureFlags @@ -121,36 +129,45 @@ export default class IncomingTransactionsController { this.blockTracker.addListener('latest', this._onLatestBlock) } - stop () { + stop() { this.blockTracker.removeListener('latest', this._onLatestBlock) } - async _update ({ address, newBlockNumberDec } = {}) { + async _update({ address, newBlockNumberDec } = {}) { const chainId = this.networkController.getCurrentChainId() if (!etherscanSupportedNetworks.includes(chainId)) { return } try { - const dataForUpdate = await this._getDataForUpdate({ address, chainId, newBlockNumberDec }) + const dataForUpdate = await this._getDataForUpdate({ + address, + chainId, + newBlockNumberDec, + }) this._updateStateWithNewTxData(dataForUpdate) } catch (err) { log.error(err) } } - async _getDataForUpdate ({ address, chainId, newBlockNumberDec } = {}) { + async _getDataForUpdate({ address, chainId, newBlockNumberDec } = {}) { const { incomingTransactions: currentIncomingTxs, incomingTxLastFetchedBlocksByNetwork: currentBlocksByNetwork, } = this.store.getState() - const lastFetchBlockByCurrentNetwork = currentBlocksByNetwork[CHAIN_ID_TO_TYPE_MAP[chainId]] + const lastFetchBlockByCurrentNetwork = + currentBlocksByNetwork[CHAIN_ID_TO_TYPE_MAP[chainId]] let blockToFetchFrom = lastFetchBlockByCurrentNetwork || newBlockNumberDec if (blockToFetchFrom === undefined) { blockToFetchFrom = parseInt(this.blockTracker.getCurrentBlock(), 16) } - const { latestIncomingTxBlockNumber, txs: newTxs } = await this._fetchAll(address, blockToFetchFrom, chainId) + const { latestIncomingTxBlockNumber, txs: newTxs } = await this._fetchAll( + address, + blockToFetchFrom, + chainId, + ) return { latestIncomingTxBlockNumber, @@ -162,7 +179,7 @@ export default class IncomingTransactionsController { } } - _updateStateWithNewTxData ({ + _updateStateWithNewTxData({ latestIncomingTxBlockNumber, newTxs, currentIncomingTxs, @@ -189,15 +206,16 @@ export default class IncomingTransactionsController { }) } - async _fetchAll (address, fromBlock, chainId) { + async _fetchAll(address, fromBlock, chainId) { const fetchedTxResponse = await this._fetchTxs(address, fromBlock, chainId) return this._processTxFetchResponse(fetchedTxResponse) } - async _fetchTxs (address, fromBlock, chainId) { - const etherscanSubdomain = chainId === MAINNET_CHAIN_ID - ? 'api' - : `api-${CHAIN_ID_TO_TYPE_MAP[chainId]}` + async _fetchTxs(address, fromBlock, chainId) { + const etherscanSubdomain = + chainId === MAINNET_CHAIN_ID + ? 'api' + : `api-${CHAIN_ID_TO_TYPE_MAP[chainId]}` const apiUrl = `https://${etherscanSubdomain}.etherscan.io` let url = `${apiUrl}/api?module=account&action=txlist&address=${address}&tag=latest&page=1` @@ -215,7 +233,7 @@ export default class IncomingTransactionsController { } } - _processTxFetchResponse ({ status, result = [], address, chainId }) { + _processTxFetchResponse({ status, result = [], address, chainId }) { if (status === '1' && Array.isArray(result) && result.length > 0) { const remoteTxList = {} const remoteTxs = [] @@ -226,7 +244,11 @@ export default class IncomingTransactionsController { } }) - const incomingTxs = remoteTxs.filter((tx) => tx.txParams.to && tx.txParams.to.toLowerCase() === address.toLowerCase()) + const incomingTxs = remoteTxs.filter( + (tx) => + tx.txParams.to && + tx.txParams.to.toLowerCase() === address.toLowerCase(), + ) incomingTxs.sort((a, b) => (a.time < b.time ? -1 : 1)) let latestIncomingTxBlockNumber = null @@ -234,7 +256,8 @@ export default class IncomingTransactionsController { if ( tx.blockNumber && (!latestIncomingTxBlockNumber || - parseInt(latestIncomingTxBlockNumber, 10) < parseInt(tx.blockNumber, 10)) + parseInt(latestIncomingTxBlockNumber, 10) < + parseInt(tx.blockNumber, 10)) ) { latestIncomingTxBlockNumber = tx.blockNumber } @@ -250,7 +273,7 @@ export default class IncomingTransactionsController { } } - _normalizeTxFromEtherscan (txMeta, chainId) { + _normalizeTxFromEtherscan(txMeta, chainId) { const time = parseInt(txMeta.timeStamp, 10) * 1000 const status = txMeta.isError === '0' ? 'confirmed' : 'failed' return { @@ -273,7 +296,7 @@ export default class IncomingTransactionsController { } } -function pairwise (fn) { +function pairwise(fn) { let first = true let cache return (value) => { diff --git a/app/scripts/controllers/network/contract-addresses.js b/app/scripts/controllers/network/contract-addresses.js index d09e9c48e..c2a8c9737 100644 --- a/app/scripts/controllers/network/contract-addresses.js +++ b/app/scripts/controllers/network/contract-addresses.js @@ -1,4 +1,8 @@ -export const SINGLE_CALL_BALANCES_ADDRESS = '0xb1f8e55c7f64d203c1400b9d8555d050f94adf39' -export const SINGLE_CALL_BALANCES_ADDRESS_RINKEBY = '0x9f510b19f1ad66f0dcf6e45559fab0d6752c1db7' -export const SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN = '0xb8e671734ce5c8d7dfbbea5574fa4cf39f7a54a4' -export const SINGLE_CALL_BALANCES_ADDRESS_KOVAN = '0xb1d3fbb2f83aecd196f474c16ca5d9cffa0d0ffc' +export const SINGLE_CALL_BALANCES_ADDRESS = + '0xb1f8e55c7f64d203c1400b9d8555d050f94adf39' +export const SINGLE_CALL_BALANCES_ADDRESS_RINKEBY = + '0x9f510b19f1ad66f0dcf6e45559fab0d6752c1db7' +export const SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN = + '0xb8e671734ce5c8d7dfbbea5574fa4cf39f7a54a4' +export const SINGLE_CALL_BALANCES_ADDRESS_KOVAN = + '0xb1d3fbb2f83aecd196f474c16ca5d9cffa0d0ffc' diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 66aa69472..52048a775 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -10,7 +10,7 @@ import createInfuraMiddleware from 'eth-json-rpc-infura' import BlockTracker from 'eth-block-tracker' import * as networkEnums from './enums' -export default function createInfuraClient ({ network, projectId }) { +export default function createInfuraClient({ network, projectId }) { const infuraMiddleware = createInfuraMiddleware({ network, projectId, @@ -32,7 +32,7 @@ export default function createInfuraClient ({ network, projectId }) { return { networkMiddleware, blockTracker } } -function createNetworkAndChainIdMiddleware ({ network }) { +function createNetworkAndChainIdMiddleware({ network }) { let chainId let netId diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index 823a34d49..b3c9cb062 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -9,16 +9,12 @@ import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddlewa import BlockTracker from 'eth-block-tracker' const inTest = process.env.IN_TEST === 'true' -const blockTrackerOpts = inTest - ? { pollingInterval: 1000 } - : {} +const blockTrackerOpts = inTest ? { pollingInterval: 1000 } : {} const getTestMiddlewares = () => { - return inTest - ? [createEstimateGasDelayTestMiddleware()] - : [] + return inTest ? [createEstimateGasDelayTestMiddleware()] : [] } -export default function createJsonRpcClient ({ rpcUrl, chainId }) { +export default function createJsonRpcClient({ rpcUrl, chainId }) { const fetchMiddleware = createFetchMiddleware({ rpcUrl }) const blockProvider = providerFromMiddleware(fetchMiddleware) const blockTracker = new BlockTracker({ @@ -39,7 +35,7 @@ export default function createJsonRpcClient ({ rpcUrl, chainId }) { return { networkMiddleware, blockTracker } } -function createChainIdMiddleware (chainId) { +function createChainIdMiddleware(chainId) { return (req, res, next, end) => { if (req.method === 'eth_chainId') { res.result = chainId @@ -53,7 +49,7 @@ function createChainIdMiddleware (chainId) { * For use in tests only. * Adds a delay to `eth_estimateGas` calls. */ -function createEstimateGasDelayTestMiddleware () { +function createEstimateGasDelayTestMiddleware() { return createAsyncMiddleware(async (req, _, next) => { if (req.method === 'eth_estimateGas') { await new Promise((resolve) => setTimeout(resolve, 2000)) diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 179164952..1d1291eea 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -1,9 +1,12 @@ import mergeMiddleware from 'json-rpc-engine/src/mergeMiddleware' import createScaffoldMiddleware from 'json-rpc-engine/src/createScaffoldMiddleware' import createWalletSubprovider from 'eth-json-rpc-middleware/wallet' -import { createPendingNonceMiddleware, createPendingTxMiddleware } from './middleware/pending' +import { + createPendingNonceMiddleware, + createPendingTxMiddleware, +} from './middleware/pending' -export default function createMetamaskMiddleware ({ +export default function createMetamaskMiddleware({ version, getAccounts, processTransaction, diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js index 9b0d37602..6887a08dd 100644 --- a/app/scripts/controllers/network/enums.js +++ b/app/scripts/controllers/network/enums.js @@ -22,13 +22,7 @@ export const KOVAN_DISPLAY_NAME = 'Kovan' export const MAINNET_DISPLAY_NAME = 'Ethereum Mainnet' export const GOERLI_DISPLAY_NAME = 'Goerli' -export const INFURA_PROVIDER_TYPES = [ - ROPSTEN, - RINKEBY, - KOVAN, - MAINNET, - GOERLI, -] +export const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, GOERLI] export const NETWORK_TYPE_TO_ID_MAP = { [ROPSTEN]: { networkId: ROPSTEN_NETWORK_ID, chainId: ROPSTEN_CHAIN_ID }, @@ -58,20 +52,16 @@ export const NETWORK_TO_NAME_MAP = { [MAINNET_CHAIN_ID]: MAINNET_DISPLAY_NAME, } -export const CHAIN_ID_TO_TYPE_MAP = Object.entries(NETWORK_TYPE_TO_ID_MAP) - .reduce( - (chainIdToTypeMap, [networkType, { chainId }]) => { - chainIdToTypeMap[chainId] = networkType - return chainIdToTypeMap - }, - {}, - ) +export const CHAIN_ID_TO_TYPE_MAP = Object.entries( + NETWORK_TYPE_TO_ID_MAP, +).reduce((chainIdToTypeMap, [networkType, { chainId }]) => { + chainIdToTypeMap[chainId] = networkType + return chainIdToTypeMap +}, {}) -export const CHAIN_ID_TO_NETWORK_ID_MAP = Object.values(NETWORK_TYPE_TO_ID_MAP) - .reduce( - (chainIdToNetworkIdMap, { chainId, networkId }) => { - chainIdToNetworkIdMap[chainId] = networkId - return chainIdToNetworkIdMap - }, - {}, - ) +export const CHAIN_ID_TO_NETWORK_ID_MAP = Object.values( + NETWORK_TYPE_TO_ID_MAP, +).reduce((chainIdToNetworkIdMap, { chainId, networkId }) => { + chainIdToNetworkIdMap[chainId] = networkId + return chainIdToNetworkIdMap +}, {}) diff --git a/app/scripts/controllers/network/middleware/pending.js b/app/scripts/controllers/network/middleware/pending.js index 1a67688c9..fe243ec28 100644 --- a/app/scripts/controllers/network/middleware/pending.js +++ b/app/scripts/controllers/network/middleware/pending.js @@ -1,7 +1,7 @@ import createAsyncMiddleware from 'json-rpc-engine/src/createAsyncMiddleware' import { formatTxMetaForRpcResult } from '../util' -export function createPendingNonceMiddleware ({ getPendingNonce }) { +export function createPendingNonceMiddleware({ getPendingNonce }) { return createAsyncMiddleware(async (req, res, next) => { const { method, params } = req if (method !== 'eth_getTransactionCount') { @@ -17,7 +17,7 @@ export function createPendingNonceMiddleware ({ getPendingNonce }) { }) } -export function createPendingTxMiddleware ({ getPendingTransactionByHash }) { +export function createPendingTxMiddleware({ getPendingTransactionByHash }) { return createAsyncMiddleware(async (req, res, next) => { const { method, params } = req if (method !== 'eth_getTransactionByHash') { diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index f9ffb8463..5527d8628 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -5,7 +5,10 @@ import ComposedStore from 'obs-store/lib/composed' import JsonRpcEngine from 'json-rpc-engine' import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine' import log from 'loglevel' -import { createSwappableProxy, createEventEmitterProxy } from 'swappable-obj-proxy' +import { + createSwappableProxy, + createEventEmitterProxy, +} from 'swappable-obj-proxy' import EthQuery from 'eth-query' import createMetamaskMiddleware from './createMetamaskMiddleware' import createInfuraClient from './createInfuraClient' @@ -40,8 +43,7 @@ const defaultProviderConfig = { } export default class NetworkController extends EventEmitter { - - constructor (opts = {}) { + constructor(opts = {}) { super() // create stores @@ -72,7 +74,7 @@ export default class NetworkController extends EventEmitter { * @throws {Error} if the project ID is not a valid string * @return {void} */ - setInfuraProjectId (projectId) { + setInfuraProjectId(projectId) { if (!projectId || typeof projectId !== 'string') { throw new Error('Invalid Infura project ID') } @@ -80,7 +82,7 @@ export default class NetworkController extends EventEmitter { this._infuraProjectId = projectId } - initializeProvider (providerParams) { + initializeProvider(providerParams) { this._baseProviderParams = providerParams const { type, rpcUrl, chainId } = this.getProviderConfig() this._configureProvider({ type, rpcUrl, chainId }) @@ -88,41 +90,45 @@ export default class NetworkController extends EventEmitter { } // return the proxies so the references will always be good - getProviderAndBlockTracker () { + getProviderAndBlockTracker() { const provider = this._providerProxy const blockTracker = this._blockTrackerProxy return { provider, blockTracker } } - verifyNetwork () { + verifyNetwork() { // Check network when restoring connectivity: if (this.isNetworkLoading()) { this.lookupNetwork() } } - getNetworkState () { + getNetworkState() { return this.networkStore.getState() } - setNetworkState (network) { + setNetworkState(network) { this.networkStore.putState(network) } - isNetworkLoading () { + isNetworkLoading() { return this.getNetworkState() === 'loading' } - lookupNetwork () { + lookupNetwork() { // Prevent firing when provider is not defined. if (!this._provider) { - log.warn('NetworkController - lookupNetwork aborted due to missing provider') + log.warn( + 'NetworkController - lookupNetwork aborted due to missing provider', + ) return } const chainId = this.getCurrentChainId() if (!chainId) { - log.warn('NetworkController - lookupNetwork aborted due to missing chainId') + log.warn( + 'NetworkController - lookupNetwork aborted due to missing chainId', + ) this.setNetworkState('loading') return } @@ -143,12 +149,12 @@ export default class NetworkController extends EventEmitter { }) } - getCurrentChainId () { + getCurrentChainId() { const { type, chainId: configChainId } = this.getProviderConfig() return NETWORK_TYPE_TO_ID_MAP[type]?.chainId || configChainId } - setRpcTarget (rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) { + setRpcTarget(rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) { this.setProviderConfig({ type: 'rpc', rpcUrl, @@ -159,26 +165,33 @@ export default class NetworkController extends EventEmitter { }) } - async setProviderType (type, rpcUrl = '', ticker = 'ETH', nickname = '') { - assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`) - assert(INFURA_PROVIDER_TYPES.includes(type), `NetworkController - Unknown rpc type "${type}"`) + async setProviderType(type, rpcUrl = '', ticker = 'ETH', nickname = '') { + assert.notEqual( + type, + 'rpc', + `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`, + ) + assert( + INFURA_PROVIDER_TYPES.includes(type), + `NetworkController - Unknown rpc type "${type}"`, + ) const { chainId } = NETWORK_TYPE_TO_ID_MAP[type] this.setProviderConfig({ type, rpcUrl, chainId, ticker, nickname }) } - resetConnection () { + resetConnection() { this.setProviderConfig(this.getProviderConfig()) } /** * Sets the provider config and switches the network. */ - setProviderConfig (config) { + setProviderConfig(config) { this.providerStore.updateState(config) this._switchNetwork(config) } - getProviderConfig () { + getProviderConfig() { return this.providerStore.getState() } @@ -186,26 +199,28 @@ export default class NetworkController extends EventEmitter { // Private // - _switchNetwork (opts) { + _switchNetwork(opts) { this.setNetworkState('loading') this._configureProvider(opts) this.emit('networkDidChange', opts.type) } - _configureProvider ({ type, rpcUrl, chainId }) { + _configureProvider({ type, rpcUrl, chainId }) { // infura type-based endpoints const isInfura = INFURA_PROVIDER_TYPES.includes(type) if (isInfura) { this._configureInfuraProvider(type, this._infuraProjectId) - // url-based rpc endpoints + // url-based rpc endpoints } else if (type === 'rpc') { this._configureStandardProvider(rpcUrl, chainId) } else { - throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`) + throw new Error( + `NetworkController - _configureProvider - unknown type "${type}"`, + ) } } - _configureInfuraProvider (type, projectId) { + _configureInfuraProvider(type, projectId) { log.info('NetworkController - configureInfuraProvider', type) const networkClient = createInfuraClient({ network: type, @@ -214,14 +229,16 @@ export default class NetworkController extends EventEmitter { this._setNetworkClient(networkClient) } - _configureStandardProvider (rpcUrl, chainId) { + _configureStandardProvider(rpcUrl, chainId) { log.info('NetworkController - configureStandardProvider', rpcUrl) const networkClient = createJsonRpcClient({ rpcUrl, chainId }) this._setNetworkClient(networkClient) } - _setNetworkClient ({ networkMiddleware, blockTracker }) { - const metamaskMiddleware = createMetamaskMiddleware(this._baseProviderParams) + _setNetworkClient({ networkMiddleware, blockTracker }) { + const metamaskMiddleware = createMetamaskMiddleware( + this._baseProviderParams, + ) const engine = new JsonRpcEngine() engine.push(metamaskMiddleware) engine.push(networkMiddleware) @@ -229,7 +246,7 @@ export default class NetworkController extends EventEmitter { this._setProviderAndBlockTracker({ provider, blockTracker }) } - _setProviderAndBlockTracker ({ provider, blockTracker }) { + _setProviderAndBlockTracker({ provider, blockTracker }) { // update or intialize proxies if (this._providerProxy) { this._providerProxy.setTarget(provider) @@ -239,7 +256,9 @@ export default class NetworkController extends EventEmitter { if (this._blockTrackerProxy) { this._blockTrackerProxy.setTarget(blockTracker) } else { - this._blockTrackerProxy = createEventEmitterProxy(blockTracker, { eventFilter: 'skipInternal' }) + this._blockTrackerProxy = createEventEmitterProxy(blockTracker, { + eventFilter: 'skipInternal', + }) } // set new provider and blockTracker this._provider = provider diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js index bea71d666..958a1d4dd 100644 --- a/app/scripts/controllers/network/util.js +++ b/app/scripts/controllers/network/util.js @@ -2,21 +2,23 @@ import { NETWORK_TO_NAME_MAP } from './enums' export const getNetworkDisplayName = (key) => NETWORK_TO_NAME_MAP[key] -export function formatTxMetaForRpcResult (txMeta) { +export function formatTxMetaForRpcResult(txMeta) { return { - 'blockHash': txMeta.txReceipt ? txMeta.txReceipt.blockHash : null, - 'blockNumber': txMeta.txReceipt ? txMeta.txReceipt.blockNumber : null, - 'from': txMeta.txParams.from, - 'gas': txMeta.txParams.gas, - 'gasPrice': txMeta.txParams.gasPrice, - 'hash': txMeta.hash, - 'input': txMeta.txParams.data || '0x', - 'nonce': txMeta.txParams.nonce, - 'to': txMeta.txParams.to, - 'transactionIndex': txMeta.txReceipt ? txMeta.txReceipt.transactionIndex : null, - 'value': txMeta.txParams.value || '0x0', - 'v': txMeta.v, - 'r': txMeta.r, - 's': txMeta.s, + blockHash: txMeta.txReceipt ? txMeta.txReceipt.blockHash : null, + blockNumber: txMeta.txReceipt ? txMeta.txReceipt.blockNumber : null, + from: txMeta.txParams.from, + gas: txMeta.txParams.gas, + gasPrice: txMeta.txParams.gasPrice, + hash: txMeta.hash, + input: txMeta.txParams.data || '0x', + nonce: txMeta.txParams.nonce, + to: txMeta.txParams.to, + transactionIndex: txMeta.txReceipt + ? txMeta.txReceipt.transactionIndex + : null, + value: txMeta.txParams.value || '0x0', + v: txMeta.v, + r: txMeta.r, + s: txMeta.s, } } diff --git a/app/scripts/controllers/onboarding.js b/app/scripts/controllers/onboarding.js index 0ff92f5b1..99d8dab96 100644 --- a/app/scripts/controllers/onboarding.js +++ b/app/scripts/controllers/onboarding.js @@ -17,13 +17,12 @@ import log from 'loglevel' * state related to onboarding */ export default class OnboardingController { - /** * Creates a new controller instance * * @param {OnboardingOptions} [opts] Controller configuration parameters */ - constructor (opts = {}) { + constructor(opts = {}) { const initialTransientState = { onboardingTabs: {}, } @@ -46,7 +45,7 @@ export default class OnboardingController { }) } - setSeedPhraseBackedUp (newSeedPhraseBackUpState) { + setSeedPhraseBackedUp(newSeedPhraseBackUpState) { this.store.updateState({ seedPhraseBackedUp: newSeedPhraseBackUpState, }) @@ -65,7 +64,9 @@ export default class OnboardingController { } const onboardingTabs = { ...this.store.getState().onboardingTabs } if (!onboardingTabs[location] || onboardingTabs[location] !== tabId) { - log.debug(`Registering onboarding tab at location '${location}' with tabId '${tabId}'`) + log.debug( + `Registering onboarding tab at location '${location}' with tabId '${tabId}'`, + ) onboardingTabs[location] = tabId this.store.updateState({ onboardingTabs }) } diff --git a/app/scripts/controllers/permissions/enums.js b/app/scripts/controllers/permissions/enums.js index a4d3afd5b..56a87fdf5 100644 --- a/app/scripts/controllers/permissions/enums.js +++ b/app/scripts/controllers/permissions/enums.js @@ -1,4 +1,3 @@ - export const WALLET_PREFIX = 'wallet_' export const HISTORY_STORE_KEY = 'permissionsHistory' @@ -23,9 +22,7 @@ export const NOTIFICATION_NAMES = { accountsChanged: 'wallet_accountsChanged', } -export const LOG_IGNORE_METHODS = [ - 'wallet_sendDomainMetadata', -] +export const LOG_IGNORE_METHODS = ['wallet_sendDomainMetadata'] export const LOG_METHOD_TYPES = { restricted: 'restricted', diff --git a/app/scripts/controllers/permissions/index.js b/app/scripts/controllers/permissions/index.js index 093983343..0ee430741 100644 --- a/app/scripts/controllers/permissions/index.js +++ b/app/scripts/controllers/permissions/index.js @@ -24,8 +24,7 @@ import { } from './enums' export class PermissionsController { - - constructor ( + constructor( { getKeyringAccounts, getRestrictedMethods, @@ -38,7 +37,6 @@ export class PermissionsController { restoredPermissions = {}, restoredState = {}, ) { - // additional top-level store key set in _initializeMetadataStore this.store = new ObservableStore({ [LOG_STORE_KEY]: restoredState[LOG_STORE_KEY] || [], @@ -75,8 +73,7 @@ export class PermissionsController { }) } - createMiddleware ({ origin, extensionId }) { - + createMiddleware({ origin, extensionId }) { if (typeof origin !== 'string' || !origin.length) { throw new Error('Must provide non-empty string origin.') } @@ -91,20 +88,26 @@ export class PermissionsController { engine.push(this.permissionsLog.createMiddleware()) - engine.push(createPermissionsMethodMiddleware({ - addDomainMetadata: this.addDomainMetadata.bind(this), - getAccounts: this.getAccounts.bind(this, origin), - getUnlockPromise: () => this._getUnlockPromise(true), - hasPermission: this.hasPermission.bind(this, origin), - notifyAccountsChanged: this.notifyAccountsChanged.bind(this, origin), - requestAccountsPermission: this._requestPermissions.bind( - this, { origin }, { eth_accounts: {} }, - ), - })) + engine.push( + createPermissionsMethodMiddleware({ + addDomainMetadata: this.addDomainMetadata.bind(this), + getAccounts: this.getAccounts.bind(this, origin), + getUnlockPromise: () => this._getUnlockPromise(true), + hasPermission: this.hasPermission.bind(this, origin), + notifyAccountsChanged: this.notifyAccountsChanged.bind(this, origin), + requestAccountsPermission: this._requestPermissions.bind( + this, + { origin }, + { eth_accounts: {} }, + ), + }), + ) - engine.push(this.permissions.providerMiddlewareFunction.bind( - this.permissions, { origin }, - )) + engine.push( + this.permissions.providerMiddlewareFunction.bind(this.permissions, { + origin, + }), + ) return asMiddleware(engine) } @@ -114,7 +117,7 @@ export class PermissionsController { * @param {string} origin - The requesting origin * @returns {Promise} The permissions request ID */ - async requestAccountsPermissionWithId (origin) { + async requestAccountsPermissionWithId(origin) { const id = nanoid() this._requestPermissions({ origin }, { eth_accounts: {} }, id) return id @@ -127,16 +130,19 @@ export class PermissionsController { * * @param {string} origin - The origin string. */ - getAccounts (origin) { + getAccounts(origin) { return new Promise((resolve, _) => { - const req = { method: 'eth_accounts' } const res = {} this.permissions.providerMiddlewareFunction( - { origin }, req, res, () => undefined, _end, + { origin }, + req, + res, + () => undefined, + _end, ) - function _end () { + function _end() { if (res.error || !Array.isArray(res.result)) { resolve([]) } else { @@ -153,7 +159,7 @@ export class PermissionsController { * @param {string} permission - The permission to check for. * @returns {boolean} Whether the origin has the permission. */ - hasPermission (origin, permission) { + hasPermission(origin, permission) { return Boolean(this.permissions.getPermission(origin, permission)) } @@ -162,7 +168,7 @@ export class PermissionsController { * * @returns {Object} identities */ - _getIdentities () { + _getIdentities() { return this.preferences.getState().identities } @@ -175,9 +181,8 @@ export class PermissionsController { * @returns {Promise} A Promise that resolves with the * approved permissions, or rejects with an error. */ - _requestPermissions (domain, permissions, id) { + _requestPermissions(domain, permissions, id) { return new Promise((resolve, reject) => { - // rpc-cap assigns an id to the request if there is none, as expected by // requestUserApproval below const req = { @@ -188,10 +193,14 @@ export class PermissionsController { const res = {} this.permissions.providerMiddlewareFunction( - domain, req, res, () => undefined, _end, + domain, + req, + res, + () => undefined, + _end, ) - function _end (_err) { + function _end(_err) { const err = _err || res.error if (err) { reject(err) @@ -211,8 +220,7 @@ export class PermissionsController { * @param {Object} approved - The request object approved by the user * @param {Array} accounts - The accounts to expose, if any */ - async approvePermissionsRequest (approved, accounts) { - + async approvePermissionsRequest(approved, accounts) { const { id } = approved.metadata const approval = this.pendingApprovals.get(id) @@ -222,28 +230,29 @@ export class PermissionsController { } try { - if (Object.keys(approved.permissions).length === 0) { - - approval.reject(ethErrors.rpc.invalidRequest({ - message: 'Must request at least one permission.', - })) - + approval.reject( + ethErrors.rpc.invalidRequest({ + message: 'Must request at least one permission.', + }), + ) } else { - // attempt to finalize the request and resolve it, // settings caveats as necessary approved.permissions = await this.finalizePermissionsRequest( - approved.permissions, accounts, + approved.permissions, + accounts, ) approval.resolve(approved.permissions) } } catch (err) { - // if finalization fails, reject the request - approval.reject(ethErrors.rpc.invalidRequest({ - message: err.message, data: err, - })) + approval.reject( + ethErrors.rpc.invalidRequest({ + message: err.message, + data: err, + }), + ) } this._removePendingApproval(id) @@ -256,7 +265,7 @@ export class PermissionsController { * * @param {string} id - The id of the request rejected by the user */ - async rejectPermissionsRequest (id) { + async rejectPermissionsRequest(id) { const approval = this.pendingApprovals.get(id) if (!approval) { @@ -277,8 +286,7 @@ export class PermissionsController { * @param {string} origin - The origin to expose the account to. * @param {string} account - The new account to expose. */ - async addPermittedAccount (origin, account) { - + async addPermittedAccount(origin, account) { const domains = this.permissions.getDomains() if (!domains[origin]) { throw new Error('Unrecognized domain') @@ -294,7 +302,8 @@ export class PermissionsController { } this.permissions.updateCaveatFor( - origin, 'eth_accounts', + origin, + 'eth_accounts', CAVEAT_NAMES.exposedAccounts, [...oldPermittedAccounts, account], ) @@ -315,8 +324,7 @@ export class PermissionsController { * @param {string} origin - The origin to remove the account from. * @param {string} account - The account to remove. */ - async removePermittedAccount (origin, account) { - + async removePermittedAccount(origin, account) { const domains = this.permissions.getDomains() if (!domains[origin]) { throw new Error('Unrecognized domain') @@ -331,15 +339,16 @@ export class PermissionsController { throw new Error('Account is not permitted for origin') } - let newPermittedAccounts = oldPermittedAccounts - .filter((acc) => acc !== account) + let newPermittedAccounts = oldPermittedAccounts.filter( + (acc) => acc !== account, + ) if (newPermittedAccounts.length === 0) { this.removePermissionsFor({ [origin]: ['eth_accounts'] }) } else { - this.permissions.updateCaveatFor( - origin, 'eth_accounts', + origin, + 'eth_accounts', CAVEAT_NAMES.exposedAccounts, newPermittedAccounts, ) @@ -358,14 +367,19 @@ export class PermissionsController { * * @param {string} account - The account to remove. */ - async removeAllAccountPermissions (account) { + async removeAllAccountPermissions(account) { this.validatePermittedAccounts([account]) const domains = this.permissions.getDomains() - const connectedOrigins = Object.keys(domains) - .filter((origin) => this._getPermittedAccounts(origin).includes(account)) + const connectedOrigins = Object.keys(domains).filter((origin) => + this._getPermittedAccounts(origin).includes(account), + ) - await Promise.all(connectedOrigins.map((origin) => this.removePermittedAccount(origin, account))) + await Promise.all( + connectedOrigins.map((origin) => + this.removePermittedAccount(origin, account), + ), + ) } /** @@ -378,15 +392,13 @@ export class PermissionsController { * @param {string[]} requestedAccounts - The accounts to expose, if any. * @returns {Object} The finalized permissions request object. */ - async finalizePermissionsRequest (requestedPermissions, requestedAccounts) { - + async finalizePermissionsRequest(requestedPermissions, requestedAccounts) { const finalizedPermissions = cloneDeep(requestedPermissions) const finalizedAccounts = cloneDeep(requestedAccounts) const { eth_accounts: ethAccounts } = finalizedPermissions if (ethAccounts) { - this.validatePermittedAccounts(finalizedAccounts) if (!ethAccounts.caveats) { @@ -394,9 +406,11 @@ export class PermissionsController { } // caveat names are unique, and we will only construct this caveat here - ethAccounts.caveats = ethAccounts.caveats.filter((c) => ( - c.name !== CAVEAT_NAMES.exposedAccounts && c.name !== CAVEAT_NAMES.primaryAccountOnly - )) + ethAccounts.caveats = ethAccounts.caveats.filter( + (c) => + c.name !== CAVEAT_NAMES.exposedAccounts && + c.name !== CAVEAT_NAMES.primaryAccountOnly, + ) ethAccounts.caveats.push({ type: CAVEAT_TYPES.limitResponseLength, @@ -420,7 +434,7 @@ export class PermissionsController { * * @param {string[]} accounts - An array of addresses. */ - validatePermittedAccounts (accounts) { + validatePermittedAccounts(accounts) { if (!Array.isArray(accounts) || accounts.length === 0) { throw new Error('Must provide non-empty array of account(s).') } @@ -441,8 +455,7 @@ export class PermissionsController { * @param {string} origin - The origin of the domain to notify. * @param {Array} newAccounts - The currently permitted accounts. */ - notifyAccountsChanged (origin, newAccounts) { - + notifyAccountsChanged(origin, newAccounts) { if (typeof origin !== 'string' || !origin) { throw new Error(`Invalid origin: '${origin}'`) } @@ -459,9 +472,7 @@ export class PermissionsController { // if the accounts changed from the perspective of the dapp, // update "last seen" time for the origin and account(s) // exception: no accounts -> no times to update - this.permissionsLog.updateAccountsHistory( - origin, newAccounts, - ) + this.permissionsLog.updateAccountsHistory(origin, newAccounts) // NOTE: // we don't check for accounts changing in the notifyAllDomains case, @@ -478,14 +489,11 @@ export class PermissionsController { * @param {Object} domains { origin: [permissions] } - The map of domain * origins to permissions to remove. */ - removePermissionsFor (domains) { - + removePermissionsFor(domains) { Object.entries(domains).forEach(([origin, perms]) => { - this.permissions.removePermissionsFor( origin, perms.map((methodName) => { - if (methodName === 'eth_accounts') { this.notifyAccountsChanged(origin, []) } @@ -499,7 +507,7 @@ export class PermissionsController { /** * Removes all known domains and their related permissions. */ - clearPermissions () { + clearPermissions() { this.permissions.clearDomains() this._notifyAllDomains({ method: NOTIFICATION_NAMES.accountsChanged, @@ -517,8 +525,7 @@ export class PermissionsController { * @param {string} origin - The origin whose domain metadata to store. * @param {Object} metadata - The domain's metadata that will be stored. */ - addDomainMetadata (origin, metadata) { - + addDomainMetadata(origin, metadata) { const oldMetadataState = this.store.getState()[METADATA_STORE_KEY] const newMetadataState = { ...oldMetadataState } @@ -541,7 +548,10 @@ export class PermissionsController { lastUpdated: Date.now(), } - if (!newMetadataState[origin].extensionId && !newMetadataState[origin].host) { + if ( + !newMetadataState[origin].extensionId && + !newMetadataState[origin].host + ) { newMetadataState[origin].host = new URL(origin).host } @@ -557,8 +567,7 @@ export class PermissionsController { * * @param {Object} restoredState - The restored permissions controller state. */ - _initializeMetadataStore (restoredState) { - + _initializeMetadataStore(restoredState) { const metadataState = restoredState[METADATA_STORE_KEY] || {} const newMetadataState = this._trimDomainMetadata(metadataState) @@ -574,8 +583,7 @@ export class PermissionsController { * @param {Object} metadataState - The metadata store state object to trim. * @returns {Object} The new metadata state object. */ - _trimDomainMetadata (metadataState) { - + _trimDomainMetadata(metadataState) { const newMetadataState = { ...metadataState } const origins = Object.keys(metadataState) const permissionsDomains = this.permissions.getDomains() @@ -593,7 +601,7 @@ export class PermissionsController { * Replaces the existing domain metadata with the passed-in object. * @param {Object} newMetadataState - The new metadata to set. */ - _setDomainMetadata (newMetadataState) { + _setDomainMetadata(newMetadataState) { this.store.updateState({ [METADATA_STORE_KEY]: newMetadataState }) } @@ -603,11 +611,10 @@ export class PermissionsController { * @param {string} origin - The origin to obtain permitted accounts for * @returns {Array|null} The list of permitted accounts */ - _getPermittedAccounts (origin) { + _getPermittedAccounts(origin) { const permittedAccounts = this.permissions .getPermission(origin, 'eth_accounts') - ?.caveats - ?.find((caveat) => caveat.name === CAVEAT_NAMES.exposedAccounts) + ?.caveats?.find((caveat) => caveat.name === CAVEAT_NAMES.exposedAccounts) ?.value return permittedAccounts || null @@ -622,8 +629,7 @@ export class PermissionsController { * * @param {string} account - The newly selected account's address. */ - async _handleAccountSelected (account) { - + async _handleAccountSelected(account) { if (typeof account !== 'string') { throw new Error('Selected account should be a non-empty string.') } @@ -631,20 +637,20 @@ export class PermissionsController { const domains = this.permissions.getDomains() || {} const connectedDomains = Object.entries(domains) .filter(([_, { permissions }]) => { - const ethAccounts = permissions.find((permission) => permission.parentCapability === 'eth_accounts') - const exposedAccounts = ethAccounts - ?.caveats - .find((caveat) => caveat.name === 'exposedAccounts') - ?.value + const ethAccounts = permissions.find( + (permission) => permission.parentCapability === 'eth_accounts', + ) + const exposedAccounts = ethAccounts?.caveats.find( + (caveat) => caveat.name === 'exposedAccounts', + )?.value return exposedAccounts?.includes(account) }) .map(([domain]) => domain) await Promise.all( - connectedDomains - .map( - (origin) => this._handleConnectedAccountSelected(origin), - ), + connectedDomains.map((origin) => + this._handleConnectedAccountSelected(origin), + ), ) } @@ -656,7 +662,7 @@ export class PermissionsController { * * @param {string} origin - The origin */ - async _handleConnectedAccountSelected (origin) { + async _handleConnectedAccountSelected(origin) { const permittedAccounts = await this.getAccounts(origin) this.notifyAccountsChanged(origin, permittedAccounts) @@ -669,8 +675,7 @@ export class PermissionsController { * @param {Function} resolve - The function resolving the pending approval Promise. * @param {Function} reject - The function rejecting the pending approval Promise. */ - _addPendingApproval (id, origin, resolve, reject) { - + _addPendingApproval(id, origin, resolve, reject) { if ( this.pendingApprovalOrigins.has(origin) || this.pendingApprovals.has(id) @@ -688,7 +693,7 @@ export class PermissionsController { * Removes the pending approval with the given id. * @param {string} id - The id of the pending approval to remove. */ - _removePendingApproval (id) { + _removePendingApproval(id) { const { origin } = this.pendingApprovals.get(id) this.pendingApprovalOrigins.delete(origin) this.pendingApprovals.delete(id) @@ -700,49 +705,52 @@ export class PermissionsController { * * @param {string} origin = The origin string representing the domain. */ - _initializePermissions (restoredState) { - + _initializePermissions(restoredState) { // these permission requests are almost certainly stale const initState = { ...restoredState, permissionsRequests: [] } - this.permissions = new RpcCap({ + this.permissions = new RpcCap( + { + // Supports passthrough methods: + safeMethods: SAFE_METHODS, - // Supports passthrough methods: - safeMethods: SAFE_METHODS, + // optional prefix for internal methods + methodPrefix: WALLET_PREFIX, - // optional prefix for internal methods - methodPrefix: WALLET_PREFIX, + restrictedMethods: this._restrictedMethods, - restrictedMethods: this._restrictedMethods, + /** + * A promise-returning callback used to determine whether to approve + * permissions requests or not. + * + * Currently only returns a boolean, but eventually should return any + * specific parameters or amendments to the permissions. + * + * @param {string} req - The internal rpc-cap user request object. + */ + requestUserApproval: async (req) => { + const { + metadata: { id, origin }, + } = req - /** - * A promise-returning callback used to determine whether to approve - * permissions requests or not. - * - * Currently only returns a boolean, but eventually should return any - * specific parameters or amendments to the permissions. - * - * @param {string} req - The internal rpc-cap user request object. - */ - requestUserApproval: async (req) => { - const { metadata: { id, origin } } = req + if (this.pendingApprovalOrigins.has(origin)) { + throw ethErrors.rpc.resourceUnavailable( + 'Permissions request already pending; please wait.', + ) + } - if (this.pendingApprovalOrigins.has(origin)) { - throw ethErrors.rpc.resourceUnavailable( - 'Permissions request already pending; please wait.', - ) - } + this._showPermissionRequest() - this._showPermissionRequest() - - return new Promise((resolve, reject) => { - this._addPendingApproval(id, origin, resolve, reject) - }) + return new Promise((resolve, reject) => { + this._addPendingApproval(id, origin, resolve, reject) + }) + }, }, - }, initState) + initState, + ) } } -export function addInternalMethodPrefix (method) { +export function addInternalMethodPrefix(method) { return WALLET_PREFIX + method } diff --git a/app/scripts/controllers/permissions/permissionsLog.js b/app/scripts/controllers/permissions/permissionsLog.js index eda7c394a..6bb142993 100644 --- a/app/scripts/controllers/permissions/permissionsLog.js +++ b/app/scripts/controllers/permissions/permissionsLog.js @@ -14,8 +14,7 @@ import { * and permissions-related methods. */ export default class PermissionsLogController { - - constructor ({ restrictedMethods, store }) { + constructor({ restrictedMethods, store }) { this.restrictedMethods = restrictedMethods this.store = store } @@ -25,7 +24,7 @@ export default class PermissionsLogController { * * @returns {Array} The activity log. */ - getActivityLog () { + getActivityLog() { return this.store.getState()[LOG_STORE_KEY] || [] } @@ -34,7 +33,7 @@ export default class PermissionsLogController { * * @param {Array} logs - The new activity log array. */ - updateActivityLog (logs) { + updateActivityLog(logs) { this.store.updateState({ [LOG_STORE_KEY]: logs }) } @@ -43,7 +42,7 @@ export default class PermissionsLogController { * * @returns {Object} The permissions history log. */ - getHistory () { + getHistory() { return this.store.getState()[HISTORY_STORE_KEY] || {} } @@ -52,7 +51,7 @@ export default class PermissionsLogController { * * @param {Object} history - The new permissions history log object. */ - updateHistory (history) { + updateHistory(history) { this.store.updateState({ [HISTORY_STORE_KEY]: history }) } @@ -63,8 +62,7 @@ export default class PermissionsLogController { * @param {string} origin - The origin that the accounts are exposed to. * @param {Array} accounts - The accounts. */ - updateAccountsHistory (origin, accounts) { - + updateAccountsHistory(origin, accounts) { if (accounts.length === 0) { return } @@ -88,9 +86,8 @@ export default class PermissionsLogController { * * @returns {JsonRpcEngineMiddleware} The permissions log middleware. */ - createMiddleware () { + createMiddleware() { return (req, res, next, _end) => { - let activityEntry, requestedMethods const { origin, method } = req const isInternal = method.startsWith(WALLET_PREFIX) @@ -100,7 +97,6 @@ export default class PermissionsLogController { !LOG_IGNORE_METHODS.includes(method) && (isInternal || this.restrictedMethods.includes(method)) ) { - activityEntry = this.logRequest(req, isInternal) if (method === `${WALLET_PREFIX}requestPermissions`) { @@ -109,7 +105,6 @@ export default class PermissionsLogController { requestedMethods = this.getRequestedMethods(req) } } else if (method === 'eth_requestAccounts') { - // eth_requestAccounts is a special case; we need to extract the accounts // from it activityEntry = this.logRequest(req, isInternal) @@ -122,7 +117,6 @@ export default class PermissionsLogController { // call next with a return handler for capturing the response next((cb) => { - const time = Date.now() this.logResponse(activityEntry, res, time) @@ -130,7 +124,10 @@ export default class PermissionsLogController { // any permissions or accounts changes will be recorded on the response, // so we only log permissions history here this.logPermissionsHistory( - requestedMethods, origin, res.result, time, + requestedMethods, + origin, + res.result, + time, method === 'eth_requestAccounts', ) } @@ -145,13 +142,13 @@ export default class PermissionsLogController { * @param {Object} request - The request object. * @param {boolean} isInternal - Whether the request is internal. */ - logRequest (request, isInternal) { + logRequest(request, isInternal) { const activityEntry = { id: request.id, method: request.method, - methodType: ( - isInternal ? LOG_METHOD_TYPES.internal : LOG_METHOD_TYPES.restricted - ), + methodType: isInternal + ? LOG_METHOD_TYPES.internal + : LOG_METHOD_TYPES.restricted, origin: request.origin, request: cloneDeep(request), requestTime: Date.now(), @@ -171,8 +168,7 @@ export default class PermissionsLogController { * @param {Object} response - The response object. * @param {number} time - Output from Date.now() */ - logResponse (entry, response, time) { - + logResponse(entry, response, time) { if (!entry || !response) { return } @@ -188,8 +184,7 @@ export default class PermissionsLogController { * * @param {Object} entry - The activity log entry. */ - commitNewActivity (entry) { - + commitNewActivity(entry) { const logs = this.getActivityLog() // add new entry to end of log @@ -212,32 +207,31 @@ export default class PermissionsLogController { * @param {string} time - The time of the request, i.e. Date.now(). * @param {boolean} isEthRequestAccounts - Whether the permissions request was 'eth_requestAccounts'. */ - logPermissionsHistory ( - requestedMethods, origin, result, - time, isEthRequestAccounts, + logPermissionsHistory( + requestedMethods, + origin, + result, + time, + isEthRequestAccounts, ) { - let accounts, newEntries if (isEthRequestAccounts) { - accounts = result const accountToTimeMap = getAccountToTimeMap(accounts, time) newEntries = { - 'eth_accounts': { + eth_accounts: { accounts: accountToTimeMap, lastApproved: time, }, } } else { - // Records new "lastApproved" times for the granted permissions, if any. // Special handling for eth_accounts, in order to record the time the // accounts were last seen or approved by the origin. newEntries = result .map((perm) => { - if (perm.parentCapability === 'eth_accounts') { accounts = this.getAccountsFromPermission(perm) } @@ -245,13 +239,10 @@ export default class PermissionsLogController { return perm.parentCapability }) .reduce((acc, method) => { - // all approved permissions will be included in the response, // not just the newly requested ones if (requestedMethods.includes(method)) { - if (method === 'eth_accounts') { - const accountToTimeMap = getAccountToTimeMap(accounts, time) acc[method] = { @@ -280,8 +271,7 @@ export default class PermissionsLogController { * @param {string} origin - The requesting origin. * @param {Object} newEntries - The new entries to commit. */ - commitNewHistory (origin, newEntries) { - + commitNewHistory(origin, newEntries) { // a simple merge updates most permissions const history = this.getHistory() const newOriginHistory = { @@ -291,19 +281,16 @@ export default class PermissionsLogController { // eth_accounts requires special handling, because of information // we store about the accounts - const existingEthAccountsEntry = ( + const existingEthAccountsEntry = history[origin] && history[origin].eth_accounts - ) const newEthAccountsEntry = newEntries.eth_accounts if (existingEthAccountsEntry && newEthAccountsEntry) { - // we may intend to update just the accounts, not the permission // itself - const lastApproved = ( + const lastApproved = newEthAccountsEntry.lastApproved || existingEthAccountsEntry.lastApproved - ) // merge old and new eth_accounts history entries newOriginHistory.eth_accounts = { @@ -326,7 +313,7 @@ export default class PermissionsLogController { * @param {Object} request - The request object. * @returns {Array} The names of the requested permissions. */ - getRequestedMethods (request) { + getRequestedMethods(request) { if ( !request.params || !request.params[0] || @@ -345,20 +332,17 @@ export default class PermissionsLogController { * @param {Object} perm - The permissions object. * @returns {Array} The permitted accounts. */ - getAccountsFromPermission (perm) { - + getAccountsFromPermission(perm) { if (perm.parentCapability !== 'eth_accounts' || !perm.caveats) { return [] } const accounts = new Set() for (const caveat of perm.caveats) { - if ( caveat.name === CAVEAT_NAMES.exposedAccounts && Array.isArray(caveat.value) ) { - for (const value of caveat.value) { accounts.add(value) } @@ -377,8 +361,6 @@ export default class PermissionsLogController { * @param {number} time - A time, e.g. Date.now(). * @returns {Object} A string:number map of addresses to time. */ -function getAccountToTimeMap (accounts, time) { - return accounts.reduce( - (acc, account) => ({ ...acc, [account]: time }), {}, - ) +function getAccountToTimeMap(accounts, time) { + return accounts.reduce((acc, account) => ({ ...acc, [account]: time }), {}) } diff --git a/app/scripts/controllers/permissions/permissionsMethodMiddleware.js b/app/scripts/controllers/permissions/permissionsMethodMiddleware.js index a89d74632..eae072495 100644 --- a/app/scripts/controllers/permissions/permissionsMethodMiddleware.js +++ b/app/scripts/controllers/permissions/permissionsMethodMiddleware.js @@ -4,7 +4,7 @@ import { ethErrors } from 'eth-json-rpc-errors' /** * Create middleware for handling certain methods and preprocessing permissions requests. */ -export default function createPermissionsMethodMiddleware ({ +export default function createPermissionsMethodMiddleware({ addDomainMetadata, getAccounts, getUnlockPromise, @@ -12,26 +12,21 @@ export default function createPermissionsMethodMiddleware ({ notifyAccountsChanged, requestAccountsPermission, }) { - let isProcessingRequestAccounts = false return createAsyncMiddleware(async (req, res, next) => { - let responseHandler switch (req.method) { - // Intercepting eth_accounts requests for backwards compatibility: // The getAccounts call below wraps the rpc-cap middleware, and returns // an empty array in case of errors (such as 4100:unauthorized) case 'eth_accounts': { - res.result = await getAccounts() return } case 'eth_requestAccounts': { - if (isProcessingRequestAccounts) { res.error = ethErrors.rpc.resourceUnavailable( 'Already processing eth_requestAccounts. Please wait.', @@ -79,7 +74,6 @@ export default function createPermissionsMethodMiddleware ({ // custom method for getting metadata from the requesting domain, // sent automatically by the inpage provider when it's initialized case 'wallet_sendDomainMetadata': { - if (typeof req.domainMetadata?.name === 'string') { addDomainMetadata(req.origin, req.domainMetadata) } @@ -89,11 +83,8 @@ export default function createPermissionsMethodMiddleware ({ // register return handler to send accountsChanged notification case 'wallet_requestPermissions': { - if ('eth_accounts' in req.params?.[0]) { - responseHandler = async () => { - if (Array.isArray(res.result)) { for (const permission of res.result) { if (permission.parentCapability === 'eth_accounts') { diff --git a/app/scripts/controllers/permissions/restrictedMethods.js b/app/scripts/controllers/permissions/restrictedMethods.js index 0e1ae4b9a..b8dd39c71 100644 --- a/app/scripts/controllers/permissions/restrictedMethods.js +++ b/app/scripts/controllers/permissions/restrictedMethods.js @@ -1,6 +1,9 @@ -export default function getRestrictedMethods ({ getIdentities, getKeyringAccounts }) { +export default function getRestrictedMethods({ + getIdentities, + getKeyringAccounts, +}) { return { - 'eth_accounts': { + eth_accounts: { method: async (_, res, __, end) => { try { const accounts = await getKeyringAccounts() @@ -10,7 +13,10 @@ export default function getRestrictedMethods ({ getIdentities, getKeyringAccount throw new Error(`Missing identity for address ${firstAddress}`) } else if (!identities[secondAddress]) { throw new Error(`Missing identity for address ${secondAddress}`) - } else if (identities[firstAddress].lastSelected === identities[secondAddress].lastSelected) { + } else if ( + identities[firstAddress].lastSelected === + identities[secondAddress].lastSelected + ) { return 0 } else if (identities[firstAddress].lastSelected === undefined) { return 1 @@ -18,7 +24,10 @@ export default function getRestrictedMethods ({ getIdentities, getKeyringAccount return -1 } - return identities[secondAddress].lastSelected - identities[firstAddress].lastSelected + return ( + identities[secondAddress].lastSelected - + identities[firstAddress].lastSelected + ) }) end() } catch (err) { diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 02f4086fd..1b50e7de1 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -9,7 +9,6 @@ import { addInternalMethodPrefix } from './permissions' import { NETWORK_TYPE_TO_ID_MAP } from './network/enums' export default class PreferencesController { - /** * * @typedef {Object} PreferencesController @@ -30,7 +29,7 @@ export default class PreferencesController { * @property {string} store.selectedAddress A hex string that matches the currently selected address in the app * */ - constructor (opts = {}) { + constructor(opts = {}) { const initState = { frequentRpcListDetail: [], accountTokens: {}, @@ -66,7 +65,8 @@ export default class PreferencesController { metaMetricsSendCount: 0, // ENS decentralized website resolution - ipfsGateway: 'dweb.link', ...opts.initState, + ipfsGateway: 'dweb.link', + ...opts.initState, } this.network = opts.network @@ -86,7 +86,7 @@ export default class PreferencesController { * Sets the {@code forgottenPassword} state property * @param {boolean} forgottenPassword - whether or not the user has forgotten their password */ - setPasswordForgotten (forgottenPassword) { + setPasswordForgotten(forgottenPassword) { this.store.updateState({ forgottenPassword }) } @@ -96,7 +96,7 @@ export default class PreferencesController { * @param {boolean} val - Whether or not the user prefers blockie indicators * */ - setUseBlockie (val) { + setUseBlockie(val) { this.store.updateState({ useBlockie: val }) } @@ -106,7 +106,7 @@ export default class PreferencesController { * @param {boolean} val - Whether or not the user prefers to set nonce * */ - setUseNonceField (val) { + setUseNonceField(val) { this.store.updateState({ useNonceField: val }) } @@ -116,7 +116,7 @@ export default class PreferencesController { * @param {boolean} val - Whether or not the user prefers phishing domain protection * */ - setUsePhishDetect (val) { + setUsePhishDetect(val) { this.store.updateState({ usePhishDetect: val }) } @@ -127,11 +127,16 @@ export default class PreferencesController { * @returns {string|null} - the string of the new metametrics id, or null if not set * */ - setParticipateInMetaMetrics (bool) { + setParticipateInMetaMetrics(bool) { this.store.updateState({ participateInMetaMetrics: bool }) let metaMetricsId = null if (bool && !this.store.getState().metaMetricsId) { - metaMetricsId = bufferToHex(sha3(String(Date.now()) + String(Math.round(Math.random() * Number.MAX_SAFE_INTEGER)))) + metaMetricsId = bufferToHex( + sha3( + String(Date.now()) + + String(Math.round(Math.random() * Number.MAX_SAFE_INTEGER)), + ), + ) this.store.updateState({ metaMetricsId }) } else if (bool === false) { this.store.updateState({ metaMetricsId }) @@ -139,11 +144,11 @@ export default class PreferencesController { return metaMetricsId } - getParticipateInMetaMetrics () { + getParticipateInMetaMetrics() { return this.store.getState().participateInMetaMetrics } - setMetaMetricsSendCount (val) { + setMetaMetricsSendCount(val) { this.store.updateState({ metaMetricsSendCount: val }) } @@ -153,19 +158,19 @@ export default class PreferencesController { * @param {string} type - Indicates the type of first time flow - create or import - the user wishes to follow * */ - setFirstTimeFlowType (type) { + setFirstTimeFlowType(type) { this.store.updateState({ firstTimeFlowType: type }) } - getSuggestedTokens () { + getSuggestedTokens() { return this.store.getState().suggestedTokens } - getAssetImages () { + getAssetImages() { return this.store.getState().assetImages } - addSuggestedERC20Asset (tokenOpts) { + addSuggestedERC20Asset(tokenOpts) { this._validateERC20AssetParams(tokenOpts) const suggested = this.getSuggestedTokens() const { rawAddress, symbol, decimals, image } = tokenOpts @@ -181,7 +186,7 @@ export default class PreferencesController { * @param {string} fourBytePrefix - Four-byte method signature * @param {string} methodData - Corresponding data method */ - addKnownMethodData (fourBytePrefix, methodData) { + addKnownMethodData(fourBytePrefix, methodData) { const { knownMethodData } = this.store.getState() knownMethodData[fourBytePrefix] = methodData this.store.updateState({ knownMethodData }) @@ -195,7 +200,7 @@ export default class PreferencesController { * @param {Function} - next * @param {Function} - end */ - async requestWatchAsset (req, res, next, end) { + async requestWatchAsset(req, res, next, end) { if ( req.method === 'metamask_watchAsset' || req.method === addInternalMethodPrefix('watchAsset') @@ -227,8 +232,10 @@ export default class PreferencesController { * @param {string} key - he preferred language locale key * */ - setCurrentLocale (key) { - const textDirection = (['ar', 'dv', 'fa', 'he', 'ku'].includes(key)) ? 'rtl' : 'auto' + setCurrentLocale(key) { + const textDirection = ['ar', 'dv', 'fa', 'he', 'ku'].includes(key) + ? 'rtl' + : 'auto' this.store.updateState({ currentLocale: key, textDirection, @@ -243,7 +250,7 @@ export default class PreferencesController { * @param {string[]} addresses - An array of hex addresses * */ - setAddresses (addresses) { + setAddresses(addresses) { const oldIdentities = this.store.getState().identities const oldAccountTokens = this.store.getState().accountTokens @@ -266,7 +273,7 @@ export default class PreferencesController { * @param {string} address - A hex address * @returns {string} - the address that was removed */ - removeAddress (address) { + removeAddress(address) { const { identities } = this.store.getState() const { accountTokens } = this.store.getState() if (!identities[address]) { @@ -291,7 +298,7 @@ export default class PreferencesController { * @param {string[]} addresses - An array of hex addresses * */ - addAddresses (addresses) { + addAddresses(addresses) { const { identities, accountTokens } = this.store.getState() addresses.forEach((address) => { // skip if already exists @@ -314,8 +321,7 @@ export default class PreferencesController { * @param {Array} addresses - known to the vault. * @returns {Promise} - selectedAddress the selected address. */ - syncAddresses (addresses) { - + syncAddresses(addresses) { if (!Array.isArray(addresses) || addresses.length === 0) { throw new Error('Expected non-empty array of addresses.') } @@ -332,7 +338,6 @@ export default class PreferencesController { // Identities are no longer present. if (Object.keys(newlyLost).length > 0) { - // store lost accounts Object.keys(newlyLost).forEach((key) => { lostIdentities[key] = newlyLost[key] @@ -353,7 +358,7 @@ export default class PreferencesController { return selected } - removeSuggestedTokens () { + removeSuggestedTokens() { return new Promise((resolve) => { this.store.updateState({ suggestedTokens: {} }) resolve({}) @@ -367,7 +372,7 @@ export default class PreferencesController { * @returns {Promise} - Promise resolves with tokens * */ - setSelectedAddress (_address) { + setSelectedAddress(_address) { const address = normalizeAddress(_address) this._updateTokens(address) @@ -388,7 +393,7 @@ export default class PreferencesController { * @returns {string} - The hex address for the currently selected account * */ - getSelectedAddress () { + getSelectedAddress() { return this.store.getState().selectedAddress } @@ -413,7 +418,7 @@ export default class PreferencesController { * @returns {Promise} - Promises the new array of AddedToken objects. * */ - async addToken (rawAddress, symbol, decimals, image) { + async addToken(rawAddress, symbol, decimals, image) { const address = normalizeAddress(rawAddress) const newEntry = { address, symbol, decimals } const { tokens } = this.store.getState() @@ -440,7 +445,7 @@ export default class PreferencesController { * @returns {Promise} - The new array of AddedToken objects * */ - removeToken (rawAddress) { + removeToken(rawAddress) { const { tokens } = this.store.getState() const assetImages = this.getAssetImages() const updatedTokens = tokens.filter((token) => token.address !== rawAddress) @@ -455,7 +460,7 @@ export default class PreferencesController { * @returns {array} - The current array of AddedToken objects * */ - getTokens () { + getTokens() { return this.store.getState().tokens } @@ -465,9 +470,11 @@ export default class PreferencesController { * @param {string} label - the custom label for the account * @returns {Promise} */ - setAccountLabel (account, label) { + setAccountLabel(account, label) { if (!account) { - throw new Error(`setAccountLabel requires a valid address, got ${String(account)}`) + throw new Error( + `setAccountLabel requires a valid address, got ${String(account)}`, + ) } const address = normalizeAddress(account) const { identities } = this.store.getState() @@ -488,7 +495,7 @@ export default class PreferencesController { * @param {Object} [newRpcDetails.rpcPrefs] - Optional RPC preferences, such as the block explorer URL * */ - async updateRpc (newRpcDetails) { + async updateRpc(newRpcDetails) { const rpcList = this.getFrequentRpcListDetail() const index = rpcList.findIndex((element) => { return element.rpcUrl === newRpcDetails.rpcUrl @@ -497,7 +504,6 @@ export default class PreferencesController { const rpcDetail = rpcList[index] const updatedRpc = { ...rpcDetail, ...newRpcDetails } if (rpcDetail.chainId !== updatedRpc.chainId) { - // When the chainId is changed, associated address book entries should // also be migrated. The address book entries are keyed by the `network` state, // which for custom networks is the chainId with a fallback to the networkId @@ -506,13 +512,17 @@ export default class PreferencesController { let addressBookKey = rpcDetail.chainId if (!addressBookKey) { // We need to find the networkId to determine what these addresses were keyed by - const provider = new ethers.providers.JsonRpcProvider(rpcDetail.rpcUrl) + const provider = new ethers.providers.JsonRpcProvider( + rpcDetail.rpcUrl, + ) try { addressBookKey = await provider.send('net_version') assert(typeof addressBookKey === 'string') } catch (error) { log.debug(error) - log.warn(`Failed to get networkId from ${rpcDetail.rpcUrl}; skipping address book migration`) + log.warn( + `Failed to get networkId from ${rpcDetail.rpcUrl}; skipping address book migration`, + ) } } @@ -521,10 +531,12 @@ export default class PreferencesController { // on both networks, since we don't know which network each contact is intended for. let duplicate = false - const builtInProviderNetworkIds = Object.values(NETWORK_TYPE_TO_ID_MAP) - .map((ids) => ids.networkId) - const otherRpcEntries = rpcList - .filter((entry) => entry.rpcUrl !== newRpcDetails.rpcUrl) + const builtInProviderNetworkIds = Object.values( + NETWORK_TYPE_TO_ID_MAP, + ).map((ids) => ids.networkId) + const otherRpcEntries = rpcList.filter( + (entry) => entry.rpcUrl !== newRpcDetails.rpcUrl, + ) if ( builtInProviderNetworkIds.includes(addressBookKey) || otherRpcEntries.some((entry) => entry.chainId === addressBookKey) @@ -532,7 +544,11 @@ export default class PreferencesController { duplicate = true } - this.migrateAddressBookState(addressBookKey, updatedRpc.chainId, duplicate) + this.migrateAddressBookState( + addressBookKey, + updatedRpc.chainId, + duplicate, + ) } rpcList[index] = updatedRpc this.store.updateState({ frequentRpcListDetail: rpcList }) @@ -552,7 +568,13 @@ export default class PreferencesController { * @param {Object} [rpcPrefs] - Optional RPC preferences, such as the block explorer URL * */ - addToFrequentRpcList (rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) { + addToFrequentRpcList( + rpcUrl, + chainId, + ticker = 'ETH', + nickname = '', + rpcPrefs = {}, + ) { const rpcList = this.getFrequentRpcListDetail() const index = rpcList.findIndex((element) => { @@ -577,7 +599,7 @@ export default class PreferencesController { * @returns {Promise} - Promise resolving to updated frequentRpcList. * */ - removeFromFrequentRpcList (url) { + removeFromFrequentRpcList(url) { const rpcList = this.getFrequentRpcListDetail() const index = rpcList.findIndex((element) => { return element.rpcUrl === url @@ -595,7 +617,7 @@ export default class PreferencesController { * @returns {array} - An array of rpc urls. * */ - getFrequentRpcListDetail () { + getFrequentRpcListDetail() { return this.store.getState().frequentRpcListDetail } @@ -607,7 +629,7 @@ export default class PreferencesController { * @returns {Promise} - Promises a new object; the updated featureFlags object. * */ - setFeatureFlag (feature, activated) { + setFeatureFlag(feature, activated) { const currentFeatureFlags = this.store.getState().featureFlags const updatedFeatureFlags = { ...currentFeatureFlags, @@ -626,7 +648,7 @@ export default class PreferencesController { * @param {boolean} value - Indicates whether or not the preference should be enabled or disabled. * @returns {Promise} - Promises a new object; the updated preferences object. */ - setPreference (preference, value) { + setPreference(preference, value) { const currentPreferences = this.getPreferences() const updatedPreferences = { ...currentPreferences, @@ -641,7 +663,7 @@ export default class PreferencesController { * A getter for the `preferences` property * @returns {Object} - A key-boolean map of user-selected preferences. */ - getPreferences () { + getPreferences() { return this.store.getState().preferences } @@ -649,7 +671,7 @@ export default class PreferencesController { * Sets the completedOnboarding state to true, indicating that the user has completed the * onboarding process. */ - completeOnboarding () { + completeOnboarding() { this.store.updateState({ completedOnboarding: true }) return Promise.resolve(true) } @@ -658,7 +680,7 @@ export default class PreferencesController { * A getter for the `ipfsGateway` property * @returns {string} - The current IPFS gateway domain */ - getIpfsGateway () { + getIpfsGateway() { return this.store.getState().ipfsGateway } @@ -667,7 +689,7 @@ export default class PreferencesController { * @param {string} domain - The new IPFS gateway domain * @returns {Promise} - A promise of the update IPFS gateway domain */ - setIpfsGateway (domain) { + setIpfsGateway(domain) { this.store.updateState({ ipfsGateway: domain }) return Promise.resolve(domain) } @@ -681,7 +703,7 @@ export default class PreferencesController { * * */ - _subscribeProviderType () { + _subscribeProviderType() { this.network.providerStore.subscribe(() => { const { tokens } = this._getTokenRelatedStates() this.store.updateState({ tokens }) @@ -694,8 +716,12 @@ export default class PreferencesController { * @param {array} tokens - Array of tokens to be updated. * */ - _updateAccountTokens (tokens, assetImages) { - const { accountTokens, providerType, selectedAddress } = this._getTokenRelatedStates() + _updateAccountTokens(tokens, assetImages) { + const { + accountTokens, + providerType, + selectedAddress, + } = this._getTokenRelatedStates() accountTokens[selectedAddress][providerType] = tokens this.store.updateState({ accountTokens, tokens, assetImages }) } @@ -706,7 +732,7 @@ export default class PreferencesController { * @param {string} selectedAddress - Account address to be updated with. * */ - _updateTokens (selectedAddress) { + _updateTokens(selectedAddress) { const { tokens } = this._getTokenRelatedStates(selectedAddress) this.store.updateState({ tokens }) } @@ -718,7 +744,7 @@ export default class PreferencesController { * @returns {Object.} - States to interact with tokens in `accountTokens` * */ - _getTokenRelatedStates (selectedAddress) { + _getTokenRelatedStates(selectedAddress) { const { accountTokens } = this.store.getState() if (!selectedAddress) { // eslint-disable-next-line no-param-reassign @@ -741,7 +767,7 @@ export default class PreferencesController { * @param {Promise} promise - Promise according to addition of ERC20 token * */ - async _handleWatchAssetERC20 (options) { + async _handleWatchAssetERC20(options) { const { address, symbol, decimals, image } = options const rawAddress = address try { @@ -752,7 +778,9 @@ export default class PreferencesController { const tokenOpts = { rawAddress, decimals, symbol, image } this.addSuggestedERC20Asset(tokenOpts) return this.openPopup().then(() => { - const tokenAddresses = this.getTokens().filter((token) => token.address === normalizeAddress(rawAddress)) + const tokenAddresses = this.getTokens().filter( + (token) => token.address === normalizeAddress(rawAddress), + ) return tokenAddresses.length > 0 }) } @@ -765,17 +793,21 @@ export default class PreferencesController { * doesn't fulfill requirements * */ - _validateERC20AssetParams (opts) { + _validateERC20AssetParams(opts) { const { rawAddress, symbol, decimals } = opts if (!rawAddress || !symbol || typeof decimals === 'undefined') { - throw new Error(`Cannot suggest token without address, symbol, and decimals`) + throw new Error( + `Cannot suggest token without address, symbol, and decimals`, + ) } if (!(symbol.length < 7)) { throw new Error(`Invalid symbol ${symbol} more than six characters`) } const numDecimals = parseInt(decimals, 10) if (isNaN(numDecimals) || numDecimals > 36 || numDecimals < 0) { - throw new Error(`Invalid decimals ${decimals} must be at least 0, and not over 36`) + throw new Error( + `Invalid decimals ${decimals} must be at least 0, and not over 36`, + ) } if (!isValidAddress(rawAddress)) { throw new Error(`Invalid address ${rawAddress}`) diff --git a/app/scripts/controllers/swaps.js b/app/scripts/controllers/swaps.js index da3d226fe..3b964d9a8 100644 --- a/app/scripts/controllers/swaps.js +++ b/app/scripts/controllers/swaps.js @@ -28,17 +28,14 @@ const MAX_GAS_LIMIT = 2500000 // 3 seems to be an appropriate balance of giving users the time they need when MetaMask is not left idle, and turning polling off when it is. const POLL_COUNT_LIMIT = 3 -function calculateGasEstimateWithRefund (maxGas = MAX_GAS_LIMIT, estimatedRefund = 0, estimatedGas = 0) { - const maxGasMinusRefund = new BigNumber( - maxGas, - 10, - ) - .minus(estimatedRefund, 10) +function calculateGasEstimateWithRefund( + maxGas = MAX_GAS_LIMIT, + estimatedRefund = 0, + estimatedGas = 0, +) { + const maxGasMinusRefund = new BigNumber(maxGas, 10).minus(estimatedRefund, 10) - const gasEstimateWithRefund = maxGasMinusRefund.lt( - estimatedGas, - 16, - ) + const gasEstimateWithRefund = maxGasMinusRefund.lt(estimatedGas, 16) ? maxGasMinusRefund.toString(16) : estimatedGas @@ -68,7 +65,7 @@ const initialState = { } export default class SwapsController { - constructor ({ + constructor({ getBufferedGasLimit, networkController, provider, @@ -108,18 +105,26 @@ export default class SwapsController { // that quotes will no longer be available after 1 or 2 minutes. When fetchAndSetQuotes is first called it, receives fetch that parameters are stored in // state. These stored parameters are used on subsequent calls made during polling. // Note: we stop polling after 3 requests, until new quotes are explicitly asked for. The logic that enforces that maximum is in the body of fetchAndSetQuotes - pollForNewQuotes () { + pollForNewQuotes() { this.pollingTimeout = setTimeout(() => { const { swapsState } = this.store.getState() - this.fetchAndSetQuotes(swapsState.fetchParams, swapsState.fetchParams?.metaData, true) + this.fetchAndSetQuotes( + swapsState.fetchParams, + swapsState.fetchParams?.metaData, + true, + ) }, QUOTE_POLLING_INTERVAL) } - stopPollingForQuotes () { + stopPollingForQuotes() { clearTimeout(this.pollingTimeout) } - async fetchAndSetQuotes (fetchParams, fetchParamsMetaData = {}, isPolledRequest) { + async fetchAndSetQuotes( + fetchParams, + fetchParamsMetaData = {}, + isPolledRequest, + ) { if (!fetchParams) { return null } @@ -150,7 +155,10 @@ export default class SwapsController { const quotesLastFetched = Date.now() let approvalRequired = false - if (fetchParams.sourceToken !== ETH_SWAPS_TOKEN_ADDRESS && Object.values(newQuotes).length) { + if ( + fetchParams.sourceToken !== ETH_SWAPS_TOKEN_ADDRESS && + Object.values(newQuotes).length + ) { const allowance = await this._getERC20Allowance( fetchParams.sourceToken, fetchParams.fromAddress, @@ -167,7 +175,9 @@ export default class SwapsController { approvalNeeded: null, })) } else if (!isPolledRequest) { - const { gasLimit: approvalGas } = await this.timedoutGasReturn(Object.values(newQuotes)[0].approvalNeeded) + const { gasLimit: approvalGas } = await this.timedoutGasReturn( + Object.values(newQuotes)[0].approvalNeeded, + ) newQuotes = mapValues(newQuotes, (quote) => ({ ...quote, @@ -190,7 +200,9 @@ export default class SwapsController { if (Object.values(newQuotes).length === 0) { this.setSwapsErrorKey(QUOTES_NOT_AVAILABLE_ERROR) } else { - const topQuoteData = await this._findTopQuoteAndCalculateSavings(newQuotes) + const topQuoteData = await this._findTopQuoteAndCalculateSavings( + newQuotes, + ) if (topQuoteData.topAggId) { topAggId = topQuoteData.topAggId @@ -235,32 +247,34 @@ export default class SwapsController { return [newQuotes, topAggId] } - safeRefetchQuotes () { + safeRefetchQuotes() { const { swapsState } = this.store.getState() if (!this.pollingTimeout && swapsState.fetchParams) { this.fetchAndSetQuotes(swapsState.fetchParams) } } - setSelectedQuoteAggId (selectedAggId) { + setSelectedQuoteAggId(selectedAggId) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, selectedAggId } }) } - setSwapsTokens (tokens) { + setSwapsTokens(tokens) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, tokens } }) } - setSwapsErrorKey (errorKey) { + setSwapsErrorKey(errorKey) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, errorKey } }) } - async getAllQuotesWithGasEstimates (quotes) { + async getAllQuotesWithGasEstimates(quotes) { const quoteGasData = await Promise.all( Object.values(quotes).map(async (quote) => { - const { gasLimit, simulationFails } = await this.timedoutGasReturn(quote.trade) + const { gasLimit, simulationFails } = await this.timedoutGasReturn( + quote.trade, + ) return [gasLimit, simulationFails, quote.aggregator] }), ) @@ -268,7 +282,11 @@ export default class SwapsController { const newQuotes = {} quoteGasData.forEach(([gasLimit, simulationFails, aggId]) => { if (gasLimit && !simulationFails) { - const gasEstimateWithRefund = calculateGasEstimateWithRefund(quotes[aggId].maxGas, quotes[aggId].estimatedRefund, gasLimit) + const gasEstimateWithRefund = calculateGasEstimateWithRefund( + quotes[aggId].maxGas, + quotes[aggId].estimatedRefund, + gasLimit, + ) newQuotes[aggId] = { ...quotes[aggId], @@ -285,7 +303,7 @@ export default class SwapsController { return newQuotes } - timedoutGasReturn (tradeTxParams) { + timedoutGasReturn(tradeTxParams) { return new Promise((resolve) => { let gasTimedOut = false @@ -321,7 +339,7 @@ export default class SwapsController { }) } - async setInitialGasEstimate (initialAggId) { + async setInitialGasEstimate(initialAggId) { const { swapsState } = this.store.getState() const quoteToUpdate = { ...swapsState.quotes[initialAggId] } @@ -332,64 +350,73 @@ export default class SwapsController { } = await this.timedoutGasReturn(quoteToUpdate.trade) if (newGasEstimate && !simulationFails) { - const gasEstimateWithRefund = calculateGasEstimateWithRefund(quoteToUpdate.maxGas, quoteToUpdate.estimatedRefund, newGasEstimate) + const gasEstimateWithRefund = calculateGasEstimateWithRefund( + quoteToUpdate.maxGas, + quoteToUpdate.estimatedRefund, + newGasEstimate, + ) quoteToUpdate.gasEstimate = newGasEstimate quoteToUpdate.gasEstimateWithRefund = gasEstimateWithRefund } this.store.updateState({ - swapsState: { ...swapsState, quotes: { ...swapsState.quotes, [initialAggId]: quoteToUpdate } }, + swapsState: { + ...swapsState, + quotes: { ...swapsState.quotes, [initialAggId]: quoteToUpdate }, + }, }) } - setApproveTxId (approveTxId) { + setApproveTxId(approveTxId) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, approveTxId } }) } - setTradeTxId (tradeTxId) { + setTradeTxId(tradeTxId) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, tradeTxId } }) } - setQuotesLastFetched (quotesLastFetched) { + setQuotesLastFetched(quotesLastFetched) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, quotesLastFetched } }) } - setSwapsTxGasPrice (gasPrice) { + setSwapsTxGasPrice(gasPrice) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, customGasPrice: gasPrice }, }) } - setSwapsTxGasLimit (gasLimit) { + setSwapsTxGasLimit(gasLimit) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, customMaxGas: gasLimit }, }) } - setCustomApproveTxData (data) { + setCustomApproveTxData(data) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, customApproveTxData: data }, }) } - setBackgroundSwapRouteState (routeState) { + setBackgroundSwapRouteState(routeState) { const { swapsState } = this.store.getState() this.store.updateState({ swapsState: { ...swapsState, routeState } }) } - setSwapsLiveness (swapsFeatureIsLive) { + setSwapsLiveness(swapsFeatureIsLive) { const { swapsState } = this.store.getState() - this.store.updateState({ swapsState: { ...swapsState, swapsFeatureIsLive } }) + this.store.updateState({ + swapsState: { ...swapsState, swapsFeatureIsLive }, + }) } - resetPostFetchState () { + resetPostFetchState() { const { swapsState } = this.store.getState() this.store.updateState({ @@ -403,21 +430,25 @@ export default class SwapsController { clearTimeout(this.pollingTimeout) } - resetSwapsState () { + resetSwapsState() { const { swapsState } = this.store.getState() this.store.updateState({ - swapsState: { ...initialState.swapsState, tokens: swapsState.tokens, swapsFeatureIsLive: swapsState.swapsFeatureIsLive }, + swapsState: { + ...initialState.swapsState, + tokens: swapsState.tokens, + swapsFeatureIsLive: swapsState.swapsFeatureIsLive, + }, }) clearTimeout(this.pollingTimeout) } - async _getEthersGasPrice () { + async _getEthersGasPrice() { const ethersGasPrice = await this.ethersProvider.getGasPrice() return ethersGasPrice.toHexString() } - async _findTopQuoteAndCalculateSavings (quotes = {}) { + async _findTopQuoteAndCalculateSavings(quotes = {}) { const tokenConversionRates = this.tokenRatesStore.getState() .contractExchangeRates const { @@ -429,7 +460,7 @@ export default class SwapsController { return {} } - const usedGasPrice = customGasPrice || await this._getEthersGasPrice() + const usedGasPrice = customGasPrice || (await this._getEthersGasPrice()) let topAggId = '' let ethTradeValueOfBestQuote = null @@ -468,8 +499,10 @@ export default class SwapsController { // It always includes any external fees charged by the quote source. In // addition, if the source asset is ETH, trade.value includes the amount // of swapped ETH. - const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16) - .plus(trade.value, 16) + const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16).plus( + trade.value, + 16, + ) const totalEthCost = conversionUtil(totalWeiCost, { fromCurrency: 'ETH', @@ -482,32 +515,33 @@ export default class SwapsController { // The total fee is aggregator/exchange fees plus gas fees. // If the swap is from ETH, subtract the sourceAmount from the total cost. // Otherwise, the total fee is simply trade.value plus gas fees. - const ethFee = sourceToken === ETH_SWAPS_TOKEN_ADDRESS - ? conversionUtil( - totalWeiCost.minus(sourceAmount, 10), // sourceAmount is in wei - { - fromCurrency: 'ETH', - fromDenomination: 'WEI', - toDenomination: 'ETH', - fromNumericBase: 'BN', - numberOfDecimals: 6, - }, - ) - : totalEthCost + const ethFee = + sourceToken === ETH_SWAPS_TOKEN_ADDRESS + ? conversionUtil( + totalWeiCost.minus(sourceAmount, 10), // sourceAmount is in wei + { + fromCurrency: 'ETH', + fromDenomination: 'WEI', + toDenomination: 'ETH', + fromNumericBase: 'BN', + numberOfDecimals: 6, + }, + ) + : totalEthCost const tokenConversionRate = tokenConversionRates[destinationToken] const ethValueOfTrade = destinationToken === ETH_SWAPS_TOKEN_ADDRESS ? calcTokenAmount(destinationAmount, 18).minus(totalEthCost, 10) : new BigNumber(tokenConversionRate || 1, 10) - .times( - calcTokenAmount( - destinationAmount, - destinationTokenInfo.decimals, - ), - 10, - ) - .minus(tokenConversionRate ? totalEthCost : 0, 10) + .times( + calcTokenAmount( + destinationAmount, + destinationTokenInfo.decimals, + ), + 10, + ) + .minus(tokenConversionRate ? totalEthCost : 0, 10) // collect values for savings calculation allEthTradeValues.push(ethValueOfTrade) @@ -540,10 +574,7 @@ export default class SwapsController { // Performance savings are calculated as: // medianFeeOfAllTrades - feeForBestTrade - savings.fee = getMedian(allEthFees).minus( - ethFeeForBestQuote, - 10, - ) + savings.fee = getMedian(allEthFees).minus(ethFeeForBestQuote, 10) // Total savings are the sum of performance and fee savings savings.total = savings.performance.plus(savings.fee, 10).toString(10) @@ -554,9 +585,11 @@ export default class SwapsController { return { topAggId, isBest, savings } } - async _getERC20Allowance (contractAddress, walletAddress) { + async _getERC20Allowance(contractAddress, walletAddress) { const contract = new ethers.Contract( - contractAddress, abi, this.ethersProvider, + contractAddress, + abi, + this.ethersProvider, ) return await contract.allowance(walletAddress, METASWAP_ADDRESS) } @@ -569,7 +602,7 @@ export default class SwapsController { * If the browser goes offline, the interval is cleared and swaps are disabled * until the value can be fetched again. */ - _setupSwapsLivenessFetching () { + _setupSwapsLivenessFetching() { const TEN_MINUTES_MS = 10 * 60 * 1000 let intervalId = null @@ -577,7 +610,10 @@ export default class SwapsController { if (window.navigator.onLine && intervalId === null) { // Set the interval first to prevent race condition between listener and // initial call to this function. - intervalId = setInterval(this._fetchAndSetSwapsLiveness.bind(this), TEN_MINUTES_MS) + intervalId = setInterval( + this._fetchAndSetSwapsLiveness.bind(this), + TEN_MINUTES_MS, + ) this._fetchAndSetSwapsLiveness() } } @@ -608,7 +644,7 @@ export default class SwapsController { * Only updates state if the fetched/computed flag value differs from current * state. */ - async _fetchAndSetSwapsLiveness () { + async _fetchAndSetSwapsLiveness() { const { swapsState } = this.store.getState() const { swapsFeatureIsLive: oldSwapsFeatureIsLive } = swapsState let swapsFeatureIsLive = false @@ -637,7 +673,9 @@ export default class SwapsController { } if (!successfullyFetched) { - log.error('Failed to fetch swaps feature flag 3 times. Setting to false and trying again next interval.') + log.error( + 'Failed to fetch swaps feature flag 3 times. Setting to false and trying again next interval.', + ) } if (swapsFeatureIsLive !== oldSwapsFeatureIsLive) { @@ -653,7 +691,7 @@ export default class SwapsController { * values. The array will be sorted in place. * @returns {import('bignumber.js').BigNumber} The median of the sample. */ -function getMedian (values) { +function getMedian(values) { if (!Array.isArray(values) || values.length === 0) { throw new Error('Expected non-empty array param.') } @@ -672,9 +710,7 @@ function getMedian (values) { // return mean of middle two values const upperIndex = values.length / 2 - return values[upperIndex] - .plus(values[upperIndex - 1]) - .dividedBy(2) + return values[upperIndex].plus(values[upperIndex - 1]).dividedBy(2) } export const utils = { diff --git a/app/scripts/controllers/threebox.js b/app/scripts/controllers/threebox.js index be6c2fa0a..2459d79e2 100644 --- a/app/scripts/controllers/threebox.js +++ b/app/scripts/controllers/threebox.js @@ -18,7 +18,7 @@ import createMetamaskMiddleware from './network/createMetamaskMiddleware' const SYNC_TIMEOUT = 60 * 1000 // one minute export default class ThreeBoxController { - constructor (opts = {}) { + constructor(opts = {}) { const { preferencesController, keyringController, @@ -41,16 +41,22 @@ export default class ThreeBoxController { const accounts = await this.keyringController.getAccounts() if (isUnlocked && accounts[0]) { - const appKeyAddress = await this.keyringController.getAppKeyAddress(accounts[0], 'wallet://3box.metamask.io') + const appKeyAddress = await this.keyringController.getAppKeyAddress( + accounts[0], + 'wallet://3box.metamask.io', + ) return [appKeyAddress] } return [] }, processPersonalMessage: async (msgParams) => { const accounts = await this.keyringController.getAccounts() - return keyringController.signPersonalMessage({ ...msgParams, from: accounts[0] }, { - withAppKeyOrigin: 'wallet://3box.metamask.io', - }) + return keyringController.signPersonalMessage( + { ...msgParams, from: accounts[0] }, + { + withAppKeyOrigin: 'wallet://3box.metamask.io', + }, + ) }, }) @@ -65,14 +71,16 @@ export default class ThreeBoxController { } this.store = new ObservableStore(initState) this.registeringUpdates = false - this.lastMigration = migrations.sort((a, b) => a.version - b.version).slice(-1)[0] + this.lastMigration = migrations + .sort((a, b) => a.version - b.version) + .slice(-1)[0] if (initState.threeBoxSyncingAllowed) { this.init() } } - async init () { + async init() { const accounts = await this.keyringController.getAccounts() this.address = accounts[0] if (this.address && !(this.box && this.store.getState().threeBoxSynced)) { @@ -80,7 +88,7 @@ export default class ThreeBoxController { } } - async _update3Box () { + async _update3Box() { try { const { threeBoxSyncingAllowed, threeBoxSynced } = this.store.getState() if (threeBoxSyncingAllowed && threeBoxSynced) { @@ -99,7 +107,7 @@ export default class ThreeBoxController { } } - _createProvider (providerOpts) { + _createProvider(providerOpts) { const metamaskMiddleware = createMetamaskMiddleware(providerOpts) const engine = new JsonRpcEngine() engine.push(createOriginMiddleware({ origin: '3Box' })) @@ -108,7 +116,7 @@ export default class ThreeBoxController { return provider } - _waitForOnSyncDone () { + _waitForOnSyncDone() { return new Promise((resolve) => { this.box.onSyncDone(() => { log.debug('3Box box sync done') @@ -117,9 +125,12 @@ export default class ThreeBoxController { }) } - async new3Box () { + async new3Box() { const accounts = await this.keyringController.getAccounts() - this.address = await this.keyringController.getAppKeyAddress(accounts[0], 'wallet://3box.metamask.io') + this.address = await this.keyringController.getAppKeyAddress( + accounts[0], + 'wallet://3box.metamask.io', + ) let backupExists try { const threeBoxConfig = await Box.getConfig(this.address) @@ -170,20 +181,22 @@ export default class ThreeBoxController { } } - async getLastUpdated () { + async getLastUpdated() { const res = await this.space.private.get('metamaskBackup') const parsedRes = JSON.parse(res || '{}') return parsedRes.lastUpdated } - async migrateBackedUpState (backedUpState) { + async migrateBackedUpState(backedUpState) { const migrator = new Migrator({ migrations }) const { preferences, addressBook } = JSON.parse(backedUpState) const formattedStateBackup = { PreferencesController: preferences, AddressBookController: addressBook, } - const initialMigrationState = migrator.generateInitialState(formattedStateBackup) + const initialMigrationState = migrator.generateInitialState( + formattedStateBackup, + ) const migratedState = await migrator.migrateData(initialMigrationState) return { preferences: migratedState.data.PreferencesController, @@ -191,31 +204,30 @@ export default class ThreeBoxController { } } - async restoreFromThreeBox () { + async restoreFromThreeBox() { const backedUpState = await this.space.private.get('metamaskBackup') - const { - preferences, - addressBook, - } = await this.migrateBackedUpState(backedUpState) + const { preferences, addressBook } = await this.migrateBackedUpState( + backedUpState, + ) this.store.updateState({ threeBoxLastUpdated: backedUpState.lastUpdated }) preferences && this.preferencesController.store.updateState(preferences) addressBook && this.addressBookController.update(addressBook, true) this.setShowRestorePromptToFalse() } - turnThreeBoxSyncingOn () { + turnThreeBoxSyncingOn() { this._registerUpdates() } - turnThreeBoxSyncingOff () { + turnThreeBoxSyncingOff() { this.box.logout() } - setShowRestorePromptToFalse () { + setShowRestorePromptToFalse() { this.store.updateState({ showRestorePrompt: false }) } - setThreeBoxSyncingPermission (newThreeboxSyncingState) { + setThreeBoxSyncingPermission(newThreeboxSyncingState) { if (this.store.getState().threeBoxDisabled) { return } @@ -232,11 +244,11 @@ export default class ThreeBoxController { } } - getThreeBoxSyncingState () { + getThreeBoxSyncingState() { return this.store.getState().threeBoxSyncingAllowed } - _registerUpdates () { + _registerUpdates() { if (!this.registeringUpdates) { const updatePreferences = this._update3Box.bind(this) this.preferencesController.store.subscribe(updatePreferences) diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js index c3e872ca2..b943c540f 100644 --- a/app/scripts/controllers/token-rates.js +++ b/app/scripts/controllers/token-rates.js @@ -11,13 +11,12 @@ const DEFAULT_INTERVAL = 180 * 1000 * rates based on a user's current token list */ export default class TokenRatesController { - /** * Creates a TokenRatesController * * @param {Object} [config] - Options to configure controller */ - constructor ({ currency, preferences } = {}) { + constructor({ currency, preferences } = {}) { this.store = new ObservableStore() this.currency = currency this.preferences = preferences @@ -26,21 +25,32 @@ export default class TokenRatesController { /** * Updates exchange rates for all tokens */ - async updateExchangeRates () { + async updateExchangeRates() { const contractExchangeRates = {} - const nativeCurrency = this.currency ? this.currency.state.nativeCurrency.toLowerCase() : 'eth' + const nativeCurrency = this.currency + ? this.currency.state.nativeCurrency.toLowerCase() + : 'eth' const pairs = this._tokens.map((token) => token.address).join(',') const query = `contract_addresses=${pairs}&vs_currencies=${nativeCurrency}` if (this._tokens.length > 0) { try { - const response = await window.fetch(`https://api.coingecko.com/api/v3/simple/token_price/ethereum?${query}`) + const response = await window.fetch( + `https://api.coingecko.com/api/v3/simple/token_price/ethereum?${query}`, + ) const prices = await response.json() this._tokens.forEach((token) => { - const price = prices[token.address.toLowerCase()] || prices[ethUtil.toChecksumAddress(token.address)] - contractExchangeRates[normalizeAddress(token.address)] = price ? price[nativeCurrency] : 0 + const price = + prices[token.address.toLowerCase()] || + prices[ethUtil.toChecksumAddress(token.address)] + contractExchangeRates[normalizeAddress(token.address)] = price + ? price[nativeCurrency] + : 0 }) } catch (error) { - log.warn(`MetaMask - TokenRatesController exchange rate fetch failed.`, error) + log.warn( + `MetaMask - TokenRatesController exchange rate fetch failed.`, + error, + ) } } this.store.putState({ contractExchangeRates }) @@ -50,7 +60,7 @@ export default class TokenRatesController { /** * @type {Object} */ - set preferences (preferences) { + set preferences(preferences) { this._preferences && this._preferences.unsubscribe() if (!preferences) { return @@ -65,13 +75,13 @@ export default class TokenRatesController { /** * @type {Array} */ - set tokens (tokens) { + set tokens(tokens) { this._tokens = tokens this.updateExchangeRates() } /* eslint-enable accessor-pairs */ - start (interval = DEFAULT_INTERVAL) { + start(interval = DEFAULT_INTERVAL) { this._handle && clearInterval(this._handle) if (!interval) { return @@ -82,7 +92,7 @@ export default class TokenRatesController { this.updateExchangeRates() } - stop () { + stop() { this._handle && clearInterval(this._handle) } } diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 4ec69ff46..3e618743b 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -66,7 +66,7 @@ const MAX_MEMSTORE_TX_LIST_SIZE = 100 // Number of transactions (by unique nonce */ export default class TransactionController extends EventEmitter { - constructor (opts) { + constructor(opts) { super() this.networkStore = opts.networkStore || new ObservableStore({}) this._getCurrentChainId = opts.getCurrentChainId @@ -95,8 +95,12 @@ export default class TransactionController extends EventEmitter { this.nonceTracker = new NonceTracker({ provider: this.provider, blockTracker: this.blockTracker, - getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager), - getConfirmedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager), + getPendingTransactions: this.txStateManager.getPendingTransactions.bind( + this.txStateManager, + ), + getConfirmedTransactions: this.txStateManager.getConfirmedTransactions.bind( + this.txStateManager, + ), }) this.pendingTxTracker = new PendingTransactionTracker({ @@ -109,7 +113,9 @@ export default class TransactionController extends EventEmitter { return [...pending, ...approved] }, approveTransaction: this.approveTransaction.bind(this), - getCompletedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager), + getCompletedTransactions: this.txStateManager.getConfirmedTransactions.bind( + this.txStateManager, + ), }) this.txStateManager.store.subscribe(() => this.emit('update:badge')) @@ -132,7 +138,7 @@ export default class TransactionController extends EventEmitter { * * @returns {number} The numerical chainId. */ - getChainId () { + getChainId() { const networkState = this.networkStore.getState() const chainId = this._getCurrentChainId() const integerChainId = parseInt(chainId, 16) @@ -146,7 +152,7 @@ export default class TransactionController extends EventEmitter { Adds a tx to the txlist @emits ${txMeta.id}:unapproved */ - addTx (txMeta) { + addTx(txMeta) { this.txStateManager.addTx(txMeta) this.emit(`${txMeta.id}:unapproved`, txMeta) } @@ -155,37 +161,62 @@ export default class TransactionController extends EventEmitter { Wipes the transactions for a given account @param {string} address - hex string of the from address for txs being removed */ - wipeTransactions (address) { + wipeTransactions(address) { this.txStateManager.wipeTransactions(address) } /** - * Add a new unapproved transaction to the pipeline - * - * @returns {Promise} - the hash of the transaction after being submitted to the network - * @param {Object} txParams - txParams for the transaction - * @param {Object} opts - with the key origin to put the origin on the txMeta - */ - async newUnapprovedTransaction (txParams, opts = {}) { + * Add a new unapproved transaction to the pipeline + * + * @returns {Promise} - the hash of the transaction after being submitted to the network + * @param {Object} txParams - txParams for the transaction + * @param {Object} opts - with the key origin to put the origin on the txMeta + */ + async newUnapprovedTransaction(txParams, opts = {}) { + log.debug( + `MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`, + ) - log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) - - const initialTxMeta = await this.addUnapprovedTransaction(txParams, opts.origin) + const initialTxMeta = await this.addUnapprovedTransaction( + txParams, + opts.origin, + ) // listen for tx completion (success, fail) return new Promise((resolve, reject) => { - this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => { - switch (finishedTxMeta.status) { - case 'submitted': - return resolve(finishedTxMeta.hash) - case 'rejected': - return reject(cleanErrorStack(ethErrors.provider.userRejectedRequest('MetaMask Tx Signature: User denied transaction signature.'))) - case 'failed': - return reject(cleanErrorStack(ethErrors.rpc.internal(finishedTxMeta.err.message))) - default: - return reject(cleanErrorStack(ethErrors.rpc.internal(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))) - } - }) + this.txStateManager.once( + `${initialTxMeta.id}:finished`, + (finishedTxMeta) => { + switch (finishedTxMeta.status) { + case 'submitted': + return resolve(finishedTxMeta.hash) + case 'rejected': + return reject( + cleanErrorStack( + ethErrors.provider.userRejectedRequest( + 'MetaMask Tx Signature: User denied transaction signature.', + ), + ), + ) + case 'failed': + return reject( + cleanErrorStack( + ethErrors.rpc.internal(finishedTxMeta.err.message), + ), + ) + default: + return reject( + cleanErrorStack( + ethErrors.rpc.internal( + `MetaMask Tx Signature: Unknown problem: ${JSON.stringify( + finishedTxMeta.txParams, + )}`, + ), + ), + ) + } + }, + ) }) } @@ -195,8 +226,7 @@ export default class TransactionController extends EventEmitter { * * @returns {txMeta} */ - async addUnapprovedTransaction (txParams, origin) { - + async addUnapprovedTransaction(txParams, origin) { // validate const normalizedTxParams = txUtils.normalizeTxParams(txParams) @@ -236,7 +266,10 @@ export default class TransactionController extends EventEmitter { txMeta.origin = origin - const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams) + const { + transactionCategory, + getCodeResponse, + } = await this._determineTransactionCategory(txParams) txMeta.transactionCategory = transactionCategory // ensure value @@ -269,9 +302,12 @@ export default class TransactionController extends EventEmitter { * @param {Object} txMeta - the txMeta object * @returns {Promise} - resolves with txMeta */ - async addTxGasDefaults (txMeta, getCodeResponse) { + async addTxGasDefaults(txMeta, getCodeResponse) { const defaultGasPrice = await this._getDefaultGasPrice(txMeta) - const { gasLimit: defaultGasLimit, simulationFails } = await this._getDefaultGasLimit(txMeta, getCodeResponse) + const { + gasLimit: defaultGasLimit, + simulationFails, + } = await this._getDefaultGasLimit(txMeta, getCodeResponse) // eslint-disable-next-line no-param-reassign txMeta = this.txStateManager.getTx(txMeta.id) @@ -292,7 +328,7 @@ export default class TransactionController extends EventEmitter { * @param {Object} txMeta - The txMeta object * @returns {Promise} The default gas price */ - async _getDefaultGasPrice (txMeta) { + async _getDefaultGasPrice(txMeta) { if (txMeta.txParams.gasPrice) { return undefined } @@ -307,7 +343,7 @@ export default class TransactionController extends EventEmitter { * @param {string} getCodeResponse - The transaction category code response, used for debugging purposes * @returns {Promise} Object containing the default gas limit, or the simulation failure object */ - async _getDefaultGasLimit (txMeta, getCodeResponse) { + async _getDefaultGasLimit(txMeta, getCodeResponse) { if (txMeta.txParams.gas) { return {} } else if ( @@ -316,7 +352,9 @@ export default class TransactionController extends EventEmitter { ) { // if there's data in the params, but there's no contract code, it's not a valid transaction if (txMeta.txParams.data) { - const err = new Error('TxGasUtil - Trying to call a function on a non-contract address') + const err = new Error( + 'TxGasUtil - Trying to call a function on a non-contract address', + ) // set error key so ui can display localized error message err.errorKey = TRANSACTION_NO_CONTRACT_ERROR_KEY @@ -329,10 +367,17 @@ export default class TransactionController extends EventEmitter { return { gasLimit: SIMPLE_GAS_COST } } - const { blockGasLimit, estimatedGasHex, simulationFails } = await this.txGasUtil.analyzeGasUsage(txMeta) + const { + blockGasLimit, + estimatedGasHex, + simulationFails, + } = await this.txGasUtil.analyzeGasUsage(txMeta) // add additional gas buffer to our estimation for safety - const gasLimit = this.txGasUtil.addGasBuffer(ethUtil.addHexPrefix(estimatedGasHex), blockGasLimit) + const gasLimit = this.txGasUtil.addGasBuffer( + ethUtil.addHexPrefix(estimatedGasHex), + blockGasLimit, + ) return { gasLimit, simulationFails } } @@ -344,12 +389,14 @@ export default class TransactionController extends EventEmitter { * @param {string} [customGasPrice] - the hex value to use for the cancel transaction * @returns {txMeta} */ - async createCancelTransaction (originalTxId, customGasPrice) { + async createCancelTransaction(originalTxId, customGasPrice) { const originalTxMeta = this.txStateManager.getTx(originalTxId) const { txParams } = originalTxMeta const { gasPrice: lastGasPrice, from, nonce } = txParams - const newGasPrice = customGasPrice || bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10)) + const newGasPrice = + customGasPrice || + bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10)) const newTxMeta = this.txStateManager.generateTxMeta({ txParams: { from, @@ -380,12 +427,14 @@ export default class TransactionController extends EventEmitter { * @param {string} [customGasLimit] - The new custom gas limt, in hex * @returns {txMeta} */ - async createSpeedUpTransaction (originalTxId, customGasPrice, customGasLimit) { + async createSpeedUpTransaction(originalTxId, customGasPrice, customGasLimit) { const originalTxMeta = this.txStateManager.getTx(originalTxId) const { txParams } = originalTxMeta const { gasPrice: lastGasPrice } = txParams - const newGasPrice = customGasPrice || bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10)) + const newGasPrice = + customGasPrice || + bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10)) const newTxMeta = this.txStateManager.generateTxMeta({ txParams: { @@ -411,7 +460,7 @@ export default class TransactionController extends EventEmitter { updates the txMeta in the txStateManager @param {Object} txMeta - the updated txMeta */ - async updateTransaction (txMeta) { + async updateTransaction(txMeta) { this.txStateManager.updateTx(txMeta, 'confTx: user updated transaction') } @@ -419,7 +468,7 @@ export default class TransactionController extends EventEmitter { updates and approves the transaction @param {Object} txMeta */ - async updateAndApproveTransaction (txMeta) { + async updateAndApproveTransaction(txMeta) { this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction') await this.approveTransaction(txMeta.id) } @@ -432,7 +481,7 @@ export default class TransactionController extends EventEmitter { if any of these steps fails the tx status will be set to failed @param {number} txId - the tx's Id */ - async approveTransaction (txId) { + async approveTransaction(txId) { // TODO: Move this safety out of this function. // Since this transaction is async, // we need to keep track of what is currently being signed, @@ -456,8 +505,11 @@ export default class TransactionController extends EventEmitter { // add nonce to txParams // if txMeta has lastGasPrice then it is a retry at same nonce with higher // gas price transaction and their for the nonce should not be calculated - const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce - const customOrNonce = (customNonceValue === 0) ? customNonceValue : customNonceValue || nonce + const nonce = txMeta.lastGasPrice + ? txMeta.txParams.nonce + : nonceLock.nextNonce + const customOrNonce = + customNonceValue === 0 ? customNonceValue : customNonceValue || nonce txMeta.txParams.nonce = ethUtil.addHexPrefix(customOrNonce.toString(16)) // add nonce debugging information to txMeta @@ -494,7 +546,7 @@ export default class TransactionController extends EventEmitter { @param {number} txId - the tx's Id @returns {string} - rawTx */ - async signTransaction (txId) { + async signTransaction(txId) { const txMeta = this.txStateManager.getTx(txId) // add network/chain id const chainId = this.getChainId() @@ -510,7 +562,10 @@ export default class TransactionController extends EventEmitter { txMeta.s = ethUtil.bufferToHex(ethTx.s) txMeta.v = ethUtil.bufferToHex(ethTx.v) - this.txStateManager.updateTx(txMeta, 'transactions#signTransaction: add r, s, v values') + this.txStateManager.updateTx( + txMeta, + 'transactions#signTransaction: add r, s, v values', + ) // set state to signed this.txStateManager.setTxStatusSigned(txMeta.id) @@ -524,7 +579,7 @@ export default class TransactionController extends EventEmitter { @param {string} rawTx - the hex string of the serialized signed transaction @returns {Promise} */ - async publishTransaction (txId, rawTx) { + async publishTransaction(txId, rawTx) { const txMeta = this.txStateManager.getTx(txId) txMeta.rawTx = rawTx if (txMeta.transactionCategory === SWAP) { @@ -554,7 +609,7 @@ export default class TransactionController extends EventEmitter { * @param {number} txId - The tx's ID * @returns {Promise} */ - async confirmTransaction (txId, txReceipt) { + async confirmTransaction(txId, txReceipt) { // get the txReceipt before marking the transaction confirmed // to ensure the receipt is gotten before the ui revives the tx const txMeta = this.txStateManager.getTx(txId) @@ -566,9 +621,10 @@ export default class TransactionController extends EventEmitter { try { // It seems that sometimes the numerical values being returned from // this.query.getTransactionReceipt are BN instances and not strings. - const gasUsed = typeof txReceipt.gasUsed === 'string' - ? txReceipt.gasUsed - : txReceipt.gasUsed.toString(16) + const gasUsed = + typeof txReceipt.gasUsed === 'string' + ? txReceipt.gasUsed + : txReceipt.gasUsed.toString(16) txMeta.txReceipt = { ...txReceipt, @@ -577,7 +633,10 @@ export default class TransactionController extends EventEmitter { this.txStateManager.setTxStatusConfirmed(txId) this._markNonceDuplicatesDropped(txId) - this.txStateManager.updateTx(txMeta, 'transactions#confirmTransaction - add txReceipt') + this.txStateManager.updateTx( + txMeta, + 'transactions#confirmTransaction - add txReceipt', + ) if (txMeta.transactionCategory === SWAP) { const postTxBalance = await this.query.getBalance(txMeta.txParams.from) @@ -589,11 +648,13 @@ export default class TransactionController extends EventEmitter { latestTxMeta.postTxBalance = postTxBalance.toString(16) - this.txStateManager.updateTx(latestTxMeta, 'transactions#confirmTransaction - add postTxBalance') + this.txStateManager.updateTx( + latestTxMeta, + 'transactions#confirmTransaction - add postTxBalance', + ) this._trackSwapsMetrics(latestTxMeta, approvalTxMeta) } - } catch (err) { log.error(err) } @@ -604,7 +665,7 @@ export default class TransactionController extends EventEmitter { @param {number} txId - the tx's Id @returns {Promise} */ - async cancelTransaction (txId) { + async cancelTransaction(txId) { this.txStateManager.setTxStatusRejected(txId) } @@ -613,7 +674,7 @@ export default class TransactionController extends EventEmitter { @param {number} txId - the tx's Id @param {string} txHash - the hash for the txMeta */ - setTxHash (txId, txHash) { + setTxHash(txId, txHash) { // Add the tx hash to the persisted meta-tx object const txMeta = this.txStateManager.getTx(txId) txMeta.hash = txHash @@ -624,8 +685,7 @@ export default class TransactionController extends EventEmitter { // PRIVATE METHODS // /** maps methods for convenience*/ - _mapMethods () { - + _mapMethods() { /** @returns {Object} - the state in transaction controller */ this.getState = () => this.memStore.getState() @@ -633,23 +693,27 @@ export default class TransactionController extends EventEmitter { this.getNetwork = () => this.networkStore.getState() /** @returns {string} - the user selected address */ - this.getSelectedAddress = () => this.preferencesStore.getState().selectedAddress + this.getSelectedAddress = () => + this.preferencesStore.getState().selectedAddress /** @returns {array} - transactions whos status is unapproved */ - this.getUnapprovedTxCount = () => Object.keys(this.txStateManager.getUnapprovedTxList()).length + this.getUnapprovedTxCount = () => + Object.keys(this.txStateManager.getUnapprovedTxList()).length /** @returns {number} - number of transactions that have the status submitted @param {string} account - hex prefixed account */ - this.getPendingTxCount = (account) => this.txStateManager.getPendingTransactions(account).length + this.getPendingTxCount = (account) => + this.txStateManager.getPendingTransactions(account).length /** see txStateManager */ - this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts) + this.getFilteredTxList = (opts) => + this.txStateManager.getFilteredTxList(opts) } // called once on startup - async _updatePendingTxsAfterFirstBlock () { + async _updatePendingTxsAfterFirstBlock() { // wait for first block so we know we're ready await this.blockTracker.getLatestBlock() // get status update for all pending transactions (for the current network) @@ -662,49 +726,78 @@ export default class TransactionController extends EventEmitter { transition txMetas to a failed state or try to redo those tasks. */ - _onBootCleanUp () { - this.txStateManager.getFilteredTxList({ - status: 'unapproved', - loadingDefaults: true, - }).forEach((tx) => { + _onBootCleanUp() { + this.txStateManager + .getFilteredTxList({ + status: 'unapproved', + loadingDefaults: true, + }) + .forEach((tx) => { + this.addTxGasDefaults(tx) + .then((txMeta) => { + txMeta.loadingDefaults = false + this.txStateManager.updateTx( + txMeta, + 'transactions: gas estimation for tx on boot', + ) + }) + .catch((error) => { + const txMeta = this.txStateManager.getTx(tx.id) + txMeta.loadingDefaults = false + this.txStateManager.updateTx( + txMeta, + 'failed to estimate gas during boot cleanup.', + ) + this.txStateManager.setTxStatusFailed(txMeta.id, error) + }) + }) - this.addTxGasDefaults(tx) - .then((txMeta) => { - txMeta.loadingDefaults = false - this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot') - }).catch((error) => { - const txMeta = this.txStateManager.getTx(tx.id) - txMeta.loadingDefaults = false - this.txStateManager.updateTx(txMeta, 'failed to estimate gas during boot cleanup.') - this.txStateManager.setTxStatusFailed(txMeta.id, error) - }) - }) - - this.txStateManager.getFilteredTxList({ - status: TRANSACTION_STATUS_APPROVED, - }).forEach((txMeta) => { - const txSignError = new Error('Transaction found as "approved" during boot - possibly stuck during signing') - this.txStateManager.setTxStatusFailed(txMeta.id, txSignError) - }) + this.txStateManager + .getFilteredTxList({ + status: TRANSACTION_STATUS_APPROVED, + }) + .forEach((txMeta) => { + const txSignError = new Error( + 'Transaction found as "approved" during boot - possibly stuck during signing', + ) + this.txStateManager.setTxStatusFailed(txMeta.id, txSignError) + }) } /** is called in constructor applies the listeners for pendingTxTracker txStateManager and blockTracker */ - _setupListeners () { - this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update')) + _setupListeners() { + this.txStateManager.on( + 'tx:status-update', + this.emit.bind(this, 'tx:status-update'), + ) this._setupBlockTrackerListener() this.pendingTxTracker.on('tx:warning', (txMeta) => { - this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') + this.txStateManager.updateTx( + txMeta, + 'transactions/pending-tx-tracker#event: tx:warning', + ) }) - this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) - this.pendingTxTracker.on('tx:confirmed', (txId, transactionReceipt) => this.confirmTransaction(txId, transactionReceipt)) - this.pendingTxTracker.on('tx:dropped', this.txStateManager.setTxStatusDropped.bind(this.txStateManager)) + this.pendingTxTracker.on( + 'tx:failed', + this.txStateManager.setTxStatusFailed.bind(this.txStateManager), + ) + this.pendingTxTracker.on('tx:confirmed', (txId, transactionReceipt) => + this.confirmTransaction(txId, transactionReceipt), + ) + this.pendingTxTracker.on( + 'tx:dropped', + this.txStateManager.setTxStatusDropped.bind(this.txStateManager), + ) this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { if (!txMeta.firstRetryBlockNumber) { txMeta.firstRetryBlockNumber = latestBlockNumber - this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:block-update') + this.txStateManager.updateTx( + txMeta, + 'transactions/pending-tx-tracker#event: tx:block-update', + ) } }) this.pendingTxTracker.on('tx:retry', (txMeta) => { @@ -712,7 +805,10 @@ export default class TransactionController extends EventEmitter { txMeta.retryCount = 0 } txMeta.retryCount += 1 - this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') + this.txStateManager.updateTx( + txMeta, + 'transactions/pending-tx-tracker#event: tx:retry', + ) }) } @@ -720,7 +816,7 @@ export default class TransactionController extends EventEmitter { Returns a "type" for a transaction out of the following list: simpleSend, tokenTransfer, tokenApprove, contractDeployment, contractMethodCall */ - async _determineTransactionCategory (txParams) { + async _determineTransactionCategory(txParams) { const { data, to } = txParams let name try { @@ -765,7 +861,7 @@ export default class TransactionController extends EventEmitter { @param {number} txId - the txId of the transaction that has been confirmed in a block */ - _markNonceDuplicatesDropped (txId) { + _markNonceDuplicatesDropped(txId) { // get the confirmed transactions nonce and from address const txMeta = this.txStateManager.getTx(txId) const { nonce, from } = txMeta.txParams @@ -779,12 +875,15 @@ export default class TransactionController extends EventEmitter { return } otherTxMeta.replacedBy = txMeta.hash - this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce') + this.txStateManager.updateTx( + txMeta, + 'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce', + ) this.txStateManager.setTxStatusDropped(otherTxMeta.id) }) } - _setupBlockTrackerListener () { + _setupBlockTrackerListener() { let listenersAreActive = false const latestBlockHandler = this._onLatestBlock.bind(this) const { blockTracker, txStateManager } = this @@ -792,7 +891,7 @@ export default class TransactionController extends EventEmitter { txStateManager.on('tx:status-update', updateSubscription) updateSubscription() - function updateSubscription () { + function updateSubscription() { const pendingTxs = txStateManager.getPendingTransactions() if (!listenersAreActive && pendingTxs.length > 0) { blockTracker.on('latest', latestBlockHandler) @@ -804,7 +903,7 @@ export default class TransactionController extends EventEmitter { } } - async _onLatestBlock (blockNumber) { + async _onLatestBlock(blockNumber) { try { await this.pendingTxTracker.updatePendingTxs() } catch (err) { @@ -820,13 +919,15 @@ export default class TransactionController extends EventEmitter { /** Updates the memStore in transaction controller */ - _updateMemstore () { + _updateMemstore() { const unapprovedTxs = this.txStateManager.getUnapprovedTxList() - const currentNetworkTxList = this.txStateManager.getTxList(MAX_MEMSTORE_TX_LIST_SIZE) + const currentNetworkTxList = this.txStateManager.getTxList( + MAX_MEMSTORE_TX_LIST_SIZE, + ) this.memStore.updateState({ unapprovedTxs, currentNetworkTxList }) } - _trackSwapsMetrics (txMeta, approvalTxMeta) { + _trackSwapsMetrics(txMeta, approvalTxMeta) { if (this._getParticipateInMetrics() && txMeta.swapMetaData) { if (txMeta.txReceipt.status === '0x0') { this._trackMetaMetricsEvent({ @@ -851,19 +952,18 @@ export default class TransactionController extends EventEmitter { approvalTxMeta, ) - const quoteVsExecutionRatio = `${ - (new BigNumber(tokensReceived, 10)) - .div(txMeta.swapMetaData.token_to_amount, 10) - .times(100) - .round(2) - }%` + const quoteVsExecutionRatio = `${new BigNumber(tokensReceived, 10) + .div(txMeta.swapMetaData.token_to_amount, 10) + .times(100) + .round(2)}%` - const estimatedVsUsedGasRatio = `${ - (new BigNumber(txMeta.txReceipt.gasUsed, 16)) - .div(txMeta.swapMetaData.estimated_gas, 10) - .times(100) - .round(2) - }%` + const estimatedVsUsedGasRatio = `${new BigNumber( + txMeta.txReceipt.gasUsed, + 16, + ) + .div(txMeta.swapMetaData.estimated_gas, 10) + .times(100) + .round(2)}%` this._trackMetaMetricsEvent({ event: 'Swap Completed', diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js b/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js index 20505ec06..382ab178f 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js @@ -6,10 +6,10 @@ import { cloneDeep } from 'lodash' @param {array} longHistory @returns {array} */ -export function migrateFromSnapshotsToDiffs (longHistory) { +export function migrateFromSnapshotsToDiffs(longHistory) { return ( longHistory - // convert non-initial history entries into diffs + // convert non-initial history entries into diffs .map((entry, index) => { if (index === 0) { return entry @@ -31,7 +31,7 @@ export function migrateFromSnapshotsToDiffs (longHistory) { @param {string} [note] - a optional note for the state change @returns {array} */ -export function generateHistoryEntry (previousState, newState, note) { +export function generateHistoryEntry(previousState, newState, note) { const entry = jsonDiffer.compare(previousState, newState) // Add a note to the first op, since it breaks if we append it to the entry if (entry[0]) { @@ -48,9 +48,11 @@ export function generateHistoryEntry (previousState, newState, note) { Recovers previous txMeta state obj @returns {Object} */ -export function replayHistory (_shortHistory) { +export function replayHistory(_shortHistory) { const shortHistory = cloneDeep(_shortHistory) - return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument) + return shortHistory.reduce( + (val, entry) => jsonDiffer.applyPatch(val, entry).newDocument, + ) } /** @@ -58,7 +60,7 @@ export function replayHistory (_shortHistory) { * @param {Object} txMeta - the tx metadata object * @returns {Object} a deep clone without history */ -export function snapshotFromTxMeta (txMeta) { +export function snapshotFromTxMeta(txMeta) { const shallow = { ...txMeta } delete shallow.history return cloneDeep(shallow) diff --git a/app/scripts/controllers/transactions/lib/util.js b/app/scripts/controllers/transactions/lib/util.js index da58bf6f3..45ae4bcdd 100644 --- a/app/scripts/controllers/transactions/lib/util.js +++ b/app/scripts/controllers/transactions/lib/util.js @@ -2,7 +2,8 @@ import { addHexPrefix, isValidAddress } from 'ethereumjs-util' const normalizers = { from: (from) => addHexPrefix(from), - to: (to, lowerCase) => (lowerCase ? addHexPrefix(to).toLowerCase() : addHexPrefix(to)), + to: (to, lowerCase) => + lowerCase ? addHexPrefix(to).toLowerCase() : addHexPrefix(to), nonce: (nonce) => addHexPrefix(nonce), value: (value) => addHexPrefix(value), data: (data) => addHexPrefix(data), @@ -17,7 +18,7 @@ const normalizers = { * Default: true * @returns {Object} the normalized tx params */ -export function normalizeTxParams (txParams, lowerCase = true) { +export function normalizeTxParams(txParams, lowerCase = true) { // apply only keys in the normalizers const normalizedTxParams = {} for (const key in normalizers) { @@ -33,17 +34,21 @@ export function normalizeTxParams (txParams, lowerCase = true) { * @param {Object} txParams - the tx params * @throws {Error} if the tx params contains invalid fields */ -export function validateTxParams (txParams) { +export function validateTxParams(txParams) { validateFrom(txParams) validateRecipient(txParams) if ('value' in txParams) { const value = txParams.value.toString() if (value.includes('-')) { - throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`) + throw new Error( + `Invalid transaction value of ${txParams.value} not a positive number.`, + ) } if (value.includes('.')) { - throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`) + throw new Error( + `Invalid transaction value of ${txParams.value} number must be in wei`, + ) } } } @@ -53,7 +58,7 @@ export function validateTxParams (txParams) { * @param {Object} txParams * @throws {Error} if the from address isn't valid */ -export function validateFrom (txParams) { +export function validateFrom(txParams) { if (!(typeof txParams.from === 'string')) { throw new Error(`Invalid from address ${txParams.from} not a string`) } @@ -68,7 +73,7 @@ export function validateFrom (txParams) { * @returns {Object} the tx params * @throws {Error} if the recipient is invalid OR there isn't tx data */ -export function validateRecipient (txParams) { +export function validateRecipient(txParams) { if (txParams.to === '0x' || txParams.to === null) { if (txParams.data) { delete txParams.to @@ -85,7 +90,7 @@ export function validateRecipient (txParams) { * Returns a list of final states * @returns {string[]} the states that can be considered final states */ -export function getFinalStates () { +export function getFinalStates() { return [ 'rejected', // the user has responded no! 'confirmed', // the tx has been included in a block. diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index e1b33cb2f..e173e250a 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -19,7 +19,6 @@ import EthQuery from 'ethjs-query' */ export default class PendingTransactionTracker extends EventEmitter { - /** * We wait this many blocks before emitting a 'tx:dropped' event * @@ -37,9 +36,9 @@ export default class PendingTransactionTracker extends EventEmitter { */ droppedBlocksBufferByHash = new Map() - constructor (config) { + constructor(config) { super() - this.query = config.query || (new EthQuery(config.provider)) + this.query = config.query || new EthQuery(config.provider) this.nonceTracker = config.nonceTracker this.getPendingTransactions = config.getPendingTransactions this.getCompletedTransactions = config.getCompletedTransactions @@ -51,14 +50,18 @@ export default class PendingTransactionTracker extends EventEmitter { /** checks the network for signed txs and releases the nonce global lock if it is */ - async updatePendingTxs () { + async updatePendingTxs() { // in order to keep the nonceTracker accurate we block it while updating pending transactions const nonceGlobalLock = await this.nonceTracker.getGlobalLock() try { const pendingTxs = this.getPendingTransactions() - await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) + await Promise.all( + pendingTxs.map((txMeta) => this._checkPendingTx(txMeta)), + ) } catch (err) { - log.error('PendingTransactionTracker - Error updating pending transactions') + log.error( + 'PendingTransactionTracker - Error updating pending transactions', + ) log.error(err) } nonceGlobalLock.releaseLock() @@ -70,7 +73,7 @@ export default class PendingTransactionTracker extends EventEmitter { * @emits tx:warning * @returns {Promise} */ - async resubmitPendingTxs (blockNumber) { + async resubmitPendingTxs(blockNumber) { const pending = this.getPendingTransactions() if (!pending.length) { return @@ -79,18 +82,20 @@ export default class PendingTransactionTracker extends EventEmitter { try { await this._resubmitTx(txMeta, blockNumber) } catch (err) { - const errorMessage = err.value?.message?.toLowerCase() || err.message.toLowerCase() - const isKnownTx = ( + const errorMessage = + err.value?.message?.toLowerCase() || err.message.toLowerCase() + const isKnownTx = // geth errorMessage.includes('replacement transaction underpriced') || errorMessage.includes('known transaction') || // parity errorMessage.includes('gas price too low to replace') || - errorMessage.includes('transaction with the same hash was already imported') || + errorMessage.includes( + 'transaction with the same hash was already imported', + ) || // other errorMessage.includes('gateway timeout') || errorMessage.includes('nonce too low') - ) // ignore resubmit warnings, return early if (isKnownTx) { return @@ -117,13 +122,16 @@ export default class PendingTransactionTracker extends EventEmitter { * @emits tx:retry * @private */ - async _resubmitTx (txMeta, latestBlockNumber) { + async _resubmitTx(txMeta, latestBlockNumber) { if (!txMeta.firstRetryBlockNumber) { this.emit('tx:block-update', txMeta, latestBlockNumber) } - const firstRetryBlockNumber = txMeta.firstRetryBlockNumber || latestBlockNumber - const txBlockDistance = Number.parseInt(latestBlockNumber, 16) - Number.parseInt(firstRetryBlockNumber, 16) + const firstRetryBlockNumber = + txMeta.firstRetryBlockNumber || latestBlockNumber + const txBlockDistance = + Number.parseInt(latestBlockNumber, 16) - + Number.parseInt(firstRetryBlockNumber, 16) const retryCount = txMeta.retryCount || 0 @@ -155,7 +163,7 @@ export default class PendingTransactionTracker extends EventEmitter { * @emits tx:warning * @private */ - async _checkPendingTx (txMeta) { + async _checkPendingTx(txMeta) { const txHash = txMeta.hash const txId = txMeta.id @@ -167,7 +175,9 @@ export default class PendingTransactionTracker extends EventEmitter { // extra check in case there was an uncaught error during the // signature and submission process if (!txHash) { - const noTxHashErr = new Error('We had an error while submitting this transaction, please try again.') + const noTxHashErr = new Error( + 'We had an error while submitting this transaction, please try again.', + ) noTxHashErr.name = 'NoTxHashError' this.emit('tx:failed', txId, noTxHashErr) @@ -206,8 +216,11 @@ export default class PendingTransactionTracker extends EventEmitter { * @returns {Promise} * @private */ - async _checkIfTxWasDropped (txMeta) { - const { hash: txHash, txParams: { nonce, from } } = txMeta + async _checkIfTxWasDropped(txMeta) { + const { + hash: txHash, + txParams: { nonce, from }, + } = txMeta const networkNextNonce = await this.query.getTransactionCount(from) if (parseInt(nonce, 16) >= networkNextNonce.toNumber()) { @@ -235,14 +248,16 @@ export default class PendingTransactionTracker extends EventEmitter { * @returns {Promise} * @private */ - async _checkIfNonceIsTaken (txMeta) { + async _checkIfNonceIsTaken(txMeta) { const address = txMeta.txParams.from const completed = this.getCompletedTransactions(address) return completed.some( // This is called while the transaction is in-flight, so it is possible that the // list of completed transactions now includes the transaction we were looking at // and if that is the case, don't consider the transaction to have taken its own nonce - (other) => !(other.id === txMeta.id) && other.txParams.nonce === txMeta.txParams.nonce, + (other) => + !(other.id === txMeta.id) && + other.txParams.nonce === txMeta.txParams.nonce, ) } } diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index fa89ef293..c1c781bf3 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -20,8 +20,7 @@ and used to do things like calculate gas of a tx. */ export default class TxGasUtil { - - constructor (provider) { + constructor(provider) { this.query = new EthQuery(provider) } @@ -29,7 +28,7 @@ export default class TxGasUtil { @param {Object} txMeta - the txMeta object @returns {GasAnalysisResult} The result of the gas analysis */ - async analyzeGasUsage (txMeta) { + async analyzeGasUsage(txMeta) { const block = await this.query.getBlockByNumber('latest', false) // fallback to block gasLimit @@ -56,7 +55,7 @@ export default class TxGasUtil { @param {Object} txMeta - the txMeta object @returns {string} - the estimated gas limit as a hex string */ - async estimateTxGas (txMeta) { + async estimateTxGas(txMeta) { const { txParams } = txMeta // estimate tx gas requirements @@ -70,7 +69,7 @@ export default class TxGasUtil { @param {string} blockGasLimitHex - the block gas limit @returns {string} - the buffered gas limit as a hex string */ - addGasBuffer (initialGasLimitHex, blockGasLimitHex, multiplier = 1.5) { + addGasBuffer(initialGasLimitHex, blockGasLimitHex, multiplier = 1.5) { const initialGasLimitBn = hexToBn(initialGasLimitHex) const blockGasLimitBn = hexToBn(blockGasLimitHex) const upperGasLimitBn = blockGasLimitBn.muln(0.9) @@ -88,11 +87,19 @@ export default class TxGasUtil { return bnToHex(upperGasLimitBn) } - async getBufferedGasLimit (txMeta, multiplier) { - const { blockGasLimit, estimatedGasHex, simulationFails } = await this.analyzeGasUsage(txMeta) + async getBufferedGasLimit(txMeta, multiplier) { + const { + blockGasLimit, + estimatedGasHex, + simulationFails, + } = await this.analyzeGasUsage(txMeta) // add additional gas buffer to our estimation for safety - const gasLimit = this.addGasBuffer(ethUtil.addHexPrefix(estimatedGasHex), blockGasLimit, multiplier) + const gasLimit = this.addGasBuffer( + ethUtil.addHexPrefix(estimatedGasHex), + blockGasLimit, + multiplier, + ) return { gasLimit, simulationFails } } } diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index b5c7e3353..46ba95140 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -2,7 +2,11 @@ import EventEmitter from 'safe-event-emitter' import ObservableStore from 'obs-store' import log from 'loglevel' import createId from '../../lib/random-id' -import { generateHistoryEntry, replayHistory, snapshotFromTxMeta } from './lib/tx-state-history-helpers' +import { + generateHistoryEntry, + replayHistory, + snapshotFromTxMeta, +} from './lib/tx-state-history-helpers' import { getFinalStates, normalizeTxParams } from './lib/util' /** @@ -28,12 +32,10 @@ import { getFinalStates, normalizeTxParams } from './lib/util' @class */ export default class TransactionStateManager extends EventEmitter { - constructor ({ initState, txHistoryLimit, getNetwork }) { + constructor({ initState, txHistoryLimit, getNetwork }) { super() - this.store = new ObservableStore( - { transactions: [], ...initState }, - ) + this.store = new ObservableStore({ transactions: [], ...initState }) this.txHistoryLimit = txHistoryLimit this.getNetwork = getNetwork } @@ -42,17 +44,18 @@ export default class TransactionStateManager extends EventEmitter { @param {Object} opts - the object to use when overwriting defaults @returns {txMeta} - the default txMeta object */ - generateTxMeta (opts) { + generateTxMeta(opts) { const netId = this.getNetwork() if (netId === 'loading') { throw new Error('MetaMask is having trouble connecting to the network') } return { id: createId(), - time: (new Date()).getTime(), + time: new Date().getTime(), status: 'unapproved', metamaskNetworkId: netId, - loadingDefaults: true, ...opts, + loadingDefaults: true, + ...opts, } } @@ -64,7 +67,7 @@ export default class TransactionStateManager extends EventEmitter { * @param {number} [limit] a limit for the number of transactions to return * @returns {Object[]} The {@code txMeta}s, filtered to the current network */ - getTxList (limit) { + getTxList(limit) { const network = this.getNetwork() const fullTxList = this.getFullTxList() @@ -95,14 +98,14 @@ export default class TransactionStateManager extends EventEmitter { /** @returns {array} - of all the txMetas in store */ - getFullTxList () { + getFullTxList() { return this.store.getState().transactions } /** @returns {array} - the tx list whose status is unapproved */ - getUnapprovedTxList () { + getUnapprovedTxList() { const txList = this.getTxsByMetaData('status', 'unapproved') return txList.reduce((result, tx) => { result[tx.id] = tx @@ -115,7 +118,7 @@ export default class TransactionStateManager extends EventEmitter { @returns {array} - the tx list whose status is approved if no address is provide returns all txMetas who's status is approved for the current network */ - getApprovedTransactions (address) { + getApprovedTransactions(address) { const opts = { status: 'approved' } if (address) { opts.from = address @@ -128,7 +131,7 @@ export default class TransactionStateManager extends EventEmitter { @returns {array} - the tx list whose status is submitted if no address is provide returns all txMetas who's status is submitted for the current network */ - getPendingTransactions (address) { + getPendingTransactions(address) { const opts = { status: 'submitted' } if (address) { opts.from = address @@ -141,7 +144,7 @@ export default class TransactionStateManager extends EventEmitter { @returns {array} - the tx list whose status is confirmed if no address is provide returns all txMetas who's status is confirmed for the current network */ - getConfirmedTransactions (address) { + getConfirmedTransactions(address) { const opts = { status: 'confirmed' } if (address) { opts.from = address @@ -158,7 +161,7 @@ export default class TransactionStateManager extends EventEmitter { @param {Object} txMeta @returns {Object} - the txMeta */ - addTx (txMeta) { + addTx(txMeta) { // normalize and validate txParams if present if (txMeta.txParams) { txMeta.txParams = this.normalizeAndValidateTxParams(txMeta.txParams) @@ -193,8 +196,9 @@ export default class TransactionStateManager extends EventEmitter { transactions.splice(index, 1) } } - const newTxIndex = transactions - .findIndex((currentTxMeta) => currentTxMeta.time > txMeta.time) + const newTxIndex = transactions.findIndex( + (currentTxMeta) => currentTxMeta.time > txMeta.time, + ) newTxIndex === -1 ? transactions.push(txMeta) @@ -208,7 +212,7 @@ export default class TransactionStateManager extends EventEmitter { @returns {Object} - the txMeta who matches the given id if none found for the network returns undefined */ - getTx (txId) { + getTx(txId) { const txMeta = this.getTxsByMetaData('id', txId)[0] return txMeta } @@ -218,7 +222,7 @@ export default class TransactionStateManager extends EventEmitter { @param {Object} txMeta - the txMeta to update @param {string} [note] - a note about the update for history */ - updateTx (txMeta, note) { + updateTx(txMeta, note) { // normalize and validate txParams if present if (txMeta.txParams) { txMeta.txParams = this.normalizeAndValidateTxParams(txMeta.txParams) @@ -248,7 +252,7 @@ export default class TransactionStateManager extends EventEmitter { @param {number} txId - the id of the txMeta @param {Object} txParams - the updated txParams */ - updateTxParams (txId, txParams) { + updateTxParams(txId, txParams) { const txMeta = this.getTx(txId) txMeta.txParams = { ...txMeta.txParams, ...txParams } this.updateTx(txMeta, `txStateManager#updateTxParams`) @@ -258,7 +262,7 @@ export default class TransactionStateManager extends EventEmitter { * normalize and validate txParams members * @param {Object} txParams - txParams */ - normalizeAndValidateTxParams (txParams) { + normalizeAndValidateTxParams(txParams) { if (typeof txParams.data === 'undefined') { delete txParams.data } @@ -272,19 +276,23 @@ export default class TransactionStateManager extends EventEmitter { validates txParams members by type @param {Object} txParams - txParams to validate */ - validateTxParams (txParams) { + validateTxParams(txParams) { Object.keys(txParams).forEach((key) => { const value = txParams[key] // validate types switch (key) { case 'chainId': if (typeof value !== 'number' && typeof value !== 'string') { - throw new Error(`${key} in txParams is not a Number or hex string. got: (${value})`) + throw new Error( + `${key} in txParams is not a Number or hex string. got: (${value})`, + ) } break default: if (typeof value !== 'string') { - throw new Error(`${key} in txParams is not a string. got: (${value})`) + throw new Error( + `${key} in txParams is not a string. got: (${value})`, + ) } break } @@ -319,7 +327,7 @@ export default class TransactionStateManager extends EventEmitter { or for filtering for all txs from one account and that have been 'confirmed' */ - getFilteredTxList (opts, initialList) { + getFilteredTxList(opts, initialList) { let filteredTxList = initialList Object.keys(opts).forEach((key) => { filteredTxList = this.getTxsByMetaData(key, opts[key], filteredTxList) @@ -335,7 +343,7 @@ export default class TransactionStateManager extends EventEmitter { from txStateManager#getTxList @returns {array} - a list of txMetas who matches the search params */ - getTxsByMetaData (key, value, txList = this.getTxList()) { + getTxsByMetaData(key, value, txList = this.getTxList()) { const filter = typeof value === 'function' ? value : (v) => v === value return txList.filter((txMeta) => { @@ -352,7 +360,7 @@ export default class TransactionStateManager extends EventEmitter { @param {number} txId - the txMeta Id @returns {string} - the status of the tx. */ - getTxStatus (txId) { + getTxStatus(txId) { const txMeta = this.getTx(txId) return txMeta.status } @@ -361,7 +369,7 @@ export default class TransactionStateManager extends EventEmitter { should update the status of the tx to 'rejected'. @param {number} txId - the txMeta Id */ - setTxStatusRejected (txId) { + setTxStatusRejected(txId) { this._setTxStatus(txId, 'rejected') this._removeTx(txId) } @@ -370,7 +378,7 @@ export default class TransactionStateManager extends EventEmitter { should update the status of the tx to 'unapproved'. @param {number} txId - the txMeta Id */ - setTxStatusUnapproved (txId) { + setTxStatusUnapproved(txId) { this._setTxStatus(txId, 'unapproved') } @@ -378,7 +386,7 @@ export default class TransactionStateManager extends EventEmitter { should update the status of the tx to 'approved'. @param {number} txId - the txMeta Id */ - setTxStatusApproved (txId) { + setTxStatusApproved(txId) { this._setTxStatus(txId, 'approved') } @@ -386,7 +394,7 @@ export default class TransactionStateManager extends EventEmitter { should update the status of the tx to 'signed'. @param {number} txId - the txMeta Id */ - setTxStatusSigned (txId) { + setTxStatusSigned(txId) { this._setTxStatus(txId, 'signed') } @@ -395,9 +403,9 @@ export default class TransactionStateManager extends EventEmitter { and add a time stamp for when it was called @param {number} txId - the txMeta Id */ - setTxStatusSubmitted (txId) { + setTxStatusSubmitted(txId) { const txMeta = this.getTx(txId) - txMeta.submittedTime = (new Date()).getTime() + txMeta.submittedTime = new Date().getTime() this.updateTx(txMeta, 'txStateManager - add submitted time stamp') this._setTxStatus(txId, 'submitted') } @@ -406,7 +414,7 @@ export default class TransactionStateManager extends EventEmitter { should update the status of the tx to 'confirmed'. @param {number} txId - the txMeta Id */ - setTxStatusConfirmed (txId) { + setTxStatusConfirmed(txId) { this._setTxStatus(txId, 'confirmed') } @@ -414,7 +422,7 @@ export default class TransactionStateManager extends EventEmitter { should update the status of the tx to 'dropped'. @param {number} txId - the txMeta Id */ - setTxStatusDropped (txId) { + setTxStatusDropped(txId) { this._setTxStatus(txId, 'dropped') } @@ -424,7 +432,7 @@ export default class TransactionStateManager extends EventEmitter { @param {number} txId - the txMeta Id @param {erroObject} err - error object */ - setTxStatusFailed (txId, err) { + setTxStatusFailed(txId, err) { const error = err || new Error('Internal metamask failure') const txMeta = this.getTx(txId) @@ -442,13 +450,19 @@ export default class TransactionStateManager extends EventEmitter { from the txList @param {string} address - hex string of the from address on the txParams to remove */ - wipeTransactions (address) { + wipeTransactions(address) { // network only tx const txs = this.getFullTxList() const network = this.getNetwork() // Filter out the ones from the current account and network - const otherAccountTxs = txs.filter((txMeta) => !(txMeta.txParams.from === address && txMeta.metamaskNetworkId === network)) + const otherAccountTxs = txs.filter( + (txMeta) => + !( + txMeta.txParams.from === address && + txMeta.metamaskNetworkId === network + ), + ) // Update state this._saveTxList(otherAccountTxs) @@ -475,7 +489,7 @@ export default class TransactionStateManager extends EventEmitter { @emits ${txMeta.id}:finished - if it is a finished state. Passes the txMeta @emits update:badge */ - _setTxStatus (txId, status) { + _setTxStatus(txId, status) { const txMeta = this.getTx(txId) if (!txMeta) { @@ -501,11 +515,11 @@ export default class TransactionStateManager extends EventEmitter { @param {array} transactions - the list of transactions to save */ // Function is intended only for internal use - _saveTxList (transactions) { + _saveTxList(transactions) { this.store.updateState({ transactions }) } - _removeTx (txId) { + _removeTx(txId) { const transactionList = this.getFullTxList() this._saveTxList(transactionList.filter((txMeta) => txMeta.id !== txId)) } @@ -514,9 +528,11 @@ export default class TransactionStateManager extends EventEmitter { * Filters out the unapproved transactions */ - clearUnapprovedTxs () { + clearUnapprovedTxs() { const transactions = this.getFullTxList() - const nonUnapprovedTxs = transactions.filter((tx) => tx.status !== 'unapproved') + const nonUnapprovedTxs = transactions.filter( + (tx) => tx.status !== 'unapproved', + ) this._saveTxList(nonUnapprovedTxs) } } diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js index 5577907fd..b5b498694 100644 --- a/app/scripts/first-time-state.js +++ b/app/scripts/first-time-state.js @@ -1,4 +1,3 @@ - /** * @typedef {Object} FirstTimeState * @property {Object} config Initial configuration parameters diff --git a/app/scripts/lib/ComposableObservableStore.js b/app/scripts/lib/ComposableObservableStore.js index ef8e91f22..288caf73e 100644 --- a/app/scripts/lib/ComposableObservableStore.js +++ b/app/scripts/lib/ComposableObservableStore.js @@ -5,14 +5,13 @@ import ObservableStore from 'obs-store' * structure of child stores based on configuration */ export default class ComposableObservableStore extends ObservableStore { - /** * Create a new store * * @param {Object} [initState] - The initial store state * @param {Object} [config] - Map of internal state keys to child stores */ - constructor (initState, config) { + constructor(initState, config) { super(initState) this.updateStructure(config) } @@ -22,7 +21,7 @@ export default class ComposableObservableStore extends ObservableStore { * * @param {Object} [config] - Map of internal state keys to child stores */ - updateStructure (config) { + updateStructure(config) { this.config = config this.removeAllListeners() for (const key in config) { @@ -40,12 +39,14 @@ export default class ComposableObservableStore extends ObservableStore { * * @returns {Object} - Object containing merged child store state */ - getFlatState () { + getFlatState() { let flatState = {} for (const key in this.config) { if (Object.prototype.hasOwnProperty.call(this.config, key)) { const controller = this.config[key] - const state = controller.getState ? controller.getState() : controller.state + const state = controller.getState + ? controller.getState() + : controller.state flatState = { ...flatState, ...state } } } diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index bb5563606..39fc5fb71 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -14,7 +14,12 @@ import log from 'loglevel' import pify from 'pify' import Web3 from 'web3' import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi' -import { MAINNET_CHAIN_ID, RINKEBY_CHAIN_ID, ROPSTEN_CHAIN_ID, KOVAN_CHAIN_ID } from '../controllers/network/enums' +import { + MAINNET_CHAIN_ID, + RINKEBY_CHAIN_ID, + ROPSTEN_CHAIN_ID, + KOVAN_CHAIN_ID, +} from '../controllers/network/enums' import { SINGLE_CALL_BALANCES_ADDRESS, @@ -42,14 +47,13 @@ import { bnToHex } from './util' * */ export default class AccountTracker { - /** * @param {Object} opts - Options for initializing the controller * @param {Object} opts.provider - An EIP-1193 provider instance that uses the current global network * @param {Object} opts.blockTracker - A block tracker, which emits events for each new block * @param {Function} opts.getCurrentChainId - A function that returns the `chainId` for the current global network */ - constructor (opts = {}) { + constructor(opts = {}) { const initState = { accounts: {}, currentBlockGasLimit: '', @@ -71,7 +75,7 @@ export default class AccountTracker { this.web3 = new Web3(this._provider) } - start () { + start() { // remove first to avoid double add this._blockTracker.removeListener('latest', this._updateForBlock) // add listener @@ -80,7 +84,7 @@ export default class AccountTracker { this._updateAccounts() } - stop () { + stop() { // remove listener this._blockTracker.removeListener('latest', this._updateForBlock) } @@ -96,7 +100,7 @@ export default class AccountTracker { * in sync * */ - syncWithAddresses (addresses) { + syncWithAddresses(addresses) { const { accounts } = this.store.getState() const locals = Object.keys(accounts) @@ -125,7 +129,7 @@ export default class AccountTracker { * @param {array} addresses - An array of hex addresses of new accounts to track * */ - addAccounts (addresses) { + addAccounts(addresses) { const { accounts } = this.store.getState() // add initial state for addresses addresses.forEach((address) => { @@ -146,7 +150,7 @@ export default class AccountTracker { * @param {array} an - array of hex addresses to stop tracking * */ - removeAccount (addresses) { + removeAccount(addresses) { const { accounts } = this.store.getState() // remove each state object addresses.forEach((address) => { @@ -160,7 +164,7 @@ export default class AccountTracker { * Removes all addresses and associated balances */ - clearAccounts () { + clearAccounts() { this.store.updateState({ accounts: {} }) } @@ -173,7 +177,7 @@ export default class AccountTracker { * @fires 'block' The updated state, if all account updates are successful * */ - async _updateForBlock (blockNumber) { + async _updateForBlock(blockNumber) { this._currentBlockNumber = blockNumber // block gasLimit polling shouldn't be in account-tracker shouldn't be here... @@ -198,26 +202,38 @@ export default class AccountTracker { * @returns {Promise} - after all account balances updated * */ - async _updateAccounts () { + async _updateAccounts() { const { accounts } = this.store.getState() const addresses = Object.keys(accounts) const chainId = this.getCurrentChainId() switch (chainId) { case MAINNET_CHAIN_ID: - await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS) + await this._updateAccountsViaBalanceChecker( + addresses, + SINGLE_CALL_BALANCES_ADDRESS, + ) break case RINKEBY_CHAIN_ID: - await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_RINKEBY) + await this._updateAccountsViaBalanceChecker( + addresses, + SINGLE_CALL_BALANCES_ADDRESS_RINKEBY, + ) break case ROPSTEN_CHAIN_ID: - await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN) + await this._updateAccountsViaBalanceChecker( + addresses, + SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN, + ) break case KOVAN_CHAIN_ID: - await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_KOVAN) + await this._updateAccountsViaBalanceChecker( + addresses, + SINGLE_CALL_BALANCES_ADDRESS_KOVAN, + ) break default: @@ -233,7 +249,7 @@ export default class AccountTracker { * @returns {Promise} - after the account balance is updated * */ - async _updateAccount (address) { + async _updateAccount(address) { // query balance const balance = await this._query.getBalance(address) const result = { address, balance } @@ -252,15 +268,20 @@ export default class AccountTracker { * @param {*} addresses * @param {*} deployedContractAddress */ - async _updateAccountsViaBalanceChecker (addresses, deployedContractAddress) { + async _updateAccountsViaBalanceChecker(addresses, deployedContractAddress) { const { accounts } = this.store.getState() this.web3.setProvider(this._provider) - const ethContract = this.web3.eth.contract(SINGLE_CALL_BALANCES_ABI).at(deployedContractAddress) + const ethContract = this.web3.eth + .contract(SINGLE_CALL_BALANCES_ABI) + .at(deployedContractAddress) const ethBalance = ['0x0'] ethContract.balances(addresses, ethBalance, (error, result) => { if (error) { - log.warn(`MetaMask - Account Tracker single call balance fetch failed`, error) + log.warn( + `MetaMask - Account Tracker single call balance fetch failed`, + error, + ) Promise.all(addresses.map(this._updateAccount.bind(this))) return } @@ -271,5 +292,4 @@ export default class AccountTracker { this.store.updateState({ accounts }) }) } - } diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index 8cf4c137f..2d8cef438 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -8,7 +8,7 @@ * network does not match any of the specified cases, or if no network is given, returns undefined. * */ -export default function getBuyEthUrl ({ network, address, service }) { +export default function getBuyEthUrl({ network, address, service }) { // default service by network if not specified if (!service) { // eslint-disable-next-line no-param-reassign @@ -33,7 +33,7 @@ export default function getBuyEthUrl ({ network, address, service }) { } } -function getDefaultServiceForNetwork (network) { +function getDefaultServiceForNetwork(network) { switch (network) { case '1': return 'wyre' @@ -46,6 +46,8 @@ function getDefaultServiceForNetwork (network) { case '5': return 'goerli-faucet' default: - throw new Error(`No default cryptocurrency exchange or faucet for networkId: "${network}"`) + throw new Error( + `No default cryptocurrency exchange or faucet for networkId: "${network}"`, + ) } } diff --git a/app/scripts/lib/cleanErrorStack.js b/app/scripts/lib/cleanErrorStack.js index c68c29b9e..e7efb62c4 100644 --- a/app/scripts/lib/cleanErrorStack.js +++ b/app/scripts/lib/cleanErrorStack.js @@ -3,12 +3,12 @@ * @param {Error} err - error * @returns {Error} - Error with clean stack trace. */ -export default function cleanErrorStack (err) { +export default function cleanErrorStack(err) { let { name } = err - name = (name === undefined) ? 'Error' : String(name) + name = name === undefined ? 'Error' : String(name) let msg = err.message - msg = (msg === undefined) ? '' : String(msg) + msg = msg === undefined ? '' : String(msg) if (name === '') { err.stack = err.message diff --git a/app/scripts/lib/createLoggerMiddleware.js b/app/scripts/lib/createLoggerMiddleware.js index d1710d274..18a128cba 100644 --- a/app/scripts/lib/createLoggerMiddleware.js +++ b/app/scripts/lib/createLoggerMiddleware.js @@ -5,8 +5,12 @@ import log from 'loglevel' * @param {{ origin: string }} opts - The middleware options * @returns {Function} */ -export default function createLoggerMiddleware (opts) { - return function loggerMiddleware (/** @type {any} */ req, /** @type {any} */ res, /** @type {Function} */ next) { +export default function createLoggerMiddleware(opts) { + return function loggerMiddleware( + /** @type {any} */ req, + /** @type {any} */ res, + /** @type {Function} */ next, + ) { next((/** @type {Function} */ cb) => { if (res.error) { log.error('Error in RPC response:\n', res) diff --git a/app/scripts/lib/createOnboardingMiddleware.js b/app/scripts/lib/createOnboardingMiddleware.js index d7eb020f0..cef41deb6 100644 --- a/app/scripts/lib/createOnboardingMiddleware.js +++ b/app/scripts/lib/createOnboardingMiddleware.js @@ -6,8 +6,11 @@ import extension from 'extensionizer' * @param {{ location: string, registerOnboarding: Function }} opts - The middleware options * @returns {(req: any, res: any, next: Function, end: Function) => void} */ -export default function createOnboardingMiddleware ({ location, registerOnboarding }) { - return async function originMiddleware (req, res, next, end) { +export default function createOnboardingMiddleware({ + location, + registerOnboarding, +}) { + return async function originMiddleware(req, res, next, end) { try { if (req.method !== 'wallet_registerOnboarding') { next() @@ -16,7 +19,9 @@ export default function createOnboardingMiddleware ({ location, registerOnboardi if (req.tabId && req.tabId !== extension.tabs.TAB_ID_NONE) { await registerOnboarding(location, req.tabId) } else { - log.debug(`'wallet_registerOnboarding' message from ${location} ignored due to missing tabId`) + log.debug( + `'wallet_registerOnboarding' message from ${location} ignored due to missing tabId`, + ) } res.result = true end() diff --git a/app/scripts/lib/createOriginMiddleware.js b/app/scripts/lib/createOriginMiddleware.js index db10c0778..031ba84d5 100644 --- a/app/scripts/lib/createOriginMiddleware.js +++ b/app/scripts/lib/createOriginMiddleware.js @@ -3,8 +3,12 @@ * @param {{ origin: string }} opts - The middleware options * @returns {Function} */ -export default function createOriginMiddleware (opts) { - return function originMiddleware (/** @type {any} */ req, /** @type {any} */ _, /** @type {Function} */ next) { +export default function createOriginMiddleware(opts) { + return function originMiddleware( + /** @type {any} */ req, + /** @type {any} */ _, + /** @type {Function} */ next, + ) { req.origin = opts.origin next() } diff --git a/app/scripts/lib/createStreamSink.js b/app/scripts/lib/createStreamSink.js index ad0a67959..648e745dd 100644 --- a/app/scripts/lib/createStreamSink.js +++ b/app/scripts/lib/createStreamSink.js @@ -2,20 +2,18 @@ import { Writable as WritableStream } from 'readable-stream' import promiseToCallback from 'promise-to-callback' class AsyncWritableStream extends WritableStream { - - constructor (asyncWriteFn, _opts) { + constructor(asyncWriteFn, _opts) { const opts = { objectMode: true, ..._opts } super(opts) this._asyncWriteFn = asyncWriteFn } // write from incoming stream to state - _write (chunk, encoding, callback) { + _write(chunk, encoding, callback) { promiseToCallback(this._asyncWriteFn(chunk, encoding))(callback) } - } -export default function createStreamSink (asyncWriteFn, _opts) { +export default function createStreamSink(asyncWriteFn, _opts) { return new AsyncWritableStream(asyncWriteFn, _opts) } diff --git a/app/scripts/lib/createTabIdMiddleware.js b/app/scripts/lib/createTabIdMiddleware.js index bb7db79d2..9848b68c9 100644 --- a/app/scripts/lib/createTabIdMiddleware.js +++ b/app/scripts/lib/createTabIdMiddleware.js @@ -3,8 +3,12 @@ * @param {{ tabId: number }} opts - The middleware options * @returns {Function} */ -export default function createTabIdMiddleware (opts) { - return function tabIdMiddleware (/** @type {any} */ req, /** @type {any} */ _, /** @type {Function} */ next) { +export default function createTabIdMiddleware(opts) { + return function tabIdMiddleware( + /** @type {any} */ req, + /** @type {any} */ _, + /** @type {Function} */ next, + ) { req.tabId = opts.tabId next() } diff --git a/app/scripts/lib/decrypt-message-manager.js b/app/scripts/lib/decrypt-message-manager.js index a31074f12..99fa9d696 100644 --- a/app/scripts/lib/decrypt-message-manager.js +++ b/app/scripts/lib/decrypt-message-manager.js @@ -6,7 +6,7 @@ import log from 'loglevel' import createId from './random-id' import { MESSAGE_TYPE } from './enums' -const hexRe = /^[0-9A-Fa-f]+$/ug +const hexRe = /^[0-9A-Fa-f]+$/gu /** * Represents, and contains data about, an 'eth_decrypt' type decryption request. These are created when a @@ -26,7 +26,6 @@ const hexRe = /^[0-9A-Fa-f]+$/ug */ export default class DecryptMessageManager extends EventEmitter { - /** * Controller in charge of managing - storing, adding, removing, updating - DecryptMessage. * @@ -37,7 +36,7 @@ export default class DecryptMessageManager extends EventEmitter { * @property {array} messages Holds all messages that have been created by this DecryptMessageManager * */ - constructor () { + constructor() { super() this.memStore = new ObservableStore({ unapprovedDecryptMsgs: {}, @@ -52,7 +51,7 @@ export default class DecryptMessageManager extends EventEmitter { * @returns {number} The number of 'unapproved' DecryptMessages in this.messages * */ - get unapprovedDecryptMsgCount () { + get unapprovedDecryptMsgCount() { return Object.keys(this.getUnapprovedMsgs()).length } @@ -63,8 +62,9 @@ export default class DecryptMessageManager extends EventEmitter { * this.messages * */ - getUnapprovedMsgs () { - return this.messages.filter((msg) => msg.status === 'unapproved') + getUnapprovedMsgs() { + return this.messages + .filter((msg) => msg.status === 'unapproved') .reduce((result, msg) => { result[msg.id] = msg return result @@ -81,7 +81,7 @@ export default class DecryptMessageManager extends EventEmitter { * @returns {Promise} The raw decrypted message contents * */ - addUnapprovedMessageAsync (msgParams, req) { + addUnapprovedMessageAsync(msgParams, req) { return new Promise((resolve, reject) => { if (!msgParams.from) { reject(new Error('MetaMask Decryption: from field is required.')) @@ -94,13 +94,23 @@ export default class DecryptMessageManager extends EventEmitter { resolve(data.rawData) return case 'rejected': - reject(ethErrors.provider.userRejectedRequest('MetaMask Decryption: User denied message decryption.')) + reject( + ethErrors.provider.userRejectedRequest( + 'MetaMask Decryption: User denied message decryption.', + ), + ) return case 'errored': reject(new Error('This message cannot be decrypted')) return default: - reject(new Error(`MetaMask Decryption: Unknown problem: ${JSON.stringify(msgParams)}`)) + reject( + new Error( + `MetaMask Decryption: Unknown problem: ${JSON.stringify( + msgParams, + )}`, + ), + ) } }) }) @@ -116,15 +126,19 @@ export default class DecryptMessageManager extends EventEmitter { * @returns {number} The id of the newly created DecryptMessage. * */ - addUnapprovedMessage (msgParams, req) { - log.debug(`DecryptMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) + addUnapprovedMessage(msgParams, req) { + log.debug( + `DecryptMessageManager addUnapprovedMessage: ${JSON.stringify( + msgParams, + )}`, + ) // add origin from request if (req) { msgParams.origin = req.origin } msgParams.data = this.normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data - const time = (new Date()).getTime() + const time = new Date().getTime() const msgId = createId() const msgData = { id: msgId, @@ -147,7 +161,7 @@ export default class DecryptMessageManager extends EventEmitter { * @param {Message} msg The DecryptMessage to add to this.messages * */ - addMsg (msg) { + addMsg(msg) { this.messages.push(msg) this._saveMsgList() } @@ -160,7 +174,7 @@ export default class DecryptMessageManager extends EventEmitter { * if no DecryptMessage has that id. * */ - getMsg (msgId) { + getMsg(msgId) { return this.messages.find((msg) => msg.id === msgId) } @@ -173,7 +187,7 @@ export default class DecryptMessageManager extends EventEmitter { * @returns {Promise} Promises the msgParams object with metamaskId removed. * */ - approveMessage (msgParams) { + approveMessage(msgParams) { this.setMsgStatusApproved(msgParams.metamaskId) return this.prepMsgForDecryption(msgParams) } @@ -184,7 +198,7 @@ export default class DecryptMessageManager extends EventEmitter { * @param {number} msgId The id of the DecryptMessage to approve. * */ - setMsgStatusApproved (msgId) { + setMsgStatusApproved(msgId) { this._setMsgStatus(msgId, 'approved') } @@ -196,7 +210,7 @@ export default class DecryptMessageManager extends EventEmitter { * @param {buffer} rawData The raw data of the message request * */ - setMsgStatusDecrypted (msgId, rawData) { + setMsgStatusDecrypted(msgId, rawData) { const msg = this.getMsg(msgId) msg.rawData = rawData this._updateMsg(msg) @@ -210,7 +224,7 @@ export default class DecryptMessageManager extends EventEmitter { * @returns {Promise} Promises the msgParams with the metamaskId property removed * */ - prepMsgForDecryption (msgParams) { + prepMsgForDecryption(msgParams) { delete msgParams.metamaskId return Promise.resolve(msgParams) } @@ -221,7 +235,7 @@ export default class DecryptMessageManager extends EventEmitter { * @param {number} msgId The id of the DecryptMessage to reject. * */ - rejectMsg (msgId) { + rejectMsg(msgId) { this._setMsgStatus(msgId, 'rejected') } @@ -231,7 +245,7 @@ export default class DecryptMessageManager extends EventEmitter { * @param {number} msgId The id of the TypedMessage to error * */ - errorMessage (msgId, error) { + errorMessage(msgId, error) { const msg = this.getMsg(msgId) msg.error = error this._updateMsg(msg) @@ -251,15 +265,21 @@ export default class DecryptMessageManager extends EventEmitter { * with the DecryptMessage * */ - _setMsgStatus (msgId, status) { + _setMsgStatus(msgId, status) { const msg = this.getMsg(msgId) if (!msg) { - throw new Error(`DecryptMessageManager - Message not found for id: "${msgId}".`) + throw new Error( + `DecryptMessageManager - Message not found for id: "${msgId}".`, + ) } msg.status = status this._updateMsg(msg) this.emit(`${msgId}:${status}`, msg) - if (status === 'rejected' || status === 'decrypted' || status === 'errored') { + if ( + status === 'rejected' || + status === 'decrypted' || + status === 'errored' + ) { this.emit(`${msgId}:finished`, msg) } } @@ -273,7 +293,7 @@ export default class DecryptMessageManager extends EventEmitter { * id) in this.messages * */ - _updateMsg (msg) { + _updateMsg(msg) { const index = this.messages.findIndex((message) => message.id === msg.id) if (index !== -1) { this.messages[index] = msg @@ -288,10 +308,13 @@ export default class DecryptMessageManager extends EventEmitter { * @fires 'updateBadge' * */ - _saveMsgList () { + _saveMsgList() { const unapprovedDecryptMsgs = this.getUnapprovedMsgs() const unapprovedDecryptMsgCount = Object.keys(unapprovedDecryptMsgs).length - this.memStore.updateState({ unapprovedDecryptMsgs, unapprovedDecryptMsgCount }) + this.memStore.updateState({ + unapprovedDecryptMsgs, + unapprovedDecryptMsgCount, + }) this.emit('updateBadge') } @@ -302,7 +325,7 @@ export default class DecryptMessageManager extends EventEmitter { * @returns {string} A hex string conversion of the buffer data * */ - normalizeMsgData (data) { + normalizeMsgData(data) { try { const stripped = ethUtil.stripHexPrefix(data) if (stripped.match(hexRe)) { @@ -314,5 +337,4 @@ export default class DecryptMessageManager extends EventEmitter { return ethUtil.bufferToHex(Buffer.from(data, 'utf8')) } - } diff --git a/app/scripts/lib/encryption-public-key-manager.js b/app/scripts/lib/encryption-public-key-manager.js index 2631dc7d3..e07d77442 100644 --- a/app/scripts/lib/encryption-public-key-manager.js +++ b/app/scripts/lib/encryption-public-key-manager.js @@ -23,7 +23,6 @@ import { MESSAGE_TYPE } from './enums' */ export default class EncryptionPublicKeyManager extends EventEmitter { - /** * Controller in charge of managing - storing, adding, removing, updating - EncryptionPublicKey. * @@ -34,7 +33,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @property {array} messages Holds all messages that have been created by this EncryptionPublicKeyManager * */ - constructor () { + constructor() { super() this.memStore = new ObservableStore({ unapprovedEncryptionPublicKeyMsgs: {}, @@ -49,7 +48,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @returns {number} The number of 'unapproved' EncryptionPublicKeys in this.messages * */ - get unapprovedEncryptionPublicKeyMsgCount () { + get unapprovedEncryptionPublicKeyMsgCount() { return Object.keys(this.getUnapprovedMsgs()).length } @@ -60,8 +59,9 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * this.messages * */ - getUnapprovedMsgs () { - return this.messages.filter((msg) => msg.status === 'unapproved') + getUnapprovedMsgs() { + return this.messages + .filter((msg) => msg.status === 'unapproved') .reduce((result, msg) => { result[msg.id] = msg return result @@ -78,7 +78,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @returns {Promise} The raw public key contents * */ - addUnapprovedMessageAsync (address, req) { + addUnapprovedMessageAsync(address, req) { return new Promise((resolve, reject) => { if (!address) { reject(new Error('MetaMask Message: address field is required.')) @@ -91,10 +91,20 @@ export default class EncryptionPublicKeyManager extends EventEmitter { resolve(data.rawData) return case 'rejected': - reject(ethErrors.provider.userRejectedRequest('MetaMask EncryptionPublicKey: User denied message EncryptionPublicKey.')) + reject( + ethErrors.provider.userRejectedRequest( + 'MetaMask EncryptionPublicKey: User denied message EncryptionPublicKey.', + ), + ) return default: - reject(new Error(`MetaMask EncryptionPublicKey: Unknown problem: ${JSON.stringify(address)}`)) + reject( + new Error( + `MetaMask EncryptionPublicKey: Unknown problem: ${JSON.stringify( + address, + )}`, + ), + ) } }) }) @@ -110,10 +120,10 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @returns {number} The id of the newly created EncryptionPublicKey. * */ - addUnapprovedMessage (address, req) { + addUnapprovedMessage(address, req) { log.debug(`EncryptionPublicKeyManager addUnapprovedMessage: address`) // create txData obj with parameters and meta data - const time = (new Date()).getTime() + const time = new Date().getTime() const msgId = createId() const msgData = { id: msgId, @@ -141,7 +151,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @param {Message} msg The EncryptionPublicKey to add to this.messages * */ - addMsg (msg) { + addMsg(msg) { this.messages.push(msg) this._saveMsgList() } @@ -154,7 +164,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * if no EncryptionPublicKey has that id. * */ - getMsg (msgId) { + getMsg(msgId) { return this.messages.find((msg) => msg.id === msgId) } @@ -167,7 +177,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @returns {Promise} Promises the msgParams object with metamaskId removed. * */ - approveMessage (msgParams) { + approveMessage(msgParams) { this.setMsgStatusApproved(msgParams.metamaskId) return this.prepMsgForEncryptionPublicKey(msgParams) } @@ -178,7 +188,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @param {number} msgId The id of the EncryptionPublicKey to approve. * */ - setMsgStatusApproved (msgId) { + setMsgStatusApproved(msgId) { this._setMsgStatus(msgId, 'approved') } @@ -190,7 +200,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @param {buffer} rawData The raw data of the message request * */ - setMsgStatusReceived (msgId, rawData) { + setMsgStatusReceived(msgId, rawData) { const msg = this.getMsg(msgId) msg.rawData = rawData this._updateMsg(msg) @@ -204,7 +214,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @returns {Promise} Promises the msgParams with the metamaskId property removed * */ - prepMsgForEncryptionPublicKey (msgParams) { + prepMsgForEncryptionPublicKey(msgParams) { delete msgParams.metamaskId return Promise.resolve(msgParams) } @@ -215,7 +225,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @param {number} msgId The id of the EncryptionPublicKey to reject. * */ - rejectMsg (msgId) { + rejectMsg(msgId) { this._setMsgStatus(msgId, 'rejected') } @@ -225,7 +235,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @param {number} msgId The id of the TypedMessage to error * */ - errorMessage (msgId, error) { + errorMessage(msgId, error) { const msg = this.getMsg(msgId) msg.error = error this._updateMsg(msg) @@ -245,10 +255,12 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * with the EncryptionPublicKey * */ - _setMsgStatus (msgId, status) { + _setMsgStatus(msgId, status) { const msg = this.getMsg(msgId) if (!msg) { - throw new Error(`EncryptionPublicKeyManager - Message not found for id: "${msgId}".`) + throw new Error( + `EncryptionPublicKeyManager - Message not found for id: "${msgId}".`, + ) } msg.status = status this._updateMsg(msg) @@ -267,7 +279,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * id) in this.messages * */ - _updateMsg (msg) { + _updateMsg(msg) { const index = this.messages.findIndex((message) => message.id === msg.id) if (index !== -1) { this.messages[index] = msg @@ -282,10 +294,15 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @fires 'updateBadge' * */ - _saveMsgList () { + _saveMsgList() { const unapprovedEncryptionPublicKeyMsgs = this.getUnapprovedMsgs() - const unapprovedEncryptionPublicKeyMsgCount = Object.keys(unapprovedEncryptionPublicKeyMsgs).length - this.memStore.updateState({ unapprovedEncryptionPublicKeyMsgs, unapprovedEncryptionPublicKeyMsgCount }) + const unapprovedEncryptionPublicKeyMsgCount = Object.keys( + unapprovedEncryptionPublicKeyMsgs, + ).length + this.memStore.updateState({ + unapprovedEncryptionPublicKeyMsgs, + unapprovedEncryptionPublicKeyMsgCount, + }) this.emit('updateBadge') } } diff --git a/app/scripts/lib/ens-ipfs/contracts/registry.js b/app/scripts/lib/ens-ipfs/contracts/registry.js index b896eaa53..4eab80287 100644 --- a/app/scripts/lib/ens-ipfs/contracts/registry.js +++ b/app/scripts/lib/ens-ipfs/contracts/registry.js @@ -1,2 +1,109 @@ -const abi = [{ 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'resolver', 'outputs': [{ 'name': '', 'type': 'address' }], 'payable': false, 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'owner', 'outputs': [{ 'name': '', 'type': 'address' }], 'payable': false, 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'label', 'type': 'bytes32' }, { 'name': 'owner', 'type': 'address' }], 'name': 'setSubnodeOwner', 'outputs': [], 'payable': false, 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'ttl', 'type': 'uint64' }], 'name': 'setTTL', 'outputs': [], 'payable': false, 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'ttl', 'outputs': [{ 'name': '', 'type': 'uint64' }], 'payable': false, 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'resolver', 'type': 'address' }], 'name': 'setResolver', 'outputs': [], 'payable': false, 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'owner', 'type': 'address' }], 'name': 'setOwner', 'outputs': [], 'payable': false, 'type': 'function' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'owner', 'type': 'address' }], 'name': 'Transfer', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': true, 'name': 'label', 'type': 'bytes32' }, { 'indexed': false, 'name': 'owner', 'type': 'address' }], 'name': 'NewOwner', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'resolver', 'type': 'address' }], 'name': 'NewResolver', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'ttl', 'type': 'uint64' }], 'name': 'NewTTL', 'type': 'event' }] +const abi = [ + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'resolver', + outputs: [{ name: '', type: 'address' }], + payable: false, + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'owner', + outputs: [{ name: '', type: 'address' }], + payable: false, + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'label', type: 'bytes32' }, + { name: 'owner', type: 'address' }, + ], + name: 'setSubnodeOwner', + outputs: [], + payable: false, + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'ttl', type: 'uint64' }, + ], + name: 'setTTL', + outputs: [], + payable: false, + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'ttl', + outputs: [{ name: '', type: 'uint64' }], + payable: false, + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'resolver', type: 'address' }, + ], + name: 'setResolver', + outputs: [], + payable: false, + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'owner', type: 'address' }, + ], + name: 'setOwner', + outputs: [], + payable: false, + type: 'function', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'owner', type: 'address' }, + ], + name: 'Transfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: true, name: 'label', type: 'bytes32' }, + { indexed: false, name: 'owner', type: 'address' }, + ], + name: 'NewOwner', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'resolver', type: 'address' }, + ], + name: 'NewResolver', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'ttl', type: 'uint64' }, + ], + name: 'NewTTL', + type: 'event', + }, +] export default abi diff --git a/app/scripts/lib/ens-ipfs/contracts/resolver.js b/app/scripts/lib/ens-ipfs/contracts/resolver.js index 92c0c0f45..a392bcfe8 100644 --- a/app/scripts/lib/ens-ipfs/contracts/resolver.js +++ b/app/scripts/lib/ens-ipfs/contracts/resolver.js @@ -1,2 +1,236 @@ -const abi = [{ 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'hash', 'type': 'bytes32' }], 'name': 'setContent', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'content', 'outputs': [{ 'name': '', 'type': 'bytes32' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'interfaceID', 'type': 'bytes4' }], 'name': 'supportsInterface', 'outputs': [{ 'name': '', 'type': 'bool' }], 'payable': false, 'stateMutability': 'pure', 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'key', 'type': 'string' }, { 'name': 'value', 'type': 'string' }], 'name': 'setText', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'contentTypes', 'type': 'uint256' }], 'name': 'ABI', 'outputs': [{ 'name': 'contentType', 'type': 'uint256' }, { 'name': 'data', 'type': 'bytes' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'x', 'type': 'bytes32' }, { 'name': 'y', 'type': 'bytes32' }], 'name': 'setPubkey', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'hash', 'type': 'bytes' }], 'name': 'setContenthash', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'addr', 'outputs': [{ 'name': '', 'type': 'address' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'key', 'type': 'string' }], 'name': 'text', 'outputs': [{ 'name': '', 'type': 'string' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'contentType', 'type': 'uint256' }, { 'name': 'data', 'type': 'bytes' }], 'name': 'setABI', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'name', 'outputs': [{ 'name': '', 'type': 'string' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'name', 'type': 'string' }], 'name': 'setName', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'contenthash', 'outputs': [{ 'name': '', 'type': 'bytes' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': true, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }], 'name': 'pubkey', 'outputs': [{ 'name': 'x', 'type': 'bytes32' }, { 'name': 'y', 'type': 'bytes32' }], 'payable': false, 'stateMutability': 'view', 'type': 'function' }, { 'constant': false, 'inputs': [{ 'name': 'node', 'type': 'bytes32' }, { 'name': 'addr', 'type': 'address' }], 'name': 'setAddr', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, { 'inputs': [{ 'name': 'ensAddr', 'type': 'address' }], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'a', 'type': 'address' }], 'name': 'AddrChanged', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'name', 'type': 'string' }], 'name': 'NameChanged', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': true, 'name': 'contentType', 'type': 'uint256' }], 'name': 'ABIChanged', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'x', 'type': 'bytes32' }, { 'indexed': false, 'name': 'y', 'type': 'bytes32' }], 'name': 'PubkeyChanged', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'indexedKey', 'type': 'string' }, { 'indexed': false, 'name': 'key', 'type': 'string' }], 'name': 'TextChanged', 'type': 'event' }, { 'anonymous': false, 'inputs': [{ 'indexed': true, 'name': 'node', 'type': 'bytes32' }, { 'indexed': false, 'name': 'hash', 'type': 'bytes' }], 'name': 'ContenthashChanged', 'type': 'event' }] +const abi = [ + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'hash', type: 'bytes32' }, + ], + name: 'setContent', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'content', + outputs: [{ name: '', type: 'bytes32' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'interfaceID', type: 'bytes4' }], + name: 'supportsInterface', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'key', type: 'string' }, + { name: 'value', type: 'string' }, + ], + name: 'setText', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'contentTypes', type: 'uint256' }, + ], + name: 'ABI', + outputs: [ + { name: 'contentType', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'x', type: 'bytes32' }, + { name: 'y', type: 'bytes32' }, + ], + name: 'setPubkey', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'hash', type: 'bytes' }, + ], + name: 'setContenthash', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'addr', + outputs: [{ name: '', type: 'address' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'key', type: 'string' }, + ], + name: 'text', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'contentType', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + name: 'setABI', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'name', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'name', type: 'string' }, + ], + name: 'setName', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'contenthash', + outputs: [{ name: '', type: 'bytes' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [{ name: 'node', type: 'bytes32' }], + name: 'pubkey', + outputs: [ + { name: 'x', type: 'bytes32' }, + { name: 'y', type: 'bytes32' }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: 'node', type: 'bytes32' }, + { name: 'addr', type: 'address' }, + ], + name: 'setAddr', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ name: 'ensAddr', type: 'address' }], + payable: false, + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'a', type: 'address' }, + ], + name: 'AddrChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'name', type: 'string' }, + ], + name: 'NameChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: true, name: 'contentType', type: 'uint256' }, + ], + name: 'ABIChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'x', type: 'bytes32' }, + { indexed: false, name: 'y', type: 'bytes32' }, + ], + name: 'PubkeyChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'indexedKey', type: 'string' }, + { indexed: false, name: 'key', type: 'string' }, + ], + name: 'TextChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'node', type: 'bytes32' }, + { indexed: false, name: 'hash', type: 'bytes' }, + ], + name: 'ContenthashChanged', + type: 'event', + }, +] export default abi diff --git a/app/scripts/lib/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js index cc307e617..f19a7b60a 100644 --- a/app/scripts/lib/ens-ipfs/resolver.js +++ b/app/scripts/lib/ens-ipfs/resolver.js @@ -5,7 +5,7 @@ import contentHash from 'content-hash' import registryAbi from './contracts/registry' import resolverAbi from './contracts/resolver' -export default async function resolveEnsToIpfsContentId ({ provider, name }) { +export default async function resolveEnsToIpfsContentId({ provider, name }) { const eth = new Eth(provider) const hash = namehash.hash(name) const contract = new EthContract(eth) @@ -13,7 +13,9 @@ export default async function resolveEnsToIpfsContentId ({ provider, name }) { const chainId = Number.parseInt(await eth.net_version(), 10) const registryAddress = getRegistryForChainId(chainId) if (!registryAddress) { - throw new Error(`EnsIpfsResolver - no known ens-ipfs registry for chainId "${chainId}"`) + throw new Error( + `EnsIpfsResolver - no known ens-ipfs registry for chainId "${chainId}"`, + ) } const Registry = contract(registryAbi).at(registryAddress) // lookup resolver @@ -33,7 +35,9 @@ export default async function resolveEnsToIpfsContentId ({ provider, name }) { const type = contentHash.getCodec(rawContentHash) if (type === 'ipfs-ns' || type === 'ipns-ns') { - decodedContentHash = contentHash.helpers.cidV0ToV1Base32(decodedContentHash) + decodedContentHash = contentHash.helpers.cidV0ToV1Base32( + decodedContentHash, + ) } return { type, hash: decodedContentHash } @@ -43,15 +47,25 @@ export default async function resolveEnsToIpfsContentId ({ provider, name }) { const contentLookupResult = await Resolver.content(hash) const content = contentLookupResult[0] if (hexValueIsEmpty(content)) { - throw new Error(`EnsIpfsResolver - no content ID found for name "${name}"`) + throw new Error( + `EnsIpfsResolver - no content ID found for name "${name}"`, + ) } return { type: 'swarm-ns', hash: content.slice(2) } } - throw new Error(`EnsIpfsResolver - the resolver for name "${name}" is not standard, it should either supports contenthash() or content()`) + throw new Error( + `EnsIpfsResolver - the resolver for name "${name}" is not standard, it should either supports contenthash() or content()`, + ) } -function hexValueIsEmpty (value) { - return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value) +function hexValueIsEmpty(value) { + return [ + undefined, + null, + '0x', + '0x0', + '0x0000000000000000000000000000000000000000000000000000000000000000', + ].includes(value) } /** @@ -59,7 +73,7 @@ function hexValueIsEmpty (value) { * @param {number} chainId the chain ID * @returns {string|null} the registry address if known, null otherwise */ -function getRegistryForChainId (chainId) { +function getRegistryForChainId(chainId) { switch (chainId) { case 1: case 3: diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index 92968d28d..ab4cec023 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -3,21 +3,27 @@ import resolveEnsToIpfsContentId from './resolver' const supportedTopLevelDomains = ['eth'] -export default function setupEnsIpfsResolver ({ provider, getCurrentNetwork, getIpfsGateway }) { - +export default function setupEnsIpfsResolver({ + provider, + getCurrentNetwork, + getIpfsGateway, +}) { // install listener const urlPatterns = supportedTopLevelDomains.map((tld) => `*://*.${tld}/*`) - extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns, types: ['main_frame'] }) + extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { + urls: urlPatterns, + types: ['main_frame'], + }) // return api object return { // uninstall listener - remove () { + remove() { extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail) }, } - async function webRequestDidFail (details) { + async function webRequestDidFail(details) { const { tabId, url } = details // ignore requests that are not associated with tabs // only attempt ENS resolution on mainnet @@ -36,14 +42,17 @@ export default function setupEnsIpfsResolver ({ provider, getCurrentNetwork, get attemptResolve({ tabId, name, pathname, search, fragment }) } - async function attemptResolve ({ tabId, name, pathname, search, fragment }) { + async function attemptResolve({ tabId, name, pathname, search, fragment }) { const ipfsGateway = getIpfsGateway() extension.tabs.update(tabId, { url: `loading.html` }) let url = `https://app.ens.domains/name/${name}` try { const { type, hash } = await resolveEnsToIpfsContentId({ provider, name }) if (type === 'ipfs-ns' || type === 'ipns-ns') { - const resolvedUrl = `https://${hash}.${type.slice(0, 4)}.${ipfsGateway}${pathname}${search || ''}${fragment || ''}` + const resolvedUrl = `https://${hash}.${type.slice( + 0, + 4, + )}.${ipfsGateway}${pathname}${search || ''}${fragment || ''}` try { // check if ipfs gateway has result const response = await window.fetch(resolvedUrl, { method: 'HEAD' }) @@ -54,11 +63,15 @@ export default function setupEnsIpfsResolver ({ provider, getCurrentNetwork, get console.warn(err) } } else if (type === 'swarm-ns') { - url = `https://swarm-gateways.net/bzz:/${hash}${pathname}${search || ''}${fragment || ''}` + url = `https://swarm-gateways.net/bzz:/${hash}${pathname}${ + search || '' + }${fragment || ''}` } else if (type === 'onion' || type === 'onion3') { url = `http://${hash}.onion${pathname}${search || ''}${fragment || ''}` } else if (type === 'zeronet') { - url = `http://127.0.0.1:43110/${hash}${pathname}${search || ''}${fragment || ''}` + url = `http://127.0.0.1:43110/${hash}${pathname}${search || ''}${ + fragment || '' + }` } } catch (err) { console.warn(err) diff --git a/app/scripts/lib/extractEthjsErrorMessage.js b/app/scripts/lib/extractEthjsErrorMessage.js index 0dde04f06..1436d33af 100644 --- a/app/scripts/lib/extractEthjsErrorMessage.js +++ b/app/scripts/lib/extractEthjsErrorMessage.js @@ -12,12 +12,14 @@ const errorLabelPrefix = 'Error: ' * // returns 'Transaction Failed: replacement transaction underpriced' * extractEthjsErrorMessage(`Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced`) * -*/ -export default function extractEthjsErrorMessage (errorMessage) { + */ +export default function extractEthjsErrorMessage(errorMessage) { const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) if (isEthjsRpcError) { const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) - const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length) + const originalError = payloadAndError.slice( + payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length, + ) return originalError } return errorMessage diff --git a/app/scripts/lib/fetch-with-timeout.js b/app/scripts/lib/fetch-with-timeout.js index a2f6663cc..bca8d652d 100644 --- a/app/scripts/lib/fetch-with-timeout.js +++ b/app/scripts/lib/fetch-with-timeout.js @@ -1,5 +1,5 @@ const fetchWithTimeout = ({ timeout = 120000 } = {}) => { - return async function _fetch (url, opts) { + return async function _fetch(url, opts) { const abortController = new window.AbortController() const abortSignal = abortController.signal const f = window.fetch(url, { diff --git a/app/scripts/lib/freezeGlobals.js b/app/scripts/lib/freezeGlobals.js index b17a84781..08b201bee 100644 --- a/app/scripts/lib/freezeGlobals.js +++ b/app/scripts/lib/freezeGlobals.js @@ -1,13 +1,9 @@ - /** * Freezes the Promise global and prevents its reassignment. */ import deepFreeze from 'deep-freeze-strict' -if ( - process.env.IN_TEST !== 'true' && - process.env.METAMASK_ENV !== 'test' -) { +if (process.env.IN_TEST !== 'true' && process.env.METAMASK_ENV !== 'test') { freeze(global, 'Promise') } @@ -24,10 +20,10 @@ if ( * @param {any} [value] - The value to freeze, if different from the existing value on the target. * @param {boolean} [enumerable=true] - If given a value, whether the property is enumerable. */ -function freeze (target, key, value, enumerable = true) { - +function freeze(target, key, value, enumerable = true) { const opts = { - configurable: false, writable: false, + configurable: false, + writable: false, } if (value === undefined) { diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js index d4bb61a8f..0cc39dab9 100644 --- a/app/scripts/lib/get-first-preferred-lang-code.js +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -2,16 +2,16 @@ import extension from 'extensionizer' import promisify from 'pify' import allLocales from '../../_locales/index.json' -const getPreferredLocales = extension.i18n ? promisify( - extension.i18n.getAcceptLanguages, - { errorFirst: false }, -) : async () => [] +const getPreferredLocales = extension.i18n + ? promisify(extension.i18n.getAcceptLanguages, { errorFirst: false }) + : async () => [] // mapping some browsers return hyphen instead underscore in locale codes (e.g. zh_TW -> zh-tw) const existingLocaleCodes = {} allLocales.forEach((locale) => { if (locale && locale.code) { - existingLocaleCodes[locale.code.toLowerCase().replace('_', '-')] = locale.code + existingLocaleCodes[locale.code.toLowerCase().replace('_', '-')] = + locale.code } }) @@ -22,7 +22,7 @@ allLocales.forEach((locale) => { * @returns {Promise} - Promises a locale code, either one from the user's preferred list that we have a translation for, or 'en' * */ -export default async function getFirstPreferredLangCode () { +export default async function getFirstPreferredLangCode() { let userPreferredLocaleCodes try { @@ -40,7 +40,9 @@ export default async function getFirstPreferredLangCode () { const firstPreferredLangCode = userPreferredLocaleCodes .map((code) => code.toLowerCase().replace('_', '-')) - .find((code) => Object.prototype.hasOwnProperty.call(existingLocaleCodes, code)) + .find((code) => + Object.prototype.hasOwnProperty.call(existingLocaleCodes, code), + ) return existingLocaleCodes[firstPreferredLangCode] || 'en' } diff --git a/app/scripts/lib/getObjStructure.js b/app/scripts/lib/getObjStructure.js index ef9e3760f..4c19c135f 100644 --- a/app/scripts/lib/getObjStructure.js +++ b/app/scripts/lib/getObjStructure.js @@ -21,7 +21,7 @@ import { cloneDeep } from 'lodash' * replaced with the javascript type of that value. * */ -export default function getObjStructure (obj) { +export default function getObjStructure(obj) { const structure = cloneDeep(obj) return deepMap(structure, (value) => { return value === null ? 'null' : typeof value @@ -36,7 +36,7 @@ export default function getObjStructure (obj) { * @param {Function} visit - The modifier to apply to each non-object property value * @returns {Object} - The modified object */ -function deepMap (target = {}, visit) { +function deepMap(target = {}, visit) { Object.entries(target).forEach(([key, value]) => { if (typeof value === 'object' && value !== null) { target[key] = deepMap(value, visit) diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index e7f05781c..4390d059c 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -6,11 +6,10 @@ import { checkForError } from './util' * A wrapper around the extension's storage local API */ export default class ExtensionStore { - /** * @constructor */ - constructor () { + constructor() { this.isSupported = Boolean(extension.storage.local) if (!this.isSupported) { log.error('Storage local API not available.') @@ -21,7 +20,7 @@ export default class ExtensionStore { * Returns all of the keys currently saved * @returns {Promise<*>} */ - async get () { + async get() { if (!this.isSupported) { return undefined } @@ -39,7 +38,7 @@ export default class ExtensionStore { * @param {Object} state - The state to set * @returns {Promise} */ - async set (state) { + async set(state) { return this._set(state) } @@ -48,7 +47,7 @@ export default class ExtensionStore { * @private * @returns {Object} - the key-value map from local storage */ - _get () { + _get() { const { local } = extension.storage return new Promise((resolve, reject) => { local.get(null, (/** @type {any} */ result) => { @@ -68,7 +67,7 @@ export default class ExtensionStore { * @returns {Promise} * @private */ - _set (obj) { + _set(obj) { const { local } = extension.storage return new Promise((resolve, reject) => { local.set(obj, () => { @@ -88,6 +87,6 @@ export default class ExtensionStore { * @param {Object} obj - The object to check * @returns {boolean} */ -function isEmpty (obj) { +function isEmpty(obj) { return Object.keys(obj).length === 0 } diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index 280003c40..b78d2c521 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -24,7 +24,6 @@ import { MESSAGE_TYPE } from './enums' */ export default class MessageManager extends EventEmitter { - /** * Controller in charge of managing - storing, adding, removing, updating - Messages. * @@ -36,7 +35,7 @@ export default class MessageManager extends EventEmitter { * @property {array} messages Holds all messages that have been created by this MessageManager * */ - constructor () { + constructor() { super() this.memStore = new ObservableStore({ unapprovedMsgs: {}, @@ -51,7 +50,7 @@ export default class MessageManager extends EventEmitter { * @returns {number} - The number of 'unapproved' Messages in this.messages * */ - get unapprovedMsgCount () { + get unapprovedMsgCount() { return Object.keys(this.getUnapprovedMsgs()).length } @@ -61,8 +60,9 @@ export default class MessageManager extends EventEmitter { * @returns {Object} - An index of Message ids to Messages, for all 'unapproved' Messages in this.messages * */ - getUnapprovedMsgs () { - return this.messages.filter((msg) => msg.status === 'unapproved') + getUnapprovedMsgs() { + return this.messages + .filter((msg) => msg.status === 'unapproved') .reduce((result, msg) => { result[msg.id] = msg return result @@ -78,7 +78,7 @@ export default class MessageManager extends EventEmitter { * @returns {promise} - after signature has been * */ - addUnapprovedMessageAsync (msgParams, req) { + addUnapprovedMessageAsync(msgParams, req) { return new Promise((resolve, reject) => { const msgId = this.addUnapprovedMessage(msgParams, req) // await finished @@ -87,9 +87,19 @@ export default class MessageManager extends EventEmitter { case 'signed': return resolve(data.rawSig) case 'rejected': - return reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.')) + return reject( + ethErrors.provider.userRejectedRequest( + 'MetaMask Message Signature: User denied message signature.', + ), + ) default: - return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + return reject( + new Error( + `MetaMask Message Signature: Unknown problem: ${JSON.stringify( + msgParams, + )}`, + ), + ) } }) }) @@ -104,14 +114,14 @@ export default class MessageManager extends EventEmitter { * @returns {number} - The id of the newly created message. * */ - addUnapprovedMessage (msgParams, req) { + addUnapprovedMessage(msgParams, req) { // add origin from request if (req) { msgParams.origin = req.origin } msgParams.data = normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data - const time = (new Date()).getTime() + const time = new Date().getTime() const msgId = createId() const msgData = { id: msgId, @@ -134,7 +144,7 @@ export default class MessageManager extends EventEmitter { * @param {Message} msg - The Message to add to this.messages * */ - addMsg (msg) { + addMsg(msg) { this.messages.push(msg) this._saveMsgList() } @@ -146,7 +156,7 @@ export default class MessageManager extends EventEmitter { * @returns {Message|undefined} - The Message with the id that matches the passed msgId, or undefined if no Message has that id. * */ - getMsg (msgId) { + getMsg(msgId) { return this.messages.find((msg) => msg.id === msgId) } @@ -159,7 +169,7 @@ export default class MessageManager extends EventEmitter { * @returns {Promise} - Promises the msgParams object with metamaskId removed. * */ - approveMessage (msgParams) { + approveMessage(msgParams) { this.setMsgStatusApproved(msgParams.metamaskId) return this.prepMsgForSigning(msgParams) } @@ -170,7 +180,7 @@ export default class MessageManager extends EventEmitter { * @param {number} msgId - The id of the Message to approve. * */ - setMsgStatusApproved (msgId) { + setMsgStatusApproved(msgId) { this._setMsgStatus(msgId, 'approved') } @@ -182,7 +192,7 @@ export default class MessageManager extends EventEmitter { * @param {buffer} rawSig - The raw data of the signature request * */ - setMsgStatusSigned (msgId, rawSig) { + setMsgStatusSigned(msgId, rawSig) { const msg = this.getMsg(msgId) msg.rawSig = rawSig this._updateMsg(msg) @@ -196,7 +206,7 @@ export default class MessageManager extends EventEmitter { * @returns {Promise} - Promises the msgParams with the metamaskId property removed * */ - prepMsgForSigning (msgParams) { + prepMsgForSigning(msgParams) { delete msgParams.metamaskId return Promise.resolve(msgParams) } @@ -207,7 +217,7 @@ export default class MessageManager extends EventEmitter { * @param {number} msgId - The id of the Message to reject. * */ - rejectMsg (msgId) { + rejectMsg(msgId) { this._setMsgStatus(msgId, 'rejected') } @@ -223,7 +233,7 @@ export default class MessageManager extends EventEmitter { * @fires If status is 'rejected' or 'signed', an event with a name equal to `${msgId}:finished` is fired along with the message * */ - _setMsgStatus (msgId, status) { + _setMsgStatus(msgId, status) { const msg = this.getMsg(msgId) if (!msg) { throw new Error(`MessageManager - Message not found for id: "${msgId}".`) @@ -244,7 +254,7 @@ export default class MessageManager extends EventEmitter { * @param {msg} Message - A Message that will replace an existing Message (with the same id) in this.messages * */ - _updateMsg (msg) { + _updateMsg(msg) { const index = this.messages.findIndex((message) => message.id === msg.id) if (index !== -1) { this.messages[index] = msg @@ -259,13 +269,12 @@ export default class MessageManager extends EventEmitter { * @fires 'updateBadge' * */ - _saveMsgList () { + _saveMsgList() { const unapprovedMsgs = this.getUnapprovedMsgs() const unapprovedMsgCount = Object.keys(unapprovedMsgs).length this.memStore.updateState({ unapprovedMsgs, unapprovedMsgCount }) this.emit('updateBadge') } - } /** @@ -275,7 +284,7 @@ export default class MessageManager extends EventEmitter { * @returns {string} - A hex string conversion of the buffer data * */ -function normalizeMsgData (data) { +function normalizeMsgData(data) { if (data.slice(0, 2) === '0x') { // data is already hex return data diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index 5c2f6185f..4a7f66391 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -13,12 +13,11 @@ import EventEmitter from 'events' */ export default class Migrator extends EventEmitter { - /** * @constructor * @param {MigratorOptions} opts */ - constructor (opts = {}) { + constructor(opts = {}) { super() const migrations = opts.migrations || [] // sort migrations by version @@ -26,11 +25,12 @@ export default class Migrator extends EventEmitter { // grab migration with highest version const lastMigration = this.migrations.slice(-1)[0] // use specified defaultVersion or highest migration version - this.defaultVersion = opts.defaultVersion || (lastMigration && lastMigration.version) || 0 + this.defaultVersion = + opts.defaultVersion || (lastMigration && lastMigration.version) || 0 } // run all pending migrations on meta in place - async migrateData (versionedData = this.generateInitialState()) { + async migrateData(versionedData = this.generateInitialState()) { // get all migrations that have not yet been run const pendingMigrations = this.migrations.filter(migrationIsPending) @@ -42,8 +42,13 @@ export default class Migrator extends EventEmitter { if (!migratedData.data) { throw new Error('Migrator - migration returned empty data') } - if (migratedData.version !== undefined && migratedData.meta.version !== migration.version) { - throw new Error('Migrator - Migration did not update version number correctly') + if ( + migratedData.version !== undefined && + migratedData.meta.version !== migration.version + ) { + throw new Error( + 'Migrator - Migration did not update version number correctly', + ) } // accept the migration as good // eslint-disable-next-line no-param-reassign @@ -69,7 +74,7 @@ export default class Migrator extends EventEmitter { * @param {Migration} migration * @returns {boolean} */ - function migrationIsPending (migration) { + function migrationIsPending(migration) { return migration.version > versionedData.meta.version } } @@ -79,7 +84,7 @@ export default class Migrator extends EventEmitter { * @param {Object} [data] - The data for the initial state * @returns {{meta: {version: number}, data: any}} */ - generateInitialState (data) { + generateInitialState(data) { return { meta: { version: this.defaultVersion, @@ -87,5 +92,4 @@ export default class Migrator extends EventEmitter { data, } } - } diff --git a/app/scripts/lib/network-store.js b/app/scripts/lib/network-store.js index 3116947d7..cc2898292 100644 --- a/app/scripts/lib/network-store.js +++ b/app/scripts/lib/network-store.js @@ -8,21 +8,21 @@ const FIXTURE_SERVER_URL = `http://${FIXTURE_SERVER_HOST}:${FIXTURE_SERVER_PORT} * A read-only network-based storage wrapper */ export default class ReadOnlyNetworkStore { - constructor () { + constructor() { this._initialized = false this._initializing = this._init() this._state = undefined } /** - * Declares this store as compatible with the current browser - */ + * Declares this store as compatible with the current browser + */ isSupported = true /** * Initializes by loading state from the network */ - async _init () { + async _init() { try { const response = await window.fetch(FIXTURE_SERVER_URL) if (response.ok) { @@ -39,7 +39,7 @@ export default class ReadOnlyNetworkStore { * Returns state * @returns {Promise} */ - async get () { + async get() { if (!this._initialized) { await this._initializing } @@ -51,7 +51,7 @@ export default class ReadOnlyNetworkStore { * @param {Object} state - The state to set * @returns {Promise} */ - async set (state) { + async set(state) { if (!this._initialized) { await this._initializing } diff --git a/app/scripts/lib/nodeify.js b/app/scripts/lib/nodeify.js index 074fba3bb..5e6f46309 100644 --- a/app/scripts/lib/nodeify.js +++ b/app/scripts/lib/nodeify.js @@ -14,7 +14,7 @@ const callbackNoop = function (err) { * @param {Object} context - The context in which the fn is to be called, most often a this reference * */ -export default function nodeify (fn, context) { +export default function nodeify(fn, context) { return function (...args) { const lastArg = args[args.length - 1] const lastArgIsCallback = typeof lastArg === 'function' diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index 631ae3290..d18fadbe0 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -4,7 +4,6 @@ const NOTIFICATION_HEIGHT = 620 const NOTIFICATION_WIDTH = 360 export default class NotificationManager { - /** * A collection of methods for controlling the showing and hiding of the notification popup. * @@ -12,7 +11,7 @@ export default class NotificationManager { * */ - constructor () { + constructor() { this.platform = new ExtensionPlatform() } @@ -21,7 +20,7 @@ export default class NotificationManager { * notification windows are given a 'popup' type. * */ - async showPopup () { + async showPopup() { const popup = await this._getPopup() // Bring focus to chrome popup @@ -71,7 +70,7 @@ export default class NotificationManager { * @param {Function} cb - A node style callback that to which the found notification window will be passed. * */ - async _getPopup () { + async _getPopup() { const windows = await this.platform.getAllWindows() return this._getPopupIn(windows) } @@ -83,11 +82,12 @@ export default class NotificationManager { * @param {array} windows - An array of objects containing data about the open MetaMask extension windows. * */ - _getPopupIn (windows) { - return windows ? windows.find((win) => { - // Returns notification popup - return (win && win.type === 'popup' && win.id === this._popupId) - }) : null + _getPopupIn(windows) { + return windows + ? windows.find((win) => { + // Returns notification popup + return win && win.type === 'popup' && win.id === this._popupId + }) + : null } - } diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index 52c0f9bad..9ae95cd26 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -6,7 +6,7 @@ import log from 'loglevel' import createId from './random-id' import { MESSAGE_TYPE } from './enums' -const hexRe = /^[0-9A-Fa-f]+$/ug +const hexRe = /^[0-9A-Fa-f]+$/gu /** * Represents, and contains data about, an 'personal_sign' type signature request. These are created when a @@ -28,7 +28,6 @@ const hexRe = /^[0-9A-Fa-f]+$/ug */ export default class PersonalMessageManager extends EventEmitter { - /** * Controller in charge of managing - storing, adding, removing, updating - PersonalMessage. * @@ -40,7 +39,7 @@ export default class PersonalMessageManager extends EventEmitter { * @property {array} messages Holds all messages that have been created by this PersonalMessageManager * */ - constructor () { + constructor() { super() this.memStore = new ObservableStore({ unapprovedPersonalMsgs: {}, @@ -55,7 +54,7 @@ export default class PersonalMessageManager extends EventEmitter { * @returns {number} - The number of 'unapproved' PersonalMessages in this.messages * */ - get unapprovedPersonalMsgCount () { + get unapprovedPersonalMsgCount() { return Object.keys(this.getUnapprovedMsgs()).length } @@ -66,8 +65,9 @@ export default class PersonalMessageManager extends EventEmitter { * this.messages * */ - getUnapprovedMsgs () { - return this.messages.filter((msg) => msg.status === 'unapproved') + getUnapprovedMsgs() { + return this.messages + .filter((msg) => msg.status === 'unapproved') .reduce((result, msg) => { result[msg.id] = msg return result @@ -84,7 +84,7 @@ export default class PersonalMessageManager extends EventEmitter { * @returns {promise} - When the message has been signed or rejected * */ - addUnapprovedMessageAsync (msgParams, req) { + addUnapprovedMessageAsync(msgParams, req) { return new Promise((resolve, reject) => { if (!msgParams.from) { reject(new Error('MetaMask Message Signature: from field is required.')) @@ -97,10 +97,20 @@ export default class PersonalMessageManager extends EventEmitter { resolve(data.rawSig) return case 'rejected': - reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.')) + reject( + ethErrors.provider.userRejectedRequest( + 'MetaMask Message Signature: User denied message signature.', + ), + ) return default: - reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + reject( + new Error( + `MetaMask Message Signature: Unknown problem: ${JSON.stringify( + msgParams, + )}`, + ), + ) } }) }) @@ -116,15 +126,19 @@ export default class PersonalMessageManager extends EventEmitter { * @returns {number} - The id of the newly created PersonalMessage. * */ - addUnapprovedMessage (msgParams, req) { - log.debug(`PersonalMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) + addUnapprovedMessage(msgParams, req) { + log.debug( + `PersonalMessageManager addUnapprovedMessage: ${JSON.stringify( + msgParams, + )}`, + ) // add origin from request if (req) { msgParams.origin = req.origin } msgParams.data = this.normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data - const time = (new Date()).getTime() + const time = new Date().getTime() const msgId = createId() const msgData = { id: msgId, @@ -147,7 +161,7 @@ export default class PersonalMessageManager extends EventEmitter { * @param {Message} msg - The PersonalMessage to add to this.messages * */ - addMsg (msg) { + addMsg(msg) { this.messages.push(msg) this._saveMsgList() } @@ -160,7 +174,7 @@ export default class PersonalMessageManager extends EventEmitter { * if no PersonalMessage has that id. * */ - getMsg (msgId) { + getMsg(msgId) { return this.messages.find((msg) => msg.id === msgId) } @@ -173,7 +187,7 @@ export default class PersonalMessageManager extends EventEmitter { * @returns {Promise} - Promises the msgParams object with metamaskId removed. * */ - approveMessage (msgParams) { + approveMessage(msgParams) { this.setMsgStatusApproved(msgParams.metamaskId) return this.prepMsgForSigning(msgParams) } @@ -184,7 +198,7 @@ export default class PersonalMessageManager extends EventEmitter { * @param {number} msgId - The id of the PersonalMessage to approve. * */ - setMsgStatusApproved (msgId) { + setMsgStatusApproved(msgId) { this._setMsgStatus(msgId, 'approved') } @@ -196,7 +210,7 @@ export default class PersonalMessageManager extends EventEmitter { * @param {buffer} rawSig - The raw data of the signature request * */ - setMsgStatusSigned (msgId, rawSig) { + setMsgStatusSigned(msgId, rawSig) { const msg = this.getMsg(msgId) msg.rawSig = rawSig this._updateMsg(msg) @@ -210,7 +224,7 @@ export default class PersonalMessageManager extends EventEmitter { * @returns {Promise} - Promises the msgParams with the metamaskId property removed * */ - prepMsgForSigning (msgParams) { + prepMsgForSigning(msgParams) { delete msgParams.metamaskId return Promise.resolve(msgParams) } @@ -221,7 +235,7 @@ export default class PersonalMessageManager extends EventEmitter { * @param {number} msgId - The id of the PersonalMessage to reject. * */ - rejectMsg (msgId) { + rejectMsg(msgId) { this._setMsgStatus(msgId, 'rejected') } @@ -238,10 +252,12 @@ export default class PersonalMessageManager extends EventEmitter { * with the PersonalMessage * */ - _setMsgStatus (msgId, status) { + _setMsgStatus(msgId, status) { const msg = this.getMsg(msgId) if (!msg) { - throw new Error(`PersonalMessageManager - Message not found for id: "${msgId}".`) + throw new Error( + `PersonalMessageManager - Message not found for id: "${msgId}".`, + ) } msg.status = status this._updateMsg(msg) @@ -260,7 +276,7 @@ export default class PersonalMessageManager extends EventEmitter { * id) in this.messages * */ - _updateMsg (msg) { + _updateMsg(msg) { const index = this.messages.findIndex((message) => message.id === msg.id) if (index !== -1) { this.messages[index] = msg @@ -275,10 +291,14 @@ export default class PersonalMessageManager extends EventEmitter { * @fires 'updateBadge' * */ - _saveMsgList () { + _saveMsgList() { const unapprovedPersonalMsgs = this.getUnapprovedMsgs() - const unapprovedPersonalMsgCount = Object.keys(unapprovedPersonalMsgs).length - this.memStore.updateState({ unapprovedPersonalMsgs, unapprovedPersonalMsgCount }) + const unapprovedPersonalMsgCount = Object.keys(unapprovedPersonalMsgs) + .length + this.memStore.updateState({ + unapprovedPersonalMsgs, + unapprovedPersonalMsgCount, + }) this.emit('updateBadge') } @@ -289,7 +309,7 @@ export default class PersonalMessageManager extends EventEmitter { * @returns {string} - A hex string conversion of the buffer data * */ - normalizeMsgData (data) { + normalizeMsgData(data) { try { const stripped = ethUtil.stripHexPrefix(data) if (stripped.match(hexRe)) { @@ -301,5 +321,4 @@ export default class PersonalMessageManager extends EventEmitter { return ethUtil.bufferToHex(Buffer.from(data, 'utf8')) } - } diff --git a/app/scripts/lib/random-id.js b/app/scripts/lib/random-id.js index 9345fcaad..a21717a2b 100644 --- a/app/scripts/lib/random-id.js +++ b/app/scripts/lib/random-id.js @@ -1,7 +1,7 @@ const MAX = Number.MAX_SAFE_INTEGER let idCounter = Math.round(Math.random() * MAX) -export default function createRandomId () { +export default function createRandomId() { idCounter %= MAX // eslint-disable-next-line no-plusplus return idCounter++ diff --git a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js index 106f38e44..fff0afb16 100644 --- a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js +++ b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js @@ -23,8 +23,8 @@ const handlerMap = handlers.reduce((map, handler) => { * @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) { +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) } diff --git a/app/scripts/lib/rpc-method-middleware/handlers/index.js b/app/scripts/lib/rpc-method-middleware/handlers/index.js index 3a538680b..bc87cb309 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/index.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/index.js @@ -1,6 +1,4 @@ import logWeb3Usage from './log-web3-usage' -const handlers = [ - logWeb3Usage, -] +const handlers = [logWeb3Usage] export default handlers diff --git a/app/scripts/lib/rpc-method-middleware/handlers/log-web3-usage.js b/app/scripts/lib/rpc-method-middleware/handlers/log-web3-usage.js index 91e4e60c2..003e6fa8a 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/log-web3-usage.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/log-web3-usage.js @@ -34,10 +34,7 @@ const recordedWeb3Usage = {} * @param {Function} end - The json-rpc-engine 'end' callback. * @param {LogWeb3UsageOptions} options */ -function logWeb3UsageHandler ( - req, res, _next, end, - { origin, sendMetrics }, -) { +function logWeb3UsageHandler(req, res, _next, end, { origin, sendMetrics }) { const { action, name } = req.params[0] if (!recordedWeb3Usage[origin]) { diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index 71b9e2819..bfcba0b28 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -2,7 +2,6 @@ import KeyringController from 'eth-keyring-controller' import log from 'loglevel' const seedPhraseVerifier = { - /** * Verifies if the seed words can restore the accounts. * @@ -15,8 +14,8 @@ const seedPhraseVerifier = { * @param {string} seedWords - The seed words to verify * @returns {Promise} - Promises undefined * - */ - async verifyAccounts (createdAccounts, seedWords) { + */ + async verifyAccounts(createdAccounts, seedWords) { if (!createdAccounts || createdAccounts.length < 1) { throw new Error('No created accounts defined.') } @@ -39,8 +38,12 @@ const seedPhraseVerifier = { } for (let i = 0; i < restoredAccounts.length; i++) { - if (restoredAccounts[i].toLowerCase() !== createdAccounts[i].toLowerCase()) { - throw new Error(`Not identical accounts! Original: ${createdAccounts[i]}, Restored: ${restoredAccounts[i]}`) + if ( + restoredAccounts[i].toLowerCase() !== createdAccounts[i].toLowerCase() + ) { + throw new Error( + `Not identical accounts! Original: ${createdAccounts[i]}, Restored: ${restoredAccounts[i]}`, + ) } } }, diff --git a/app/scripts/lib/setupFetchDebugging.js b/app/scripts/lib/setupFetchDebugging.js index 25f5431d5..8b566c31d 100644 --- a/app/scripts/lib/setupFetchDebugging.js +++ b/app/scripts/lib/setupFetchDebugging.js @@ -4,7 +4,7 @@ // https://github.com/getsentry/sentry-javascript/pull/1293 // -export default function setupFetchDebugging () { +export default function setupFetchDebugging() { if (!window.fetch) { return } @@ -12,14 +12,19 @@ export default function setupFetchDebugging () { window.fetch = wrappedFetch - async function wrappedFetch (...args) { + async function wrappedFetch(...args) { const initialStack = getCurrentStack() try { return await originalFetch.call(window, ...args) } catch (err) { if (!err.stack) { - console.warn('FetchDebugger - fetch encountered an Error without a stack', err) - console.warn('FetchDebugger - overriding stack to point of original call') + console.warn( + 'FetchDebugger - fetch encountered an Error without a stack', + err, + ) + console.warn( + 'FetchDebugger - overriding stack to point of original call', + ) err.stack = initialStack } throw err @@ -27,7 +32,7 @@ export default function setupFetchDebugging () { } } -function getCurrentStack () { +function getCurrentStack() { try { throw new Error('Fake error for generating stack trace') } catch (err) { diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index bf5490091..1deb4c94b 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -8,7 +8,8 @@ import extractEthjsErrorMessage from './extractEthjsErrorMessage' const METAMASK_DEBUG = process.env.METAMASK_DEBUG const METAMASK_ENVIRONMENT = process.env.METAMASK_ENVIRONMENT /* eslint-enable prefer-destructuring */ -const SENTRY_DSN_DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' +const SENTRY_DSN_DEV = + 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' // This describes the subset of Redux state attached to errors sent to Sentry // These properties have some potential to be useful for debugging, and they do @@ -66,19 +67,25 @@ export const SENTRY_STATE = { unconnectedAccount: true, } -export default function setupSentry ({ release, getState }) { +export default function setupSentry({ release, getState }) { let sentryTarget if (METAMASK_DEBUG) { return undefined } else if (METAMASK_ENVIRONMENT === 'production') { if (!process.env.SENTRY_DSN) { - throw new Error(`Missing SENTRY_DSN environment variable in production environment`) + throw new Error( + `Missing SENTRY_DSN environment variable in production environment`, + ) } - console.log(`Setting up Sentry Remote Error Reporting for '${METAMASK_ENVIRONMENT}': SENTRY_DSN`) + console.log( + `Setting up Sentry Remote Error Reporting for '${METAMASK_ENVIRONMENT}': SENTRY_DSN`, + ) sentryTarget = process.env.SENTRY_DSN } else { - console.log(`Setting up Sentry Remote Error Reporting for '${METAMASK_ENVIRONMENT}': SENTRY_DSN_DEV`) + console.log( + `Setting up Sentry Remote Error Reporting for '${METAMASK_ENVIRONMENT}': SENTRY_DSN_DEV`, + ) sentryTarget = SENTRY_DSN_DEV } @@ -86,15 +93,12 @@ export default function setupSentry ({ release, getState }) { dsn: sentryTarget, debug: METAMASK_DEBUG, environment: METAMASK_ENVIRONMENT, - integrations: [ - new Dedupe(), - new ExtraErrorData(), - ], + integrations: [new Dedupe(), new ExtraErrorData()], release, beforeSend: (report) => rewriteReport(report), }) - function rewriteReport (report) { + function rewriteReport(report) { try { // simplify certain complex error messages (e.g. Ethjs) simplifyErrorMessages(report) @@ -117,12 +121,16 @@ export default function setupSentry ({ release, getState }) { return Sentry } -function simplifyErrorMessages (report) { +function simplifyErrorMessages(report) { rewriteErrorMessages(report, (errorMessage) => { // simplify ethjs error messages let simplifiedErrorMessage = extractEthjsErrorMessage(errorMessage) // simplify 'Transaction Failed: known transaction' - if (simplifiedErrorMessage.indexOf('Transaction Failed: known transaction') === 0) { + if ( + simplifiedErrorMessage.indexOf( + 'Transaction Failed: known transaction', + ) === 0 + ) { // cut the hash from the error message simplifiedErrorMessage = 'Transaction Failed: known transaction' } @@ -130,7 +138,7 @@ function simplifyErrorMessages (report) { }) } -function rewriteErrorMessages (report, rewriteFn) { +function rewriteErrorMessages(report, rewriteFn) { // rewrite top level message if (typeof report.message === 'string') { report.message = rewriteFn(report.message) @@ -145,7 +153,7 @@ function rewriteErrorMessages (report, rewriteFn) { } } -function rewriteReportUrls (report) { +function rewriteReportUrls(report) { // update request url report.request.url = toMetamaskUrl(report.request.url) // update exception stack trace @@ -160,7 +168,7 @@ function rewriteReportUrls (report) { } } -function toMetamaskUrl (origUrl) { +function toMetamaskUrl(origUrl) { const filePath = origUrl.split(window.location.origin)[1] if (!filePath) { return origUrl diff --git a/app/scripts/lib/setupWeb3.js b/app/scripts/lib/setupWeb3.js index ad86751e1..248ca3fd1 100644 --- a/app/scripts/lib/setupWeb3.js +++ b/app/scripts/lib/setupWeb3.js @@ -5,13 +5,13 @@ import 'web3/dist/web3.min' -const shouldLogUsage = !([ +const shouldLogUsage = ![ 'docs.metamask.io', 'metamask.github.io', 'metamask.io', -].includes(window.location.hostname)) +].includes(window.location.hostname) -export default function setupWeb3 (log) { +export default function setupWeb3(log) { // export web3 as a global, checking for usage let reloadInProgress = false let lastTimeUsed @@ -33,13 +33,14 @@ export default function setupWeb3 (log) { const web3Proxy = new Proxy(web3, { get: (_web3, key) => { - // get the time of use lastTimeUsed = Date.now() // show warning once on web3 access if (!hasBeenWarned) { - console.warn(`MetaMask: We will stop injecting web3 in Q4 2020.\nPlease see this article for more information: https://medium.com/metamask/no-longer-injecting-web3-js-4a899ad6e59e`) + console.warn( + `MetaMask: We will stop injecting web3 in Q4 2020.\nPlease see this article for more information: https://medium.com/metamask/no-longer-injecting-web3-js-4a899ad6e59e`, + ) hasBeenWarned = true } @@ -118,7 +119,7 @@ export default function setupWeb3 (log) { } // reload the page -function triggerReset () { +function triggerReset() { global.location.reload() } @@ -128,8 +129,6 @@ function triggerReset () { * * @param {any} key - The key to stringify */ -function stringifyKey (key) { - return typeof key === 'string' - ? key - : `typeof ${typeof key}` +function stringifyKey(key) { + return typeof key === 'string' ? key : `typeof ${typeof key}` } diff --git a/app/scripts/lib/stream-utils.js b/app/scripts/lib/stream-utils.js index b1b4aeec3..32333a0c5 100644 --- a/app/scripts/lib/stream-utils.js +++ b/app/scripts/lib/stream-utils.js @@ -6,17 +6,12 @@ import pump from 'pump' * @param {any} connectionStream - the stream to mux * @returns {stream.Stream} - the multiplexed stream */ -export function setupMultiplex (connectionStream) { +export function setupMultiplex(connectionStream) { const mux = new ObjectMultiplex() - pump( - connectionStream, - mux, - connectionStream, - (err) => { - if (err) { - console.error(err) - } - }, - ) + pump(connectionStream, mux, connectionStream, (err) => { + if (err) { + console.error(err) + } + }) return mux } diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index 4769f6e4c..3cf40ee3c 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -28,11 +28,10 @@ import { MESSAGE_TYPE } from './enums' */ export default class TypedMessageManager extends EventEmitter { - /** * Controller in charge of managing - storing, adding, removing, updating - TypedMessage. */ - constructor ({ getCurrentChainId }) { + constructor({ getCurrentChainId }) { super() this._getCurrentChainId = getCurrentChainId this.memStore = new ObservableStore({ @@ -48,7 +47,7 @@ export default class TypedMessageManager extends EventEmitter { * @returns {number} - The number of 'unapproved' TypedMessages in this.messages * */ - get unapprovedTypedMessagesCount () { + get unapprovedTypedMessagesCount() { return Object.keys(this.getUnapprovedMsgs()).length } @@ -59,8 +58,9 @@ export default class TypedMessageManager extends EventEmitter { * this.messages * */ - getUnapprovedMsgs () { - return this.messages.filter((msg) => msg.status === 'unapproved') + getUnapprovedMsgs() { + return this.messages + .filter((msg) => msg.status === 'unapproved') .reduce((result, msg) => { result[msg.id] = msg return result @@ -77,7 +77,7 @@ export default class TypedMessageManager extends EventEmitter { * @returns {promise} - When the message has been signed or rejected * */ - addUnapprovedMessageAsync (msgParams, req, version) { + addUnapprovedMessageAsync(msgParams, req, version) { return new Promise((resolve, reject) => { const msgId = this.addUnapprovedMessage(msgParams, req, version) this.once(`${msgId}:finished`, (data) => { @@ -85,11 +85,23 @@ export default class TypedMessageManager extends EventEmitter { case 'signed': return resolve(data.rawSig) case 'rejected': - return reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.')) + return reject( + ethErrors.provider.userRejectedRequest( + 'MetaMask Message Signature: User denied message signature.', + ), + ) case 'errored': - return reject(new Error(`MetaMask Message Signature: ${data.error}`)) + return reject( + new Error(`MetaMask Message Signature: ${data.error}`), + ) default: - return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + return reject( + new Error( + `MetaMask Message Signature: Unknown problem: ${JSON.stringify( + msgParams, + )}`, + ), + ) } }) }) @@ -105,18 +117,19 @@ export default class TypedMessageManager extends EventEmitter { * @returns {number} - The id of the newly created TypedMessage. * */ - addUnapprovedMessage (msgParams, req, version) { - + addUnapprovedMessage(msgParams, req, version) { msgParams.version = version if (req) { msgParams.origin = req.origin } this.validateParams(msgParams) - log.debug(`TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) + log.debug( + `TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`, + ) // create txData obj with parameters and meta data - const time = (new Date()).getTime() + const time = new Date().getTime() const msgId = createId() const msgData = { id: msgId, @@ -138,8 +151,7 @@ export default class TypedMessageManager extends EventEmitter { * @param {Object} params - The params to validate * */ - validateParams (params) { - + validateParams(params) { assert.ok(params && typeof params === 'object', 'Params must be an object.') assert.ok('data' in params, 'Params must include a "data" field.') assert.ok('from' in params, 'Params must include a "from" field.') @@ -157,19 +169,40 @@ export default class TypedMessageManager extends EventEmitter { break case 'V3': case 'V4': { - assert.equal(typeof params.data, 'string', '"params.data" must be a string.') + assert.equal( + typeof params.data, + 'string', + '"params.data" must be a string.', + ) let data assert.doesNotThrow(() => { data = JSON.parse(params.data) }, '"data" must be a valid JSON string.') - const validation = jsonschema.validate(data, sigUtil.TYPED_MESSAGE_SCHEMA) - assert.ok(data.primaryType in data.types, `Primary type of "${data.primaryType}" has no type definition.`) - assert.equal(validation.errors.length, 0, 'Signing data must conform to EIP-712 schema. See https://git.io/fNtcx.') + const validation = jsonschema.validate( + data, + sigUtil.TYPED_MESSAGE_SCHEMA, + ) + assert.ok( + data.primaryType in data.types, + `Primary type of "${data.primaryType}" has no type definition.`, + ) + assert.equal( + validation.errors.length, + 0, + 'Signing data must conform to EIP-712 schema. See https://git.io/fNtcx.', + ) const { chainId } = data.domain if (chainId) { const activeChainId = parseInt(this._getCurrentChainId(), 16) - assert.ok(!Number.isNaN(activeChainId), `Cannot sign messages for chainId "${chainId}", because MetaMask is switching networks.`) - assert.equal(chainId, activeChainId, `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`) + assert.ok( + !Number.isNaN(activeChainId), + `Cannot sign messages for chainId "${chainId}", because MetaMask is switching networks.`, + ) + assert.equal( + chainId, + activeChainId, + `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`, + ) } break } @@ -185,7 +218,7 @@ export default class TypedMessageManager extends EventEmitter { * @param {Message} msg - The TypedMessage to add to this.messages * */ - addMsg (msg) { + addMsg(msg) { this.messages.push(msg) this._saveMsgList() } @@ -198,7 +231,7 @@ export default class TypedMessageManager extends EventEmitter { * if no TypedMessage has that id. * */ - getMsg (msgId) { + getMsg(msgId) { return this.messages.find((msg) => msg.id === msgId) } @@ -211,7 +244,7 @@ export default class TypedMessageManager extends EventEmitter { * @returns {Promise} - Promises the msgParams object with metamaskId removed. * */ - approveMessage (msgParams) { + approveMessage(msgParams) { this.setMsgStatusApproved(msgParams.metamaskId) return this.prepMsgForSigning(msgParams) } @@ -222,7 +255,7 @@ export default class TypedMessageManager extends EventEmitter { * @param {number} msgId - The id of the TypedMessage to approve. * */ - setMsgStatusApproved (msgId) { + setMsgStatusApproved(msgId) { this._setMsgStatus(msgId, 'approved') } @@ -234,7 +267,7 @@ export default class TypedMessageManager extends EventEmitter { * @param {buffer} rawSig - The raw data of the signature request * */ - setMsgStatusSigned (msgId, rawSig) { + setMsgStatusSigned(msgId, rawSig) { const msg = this.getMsg(msgId) msg.rawSig = rawSig this._updateMsg(msg) @@ -248,7 +281,7 @@ export default class TypedMessageManager extends EventEmitter { * @returns {Promise} - Promises the msgParams with the metamaskId property removed * */ - prepMsgForSigning (msgParams) { + prepMsgForSigning(msgParams) { delete msgParams.metamaskId delete msgParams.version return Promise.resolve(msgParams) @@ -260,7 +293,7 @@ export default class TypedMessageManager extends EventEmitter { * @param {number} msgId - The id of the TypedMessage to reject. * */ - rejectMsg (msgId) { + rejectMsg(msgId) { this._setMsgStatus(msgId, 'rejected') } @@ -270,7 +303,7 @@ export default class TypedMessageManager extends EventEmitter { * @param {number} msgId - The id of the TypedMessage to error * */ - errorMessage (msgId, error) { + errorMessage(msgId, error) { const msg = this.getMsg(msgId) msg.error = error this._updateMsg(msg) @@ -294,10 +327,12 @@ export default class TypedMessageManager extends EventEmitter { * with the TypedMessage * */ - _setMsgStatus (msgId, status) { + _setMsgStatus(msgId, status) { const msg = this.getMsg(msgId) if (!msg) { - throw new Error(`TypedMessageManager - Message not found for id: "${msgId}".`) + throw new Error( + `TypedMessageManager - Message not found for id: "${msgId}".`, + ) } msg.status = status this._updateMsg(msg) @@ -316,7 +351,7 @@ export default class TypedMessageManager extends EventEmitter { * id) in this.messages * */ - _updateMsg (msg) { + _updateMsg(msg) { const index = this.messages.findIndex((message) => message.id === msg.id) if (index !== -1) { this.messages[index] = msg @@ -331,11 +366,14 @@ export default class TypedMessageManager extends EventEmitter { * @fires 'updateBadge' * */ - _saveMsgList () { + _saveMsgList() { const unapprovedTypedMessages = this.getUnapprovedMsgs() - const unapprovedTypedMessagesCount = Object.keys(unapprovedTypedMessages).length - this.memStore.updateState({ unapprovedTypedMessages, unapprovedTypedMessagesCount }) + const unapprovedTypedMessagesCount = Object.keys(unapprovedTypedMessages) + .length + this.memStore.updateState({ + unapprovedTypedMessages, + unapprovedTypedMessagesCount, + }) this.emit('updateBadge') } - } diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js index 20ab998de..d727949ba 100644 --- a/app/scripts/lib/util.js +++ b/app/scripts/lib/util.js @@ -44,7 +44,8 @@ const getEnvironmentTypeMemo = memoize((url) => { * @param {string} [url] - the URL of the window * @returns {string} the environment ENUM */ -const getEnvironmentType = (url = window.location.href) => getEnvironmentTypeMemo(url) +const getEnvironmentType = (url = window.location.href) => + getEnvironmentTypeMemo(url) /** * Returns the platform (browser) where the extension is running. @@ -80,10 +81,18 @@ const getPlatform = (_) => { * @returns {boolean} - Whether the balance is greater than or equal to the value plus the value of gas times gasPrice * */ -function sufficientBalance (txParams, hexBalance) { +function sufficientBalance(txParams, hexBalance) { // validate hexBalance is a hex string - assert.equal(typeof hexBalance, 'string', 'sufficientBalance - hexBalance is not a hex string') - assert.equal(hexBalance.slice(0, 2), '0x', 'sufficientBalance - hexBalance is not a hex string') + assert.equal( + typeof hexBalance, + 'string', + 'sufficientBalance - hexBalance is not a hex string', + ) + assert.equal( + hexBalance.slice(0, 2), + '0x', + 'sufficientBalance - hexBalance is not a hex string', + ) const balance = hexToBn(hexBalance) const value = hexToBn(txParams.value) @@ -101,7 +110,7 @@ function sufficientBalance (txParams, hexBalance) { * @returns {string} - A '0x' prefixed hex string * */ -function bnToHex (inputBn) { +function bnToHex(inputBn) { return ethUtil.addHexPrefix(inputBn.toString(16)) } @@ -112,7 +121,7 @@ function bnToHex (inputBn) { * @returns {Object} - A BN object * */ -function hexToBn (inputHex) { +function hexToBn(inputHex) { return new BN(ethUtil.stripHexPrefix(inputHex), 16) } @@ -125,7 +134,7 @@ function hexToBn (inputHex) { * @returns {BN} - The product of the multiplication * */ -function BnMultiplyByFraction (targetBN, numerator, denominator) { +function BnMultiplyByFraction(targetBN, numerator, denominator) { const numBN = new BN(numerator) const denomBN = new BN(denominator) return targetBN.mul(numBN).div(denomBN) @@ -136,7 +145,7 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) { * this is a workaround for the non-standard error object that's used * @returns {Error|undefined} */ -function checkForError () { +function checkForError() { const { lastError } = extension.runtime if (!lastError) { return undefined @@ -157,11 +166,11 @@ function checkForError () { * @returns {boolean} True if the value is a correctly formatted hex string, * false otherwise. */ -function isPrefixedFormattedHexString (value) { +function isPrefixedFormattedHexString(value) { if (typeof value !== 'string') { return false } - return (/^0x[1-9a-f]+[0-9a-f]*$/ui).test(value) + return /^0x[1-9a-f]+[0-9a-f]*$/iu.test(value) } export { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index e8a6a68da..5f0bcc7d5 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -60,12 +60,11 @@ import seedPhraseVerifier from './lib/seed-phrase-verifier' import { ENVIRONMENT_TYPE_BACKGROUND } from './lib/enums' export default class MetamaskController extends EventEmitter { - /** * @constructor * @param {Object} opts */ - constructor (opts) { + constructor(opts) { super() this.defaultMaxListeners = 20 @@ -125,7 +124,8 @@ export default class MetamaskController extends EventEmitter { } = this.preferencesController.store.getState() const chainId = this.networkController.getCurrentChainId() const provider = this.networkController.getProviderConfig() - const network = provider.type === 'rpc' ? provider.rpcUrl : provider.type + const network = + provider.type === 'rpc' ? provider.rpcUrl : provider.type return { participateInMetaMetrics, metaMetricsId, @@ -153,7 +153,10 @@ export default class MetamaskController extends EventEmitter { preferencesStore: this.preferencesController.store, }) - this.currencyRateController = new CurrencyRateController(undefined, initState.CurrencyController) + this.currencyRateController = new CurrencyRateController( + undefined, + initState.CurrencyController, + ) this.phishingController = new PhishingController() @@ -184,7 +187,9 @@ export default class MetamaskController extends EventEmitter { this.accountTracker = new AccountTracker({ provider: this.provider, blockTracker: this.blockTracker, - getCurrentChainId: this.networkController.getCurrentChainId.bind(this.networkController), + getCurrentChainId: this.networkController.getCurrentChainId.bind( + this.networkController, + ), }) // start and stop polling for balances based on activeControllerConnections @@ -202,7 +207,9 @@ export default class MetamaskController extends EventEmitter { this.cachedBalancesController = new CachedBalancesController({ accountTracker: this.accountTracker, - getNetwork: this.networkController.getNetworkState.bind(this.networkController), + getNetwork: this.networkController.getNetworkState.bind( + this.networkController, + ), initState: initState.CachedBalancesController, }) @@ -222,18 +229,28 @@ export default class MetamaskController extends EventEmitter { initState: initState.KeyringController, encryptor: opts.encryptor || undefined, }) - this.keyringController.memStore.subscribe((s) => this._onKeyringControllerUpdate(s)) + this.keyringController.memStore.subscribe((s) => + this._onKeyringControllerUpdate(s), + ) this.keyringController.on('unlock', () => this.emit('unlock')) - this.permissionsController = new PermissionsController({ - getKeyringAccounts: this.keyringController.getAccounts.bind(this.keyringController), - getRestrictedMethods, - getUnlockPromise: this.appStateController.getUnlockPromise.bind(this.appStateController), - notifyDomain: this.notifyConnections.bind(this), - notifyAllDomains: this.notifyAllConnections.bind(this), - preferences: this.preferencesController.store, - showPermissionRequest: opts.showPermissionRequest, - }, initState.PermissionsController, initState.PermissionsMetadata) + this.permissionsController = new PermissionsController( + { + getKeyringAccounts: this.keyringController.getAccounts.bind( + this.keyringController, + ), + getRestrictedMethods, + getUnlockPromise: this.appStateController.getUnlockPromise.bind( + this.appStateController, + ), + notifyDomain: this.notifyConnections.bind(this), + notifyAllDomains: this.notifyAllConnections.bind(this), + preferences: this.preferencesController.store, + showPermissionRequest: opts.showPermissionRequest, + }, + initState.PermissionsController, + initState.PermissionsMetadata, + ) this.detectTokensController = new DetectTokensController({ preferences: this.preferencesController, @@ -241,7 +258,10 @@ export default class MetamaskController extends EventEmitter { keyringMemStore: this.keyringController.memStore, }) - this.addressBookController = new AddressBookController(undefined, initState.AddressBookController) + this.addressBookController = new AddressBookController( + undefined, + initState.AddressBookController, + ) this.alertController = new AlertController({ initState: initState.AlertController, @@ -253,23 +273,33 @@ export default class MetamaskController extends EventEmitter { addressBookController: this.addressBookController, keyringController: this.keyringController, initState: initState.ThreeBoxController, - getKeyringControllerState: this.keyringController.memStore.getState.bind(this.keyringController.memStore), + getKeyringControllerState: this.keyringController.memStore.getState.bind( + this.keyringController.memStore, + ), version, }) this.txController = new TransactionController({ - initState: initState.TransactionController || initState.TransactionManager, - getPermittedAccounts: this.permissionsController.getAccounts.bind(this.permissionsController), + initState: + initState.TransactionController || initState.TransactionManager, + getPermittedAccounts: this.permissionsController.getAccounts.bind( + this.permissionsController, + ), networkStore: this.networkController.networkStore, - getCurrentChainId: this.networkController.getCurrentChainId.bind(this.networkController), + getCurrentChainId: this.networkController.getCurrentChainId.bind( + this.networkController, + ), preferencesStore: this.preferencesController.store, txHistoryLimit: 40, getNetwork: this.networkController.getNetworkState.bind(this), - signTransaction: this.keyringController.signTransaction.bind(this.keyringController), + signTransaction: this.keyringController.signTransaction.bind( + this.keyringController, + ), provider: this.provider, blockTracker: this.blockTracker, trackMetaMetricsEvent: this.trackMetaMetricsEvent, - getParticipateInMetrics: () => this.preferencesController.getParticipateInMetaMetrics(), + getParticipateInMetrics: () => + this.preferencesController.getParticipateInMetaMetrics(), }) this.txController.on('newUnapprovedTx', () => opts.showUnapprovedTx()) @@ -306,14 +336,20 @@ export default class MetamaskController extends EventEmitter { this.decryptMessageManager = new DecryptMessageManager() this.encryptionPublicKeyManager = new EncryptionPublicKeyManager() this.typedMessageManager = new TypedMessageManager({ - getCurrentChainId: this.networkController.getCurrentChainId.bind(this.networkController), + getCurrentChainId: this.networkController.getCurrentChainId.bind( + this.networkController, + ), }) this.swapsController = new SwapsController({ - getBufferedGasLimit: this.txController.txGasUtil.getBufferedGasLimit.bind(this.txController.txGasUtil), + getBufferedGasLimit: this.txController.txGasUtil.getBufferedGasLimit.bind( + this.txController.txGasUtil, + ), networkController: this.networkController, provider: this.provider, - getProviderConfig: this.networkController.getProviderConfig.bind(this.networkController), + getProviderConfig: this.networkController.getProviderConfig.bind( + this.networkController, + ), tokenRatesStore: this.tokenRatesController.store, }) @@ -364,7 +400,8 @@ export default class MetamaskController extends EventEmitter { const password = process.env.CONF?.password if ( - password && !this.isUnlocked() && + password && + !this.isUnlocked() && this.onboardingController.completedOnboarding ) { this.submitPassword(password) @@ -374,7 +411,7 @@ export default class MetamaskController extends EventEmitter { /** * Constructor helper: initialize a provider. */ - initializeProvider () { + initializeProvider() { const version = this.platform.getVersion() const providerOpts = { static: { @@ -403,9 +440,12 @@ export default class MetamaskController extends EventEmitter { processDecryptMessage: this.newRequestDecryptMessage.bind(this), processEncryptionPublicKey: this.newRequestEncryptionPublicKey.bind(this), getPendingNonce: this.getPendingNonce.bind(this), - getPendingTransactionByHash: (hash) => this.txController.getFilteredTxList({ hash, status: 'submitted' })[0], + getPendingTransactionByHash: (hash) => + this.txController.getFilteredTxList({ hash, status: 'submitted' })[0], } - const providerProxy = this.networkController.initializeProvider(providerOpts) + const providerProxy = this.networkController.initializeProvider( + providerOpts, + ) return providerProxy } @@ -413,7 +453,7 @@ export default class MetamaskController extends EventEmitter { * Constructor helper: initialize a public config store. * This store is used to make some config info available to Dapps synchronously. */ - createPublicConfigStore () { + createPublicConfigStore() { // subset of state for metamask inpage provider const publicConfigStore = new ObservableStore() const { networkController } = this @@ -423,17 +463,18 @@ export default class MetamaskController extends EventEmitter { updatePublicConfigStore(this.getState()) publicConfigStore.destroy = () => { - this.removeEventListener && this.removeEventListener('update', updatePublicConfigStore) + this.removeEventListener && + this.removeEventListener('update', updatePublicConfigStore) } - function updatePublicConfigStore (memState) { + function updatePublicConfigStore(memState) { const chainId = networkController.getCurrentChainId() if (memState.network !== 'loading') { publicConfigStore.putState(selectPublicState(chainId, memState)) } } - function selectPublicState (chainId, { isUnlocked, network }) { + function selectPublicState(chainId, { isUnlocked, network }) { return { isUnlocked, chainId, @@ -452,7 +493,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {Object} - status */ - getState () { + getState() { const { vault } = this.keyringController.store.getState() const isInitialized = Boolean(vault) @@ -469,7 +510,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {Object} - Object containing API functions. */ - getApi () { + getApi() { const { keyringController, networkController, @@ -511,7 +552,10 @@ export default class MetamaskController extends EventEmitter { connectHardware: nodeify(this.connectHardware, this), forgetDevice: nodeify(this.forgetDevice, this), checkHardwareStatus: nodeify(this.checkHardwareStatus, this), - unlockHardwareWalletAccount: nodeify(this.unlockHardwareWalletAccount, this), + unlockHardwareWalletAccount: nodeify( + this.unlockHardwareWalletAccount, + this, + ), // mobile fetchInfoToSync: nodeify(this.fetchInfoToSync, this), @@ -521,45 +565,99 @@ export default class MetamaskController extends EventEmitter { verifyPassword: nodeify(this.verifyPassword, this), // network management - setProviderType: nodeify(networkController.setProviderType, networkController), + setProviderType: nodeify( + networkController.setProviderType, + networkController, + ), setCustomRpc: nodeify(this.setCustomRpc, this), updateAndSetCustomRpc: nodeify(this.updateAndSetCustomRpc, this), delCustomRpc: nodeify(this.delCustomRpc, this), // PreferencesController - setSelectedAddress: nodeify(preferencesController.setSelectedAddress, preferencesController), + setSelectedAddress: nodeify( + preferencesController.setSelectedAddress, + preferencesController, + ), addToken: nodeify(preferencesController.addToken, preferencesController), - removeToken: nodeify(preferencesController.removeToken, preferencesController), - removeSuggestedTokens: nodeify(preferencesController.removeSuggestedTokens, preferencesController), - setAccountLabel: nodeify(preferencesController.setAccountLabel, preferencesController), - setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController), - setPreference: nodeify(preferencesController.setPreference, preferencesController), - completeOnboarding: nodeify(preferencesController.completeOnboarding, preferencesController), - addKnownMethodData: nodeify(preferencesController.addKnownMethodData, preferencesController), + removeToken: nodeify( + preferencesController.removeToken, + preferencesController, + ), + removeSuggestedTokens: nodeify( + preferencesController.removeSuggestedTokens, + preferencesController, + ), + setAccountLabel: nodeify( + preferencesController.setAccountLabel, + preferencesController, + ), + setFeatureFlag: nodeify( + preferencesController.setFeatureFlag, + preferencesController, + ), + setPreference: nodeify( + preferencesController.setPreference, + preferencesController, + ), + completeOnboarding: nodeify( + preferencesController.completeOnboarding, + preferencesController, + ), + addKnownMethodData: nodeify( + preferencesController.addKnownMethodData, + preferencesController, + ), // AddressController - setAddressBook: nodeify(this.addressBookController.set, this.addressBookController), - removeFromAddressBook: nodeify(this.addressBookController.delete, this.addressBookController), + setAddressBook: nodeify( + this.addressBookController.set, + this.addressBookController, + ), + removeFromAddressBook: nodeify( + this.addressBookController.delete, + this.addressBookController, + ), // AppStateController - setLastActiveTime: nodeify(this.appStateController.setLastActiveTime, this.appStateController), - setDefaultHomeActiveTabName: nodeify(this.appStateController.setDefaultHomeActiveTabName, this.appStateController), - setConnectedStatusPopoverHasBeenShown: nodeify(this.appStateController.setConnectedStatusPopoverHasBeenShown, this.appStateController), - setSwapsWelcomeMessageHasBeenShown: nodeify(this.appStateController.setSwapsWelcomeMessageHasBeenShown, this.appStateController), + setLastActiveTime: nodeify( + this.appStateController.setLastActiveTime, + this.appStateController, + ), + setDefaultHomeActiveTabName: nodeify( + this.appStateController.setDefaultHomeActiveTabName, + this.appStateController, + ), + setConnectedStatusPopoverHasBeenShown: nodeify( + this.appStateController.setConnectedStatusPopoverHasBeenShown, + this.appStateController, + ), + setSwapsWelcomeMessageHasBeenShown: nodeify( + this.appStateController.setSwapsWelcomeMessageHasBeenShown, + this.appStateController, + ), // EnsController - tryReverseResolveAddress: nodeify(this.ensController.reverseResolveAddress, this.ensController), + tryReverseResolveAddress: nodeify( + this.ensController.reverseResolveAddress, + this.ensController, + ), // KeyringController setLocked: nodeify(this.setLocked, this), createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this), createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this), - exportAccount: nodeify(keyringController.exportAccount, keyringController), + exportAccount: nodeify( + keyringController.exportAccount, + keyringController, + ), // txController cancelTransaction: nodeify(txController.cancelTransaction, txController), updateTransaction: nodeify(txController.updateTransaction, txController), - updateAndApproveTransaction: nodeify(txController.updateAndApproveTransaction, txController), + updateAndApproveTransaction: nodeify( + txController.updateAndApproveTransaction, + txController, + ), createCancelTransaction: nodeify(this.createCancelTransaction, this), createSpeedUpTransaction: nodeify(this.createSpeedUpTransaction, this), getFilteredTxList: nodeify(txController.getFilteredTxList, txController), @@ -567,7 +665,10 @@ export default class MetamaskController extends EventEmitter { estimateGas: nodeify(this.estimateGas, this), getPendingNonce: nodeify(this.getPendingNonce, this), getNextNonce: nodeify(this.getNextNonce, this), - addUnapprovedTransaction: nodeify(txController.addUnapprovedTransaction, txController), + addUnapprovedTransaction: nodeify( + txController.addUnapprovedTransaction, + txController, + ), // messageManager signMessage: nodeify(this.signMessage, this), @@ -591,47 +692,132 @@ export default class MetamaskController extends EventEmitter { cancelEncryptionPublicKey: this.cancelEncryptionPublicKey.bind(this), // onboarding controller - setSeedPhraseBackedUp: nodeify(onboardingController.setSeedPhraseBackedUp, onboardingController), + setSeedPhraseBackedUp: nodeify( + onboardingController.setSeedPhraseBackedUp, + onboardingController, + ), // alert controller - setAlertEnabledness: nodeify(alertController.setAlertEnabledness, alertController), - setUnconnectedAccountAlertShown: nodeify(this.alertController.setUnconnectedAccountAlertShown, this.alertController), + setAlertEnabledness: nodeify( + alertController.setAlertEnabledness, + alertController, + ), + setUnconnectedAccountAlertShown: nodeify( + this.alertController.setUnconnectedAccountAlertShown, + this.alertController, + ), // 3Box - setThreeBoxSyncingPermission: nodeify(threeBoxController.setThreeBoxSyncingPermission, threeBoxController), - restoreFromThreeBox: nodeify(threeBoxController.restoreFromThreeBox, threeBoxController), - setShowRestorePromptToFalse: nodeify(threeBoxController.setShowRestorePromptToFalse, threeBoxController), - getThreeBoxLastUpdated: nodeify(threeBoxController.getLastUpdated, threeBoxController), - turnThreeBoxSyncingOn: nodeify(threeBoxController.turnThreeBoxSyncingOn, threeBoxController), + setThreeBoxSyncingPermission: nodeify( + threeBoxController.setThreeBoxSyncingPermission, + threeBoxController, + ), + restoreFromThreeBox: nodeify( + threeBoxController.restoreFromThreeBox, + threeBoxController, + ), + setShowRestorePromptToFalse: nodeify( + threeBoxController.setShowRestorePromptToFalse, + threeBoxController, + ), + getThreeBoxLastUpdated: nodeify( + threeBoxController.getLastUpdated, + threeBoxController, + ), + turnThreeBoxSyncingOn: nodeify( + threeBoxController.turnThreeBoxSyncingOn, + threeBoxController, + ), initializeThreeBox: nodeify(this.initializeThreeBox, this), // permissions - approvePermissionsRequest: nodeify(permissionsController.approvePermissionsRequest, permissionsController), - clearPermissions: permissionsController.clearPermissions.bind(permissionsController), - getApprovedAccounts: nodeify(permissionsController.getAccounts, permissionsController), - rejectPermissionsRequest: nodeify(permissionsController.rejectPermissionsRequest, permissionsController), - removePermissionsFor: permissionsController.removePermissionsFor.bind(permissionsController), - addPermittedAccount: nodeify(permissionsController.addPermittedAccount, permissionsController), - removePermittedAccount: nodeify(permissionsController.removePermittedAccount, permissionsController), - requestAccountsPermissionWithId: nodeify(permissionsController.requestAccountsPermissionWithId, permissionsController), + approvePermissionsRequest: nodeify( + permissionsController.approvePermissionsRequest, + permissionsController, + ), + clearPermissions: permissionsController.clearPermissions.bind( + permissionsController, + ), + getApprovedAccounts: nodeify( + permissionsController.getAccounts, + permissionsController, + ), + rejectPermissionsRequest: nodeify( + permissionsController.rejectPermissionsRequest, + permissionsController, + ), + removePermissionsFor: permissionsController.removePermissionsFor.bind( + permissionsController, + ), + addPermittedAccount: nodeify( + permissionsController.addPermittedAccount, + permissionsController, + ), + removePermittedAccount: nodeify( + permissionsController.removePermittedAccount, + permissionsController, + ), + requestAccountsPermissionWithId: nodeify( + permissionsController.requestAccountsPermissionWithId, + permissionsController, + ), // swaps - fetchAndSetQuotes: nodeify(swapsController.fetchAndSetQuotes, swapsController), - setSelectedQuoteAggId: nodeify(swapsController.setSelectedQuoteAggId, swapsController), - resetSwapsState: nodeify(swapsController.resetSwapsState, swapsController), + fetchAndSetQuotes: nodeify( + swapsController.fetchAndSetQuotes, + swapsController, + ), + setSelectedQuoteAggId: nodeify( + swapsController.setSelectedQuoteAggId, + swapsController, + ), + resetSwapsState: nodeify( + swapsController.resetSwapsState, + swapsController, + ), setSwapsTokens: nodeify(swapsController.setSwapsTokens, swapsController), setApproveTxId: nodeify(swapsController.setApproveTxId, swapsController), setTradeTxId: nodeify(swapsController.setTradeTxId, swapsController), - setSwapsTxGasPrice: nodeify(swapsController.setSwapsTxGasPrice, swapsController), - setSwapsTxGasLimit: nodeify(swapsController.setSwapsTxGasLimit, swapsController), - safeRefetchQuotes: nodeify(swapsController.safeRefetchQuotes, swapsController), - stopPollingForQuotes: nodeify(swapsController.stopPollingForQuotes, swapsController), - setBackgroundSwapRouteState: nodeify(swapsController.setBackgroundSwapRouteState, swapsController), - resetPostFetchState: nodeify(swapsController.resetPostFetchState, swapsController), - setSwapsErrorKey: nodeify(swapsController.setSwapsErrorKey, swapsController), - setInitialGasEstimate: nodeify(swapsController.setInitialGasEstimate, swapsController), - setCustomApproveTxData: nodeify(swapsController.setCustomApproveTxData, swapsController), - setSwapsLiveness: nodeify(swapsController.setSwapsLiveness, swapsController), + setSwapsTxGasPrice: nodeify( + swapsController.setSwapsTxGasPrice, + swapsController, + ), + setSwapsTxGasLimit: nodeify( + swapsController.setSwapsTxGasLimit, + swapsController, + ), + safeRefetchQuotes: nodeify( + swapsController.safeRefetchQuotes, + swapsController, + ), + stopPollingForQuotes: nodeify( + swapsController.stopPollingForQuotes, + swapsController, + ), + setBackgroundSwapRouteState: nodeify( + swapsController.setBackgroundSwapRouteState, + swapsController, + ), + resetPostFetchState: nodeify( + swapsController.resetPostFetchState, + swapsController, + ), + setSwapsErrorKey: nodeify( + swapsController.setSwapsErrorKey, + swapsController, + ), + setInitialGasEstimate: nodeify( + swapsController.setInitialGasEstimate, + swapsController, + ), + setCustomApproveTxData: nodeify( + swapsController.setCustomApproveTxData, + swapsController, + ), + setSwapsLiveness: nodeify( + swapsController.setSwapsLiveness, + swapsController, + ), } } @@ -653,7 +839,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {Object} - vault */ - async createNewVaultAndKeychain (password) { + async createNewVaultAndKeychain(password) { const releaseLock = await this.createVaultMutex.acquire() try { let vault @@ -677,7 +863,7 @@ export default class MetamaskController extends EventEmitter { * @param {} password * @param {} seed */ - async createNewVaultAndRestore (password, seed) { + async createNewVaultAndRestore(password, seed) { const releaseLock = await this.createVaultMutex.acquire() try { let accounts, lastBalance @@ -700,13 +886,21 @@ export default class MetamaskController extends EventEmitter { this.txController.txStateManager.clearUnapprovedTxs() // create new vault - const vault = await keyringController.createNewVaultAndRestore(password, seed) + const vault = await keyringController.createNewVaultAndRestore( + password, + seed, + ) const ethQuery = new EthQuery(this.provider) accounts = await keyringController.getAccounts() - lastBalance = await this.getBalance(accounts[accounts.length - 1], ethQuery) + lastBalance = await this.getBalance( + accounts[accounts.length - 1], + ethQuery, + ) - const primaryKeyring = keyringController.getKeyringsByType('HD Key Tree')[0] + const primaryKeyring = keyringController.getKeyringsByType( + 'HD Key Tree', + )[0] if (!primaryKeyring) { throw new Error('MetamaskController - No HD Key Tree found') } @@ -715,7 +909,10 @@ export default class MetamaskController extends EventEmitter { while (lastBalance !== '0x0') { await keyringController.addNewAccount(primaryKeyring) accounts = await keyringController.getAccounts() - lastBalance = await this.getBalance(accounts[accounts.length - 1], ethQuery) + lastBalance = await this.getBalance( + accounts[accounts.length - 1], + ethQuery, + ) } // set new identities @@ -732,7 +929,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} address - The account address * @param {EthQuery} ethQuery - The EthQuery instance to use when asking the network */ - getBalance (address, ethQuery) { + getBalance(address, ethQuery) { return new Promise((resolve, reject) => { const cached = this.accountTracker.store.getState().accounts[address] @@ -760,7 +957,7 @@ export default class MetamaskController extends EventEmitter { * with the mobile client for syncing purposes * @returns {Promise} - Parts of the state that we want to syncx */ - async fetchInfoToSync () { + async fetchInfoToSync() { // Preferences const { accountTokens, @@ -777,14 +974,19 @@ export default class MetamaskController extends EventEmitter { const checksummedAddress = ethUtil.toChecksumAddress(address) filteredAccountTokens[checksummedAddress] = {} Object.keys(accountTokens[address]).forEach((networkType) => { - filteredAccountTokens[checksummedAddress][networkType] = networkType === 'mainnet' - ? ( - accountTokens[address][networkType].filter(({ address: tokenAddress }) => { - const checksumAddress = ethUtil.toChecksumAddress(tokenAddress) - return contractMap[checksumAddress] ? contractMap[checksumAddress].erc20 : true - }) - ) - : accountTokens[address][networkType] + filteredAccountTokens[checksummedAddress][networkType] = + networkType === 'mainnet' + ? accountTokens[address][networkType].filter( + ({ address: tokenAddress }) => { + const checksumAddress = ethUtil.toChecksumAddress( + tokenAddress, + ) + return contractMap[checksumAddress] + ? contractMap[checksumAddress].erc20 + : true + }, + ) + : accountTokens[address][networkType] }) }) @@ -799,15 +1001,24 @@ export default class MetamaskController extends EventEmitter { // Accounts const hdKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] - const simpleKeyPairKeyrings = this.keyringController.getKeyringsByType('Simple Key Pair') + const simpleKeyPairKeyrings = this.keyringController.getKeyringsByType( + 'Simple Key Pair', + ) const hdAccounts = await hdKeyring.getAccounts() const simpleKeyPairKeyringAccounts = await Promise.all( simpleKeyPairKeyrings.map((keyring) => keyring.getAccounts()), ) - const simpleKeyPairAccounts = simpleKeyPairKeyringAccounts.reduce((acc, accounts) => [...acc, ...accounts], []) + const simpleKeyPairAccounts = simpleKeyPairKeyringAccounts.reduce( + (acc, accounts) => [...acc, ...accounts], + [], + ) const accounts = { - hd: hdAccounts.filter((item, pos) => (hdAccounts.indexOf(item) === pos)).map((address) => ethUtil.toChecksumAddress(address)), - simpleKeyPair: simpleKeyPairAccounts.filter((item, pos) => (simpleKeyPairAccounts.indexOf(item) === pos)).map((address) => ethUtil.toChecksumAddress(address)), + hd: hdAccounts + .filter((item, pos) => hdAccounts.indexOf(item) === pos) + .map((address) => ethUtil.toChecksumAddress(address)), + simpleKeyPair: simpleKeyPairAccounts + .filter((item, pos) => simpleKeyPairAccounts.indexOf(item) === pos) + .map((address) => ethUtil.toChecksumAddress(address)), ledger: [], trezor: [], } @@ -818,9 +1029,7 @@ export default class MetamaskController extends EventEmitter { // delete tx for other accounts that we're not importing transactions = transactions.filter((tx) => { const checksummedTxFrom = ethUtil.toChecksumAddress(tx.txParams.from) - return ( - accounts.hd.includes(checksummedTxFrom) - ) + return accounts.hd.includes(checksummedTxFrom) }) return { @@ -839,7 +1048,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} password - The user's password * @returns {Promise} - The keyringController update. */ - async submitPassword (password) { + async submitPassword(password) { await this.keyringController.submitPassword(password) try { @@ -869,7 +1078,7 @@ export default class MetamaskController extends EventEmitter { * * @param {string} password The user's password */ - async verifyPassword (password) { + async verifyPassword(password) { await this.keyringController.verifyPassword(password) } @@ -884,7 +1093,7 @@ export default class MetamaskController extends EventEmitter { /** * Sets the first address in the state to the selected address */ - selectFirstIdentity () { + selectFirstIdentity() { const { identities } = this.preferencesController.store.getState() const address = Object.keys(identities)[0] this.preferencesController.setSelectedAddress(address) @@ -894,7 +1103,7 @@ export default class MetamaskController extends EventEmitter { // Hardware // - async getKeyringForDevice (deviceName, hdPath = null) { + async getKeyringForDevice(deviceName, hdPath = null) { let keyringName = null switch (deviceName) { case 'trezor': @@ -904,7 +1113,9 @@ export default class MetamaskController extends EventEmitter { keyringName = LedgerBridgeKeyring.type break default: - throw new Error('MetamaskController:getKeyringForDevice - Unknown device') + throw new Error( + 'MetamaskController:getKeyringForDevice - Unknown device', + ) } let keyring = await this.keyringController.getKeyringsByType(keyringName)[0] if (!keyring) { @@ -917,7 +1128,6 @@ export default class MetamaskController extends EventEmitter { keyring.network = this.networkController.getProviderConfig().type return keyring - } /** @@ -925,7 +1135,7 @@ export default class MetamaskController extends EventEmitter { * * @returns [] accounts */ - async connectHardware (deviceName, page, hdPath) { + async connectHardware(deviceName, page, hdPath) { const keyring = await this.getKeyringForDevice(deviceName, hdPath) let accounts = [] switch (page) { @@ -942,7 +1152,11 @@ export default class MetamaskController extends EventEmitter { // Merge with existing accounts // and make sure addresses are not repeated const oldAccounts = await this.keyringController.getAccounts() - const accountsToTrack = [...new Set(oldAccounts.concat(accounts.map((a) => a.address.toLowerCase())))] + const accountsToTrack = [ + ...new Set( + oldAccounts.concat(accounts.map((a) => a.address.toLowerCase())), + ), + ] this.accountTracker.syncWithAddresses(accountsToTrack) return accounts } @@ -952,7 +1166,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {Promise} */ - async checkHardwareStatus (deviceName, hdPath) { + async checkHardwareStatus(deviceName, hdPath) { const keyring = await this.getKeyringForDevice(deviceName, hdPath) return keyring.isUnlocked() } @@ -962,8 +1176,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {Promise} */ - async forgetDevice (deviceName) { - + async forgetDevice(deviceName) { const keyring = await this.getKeyringForDevice(deviceName) keyring.forgetDevice() return true @@ -974,7 +1187,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {} keyState */ - async unlockHardwareWalletAccount (index, deviceName, hdPath) { + async unlockHardwareWalletAccount(index, deviceName, hdPath) { const keyring = await this.getKeyringForDevice(deviceName, hdPath) keyring.setAccountToUnlock(index) @@ -985,7 +1198,12 @@ export default class MetamaskController extends EventEmitter { newAccounts.forEach((address) => { if (!oldAccounts.includes(address)) { // Set the account label to Trezor 1 / Ledger 1, etc - this.preferencesController.setAccountLabel(address, `${deviceName[0].toUpperCase()}${deviceName.slice(1)} ${parseInt(index, 10) + 1}`) + this.preferencesController.setAccountLabel( + address, + `${deviceName[0].toUpperCase()}${deviceName.slice(1)} ${ + parseInt(index, 10) + 1 + }`, + ) // Select the account this.preferencesController.setSelectedAddress(address) } @@ -1004,8 +1222,10 @@ export default class MetamaskController extends EventEmitter { * * @returns {} keyState */ - async addNewAccount () { - const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + async addNewAccount() { + const primaryKeyring = this.keyringController.getKeyringsByType( + 'HD Key Tree', + )[0] if (!primaryKeyring) { throw new Error('MetamaskController - No HD Key Tree found') } @@ -1036,9 +1256,10 @@ export default class MetamaskController extends EventEmitter { * * @returns {Promise} - Seed phrase to be confirmed by the user. */ - async verifySeedPhrase () { - - const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + async verifySeedPhrase() { + const primaryKeyring = this.keyringController.getKeyringsByType( + 'HD Key Tree', + )[0] if (!primaryKeyring) { throw new Error('MetamaskController - No HD Key Tree found') } @@ -1067,7 +1288,7 @@ export default class MetamaskController extends EventEmitter { * * @returns {Promise} - The current selected address. */ - async resetAccount () { + async resetAccount() { const selectedAddress = this.preferencesController.getSelectedAddress() this.txController.wipeTransactions(selectedAddress) this.networkController.resetConnection() @@ -1081,7 +1302,7 @@ export default class MetamaskController extends EventEmitter { * @param {string[]} address - A hex address * */ - async removeAccount (address) { + async removeAccount(address) { // Remove all associated permissions await this.permissionsController.removeAllAccountPermissions(address) // Remove account from the preferences controller @@ -1103,9 +1324,12 @@ export default class MetamaskController extends EventEmitter { * @param {any} args - The data required by that strategy to import an account. * @param {Function} cb - A callback function called with a state update on success. */ - async importAccountWithStrategy (strategy, args) { + async importAccountWithStrategy(strategy, args) { const privateKey = await accountImporter.importAccount(strategy, args) - const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [privateKey]) + const keyring = await this.keyringController.addNewKeyring( + 'Simple Key Pair', + [privateKey], + ) const accounts = await keyring.getAccounts() // update accounts in preferences controller const allAccounts = await this.keyringController.getAccounts() @@ -1125,7 +1349,7 @@ export default class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_sign. * @param {Object} req - (optional) the original request, containing the origin */ - async newUnapprovedTransaction (txParams, req) { + async newUnapprovedTransaction(txParams, req) { return await this.txController.newUnapprovedTransaction(txParams, req) } @@ -1140,8 +1364,11 @@ export default class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_sign. * @param {Function} cb = The callback function called with the signature. */ - newUnsignedMessage (msgParams, req) { - const promise = this.messageManager.addUnapprovedMessageAsync(msgParams, req) + newUnsignedMessage(msgParams, req) { + const promise = this.messageManager.addUnapprovedMessageAsync( + msgParams, + req, + ) this.sendUpdate() this.opts.showUnconfirmedMessage() return promise @@ -1153,20 +1380,21 @@ export default class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_call. * @returns {Promise} - Full state update. */ - signMessage (msgParams) { + signMessage(msgParams) { log.info('MetaMaskController - signMessage') const msgId = msgParams.metamaskId // sets the status op the message to 'approved' // and removes the metamaskId for signing - return this.messageManager.approveMessage(msgParams) + return this.messageManager + .approveMessage(msgParams) .then((cleanMsgParams) => { - // signs the message + // signs the message return this.keyringController.signMessage(cleanMsgParams) }) .then((rawSig) => { - // tells the listener that the message has been signed - // and can be returned to the dapp + // tells the listener that the message has been signed + // and can be returned to the dapp this.messageManager.setMsgStatusSigned(msgId, rawSig) return this.getState() }) @@ -1177,7 +1405,7 @@ export default class MetamaskController extends EventEmitter { * * @param {string} msgId - The id of the message to cancel. */ - cancelMessage (msgId, cb) { + cancelMessage(msgId, cb) { const { messageManager } = this messageManager.rejectMsg(msgId) if (!cb || typeof cb !== 'function') { @@ -1199,8 +1427,11 @@ export default class MetamaskController extends EventEmitter { * @param {Function} cb - The callback function called with the signature. * Passed back to the requesting Dapp. */ - async newUnsignedPersonalMessage (msgParams, req) { - const promise = this.personalMessageManager.addUnapprovedMessageAsync(msgParams, req) + async newUnsignedPersonalMessage(msgParams, req) { + const promise = this.personalMessageManager.addUnapprovedMessageAsync( + msgParams, + req, + ) this.sendUpdate() this.opts.showUnconfirmedMessage() return promise @@ -1213,19 +1444,20 @@ export default class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params of the message to sign & return to the Dapp. * @returns {Promise} - A full state update. */ - signPersonalMessage (msgParams) { + signPersonalMessage(msgParams) { log.info('MetaMaskController - signPersonalMessage') const msgId = msgParams.metamaskId // sets the status op the message to 'approved' // and removes the metamaskId for signing - return this.personalMessageManager.approveMessage(msgParams) + return this.personalMessageManager + .approveMessage(msgParams) .then((cleanMsgParams) => { - // signs the message + // signs the message return this.keyringController.signPersonalMessage(cleanMsgParams) }) .then((rawSig) => { - // tells the listener that the message has been signed - // and can be returned to the dapp + // tells the listener that the message has been signed + // and can be returned to the dapp this.personalMessageManager.setMsgStatusSigned(msgId, rawSig) return this.getState() }) @@ -1236,7 +1468,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} msgId - The ID of the message to cancel. * @param {Function} cb - The callback function called with a full state update. */ - cancelPersonalMessage (msgId, cb) { + cancelPersonalMessage(msgId, cb) { const messageManager = this.personalMessageManager messageManager.rejectMsg(msgId) if (!cb || typeof cb !== 'function') { @@ -1248,26 +1480,29 @@ export default class MetamaskController extends EventEmitter { // eth_decrypt methods /** - * Called when a dapp uses the eth_decrypt method. - * - * @param {Object} msgParams - The params of the message to sign & return to the Dapp. - * @param {Object} req - (optional) the original request, containing the origin - * Passed back to the requesting Dapp. - */ - async newRequestDecryptMessage (msgParams, req) { - const promise = this.decryptMessageManager.addUnapprovedMessageAsync(msgParams, req) + * Called when a dapp uses the eth_decrypt method. + * + * @param {Object} msgParams - The params of the message to sign & return to the Dapp. + * @param {Object} req - (optional) the original request, containing the origin + * Passed back to the requesting Dapp. + */ + async newRequestDecryptMessage(msgParams, req) { + const promise = this.decryptMessageManager.addUnapprovedMessageAsync( + msgParams, + req, + ) this.sendUpdate() this.opts.showUnconfirmedMessage() return promise } /** - * Only decrypt message and don't touch transaction state - * - * @param {Object} msgParams - The params of the message to decrypt. - * @returns {Promise} - A full state update. - */ - async decryptMessageInline (msgParams) { + * Only decrypt message and don't touch transaction state + * + * @param {Object} msgParams - The params of the message to decrypt. + * @returns {Promise} - A full state update. + */ + async decryptMessageInline(msgParams) { log.info('MetaMaskController - decryptMessageInline') // decrypt the message inline const msgId = msgParams.metamaskId @@ -1287,26 +1522,30 @@ export default class MetamaskController extends EventEmitter { } /** - * Signifies a user's approval to decrypt a message in queue. - * Triggers decrypt, and the callback function from newUnsignedDecryptMessage. - * - * @param {Object} msgParams - The params of the message to decrypt & return to the Dapp. - * @returns {Promise} - A full state update. - */ - async decryptMessage (msgParams) { + * Signifies a user's approval to decrypt a message in queue. + * Triggers decrypt, and the callback function from newUnsignedDecryptMessage. + * + * @param {Object} msgParams - The params of the message to decrypt & return to the Dapp. + * @returns {Promise} - A full state update. + */ + async decryptMessage(msgParams) { log.info('MetaMaskController - decryptMessage') const msgId = msgParams.metamaskId // sets the status op the message to 'approved' // and removes the metamaskId for decryption try { - const cleanMsgParams = await this.decryptMessageManager.approveMessage(msgParams) + const cleanMsgParams = await this.decryptMessageManager.approveMessage( + msgParams, + ) const stripped = ethUtil.stripHexPrefix(cleanMsgParams.data) const buff = Buffer.from(stripped, 'hex') cleanMsgParams.data = JSON.parse(buff.toString('utf8')) // decrypt the message - const rawMess = await this.keyringController.decryptMessage(cleanMsgParams) + const rawMess = await this.keyringController.decryptMessage( + cleanMsgParams, + ) // tells the listener that the message has been decrypted and can be returned to the dapp this.decryptMessageManager.setMsgStatusDecrypted(msgId, rawMess) } catch (error) { @@ -1321,7 +1560,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} msgId - The ID of the message to cancel. * @param {Function} cb - The callback function called with a full state update. */ - cancelDecryptMessage (msgId, cb) { + cancelDecryptMessage(msgId, cb) { const messageManager = this.decryptMessageManager messageManager.rejectMsg(msgId) if (!cb || typeof cb !== 'function') { @@ -1333,36 +1572,43 @@ export default class MetamaskController extends EventEmitter { // eth_getEncryptionPublicKey methods /** - * Called when a dapp uses the eth_getEncryptionPublicKey method. - * - * @param {Object} msgParams - The params of the message to sign & return to the Dapp. - * @param {Object} req - (optional) the original request, containing the origin - * Passed back to the requesting Dapp. - */ - async newRequestEncryptionPublicKey (msgParams, req) { - const promise = this.encryptionPublicKeyManager.addUnapprovedMessageAsync(msgParams, req) + * Called when a dapp uses the eth_getEncryptionPublicKey method. + * + * @param {Object} msgParams - The params of the message to sign & return to the Dapp. + * @param {Object} req - (optional) the original request, containing the origin + * Passed back to the requesting Dapp. + */ + async newRequestEncryptionPublicKey(msgParams, req) { + const promise = this.encryptionPublicKeyManager.addUnapprovedMessageAsync( + msgParams, + req, + ) this.sendUpdate() this.opts.showUnconfirmedMessage() return promise } /** - * Signifies a user's approval to receiving encryption public key in queue. - * Triggers receiving, and the callback function from newUnsignedEncryptionPublicKey. - * - * @param {Object} msgParams - The params of the message to receive & return to the Dapp. - * @returns {Promise} - A full state update. - */ - async encryptionPublicKey (msgParams) { + * Signifies a user's approval to receiving encryption public key in queue. + * Triggers receiving, and the callback function from newUnsignedEncryptionPublicKey. + * + * @param {Object} msgParams - The params of the message to receive & return to the Dapp. + * @returns {Promise} - A full state update. + */ + async encryptionPublicKey(msgParams) { log.info('MetaMaskController - encryptionPublicKey') const msgId = msgParams.metamaskId // sets the status op the message to 'approved' // and removes the metamaskId for decryption try { - const params = await this.encryptionPublicKeyManager.approveMessage(msgParams) + const params = await this.encryptionPublicKeyManager.approveMessage( + msgParams, + ) // EncryptionPublicKey message - const publicKey = await this.keyringController.getEncryptionPublicKey(params.data) + const publicKey = await this.keyringController.getEncryptionPublicKey( + params.data, + ) // tells the listener that the message has been processed // and can be returned to the dapp @@ -1379,7 +1625,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} msgId - The ID of the message to cancel. * @param {Function} cb - The callback function called with a full state update. */ - cancelEncryptionPublicKey (msgId, cb) { + cancelEncryptionPublicKey(msgId, cb) { const messageManager = this.encryptionPublicKeyManager messageManager.rejectMsg(msgId) if (!cb || typeof cb !== 'function') { @@ -1396,8 +1642,12 @@ export default class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_signTypedData. * @param {Function} cb - The callback function, called with the signature. */ - newUnsignedTypedMessage (msgParams, req, version) { - const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req, version) + newUnsignedTypedMessage(msgParams, req, version) { + const promise = this.typedMessageManager.addUnapprovedMessageAsync( + msgParams, + req, + version, + ) this.sendUpdate() this.opts.showUnconfirmedMessage() return promise @@ -1410,12 +1660,14 @@ export default class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_signTypedData. * @returns {Object|undefined} - Full state update. */ - async signTypedMessage (msgParams) { + async signTypedMessage(msgParams) { log.info('MetaMaskController - eth_signTypedData') const msgId = msgParams.metamaskId const { version } = msgParams try { - const cleanMsgParams = await this.typedMessageManager.approveMessage(msgParams) + const cleanMsgParams = await this.typedMessageManager.approveMessage( + msgParams, + ) // For some reason every version after V1 used stringified params. if (version !== 'V1') { @@ -1425,7 +1677,10 @@ export default class MetamaskController extends EventEmitter { } } - const signature = await this.keyringController.signTypedMessage(cleanMsgParams, { version }) + const signature = await this.keyringController.signTypedMessage( + cleanMsgParams, + { version }, + ) this.typedMessageManager.setMsgStatusSigned(msgId, signature) return this.getState() } catch (error) { @@ -1440,7 +1695,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} msgId - The ID of the message to cancel. * @param {Function} cb - The callback function called with a full state update. */ - cancelTypedMessage (msgId, cb) { + cancelTypedMessage(msgId, cb) { const messageManager = this.typedMessageManager messageManager.rejectMsg(msgId) if (!cb || typeof cb !== 'function') { @@ -1460,27 +1715,37 @@ export default class MetamaskController extends EventEmitter { * @param {string} [customGasPrice] - the hex value to use for the cancel transaction * @returns {Object} - MetaMask state */ - async createCancelTransaction (originalTxId, customGasPrice) { - await this.txController.createCancelTransaction(originalTxId, customGasPrice) + async createCancelTransaction(originalTxId, customGasPrice) { + await this.txController.createCancelTransaction( + originalTxId, + customGasPrice, + ) const state = await this.getState() return state } - async createSpeedUpTransaction (originalTxId, customGasPrice, customGasLimit) { - await this.txController.createSpeedUpTransaction(originalTxId, customGasPrice, customGasLimit) + async createSpeedUpTransaction(originalTxId, customGasPrice, customGasLimit) { + await this.txController.createSpeedUpTransaction( + originalTxId, + customGasPrice, + customGasLimit, + ) const state = await this.getState() return state } - estimateGas (estimateGasParams) { + estimateGas(estimateGasParams) { return new Promise((resolve, reject) => { - return this.txController.txGasUtil.query.estimateGas(estimateGasParams, (err, res) => { - if (err) { - return reject(err) - } + return this.txController.txGasUtil.query.estimateGas( + estimateGasParams, + (err, res) => { + if (err) { + return reject(err) + } - return resolve(res) - }) + return resolve(res) + }, + ) }) } @@ -1492,7 +1757,7 @@ export default class MetamaskController extends EventEmitter { * Allows a user to begin the seed phrase recovery process. * @param {Function} cb - A callback function called when complete. */ - markPasswordForgotten (cb) { + markPasswordForgotten(cb) { this.preferencesController.setPasswordForgotten(true) this.sendUpdate() cb() @@ -1502,7 +1767,7 @@ export default class MetamaskController extends EventEmitter { * Allows a user to end the seed phrase recovery process. * @param {Function} cb - A callback function called when complete. */ - unMarkPasswordForgotten (cb) { + unMarkPasswordForgotten(cb) { this.preferencesController.setPasswordForgotten(false) this.sendUpdate() cb() @@ -1524,7 +1789,7 @@ export default class MetamaskController extends EventEmitter { * @param {*} connectionStream - The Duplex stream to connect to. * @param {MessageSender} sender - The sender of the messages on this stream */ - setupUntrustedCommunication (connectionStream, sender) { + setupUntrustedCommunication(connectionStream, sender) { const { usePhishDetect } = this.preferencesController.store.getState() const { hostname } = new URL(sender.url) // Check if new connection is blocked if phishing detection is on @@ -1551,7 +1816,7 @@ export default class MetamaskController extends EventEmitter { * @param {*} connectionStream - The duplex stream to connect to. * @param {MessageSender} sender - The sender of the messages on this stream */ - setupTrustedCommunication (connectionStream, sender) { + setupTrustedCommunication(connectionStream, sender) { // setup multiplexing const mux = setupMultiplex(connectionStream) // connect features @@ -1568,7 +1833,7 @@ export default class MetamaskController extends EventEmitter { * for sending the reload attempt to. * @param {string} hostname - The hostname that triggered the suspicion. */ - sendPhishingWarning (connectionStream, hostname) { + sendPhishingWarning(connectionStream, hostname) { const mux = setupMultiplex(connectionStream) const phishingStream = mux.createStream('phishing') phishingStream.write({ hostname }) @@ -1578,27 +1843,22 @@ export default class MetamaskController extends EventEmitter { * A method for providing our API over a stream using Dnode. * @param {*} outStream - The stream to provide our API over. */ - setupControllerConnection (outStream) { + setupControllerConnection(outStream) { const api = this.getApi() const dnode = Dnode(api) // report new active controller connection this.activeControllerConnections += 1 this.emit('controllerConnectionChanged', this.activeControllerConnections) // connect dnode api to remote connection - pump( - outStream, - dnode, - outStream, - (err) => { - // report new active controller connection - this.activeControllerConnections -= 1 - this.emit('controllerConnectionChanged', this.activeControllerConnections) - // report any error - if (err) { - log.error(err) - } - }, - ) + pump(outStream, dnode, outStream, (err) => { + // report new active controller connection + this.activeControllerConnections -= 1 + this.emit('controllerConnectionChanged', this.activeControllerConnections) + // report any error + if (err) { + log.error(err) + } + }) dnode.on('remote', (remote) => { // push updates to popup const sendUpdate = (update) => remote.sendUpdate(update) @@ -1614,10 +1874,8 @@ export default class MetamaskController extends EventEmitter { * @param {MessageSender} sender - The sender of the messages on this stream * @param {boolean} isInternal - True if this is a connection with an internal process */ - setupProviderConnection (outStream, sender, isInternal) { - const origin = isInternal - ? 'metamask' - : (new URL(sender.url)).origin + setupProviderConnection(outStream, sender, isInternal) { + const origin = isInternal ? 'metamask' : new URL(sender.url).origin let extensionId if (sender.id !== this.extension.runtime.id) { extensionId = sender.id @@ -1627,30 +1885,31 @@ export default class MetamaskController extends EventEmitter { tabId = sender.tab.id } - const engine = this.setupProviderEngine({ origin, location: sender.url, extensionId, tabId, isInternal }) + const engine = this.setupProviderEngine({ + origin, + location: sender.url, + extensionId, + tabId, + isInternal, + }) // setup connection const providerStream = createEngineStream({ engine }) const connectionId = this.addConnection(origin, { engine }) - pump( - outStream, - providerStream, - outStream, - (err) => { - // handle any middleware cleanup - engine._middleware.forEach((mid) => { - if (mid.destroy && typeof mid.destroy === 'function') { - mid.destroy() - } - }) - connectionId && this.removeConnection(origin, connectionId) - if (err) { - log.error(err) + pump(outStream, providerStream, outStream, (err) => { + // handle any middleware cleanup + engine._middleware.forEach((mid) => { + if (mid.destroy && typeof mid.destroy === 'function') { + mid.destroy() } - }, - ) + }) + connectionId && this.removeConnection(origin, connectionId) + if (err) { + log.error(err) + } + }) } /** @@ -1662,7 +1921,13 @@ export default class MetamaskController extends EventEmitter { * @param {tabId} [options.tabId] - The tab ID of the sender - if the sender is within a tab * @param {boolean} [options.isInternal] - True if called for a connection to an internal process **/ - setupProviderEngine ({ origin, location, extensionId, tabId, isInternal = false }) { + setupProviderEngine({ + origin, + location, + extensionId, + tabId, + isInternal = false, + }) { // setup json rpc engine stack const engine = new RpcEngine() const { provider, blockTracker } = this @@ -1671,8 +1936,13 @@ export default class MetamaskController extends EventEmitter { const filterMiddleware = createFilterMiddleware({ provider, blockTracker }) // create subscription polyfill middleware - const subscriptionManager = createSubscriptionManager({ provider, blockTracker }) - subscriptionManager.events.on('notification', (message) => engine.emit('notification', message)) + const subscriptionManager = createSubscriptionManager({ + provider, + blockTracker, + }) + subscriptionManager.events.on('notification', (message) => + engine.emit('notification', message), + ) // append origin to each request engine.push(createOriginMiddleware({ origin })) @@ -1682,23 +1952,33 @@ export default class MetamaskController extends EventEmitter { } // logging engine.push(createLoggerMiddleware({ origin })) - engine.push(createOnboardingMiddleware({ - location, - registerOnboarding: this.onboardingController.registerOnboarding, - })) - engine.push(createMethodMiddleware({ - origin, - sendMetrics: this.trackMetaMetricsEvent, - })) + engine.push( + createOnboardingMiddleware({ + location, + registerOnboarding: this.onboardingController.registerOnboarding, + }), + ) + engine.push( + createMethodMiddleware({ + origin, + sendMetrics: this.trackMetaMetricsEvent, + }), + ) // filter and subscription polyfills engine.push(filterMiddleware) engine.push(subscriptionManager.middleware) if (!isInternal) { // permissions - engine.push(this.permissionsController.createMiddleware({ origin, extensionId })) + engine.push( + this.permissionsController.createMiddleware({ origin, extensionId }), + ) } // watch asset - engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController)) + engine.push( + this.preferencesController.requestWatchAsset.bind( + this.preferencesController, + ), + ) // forward to metamask primary provider engine.push(providerAsMiddleware(provider)) return engine @@ -1714,21 +1994,17 @@ export default class MetamaskController extends EventEmitter { * * @param {*} outStream - The stream to provide public config over. */ - setupPublicConfig (outStream) { + setupPublicConfig(outStream) { const configStore = this.createPublicConfigStore() const configStream = asStream(configStore) - pump( - configStream, - outStream, - (err) => { - configStore.destroy() - configStream.destroy() - if (err) { - log.error(err) - } - }, - ) + pump(configStream, outStream, (err) => { + configStore.destroy() + configStream.destroy() + if (err) { + log.error(err) + } + }) } /** @@ -1741,8 +2017,7 @@ export default class MetamaskController extends EventEmitter { * @param {Object} options.engine - The connection's JSON Rpc Engine * @returns {string} - The connection's id (so that it can be deleted later) */ - addConnection (origin, { engine }) { - + addConnection(origin, { engine }) { if (origin === 'metamask') { return null } @@ -1766,8 +2041,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} origin - The connection's origin string. * @param {string} id - The connection's id, as returned from addConnection. */ - removeConnection (origin, id) { - + removeConnection(origin, id) { const connections = this.connections[origin] if (!connections) { return @@ -1788,8 +2062,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} origin - The connection's origin string. * @param {any} payload - The event payload. */ - notifyConnections (origin, payload) { - + notifyConnections(origin, payload) { const connections = this.connections[origin] if (!this.isUnlocked() || !connections) { return @@ -1807,8 +2080,7 @@ export default class MetamaskController extends EventEmitter { * * @param {any} payload - The event payload. */ - notifyAllConnections (payload) { - + notifyAllConnections(payload) { if (!this.isUnlocked()) { return } @@ -1828,9 +2100,12 @@ export default class MetamaskController extends EventEmitter { * @returns {Promise} * @private */ - async _onKeyringControllerUpdate (state) { + async _onKeyringControllerUpdate(state) { const { keyrings } = state - const addresses = keyrings.reduce((acc, { accounts }) => acc.concat(accounts), []) + const addresses = keyrings.reduce( + (acc, { accounts }) => acc.concat(accounts), + [], + ) if (!addresses.length) { return @@ -1847,14 +2122,14 @@ export default class MetamaskController extends EventEmitter { * A method for emitting the full MetaMask state to all registered listeners. * @private */ - privateSendUpdate () { + privateSendUpdate() { this.emit('update', this.getState()) } /** * @returns {boolean} Whether the extension is unlocked. */ - isUnlocked () { + isUnlocked() { return this.keyringController.memStore.getState().isUnlocked } @@ -1867,8 +2142,11 @@ export default class MetamaskController extends EventEmitter { * @param {string} address - The hex string address for the transaction * @returns {Promise} */ - async getPendingNonce (address) { - const { nonceDetails, releaseLock } = await this.txController.nonceTracker.getNonceLock(address) + async getPendingNonce(address) { + const { + nonceDetails, + releaseLock, + } = await this.txController.nonceTracker.getNonceLock(address) const pendingNonce = nonceDetails.params.highestSuggested releaseLock() @@ -1880,20 +2158,21 @@ export default class MetamaskController extends EventEmitter { * @param {string} address - The hex string address for the transaction * @returns {Promise} */ - async getNextNonce (address) { + async getNextNonce(address) { const nonceLock = await this.txController.nonceTracker.getNonceLock(address) nonceLock.releaseLock() return nonceLock.nextNonce } - async sendBackgroundMetaMetrics ({ action, name, customVariables } = {}) { - + async sendBackgroundMetaMetrics({ action, name, customVariables } = {}) { if (!action || !name) { throw new Error('Must provide action and name.') } const metamaskState = await this.getState() - const additionalProperties = getBackgroundMetaMetricState({ metamask: metamaskState }) + const additionalProperties = getBackgroundMetaMetricState({ + metamask: metamaskState, + }) this.trackMetaMetricsEvent({ event: name, @@ -1923,7 +2202,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} newChainId - The new chainId * @param {boolean} [duplicate] - Whether to duplicate the addresses on both chainIds (default: false) */ - async migrateAddressBookState (oldChainId, newChainId, duplicate = false) { + async migrateAddressBookState(oldChainId, newChainId, duplicate = false) { const { addressBook } = this.addressBookController.state if (!addressBook[oldChainId]) { @@ -1932,7 +2211,12 @@ export default class MetamaskController extends EventEmitter { for (const address of Object.keys(addressBook[oldChainId])) { const entry = addressBook[oldChainId][address] - this.addressBookController.set(address, entry.name, newChainId, entry.memo) + this.addressBookController.set( + address, + entry.name, + newChainId, + entry.memo, + ) if (!duplicate) { this.addressBookController.delete(oldChainId, address) } @@ -1950,7 +2234,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} currencyCode - The code of the preferred currency. * @param {Function} cb - A callback function returning currency info. */ - setCurrentCurrency (currencyCode, cb) { + setCurrentCurrency(currencyCode, cb) { const { ticker } = this.networkController.getProviderConfig() try { const currencyState = { @@ -1976,9 +2260,27 @@ export default class MetamaskController extends EventEmitter { * @param {string} nickname - Optional nickname of the selected network. * @returns {Promise} - The RPC Target URL confirmed. */ - async updateAndSetCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname, rpcPrefs) { - await this.preferencesController.updateRpc({ rpcUrl, chainId, ticker, nickname, rpcPrefs }) - this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname, rpcPrefs) + async updateAndSetCustomRpc( + rpcUrl, + chainId, + ticker = 'ETH', + nickname, + rpcPrefs, + ) { + await this.preferencesController.updateRpc({ + rpcUrl, + chainId, + ticker, + nickname, + rpcPrefs, + }) + this.networkController.setRpcTarget( + rpcUrl, + chainId, + ticker, + nickname, + rpcPrefs, + ) return rpcUrl } @@ -1990,15 +2292,41 @@ export default class MetamaskController extends EventEmitter { * @param {string} nickname - Optional nickname of the selected network. * @returns {Promise} - The RPC Target URL confirmed. */ - async setCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) { + async setCustomRpc( + rpcUrl, + chainId, + ticker = 'ETH', + nickname = '', + rpcPrefs = {}, + ) { const frequentRpcListDetail = this.preferencesController.getFrequentRpcListDetail() - const rpcSettings = frequentRpcListDetail.find((rpc) => rpcUrl === rpc.rpcUrl) + const rpcSettings = frequentRpcListDetail.find( + (rpc) => rpcUrl === rpc.rpcUrl, + ) if (rpcSettings) { - this.networkController.setRpcTarget(rpcSettings.rpcUrl, rpcSettings.chainId, rpcSettings.ticker, rpcSettings.nickname, rpcPrefs) + this.networkController.setRpcTarget( + rpcSettings.rpcUrl, + rpcSettings.chainId, + rpcSettings.ticker, + rpcSettings.nickname, + rpcPrefs, + ) } else { - this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname, rpcPrefs) - await this.preferencesController.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname, rpcPrefs) + this.networkController.setRpcTarget( + rpcUrl, + chainId, + ticker, + nickname, + rpcPrefs, + ) + await this.preferencesController.addToFrequentRpcList( + rpcUrl, + chainId, + ticker, + nickname, + rpcPrefs, + ) } return rpcUrl } @@ -2007,11 +2335,11 @@ export default class MetamaskController extends EventEmitter { * A method for deleting a selected custom URL. * @param {string} rpcUrl - A RPC URL to delete. */ - async delCustomRpc (rpcUrl) { + async delCustomRpc(rpcUrl) { await this.preferencesController.removeFromFrequentRpcList(rpcUrl) } - async initializeThreeBox () { + async initializeThreeBox() { await this.threeBoxController.init() } @@ -2020,7 +2348,7 @@ export default class MetamaskController extends EventEmitter { * @param {boolean} val - True for bockie, false for jazzicon. * @param {Function} cb - A callback function called when complete. */ - setUseBlockie (val, cb) { + setUseBlockie(val, cb) { try { this.preferencesController.setUseBlockie(val) cb(null) @@ -2037,7 +2365,7 @@ export default class MetamaskController extends EventEmitter { * @param {boolean} val - True for nonce field, false for not nonce field. * @param {Function} cb - A callback function called when complete. */ - setUseNonceField (val, cb) { + setUseNonceField(val, cb) { try { this.preferencesController.setUseNonceField(val) cb(null) @@ -2054,7 +2382,7 @@ export default class MetamaskController extends EventEmitter { * @param {boolean} val * @param {Function} cb */ - setUsePhishDetect (val, cb) { + setUsePhishDetect(val, cb) { try { this.preferencesController.setUsePhishDetect(val) cb(null) @@ -2071,7 +2399,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} val - the host of the gateway to set * @param {Function} cb - A callback function called when complete. */ - setIpfsGateway (val, cb) { + setIpfsGateway(val, cb) { try { this.preferencesController.setIpfsGateway(val) cb(null) @@ -2088,9 +2416,11 @@ export default class MetamaskController extends EventEmitter { * @param {boolean} bool - True for users that wish to opt-in, false for users that wish to remain out. * @param {Function} cb - A callback function called when complete. */ - setParticipateInMetaMetrics (bool, cb) { + setParticipateInMetaMetrics(bool, cb) { try { - const metaMetricsId = this.preferencesController.setParticipateInMetaMetrics(bool) + const metaMetricsId = this.preferencesController.setParticipateInMetaMetrics( + bool, + ) cb(null, metaMetricsId) return } catch (err) { @@ -2100,7 +2430,7 @@ export default class MetamaskController extends EventEmitter { } } - setMetaMetricsSendCount (val, cb) { + setMetaMetricsSendCount(val, cb) { try { this.preferencesController.setMetaMetricsSendCount(val) cb(null) @@ -2117,7 +2447,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} type - Indicates the type of first time flow the user wishes to follow * @param {Function} cb - A callback function called when complete. */ - setFirstTimeFlowType (type, cb) { + setFirstTimeFlowType(type, cb) { try { this.preferencesController.setFirstTimeFlowType(type) cb(null) @@ -2134,7 +2464,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} key - Locale identifier. * @param {Function} cb - A callback function called when complete. */ - setCurrentLocale (key, cb) { + setCurrentLocale(key, cb) { try { const direction = this.preferencesController.setCurrentLocale(key) cb(null, direction) @@ -2151,7 +2481,7 @@ export default class MetamaskController extends EventEmitter { * @param {Object} initState - The default state to initialize with. * @private */ - recordFirstTimeInfo (initState) { + recordFirstTimeInfo(initState) { if (!('firstTimeInfo' in initState)) { const version = this.platform.getVersion() initState.firstTimeInfo = { @@ -2168,33 +2498,33 @@ export default class MetamaskController extends EventEmitter { * @private * @param {boolean} open */ - set isClientOpen (open) { + set isClientOpen(open) { this._isClientOpen = open this.detectTokensController.isOpen = open } /* eslint-enable accessor-pairs */ /** - * Creates RPC engine middleware for processing eth_signTypedData requests - * - * @param {Object} req - request object - * @param {Object} res - response object - * @param {Function} - next - * @param {Function} - end - */ + * Creates RPC engine middleware for processing eth_signTypedData requests + * + * @param {Object} req - request object + * @param {Object} res - response object + * @param {Function} - next + * @param {Function} - end + */ /** * Adds a domain to the PhishingController safelist * @param {string} hostname - the domain to safelist */ - safelistPhishingDomain (hostname) { + safelistPhishingDomain(hostname) { return this.phishingController.bypass(hostname) } /** * Locks MetaMask */ - setLocked () { + setLocked() { return this.keyringController.setLocked() } } diff --git a/app/scripts/migrations/002.js b/app/scripts/migrations/002.js index 24df7f4de..9de898f83 100644 --- a/app/scripts/migrations/002.js +++ b/app/scripts/migrations/002.js @@ -5,13 +5,14 @@ const version = 2 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { if (versionedData.data.config.provider.type === 'etherscan') { versionedData.data.config.provider.type = 'rpc' - versionedData.data.config.provider.rpcTarget = 'https://rpc.metamask.io/' + versionedData.data.config.provider.rpcTarget = + 'https://rpc.metamask.io/' } } catch (_) { // empty diff --git a/app/scripts/migrations/003.js b/app/scripts/migrations/003.js index 08e4be468..8859f2a0f 100644 --- a/app/scripts/migrations/003.js +++ b/app/scripts/migrations/003.js @@ -7,7 +7,7 @@ const newTestRpc = 'https://testrpc.metamask.io/' export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { diff --git a/app/scripts/migrations/004.js b/app/scripts/migrations/004.js index 48741a267..c571e8fd1 100644 --- a/app/scripts/migrations/004.js +++ b/app/scripts/migrations/004.js @@ -5,7 +5,7 @@ const version = 4 export default { version, - migrate (versionedData) { + migrate(versionedData) { const safeVersionedData = cloneDeep(versionedData) safeVersionedData.meta.version = version try { diff --git a/app/scripts/migrations/005.js b/app/scripts/migrations/005.js index baead6890..757462353 100644 --- a/app/scripts/migrations/005.js +++ b/app/scripts/migrations/005.js @@ -11,7 +11,7 @@ const version = 5 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function selectSubstateForKeyringController (state) { +function selectSubstateForKeyringController(state) { const { config } = state const newState = { ...state, diff --git a/app/scripts/migrations/006.js b/app/scripts/migrations/006.js index 8d1e72935..90ff3f2cb 100644 --- a/app/scripts/migrations/006.js +++ b/app/scripts/migrations/006.js @@ -11,7 +11,7 @@ const version = 6 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function migrateState (state) { +function migrateState(state) { const keyringSubstate = state.KeyringController // add new state diff --git a/app/scripts/migrations/007.js b/app/scripts/migrations/007.js index 41272ee3b..cea831b7e 100644 --- a/app/scripts/migrations/007.js +++ b/app/scripts/migrations/007.js @@ -11,7 +11,7 @@ const version = 7 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = { ...state, TransactionManager: { diff --git a/app/scripts/migrations/008.js b/app/scripts/migrations/008.js index 6f25bbcd5..ce8ab37ce 100644 --- a/app/scripts/migrations/008.js +++ b/app/scripts/migrations/008.js @@ -11,7 +11,7 @@ const version = 8 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = { ...state, NoticeController: { diff --git a/app/scripts/migrations/009.js b/app/scripts/migrations/009.js index f63297836..2d1370bfc 100644 --- a/app/scripts/migrations/009.js +++ b/app/scripts/migrations/009.js @@ -11,7 +11,7 @@ const version = 9 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = merge({}, state, { CurrencyController: { currentCurrency: state.currentFiat || state.fiatCurrency || 'USD', diff --git a/app/scripts/migrations/010.js b/app/scripts/migrations/010.js index 354b19871..053af2562 100644 --- a/app/scripts/migrations/010.js +++ b/app/scripts/migrations/010.js @@ -11,7 +11,7 @@ const version = 10 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = merge({}, state, { ShapeShiftController: { shapeShiftTxList: state.shapeShiftTxList || [], diff --git a/app/scripts/migrations/011.js b/app/scripts/migrations/011.js index d8f852f9f..1e1884825 100644 --- a/app/scripts/migrations/011.js +++ b/app/scripts/migrations/011.js @@ -11,7 +11,7 @@ const version = 11 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state delete newState.TOSHash delete newState.isDisclaimerConfirmed diff --git a/app/scripts/migrations/012.js b/app/scripts/migrations/012.js index d01edbc41..3a42992ee 100644 --- a/app/scripts/migrations/012.js +++ b/app/scripts/migrations/012.js @@ -11,7 +11,7 @@ const version = 12 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state newState.NoticeController.noticesList.forEach((notice) => { if (notice.read) { diff --git a/app/scripts/migrations/013.js b/app/scripts/migrations/013.js index 530fc687c..5c27496dc 100644 --- a/app/scripts/migrations/013.js +++ b/app/scripts/migrations/013.js @@ -11,7 +11,7 @@ const version = 13 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { config } = newState if (config && config.provider) { diff --git a/app/scripts/migrations/014.js b/app/scripts/migrations/014.js index 630aa2051..0a26fcea4 100644 --- a/app/scripts/migrations/014.js +++ b/app/scripts/migrations/014.js @@ -11,7 +11,7 @@ const version = 14 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state newState.NetworkController = {} newState.NetworkController.provider = newState.config.provider diff --git a/app/scripts/migrations/015.js b/app/scripts/migrations/015.js index 682eb8db7..34cffb4f7 100644 --- a/app/scripts/migrations/015.js +++ b/app/scripts/migrations/015.js @@ -12,7 +12,7 @@ const version = 15 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -26,7 +26,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { diff --git a/app/scripts/migrations/016.js b/app/scripts/migrations/016.js index 974a1125d..1a36d25eb 100644 --- a/app/scripts/migrations/016.js +++ b/app/scripts/migrations/016.js @@ -12,7 +12,7 @@ const version = 16 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -26,7 +26,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { @@ -36,7 +36,9 @@ function transformState (state) { if (!txMeta.err) { return txMeta } - if (txMeta.err === 'transaction with the same hash was already imported.') { + if ( + txMeta.err === 'transaction with the same hash was already imported.' + ) { txMeta.status = 'submitted' delete txMeta.err } diff --git a/app/scripts/migrations/017.js b/app/scripts/migrations/017.js index 497cbe33e..eb02eafb9 100644 --- a/app/scripts/migrations/017.js +++ b/app/scripts/migrations/017.js @@ -11,7 +11,7 @@ const version = 17 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { diff --git a/app/scripts/migrations/018.js b/app/scripts/migrations/018.js index bb57ddf0c..5a616514c 100644 --- a/app/scripts/migrations/018.js +++ b/app/scripts/migrations/018.js @@ -15,7 +15,7 @@ const version = 18 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -29,7 +29,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { @@ -42,13 +42,11 @@ function transformState (state) { return txMeta } // has history: migrate - const newHistory = ( - migrateFromSnapshotsToDiffs(txMeta.history) + const newHistory = migrateFromSnapshotsToDiffs(txMeta.history) // remove empty diffs - .filter((entry) => { - return !Array.isArray(entry) || entry.length > 0 - }) - ) + .filter((entry) => { + return !Array.isArray(entry) || entry.length > 0 + }) txMeta.history = newHistory return txMeta }) diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js index 4c786b7c9..e82e05a82 100644 --- a/app/scripts/migrations/019.js +++ b/app/scripts/migrations/019.js @@ -1,4 +1,3 @@ - /* This migration sets transactions as failed @@ -13,7 +12,7 @@ const version = 19 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -27,44 +26,54 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { - const { transactions } = newState.TransactionController - newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { - if (txMeta.status !== 'submitted') { - return txMeta - } - - const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed') - .filter((tx) => tx.txParams.from === txMeta.txParams.from) - .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) - const highestConfirmedNonce = getHighestNonce(confirmedTxs) - - const pendingTxs = txList.filter((tx) => tx.status === 'submitted') - .filter((tx) => tx.txParams.from === txMeta.txParams.from) - .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) - const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce) - - const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce) - - if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) { - txMeta.status = 'failed' - txMeta.err = { - message: 'nonce too high', - note: 'migration 019 custom error', + newState.TransactionController.transactions = transactions.map( + (txMeta, _, txList) => { + if (txMeta.status !== 'submitted') { + return txMeta } - } - return txMeta - }) + + const confirmedTxs = txList + .filter((tx) => tx.status === 'confirmed') + .filter((tx) => tx.txParams.from === txMeta.txParams.from) + .filter( + (tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from, + ) + const highestConfirmedNonce = getHighestNonce(confirmedTxs) + + const pendingTxs = txList + .filter((tx) => tx.status === 'submitted') + .filter((tx) => tx.txParams.from === txMeta.txParams.from) + .filter( + (tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from, + ) + const highestContinuousNonce = getHighestContinuousFrom( + pendingTxs, + highestConfirmedNonce, + ) + + const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce) + + if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) { + txMeta.status = 'failed' + txMeta.err = { + message: 'nonce too high', + note: 'migration 019 custom error', + } + } + return txMeta + }, + ) } return newState } -function getHighestContinuousFrom (txList, startPoint) { +function getHighestContinuousFrom(txList, startPoint) { const nonces = txList.map((txMeta) => { const { nonce } = txMeta.txParams return parseInt(nonce, 16) @@ -78,7 +87,7 @@ function getHighestContinuousFrom (txList, startPoint) { return highest } -function getHighestNonce (txList) { +function getHighestNonce(txList) { const nonces = txList.map((txMeta) => { const { nonce } = txMeta.txParams return parseInt(nonce || '0x0', 16) @@ -86,4 +95,3 @@ function getHighestNonce (txList) { const highestNonce = Math.max.apply(null, nonces) return highestNonce } - diff --git a/app/scripts/migrations/020.js b/app/scripts/migrations/020.js index eb8080124..b2a28cb7a 100644 --- a/app/scripts/migrations/020.js +++ b/app/scripts/migrations/020.js @@ -13,7 +13,7 @@ const version = 20 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -27,10 +27,9 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state - if ('metamask' in newState && - !('firstTimeInfo' in newState.metamask)) { + if ('metamask' in newState && !('firstTimeInfo' in newState.metamask)) { newState.metamask.firstTimeInfo = { version: '3.12.0', date: Date.now(), @@ -38,4 +37,3 @@ function transformState (state) { } return newState } - diff --git a/app/scripts/migrations/021.js b/app/scripts/migrations/021.js index ac3170131..4783d6ed9 100644 --- a/app/scripts/migrations/021.js +++ b/app/scripts/migrations/021.js @@ -11,7 +11,7 @@ const version = 21 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,10 +25,9 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state delete newState.BlacklistController delete newState.RecentBlocks return newState } - diff --git a/app/scripts/migrations/022.js b/app/scripts/migrations/022.js index 76f96a0ae..2c25515b6 100644 --- a/app/scripts/migrations/022.js +++ b/app/scripts/migrations/022.js @@ -1,4 +1,3 @@ - /* This migration adds submittedTime to the txMeta if it is not their @@ -12,7 +11,7 @@ const version = 22 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -26,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { @@ -36,7 +35,7 @@ function transformState (state) { if (txMeta.status !== 'submitted' || txMeta.submittedTime) { return txMeta } - txMeta.submittedTime = (new Date()).getTime() + txMeta.submittedTime = new Date().getTime() return txMeta }) } diff --git a/app/scripts/migrations/023.js b/app/scripts/migrations/023.js index 5f0363d53..2b62d1991 100644 --- a/app/scripts/migrations/023.js +++ b/app/scripts/migrations/023.js @@ -1,4 +1,3 @@ - /* This migration removes transactions that are no longer usefull down to 40 total @@ -12,7 +11,7 @@ const version = 23 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -26,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state const { TransactionController } = newState @@ -41,10 +40,12 @@ function transformState (state) { let stripping = true while (reverseTxList.length > 40 && stripping) { const txIndex = reverseTxList.findIndex((txMeta) => { - return (txMeta.status === 'failed' || - txMeta.status === 'rejected' || - txMeta.status === 'confirmed' || - txMeta.status === 'dropped') + return ( + txMeta.status === 'failed' || + txMeta.status === 'rejected' || + txMeta.status === 'confirmed' || + txMeta.status === 'dropped' + ) }) if (txIndex < 0) { stripping = false diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js index 84a998d12..fb47d883b 100644 --- a/app/scripts/migrations/024.js +++ b/app/scripts/migrations/024.js @@ -1,4 +1,3 @@ - /* This migration ensures that the from address in txParams is to lower case for @@ -13,7 +12,7 @@ const version = 24 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -23,21 +22,23 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state if (!newState.TransactionController) { return newState } const { transactions } = newState.TransactionController - newState.TransactionController.transactions = transactions.map((txMeta, _) => { - if ( - txMeta.status === 'unapproved' && - txMeta.txParams && - txMeta.txParams.from - ) { - txMeta.txParams.from = txMeta.txParams.from.toLowerCase() - } - return txMeta - }) + newState.TransactionController.transactions = transactions.map( + (txMeta, _) => { + if ( + txMeta.status === 'unapproved' && + txMeta.txParams && + txMeta.txParams.from + ) { + txMeta.txParams.from = txMeta.txParams.from.toLowerCase() + } + return txMeta + }, + ) return newState } diff --git a/app/scripts/migrations/025.js b/app/scripts/migrations/025.js index 72bcdbf01..4819032db 100644 --- a/app/scripts/migrations/025.js +++ b/app/scripts/migrations/025.js @@ -13,7 +13,7 @@ const version = 25 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -23,26 +23,28 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state if (newState.TransactionController) { if (newState.TransactionController.transactions) { const { transactions } = newState.TransactionController - newState.TransactionController.transactions = transactions.map((txMeta) => { - if (txMeta.status !== 'unapproved') { + newState.TransactionController.transactions = transactions.map( + (txMeta) => { + if (txMeta.status !== 'unapproved') { + return txMeta + } + txMeta.txParams = normalizeTxParams(txMeta.txParams) return txMeta - } - txMeta.txParams = normalizeTxParams(txMeta.txParams) - return txMeta - }) + }, + ) } } return newState } -function normalizeTxParams (txParams) { +function normalizeTxParams(txParams) { // functions that handle normalizing of that key in txParams const whiteList = { from: (from) => ethUtil.addHexPrefix(from).toLowerCase(), diff --git a/app/scripts/migrations/026.js b/app/scripts/migrations/026.js index e6cb9db85..c237cce1c 100644 --- a/app/scripts/migrations/026.js +++ b/app/scripts/migrations/026.js @@ -11,7 +11,7 @@ const version = 26 export default { version, - migrate (originalVersionedData) { + migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version try { @@ -25,7 +25,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { if (!state.KeyringController || !state.PreferencesController) { return state } @@ -34,14 +34,15 @@ function transformState (state) { return state } - state.PreferencesController.identities = Object.keys(state.KeyringController.walletNicknames) - .reduce((identities, address) => { - identities[address] = { - name: state.KeyringController.walletNicknames[address], - address, - } - return identities - }, {}) + state.PreferencesController.identities = Object.keys( + state.KeyringController.walletNicknames, + ).reduce((identities, address) => { + identities[address] = { + name: state.KeyringController.walletNicknames[address], + address, + } + return identities + }, {}) delete state.KeyringController.walletNicknames return state } diff --git a/app/scripts/migrations/027.js b/app/scripts/migrations/027.js index 42e024f56..6d311d0ae 100644 --- a/app/scripts/migrations/027.js +++ b/app/scripts/migrations/027.js @@ -11,7 +11,7 @@ const version = 27 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -21,13 +21,15 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state if (newState.TransactionController) { if (newState.TransactionController.transactions) { const { transactions } = newState.TransactionController - newState.TransactionController.transactions = transactions.filter((txMeta) => txMeta.status !== 'rejected') + newState.TransactionController.transactions = transactions.filter( + (txMeta) => txMeta.status !== 'rejected', + ) } } diff --git a/app/scripts/migrations/028.js b/app/scripts/migrations/028.js index fa816ca53..8f83bda04 100644 --- a/app/scripts/migrations/028.js +++ b/app/scripts/migrations/028.js @@ -11,7 +11,7 @@ const version = 28 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -21,15 +21,20 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state if (newState.PreferencesController) { - if (newState.PreferencesController.tokens && newState.PreferencesController.identities) { + if ( + newState.PreferencesController.tokens && + newState.PreferencesController.identities + ) { const { identities, tokens } = newState.PreferencesController newState.PreferencesController.accountTokens = {} Object.keys(identities).forEach((identity) => { - newState.PreferencesController.accountTokens[identity] = { 'mainnet': tokens } + newState.PreferencesController.accountTokens[identity] = { + mainnet: tokens, + } }) newState.PreferencesController.tokens = [] } diff --git a/app/scripts/migrations/029.js b/app/scripts/migrations/029.js index 4773eb466..42bd0b7ea 100644 --- a/app/scripts/migrations/029.js +++ b/app/scripts/migrations/029.js @@ -18,10 +18,14 @@ normalizes txParams on unconfirmed txs export default { version, - migrate: failTxsThat(version, 'Stuck in approved state for too long.', (txMeta) => { - const isApproved = txMeta.status === 'approved' - const createdTime = txMeta.submittedTime - const now = Date.now() - return isApproved && now - createdTime > unacceptableDelay - }), + migrate: failTxsThat( + version, + 'Stuck in approved state for too long.', + (txMeta) => { + const isApproved = txMeta.status === 'approved' + const createdTime = txMeta.submittedTime + const now = Date.now() + return isApproved && now - createdTime > unacceptableDelay + }, + ), } diff --git a/app/scripts/migrations/030.js b/app/scripts/migrations/030.js index 6f11e27a5..1062cbaf2 100644 --- a/app/scripts/migrations/030.js +++ b/app/scripts/migrations/030.js @@ -12,7 +12,7 @@ const version = 30 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -22,7 +22,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state if (state.PreferencesController) { const { frequentRpcListDetail } = newState.PreferencesController @@ -37,13 +37,20 @@ function transformState (state) { } } if (state.NetworkController) { - // eslint-disable-next-line radix - if (newState.NetworkController.network && Number.isNaN(parseInt(newState.NetworkController.network))) { + if ( + newState.NetworkController.network && + // eslint-disable-next-line radix + Number.isNaN(parseInt(newState.NetworkController.network)) + ) { delete newState.NetworkController.network } - // eslint-disable-next-line radix - if (newState.NetworkController.provider && newState.NetworkController.provider.chainId && Number.isNaN(parseInt(newState.NetworkController.provider.chainId))) { + if ( + newState.NetworkController.provider && + newState.NetworkController.provider.chainId && + // eslint-disable-next-line radix + Number.isNaN(parseInt(newState.NetworkController.provider.chainId)) + ) { delete newState.NetworkController.provider.chainId } } diff --git a/app/scripts/migrations/031.js b/app/scripts/migrations/031.js index 59a8dcf15..87eea11fa 100644 --- a/app/scripts/migrations/031.js +++ b/app/scripts/migrations/031.js @@ -4,13 +4,13 @@ import { cloneDeep } from 'lodash' const version = 31 /* - * The purpose of this migration is to properly set the completedOnboarding flag based on the state - * of the KeyringController. - */ + * The purpose of this migration is to properly set the completedOnboarding flag based on the state + * of the KeyringController. + */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -20,7 +20,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const { KeyringController, PreferencesController } = state if (KeyringController && PreferencesController) { diff --git a/app/scripts/migrations/032.js b/app/scripts/migrations/032.js index fce4d65a6..facdf1072 100644 --- a/app/scripts/migrations/032.js +++ b/app/scripts/migrations/032.js @@ -7,7 +7,7 @@ const version = 32 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,7 +16,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const { PreferencesController } = state if (PreferencesController) { diff --git a/app/scripts/migrations/033.js b/app/scripts/migrations/033.js index e1e0ea3b4..8f88ba4e1 100644 --- a/app/scripts/migrations/033.js +++ b/app/scripts/migrations/033.js @@ -12,7 +12,7 @@ const version = 33 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -22,7 +22,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state // transform state here if (state.NoticeController) { diff --git a/app/scripts/migrations/034.js b/app/scripts/migrations/034.js index ba61131e4..4bb2f9491 100644 --- a/app/scripts/migrations/034.js +++ b/app/scripts/migrations/034.js @@ -8,7 +8,7 @@ const version = 34 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -17,13 +17,16 @@ export default { }, } -function transformState (state) { +function transformState(state) { const { PreferencesController } = state if (PreferencesController) { const featureFlags = PreferencesController.featureFlags || {} - if (!featureFlags.privacyMode && typeof PreferencesController.migratedPrivacyMode === 'undefined') { + if ( + !featureFlags.privacyMode && + typeof PreferencesController.migratedPrivacyMode === 'undefined' + ) { // Mark the state has being migrated and enable Privacy Mode PreferencesController.migratedPrivacyMode = true featureFlags.privacyMode = true diff --git a/app/scripts/migrations/035.js b/app/scripts/migrations/035.js index 6ea634730..d98f8562a 100644 --- a/app/scripts/migrations/035.js +++ b/app/scripts/migrations/035.js @@ -12,7 +12,7 @@ const version = 35 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version versionedData.data = transformState(versionedData.data) @@ -20,8 +20,11 @@ export default { }, } -function transformState (state) { - if (state.PreferencesController && state.PreferencesController.seedWords !== undefined) { +function transformState(state) { + if ( + state.PreferencesController && + state.PreferencesController.seedWords !== undefined + ) { delete state.PreferencesController.seedWords } return state diff --git a/app/scripts/migrations/036.js b/app/scripts/migrations/036.js index 2b64fc6ea..056f96f01 100644 --- a/app/scripts/migrations/036.js +++ b/app/scripts/migrations/036.js @@ -7,7 +7,7 @@ const version = 36 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,7 +16,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const { PreferencesController } = state if (PreferencesController) { diff --git a/app/scripts/migrations/037.js b/app/scripts/migrations/037.js index e650337d4..80a166e61 100644 --- a/app/scripts/migrations/037.js +++ b/app/scripts/migrations/037.js @@ -10,7 +10,7 @@ const version = 37 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -19,8 +19,7 @@ export default { }, } -function transformState (state) { - +function transformState(state) { if (state.AddressBookController) { const ab = state.AddressBookController.addressBook @@ -34,11 +33,10 @@ function transformState (state) { // fill the chainId object with the entries with the matching chainId for (const id of chainIds.values()) { - // make an empty object entry for each chainId + // make an empty object entry for each chainId newAddressBook[id] = {} for (const address in ab) { if (ab[address].chainId === id) { - ab[address].isEns = false if (util.normalizeEnsName(ab[address].name)) { ab[address].isEns = true diff --git a/app/scripts/migrations/038.js b/app/scripts/migrations/038.js index b104fe49f..9c179735b 100644 --- a/app/scripts/migrations/038.js +++ b/app/scripts/migrations/038.js @@ -7,7 +7,7 @@ const version = 38 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,7 +16,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const { ABTestController: ABTestControllerState = {} } = state const { abTests = {} } = ABTestControllerState diff --git a/app/scripts/migrations/039.js b/app/scripts/migrations/039.js index d190b4f9b..d8bec42e4 100644 --- a/app/scripts/migrations/039.js +++ b/app/scripts/migrations/039.js @@ -7,10 +7,13 @@ const DAI_V1_CONTRACT_ADDRESS = '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359' const DAI_V1_TOKEN_SYMBOL = 'DAI' const SAI_TOKEN_SYMBOL = 'SAI' -function isOldDai (token = {}) { - return token && typeof token === 'object' && +function isOldDai(token = {}) { + return ( + token && + typeof token === 'object' && token.symbol === DAI_V1_TOKEN_SYMBOL && ethUtil.toChecksumAddress(token.address) === DAI_V1_CONTRACT_ADDRESS + ) } /** @@ -22,7 +25,7 @@ function isOldDai (token = {}) { */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -31,7 +34,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const { PreferencesController } = state if (PreferencesController) { diff --git a/app/scripts/migrations/040.js b/app/scripts/migrations/040.js index 93b0e72be..49f91fecd 100644 --- a/app/scripts/migrations/040.js +++ b/app/scripts/migrations/040.js @@ -9,7 +9,7 @@ const version = 40 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -18,7 +18,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { delete state.ProviderApprovalController return state } diff --git a/app/scripts/migrations/041.js b/app/scripts/migrations/041.js index 9e81312c3..eb0964e4c 100644 --- a/app/scripts/migrations/041.js +++ b/app/scripts/migrations/041.js @@ -7,7 +7,7 @@ const version = 41 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,9 +16,10 @@ export default { }, } -function transformState (state) { +function transformState(state) { if (state.PreferencesController && state.PreferencesController.preferences) { - state.PreferencesController.preferences.autoLockTimeLimit = state.PreferencesController.preferences.autoLogoutTimeLimit + state.PreferencesController.preferences.autoLockTimeLimit = + state.PreferencesController.preferences.autoLogoutTimeLimit delete state.PreferencesController.preferences.autoLogoutTimeLimit } return state diff --git a/app/scripts/migrations/042.js b/app/scripts/migrations/042.js index ed8b9f7cc..ca52cada7 100644 --- a/app/scripts/migrations/042.js +++ b/app/scripts/migrations/042.js @@ -8,7 +8,7 @@ const version = 42 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -17,7 +17,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { if (state.AppStateController) { state.AppStateController.connectedStatusPopoverHasBeenShown = false } else { diff --git a/app/scripts/migrations/043.js b/app/scripts/migrations/043.js index ad2dddde5..afee378f8 100644 --- a/app/scripts/migrations/043.js +++ b/app/scripts/migrations/043.js @@ -7,7 +7,7 @@ const version = 43 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,7 +16,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { if (state?.PreferencesController?.currentAccountTab) { delete state.PreferencesController.currentAccountTab } diff --git a/app/scripts/migrations/044.js b/app/scripts/migrations/044.js index 00a23c012..a3fcf5036 100644 --- a/app/scripts/migrations/044.js +++ b/app/scripts/migrations/044.js @@ -7,7 +7,7 @@ const version = 44 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,8 +16,11 @@ export default { }, } -function transformState (state) { - if (typeof state?.AppStateController?.mkrMigrationReminderTimestamp !== 'undefined') { +function transformState(state) { + if ( + typeof state?.AppStateController?.mkrMigrationReminderTimestamp !== + 'undefined' + ) { delete state.AppStateController.mkrMigrationReminderTimestamp } return state diff --git a/app/scripts/migrations/045.js b/app/scripts/migrations/045.js index d8024a0f9..69965845a 100644 --- a/app/scripts/migrations/045.js +++ b/app/scripts/migrations/045.js @@ -7,7 +7,7 @@ const version = 45 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,12 +16,9 @@ export default { }, } -const outdatedGateways = [ - 'ipfs.io', - 'ipfs.dweb.link', -] +const outdatedGateways = ['ipfs.io', 'ipfs.dweb.link'] -function transformState (state) { +function transformState(state) { if (outdatedGateways.includes(state?.PreferencesController?.ipfsGateway)) { state.PreferencesController.ipfsGateway = 'dweb.link' } diff --git a/app/scripts/migrations/046.js b/app/scripts/migrations/046.js index 6b1ebdae0..d7e2fbcec 100644 --- a/app/scripts/migrations/046.js +++ b/app/scripts/migrations/046.js @@ -7,7 +7,7 @@ const version = 46 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,7 +16,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { if (typeof state?.ABTestController !== 'undefined') { delete state.ABTestController } diff --git a/app/scripts/migrations/047.js b/app/scripts/migrations/047.js index 371bf2135..2e3fffe84 100644 --- a/app/scripts/migrations/047.js +++ b/app/scripts/migrations/047.js @@ -7,7 +7,7 @@ const version = 47 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -16,7 +16,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const transactions = state?.TransactionController?.transactions if (Array.isArray(transactions)) { transactions.forEach((transaction) => { diff --git a/app/scripts/migrations/048.js b/app/scripts/migrations/048.js index 6e1585d54..4a7c1fecf 100644 --- a/app/scripts/migrations/048.js +++ b/app/scripts/migrations/048.js @@ -16,7 +16,7 @@ const version = 48 */ export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -25,21 +25,19 @@ export default { }, } -const hexRegEx = (/^0x[0-9a-f]+$/ui) -const chainIdRegEx = (/^0x[1-9a-f]+[0-9a-f]*$/ui) +const hexRegEx = /^0x[0-9a-f]+$/iu +const chainIdRegEx = /^0x[1-9a-f]+[0-9a-f]*$/iu -function transformState (state = {}) { +function transformState(state = {}) { // 1. Delete NetworkController.settings delete state.NetworkController?.settings // 2. Migrate NetworkController.provider to Rinkeby or rename rpcTarget key const provider = state.NetworkController?.provider || {} - const isCustomRpcWithInvalidChainId = ( - provider.type === 'rpc' && ( - typeof provider.chainId !== 'string' || - !chainIdRegEx.test(provider.chainId) - ) - ) + const isCustomRpcWithInvalidChainId = + provider.type === 'rpc' && + (typeof provider.chainId !== 'string' || + !chainIdRegEx.test(provider.chainId)) if (isCustomRpcWithInvalidChainId || provider.type === 'localhost') { state.NetworkController.provider = { type: 'rinkeby', @@ -84,8 +82,10 @@ function transformState (state = {}) { typeof metamaskNetworkId === 'string' && hexRegEx.test(metamaskNetworkId) ) { - transaction.metamaskNetworkId = parseInt(metamaskNetworkId, 16) - .toString(10) + transaction.metamaskNetworkId = parseInt( + metamaskNetworkId, + 16, + ).toString(10) } }) } @@ -93,7 +93,7 @@ function transformState (state = {}) { // 6. Convert address book keys from decimal to hex const addressBook = state.AddressBookController?.addressBook || {} Object.keys(addressBook).forEach((networkKey) => { - if ((/^\d+$/ui).test(networkKey)) { + if (/^\d+$/iu.test(networkKey)) { const chainId = `0x${parseInt(networkKey, 10).toString(16)}` updateChainIds(addressBook[networkKey], chainId) @@ -108,8 +108,7 @@ function transformState (state = {}) { // 7. Delete localhost key in IncomingTransactionsController delete state.IncomingTransactionsController - ?.incomingTxLastFetchedBlocksByNetwork - ?.localhost + ?.incomingTxLastFetchedBlocksByNetwork?.localhost // 8. Merge 'localhost' tokens into 'rpc' tokens const accountTokens = state.PreferencesController?.accountTokens @@ -121,7 +120,10 @@ function transformState (state = {}) { const rpcTokens = accountTokens[account].rpc || [] if (rpcTokens.length > 0) { - accountTokens[account].rpc = mergeTokenArrays(localhostTokens, rpcTokens) + accountTokens[account].rpc = mergeTokenArrays( + localhostTokens, + rpcTokens, + ) } else { accountTokens[account].rpc = localhostTokens } @@ -138,7 +140,7 @@ function transformState (state = {}) { * * @returns {void} */ -function mergeAddressBookKeys (addressBook, networkKey, chainIdKey) { +function mergeAddressBookKeys(addressBook, networkKey, chainIdKey) { const networkKeyEntries = addressBook[networkKey] || {} // For the new entries, start by copying the existing entries for the chainId const newEntries = { ...addressBook[chainIdKey] } @@ -155,11 +157,8 @@ function mergeAddressBookKeys (addressBook, networkKey, chainIdKey) { ...Object.keys(networkKeyEntries[address] || {}), ]).forEach((key) => { // Use non-empty value for the current key, if any - mergedEntry[key] = ( - newEntries[address][key] || - networkKeyEntries[address]?.[key] || - '' - ) + mergedEntry[key] = + newEntries[address][key] || networkKeyEntries[address]?.[key] || '' }) newEntries[address] = mergedEntry @@ -182,7 +181,7 @@ function mergeAddressBookKeys (addressBook, networkKey, chainIdKey) { * * @returns {void} */ -function updateChainIds (networkEntries, chainId) { +function updateChainIds(networkEntries, chainId) { Object.values(networkEntries).forEach((entry) => { if (entry && typeof entry === 'object') { entry.chainId = chainId @@ -196,7 +195,7 @@ function updateChainIds (networkEntries, chainId) { * * @returns {Array} */ -function mergeTokenArrays (localhostTokens, rpcTokens) { +function mergeTokenArrays(localhostTokens, rpcTokens) { const localhostTokensMap = tokenArrayToMap(localhostTokens) const rpcTokensMap = tokenArrayToMap(rpcTokens) @@ -213,7 +212,7 @@ function mergeTokenArrays (localhostTokens, rpcTokens) { return mergedTokens - function tokenArrayToMap (array) { + function tokenArrayToMap(array) { return array.reduce((map, token) => { if (token?.address && typeof token?.address === 'string') { map[token.address] = token diff --git a/app/scripts/migrations/fail-tx.js b/app/scripts/migrations/fail-tx.js index e6236ec4e..37d2dce5c 100644 --- a/app/scripts/migrations/fail-tx.js +++ b/app/scripts/migrations/fail-tx.js @@ -1,6 +1,6 @@ import { cloneDeep } from 'lodash' -export default function failTxsThat (version, reason, condition) { +export default function failTxsThat(version, reason, condition) { return function (originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version @@ -12,11 +12,10 @@ export default function failTxsThat (version, reason, condition) { console.warn(`MetaMask Migration #${version}${err.stack}`) } return Promise.resolve(versionedData) - } } -function transformState (state, condition, reason) { +function transformState(state, condition, reason) { const newState = state const { TransactionController } = newState if (TransactionController && TransactionController.transactions) { @@ -38,4 +37,3 @@ function transformState (state, condition, reason) { } return newState } - diff --git a/app/scripts/migrations/template.js b/app/scripts/migrations/template.js index 6427d49f4..b582c5a00 100644 --- a/app/scripts/migrations/template.js +++ b/app/scripts/migrations/template.js @@ -12,7 +12,7 @@ const version = 0 export default { version, - async migrate (originalVersionedData) { + async migrate(originalVersionedData) { const versionedData = cloneDeep(originalVersionedData) versionedData.meta.version = version const state = versionedData.data @@ -22,7 +22,7 @@ export default { }, } -function transformState (state) { +function transformState(state) { const newState = state // transform state here return newState diff --git a/app/scripts/phishing-detect.js b/app/scripts/phishing-detect.js index 6311b7004..cabe08aa3 100644 --- a/app/scripts/phishing-detect.js +++ b/app/scripts/phishing-detect.js @@ -9,7 +9,7 @@ import ExtensionPlatform from './platforms/extension' document.addEventListener('DOMContentLoaded', start) -function start () { +function start() { const hash = window.location.hash.substring(1) const suspect = querystring.parse(hash) @@ -17,29 +17,36 @@ function start () { global.platform = new ExtensionPlatform() - const extensionPort = extension.runtime.connect({ name: getEnvironmentType() }) + const extensionPort = extension.runtime.connect({ + name: getEnvironmentType(), + }) const connectionStream = new PortStream(extensionPort) const mx = setupMultiplex(connectionStream) - setupControllerConnection(mx.createStream('controller'), (err, metaMaskController) => { - if (err) { - return - } + setupControllerConnection( + mx.createStream('controller'), + (err, metaMaskController) => { + if (err) { + return + } - const continueLink = document.getElementById('unsafe-continue') - continueLink.addEventListener('click', () => { - metaMaskController.safelistPhishingDomain(suspect.hostname) - window.location.href = suspect.href - }) - }) + const continueLink = document.getElementById('unsafe-continue') + continueLink.addEventListener('click', () => { + metaMaskController.safelistPhishingDomain(suspect.hostname) + window.location.href = suspect.href + }) + }, + ) } -function setupControllerConnection (connectionStream, cb) { +function setupControllerConnection(connectionStream, cb) { const eventEmitter = new EventEmitter() const metaMaskControllerDnode = dnode({ - sendUpdate (state) { + sendUpdate(state) { eventEmitter.emit('update', state) }, }) connectionStream.pipe(metaMaskControllerDnode).pipe(connectionStream) - metaMaskControllerDnode.once('remote', (backgroundConnection) => cb(null, backgroundConnection)) + metaMaskControllerDnode.once('remote', (backgroundConnection) => + cb(null, backgroundConnection), + ) } diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index c891ae97c..aa9641947 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -4,15 +4,14 @@ import { getEnvironmentType, checkForError } from '../lib/util' import { ENVIRONMENT_TYPE_BACKGROUND } from '../lib/enums' export default class ExtensionPlatform { - // // Public // - reload () { + reload() { extension.runtime.reload() } - openTab (options) { + openTab(options) { return new Promise((resolve, reject) => { extension.tabs.create(options, (newTab) => { const error = checkForError() @@ -24,7 +23,7 @@ export default class ExtensionPlatform { }) } - openWindow (options) { + openWindow(options) { return new Promise((resolve, reject) => { extension.windows.create(options, (newWindow) => { const error = checkForError() @@ -36,7 +35,7 @@ export default class ExtensionPlatform { }) } - focusWindow (windowId) { + focusWindow(windowId) { return new Promise((resolve, reject) => { extension.windows.update(windowId, { focused: true }, () => { const error = checkForError() @@ -48,7 +47,7 @@ export default class ExtensionPlatform { }) } - updateWindowPosition (windowId, left, top) { + updateWindowPosition(windowId, left, top) { return new Promise((resolve, reject) => { extension.windows.update(windowId, { left, top }, () => { const error = checkForError() @@ -60,7 +59,7 @@ export default class ExtensionPlatform { }) } - getLastFocusedWindow () { + getLastFocusedWindow() { return new Promise((resolve, reject) => { extension.windows.getLastFocused((windowObject) => { const error = checkForError() @@ -72,17 +71,17 @@ export default class ExtensionPlatform { }) } - closeCurrentWindow () { + closeCurrentWindow() { return extension.windows.getCurrent((windowDetails) => { return extension.windows.remove(windowDetails.id) }) } - getVersion () { + getVersion() { return extension.runtime.getManifest().version } - openExtensionInBrowser (route = null, queryString = null) { + openExtensionInBrowser(route = null, queryString = null) { let extensionURL = extension.runtime.getURL('home.html') if (queryString) { @@ -98,7 +97,7 @@ export default class ExtensionPlatform { } } - getPlatformInfo (cb) { + getPlatformInfo(cb) { try { extension.runtime.getPlatformInfo((platform) => { cb(null, platform) @@ -110,20 +109,23 @@ export default class ExtensionPlatform { } } - showTransactionNotification (txMeta) { + showTransactionNotification(txMeta) { const { status, txReceipt: { status: receiptStatus } = {} } = txMeta if (status === 'confirmed') { // There was an on-chain failure receiptStatus === '0x0' - ? this._showFailedTransaction(txMeta, 'Transaction encountered an error.') + ? this._showFailedTransaction( + txMeta, + 'Transaction encountered an error.', + ) : this._showConfirmedTransaction(txMeta) } else if (status === 'failed') { this._showFailedTransaction(txMeta) } } - getAllWindows () { + getAllWindows() { return new Promise((resolve, reject) => { extension.windows.getAll((windows) => { const error = checkForError() @@ -135,7 +137,7 @@ export default class ExtensionPlatform { }) } - getActiveTabs () { + getActiveTabs() { return new Promise((resolve, reject) => { extension.tabs.query({ active: true }, (tabs) => { const error = checkForError() @@ -147,7 +149,7 @@ export default class ExtensionPlatform { }) } - currentTab () { + currentTab() { return new Promise((resolve, reject) => { extension.tabs.getCurrent((tab) => { const err = checkForError() @@ -160,7 +162,7 @@ export default class ExtensionPlatform { }) } - switchToTab (tabId) { + switchToTab(tabId) { return new Promise((resolve, reject) => { extension.tabs.update(tabId, { highlighted: true }, (tab) => { const err = checkForError() @@ -173,7 +175,7 @@ export default class ExtensionPlatform { }) } - closeTab (tabId) { + closeTab(tabId) { return new Promise((resolve, reject) => { extension.tabs.remove(tabId, () => { const err = checkForError() @@ -186,8 +188,7 @@ export default class ExtensionPlatform { }) } - _showConfirmedTransaction (txMeta) { - + _showConfirmedTransaction(txMeta) { this._subscribeToNotificationClicked() const url = explorerLink(txMeta.hash, txMeta.metamaskNetworkId) @@ -198,33 +199,31 @@ export default class ExtensionPlatform { this._showNotification(title, message, url) } - _showFailedTransaction (txMeta, errorMessage) { - + _showFailedTransaction(txMeta, errorMessage) { const nonce = parseInt(txMeta.txParams.nonce, 16) const title = 'Failed transaction' - const message = `Transaction ${nonce} failed! ${errorMessage || txMeta.err.message}` + const message = `Transaction ${nonce} failed! ${ + errorMessage || txMeta.err.message + }` this._showNotification(title, message) } - _showNotification (title, message, url) { - extension.notifications.create( - url, - { - 'type': 'basic', - title, - 'iconUrl': extension.extension.getURL('../../images/icon-64.png'), - message, - }, - ) + _showNotification(title, message, url) { + extension.notifications.create(url, { + type: 'basic', + title, + iconUrl: extension.extension.getURL('../../images/icon-64.png'), + message, + }) } - _subscribeToNotificationClicked () { + _subscribeToNotificationClicked() { if (!extension.notifications.onClicked.hasListener(this._viewOnEtherscan)) { extension.notifications.onClicked.addListener(this._viewOnEtherscan) } } - _viewOnEtherscan (txId) { + _viewOnEtherscan(txId) { if (txId.startsWith('https://')) { extension.tabs.create({ url: txId }) } diff --git a/app/scripts/ui.js b/app/scripts/ui.js index a77c0d6a3..5b5932a50 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -1,4 +1,3 @@ - // this must run before anything else import './lib/freezeGlobals' @@ -28,8 +27,7 @@ import { getEnvironmentType } from './lib/util' start().catch(log.error) -async function start () { - +async function start() { // create platform global global.platform = new ExtensionPlatform() @@ -50,14 +48,15 @@ async function start () { const activeTab = await queryCurrentActiveTab(windowType) initializeUiWithTab(activeTab) - function displayCriticalError (container, err) { - container.innerHTML = '
The MetaMask app failed to load: please open and close MetaMask again to restart.
' + function displayCriticalError(container, err) { + container.innerHTML = + '
The MetaMask app failed to load: please open and close MetaMask again to restart.
' container.style.height = '80px' log.error(err.stack) throw err } - function initializeUiWithTab (tab) { + function initializeUiWithTab(tab) { const container = document.getElementById('app-content') initializeUi(tab, container, connectionStream, (err, store) => { if (err) { @@ -75,7 +74,7 @@ async function start () { } } -async function queryCurrentActiveTab (windowType) { +async function queryCurrentActiveTab(windowType) { return new Promise((resolve) => { // At the time of writing we only have the `activeTab` permission which means // that this query will only succeed in the popup context (i.e. after a "browserAction") @@ -99,18 +98,21 @@ async function queryCurrentActiveTab (windowType) { }) } -function initializeUi (activeTab, container, connectionStream, cb) { +function initializeUi(activeTab, container, connectionStream, cb) { connectToAccountManager(connectionStream, (err, backgroundConnection) => { if (err) { cb(err) return } - launchMetaMaskUi({ - activeTab, - container, - backgroundConnection, - }, cb) + launchMetaMaskUi( + { + activeTab, + container, + backgroundConnection, + }, + cb, + ) }) } @@ -120,7 +122,7 @@ function initializeUi (activeTab, container, connectionStream, cb) { * @param {PortDuplexStream} connectionStream - PortStream instance establishing a background connection * @param {Function} cb - Called when controller connection is established */ -function connectToAccountManager (connectionStream, cb) { +function connectToAccountManager(connectionStream, cb) { const mx = setupMultiplex(connectionStream) setupControllerConnection(mx.createStream('controller'), cb) setupWeb3Connection(mx.createStream('provider')) @@ -131,7 +133,7 @@ function connectToAccountManager (connectionStream, cb) { * * @param {PortDuplexStream} connectionStream - PortStream instance establishing a background connection */ -function setupWeb3Connection (connectionStream) { +function setupWeb3Connection(connectionStream) { const providerStream = new StreamProvider() providerStream.pipe(connectionStream).pipe(providerStream) connectionStream.on('error', console.error.bind(console)) @@ -147,10 +149,10 @@ function setupWeb3Connection (connectionStream) { * @param {PortDuplexStream} connectionStream - PortStream instance establishing a background connection * @param {Function} cb - Called when the remote account manager connection is established */ -function setupControllerConnection (connectionStream, cb) { +function setupControllerConnection(connectionStream, cb) { const eventEmitter = new EventEmitter() const backgroundDnode = Dnode({ - sendUpdate (state) { + sendUpdate(state) { eventEmitter.emit('update', state) }, }) diff --git a/babel.config.js b/babel.config.js index 26b47fdb9..9f3af9523 100644 --- a/babel.config.js +++ b/babel.config.js @@ -6,10 +6,7 @@ module.exports = function (api) { '@babel/preset-env', { targets: { - browsers: [ - 'chrome >= 58', - 'firefox >= 56.2', - ], + browsers: ['chrome >= 58', 'firefox >= 56.2'], }, }, ], diff --git a/development/announcer.js b/development/announcer.js index 798e7da07..e6927cb8b 100644 --- a/development/announcer.js +++ b/development/announcer.js @@ -2,7 +2,10 @@ const fs = require('fs') const path = require('path') const { version } = require('../app/manifest/_base.json') -const changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md'), 'utf8') +const changelog = fs.readFileSync( + path.join(__dirname, '..', 'CHANGELOG.md'), + 'utf8', +) const log = changelog.split(version)[1].split('##')[0].trim() const msg = `*MetaMask ${version}* now published! It should auto-update soon!\n${log}` diff --git a/development/build/display.js b/development/build/display.js index e5556dd09..153f47189 100644 --- a/development/build/display.js +++ b/development/build/display.js @@ -18,7 +18,7 @@ const SYMBOLS = { RightEighth: '▕', } -function setupTaskDisplay (taskEvents) { +function setupTaskDisplay(taskEvents) { const taskData = [] taskEvents.on('start', ([name]) => { console.log(`Starting '${name}'...`) @@ -32,7 +32,7 @@ function setupTaskDisplay (taskEvents) { }) } -function displayChart (data) { +function displayChart(data) { // sort tasks by start time data.sort((a, b) => a[1] - b[1]) @@ -49,30 +49,32 @@ function displayChart (data) { // build bars for bounds data.forEach((entry, index) => { const [label, start, end] = entry - const [start2, end2] = [start, end].map((value) => adjust(value, first, last, 40)) + const [start2, end2] = [start, end].map((value) => + adjust(value, first, last, 40), + ) const barString = barBuilder(start2, end2) const color = colors[index] const coloredBarString = colorize(color, barString) const duration = ((end - start) / 1e3).toFixed(1) console.log(coloredBarString, `${label} ${duration}s`) }) - } -function colorize (color, string) { - const colorizer = (typeof chalk[color] === 'function') ? chalk[color] : chalk.hex(color) +function colorize(color, string) { + const colorizer = + typeof chalk[color] === 'function' ? chalk[color] : chalk.hex(color) return colorizer(string) } // scale number within bounds -function adjust (value, first, last, size) { +function adjust(value, first, last, size) { const length = last - first - const result = (value - first) / length * size + const result = ((value - first) / length) * size return result } // draw bars -function barBuilder (start, end) { +function barBuilder(start, end) { const [spaceInt, spaceRest] = splitNumber(start) const barBodyLength = end - spaceInt let [barInt, barRest] = splitNumber(barBodyLength) @@ -92,7 +94,7 @@ function barBuilder (start, end) { } // get integer and remainder -function splitNumber (value = 0) { +function splitNumber(value = 0) { const [int, rest = '0'] = value.toString().split('.') const int2 = parseInt(int, 10) const rest2 = parseInt(rest, 10) / Math.pow(10, rest.length) @@ -100,11 +102,11 @@ function splitNumber (value = 0) { } // get partial block char for value (left-adjusted) -function getSymbolNormal (value) { +function getSymbolNormal(value) { // round to closest supported value const possibleValues = [0, 1 / 8, 1 / 4, 3 / 8, 1 / 2, 5 / 8, 3 / 4, 7 / 8, 1] const rounded = possibleValues.reduce((prev, curr) => { - return (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev) + return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev }) if (rounded === 0) { @@ -128,11 +130,11 @@ function getSymbolNormal (value) { } // get partial block char for value (right-adjusted) -function getSymbolNormalRight (value) { +function getSymbolNormalRight(value) { // round to closest supported value (not much :/) const possibleValues = [0, 1 / 2, 7 / 8, 1] const rounded = possibleValues.reduce((prev, curr) => { - return (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev) + return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev }) if (rounded === 0) { diff --git a/development/build/etc.js b/development/build/etc.js index 92af2e338..374b9a616 100644 --- a/development/build/etc.js +++ b/development/build/etc.js @@ -9,28 +9,32 @@ const { createTask, composeParallel } = require('./task') module.exports = createEtcTasks -function createEtcTasks ({ browserPlatforms, livereload }) { - - const clean = createTask('clean', async function clean () { +function createEtcTasks({ browserPlatforms, livereload }) { + const clean = createTask('clean', async function clean() { await del(['./dist/*']) - await Promise.all(browserPlatforms.map(async (platform) => { - await fs.mkdir(`./dist/${platform}`, { recursive: true }) - })) + await Promise.all( + browserPlatforms.map(async (platform) => { + await fs.mkdir(`./dist/${platform}`, { recursive: true }) + }), + ) }) - const reload = createTask('reload', function devReload () { + const reload = createTask('reload', function devReload() { livereload.listen({ port: 35729 }) }) // zip tasks for distribution - const zip = createTask('zip', composeParallel( - ...browserPlatforms.map((platform) => createZipTask(platform)), - )) + const zip = createTask( + 'zip', + composeParallel( + ...browserPlatforms.map((platform) => createZipTask(platform)), + ), + ) return { clean, reload, zip } } -function createZipTask (target) { +function createZipTask(target) { return async () => { await pump( gulp.src(`dist/${target}/**`), diff --git a/development/build/index.js b/development/build/index.js index 21efa88b1..cc75d8398 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -9,30 +9,32 @@ require('lavamoat-core/lib/ses.umd.js') lockdown() // eslint-disable-line no-undef const livereload = require('gulp-livereload') -const { createTask, composeSeries, composeParallel, detectAndRunEntryTask } = require('./task') +const { + createTask, + composeSeries, + composeParallel, + detectAndRunEntryTask, +} = require('./task') const createManifestTasks = require('./manifest') const createScriptTasks = require('./scripts') const createStyleTasks = require('./styles') const createStaticAssetTasks = require('./static') const createEtcTasks = require('./etc') -const browserPlatforms = [ - 'firefox', - 'chrome', - 'brave', - 'opera', -] +const browserPlatforms = ['firefox', 'chrome', 'brave', 'opera'] defineAllTasks() detectAndRunEntryTask() -function defineAllTasks () { - +function defineAllTasks() { const staticTasks = createStaticAssetTasks({ livereload, browserPlatforms }) const manifestTasks = createManifestTasks({ browserPlatforms }) const styleTasks = createStyleTasks({ livereload }) const scriptTasks = createScriptTasks({ livereload, browserPlatforms }) - const { clean, reload, zip } = createEtcTasks({ livereload, browserPlatforms }) + const { clean, reload, zip } = createEtcTasks({ + livereload, + browserPlatforms, + }) // build for development (livereload) createTask( @@ -70,11 +72,7 @@ function defineAllTasks () { composeSeries( clean, styleTasks.prod, - composeParallel( - scriptTasks.prod, - staticTasks.prod, - manifestTasks.prod, - ), + composeParallel(scriptTasks.prod, staticTasks.prod, manifestTasks.prod), zip, ), ) @@ -85,15 +83,10 @@ function defineAllTasks () { composeSeries( clean, styleTasks.prod, - composeParallel( - scriptTasks.test, - staticTasks.prod, - manifestTasks.test, - ), + composeParallel(scriptTasks.test, staticTasks.prod, manifestTasks.test), ), ) // special build for minimal CI testing createTask('styles', styleTasks.prod) - } diff --git a/development/build/manifest.js b/development/build/manifest.js index 1b24e6398..7750205b1 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -12,22 +12,34 @@ const scriptsToExcludeFromBackgroundDevBuild = { 'bg-libs.js': true, } -function createManifestTasks ({ browserPlatforms }) { - +function createManifestTasks({ browserPlatforms }) { // merge base manifest with per-platform manifests const prepPlatforms = async () => { - return Promise.all(browserPlatforms.map(async (platform) => { - const platformModifications = await readJson(path.join(__dirname, '..', '..', 'app', 'manifest', `${platform}.json`)) - const result = merge(cloneDeep(baseManifest), platformModifications) - const dir = path.join('.', 'dist', platform) - await fs.mkdir(dir, { recursive: true }) - await writeJson(result, path.join(dir, 'manifest.json')) - })) + return Promise.all( + browserPlatforms.map(async (platform) => { + const platformModifications = await readJson( + path.join( + __dirname, + '..', + '..', + 'app', + 'manifest', + `${platform}.json`, + ), + ) + const result = merge(cloneDeep(baseManifest), platformModifications) + const dir = path.join('.', 'dist', platform) + await fs.mkdir(dir, { recursive: true }) + await writeJson(result, path.join(dir, 'manifest.json')) + }), + ) } // dev: remove bg-libs, add chromereload, add perms const envDev = createTaskForModifyManifestForEnvironment((manifest) => { - const scripts = manifest.background.scripts.filter((scriptName) => !scriptsToExcludeFromBackgroundDevBuild[scriptName]) + const scripts = manifest.background.scripts.filter( + (scriptName) => !scriptsToExcludeFromBackgroundDevBuild[scriptName], + ) scripts.push('chromereload.js') manifest.background = { ...manifest.background, @@ -38,60 +50,68 @@ function createManifestTasks ({ browserPlatforms }) { // testDev: remove bg-libs, add perms const envTestDev = createTaskForModifyManifestForEnvironment((manifest) => { - const scripts = manifest.background.scripts.filter((scriptName) => !scriptsToExcludeFromBackgroundDevBuild[scriptName]) + const scripts = manifest.background.scripts.filter( + (scriptName) => !scriptsToExcludeFromBackgroundDevBuild[scriptName], + ) scripts.push('chromereload.js') manifest.background = { ...manifest.background, scripts, } - manifest.permissions = [...manifest.permissions, 'webRequestBlocking', 'http://localhost/*'] + manifest.permissions = [ + ...manifest.permissions, + 'webRequestBlocking', + 'http://localhost/*', + ] }) // test: add permissions const envTest = createTaskForModifyManifestForEnvironment((manifest) => { - manifest.permissions = [...manifest.permissions, 'webRequestBlocking', 'http://localhost/*'] + manifest.permissions = [ + ...manifest.permissions, + 'webRequestBlocking', + 'http://localhost/*', + ] }) // high level manifest tasks - const dev = createTask('manifest:dev', composeSeries( - prepPlatforms, - envDev, - )) + const dev = createTask('manifest:dev', composeSeries(prepPlatforms, envDev)) - const testDev = createTask('manifest:testDev', composeSeries( - prepPlatforms, - envTestDev, - )) + const testDev = createTask( + 'manifest:testDev', + composeSeries(prepPlatforms, envTestDev), + ) - const test = createTask('manifest:test', composeSeries( - prepPlatforms, - envTest, - )) + const test = createTask( + 'manifest:test', + composeSeries(prepPlatforms, envTest), + ) const prod = createTask('manifest:prod', prepPlatforms) return { prod, dev, testDev, test } // helper for modifying each platform's manifest.json in place - function createTaskForModifyManifestForEnvironment (transformFn) { + function createTaskForModifyManifestForEnvironment(transformFn) { return () => { - return Promise.all(browserPlatforms.map(async (platform) => { - const manifestPath = path.join('.', 'dist', platform, 'manifest.json') - const manifest = await readJson(manifestPath) - transformFn(manifest) - await writeJson(manifest, manifestPath) - })) + return Promise.all( + browserPlatforms.map(async (platform) => { + const manifestPath = path.join('.', 'dist', platform, 'manifest.json') + const manifest = await readJson(manifestPath) + transformFn(manifest) + await writeJson(manifest, manifestPath) + }), + ) } } - } // helper for reading and deserializing json from fs -async function readJson (file) { +async function readJson(file) { return JSON.parse(await fs.readFile(file, 'utf8')) } // helper for serializing and writing json to fs -async function writeJson (obj, file) { +async function writeJson(obj, file) { return fs.writeFile(file, JSON.stringify(obj, null, 2)) } diff --git a/development/build/scripts.js b/development/build/scripts.js index 1f4d17881..891978216 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -22,84 +22,98 @@ const conf = require('rc')('metamask', { }) const packageJSON = require('../../package.json') -const { createTask, composeParallel, composeSeries, runInChildProcess } = require('./task') +const { + createTask, + composeParallel, + composeSeries, + runInChildProcess, +} = require('./task') module.exports = createScriptTasks -const dependencies = Object.keys((packageJSON && packageJSON.dependencies) || {}) +const dependencies = Object.keys( + (packageJSON && packageJSON.dependencies) || {}, +) const materialUIDependencies = ['@material-ui/core'] const reactDepenendencies = dependencies.filter((dep) => dep.match(/react/u)) const d3Dependencies = ['c3', 'd3'] const externalDependenciesMap = { - background: [ - '3box', - ], - ui: [ - ...materialUIDependencies, ...reactDepenendencies, ...d3Dependencies, - ], + background: ['3box'], + ui: [...materialUIDependencies, ...reactDepenendencies, ...d3Dependencies], } -function createScriptTasks ({ browserPlatforms, livereload }) { - +function createScriptTasks({ browserPlatforms, livereload }) { // internal tasks const core = { // dev tasks (live reload) - dev: createTasksForBuildJsExtension({ taskPrefix: 'scripts:core:dev', devMode: true }), - testDev: createTasksForBuildJsExtension({ taskPrefix: 'scripts:core:test-live', devMode: true, testing: true }), + dev: createTasksForBuildJsExtension({ + taskPrefix: 'scripts:core:dev', + devMode: true, + }), + testDev: createTasksForBuildJsExtension({ + taskPrefix: 'scripts:core:test-live', + devMode: true, + testing: true, + }), // built for CI tests - test: createTasksForBuildJsExtension({ taskPrefix: 'scripts:core:test', testing: true }), + test: createTasksForBuildJsExtension({ + taskPrefix: 'scripts:core:test', + testing: true, + }), // production prod: createTasksForBuildJsExtension({ taskPrefix: 'scripts:core:prod' }), } const deps = { - background: createTasksForBuildJsDeps({ filename: 'bg-libs', key: 'background' }), + background: createTasksForBuildJsDeps({ + filename: 'bg-libs', + key: 'background', + }), ui: createTasksForBuildJsDeps({ filename: 'ui-libs', key: 'ui' }), } // high level tasks - const prod = composeParallel( - deps.background, - deps.ui, - core.prod, - ) + const prod = composeParallel(deps.background, deps.ui, core.prod) const { dev, testDev } = core - const test = composeParallel( - deps.background, - deps.ui, - core.test, - ) + const test = composeParallel(deps.background, deps.ui, core.test) return { prod, dev, testDev, test } - function createTasksForBuildJsDeps ({ key, filename }) { - return createTask(`scripts:deps:${key}`, bundleTask({ - label: filename, - filename: `${filename}.js`, - buildLib: true, - dependenciesToBundle: externalDependenciesMap[key], - devMode: false, - })) + function createTasksForBuildJsDeps({ key, filename }) { + return createTask( + `scripts:deps:${key}`, + bundleTask({ + label: filename, + filename: `${filename}.js`, + buildLib: true, + dependenciesToBundle: externalDependenciesMap[key], + devMode: false, + }), + ) } - function createTasksForBuildJsExtension ({ taskPrefix, devMode, testing }) { - const standardBundles = [ - 'background', - 'ui', - 'phishing-detect', - ] + function createTasksForBuildJsExtension({ taskPrefix, devMode, testing }) { + const standardBundles = ['background', 'ui', 'phishing-detect'] const standardSubtasks = standardBundles.map((filename) => { - return createTask(`${taskPrefix}:${filename}`, - createBundleTaskForBuildJsExtensionNormal({ filename, devMode, testing })) + return createTask( + `${taskPrefix}:${filename}`, + createBundleTaskForBuildJsExtensionNormal({ + filename, + devMode, + testing, + }), + ) }) // inpage must be built before contentscript // because inpage bundle result is included inside contentscript - const contentscriptSubtask = createTask(`${taskPrefix}:contentscript`, - createTaskForBuildJsExtensionContentscript({ devMode, testing })) + const contentscriptSubtask = createTask( + `${taskPrefix}:contentscript`, + createTaskForBuildJsExtensionContentscript({ devMode, testing }), + ) // task for initiating livereload const initiateLiveReload = async () => { @@ -118,24 +132,33 @@ function createScriptTasks ({ browserPlatforms, livereload }) { } // make each bundle run in a separate process - const allSubtasks = [...standardSubtasks, contentscriptSubtask].map((subtask) => runInChildProcess(subtask)) + const allSubtasks = [ + ...standardSubtasks, + contentscriptSubtask, + ].map((subtask) => runInChildProcess(subtask)) // const allSubtasks = [...standardSubtasks, contentscriptSubtask].map(subtask => (subtask)) // make a parent task that runs each task in a child thread return composeParallel(initiateLiveReload, ...allSubtasks) } - function createBundleTaskForBuildJsExtensionNormal ({ filename, devMode, testing }) { + function createBundleTaskForBuildJsExtensionNormal({ + filename, + devMode, + testing, + }) { return bundleTask({ label: filename, filename: `${filename}.js`, filepath: `./app/scripts/${filename}.js`, - externalDependencies: devMode ? undefined : externalDependenciesMap[filename], + externalDependencies: devMode + ? undefined + : externalDependenciesMap[filename], devMode, testing, }) } - function createTaskForBuildJsExtensionContentscript ({ devMode, testing }) { + function createTaskForBuildJsExtensionContentscript({ devMode, testing }) { const inpage = 'inpage' const contentscript = 'contentscript' return composeSeries( @@ -143,7 +166,9 @@ function createScriptTasks ({ browserPlatforms, livereload }) { label: inpage, filename: `${inpage}.js`, filepath: `./app/scripts/${inpage}.js`, - externalDependencies: devMode ? undefined : externalDependenciesMap[inpage], + externalDependencies: devMode + ? undefined + : externalDependenciesMap[inpage], devMode, testing, }), @@ -151,19 +176,21 @@ function createScriptTasks ({ browserPlatforms, livereload }) { label: contentscript, filename: `${contentscript}.js`, filepath: `./app/scripts/${contentscript}.js`, - externalDependencies: devMode ? undefined : externalDependenciesMap[contentscript], + externalDependencies: devMode + ? undefined + : externalDependenciesMap[contentscript], devMode, testing, }), ) } - function bundleTask (opts) { + function bundleTask(opts) { let bundler return performBundle - async function performBundle () { + async function performBundle() { // initialize bundler if not available yet // dont create bundler until task is actually run if (!bundler) { @@ -198,26 +225,25 @@ function createScriptTasks ({ browserPlatforms, livereload }) { // Minification if (!opts.devMode) { - buildStream = buildStream - .pipe(terser({ + buildStream = buildStream.pipe( + terser({ mangle: { reserved: ['MetamaskInpageProvider'], }, sourceMap: { content: true, }, - })) + }), + ) } // Finalize Source Maps if (opts.devMode) { // Use inline source maps for development due to Chrome DevTools bug // https://bugs.chromium.org/p/chromium/issues/detail?id=931675 - buildStream = buildStream - .pipe(sourcemaps.write()) + buildStream = buildStream.pipe(sourcemaps.write()) } else { - buildStream = buildStream - .pipe(sourcemaps.write('../sourcemaps')) + buildStream = buildStream.pipe(sourcemaps.write('../sourcemaps')) } // write completed bundles @@ -230,10 +256,7 @@ function createScriptTasks ({ browserPlatforms, livereload }) { } } - function configureBundleForSesify ({ - browserifyOpts, - bundleName, - }) { + function configureBundleForSesify({ browserifyOpts, bundleName }) { // add in sesify args for better globalRef usage detection Object.assign(browserifyOpts, sesify.args) @@ -242,26 +265,36 @@ function createScriptTasks ({ browserPlatforms, livereload }) { // record dependencies used in bundle fs.mkdirSync('./sesify', { recursive: true }) - browserifyOpts.plugin.push(['deps-dump', { - filename: `./sesify/deps-${bundleName}.json`, - }]) + browserifyOpts.plugin.push([ + 'deps-dump', + { + filename: `./sesify/deps-${bundleName}.json`, + }, + ]) const sesifyConfigPath = `./sesify/${bundleName}.json` // add sesify plugin - browserifyOpts.plugin.push([sesify, { - writeAutoConfig: sesifyConfigPath, - }]) + browserifyOpts.plugin.push([ + sesify, + { + writeAutoConfig: sesifyConfigPath, + }, + ]) // remove html comments that SES is alergic to - const removeHtmlComment = makeStringTransform('remove-html-comment', { excludeExtension: ['.json'] }, (content, _, cb) => { - const result = content.split('-->').join('-- >') - cb(null, result) - }) + const removeHtmlComment = makeStringTransform( + 'remove-html-comment', + { excludeExtension: ['.json'] }, + (content, _, cb) => { + const result = content.split('-->').join('-- >') + cb(null, result) + }, + ) browserifyOpts.transform.push([removeHtmlComment, { global: true }]) } - function generateBundler (opts, performBundle) { + function generateBundler(opts, performBundle) { const browserifyOpts = assign({}, watchify.args, { plugin: [], transform: [], @@ -274,7 +307,8 @@ function createScriptTasks ({ browserPlatforms, livereload }) { // activate sesify const activateAutoConfig = Boolean(process.env.SESIFY_AUTOGEN) // const activateSesify = activateAutoConfig - const activateSesify = activateAutoConfig && ['background'].includes(bundleName) + const activateSesify = + activateAutoConfig && ['background'].includes(bundleName) if (activateSesify) { configureBundleForSesify({ browserifyOpts, bundleName }) } @@ -285,7 +319,10 @@ function createScriptTasks ({ browserPlatforms, livereload }) { if (!opts.buildLib) { if (opts.devMode && opts.filename === 'ui.js') { - browserifyOpts.entries = ['./development/require-react-devtools.js', opts.filepath] + browserifyOpts.entries = [ + './development/require-react-devtools.js', + opts.filepath, + ] } else { browserifyOpts.entries = [opts.filepath] } @@ -297,9 +334,7 @@ function createScriptTasks ({ browserPlatforms, livereload }) { // because it is incompatible with `esprima`, which is used by `envify` // See https://github.com/jquery/esprima/issues/1927 .transform('babelify', { - only: [ - './**/node_modules/libp2p', - ], + only: ['./**/node_modules/libp2p'], global: true, plugins: ['@babel/plugin-proposal-object-rest-spread'], }) @@ -313,7 +348,10 @@ function createScriptTasks ({ browserPlatforms, livereload }) { bundler = bundler.external(opts.externalDependencies) } - const environment = getEnvironment({ devMode: opts.devMode, test: opts.testing }) + const environment = getEnvironment({ + devMode: opts.devMode, + test: opts.testing, + }) if (environment === 'production' && !process.env.SENTRY_DSN) { throw new Error('Missing SENTRY_DSN environment variable') } @@ -323,33 +361,48 @@ function createScriptTasks ({ browserPlatforms, livereload }) { // the value of SEGMENT_WRITE_KEY that we envify is undefined then no events will be tracked // in the build. This is intentional so that developers can contribute to MetaMask without // inflating event volume. - const SEGMENT_PROD_WRITE_KEY = opts.testing ? undefined : process.env.SEGMENT_PROD_WRITE_KEY - const SEGMENT_DEV_WRITE_KEY = opts.testing ? undefined : conf.SEGMENT_WRITE_KEY - const SEGMENT_PROD_LEGACY_WRITE_KEY = opts.testing ? undefined : process.env.SEGMENT_PROD_LEGACY_WRITE_KEY - const SEGMENT_DEV_LEGACY_WRITE_KEY = opts.testing ? undefined : conf.SEGMENT_LEGACY_WRITE_KEY + const SEGMENT_PROD_WRITE_KEY = opts.testing + ? undefined + : process.env.SEGMENT_PROD_WRITE_KEY + const SEGMENT_DEV_WRITE_KEY = opts.testing + ? undefined + : conf.SEGMENT_WRITE_KEY + const SEGMENT_PROD_LEGACY_WRITE_KEY = opts.testing + ? undefined + : process.env.SEGMENT_PROD_LEGACY_WRITE_KEY + const SEGMENT_DEV_LEGACY_WRITE_KEY = opts.testing + ? undefined + : conf.SEGMENT_LEGACY_WRITE_KEY // Inject variables into bundle - bundler.transform(envify({ - METAMASK_DEBUG: opts.devMode, - METAMASK_ENVIRONMENT: environment, - METAMETRICS_PROJECT_ID: process.env.METAMETRICS_PROJECT_ID, - NODE_ENV: opts.devMode ? 'development' : 'production', - IN_TEST: opts.testing ? 'true' : false, - PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '', - PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '', - ETH_GAS_STATION_API_KEY: process.env.ETH_GAS_STATION_API_KEY || '', - CONF: opts.devMode ? conf : ({}), - SENTRY_DSN: process.env.SENTRY_DSN, - INFURA_PROJECT_ID: ( - opts.testing + bundler.transform( + envify({ + METAMASK_DEBUG: opts.devMode, + METAMASK_ENVIRONMENT: environment, + METAMETRICS_PROJECT_ID: process.env.METAMETRICS_PROJECT_ID, + NODE_ENV: opts.devMode ? 'development' : 'production', + IN_TEST: opts.testing ? 'true' : false, + PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '', + PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '', + ETH_GAS_STATION_API_KEY: process.env.ETH_GAS_STATION_API_KEY || '', + CONF: opts.devMode ? conf : {}, + SENTRY_DSN: process.env.SENTRY_DSN, + INFURA_PROJECT_ID: opts.testing ? '00000000000000000000000000000000' - : conf.INFURA_PROJECT_ID - ), - SEGMENT_WRITE_KEY: environment === 'production' ? SEGMENT_PROD_WRITE_KEY : SEGMENT_DEV_WRITE_KEY, - SEGMENT_LEGACY_WRITE_KEY: environment === 'production' ? SEGMENT_PROD_LEGACY_WRITE_KEY : SEGMENT_DEV_LEGACY_WRITE_KEY, - }), { - global: true, - }) + : conf.INFURA_PROJECT_ID, + SEGMENT_WRITE_KEY: + environment === 'production' + ? SEGMENT_PROD_WRITE_KEY + : SEGMENT_DEV_WRITE_KEY, + SEGMENT_LEGACY_WRITE_KEY: + environment === 'production' + ? SEGMENT_PROD_LEGACY_WRITE_KEY + : SEGMENT_DEV_LEGACY_WRITE_KEY, + }), + { + global: true, + }, + ) // Live reload - minimal rebundle on change if (opts.devMode) { @@ -362,14 +415,13 @@ function createScriptTasks ({ browserPlatforms, livereload }) { return bundler } - } -function beep () { +function beep() { process.stdout.write('\x07') } -function getEnvironment ({ devMode, test }) { +function getEnvironment({ devMode, test }) { // get environment slug if (devMode) { return 'development' @@ -377,7 +429,9 @@ function getEnvironment ({ devMode, test }) { return 'testing' } else if (process.env.CIRCLE_BRANCH === 'master') { return 'production' - } else if ((/^Version-v(\d+)[.](\d+)[.](\d+)/u).test(process.env.CIRCLE_BRANCH)) { + } else if ( + /^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH) + ) { return 'release-candidate' } else if (process.env.CIRCLE_BRANCH === 'develop') { return 'staging' diff --git a/development/build/static.js b/development/build/static.js index 3d4c74394..8a9263935 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -69,22 +69,31 @@ const copyTargetsDev = [ }, ] -function createStaticAssetTasks ({ livereload, browserPlatforms }) { - - const prod = createTask('static:prod', composeSeries(...copyTargets.map((target) => { - return async function copyStaticAssets () { - await performCopy(target) - } - }))) - const dev = createTask('static:dev', composeSeries(...copyTargetsDev.map((target) => { - return async function copyStaticAssets () { - await setupLiveCopy(target) - } - }))) +function createStaticAssetTasks({ livereload, browserPlatforms }) { + const prod = createTask( + 'static:prod', + composeSeries( + ...copyTargets.map((target) => { + return async function copyStaticAssets() { + await performCopy(target) + } + }), + ), + ) + const dev = createTask( + 'static:dev', + composeSeries( + ...copyTargetsDev.map((target) => { + return async function copyStaticAssets() { + await setupLiveCopy(target) + } + }), + ), + ) return { dev, prod } - async function setupLiveCopy (target) { + async function setupLiveCopy(target) { const pattern = target.pattern || '/**/*' watch(target.src + pattern, (event) => { livereload.changed(event.path) @@ -93,22 +102,33 @@ function createStaticAssetTasks ({ livereload, browserPlatforms }) { await performCopy(target) } - async function performCopy (target) { - await Promise.all(browserPlatforms.map(async (platform) => { - if (target.pattern) { - await copyGlob(target.src, `${target.src}${target.pattern}`, `./dist/${platform}/${target.dest}`) - } else { - await copyGlob(target.src, `${target.src}`, `./dist/${platform}/${target.dest}`) - } - })) + async function performCopy(target) { + await Promise.all( + browserPlatforms.map(async (platform) => { + if (target.pattern) { + await copyGlob( + target.src, + `${target.src}${target.pattern}`, + `./dist/${platform}/${target.dest}`, + ) + } else { + await copyGlob( + target.src, + `${target.src}`, + `./dist/${platform}/${target.dest}`, + ) + } + }), + ) } - async function copyGlob (baseDir, srcGlob, dest) { + async function copyGlob(baseDir, srcGlob, dest) { const sources = await glob(srcGlob, { onlyFiles: false }) - await Promise.all(sources.map(async (src) => { - const relativePath = path.relative(baseDir, src) - await fs.copy(src, `${dest}${relativePath}`) - })) + await Promise.all( + sources.map(async (src) => { + const relativePath = path.relative(baseDir, src) + await fs.copy(src, `${dest}${relativePath}`) + }), + ) } - } diff --git a/development/build/styles.js b/development/build/styles.js index 4be766673..966b2c818 100644 --- a/development/build/styles.js +++ b/development/build/styles.js @@ -14,35 +14,38 @@ const { createTask } = require('./task') // scss compilation and autoprefixing tasks module.exports = createStyleTasks -function createStyleTasks ({ livereload }) { +function createStyleTasks({ livereload }) { + const prod = createTask( + 'styles:prod', + createScssBuildTask({ + src: 'ui/app/css/index.scss', + dest: 'ui/app/css/output', + devMode: false, + }), + ) - const prod = createTask('styles:prod', createScssBuildTask({ - src: 'ui/app/css/index.scss', - dest: 'ui/app/css/output', - devMode: false, - })) - - const dev = createTask('styles:dev', createScssBuildTask({ - src: 'ui/app/css/index.scss', - dest: 'ui/app/css/output', - devMode: true, - pattern: 'ui/app/**/*.scss', - })) + const dev = createTask( + 'styles:dev', + createScssBuildTask({ + src: 'ui/app/css/index.scss', + dest: 'ui/app/css/output', + devMode: true, + pattern: 'ui/app/**/*.scss', + }), + ) const lint = createTask('lint-scss', function () { - return gulp - .src('ui/app/css/itcss/**/*.scss') - .pipe(gulpStylelint({ - reporters: [ - { formatter: 'string', console: true }, - ], + return gulp.src('ui/app/css/itcss/**/*.scss').pipe( + gulpStylelint({ + reporters: [{ formatter: 'string', console: true }], fix: true, - })) + }), + ) }) return { prod, dev, lint } - function createScssBuildTask ({ src, dest, devMode, pattern }) { + function createScssBuildTask({ src, dest, devMode, pattern }) { return async function () { if (devMode) { watch(pattern, async (event) => { @@ -53,26 +56,27 @@ function createStyleTasks ({ livereload }) { await buildScss() } - async function buildScss () { + async function buildScss() { await Promise.all([ buildScssPipeline(src, dest, devMode, false), buildScssPipeline(src, dest, devMode, true), ]) } } - } -async function buildScssPipeline (src, dest, devMode, rtl) { - await pump(...[ - // pre-process - gulp.src(src), - devMode && sourcemaps.init(), - sass().on('error', sass.logError), - autoprefixer(), - rtl && rtlcss(), - rtl && rename({ suffix: '-rtl' }), - devMode && sourcemaps.write(), - gulp.dest(dest), - ].filter(Boolean)) +async function buildScssPipeline(src, dest, devMode, rtl) { + await pump( + ...[ + // pre-process + gulp.src(src), + devMode && sourcemaps.init(), + sass().on('error', sass.logError), + autoprefixer(), + rtl && rtlcss(), + rtl && rename({ suffix: '-rtl' }), + devMode && sourcemaps.write(), + gulp.dest(dest), + ].filter(Boolean), + ) } diff --git a/development/build/task.js b/development/build/task.js index 6988696d7..553a06956 100644 --- a/development/build/task.js +++ b/development/build/task.js @@ -4,11 +4,20 @@ const spawn = require('cross-spawn') const tasks = {} const taskEvents = new EventEmitter() -module.exports = { detectAndRunEntryTask, tasks, taskEvents, createTask, runTask, composeSeries, composeParallel, runInChildProcess } +module.exports = { + detectAndRunEntryTask, + tasks, + taskEvents, + createTask, + runTask, + composeSeries, + composeParallel, + runInChildProcess, +} const { setupTaskDisplay } = require('./display') -function detectAndRunEntryTask () { +function detectAndRunEntryTask() { // get requested task name and execute const taskName = process.argv[2] if (!taskName) { @@ -19,7 +28,7 @@ function detectAndRunEntryTask () { runTask(taskName, { skipStats }) } -async function runTask (taskName, { skipStats } = {}) { +async function runTask(taskName, { skipStats } = {}) { if (!(taskName in tasks)) { throw new Error(`MetaMask build: Unrecognized task name "${taskName}"`) } @@ -30,16 +39,20 @@ async function runTask (taskName, { skipStats } = {}) { try { await tasks[taskName]() } catch (err) { - console.error(`MetaMask build: Encountered an error while running task "${taskName}".`) + console.error( + `MetaMask build: Encountered an error while running task "${taskName}".`, + ) console.error(err) process.exit(1) } taskEvents.emit('complete') } -function createTask (taskName, taskFn) { +function createTask(taskName, taskFn) { if (taskName in tasks) { - throw new Error(`MetaMask build: task "${taskName}" already exists. Refusing to redefine`) + throw new Error( + `MetaMask build: task "${taskName}" already exists. Refusing to redefine`, + ) } const task = instrumentForTaskStats(taskName, taskFn) task.taskName = taskName @@ -47,24 +60,34 @@ function createTask (taskName, taskFn) { return task } -function runInChildProcess (task) { +function runInChildProcess(task) { const taskName = typeof task === 'string' ? task : task.taskName if (!taskName) { - throw new Error(`MetaMask build: runInChildProcess unable to identify task name`) + throw new Error( + `MetaMask build: runInChildProcess unable to identify task name`, + ) } return instrumentForTaskStats(taskName, async () => { const childProcess = spawn('yarn', ['build', taskName, '--skip-stats']) // forward logs to main process // skip the first stdout event (announcing the process command) childProcess.stdout.once('data', () => { - childProcess.stdout.on('data', (data) => process.stdout.write(`${taskName}: ${data}`)) + childProcess.stdout.on('data', (data) => + process.stdout.write(`${taskName}: ${data}`), + ) }) - childProcess.stderr.on('data', (data) => process.stderr.write(`${taskName}: ${data}`)) + childProcess.stderr.on('data', (data) => + process.stderr.write(`${taskName}: ${data}`), + ) // await end of process await new Promise((resolve, reject) => { childProcess.once('close', (errCode) => { if (errCode !== 0) { - reject(new Error(`MetaMask build: runInChildProcess for task "${taskName}" encountered an error`)) + reject( + new Error( + `MetaMask build: runInChildProcess for task "${taskName}" encountered an error`, + ), + ) return } resolve() @@ -73,7 +96,7 @@ function runInChildProcess (task) { }) } -function instrumentForTaskStats (taskName, asyncFn) { +function instrumentForTaskStats(taskName, asyncFn) { return async () => { const start = Date.now() taskEvents.emit('start', [taskName, start]) @@ -83,7 +106,7 @@ function instrumentForTaskStats (taskName, asyncFn) { } } -function composeSeries (...subtasks) { +function composeSeries(...subtasks) { return async () => { const realTasks = subtasks for (const subtask of realTasks) { @@ -92,7 +115,7 @@ function composeSeries (...subtasks) { } } -function composeParallel (...subtasks) { +function composeParallel(...subtasks) { return async () => { const realTasks = subtasks await Promise.all(realTasks.map((subtask) => subtask())) diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index 51d9617a2..fd514fa8d 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -6,12 +6,11 @@ const VERSION = require('../dist/chrome/manifest.json').version // eslint-disabl start().catch(console.error) -function capitalizeFirstLetter (string) { +function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1) } -async function start () { - +async function start() { const { GITHUB_COMMENT_TOKEN, CIRCLE_PULL_REQUEST } = process.env console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) const { CIRCLE_SHA1 } = process.env @@ -32,17 +31,29 @@ async function start () { // links to extension builds const platforms = ['chrome', 'firefox', 'opera'] - const buildLinks = platforms.map((platform) => { - const url = `${BUILD_LINK_BASE}/builds/metamask-${platform}-${VERSION}.zip` - return `${platform}` - }).join(', ') + const buildLinks = platforms + .map((platform) => { + const url = `${BUILD_LINK_BASE}/builds/metamask-${platform}-${VERSION}.zip` + return `${platform}` + }) + .join(', ') // links to bundle browser builds - const bundles = ['background', 'ui', 'inpage', 'contentscript', 'ui-libs', 'bg-libs', 'phishing-detect'] - const bundleLinks = bundles.map((bundle) => { - const url = `${BUILD_LINK_BASE}/build-artifacts/source-map-explorer/${bundle}.html` - return `${bundle}` - }).join(', ') + const bundles = [ + 'background', + 'ui', + 'inpage', + 'contentscript', + 'ui-libs', + 'bg-libs', + 'phishing-detect', + ] + const bundleLinks = bundles + .map((bundle) => { + const url = `${BUILD_LINK_BASE}/build-artifacts/source-map-explorer/${bundle}.html` + return `${bundle}` + }) + .join(', ') // links to bundle browser builds const depVizUrl = `${BUILD_LINK_BASE}/build-artifacts/deps-viz/background/index.html` @@ -57,13 +68,19 @@ async function start () { `dep viz: ${depVizLink}`, `all artifacts`, ] - const hiddenContent = `
    ${contentRows.map((row) => `
  • ${row}
  • `).join('\n')}
` + const hiddenContent = `
    ${contentRows + .map((row) => `
  • ${row}
  • `) + .join('\n')}
` const exposedContent = `Builds ready [${SHORT_SHA1}]` const artifactsBody = `
${exposedContent}${hiddenContent}
` const benchmarkResults = {} for (const platform of platforms) { - const benchmarkPath = path.resolve(__dirname, '..', path.join('test-artifacts', platform, 'benchmark', 'pageload.json')) + const benchmarkPath = path.resolve( + __dirname, + '..', + path.join('test-artifacts', platform, 'benchmark', 'pageload.json'), + ) try { const data = await fs.readFile(benchmarkPath, 'utf8') const benchmark = JSON.parse(data) @@ -72,7 +89,9 @@ async function start () { if (error.code === 'ENOENT') { console.log(`No benchmark data found for ${platform}; skipping`) } else { - console.error(`Error encountered processing benchmark data for '${platform}': '${error}'`) + console.error( + `Error encountered processing benchmark data for '${platform}': '${error}'`, + ) } } } @@ -82,8 +101,14 @@ async function start () { let commentBody if (benchmarkResults[summaryPlatform]) { try { - const summaryPageLoad = Math.round(parseFloat(benchmarkResults[summaryPlatform][summaryPage].average.load)) - const summaryPageLoadMarginOfError = Math.round(parseFloat(benchmarkResults[summaryPlatform][summaryPage].marginOfError.load)) + const summaryPageLoad = Math.round( + parseFloat(benchmarkResults[summaryPlatform][summaryPage].average.load), + ) + const summaryPageLoadMarginOfError = Math.round( + parseFloat( + benchmarkResults[summaryPlatform][summaryPage].marginOfError.load, + ), + ) const benchmarkSummary = `Page Load Metrics (${summaryPageLoad} ± ${summaryPageLoadMarginOfError} ms)` const allPlatforms = new Set() @@ -117,14 +142,20 @@ async function start () { for (const metric of allMetrics) { let metricData = `${metric}` for (const measure of allMeasures) { - metricData += `${Math.round(parseFloat(benchmarkResults[platform][page][measure][metric]))}` + metricData += `${Math.round( + parseFloat(benchmarkResults[platform][page][measure][metric]), + )}` } metricRows.push(metricData) } - metricRows[0] = `${capitalizeFirstLetter(page)}${metricRows[0]}` + metricRows[0] = `${capitalizeFirstLetter(page)}${metricRows[0]}` pageRows.push(...metricRows) } - pageRows[0] = `${capitalizeFirstLetter(platform)}${pageRows[0]}` + pageRows[0] = `${capitalizeFirstLetter(platform)}${pageRows[0]}` for (const row of pageRows) { tableRows.push(`${row}`) } @@ -134,7 +165,9 @@ async function start () { for (const measure of allMeasures) { benchmarkTableHeaders.push(`${capitalizeFirstLetter(measure)} (ms)`) } - const benchmarkTableHeader = `${benchmarkTableHeaders.map((header) => `${header}`).join('')}` + const benchmarkTableHeader = `${benchmarkTableHeaders + .map((header) => `${header}`) + .join('')}` const benchmarkTableBody = `${tableRows.join('')}` const benchmarkTable = `${benchmarkTableHeader}${benchmarkTableBody}
` const benchmarkBody = `
${benchmarkSummary}${benchmarkTable}
` @@ -158,7 +191,7 @@ async function start () { body: JSON_PAYLOAD, headers: { 'User-Agent': 'metamaskbot', - 'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, + Authorization: `token ${GITHUB_COMMENT_TOKEN}`, }, }) if (!response.ok) { diff --git a/development/mock-3box.js b/development/mock-3box.js index e4260c610..14c888f86 100644 --- a/development/mock-3box.js +++ b/development/mock-3box.js @@ -1,14 +1,14 @@ -function delay (time) { +function delay(time) { return new Promise((resolve) => setTimeout(resolve, time)) } -async function loadFromMock3Box (key) { +async function loadFromMock3Box(key) { const res = await window.fetch(`http://localhost:8889?key=${key}`) const text = await res.text() return text.length ? JSON.parse(text) : null } -async function saveToMock3Box (key, newDataAtKey) { +async function saveToMock3Box(key, newDataAtKey) { const res = await window.fetch('http://localhost:8889', { method: 'POST', body: JSON.stringify({ @@ -21,7 +21,7 @@ async function saveToMock3Box (key, newDataAtKey) { } class Mock3Box { - static openBox (address) { + static openBox(address) { this.address = address return Promise.resolve({ onSyncDone: (cb) => { @@ -39,11 +39,16 @@ class Mock3Box { private: { get: async (key) => { await delay(50) - const res = await loadFromMock3Box(`${this.address}-${this.spaceName}-${key}`) + const res = await loadFromMock3Box( + `${this.address}-${this.spaceName}-${key}`, + ) return res }, set: async (key, data) => { - await saveToMock3Box(`${this.address}-${this.spaceName}-${key}`, data) + await saveToMock3Box( + `${this.address}-${this.spaceName}-${key}`, + data, + ) await delay(50) return null }, @@ -54,11 +59,9 @@ class Mock3Box { }) } - static async getConfig (address) { + static async getConfig(address) { const backup = await loadFromMock3Box(`${address}-metamask-metamaskBackup`) - return backup - ? { spaces: { metamask: {} } } - : {} + return backup ? { spaces: { metamask: {} } } : {} } } diff --git a/development/sentry-publish.js b/development/sentry-publish.js index 80c373608..853d1391d 100644 --- a/development/sentry-publish.js +++ b/development/sentry-publish.js @@ -7,7 +7,7 @@ const VERSION = require('../dist/chrome/manifest.json').version // eslint-disabl start().catch(console.error) -async function start () { +async function start() { const authWorked = await checkIfAuthWorks() if (!authWorked) { console.log(`Sentry auth failed...`) @@ -16,48 +16,62 @@ async function start () { const versionAlreadyExists = await checkIfVersionExists() // abort if versions exists if (versionAlreadyExists) { - console.log(`Version "${VERSION}" already exists on Sentry, skipping version creation`) + console.log( + `Version "${VERSION}" already exists on Sentry, skipping version creation`, + ) } else { // create sentry release console.log(`creating Sentry release for "${VERSION}"...`) - await exec(`sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`) - console.log(`removing any existing files from Sentry release "${VERSION}"...`) - await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} delete --all`) + await exec( + `sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`, + ) + console.log( + `removing any existing files from Sentry release "${VERSION}"...`, + ) + await exec( + `sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} delete --all`, + ) } // check if version has artifacts or not - const versionHasArtifacts = versionAlreadyExists && await checkIfVersionHasArtifacts() + const versionHasArtifacts = + versionAlreadyExists && (await checkIfVersionHasArtifacts()) if (versionHasArtifacts) { - console.log(`Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`) + console.log( + `Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`, + ) return } // upload sentry source and sourcemaps await exec(`./development/sentry-upload-artifacts.sh --release ${VERSION}`) - } -async function checkIfAuthWorks () { +async function checkIfAuthWorks() { const itWorked = await doesNotFail(async () => { await exec(`sentry-cli releases --org 'metamask' --project 'metamask' list`) }) return itWorked } -async function checkIfVersionExists () { +async function checkIfVersionExists() { const versionAlreadyExists = await doesNotFail(async () => { - await exec(`sentry-cli releases --org 'metamask' --project 'metamask' info ${VERSION}`) + await exec( + `sentry-cli releases --org 'metamask' --project 'metamask' info ${VERSION}`, + ) }) return versionAlreadyExists } -async function checkIfVersionHasArtifacts () { - const artifacts = await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} list`) +async function checkIfVersionHasArtifacts() { + const artifacts = await exec( + `sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} list`, + ) // When there's no artifacts, we get a response from the shell like this ['', ''] return artifacts[0] && artifacts[0].length > 0 } -async function doesNotFail (asyncFn) { +async function doesNotFail(asyncFn) { try { await asyncFn() return true diff --git a/development/show-deps-install-scripts.js b/development/show-deps-install-scripts.js index 12301fe0d..3421ed351 100644 --- a/development/show-deps-install-scripts.js +++ b/development/show-deps-install-scripts.js @@ -14,7 +14,9 @@ readInstalled('./', { dev: true }, function (err, data) { const packageScripts = packageData.scripts || {} const scriptKeys = Reflect.ownKeys(packageScripts) - const hasInstallScript = installScripts.some((installKey) => scriptKeys.includes(installKey)) + const hasInstallScript = installScripts.some((installKey) => + scriptKeys.includes(installKey), + ) if (!hasInstallScript) { return } diff --git a/development/sourcemap-validator.js b/development/sourcemap-validator.js index cb5f6f6c8..6730b8785 100644 --- a/development/sourcemap-validator.js +++ b/development/sourcemap-validator.js @@ -18,7 +18,7 @@ start().catch((error) => { process.exit(1) }) -async function start () { +async function start() { const targetFiles = [ `background.js`, // `bg-libs`, skipped because source maps are invalid due to browserify bug: https://github.com/browserify/browserify/issues/1971 @@ -40,37 +40,53 @@ async function start () { } } -async function validateSourcemapForFile ({ buildName }) { +async function validateSourcemapForFile({ buildName }) { console.log(`build "${buildName}"`) const platform = `chrome` // load build and sourcemaps let rawBuild try { - const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}`) + const filePath = path.join( + __dirname, + `/../dist/${platform}/`, + `${buildName}`, + ) rawBuild = await fsAsync.readFile(filePath, 'utf8') } catch (_) { // empty } if (!rawBuild) { - throw new Error(`SourcemapValidator - failed to load source file for "${buildName}"`) + throw new Error( + `SourcemapValidator - failed to load source file for "${buildName}"`, + ) } // attempt to load in dist mode let rawSourceMap try { - const filePath = path.join(__dirname, `/../dist/sourcemaps/`, `${buildName}.map`) + const filePath = path.join( + __dirname, + `/../dist/sourcemaps/`, + `${buildName}.map`, + ) rawSourceMap = await fsAsync.readFile(filePath, 'utf8') } catch (_) { // empty } // attempt to load in dev mode try { - const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}.map`) + const filePath = path.join( + __dirname, + `/../dist/${platform}/`, + `${buildName}.map`, + ) rawSourceMap = await fsAsync.readFile(filePath, 'utf8') } catch (_) { // empty } if (!rawSourceMap) { - throw new Error(`SourcemapValidator - failed to load sourcemaps for "${buildName}"`) + throw new Error( + `SourcemapValidator - failed to load sourcemaps for "${buildName}"`, + ) } const consumer = await new SourceMapConsumer(rawSourceMap) @@ -96,7 +112,9 @@ async function validateSourcemapForFile ({ buildName }) { // warn if source content is missing if (!result.source) { valid = false - console.warn(`!! missing source for position: ${JSON.stringify(position)}`) + console.warn( + `!! missing source for position: ${JSON.stringify(position)}`, + ) // const buildLine = buildLines[position.line - 1] console.warn(` origin in build:`) console.warn(` ${buildLines[position.line - 2]}`) @@ -112,7 +130,9 @@ async function validateSourcemapForFile ({ buildName }) { const isMaybeValid = portion.includes(targetString) if (!isMaybeValid) { valid = false - console.error(`Sourcemap seems invalid:\n${getFencedCode(result.source, line)}`) + console.error( + `Sourcemap seems invalid:\n${getFencedCode(result.source, line)}`, + ) } }) }) @@ -123,18 +143,25 @@ async function validateSourcemapForFile ({ buildName }) { const CODE_FENCE_LENGTH = 80 const TITLE_PADDING_LENGTH = 1 -function getFencedCode (filename, code) { - const title = `${' '.repeat(TITLE_PADDING_LENGTH)}${filename}${' '.repeat(TITLE_PADDING_LENGTH)}` - const openingFenceLength = Math.max(CODE_FENCE_LENGTH - (filename.length + (TITLE_PADDING_LENGTH * 2)), 0) +function getFencedCode(filename, code) { + const title = `${' '.repeat(TITLE_PADDING_LENGTH)}${filename}${' '.repeat( + TITLE_PADDING_LENGTH, + )}` + const openingFenceLength = Math.max( + CODE_FENCE_LENGTH - (filename.length + TITLE_PADDING_LENGTH * 2), + 0, + ) const startOpeningFenceLength = Math.floor(openingFenceLength / 2) const endOpeningFenceLength = Math.ceil(openingFenceLength / 2) - const openingFence = `${'='.repeat(startOpeningFenceLength)}${title}${'='.repeat(endOpeningFenceLength)}` + const openingFence = `${'='.repeat( + startOpeningFenceLength, + )}${title}${'='.repeat(endOpeningFenceLength)}` const closingFence = '='.repeat(CODE_FENCE_LENGTH) return `${openingFence}\n${code}\n${closingFence}\n` } -function indicesOf (substring, string) { +function indicesOf(substring, string) { const a = [] let i = -1 while ((i = string.indexOf(substring, i + 1)) >= 0) { diff --git a/development/static-server.js b/development/static-server.js index a20908878..c864d3c85 100644 --- a/development/static-server.js +++ b/development/static-server.js @@ -13,9 +13,13 @@ const onResponse = (request, response) => { if (response.statusCode >= 400) { console.log(chalk`{gray '-->'} {red ${response.statusCode}} ${request.url}`) } else if (response.statusCode >= 200 && response.statusCode < 300) { - console.log(chalk`{gray '-->'} {green ${response.statusCode}} ${request.url}`) + console.log( + chalk`{gray '-->'} {green ${response.statusCode}} ${request.url}`, + ) } else { - console.log(chalk`{gray '-->'} {green.dim ${response.statusCode}} ${request.url}`) + console.log( + chalk`{gray '-->'} {green.dim ${response.statusCode}} ${request.url}`, + ) } } const onRequest = (request, response) => { @@ -38,7 +42,9 @@ const parsePort = (portString) => { if (!Number.isInteger(port)) { throw new Error(`Port '${portString}' is invalid; must be an integer`) } else if (port < 0 || port > 65535) { - throw new Error(`Port '${portString}' is out of range; must be between 0 and 65535 inclusive`) + throw new Error( + `Port '${portString}' is out of range; must be between 0 and 65535 inclusive`, + ) } return port } @@ -61,7 +67,7 @@ const main = async () => { } while (args.length) { - if ((/^(--port|-p)$/u).test(args[0])) { + if (/^(--port|-p)$/u.test(args[0])) { if (args[1] === undefined) { throw new Error('Missing port argument') } @@ -76,8 +82,7 @@ const main = async () => { startServer(options) } -main() - .catch((error) => { - console.error(error) - process.exit(1) - }) +main().catch((error) => { + console.error(error) + process.exit(1) +}) diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index a26e421c8..9325824f7 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -46,19 +46,21 @@ for (const arg of process.argv.slice(2)) { } } -main() - .catch((error) => { - log.error(error) - process.exit(1) - }) +main().catch((error) => { + log.error(error) + process.exit(1) +}) -async function main () { +async function main() { if (specifiedLocale) { log.info(`Verifying selected locale "${specifiedLocale}":\n`) - const locale = localeIndex.find((localeMeta) => localeMeta.code === specifiedLocale) - const failed = locale.code === 'en' ? - await verifyEnglishLocale() : - await verifyLocale(locale) + const locale = localeIndex.find( + (localeMeta) => localeMeta.code === specifiedLocale, + ) + const failed = + locale.code === 'en' + ? await verifyEnglishLocale() + : await verifyLocale(locale) if (failed) { process.exit(1) } @@ -81,11 +83,11 @@ async function main () { } } -function getLocalePath (code) { +function getLocalePath(code) { return path.resolve(__dirname, '..', 'app', '_locales', code, 'messages.json') } -async function getLocale (code) { +async function getLocale(code) { try { const localeFilePath = getLocalePath(code) const fileContents = await readFile(localeFilePath, 'utf8') @@ -100,10 +102,14 @@ async function getLocale (code) { } } -async function writeLocale (code, locale) { +async function writeLocale(code, locale) { try { const localeFilePath = getLocalePath(code) - return writeFile(localeFilePath, `${JSON.stringify(locale, null, 2)}\n`, 'utf8') + return writeFile( + localeFilePath, + `${JSON.stringify(locale, null, 2)}\n`, + 'utf8', + ) } catch (e) { if (e.code === 'ENOENT') { log.error('Locale file not found') @@ -114,15 +120,22 @@ async function writeLocale (code, locale) { } } -async function verifyLocale (code) { +async function verifyLocale(code) { const englishLocale = await getLocale('en') const targetLocale = await getLocale(code) - const extraItems = compareLocalesForMissingItems({ base: targetLocale, subject: englishLocale }) - const missingItems = compareLocalesForMissingItems({ base: englishLocale, subject: targetLocale }) + const extraItems = compareLocalesForMissingItems({ + base: targetLocale, + subject: englishLocale, + }) + const missingItems = compareLocalesForMissingItems({ + base: englishLocale, + subject: targetLocale, + }) const englishEntryCount = Object.keys(englishLocale).length - const coveragePercent = 100 * (englishEntryCount - missingItems.length) / englishEntryCount + const coveragePercent = + (100 * (englishEntryCount - missingItems.length)) / englishEntryCount if (extraItems.length) { console.log(`**${code}**: ${extraItems.length} unused messages`) @@ -160,18 +173,20 @@ async function verifyLocale (code) { return false } -async function verifyEnglishLocale () { +async function verifyEnglishLocale() { const englishLocale = await getLocale('en') - const javascriptFiles = await findJavascriptFiles(path.resolve(__dirname, '..', 'ui')) + const javascriptFiles = await findJavascriptFiles( + path.resolve(__dirname, '..', 'ui'), + ) // match "t(`...`)" because constructing message keys from template strings // prevents this script from finding the messages, and then inappropriately // deletes them - const templateStringRegex = /\bt\(`.*`\)/ug + const templateStringRegex = /\bt\(`.*`\)/gu const templateUsage = [] // match the keys from the locale file - const keyRegex = /'(\w+)'|"(\w+)"/ug + const keyRegex = /'(\w+)'|"(\w+)"/gu const usedMessages = new Set() for await (const fileContents of getFileContents(javascriptFiles)) { for (const match of matchAll.call(fileContents, keyRegex)) { @@ -189,8 +204,10 @@ async function verifyEnglishLocale () { const messageExceptions = ['appName', 'appDescription'] const englishMessages = Object.keys(englishLocale) - const unusedMessages = englishMessages - .filter((message) => !messageExceptions.includes(message) && !usedMessages.has(message)) + const unusedMessages = englishMessages.filter( + (message) => + !messageExceptions.includes(message) && !usedMessages.has(message), + ) if (unusedMessages.length) { console.log(`**en**: ${unusedMessages.length} unused messages`) @@ -223,12 +240,14 @@ async function verifyEnglishLocale () { return true // failed === true } -async function findJavascriptFiles (rootDir) { +async function findJavascriptFiles(rootDir) { const javascriptFiles = [] const contents = await readdir(rootDir, { withFileTypes: true }) for (const file of contents) { if (file.isDirectory()) { - javascriptFiles.push(...(await findJavascriptFiles(path.join(rootDir, file.name)))) + javascriptFiles.push( + ...(await findJavascriptFiles(path.join(rootDir, file.name))), + ) } else if (file.isFile() && file.name.endsWith('.js')) { javascriptFiles.push(path.join(rootDir, file.name)) } @@ -236,12 +255,12 @@ async function findJavascriptFiles (rootDir) { return javascriptFiles } -async function * getFileContents (filenames) { +async function* getFileContents(filenames) { for (const filename of filenames) { yield readFile(filename, 'utf8') } } -function compareLocalesForMissingItems ({ base, subject }) { +function compareLocalesForMissingItems({ base, subject }) { return Object.keys(base).filter((key) => !subject[key]) } diff --git a/package.json b/package.json index 457ba244a..57f4d03be 100644 --- a/package.json +++ b/package.json @@ -221,6 +221,7 @@ "eslint-plugin-import": "^2.22.0", "eslint-plugin-mocha": "^8.0.0", "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "~7.20.0", "eslint-plugin-react-hooks": "^4.0.4", "fancy-log": "^1.3.3", diff --git a/shared/modules/metametrics.js b/shared/modules/metametrics.js index e794ebbd9..f957adb8d 100644 --- a/shared/modules/metametrics.js +++ b/shared/modules/metametrics.js @@ -12,15 +12,15 @@ const flushAt = 1 export const METAMETRICS_ANONYMOUS_ID = '0x0000000000000000' const segmentNoop = { - track (_, callback = () => undefined) { + track(_, callback = () => undefined) { // Need to call the callback so that environments without a segment id still // resolve the promise from trackMetaMetricsEvent return callback() }, - page () { + page() { // noop }, - identify () { + identify() { // noop }, } @@ -45,7 +45,7 @@ const trackableSendCounts = { 25000: true, } -export function sendCountIsTrackable (sendCount) { +export function sendCountIsTrackable(sendCount) { return Boolean(trackableSendCounts[sendCount]) } @@ -130,15 +130,13 @@ export const segmentLegacy = process.env.SEGMENT_LEGACY_WRITE_KEY * @param {() => MetaMetricsRequiredState} getDynamicState - A function returning required fields * @returns {(payload: MetaMetricsEventPayload) => Promise} - function to track an event */ -export function getTrackMetaMetricsEvent ( - metamaskVersion, - getDynamicState, -) { - const version = process.env.METAMASK_ENVIRONMENT === 'production' - ? metamaskVersion - : `${metamaskVersion}-${process.env.METAMASK_ENVIRONMENT}` +export function getTrackMetaMetricsEvent(metamaskVersion, getDynamicState) { + const version = + process.env.METAMASK_ENVIRONMENT === 'production' + ? metamaskVersion + : `${metamaskVersion}-${process.env.METAMASK_ENVIRONMENT}` - return function trackMetaMetricsEvent ({ + return function trackMetaMetricsEvent({ event, category, isOptIn, @@ -171,7 +169,11 @@ export function getTrackMetaMetricsEvent ( // to be updated to work with the new tracking plan. I think we should use // a config setting for this instead of trying to match the event name const isSendFlow = Boolean(event.match(/^send|^confirm/u)) - if (isSendFlow && metaMetricsSendCount && !sendCountIsTrackable(metaMetricsSendCount + 1)) { + if ( + isSendFlow && + metaMetricsSendCount && + !sendCountIsTrackable(metaMetricsSendCount + 1) + ) { excludeMetaMetricsId = true } diff --git a/test/e2e/address-book.spec.js b/test/e2e/address-book.spec.js index aac315235..6ed55b22b 100644 --- a/test/e2e/address-book.spec.js +++ b/test/e2e/address-book.spec.js @@ -2,11 +2,7 @@ const assert = require('assert') const { By, until } = require('selenium-webdriver') const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - tinyDelayMs, - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -15,7 +11,8 @@ const ganacheServer = new Ganache() describe('MetaMask', function () { let driver - const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' + const testSeedPhrase = + 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' this.timeout(0) this.bail(true) @@ -24,7 +21,8 @@ describe('MetaMask', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -38,7 +36,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors() if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -55,12 +55,18 @@ describe('MetaMask', function () { describe('Going through the first time flow', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create a Wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -70,8 +76,12 @@ describe('MetaMask', function () { }) it('accepts a secure password', async function () { - const passwordBox = await driver.findElement(By.css('.first-time-flow__form #create-password')) - const passwordBoxConfirm = await driver.findElement(By.css('.first-time-flow__form #confirm-password')) + const passwordBox = await driver.findElement( + By.css('.first-time-flow__form #create-password'), + ) + const passwordBoxConfirm = await driver.findElement( + By.css('.first-time-flow__form #confirm-password'), + ) await passwordBox.sendKeys('correct horse battery staple') await passwordBoxConfirm.sendKeys('correct horse battery staple') @@ -84,21 +94,33 @@ describe('MetaMask', function () { let seedPhrase it('reveals the seed phrase', async function () { - const byRevealButton = By.css('.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button') + const byRevealButton = By.css( + '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', + ) await driver.clickElement(byRevealButton) await driver.delay(regularDelayMs) - const revealedSeedPhrase = await driver.findElement(By.css('.reveal-seed-phrase__secret-words')) + const revealedSeedPhrase = await driver.findElement( + By.css('.reveal-seed-phrase__secret-words'), + ) seedPhrase = await revealedSeedPhrase.getText() assert.equal(seedPhrase.split(' ').length, 12) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.next.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.next.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) - async function clickWordAndWait (word) { - await driver.clickElement(By.css(`[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`)) + async function clickWordAndWait(word) { + await driver.clickElement( + By.css( + `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, + ), + ) await driver.delay(tinyDelayMs) } @@ -109,13 +131,21 @@ describe('MetaMask', function () { await clickWordAndWait(word) } - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) }) @@ -125,15 +155,22 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - const lockButton = await driver.findClickableElement(By.css('.account-menu__lock-button')) + const lockButton = await driver.findClickableElement( + By.css('.account-menu__lock-button'), + ) assert.equal(await lockButton.getText(), 'Lock') await lockButton.click() await driver.delay(regularDelayMs) }) it('imports seed phrase', async function () { - const restoreSeedLink = await driver.findClickableElement(By.css('.unlock-page__link--import')) - assert.equal(await restoreSeedLink.getText(), 'Import using account seed phrase') + const restoreSeedLink = await driver.findClickableElement( + By.css('.unlock-page__link--import'), + ) + assert.equal( + await restoreSeedLink.getText(), + 'Import using account seed phrase', + ) await restoreSeedLink.click() await driver.delay(regularDelayMs) @@ -148,12 +185,18 @@ describe('MetaMask', function () { await passwordInputs[0].sendKeys('correct horse battery staple') await passwordInputs[1].sendKeys('correct horse battery staple') - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.restore.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.restore.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) it('balance renders', async function () { - const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) + const balance = await driver.findElement( + By.css('[data-testid="wallet-balance"] .list-item__heading'), + ) await driver.wait(until.elementTextMatches(balance, /25\s*ETH/u)) await driver.delay(regularDelayMs) }) @@ -164,18 +207,26 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') await driver.delay(regularDelayMs) await driver.clickElement(By.css('.dialog.send__dialog.dialog--message')) - const addressBookAddModal = await driver.findElement(By.css('span .modal')) + const addressBookAddModal = await driver.findElement( + By.css('span .modal'), + ) await driver.findElement(By.css('.add-to-address-book-modal')) - const addressBookInput = await driver.findElement(By.css('.add-to-address-book-modal__input')) + const addressBookInput = await driver.findElement( + By.css('.add-to-address-book-modal__input'), + ) await addressBookInput.sendKeys('Test Name 1') await driver.delay(tinyDelayMs) - await driver.clickElement(By.css('.add-to-address-book-modal__footer .btn-primary')) + await driver.clickElement( + By.css('.add-to-address-book-modal__footer .btn-primary'), + ) await driver.wait(until.stalenessOf(addressBookAddModal)) @@ -192,18 +243,26 @@ describe('MetaMask', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs * 2) }) it('finds the transaction in the transactions list', async function () { await driver.clickElement(By.css('[data-testid="home__activity-tab"]')) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 1 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000) }) }) @@ -213,11 +272,15 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const recipientRowTitle = await driver.findElement(By.css('.send__select-recipient-wrapper__group-item__title')) + const recipientRowTitle = await driver.findElement( + By.css('.send__select-recipient-wrapper__group-item__title'), + ) const recipientRowTitleString = await recipientRowTitle.getText() assert.equal(recipientRowTitleString, 'Test Name 1') - await driver.clickElement(By.css('.send__select-recipient-wrapper__group-item')) + await driver.clickElement( + By.css('.send__select-recipient-wrapper__group-item'), + ) await driver.delay(regularDelayMs) const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -230,17 +293,25 @@ describe('MetaMask', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs * 2) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 2 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-2\s*ETH/u), 10000) }) }) diff --git a/test/e2e/benchmark.js b/test/e2e/benchmark.js index d8b79a9eb..442533c04 100644 --- a/test/e2e/benchmark.js +++ b/test/e2e/benchmark.js @@ -10,7 +10,7 @@ const { PAGES } = require('./webdriver/driver') const DEFAULT_NUM_SAMPLES = 20 const ALL_PAGES = Object.values(PAGES) -async function measurePage (pageName) { +async function measurePage(pageName) { let metrics await withFixtures({ fixtures: 'imported-account' }, async ({ driver }) => { const passwordField = await driver.findElement(By.css('#password')) @@ -24,7 +24,7 @@ async function measurePage (pageName) { return metrics } -function calculateResult (calc) { +function calculateResult(calc) { return (result) => { const calculatedResult = {} for (const key of Object.keys(result)) { @@ -44,10 +44,13 @@ const standardDeviationResult = calculateResult((array) => { return Math.sqrt(calculateAverage(squareDiffs)) }) // 95% margin of error calculated using Student's t-distribution -const calculateMarginOfError = (array) => ttest(array).confidence()[1] - calculateAverage(array) -const marginOfErrorResult = calculateResult((array) => calculateMarginOfError(array)) +const calculateMarginOfError = (array) => + ttest(array).confidence()[1] - calculateAverage(array) +const marginOfErrorResult = calculateResult((array) => + calculateMarginOfError(array), +) -async function profilePageLoad (pages, numSamples) { +async function profilePageLoad(pages, numSamples) { const results = {} for (const pageName of pages) { const runResults = [] @@ -57,15 +60,30 @@ async function profilePageLoad (pages, numSamples) { if (runResults.some((result) => result.navigation.lenth > 1)) { throw new Error(`Multiple navigations not supported`) - } else if (runResults.some((result) => result.navigation[0].type !== 'navigate')) { - throw new Error(`Navigation type ${runResults.find((result) => result.navigation[0].type !== 'navigate').navigation[0].type} not supported`) + } else if ( + runResults.some((result) => result.navigation[0].type !== 'navigate') + ) { + throw new Error( + `Navigation type ${ + runResults.find((result) => result.navigation[0].type !== 'navigate') + .navigation[0].type + } not supported`, + ) } const result = { firstPaint: runResults.map((metrics) => metrics.paint['first-paint']), - domContentLoaded: runResults.map((metrics) => metrics.navigation[0] && metrics.navigation[0].domContentLoaded), - load: runResults.map((metrics) => metrics.navigation[0] && metrics.navigation[0].load), - domInteractive: runResults.map((metrics) => metrics.navigation[0] && metrics.navigation[0].domInteractive), + domContentLoaded: runResults.map( + (metrics) => + metrics.navigation[0] && metrics.navigation[0].domContentLoaded, + ), + load: runResults.map( + (metrics) => metrics.navigation[0] && metrics.navigation[0].load, + ), + domInteractive: runResults.map( + (metrics) => + metrics.navigation[0] && metrics.navigation[0].domInteractive, + ), } results[pageName] = { @@ -79,7 +97,7 @@ async function profilePageLoad (pages, numSamples) { return results } -async function isWritable (directory) { +async function isWritable(directory) { try { await fs.access(directory, fsConstants.W_OK) return true @@ -91,7 +109,7 @@ async function isWritable (directory) { } } -async function getFirstParentDirectoryThatExists (directory) { +async function getFirstParentDirectoryThatExists(directory) { let nextDirectory = directory for (;;) { try { @@ -108,7 +126,7 @@ async function getFirstParentDirectoryThatExists (directory) { } } -async function main () { +async function main() { const args = process.argv.slice(2) let pages = ['home'] @@ -118,7 +136,7 @@ async function main () { let existingParentDirectory while (args.length) { - if ((/^(--pages|-p)$/u).test(args[0])) { + if (/^(--pages|-p)$/u.test(args[0])) { if (args[1] === undefined) { throw new Error('Missing pages argument') } @@ -129,7 +147,7 @@ async function main () { } } args.splice(0, 2) - } else if ((/^(--samples|-s)$/u).test(args[0])) { + } else if (/^(--samples|-s)$/u.test(args[0])) { if (args[1] === undefined) { throw new Error('Missing number of samples') } @@ -138,14 +156,16 @@ async function main () { throw new Error(`Invalid 'samples' argument given: '${args[1]}'`) } args.splice(0, 2) - } else if ((/^(--out|-o)$/u).test(args[0])) { + } else if (/^(--out|-o)$/u.test(args[0])) { if (args[1] === undefined) { throw new Error('Missing output filename') } outputPath = path.resolve(args[1]) outputDirectory = path.dirname(outputPath) - existingParentDirectory = await getFirstParentDirectoryThatExists(outputDirectory) - if (!await isWritable(existingParentDirectory)) { + existingParentDirectory = await getFirstParentDirectoryThatExists( + outputDirectory, + ) + if (!(await isWritable(existingParentDirectory))) { throw new Error(`Specified directory is not writable: '${args[1]}'`) } args.splice(0, 2) @@ -166,8 +186,7 @@ async function main () { } } -main() - .catch((e) => { - console.error(e) - process.exit(1) - }) +main().catch((e) => { + console.error(e) + process.exit(1) +}) diff --git a/test/e2e/ethereum-on.spec.js b/test/e2e/ethereum-on.spec.js index 784267900..2d90f23d7 100644 --- a/test/e2e/ethereum-on.spec.js +++ b/test/e2e/ethereum-on.spec.js @@ -3,10 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -23,7 +20,8 @@ describe('MetaMask', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -37,7 +35,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -54,12 +54,18 @@ describe('MetaMask', function () { describe('Going through the first time flow, but skipping the seed phrase challenge', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create a Wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -69,8 +75,12 @@ describe('MetaMask', function () { }) it('accepts a secure password', async function () { - const passwordBox = await driver.findElement(By.css('.first-time-flow__form #create-password')) - const passwordBoxConfirm = await driver.findElement(By.css('.first-time-flow__form #confirm-password')) + const passwordBox = await driver.findElement( + By.css('.first-time-flow__form #create-password'), + ) + const passwordBoxConfirm = await driver.findElement( + By.css('.first-time-flow__form #confirm-password'), + ) await passwordBox.sendKeys('correct horse battery staple') await passwordBoxConfirm.sendKeys('correct horse battery staple') @@ -81,15 +91,25 @@ describe('MetaMask', function () { }) it('skips the seed phrase challenge', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`, + ), + ) await driver.delay(regularDelayMs) - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) }) it('gets the current accounts address', async function () { - const addressInput = await driver.findElement(By.css('.readonly-input__input')) + const addressInput = await driver.findElement( + By.css('.readonly-input__input'), + ) publicAddress = await addressInput.getAttribute('value') const accountModal = await driver.findElement(By.css('span .modal')) @@ -98,7 +118,6 @@ describe('MetaMask', function () { await driver.wait(until.stalenessOf(accountModal)) await driver.delay(regularDelayMs) }) - }) describe('provider listening for events', function () { @@ -110,7 +129,9 @@ describe('MetaMask', function () { await driver.openNewPage('http://127.0.0.1:8080/') await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.delay(regularDelayMs) @@ -118,15 +139,22 @@ describe('MetaMask', function () { const windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) - popup = windowHandles.find((handle) => handle !== extension && handle !== dapp) + dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) + popup = windowHandles.find( + (handle) => handle !== extension && handle !== dapp, + ) await driver.switchToWindow(popup) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//button[contains(text(), 'Next')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.waitUntilXWindowHandles(2) await driver.switchToWindow(dapp) diff --git a/test/e2e/fixture-server.js b/test/e2e/fixture-server.js index b96ba8e9a..7c0ea5a86 100644 --- a/test/e2e/fixture-server.js +++ b/test/e2e/fixture-server.js @@ -9,11 +9,9 @@ const FIXTURE_SERVER_HOST = 'localhost' const FIXTURE_SERVER_PORT = 12345 class FixtureServer { - constructor () { + constructor() { this._app = new Koa() - this._stateMap = new Map([ - [DEFAULT_STATE_KEY, Object.create(null)], - ]) + this._stateMap = new Map([[DEFAULT_STATE_KEY, Object.create(null)]]) this._initialStateCache = new Map() this._app.use(async (ctx) => { @@ -25,7 +23,7 @@ class FixtureServer { }) } - async start () { + async start() { const options = { host: FIXTURE_SERVER_HOST, port: FIXTURE_SERVER_PORT, @@ -39,7 +37,7 @@ class FixtureServer { }) } - async stop () { + async stop() { if (!this._server) { return } @@ -51,7 +49,7 @@ class FixtureServer { }) } - async loadState (directory) { + async loadState(directory) { const statePath = path.resolve(__dirname, directory, 'state.json') let state @@ -66,7 +64,7 @@ class FixtureServer { this._stateMap.set(CURRENT_STATE_KEY, state) } - _isStateRequest (ctx) { + _isStateRequest(ctx) { return ctx.method === 'GET' && ctx.path === '/state.json' } } diff --git a/test/e2e/from-import-ui.spec.js b/test/e2e/from-import-ui.spec.js index 70774b04f..ec3f68d42 100644 --- a/test/e2e/from-import-ui.spec.js +++ b/test/e2e/from-import-ui.spec.js @@ -3,10 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, Key, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -15,10 +12,13 @@ const ganacheServer = new Ganache() describe('Using MetaMask with an existing account', function () { let driver - const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' + const testSeedPhrase = + 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' const testAddress = '0x0Cc5261AB8cE458dc977078A3623E2BaDD27afD3' - const testPrivateKey2 = '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6' - const testPrivateKey3 = 'F4EC2590A0C10DE95FBF4547845178910E40F5035320C516A18C117DE02B5669' + const testPrivateKey2 = + '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6' + const testPrivateKey3 = + 'F4EC2590A0C10DE95FBF4547845178910E40F5035320C516A18C117DE02B5669' this.timeout(0) this.bail(true) @@ -27,7 +27,8 @@ describe('Using MetaMask with an existing account', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -41,7 +42,9 @@ describe('Using MetaMask with an existing account', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -58,12 +61,18 @@ describe('Using MetaMask with an existing account', function () { describe('First time flow starting from an existing seed phrase', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Import Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -73,36 +82,54 @@ describe('Using MetaMask with an existing account', function () { }) it('imports a seed phrase', async function () { - const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]')) + const [seedTextArea] = await driver.findElements( + By.css('input[placeholder="Paste seed phrase from clipboard"]'), + ) await seedTextArea.sendKeys(testSeedPhrase) await driver.delay(regularDelayMs) const [password] = await driver.findElements(By.id('password')) await password.sendKeys('correct horse battery staple') - const [confirmPassword] = await driver.findElements(By.id('confirm-password')) + const [confirmPassword] = await driver.findElements( + By.id('confirm-password'), + ) confirmPassword.sendKeys('correct horse battery staple') await driver.clickElement(By.css('.first-time-flow__terms')) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import')]`), + ) await driver.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) }) describe('Show account information', function () { it('shows the correct account address', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) await driver.findVisibleElement(By.css('.qr-code__wrapper')) await driver.delay(regularDelayMs) - const [address] = await driver.findElements(By.css('.readonly-input__input')) + const [address] = await driver.findElements( + By.css('.readonly-input__input'), + ) assert.equal(await address.getAttribute('value'), testAddress) await driver.clickElement(By.css('.account-modal__close')) @@ -110,8 +137,12 @@ describe('Using MetaMask with an existing account', function () { }) it('shows a QR code for the account', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) await driver.findVisibleElement(By.css('.qr-code__wrapper')) const detailModal = await driver.findElement(By.css('span .modal')) await driver.delay(regularDelayMs) @@ -127,7 +158,9 @@ describe('Using MetaMask with an existing account', function () { await driver.clickElement(By.css('.account-menu__icon .identicon')) await driver.delay(regularDelayMs) - const lockButton = await driver.findClickableElement(By.css('.account-menu__lock-button')) + const lockButton = await driver.findClickableElement( + By.css('.account-menu__lock-button'), + ) assert.equal(await lockButton.getText(), 'Lock') await lockButton.click() await driver.delay(regularDelayMs) @@ -146,7 +179,9 @@ describe('Using MetaMask with an existing account', function () { await driver.clickElement(By.css('.network-name')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//span[contains(text(), 'Localhost')]`)) + await driver.clickElement( + By.xpath(`//span[contains(text(), 'Localhost')]`), + ) await driver.delay(largeDelayMs) }) @@ -154,21 +189,29 @@ describe('Using MetaMask with an existing account', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//div[contains(text(), 'Create Account')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Create Account')]`), + ) await driver.delay(regularDelayMs) }) it('set account name', async function () { - const [accountName] = await driver.findElements(By.css('.new-account-create-form input')) + const [accountName] = await driver.findElements( + By.css('.new-account-create-form input'), + ) await accountName.sendKeys('2nd account') await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create')]`), + ) await driver.delay(regularDelayMs) }) it('should show the correct account name', async function () { - const accountName = await driver.findElement(By.css('.selected-account__name')) + const accountName = await driver.findElement( + By.css('.selected-account__name'), + ) assert.equal(await accountName.getText(), '2nd account') await driver.delay(regularDelayMs) }) @@ -189,7 +232,9 @@ describe('Using MetaMask with an existing account', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -210,20 +255,28 @@ describe('Using MetaMask with an existing account', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.clickElement(By.css('[data-testid="home__activity-tab"]')) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 1 }, 10000) - const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) assert.equal(txValues.length, 1) - assert.ok((/-1\s*ETH/u).test(await txValues[0].getText())) + assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())) }) }) @@ -232,20 +285,28 @@ describe('Using MetaMask with an existing account', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//div[contains(text(), 'Import Account')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Import Account')]`), + ) await driver.delay(regularDelayMs) }) it('enter private key', async function () { - const privateKeyInput = await driver.findElement(By.css('#private-key-box')) + const privateKeyInput = await driver.findElement( + By.css('#private-key-box'), + ) await privateKeyInput.sendKeys(testPrivateKey2) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import')]`), + ) await driver.delay(regularDelayMs) }) it('should show the correct account name', async function () { - const accountName = await driver.findElement(By.css('.selected-account__name')) + const accountName = await driver.findElement( + By.css('.selected-account__name'), + ) assert.equal(await accountName.getText(), 'Account 4') await driver.delay(regularDelayMs) }) @@ -255,76 +316,104 @@ describe('Using MetaMask with an existing account', function () { // confirm 4th account is account 4, as expected const accountMenuItemSelector = '.account-menu__account:nth-child(4)' - const accountName = await driver.findElement(By.css(`${accountMenuItemSelector} .account-menu__name`)) + const accountName = await driver.findElement( + By.css(`${accountMenuItemSelector} .account-menu__name`), + ) assert.equal(await accountName.getText(), 'Account 4') // confirm label is present on the same menu item - const importedLabel = await driver.findElement(By.css(`${accountMenuItemSelector} .keyring-label`)) + const importedLabel = await driver.findElement( + By.css(`${accountMenuItemSelector} .keyring-label`), + ) assert.equal(await importedLabel.getText(), 'IMPORTED') }) }) describe('Imports and removes an account', function () { it('choose Create Account from the account menu', async function () { - await driver.clickElement(By.xpath(`//div[contains(text(), 'Import Account')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Import Account')]`), + ) await driver.delay(regularDelayMs) }) it('enter private key', async function () { - const privateKeyInput = await driver.findElement(By.css('#private-key-box')) + const privateKeyInput = await driver.findElement( + By.css('#private-key-box'), + ) await privateKeyInput.sendKeys(testPrivateKey3) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import')]`), + ) await driver.delay(regularDelayMs) }) it('should see new account in account menu', async function () { - const accountName = await driver.findElement(By.css('.selected-account__name')) + const accountName = await driver.findElement( + By.css('.selected-account__name'), + ) assert.equal(await accountName.getText(), 'Account 5') await driver.delay(regularDelayMs) await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - const accountListItems = await driver.findElements(By.css('.account-menu__account')) + const accountListItems = await driver.findElements( + By.css('.account-menu__account'), + ) assert.equal(accountListItems.length, 5) await driver.clickPoint(By.css('.account-menu__icon'), 0, 0) }) it('should open the remove account modal', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) - await driver.clickElement(By.css('[data-testid="account-options-menu__remove-account"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu__remove-account"]'), + ) await driver.findElement(By.css('.confirm-remove-account__account')) }) it('should remove the account', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Remove')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Remove')]`), + ) await driver.delay(regularDelayMs) - const accountName = await driver.findElement(By.css('.selected-account__name')) + const accountName = await driver.findElement( + By.css('.selected-account__name'), + ) assert.equal(await accountName.getText(), 'Account 1') await driver.delay(regularDelayMs) await driver.clickElement(By.css('.account-menu__icon')) - const accountListItems = await driver.findElements(By.css('.account-menu__account')) + const accountListItems = await driver.findElements( + By.css('.account-menu__account'), + ) assert.equal(accountListItems.length, 4) }) }) describe('Connects to a Hardware wallet', function () { it('choose Connect Hardware Wallet from the account menu', async function () { - await driver.clickElement(By.xpath(`//div[contains(text(), 'Connect Hardware Wallet')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Connect Hardware Wallet')]`), + ) await driver.delay(regularDelayMs) }) it('should open the TREZOR Connect popup', async function () { await driver.clickElement(By.css('.hw-connect__btn:nth-of-type(2)')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.delay(regularDelayMs) const allWindows = await driver.getAllWindowHandles() assert.equal(allWindows.length, 2) diff --git a/test/e2e/ganache.js b/test/e2e/ganache.js index 99ea7374c..279473766 100644 --- a/test/e2e/ganache.js +++ b/test/e2e/ganache.js @@ -4,13 +4,14 @@ const ganache = require('ganache-core') const defaultOptions = { blockTime: 2, network_id: 1337, - mnemonic: 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent', + mnemonic: + 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent', port: 8545, vmErrorsOnRPCResponse: false, } class Ganache { - async start (opts) { + async start(opts) { const options = { ...defaultOptions, ...opts } const { port } = options this._server = ganache.server(options) @@ -24,7 +25,7 @@ class Ganache { } } - async quit () { + async quit() { if (!this._server) { throw new Error('Server not running yet') } diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 26047550d..9e6aa2f9f 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -10,7 +10,7 @@ const largeDelayMs = regularDelayMs * 2 const dappPort = 8080 -async function withFixtures (options, testSuite) { +async function withFixtures(options, testSuite) { const { dapp, fixtures, ganacheOptions, driverOptions, title } = options const fixtureServer = new FixtureServer() const ganacheServer = new Ganache() @@ -22,7 +22,15 @@ async function withFixtures (options, testSuite) { await fixtureServer.start() await fixtureServer.loadState(path.join(__dirname, 'fixtures', fixtures)) if (dapp) { - const dappDirectory = path.resolve(__dirname, '..', '..', 'node_modules', '@metamask', 'test-dapp', 'dist') + const dappDirectory = path.resolve( + __dirname, + '..', + '..', + 'node_modules', + '@metamask', + 'test-dapp', + 'dist', + ) dappServer = createStaticServer(dappDirectory) dappServer.listen(dappPort) await new Promise((resolve, reject) => { @@ -41,7 +49,9 @@ async function withFixtures (options, testSuite) { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` throw new Error(errorMessage) } } diff --git a/test/e2e/incremental-security.spec.js b/test/e2e/incremental-security.spec.js index 6b76bae12..ca204baaf 100644 --- a/test/e2e/incremental-security.spec.js +++ b/test/e2e/incremental-security.spec.js @@ -3,11 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - tinyDelayMs, - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -24,11 +20,13 @@ describe('MetaMask', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x250F458997A364988956409A164BA4E16F0F99F916ACDD73ADCD3A1DE30CF8D1', + secretKey: + '0x250F458997A364988956409A164BA4E16F0F99F916ACDD73ADCD3A1DE30CF8D1', balance: 0, }, { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -42,7 +40,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -59,12 +59,18 @@ describe('MetaMask', function () { describe('Going through the first time flow, but skipping the seed phrase challenge', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create a Wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -74,8 +80,12 @@ describe('MetaMask', function () { }) it('accepts a secure password', async function () { - const passwordBox = await driver.findElement(By.css('.first-time-flow__form #create-password')) - const passwordBoxConfirm = await driver.findElement(By.css('.first-time-flow__form #confirm-password')) + const passwordBox = await driver.findElement( + By.css('.first-time-flow__form #create-password'), + ) + const passwordBoxConfirm = await driver.findElement( + By.css('.first-time-flow__form #confirm-password'), + ) await passwordBox.sendKeys('correct horse battery staple') await passwordBoxConfirm.sendKeys('correct horse battery staple') @@ -87,15 +97,25 @@ describe('MetaMask', function () { }) it('skips the seed phrase challenge', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`, + ), + ) await driver.delay(regularDelayMs) - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) }) it('gets the current accounts address', async function () { - const addressInput = await driver.findElement(By.css('.readonly-input__input')) + const addressInput = await driver.findElement( + By.css('.readonly-input__input'), + ) publicAddress = await addressInput.getAttribute('value') const accountModal = await driver.findElement(By.css('span .modal')) @@ -105,7 +125,6 @@ describe('MetaMask', function () { await driver.wait(until.stalenessOf(accountModal)) await driver.delay(regularDelayMs) }) - }) describe('send to current account from dapp with different provider', function () { @@ -135,7 +154,9 @@ describe('MetaMask', function () { }) it('should have the correct amount of eth', async function () { - const balances = await driver.findElements(By.css('.currency-display-component__text')) + const balances = await driver.findElements( + By.css('.currency-display-component__text'), + ) await driver.wait(until.elementTextMatches(balances[0], /1/u), 15000) const balance = await balances[0].getText() @@ -145,7 +166,11 @@ describe('MetaMask', function () { describe('backs up the seed phrase', function () { it('should show a backup reminder', async function () { - const backupReminder = await driver.findElements(By.xpath("//div[contains(@class, 'home-notification__text') and contains(text(), 'Backup your Secret Recovery code to keep your wallet and funds secure')]")) + const backupReminder = await driver.findElements( + By.xpath( + "//div[contains(@class, 'home-notification__text') and contains(text(), 'Backup your Secret Recovery code to keep your wallet and funds secure')]", + ), + ) assert.equal(backupReminder.length, 1) }) @@ -157,21 +182,33 @@ describe('MetaMask', function () { let seedPhrase it('reveals the seed phrase', async function () { - const byRevealButton = By.css('.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button') + const byRevealButton = By.css( + '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', + ) await driver.clickElement(byRevealButton) await driver.delay(regularDelayMs) - const revealedSeedPhrase = await driver.findElement(By.css('.reveal-seed-phrase__secret-words')) + const revealedSeedPhrase = await driver.findElement( + By.css('.reveal-seed-phrase__secret-words'), + ) seedPhrase = await revealedSeedPhrase.getText() assert.equal(seedPhrase.split(' ').length, 12) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.next.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.next.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) - async function clickWordAndWait (word) { - await driver.clickElement(By.css(`[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`)) + async function clickWordAndWait(word) { + await driver.clickElement( + By.css( + `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, + ), + ) await driver.delay(tinyDelayMs) } @@ -182,17 +219,23 @@ describe('MetaMask', function () { await clickWordAndWait(word) } - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('can click through the success screen', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'All Done')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'All Done')]`), + ) await driver.delay(regularDelayMs) }) it('should have the correct amount of eth', async function () { - const balances = await driver.findElements(By.css('.currency-display-component__text')) + const balances = await driver.findElements( + By.css('.currency-display-component__text'), + ) await driver.wait(until.elementTextMatches(balances[0], /1/u), 15000) const balance = await balances[0].getText() diff --git a/test/e2e/metamask-responsive-ui.spec.js b/test/e2e/metamask-responsive-ui.spec.js index a4b7e92c9..a3cc26db4 100644 --- a/test/e2e/metamask-responsive-ui.spec.js +++ b/test/e2e/metamask-responsive-ui.spec.js @@ -3,11 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - tinyDelayMs, - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -16,7 +12,8 @@ const ganacheServer = new Ganache() describe('MetaMask', function () { let driver - const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' + const testSeedPhrase = + 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' this.timeout(0) this.bail(true) @@ -32,7 +29,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -49,12 +48,18 @@ describe('MetaMask', function () { describe('Going through the first time flow', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create a Wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -64,8 +69,12 @@ describe('MetaMask', function () { }) it('accepts a secure password', async function () { - const passwordBox = await driver.findElement(By.css('.first-time-flow__form #create-password')) - const passwordBoxConfirm = await driver.findElement(By.css('.first-time-flow__form #confirm-password')) + const passwordBox = await driver.findElement( + By.css('.first-time-flow__form #create-password'), + ) + const passwordBoxConfirm = await driver.findElement( + By.css('.first-time-flow__form #confirm-password'), + ) await passwordBox.sendKeys('correct horse battery staple') await passwordBoxConfirm.sendKeys('correct horse battery staple') @@ -79,21 +88,33 @@ describe('MetaMask', function () { let seedPhrase it('reveals the seed phrase', async function () { - const byRevealButton = By.css('.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button') + const byRevealButton = By.css( + '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', + ) await driver.clickElement(byRevealButton) await driver.delay(regularDelayMs) - const revealedSeedPhrase = await driver.findElement(By.css('.reveal-seed-phrase__secret-words')) + const revealedSeedPhrase = await driver.findElement( + By.css('.reveal-seed-phrase__secret-words'), + ) seedPhrase = await revealedSeedPhrase.getText() assert.equal(seedPhrase.split(' ').length, 12) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.next.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.next.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) - async function clickWordAndWait (word) { - await driver.clickElement(By.css(`[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`)) + async function clickWordAndWait(word) { + await driver.clickElement( + By.css( + `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, + ), + ) await driver.delay(tinyDelayMs) } @@ -104,21 +125,33 @@ describe('MetaMask', function () { await clickWordAndWait(word) } - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) }) describe('Show account information', function () { it('show account details dropdown menu', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - const options = await driver.findElements(By.css('.account-options-menu .menu-item')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + const options = await driver.findElements( + By.css('.account-options-menu .menu-item'), + ) assert.equal(options.length, 3) // HD Wallet type does not have to show the Remove Account option // click outside of menu to dismiss // account menu button chosen because the menu never covers it. @@ -132,15 +165,22 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - const lockButton = await driver.findClickableElement(By.css('.account-menu__lock-button')) + const lockButton = await driver.findClickableElement( + By.css('.account-menu__lock-button'), + ) assert.equal(await lockButton.getText(), 'Lock') await lockButton.click() await driver.delay(regularDelayMs) }) it('imports seed phrase', async function () { - const restoreSeedLink = await driver.findClickableElement(By.css('.unlock-page__link--import')) - assert.equal(await restoreSeedLink.getText(), 'Import using account seed phrase') + const restoreSeedLink = await driver.findClickableElement( + By.css('.unlock-page__link--import'), + ) + assert.equal( + await restoreSeedLink.getText(), + 'Import using account seed phrase', + ) await restoreSeedLink.click() await driver.delay(regularDelayMs) @@ -155,7 +195,11 @@ describe('MetaMask', function () { await passwordInputs[0].sendKeys('correct horse battery staple') await passwordInputs[1].sendKeys('correct horse battery staple') - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.restore.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.restore.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) @@ -163,12 +207,16 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.network-name')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//span[contains(text(), 'Localhost')]`)) + await driver.clickElement( + By.xpath(`//span[contains(text(), 'Localhost')]`), + ) await driver.delay(largeDelayMs * 2) }) it('balance renders', async function () { - const balance = await driver.findElement(By.css('[data-testid="eth-overview__primary-currency"]')) + const balance = await driver.findElement( + By.css('[data-testid="eth-overview__primary-currency"]'), + ) await driver.wait(until.elementTextMatches(balance, /100\s*ETH/u)) await driver.delay(regularDelayMs) }) @@ -179,7 +227,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -209,17 +259,25 @@ describe('MetaMask', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) }) it('finds the transaction in the transactions list', async function () { await driver.clickElement(By.css('[data-testid="home__activity-tab"]')) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 1 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000) }) }) diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index 4ef3b056f..32ad702b3 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -3,11 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, Key, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - tinyDelayMs, - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -17,7 +13,8 @@ describe('MetaMask', function () { let driver let tokenAddress - const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' + const testSeedPhrase = + 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' this.timeout(0) this.bail(true) @@ -33,7 +30,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -50,12 +49,18 @@ describe('MetaMask', function () { describe('Going through the first time flow', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create a Wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -65,8 +70,12 @@ describe('MetaMask', function () { }) it('accepts a secure password', async function () { - const passwordBox = await driver.findElement(By.css('.first-time-flow__form #create-password')) - const passwordBoxConfirm = await driver.findElement(By.css('.first-time-flow__form #confirm-password')) + const passwordBox = await driver.findElement( + By.css('.first-time-flow__form #create-password'), + ) + const passwordBoxConfirm = await driver.findElement( + By.css('.first-time-flow__form #confirm-password'), + ) await passwordBox.sendKeys('correct horse battery staple') await passwordBoxConfirm.sendKeys('correct horse battery staple') @@ -80,22 +89,34 @@ describe('MetaMask', function () { let seedPhrase it('reveals the seed phrase', async function () { - const byRevealButton = By.css('.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button') + const byRevealButton = By.css( + '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', + ) await driver.findElement(byRevealButton) await driver.clickElement(byRevealButton) await driver.delay(regularDelayMs) - const revealedSeedPhrase = await driver.findElement(By.css('.reveal-seed-phrase__secret-words')) + const revealedSeedPhrase = await driver.findElement( + By.css('.reveal-seed-phrase__secret-words'), + ) seedPhrase = await revealedSeedPhrase.getText() assert.equal(seedPhrase.split(' ').length, 12) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.next.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.next.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) - async function clickWordAndWait (word) { - await driver.clickElement(By.css(`[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`)) + async function clickWordAndWait(word) { + await driver.clickElement( + By.css( + `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, + ), + ) await driver.delay(tinyDelayMs) } @@ -106,21 +127,33 @@ describe('MetaMask', function () { await clickWordAndWait(word) } - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) }) describe('Show account information', function () { it('shows the QR code for the account', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) await driver.findVisibleElement(By.css('.qr-code__wrapper')) await driver.delay(regularDelayMs) @@ -137,7 +170,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - const lockButton = await driver.findClickableElement(By.css('.account-menu__lock-button')) + const lockButton = await driver.findClickableElement( + By.css('.account-menu__lock-button'), + ) assert.equal(await lockButton.getText(), 'Lock') await lockButton.click() await driver.delay(regularDelayMs) @@ -156,21 +191,29 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//div[contains(text(), 'Create Account')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Create Account')]`), + ) await driver.delay(regularDelayMs) }) it('set account name', async function () { - const accountName = await driver.findElement(By.css('.new-account-create-form input')) + const accountName = await driver.findElement( + By.css('.new-account-create-form input'), + ) await accountName.sendKeys('2nd account') await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create')]`), + ) await driver.delay(largeDelayMs) }) it('should display correct account name', async function () { - const accountName = await driver.findElement(By.css('.selected-account__name')) + const accountName = await driver.findElement( + By.css('.selected-account__name'), + ) assert.equal(await accountName.getText(), '2nd account') await driver.delay(regularDelayMs) }) @@ -181,15 +224,22 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - const lockButton = await driver.findClickableElement(By.css('.account-menu__lock-button')) + const lockButton = await driver.findClickableElement( + By.css('.account-menu__lock-button'), + ) assert.equal(await lockButton.getText(), 'Lock') await lockButton.click() await driver.delay(regularDelayMs) }) it('imports seed phrase', async function () { - const restoreSeedLink = await driver.findClickableElement(By.css('.unlock-page__link--import')) - assert.equal(await restoreSeedLink.getText(), 'Import using account seed phrase') + const restoreSeedLink = await driver.findClickableElement( + By.css('.unlock-page__link--import'), + ) + assert.equal( + await restoreSeedLink.getText(), + 'Import using account seed phrase', + ) await restoreSeedLink.click() await driver.delay(regularDelayMs) @@ -204,12 +254,18 @@ describe('MetaMask', function () { await passwordInputs[0].sendKeys('correct horse battery staple') await passwordInputs[1].sendKeys('correct horse battery staple') - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.restore.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.restore.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) it('balance renders', async function () { - const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) + const balance = await driver.findElement( + By.css('[data-testid="wallet-balance"] .list-item__heading'), + ) await driver.wait(until.elementTextMatches(balance, /100\s*ETH/u)) await driver.delay(regularDelayMs) }) @@ -220,14 +276,22 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) await inputAmount.sendKeys('1000') - const errorAmount = await driver.findElement(By.css('.send-v2__error-amount')) - assert.equal(await errorAmount.getText(), 'Insufficient funds.', 'send screen should render an insufficient fund error message') + const errorAmount = await driver.findElement( + By.css('.send-v2__error-amount'), + ) + assert.equal( + await errorAmount.getText(), + 'Insufficient funds.', + 'send screen should render an insufficient fund error message', + ) await inputAmount.sendKeys(Key.BACK_SPACE) await driver.delay(50) @@ -238,7 +302,9 @@ describe('MetaMask', function () { await driver.assertElementNotPresent(By.css('.send-v2__error-amount')) - const amountMax = await driver.findClickableElement(By.css('.send-v2__amount-max')) + const amountMax = await driver.findClickableElement( + By.css('.send-v2__amount-max'), + ) await amountMax.click() assert.equal(await inputAmount.isEnabled(), false) @@ -263,18 +329,26 @@ describe('MetaMask', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs * 2) }) it('finds the transaction in the transactions list', async function () { await driver.clickElement(By.css('[data-testid="home__activity-tab"]')) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 1 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000) }) }) @@ -284,7 +358,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -294,7 +370,9 @@ describe('MetaMask', function () { assert.equal(inputValue, '1') // Set the gas price - await driver.clickElement(By.xpath(`//button/div/div[contains(text(), "Fast")]`)) + await driver.clickElement( + By.xpath(`//button/div/div[contains(text(), "Fast")]`), + ) await driver.delay(regularDelayMs) // Continue to next screen @@ -303,17 +381,25 @@ describe('MetaMask', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 2 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000) }) }) @@ -323,7 +409,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -347,21 +435,31 @@ describe('MetaMask', function () { }) it('confirms the transaction', async function () { - const transactionAmounts = await driver.findElements(By.css('.currency-display-component__text')) + const transactionAmounts = await driver.findElements( + By.css('.currency-display-component__text'), + ) const transactionAmount = transactionAmounts[0] assert.equal(await transactionAmount.getText(), '1') - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 3 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000) }) }) @@ -383,12 +481,22 @@ describe('MetaMask', function () { await driver.clickElement(By.xpath(`//div[contains(text(), 'Advanced')]`)) await driver.delay(regularDelayMs) - await driver.clickElement(By.css('[data-testid="advanced-setting-show-testnet-conversion"] .settings-page__content-item-col > div > div')) + await driver.clickElement( + By.css( + '[data-testid="advanced-setting-show-testnet-conversion"] .settings-page__content-item-col > div > div', + ), + ) - const advancedGasTitle = await driver.findElement(By.xpath(`//span[contains(text(), 'Advanced gas controls')]`)) + const advancedGasTitle = await driver.findElement( + By.xpath(`//span[contains(text(), 'Advanced gas controls')]`), + ) await driver.scrollToElement(advancedGasTitle) - await driver.clickElement(By.css('[data-testid="advanced-setting-advanced-gas-inline"] .settings-page__content-item-col > div > div')) + await driver.clickElement( + By.css( + '[data-testid="advanced-setting-advanced-gas-inline"] .settings-page__content-item-col > div > div', + ), + ) windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] await driver.closeAllWindowHandlesExcept([extension]) @@ -402,7 +510,9 @@ describe('MetaMask', function () { await driver.openNewPage('http://127.0.0.1:8080/') await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.delay(regularDelayMs) @@ -410,15 +520,22 @@ describe('MetaMask', function () { windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) - popup = windowHandles.find((handle) => handle !== extension && handle !== dapp) + dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) + popup = windowHandles.find( + (handle) => handle !== extension && handle !== dapp, + ) await driver.switchToWindow(popup) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//button[contains(text(), 'Next')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.waitUntilXWindowHandles(2) await driver.switchToWindow(dapp) @@ -426,16 +543,26 @@ describe('MetaMask', function () { }) it('initiates a send from the dapp', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Send')]`), 10000) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Send')]`), + 10000, + ) await driver.delay(2000) windowHandles = await driver.getAllWindowHandles() - await driver.switchToWindowWithTitle('MetaMask Notification', windowHandles) + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ) await driver.delay(regularDelayMs) - await driver.assertElementNotPresent(By.xpath(`//li[contains(text(), 'Data')]`)) + await driver.assertElementNotPresent( + By.xpath(`//li[contains(text(), 'Data')]`), + ) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) await gasPriceInput.clear() await driver.delay(50) @@ -450,7 +577,10 @@ describe('MetaMask', function () { await driver.delay(1000) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`), 10000) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + 10000, + ) await driver.delay(regularDelayMs) await driver.waitUntilXWindowHandles(2) @@ -460,19 +590,31 @@ describe('MetaMask', function () { it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 4 }, 10000) - const txValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) + const txValue = await driver.findClickableElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValue, /-3\s*ETH/u), 10000) }) it('the transaction has the expected gas price', async function () { - const txValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) + const txValue = await driver.findClickableElement( + By.css('.transaction-list-item__primary-currency'), + ) await txValue.click() - const popoverCloseButton = await driver.findClickableElement(By.css('.popover-header__button')) - const txGasPrice = await driver.findElement(By.css('[data-testid="transaction-breakdown__gas-price"]')) + const popoverCloseButton = await driver.findClickableElement( + By.css('.popover-header__button'), + ) + const txGasPrice = await driver.findElement( + By.css('[data-testid="transaction-breakdown__gas-price"]'), + ) await driver.wait(until.elementTextMatches(txGasPrice, /^10$/u), 10000) await popoverCloseButton.click() }) @@ -490,11 +632,15 @@ describe('MetaMask', function () { await driver.switchToWindow(dapp) await driver.delay(largeDelayMs) - const send3eth = await driver.findClickableElement(By.xpath(`//button[contains(text(), 'Send')]`)) + const send3eth = await driver.findClickableElement( + By.xpath(`//button[contains(text(), 'Send')]`), + ) await send3eth.click() await driver.delay(largeDelayMs) - const contractDeployment = await driver.findClickableElement(By.xpath(`//button[contains(text(), 'Deploy Contract')]`)) + const contractDeployment = await driver.findClickableElement( + By.xpath(`//button[contains(text(), 'Deploy Contract')]`), + ) await contractDeployment.click() await driver.delay(largeDelayMs) @@ -512,45 +658,93 @@ describe('MetaMask', function () { it('navigates the transactions', async function () { await driver.clickElement(By.css('[data-testid="next-page"]')) - let navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + let navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) let navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('2'), true, 'changed transaction right') + assert.equal( + navigationText.includes('2'), + true, + 'changed transaction right', + ) await driver.clickElement(By.css('[data-testid="next-page"]')) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('3'), true, 'changed transaction right') + assert.equal( + navigationText.includes('3'), + true, + 'changed transaction right', + ) await driver.clickElement(By.css('[data-testid="next-page"]')) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('4'), true, 'changed transaction right') + assert.equal( + navigationText.includes('4'), + true, + 'changed transaction right', + ) await driver.clickElement(By.css('[data-testid="first-page"]')) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('1'), true, 'navigate to first transaction') + assert.equal( + navigationText.includes('1'), + true, + 'navigate to first transaction', + ) await driver.clickElement(By.css('[data-testid="last-page"]')) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.split('4').length, 3, 'navigate to last transaction') + assert.equal( + navigationText.split('4').length, + 3, + 'navigate to last transaction', + ) await driver.clickElement(By.css('[data-testid="previous-page"]')) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('3'), true, 'changed transaction left') + assert.equal( + navigationText.includes('3'), + true, + 'changed transaction left', + ) await driver.clickElement(By.css('[data-testid="previous-page"]')) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('2'), true, 'changed transaction left') + assert.equal( + navigationText.includes('2'), + true, + 'changed transaction left', + ) }) it('adds a transaction while confirm screen is in focus', async function () { - let navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + let navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) let navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('2'), true, 'second transaction in focus') + assert.equal( + navigationText.includes('2'), + true, + 'second transaction in focus', + ) const windowHandles = await driver.getAllWindowHandles() const extension = windowHandles[0] @@ -565,17 +759,27 @@ describe('MetaMask', function () { await driver.switchToWindow(extension) await driver.delay(regularDelayMs) - navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) navigationText = await navigationElement.getText() - assert.equal(navigationText.includes('2'), true, 'correct (same) transaction in focus') + assert.equal( + navigationText.includes('2'), + true, + 'correct (same) transaction in focus', + ) }) it('rejects a transaction', async function () { await driver.delay(tinyDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Reject')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Reject')]`), + ) await driver.delay(largeDelayMs * 2) - const navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + const navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) await driver.delay(tinyDelayMs) const navigationText = await navigationElement.getText() assert.equal(navigationText.includes('4'), true, 'transaction rejected') @@ -583,10 +787,14 @@ describe('MetaMask', function () { it('confirms a transaction', async function () { await driver.delay(tinyDelayMs / 2) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) - const navigationElement = await driver.findElement(By.css('.confirm-page-container-navigation')) + const navigationElement = await driver.findElement( + By.css('.confirm-page-container-navigation'), + ) await driver.delay(tinyDelayMs / 2) const navigationText = await navigationElement.getText() await driver.delay(tinyDelayMs / 2) @@ -597,11 +805,17 @@ describe('MetaMask', function () { await driver.clickElement(By.xpath(`//a[contains(text(), 'Reject 3')]`)) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Reject All')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Reject All')]`), + ) await driver.delay(largeDelayMs * 2) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 5 }, 10000) }) @@ -625,7 +839,9 @@ describe('MetaMask', function () { await driver.switchToWindow(extension) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//h2[contains(text(), 'Contract Deployment')]`)) + await driver.clickElement( + By.xpath(`//h2[contains(text(), 'Contract Deployment')]`), + ) await driver.delay(largeDelayMs) }) @@ -635,7 +851,9 @@ describe('MetaMask', function () { await driver.findElement(By.xpath(`//div[contains(text(), '127.0.0.1')]`)) - const confirmDataDiv = await driver.findElement(By.css('.confirm-page-container-content__data-box')) + const confirmDataDiv = await driver.findElement( + By.css('.confirm-page-container-content__data-box'), + ) const confirmDataText = await confirmDataDiv.getText() assert.ok(confirmDataText.includes('Origin:')) assert.ok(confirmDataText.includes('127.0.0.1')) @@ -647,16 +865,25 @@ describe('MetaMask', function () { }) it('confirms a deploy contract transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 6 }, 10000) const txAction = await driver.findElements(By.css('.list-item__heading')) - await driver.wait(until.elementTextMatches(txAction[0], /Contract\sDeployment/u), 10000) + await driver.wait( + until.elementTextMatches(txAction[0], /Contract\sDeployment/u), + 10000, + ) await driver.delay(regularDelayMs) }) @@ -665,25 +892,38 @@ describe('MetaMask', function () { await driver.delay(regularDelayMs) let contractStatus = await driver.findElement(By.css('#contractStatus')) - await driver.wait(until.elementTextMatches(contractStatus, /Deployed/u), 15000) + await driver.wait( + until.elementTextMatches(contractStatus, /Deployed/u), + 15000, + ) await driver.clickElement(By.css('#depositButton')) await driver.delay(largeDelayMs) contractStatus = await driver.findElement(By.css('#contractStatus')) - await driver.wait(until.elementTextMatches(contractStatus, /Deposit\sinitiated/u), 10000) + await driver.wait( + until.elementTextMatches(contractStatus, /Deposit\sinitiated/u), + 10000, + ) await driver.switchToWindow(extension) await driver.delay(largeDelayMs * 2) await driver.findElements(By.css('.transaction-list-item--unconfirmed')) - const txListValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) - await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/u), 10000) + const txListValue = await driver.findClickableElement( + By.css('.transaction-list-item__primary-currency'), + ) + await driver.wait( + until.elementTextMatches(txListValue, /-4\s*ETH/u), + 10000, + ) await txListValue.click() await driver.delay(regularDelayMs) // Set the gas limit - await driver.clickElement(By.css('.confirm-detail-row__header-text--edit')) + await driver.clickElement( + By.css('.confirm-detail-row__header-text--edit'), + ) await driver.delay(regularDelayMs) const gasModal = await driver.findElement(By.css('span .modal')) @@ -691,7 +931,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.page-container__tab:nth-of-type(2)')) await driver.delay(regularDelayMs) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) const gasLimitValue = await gasLimitInput.getAttribute('value') assert(Number(gasLimitValue) < 100000, 'Gas Limit too high') @@ -711,16 +953,27 @@ describe('MetaMask', function () { await driver.wait(until.stalenessOf(gasModal)) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 7 }, 10000) - const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) - await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/u), 10000) + const txValues = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) + await driver.wait( + until.elementTextMatches(txValues[0], /-4\s*ETH/u), + 10000, + ) }) it('calls and confirms a contract method where ETH is received', async function () { @@ -733,18 +986,30 @@ describe('MetaMask', function () { await driver.switchToWindow(extension) await driver.delay(largeDelayMs * 2) - await driver.clickElement(By.css('.transaction-list__pending-transactions .transaction-list-item')) + await driver.clickElement( + By.css( + '.transaction-list__pending-transactions .transaction-list-item', + ), + ) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 8 }, 10000) - const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElement( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/u), 10000) await driver.closeAllWindowHandlesExcept([extension, dapp]) @@ -752,11 +1017,16 @@ describe('MetaMask', function () { }) it('renders the correct ETH balance', async function () { - const balance = await driver.findElement(By.css('[data-testid="eth-overview__primary-currency"]')) + const balance = await driver.findElement( + By.css('[data-testid="eth-overview__primary-currency"]'), + ) await driver.delay(regularDelayMs) - await driver.wait(until.elementTextMatches(balance, /^87.*\s*ETH.*$/u), 10000) + await driver.wait( + until.elementTextMatches(balance, /^87.*\s*ETH.*$/u), + 10000, + ) const tokenAmount = await balance.getText() - assert.ok((/^87.*\s*ETH.*$/u).test(tokenAmount)) + assert.ok(/^87.*\s*ETH.*$/u.test(tokenAmount)) await driver.delay(regularDelayMs) }) }) @@ -771,33 +1041,43 @@ describe('MetaMask', function () { await driver.switchToWindow(dapp) await driver.delay(regularDelayMs * 2) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create Token')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create Token')]`), + ) windowHandles = await driver.waitUntilXWindowHandles(3) const popup = windowHandles[2] await driver.switchToWindow(popup) await driver.delay(regularDelayMs) - await driver.clickElement(By.css('.confirm-detail-row__header-text--edit')) + await driver.clickElement( + By.css('.confirm-detail-row__header-text--edit'), + ) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//li[contains(text(), 'Advanced')]`)) await driver.delay(tinyDelayMs) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) assert(gasPriceInput.getAttribute('value'), 20) assert(gasLimitInput.getAttribute('value'), 4700000) await driver.clickElement(By.xpath(`//button[contains(text(), 'Save')]`)) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) await driver.switchToWindow(dapp) await driver.delay(tinyDelayMs) - const tokenContractAddress = await driver.findElement(By.css('#tokenAddress')) + const tokenContractAddress = await driver.findElement( + By.css('#tokenAddress'), + ) await driver.wait(until.elementTextMatches(tokenContractAddress, /0x/u)) tokenAddress = await tokenContractAddress.getText() @@ -810,30 +1090,40 @@ describe('MetaMask', function () { it('clicks on the Add Token button', async function () { await driver.clickElement(By.css(`[data-testid="home__asset-tab"]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Add Token')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Add Token')]`), + ) await driver.delay(regularDelayMs) }) it('picks the newly created Test token', async function () { - await driver.clickElement(By.xpath("//li[contains(text(), 'Custom Token')]")) + await driver.clickElement( + By.xpath("//li[contains(text(), 'Custom Token')]"), + ) await driver.delay(regularDelayMs) - const newTokenAddress = await driver.findElement(By.css('#custom-address')) + const newTokenAddress = await driver.findElement( + By.css('#custom-address'), + ) await newTokenAddress.sendKeys(tokenAddress) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//button[contains(text(), 'Next')]`)) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Add Tokens')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Add Tokens')]`), + ) await driver.delay(regularDelayMs) }) it('renders the balance for the new token', async function () { - const balance = await driver.findElement(By.css('.wallet-overview .token-overview__primary-balance')) + const balance = await driver.findElement( + By.css('.wallet-overview .token-overview__primary-balance'), + ) await driver.wait(until.elementTextMatches(balance, /^10\s*TST\s*$/u)) const tokenAmount = await balance.getText() - assert.ok((/^10\s*TST\s*$/u).test(tokenAmount)) + assert.ok(/^10\s*TST\s*$/u.test(tokenAmount)) await driver.delay(regularDelayMs) }) }) @@ -844,7 +1134,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -876,41 +1168,67 @@ describe('MetaMask', function () { await driver.clickElement(By.xpath(`//li[contains(text(), 'Data')]`)) await driver.delay(regularDelayMs) - const functionType = await driver.findElement(By.css('.confirm-page-container-content__function-type')) + const functionType = await driver.findElement( + By.css('.confirm-page-container-content__function-type'), + ) const functionTypeText = await functionType.getText() assert.equal(functionTypeText, 'Transfer') - const tokenAmount = await driver.findElement(By.css('.confirm-page-container-summary__title-text')) + const tokenAmount = await driver.findElement( + By.css('.confirm-page-container-summary__title-text'), + ) const tokenAmountText = await tokenAmount.getText() assert.equal(tokenAmountText, '1 TST') - const confirmDataDiv = await driver.findElement(By.css('.confirm-page-container-content__data-box')) + const confirmDataDiv = await driver.findElement( + By.css('.confirm-page-container-content__data-box'), + ) const confirmDataText = await confirmDataDiv.getText() await driver.delay(regularDelayMs) - assert(confirmDataText.match(/0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/u)) + assert( + confirmDataText.match( + /0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/u, + ), + ) await driver.clickElement(By.xpath(`//li[contains(text(), 'Details')]`)) await driver.delay(regularDelayMs) }) it('submits the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 1 }, 10000) - const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) assert.equal(txValues.length, 1) - await driver.wait(until.elementTextMatches(txValues[0], /-1\s*TST/u), 10000) + await driver.wait( + until.elementTextMatches(txValues[0], /-1\s*TST/u), + 10000, + ) - const txStatuses = await driver.findElements(By.css('.list-item__heading')) - await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/u), 10000) + const txStatuses = await driver.findElements( + By.css('.list-item__heading'), + ) + await driver.wait( + until.elementTextMatches(txStatuses[0], /Send\sTST/u), + 10000, + ) }) }) @@ -919,29 +1237,45 @@ describe('MetaMask', function () { it('sends an already created token', async function () { const windowHandles = await driver.getAllWindowHandles() const extension = windowHandles[0] - const dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) + const dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) await driver.delay(regularDelayMs) await driver.switchToWindow(dapp) await driver.delay(tinyDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Transfer Tokens')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Transfer Tokens')]`), + ) await driver.switchToWindow(extension) await driver.delay(largeDelayMs) - await driver.findElements(By.css('.transaction-list__pending-transactions')) - const txListValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) - await driver.wait(until.elementTextMatches(txListValue, /-1.5\s*TST/u), 10000) + await driver.findElements( + By.css('.transaction-list__pending-transactions'), + ) + const txListValue = await driver.findClickableElement( + By.css('.transaction-list-item__primary-currency'), + ) + await driver.wait( + until.elementTextMatches(txListValue, /-1.5\s*TST/u), + 10000, + ) await txListValue.click() await driver.delay(regularDelayMs) - const transactionAmounts = await driver.findElements(By.css('.currency-display-component__text')) + const transactionAmounts = await driver.findElements( + By.css('.currency-display-component__text'), + ) const transactionAmount = transactionAmounts[0] assert(await transactionAmount.getText(), '1.5 TST') // Set the gas limit - await driver.clickElement(By.css('.confirm-detail-row__header-text--edit')) + await driver.clickElement( + By.css('.confirm-detail-row__header-text--edit'), + ) await driver.delay(regularDelayMs) gasModal = await driver.findElement(By.css('span .modal')) @@ -951,7 +1285,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.page-container__tab:nth-of-type(2)')) await driver.delay(regularDelayMs) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) await gasPriceInput.clear() await driver.delay(50) @@ -967,33 +1303,55 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.page-container__footer-button')) await driver.wait(until.stalenessOf(gasModal)) - const gasFeeInputs = await driver.findElements(By.css('.confirm-detail-row__primary')) + const gasFeeInputs = await driver.findElements( + By.css('.confirm-detail-row__primary'), + ) const renderedGasFee = await gasFeeInputs[0].getText() assert.equal(renderedGasFee, '0.0006') }) it('submits the transaction', async function () { - const tokenAmount = await driver.findElement(By.css('.confirm-page-container-summary__title-text')) + const tokenAmount = await driver.findElement( + By.css('.confirm-page-container-summary__title-text'), + ) const tokenAmountText = await tokenAmount.getText() assert.equal(tokenAmountText, '1.5 TST') - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 2 }, 10000) - const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues[0], /-1.5\s*TST/u)) - const txStatuses = await driver.findElements(By.css('.list-item__heading')) - await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/u), 10000) + const txStatuses = await driver.findElements( + By.css('.list-item__heading'), + ) + await driver.wait( + until.elementTextMatches(txStatuses[0], /Send\sTST/u), + 10000, + ) - const tokenBalanceAmount = await driver.findElements(By.css('.token-overview__primary-balance')) - await driver.wait(until.elementTextMatches(tokenBalanceAmount[0], /7.5\s*TST/u), 10000) + const tokenBalanceAmount = await driver.findElements( + By.css('.token-overview__primary-balance'), + ) + await driver.wait( + until.elementTextMatches(tokenBalanceAmount[0], /7.5\s*TST/u), + 10000, + ) }) }) @@ -1002,44 +1360,71 @@ describe('MetaMask', function () { it('approves an already created token', async function () { const windowHandles = await driver.getAllWindowHandles() const extension = windowHandles[0] - const dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) + const dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) await driver.closeAllWindowHandlesExcept([extension, dapp]) await driver.delay(regularDelayMs) await driver.switchToWindow(dapp) await driver.delay(tinyDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Approve Tokens')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Approve Tokens')]`), + ) await driver.switchToWindow(extension) await driver.delay(regularDelayMs) await driver.wait(async () => { - const pendingTxes = await driver.findElements(By.css('.transaction-list__pending-transactions .transaction-list-item')) + const pendingTxes = await driver.findElements( + By.css( + '.transaction-list__pending-transactions .transaction-list-item', + ), + ) return pendingTxes.length === 1 }, 10000) - const [txtListHeading] = await driver.findElements(By.css('.transaction-list-item .list-item__heading')) - await driver.wait(until.elementTextMatches(txtListHeading, /Approve TST spend limit/u)) + const [txtListHeading] = await driver.findElements( + By.css('.transaction-list-item .list-item__heading'), + ) + await driver.wait( + until.elementTextMatches(txtListHeading, /Approve TST spend limit/u), + ) await driver.clickElement(By.css('.transaction-list-item')) await driver.delay(regularDelayMs) }) it('displays the token approval data', async function () { - await driver.clickElement(By.css('.confirm-approve-content__view-full-tx-button')) + await driver.clickElement( + By.css('.confirm-approve-content__view-full-tx-button'), + ) await driver.delay(regularDelayMs) - const functionType = await driver.findElement(By.css('.confirm-approve-content__data .confirm-approve-content__small-text')) + const functionType = await driver.findElement( + By.css( + '.confirm-approve-content__data .confirm-approve-content__small-text', + ), + ) const functionTypeText = await functionType.getText() assert.equal(functionTypeText, 'Function: Approve') - const confirmDataDiv = await driver.findElement(By.css('.confirm-approve-content__data__data-block')) + const confirmDataDiv = await driver.findElement( + By.css('.confirm-approve-content__data__data-block'), + ) const confirmDataText = await confirmDataDiv.getText() - assert(confirmDataText.match(/0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4/u)) + assert( + confirmDataText.match( + /0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4/u, + ), + ) }) it('opens the gas edit modal', async function () { - await driver.clickElement(By.css('.confirm-approve-content__small-blue-text.cursor-pointer')) + await driver.clickElement( + By.css('.confirm-approve-content__small-blue-text.cursor-pointer'), + ) await driver.delay(regularDelayMs) gasModal = await driver.findElement(By.css('span .modal')) @@ -1049,7 +1434,9 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.page-container__tab:nth-of-type(2)')) await driver.delay(regularDelayMs) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) await gasPriceInput.clear() await driver.delay(50) @@ -1065,18 +1452,26 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.page-container__footer-button')) await driver.wait(until.stalenessOf(gasModal)) - const gasFeeInEth = await driver.findElement(By.css('.confirm-approve-content__transaction-details-content__secondary-fee')) + const gasFeeInEth = await driver.findElement( + By.css( + '.confirm-approve-content__transaction-details-content__secondary-fee', + ), + ) assert.equal(await gasFeeInEth.getText(), '0.0006 ETH') }) it('edits the permission', async function () { - const editButtons = await driver.findClickableElements(By.css('.confirm-approve-content__small-blue-text.cursor-pointer')) + const editButtons = await driver.findClickableElements( + By.css('.confirm-approve-content__small-blue-text.cursor-pointer'), + ) await editButtons[1].click() await driver.delay(regularDelayMs) const permissionModal = await driver.findElement(By.css('span .modal')) - const radioButtons = await driver.findClickableElements(By.css('.edit-approval-permission__edit-section__radio-button')) + const radioButtons = await driver.findClickableElements( + By.css('.edit-approval-permission__edit-section__radio-button'), + ) await radioButtons[1].click() const customInput = await driver.findElement(By.css('input')) @@ -1089,24 +1484,36 @@ describe('MetaMask', function () { await driver.wait(until.stalenessOf(permissionModal)) - const permissionInfo = await driver.findElements(By.css('.confirm-approve-content__medium-text')) + const permissionInfo = await driver.findElements( + By.css('.confirm-approve-content__medium-text'), + ) const amountDiv = permissionInfo[0] assert.equal(await amountDiv.getText(), '5 TST') }) it('submits the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 3 }, 10000) - const txStatuses = await driver.findElements(By.css('.list-item__heading')) - await driver.wait(until.elementTextMatches(txStatuses[0], /Approve TST spend limit/u)) + const txStatuses = await driver.findElements( + By.css('.list-item__heading'), + ) + await driver.wait( + until.elementTextMatches(txStatuses[0], /Approve TST spend limit/u), + ) }) }) @@ -1114,23 +1521,34 @@ describe('MetaMask', function () { it('transfers an already created token, without specifying gas', async function () { const windowHandles = await driver.getAllWindowHandles() const extension = windowHandles[0] - const dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) + const dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) await driver.closeAllWindowHandlesExcept([extension, dapp]) await driver.delay(regularDelayMs) await driver.switchToWindow(dapp) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Transfer Tokens Without Gas')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Transfer Tokens Without Gas')]`), + ) await driver.switchToWindow(extension) await driver.delay(regularDelayMs) await driver.wait(async () => { - const pendingTxes = await driver.findElements(By.css('.transaction-list__pending-transactions .transaction-list-item')) + const pendingTxes = await driver.findElements( + By.css( + '.transaction-list__pending-transactions .transaction-list-item', + ), + ) return pendingTxes.length === 1 }, 10000) - const [txListValue] = await driver.findElements(By.css('.transaction-list-item__primary-currency')) + const [txListValue] = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txListValue, /-1.5\s*TST/u)) await driver.clickElement(By.css('.transaction-list-item')) await driver.delay(regularDelayMs) @@ -1138,19 +1556,29 @@ describe('MetaMask', function () { it('submits the transaction', async function () { await driver.delay(largeDelayMs * 2) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(largeDelayMs * 2) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 4 }, 10000) - const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) await driver.wait(until.elementTextMatches(txValues[0], /-1.5\s*TST/u)) - const txStatuses = await driver.findElements(By.css('.list-item__heading')) + const txStatuses = await driver.findElements( + By.css('.list-item__heading'), + ) await driver.wait(until.elementTextMatches(txStatuses[0], /Send TST/u)) }) }) @@ -1159,52 +1587,79 @@ describe('MetaMask', function () { it('approves an already created token', async function () { const windowHandles = await driver.getAllWindowHandles() const extension = windowHandles[0] - const dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) + const dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) await driver.closeAllWindowHandlesExcept([extension, dapp]) await driver.delay(regularDelayMs) await driver.switchToWindow(dapp) await driver.delay(tinyDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Approve Tokens Without Gas')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Approve Tokens Without Gas')]`), + ) await driver.switchToWindow(extension) await driver.delay(regularDelayMs) await driver.wait(async () => { - const pendingTxes = await driver.findElements(By.css('.transaction-list__pending-transactions .transaction-list-item')) + const pendingTxes = await driver.findElements( + By.css( + '.transaction-list__pending-transactions .transaction-list-item', + ), + ) return pendingTxes.length === 1 }, 10000) - const [txtListHeading] = await driver.findElements(By.css('.transaction-list-item .list-item__heading')) - await driver.wait(until.elementTextMatches(txtListHeading, /Approve TST spend limit/u)) + const [txtListHeading] = await driver.findElements( + By.css('.transaction-list-item .list-item__heading'), + ) + await driver.wait( + until.elementTextMatches(txtListHeading, /Approve TST spend limit/u), + ) await driver.clickElement(By.css('.transaction-list-item')) await driver.delay(regularDelayMs) }) it('shows the correct recipient', async function () { - await driver.clickElement(By.css('.confirm-approve-content__view-full-tx-button')) + await driver.clickElement( + By.css('.confirm-approve-content__view-full-tx-button'), + ) await driver.delay(regularDelayMs) - const permissionInfo = await driver.findElements(By.css('.confirm-approve-content__medium-text')) + const permissionInfo = await driver.findElements( + By.css('.confirm-approve-content__medium-text'), + ) const recipientDiv = permissionInfo[1] assert.equal(await recipientDiv.getText(), '0x2f318C33...C970') }) it('submits the transaction', async function () { await driver.delay(1000) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 5 }, 10000) - const txStatuses = await driver.findElements(By.css('.list-item__heading')) - await driver.wait(until.elementTextMatches(txStatuses[0], /Approve TST spend limit/u)) + const txStatuses = await driver.findElements( + By.css('.list-item__heading'), + ) + await driver.wait( + until.elementTextMatches(txStatuses[0], /Approve TST spend limit/u), + ) }) }) @@ -1216,7 +1671,9 @@ describe('MetaMask', function () { const confirmHideModal = await driver.findElement(By.css('span .modal')) - await driver.clickElement(By.css('[data-testid="hide-token-confirmation__hide"]')) + await driver.clickElement( + By.css('[data-testid="hide-token-confirmation__hide"]'), + ) await driver.wait(until.stalenessOf(confirmHideModal)) }) @@ -1224,7 +1681,9 @@ describe('MetaMask', function () { describe('Add existing token using search', function () { it('clicks on the Add Token button', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Add Token')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Add Token')]`), + ) await driver.delay(regularDelayMs) }) @@ -1239,12 +1698,16 @@ describe('MetaMask', function () { await driver.clickElement(By.xpath(`//button[contains(text(), 'Next')]`)) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Add Tokens')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Add Tokens')]`), + ) await driver.delay(largeDelayMs) }) it('renders the balance for the chosen token', async function () { - const balance = await driver.findElement(By.css('.token-overview__primary-balance')) + const balance = await driver.findElement( + By.css('.token-overview__primary-balance'), + ) await driver.wait(until.elementTextMatches(balance, /0\s*BAT/u)) await driver.delay(regularDelayMs) }) @@ -1258,12 +1721,16 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.network-name')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//span[contains(text(), 'Custom RPC')]`)) + await driver.clickElement( + By.xpath(`//span[contains(text(), 'Custom RPC')]`), + ) await driver.delay(regularDelayMs) await driver.findElement(By.css('.settings-page__sub-header-text')) - const customRpcInputs = await driver.findElements(By.css('input[type="text"]')) + const customRpcInputs = await driver.findElements( + By.css('input[type="text"]'), + ) const rpcUrlInput = customRpcInputs[1] const chainIdInput = customRpcInputs[2] @@ -1274,9 +1741,7 @@ describe('MetaMask', function () { await chainIdInput.sendKeys(chainId) await driver.clickElement(By.css('.network-form__footer .btn-secondary')) - await driver.findElement( - By.xpath(`//div[contains(text(), '${rpcUrl}')]`), - ) + await driver.findElement(By.xpath(`//div[contains(text(), '${rpcUrl}')]`)) }) it(`creates second custom RPC entry`, async function () { @@ -1286,12 +1751,16 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.network-name')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//span[contains(text(), 'Custom RPC')]`)) + await driver.clickElement( + By.xpath(`//span[contains(text(), 'Custom RPC')]`), + ) await driver.delay(regularDelayMs) await driver.findElement(By.css('.settings-page__sub-header-text')) - const customRpcInputs = await driver.findElements(By.css('input[type="text"]')) + const customRpcInputs = await driver.findElements( + By.css('input[type="text"]'), + ) const rpcUrlInput = customRpcInputs[1] const chainIdInput = customRpcInputs[2] @@ -1302,16 +1771,16 @@ describe('MetaMask', function () { await chainIdInput.sendKeys(chainId) await driver.clickElement(By.css('.network-form__footer .btn-secondary')) - await driver.findElement( - By.xpath(`//div[contains(text(), '${rpcUrl}')]`), - ) + await driver.findElement(By.xpath(`//div[contains(text(), '${rpcUrl}')]`)) }) it('selects another provider', async function () { await driver.clickElement(By.css('.network-name')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//span[contains(text(), 'Ethereum Mainnet')]`)) + await driver.clickElement( + By.xpath(`//span[contains(text(), 'Ethereum Mainnet')]`), + ) await driver.delay(largeDelayMs * 2) }) @@ -1320,13 +1789,17 @@ describe('MetaMask', function () { await driver.delay(regularDelayMs) // only recent 3 are found and in correct order (most recent at the top) - const customRpcs = await driver.findElements(By.xpath(`//span[contains(text(), 'http://127.0.0.1:8545/')]`)) + const customRpcs = await driver.findElements( + By.xpath(`//span[contains(text(), 'http://127.0.0.1:8545/')]`), + ) assert.equal(customRpcs.length, 2) }) it('deletes a custom RPC', async function () { - const networkListItems = await driver.findClickableElements(By.css('.networks-tab__networks-list-name')) + const networkListItems = await driver.findClickableElements( + By.css('.networks-tab__networks-list-name'), + ) const lastNetworkListItem = networkListItems[networkListItems.length - 1] await lastNetworkListItem.click() await driver.delay(100) @@ -1334,14 +1807,20 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.btn-danger')) await driver.delay(regularDelayMs) - const confirmDeleteNetworkModal = await driver.findElement(By.css('span .modal')) + const confirmDeleteNetworkModal = await driver.findElement( + By.css('span .modal'), + ) - const byConfirmDeleteNetworkButton = By.css('.button.btn-danger.modal-container__footer-button') + const byConfirmDeleteNetworkButton = By.css( + '.button.btn-danger.modal-container__footer-button', + ) await driver.clickElement(byConfirmDeleteNetworkButton) await driver.wait(until.stalenessOf(confirmDeleteNetworkModal)) - const newNetworkListItems = await driver.findElements(By.css('.networks-tab__networks-list-name')) + const newNetworkListItems = await driver.findElements( + By.css('.networks-tab__networks-list-name'), + ) assert.equal(networkListItems.length - 1, newNetworkListItems.length) }) diff --git a/test/e2e/mock-3box/server.js b/test/e2e/mock-3box/server.js index 66c4be6bb..7094fddd4 100644 --- a/test/e2e/mock-3box/server.js +++ b/test/e2e/mock-3box/server.js @@ -19,7 +19,9 @@ const requestHandler = (request, response) => { response.end('ok') }) } else if (request.method === 'GET') { - const key = (new URL(request.url, 'https://example.org/')).searchParams.get('key') + const key = new URL(request.url, 'https://example.org/').searchParams.get( + 'key', + ) response.setHeader('Access-Control-Allow-Headers', '*') response.end(JSON.stringify(database[key] || '')) } else { @@ -32,6 +34,5 @@ const server = http.createServer(requestHandler) server.listen(port, (err) => { if (err) { console.log('mock 3box server error: ', err) - } }) diff --git a/test/e2e/permissions.spec.js b/test/e2e/permissions.spec.js index 87c439c0c..133bade16 100644 --- a/test/e2e/permissions.spec.js +++ b/test/e2e/permissions.spec.js @@ -3,10 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -23,7 +20,8 @@ describe('MetaMask', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -37,7 +35,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -54,12 +54,18 @@ describe('MetaMask', function () { describe('Going through the first time flow, but skipping the seed phrase challenge', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Create a Wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -69,8 +75,12 @@ describe('MetaMask', function () { }) it('accepts a secure password', async function () { - const passwordBox = await driver.findElement(By.css('.first-time-flow__form #create-password')) - const passwordBoxConfirm = await driver.findElement(By.css('.first-time-flow__form #confirm-password')) + const passwordBox = await driver.findElement( + By.css('.first-time-flow__form #create-password'), + ) + const passwordBoxConfirm = await driver.findElement( + By.css('.first-time-flow__form #confirm-password'), + ) await passwordBox.sendKeys('correct horse battery staple') await passwordBoxConfirm.sendKeys('correct horse battery staple') @@ -82,15 +92,25 @@ describe('MetaMask', function () { }) it('skips the seed phrase challenge', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`, + ), + ) await driver.delay(regularDelayMs) - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) }) it('gets the current accounts address', async function () { - const addressInput = await driver.findElement(By.css('.readonly-input__input')) + const addressInput = await driver.findElement( + By.css('.readonly-input__input'), + ) publicAddress = await addressInput.getAttribute('value') const accountModal = await driver.findElement(By.css('span .modal')) @@ -110,21 +130,30 @@ describe('MetaMask', function () { await driver.openNewPage('http://127.0.0.1:8080/') await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.waitUntilXWindowHandles(3) const windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) - popup = windowHandles.find((handle) => handle !== extension && handle !== dapp) + dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) + popup = windowHandles.find( + (handle) => handle !== extension && handle !== dapp, + ) await driver.switchToWindow(popup) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//button[contains(text(), 'Next')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.waitUntilXWindowHandles(2) await driver.switchToWindow(extension) @@ -132,12 +161,20 @@ describe('MetaMask', function () { }) it('shows connected sites', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__connected-sites"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__connected-sites"]'), + ) - await driver.findElement(By.xpath(`//h2[contains(text(), 'Connected sites')]`)) + await driver.findElement( + By.xpath(`//h2[contains(text(), 'Connected sites')]`), + ) - const domains = await driver.findClickableElements(By.css('.connected-sites-list__domain-name')) + const domains = await driver.findClickableElements( + By.css('.connected-sites-list__domain-name'), + ) assert.equal(domains.length, 1) }) @@ -145,10 +182,17 @@ describe('MetaMask', function () { await driver.switchToWindow(dapp) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'eth_accounts')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'eth_accounts')]`), + ) - const getAccountsResult = await driver.findElement(By.css('#getAccountsResult')) - assert.equal((await getAccountsResult.getText()).toLowerCase(), publicAddress.toLowerCase()) + const getAccountsResult = await driver.findElement( + By.css('#getAccountsResult'), + ) + assert.equal( + (await getAccountsResult.getText()).toLowerCase(), + publicAddress.toLowerCase(), + ) }) }) }) diff --git a/test/e2e/send-edit.spec.js b/test/e2e/send-edit.spec.js index 1dba2c396..b11dde556 100644 --- a/test/e2e/send-edit.spec.js +++ b/test/e2e/send-edit.spec.js @@ -3,11 +3,7 @@ const webdriver = require('selenium-webdriver') const { By, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - tinyDelayMs, - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -16,7 +12,8 @@ const ganacheServer = new Ganache() describe('Using MetaMask with an existing account', function () { let driver - const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' + const testSeedPhrase = + 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' this.timeout(0) this.bail(true) @@ -25,7 +22,8 @@ describe('Using MetaMask with an existing account', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -39,7 +37,9 @@ describe('Using MetaMask with an existing account', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -56,12 +56,18 @@ describe('Using MetaMask with an existing account', function () { describe('First time flow starting from an existing seed phrase', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Import Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -71,24 +77,36 @@ describe('Using MetaMask with an existing account', function () { }) it('imports a seed phrase', async function () { - const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]')) + const [seedTextArea] = await driver.findElements( + By.css('input[placeholder="Paste seed phrase from clipboard"]'), + ) await seedTextArea.sendKeys(testSeedPhrase) await driver.delay(regularDelayMs) const [password] = await driver.findElements(By.id('password')) await password.sendKeys('correct horse battery staple') - const [confirmPassword] = await driver.findElements(By.id('confirm-password')) + const [confirmPassword] = await driver.findElements( + By.id('confirm-password'), + ) confirmPassword.sendKeys('correct horse battery staple') await driver.clickElement(By.css('.first-time-flow__terms')) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import')]`), + ) await driver.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) }) @@ -98,7 +116,9 @@ describe('Using MetaMask with an existing account', function () { await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) await driver.delay(regularDelayMs) - const inputAddress = await driver.findElement(By.css('input[placeholder="Search, public address (0x), or ENS"]')) + const inputAddress = await driver.findElement( + By.css('input[placeholder="Search, public address (0x), or ENS"]'), + ) await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') const inputAmount = await driver.findElement(By.css('.unit-input__input')) @@ -110,7 +130,9 @@ describe('Using MetaMask with an existing account', function () { const gasModal = await driver.findElement(By.css('span .modal')) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) await gasPriceInput.clear() await driver.delay(50) @@ -135,7 +157,9 @@ describe('Using MetaMask with an existing account', function () { }) it('has correct value and fee on the confirm screen the transaction', async function () { - const transactionAmounts = await driver.findElements(By.css('.currency-display-component__text')) + const transactionAmounts = await driver.findElements( + By.css('.currency-display-component__text'), + ) const transactionAmount = transactionAmounts[0] assert.equal(await transactionAmount.getText(), '1') @@ -144,7 +168,9 @@ describe('Using MetaMask with an existing account', function () { }) it('edits the transaction', async function () { - await driver.clickElement(By.css('.confirm-page-container-header__back-button')) + await driver.clickElement( + By.css('.confirm-page-container-header__back-button'), + ) await driver.delay(regularDelayMs) @@ -159,7 +185,9 @@ describe('Using MetaMask with an existing account', function () { const gasModal = await driver.findElement(By.css('span .modal')) - const [gasPriceInput, gasLimitInput] = await driver.findElements(By.css('.advanced-gas-inputs__gas-edit-row__input')) + const [gasPriceInput, gasLimitInput] = await driver.findElements( + By.css('.advanced-gas-inputs__gas-edit-row__input'), + ) await gasPriceInput.clear() await driver.delay(50) @@ -183,7 +211,9 @@ describe('Using MetaMask with an existing account', function () { }) it('has correct updated value on the confirm screen the transaction', async function () { - const transactionAmounts = await driver.findElements(By.css('.currency-display-component__text')) + const transactionAmounts = await driver.findElements( + By.css('.currency-display-component__text'), + ) const transactionAmount = transactionAmounts[0] assert.equal(await transactionAmount.getText(), '2.2') @@ -192,20 +222,28 @@ describe('Using MetaMask with an existing account', function () { }) it('confirms the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Confirm')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Confirm')]`), + ) await driver.delay(regularDelayMs) }) it('finds the transaction in the transactions list', async function () { await driver.clickElement(By.css('[data-testid="home__activity-tab"]')) await driver.wait(async () => { - const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item')) + const confirmedTxes = await driver.findElements( + By.css( + '.transaction-list__completed-transactions .transaction-list-item', + ), + ) return confirmedTxes.length === 1 }, 10000) - const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) + const txValues = await driver.findElements( + By.css('.transaction-list-item__primary-currency'), + ) assert.equal(txValues.length, 1) - assert.ok((/-2.2\s*ETH/u).test(await txValues[0].getText())) + assert.ok(/-2.2\s*ETH/u.test(await txValues[0].getText())) }) }) }) diff --git a/test/e2e/signature-request.spec.js b/test/e2e/signature-request.spec.js index 9e83cc25e..45087c03c 100644 --- a/test/e2e/signature-request.spec.js +++ b/test/e2e/signature-request.spec.js @@ -3,10 +3,7 @@ const path = require('path') const webdriver = require('selenium-webdriver') const { By, Key, until } = webdriver -const { - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') const FixtureServer = require('./fixture-server') @@ -25,7 +22,9 @@ describe('MetaMask', function () { before(async function () { await ganacheServer.start() await fixtureServer.start() - await fixtureServer.loadState(path.join(__dirname, 'fixtures', 'imported-account')) + await fixtureServer.loadState( + path.join(__dirname, 'fixtures', 'imported-account'), + ) publicAddress = '0x5cfe73b6021e818b776b421b1c4db2474086a7e1' const result = await buildWebDriver() driver = result.driver @@ -36,7 +35,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -69,7 +70,9 @@ describe('MetaMask', function () { await driver.openNewPage('http://127.0.0.1:8080/') await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.delay(regularDelayMs) @@ -77,15 +80,22 @@ describe('MetaMask', function () { windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - dapp = await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles) - popup = windowHandles.find((handle) => handle !== extension && handle !== dapp) + dapp = await driver.switchToWindowWithTitle( + 'E2E Test Dapp', + windowHandles, + ) + popup = windowHandles.find( + (handle) => handle !== extension && handle !== dapp, + ) await driver.switchToWindow(popup) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//button[contains(text(), 'Next')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Connect')]`), + ) await driver.waitUntilXWindowHandles(2) await driver.switchToWindow(dapp) @@ -97,22 +107,39 @@ describe('MetaMask', function () { await driver.delay(regularDelayMs) windowHandles = await driver.getAllWindowHandles() - await driver.switchToWindowWithTitle('MetaMask Notification', windowHandles) + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ) await driver.delay(regularDelayMs) - const title = await driver.findElement(By.css('.signature-request-content__title')) - const name = await driver.findElement(By.css('.signature-request-content__info--bolded')) - const content = await driver.findElements(By.css('.signature-request-content__info')) + const title = await driver.findElement( + By.css('.signature-request-content__title'), + ) + const name = await driver.findElement( + By.css('.signature-request-content__info--bolded'), + ) + const content = await driver.findElements( + By.css('.signature-request-content__info'), + ) const origin = content[0] const address = content[1] assert.equal(await title.getText(), 'Signature Request') assert.equal(await name.getText(), 'Ether Mail') assert.equal(await origin.getText(), 'http://127.0.0.1:8080') - assert.equal(await address.getText(), `${publicAddress.slice(0, 8)}...${publicAddress.slice(publicAddress.length - 8)}`) + assert.equal( + await address.getText(), + `${publicAddress.slice(0, 8)}...${publicAddress.slice( + publicAddress.length - 8, + )}`, + ) }) it('signs the transaction', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Sign')]`), 10000) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Sign')]`), + 10000, + ) await driver.delay(regularDelayMs) extension = windowHandles[0] @@ -120,11 +147,17 @@ describe('MetaMask', function () { }) it('gets the current accounts address', async function () { - await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) - await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) + await driver.clickElement( + By.css('[data-testid="account-options-menu-button"]'), + ) + await driver.clickElement( + By.css('[data-testid="account-options-menu__account-details"]'), + ) await driver.delay(regularDelayMs) - const addressInput = await driver.findElement(By.css('.readonly-input__input')) + const addressInput = await driver.findElement( + By.css('.readonly-input__input'), + ) const newPublicAddress = await addressInput.getAttribute('value') const accountModal = await driver.findElement(By.css('span .modal')) diff --git a/test/e2e/tests/localization.spec.js b/test/e2e/tests/localization.spec.js index 127d432bd..7b17b95cc 100644 --- a/test/e2e/tests/localization.spec.js +++ b/test/e2e/tests/localization.spec.js @@ -7,7 +7,8 @@ describe('Localization', function () { const ganacheOptions = { accounts: [ { - secretKey: '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', balance: 25000000000000000000, }, ], @@ -18,7 +19,9 @@ describe('Localization', function () { const passwordField = await driver.findElement(By.css('#password')) await passwordField.sendKeys('correct horse battery staple') await passwordField.sendKeys(Key.ENTER) - const secondaryBalance = await driver.findElement(By.css('[data-testid="eth-overview__secondary-currency"]')) + const secondaryBalance = await driver.findElement( + By.css('[data-testid="eth-overview__secondary-currency"]'), + ) const secondaryBalanceText = await secondaryBalance.getText() const [fiatAmount, fiatUnit] = secondaryBalanceText.trim().split(/\s+/u) assert.ok(fiatAmount.startsWith('₱')) diff --git a/test/e2e/tests/personal-sign.spec.js b/test/e2e/tests/personal-sign.spec.js index 9cc2d4fc3..dbead3dbd 100644 --- a/test/e2e/tests/personal-sign.spec.js +++ b/test/e2e/tests/personal-sign.spec.js @@ -7,13 +7,19 @@ describe('Personal sign', function () { const ganacheOptions = { accounts: [ { - secretKey: '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', balance: 25000000000000000000, }, ], } await withFixtures( - { dapp: true, fixtures: 'personal-sign', ganacheOptions, title: this.test.title }, + { + dapp: true, + fixtures: 'personal-sign', + ganacheOptions, + title: this.test.title, + }, async ({ driver }) => { const passwordField = await driver.findElement(By.css('#password')) await passwordField.sendKeys('correct horse battery staple') @@ -25,13 +31,20 @@ describe('Personal sign', function () { await driver.waitUntilXWindowHandles(3) const windowHandles = await driver.getAllWindowHandles() - await driver.switchToWindowWithTitle('MetaMask Notification', windowHandles) + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ) - const personalMessageRow = await driver.findElement(By.css('.request-signature__row-value')) + const personalMessageRow = await driver.findElement( + By.css('.request-signature__row-value'), + ) const personalMessage = await personalMessageRow.getText() assert.equal(personalMessage, 'Example `personal_sign` message') - await driver.clickElement(By.css('[data-testid="request-signature__sign"]')) + await driver.clickElement( + By.css('[data-testid="request-signature__sign"]'), + ) await driver.waitUntilXWindowHandles(2) }, diff --git a/test/e2e/tests/simple-send.spec.js b/test/e2e/tests/simple-send.spec.js index 3328b110c..68128dab7 100644 --- a/test/e2e/tests/simple-send.spec.js +++ b/test/e2e/tests/simple-send.spec.js @@ -6,7 +6,8 @@ describe('Simple send', function () { const ganacheOptions = { accounts: [ { - secretKey: '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', balance: 25000000000000000000, }, ], @@ -18,12 +19,22 @@ describe('Simple send', function () { await passwordField.sendKeys('correct horse battery staple') await passwordField.sendKeys(Key.ENTER) await driver.clickElement(By.css('[data-testid="eth-overview-send"]')) - const recipientAddressField = await driver.findElement(By.css('[data-testid="ens-input"]')) - await recipientAddressField.sendKeys('0x985c30949c92df7a0bd42e0f3e3d539ece98db24') - const amountField = await driver.findElement(By.css('.unit-input__input')) + const recipientAddressField = await driver.findElement( + By.css('[data-testid="ens-input"]'), + ) + await recipientAddressField.sendKeys( + '0x985c30949c92df7a0bd42e0f3e3d539ece98db24', + ) + const amountField = await driver.findElement( + By.css('.unit-input__input'), + ) await amountField.sendKeys('1') - await driver.clickElement(By.css('[data-testid="page-container-footer-next"]')) - await driver.clickElement(By.css('[data-testid="page-container-footer-next"]')) + await driver.clickElement( + By.css('[data-testid="page-container-footer-next"]'), + ) + await driver.clickElement( + By.css('[data-testid="page-container-footer-next"]'), + ) await driver.clickElement(By.css('[data-testid="home__activity-tab"]')) await driver.findElement(By.css('.transaction-list-item')) }, diff --git a/test/e2e/threebox.spec.js b/test/e2e/threebox.spec.js index 3254d8cb9..107531bff 100644 --- a/test/e2e/threebox.spec.js +++ b/test/e2e/threebox.spec.js @@ -4,11 +4,7 @@ const getPort = require('get-port') const { By, until } = webdriver const enLocaleMessages = require('../../app/_locales/en/messages.json') -const { - tinyDelayMs, - regularDelayMs, - largeDelayMs, -} = require('./helpers') +const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers') const { buildWebDriver } = require('./webdriver') const Ganache = require('./ganache') @@ -17,7 +13,8 @@ const ganacheServer = new Ganache() describe('MetaMask', function () { let driver - const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' + const testSeedPhrase = + 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' this.timeout(0) this.bail(true) @@ -26,7 +23,8 @@ describe('MetaMask', function () { await ganacheServer.start({ accounts: [ { - secretKey: '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', balance: 25000000000000000000, }, ], @@ -40,7 +38,9 @@ describe('MetaMask', function () { const errors = await driver.checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map((err) => err.message) - const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + const errorMessage = `Errors found in browser console:\n${errorReports.join( + '\n', + )}` console.error(new Error(errorMessage)) } } @@ -55,16 +55,21 @@ describe('MetaMask', function () { }) describe('set up data to be restored by 3box', function () { - describe('First time flow starting from an existing seed phrase', function () { it('clicks the continue button on the welcome screen', async function () { await driver.findElement(By.css('.welcome-page__header')) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver.delay(largeDelayMs) }) it('clicks the "Import Wallet" option', async function () { - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import wallet')]`), + ) await driver.delay(largeDelayMs) }) @@ -74,29 +79,43 @@ describe('MetaMask', function () { }) it('imports a seed phrase', async function () { - const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]')) + const [seedTextArea] = await driver.findElements( + By.css('input[placeholder="Paste seed phrase from clipboard"]'), + ) await seedTextArea.sendKeys(testSeedPhrase) await driver.delay(regularDelayMs) const [password] = await driver.findElements(By.id('password')) await password.sendKeys('correct horse battery staple') - const [confirmPassword] = await driver.findElements(By.id('confirm-password')) + const [confirmPassword] = await driver.findElements( + By.id('confirm-password'), + ) confirmPassword.sendKeys('correct horse battery staple') await driver.clickElement(By.css('.first-time-flow__terms')) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Import')]`), + ) await driver.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver.delay(regularDelayMs) }) it('balance renders', async function () { - const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) + const balance = await driver.findElement( + By.css('[data-testid="wallet-balance"] .list-item__heading'), + ) await driver.wait(until.elementTextMatches(balance, /25\s*ETH/u)) await driver.delay(regularDelayMs) }) @@ -107,19 +126,26 @@ describe('MetaMask', function () { await driver.clickElement(By.css('.account-menu__icon')) await driver.delay(regularDelayMs) - await driver.clickElement(By.xpath(`//div[contains(text(), 'Settings')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Settings')]`), + ) }) it('turns on threebox syncing', async function () { - await driver.clickElement(By.xpath(`//div[contains(text(), 'Advanced')]`)) - await driver.clickElement(By.css('[data-testid="advanced-setting-3box"] .toggle-button div')) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Advanced')]`), + ) + await driver.clickElement( + By.css('[data-testid="advanced-setting-3box"] .toggle-button div'), + ) }) - }) describe('updates settings and address book', function () { it('navigates to General settings', async function () { - await driver.clickElement(By.xpath(`//div[contains(text(), 'General')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'General')]`), + ) }) it('turns on use of blockies', async function () { @@ -127,7 +153,9 @@ describe('MetaMask', function () { }) it('adds an address to the contact list', async function () { - await driver.clickElement(By.xpath(`//div[contains(text(), 'Contacts')]`)) + await driver.clickElement( + By.xpath(`//div[contains(text(), 'Contacts')]`), + ) await driver.clickElement(By.css('.address-book-add-button__button')) await driver.delay(tinyDelayMs) @@ -137,17 +165,22 @@ describe('MetaMask', function () { await driver.delay(tinyDelayMs) - await addAddressInputs[1].sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') + await addAddressInputs[1].sendKeys( + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ) await driver.delay(largeDelayMs * 2) - await driver.clickElement(By.xpath(`//button[contains(text(), 'Save')]`)) + await driver.clickElement( + By.xpath(`//button[contains(text(), 'Save')]`), + ) - await driver.findElement(By.xpath(`//div[contains(text(), 'Test User Name 11')]`)) + await driver.findElement( + By.xpath(`//div[contains(text(), 'Test User Name 11')]`), + ) await driver.delay(regularDelayMs) }) }) - }) describe('restoration from 3box', function () { @@ -165,12 +198,18 @@ describe('MetaMask', function () { describe('First time flow starting from an existing seed phrase', function () { it('clicks the continue button on the welcome screen', async function () { await driver2.findElement(By.css('.welcome-page__header')) - await driver2.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + await driver2.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`, + ), + ) await driver2.delay(largeDelayMs) }) it('clicks the "Import Wallet" option', async function () { - await driver2.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`)) + await driver2.clickElement( + By.xpath(`//button[contains(text(), 'Import wallet')]`), + ) await driver2.delay(largeDelayMs) }) @@ -180,29 +219,43 @@ describe('MetaMask', function () { }) it('imports a seed phrase', async function () { - const [seedTextArea] = await driver2.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]')) + const [seedTextArea] = await driver2.findElements( + By.css('input[placeholder="Paste seed phrase from clipboard"]'), + ) await seedTextArea.sendKeys(testSeedPhrase) await driver2.delay(regularDelayMs) const [password] = await driver2.findElements(By.id('password')) await password.sendKeys('correct horse battery staple') - const [confirmPassword] = await driver2.findElements(By.id('confirm-password')) + const [confirmPassword] = await driver2.findElements( + By.id('confirm-password'), + ) confirmPassword.sendKeys('correct horse battery staple') await driver2.clickElement(By.css('.first-time-flow__terms')) - await driver2.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) + await driver2.clickElement( + By.xpath(`//button[contains(text(), 'Import')]`), + ) await driver2.delay(regularDelayMs) }) it('clicks through the success screen', async function () { - await driver2.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) - await driver2.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) + await driver2.findElement( + By.xpath(`//div[contains(text(), 'Congratulations')]`), + ) + await driver2.clickElement( + By.xpath( + `//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`, + ), + ) await driver2.delay(regularDelayMs) }) it('balance renders', async function () { - const balance = await driver2.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) + const balance = await driver2.findElement( + By.css('[data-testid="wallet-balance"] .list-item__heading'), + ) await driver2.wait(until.elementTextMatches(balance, /25\s*ETH/u)) await driver2.delay(regularDelayMs) }) @@ -217,21 +270,29 @@ describe('MetaMask', function () { await driver2.clickElement(By.css('.account-menu__icon')) await driver2.delay(regularDelayMs) - await driver2.clickElement(By.xpath(`//div[contains(text(), 'Settings')]`)) + await driver2.clickElement( + By.xpath(`//div[contains(text(), 'Settings')]`), + ) }) it('finds the blockies toggle turned on', async function () { await driver2.delay(regularDelayMs) - const toggleLabel = await driver2.findElement(By.css('.toggle-button__status')) + const toggleLabel = await driver2.findElement( + By.css('.toggle-button__status'), + ) const toggleLabelText = await toggleLabel.getText() assert.equal(toggleLabelText, 'ON') }) it('finds the restored address in the contact list', async function () { - await driver2.clickElement(By.xpath(`//div[contains(text(), 'Contacts')]`)) + await driver2.clickElement( + By.xpath(`//div[contains(text(), 'Contacts')]`), + ) await driver2.delay(regularDelayMs) - await driver2.findElement(By.xpath(`//div[contains(text(), 'Test User Name 11')]`)) + await driver2.findElement( + By.xpath(`//div[contains(text(), 'Test User Name 11')]`), + ) await driver2.delay(regularDelayMs) }) }) diff --git a/test/e2e/webdriver/chrome.js b/test/e2e/webdriver/chrome.js index 556073056..1accbc097 100644 --- a/test/e2e/webdriver/chrome.js +++ b/test/e2e/webdriver/chrome.js @@ -5,21 +5,15 @@ const chrome = require('selenium-webdriver/chrome') * A wrapper around a {@code WebDriver} instance exposing Chrome-specific functionality */ class ChromeDriver { - static async build ({ extensionPath, responsive, port }) { - const args = [ - `load-extension=${extensionPath}`, - ] + static async build({ extensionPath, responsive, port }) { + const args = [`load-extension=${extensionPath}`] if (responsive) { args.push('--auto-open-devtools-for-tabs') } - const options = new chrome.Options() - .addArguments(args) - const builder = new Builder() - .forBrowser('chrome') - .setChromeOptions(options) + const options = new chrome.Options().addArguments(args) + const builder = new Builder().forBrowser('chrome').setChromeOptions(options) if (port) { - const service = new chrome.ServiceBuilder() - .setPort(port) + const service = new chrome.ServiceBuilder().setPort(port) builder.setChromeService(service) } const driver = builder.build() @@ -36,7 +30,7 @@ class ChromeDriver { * @constructor * @param {!ThenableWebDriver} driver - a {@code WebDriver} instance */ - constructor (driver) { + constructor(driver) { this._driver = driver } @@ -45,7 +39,7 @@ class ChromeDriver { * @param {string} extensionName - the extension name * @returns {Promise} - the extension ID */ - async getExtensionIdByName (extensionName) { + async getExtensionIdByName(extensionName) { await this._driver.get('chrome://extensions') return await this._driver.executeScript(` const extensions = document.querySelector("extensions-manager").shadowRoot diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index c4a551b36..9f094e1a6 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -3,44 +3,43 @@ const { strict: assert } = require('assert') const { until, error: webdriverError } = require('selenium-webdriver') class Driver { - /** * @param {!ThenableWebDriver} driver - A {@code WebDriver} instance * @param {string} browser - The type of browser this driver is controlling * @param {number} timeout */ - constructor (driver, browser, extensionUrl, timeout = 10000) { + constructor(driver, browser, extensionUrl, timeout = 10000) { this.driver = driver this.browser = browser this.extensionUrl = extensionUrl this.timeout = timeout } - async delay (time) { + async delay(time) { await new Promise((resolve) => setTimeout(resolve, time)) } - async wait (condition, timeout = this.timeout) { + async wait(condition, timeout = this.timeout) { await this.driver.wait(condition, timeout) } - async quit () { + async quit() { await this.driver.quit() } // Element interactions - async findElement (locator) { + async findElement(locator) { return await this.driver.wait(until.elementLocated(locator), this.timeout) } - async findVisibleElement (locator) { + async findVisibleElement(locator) { const element = await this.findElement(locator) await this.driver.wait(until.elementIsVisible(element), this.timeout) return element } - async findClickableElement (locator) { + async findClickableElement(locator) { const element = await this.findElement(locator) await Promise.all([ this.driver.wait(until.elementIsVisible(element), this.timeout), @@ -49,29 +48,30 @@ class Driver { return element } - async findElements (locator) { + async findElements(locator) { return await this.driver.wait(until.elementsLocated(locator), this.timeout) } - async findClickableElements (locator) { + async findClickableElements(locator) { const elements = await this.findElements(locator) - await Promise.all(elements - .reduce((acc, element) => { + await Promise.all( + elements.reduce((acc, element) => { acc.push( this.driver.wait(until.elementIsVisible(element), this.timeout), this.driver.wait(until.elementIsEnabled(element), this.timeout), ) return acc - }, [])) + }, []), + ) return elements } - async clickElement (locator) { + async clickElement(locator) { const element = await this.findClickableElement(locator) await element.click() } - async clickPoint (locator, x, y) { + async clickPoint(locator, x, y) { const element = await this.findElement(locator) await this.driver .actions() @@ -80,49 +80,55 @@ class Driver { .perform() } - async scrollToElement (element) { - await this.driver.executeScript('arguments[0].scrollIntoView(true)', element) + async scrollToElement(element) { + await this.driver.executeScript( + 'arguments[0].scrollIntoView(true)', + element, + ) } - async assertElementNotPresent (locator) { + async assertElementNotPresent(locator) { let dataTab try { dataTab = await this.findElement(locator) } catch (err) { - assert(err instanceof webdriverError.NoSuchElementError || err instanceof webdriverError.TimeoutError) + assert( + err instanceof webdriverError.NoSuchElementError || + err instanceof webdriverError.TimeoutError, + ) } assert.ok(!dataTab, 'Found element that should not be present') } // Navigation - async navigate (page = Driver.PAGES.HOME) { + async navigate(page = Driver.PAGES.HOME) { return await this.driver.get(`${this.extensionUrl}/${page}.html`) } // Metrics - async collectMetrics () { + async collectMetrics() { return await this.driver.executeScript(collectMetrics) } // Window management - async openNewPage (url) { + async openNewPage(url) { const newHandle = await this.driver.switchTo().newWindow() await this.driver.get(url) return newHandle } - async switchToWindow (handle) { + async switchToWindow(handle) { await this.driver.switchTo().window(handle) } - async getAllWindowHandles () { + async getAllWindowHandles() { return await this.driver.getAllWindowHandles() } - async waitUntilXWindowHandles (x, delayStep = 1000, timeout = 5000) { + async waitUntilXWindowHandles(x, delayStep = 1000, timeout = 5000) { let timeElapsed = 0 let windowHandles = [] while (timeElapsed <= timeout) { @@ -136,9 +142,9 @@ class Driver { throw new Error('waitUntilXWindowHandles timed out polling window handles') } - async switchToWindowWithTitle (title, windowHandles) { + async switchToWindowWithTitle(title, windowHandles) { // eslint-disable-next-line no-param-reassign - windowHandles = windowHandles || await this.driver.getAllWindowHandles() + windowHandles = windowHandles || (await this.driver.getAllWindowHandles()) for (const handle of windowHandles) { await this.driver.switchTo().window(handle) @@ -157,9 +163,9 @@ class Driver { * @param {Array} [windowHandles] - The full list of window handles * @returns {Promise} */ - async closeAllWindowHandlesExcept (exceptions, windowHandles) { + async closeAllWindowHandlesExcept(exceptions, windowHandles) { // eslint-disable-next-line no-param-reassign - windowHandles = windowHandles || await this.driver.getAllWindowHandles() + windowHandles = windowHandles || (await this.driver.getAllWindowHandles()) for (const handle of windowHandles) { if (!exceptions.includes(handle)) { @@ -173,34 +179,46 @@ class Driver { // Error handling - async verboseReportOnFailure (title) { + async verboseReportOnFailure(title) { const artifactDir = `./test-artifacts/${this.browser}/${title}` const filepathBase = `${artifactDir}/test-failure` await fs.mkdir(artifactDir, { recursive: true }) const screenshot = await this.driver.takeScreenshot() - await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, { + encoding: 'base64', + }) const htmlSource = await this.driver.getPageSource() await fs.writeFile(`${filepathBase}-dom.html`, htmlSource) const uiState = await this.driver.executeScript( () => window.getCleanAppState && window.getCleanAppState(), ) - await fs.writeFile(`${filepathBase}-state.json`, JSON.stringify(uiState, null, 2)) + await fs.writeFile( + `${filepathBase}-state.json`, + JSON.stringify(uiState, null, 2), + ) } - async checkBrowserForConsoleErrors () { + async checkBrowserForConsoleErrors() { const ignoredLogTypes = ['WARNING'] const ignoredErrorMessages = [ // Third-party Favicon 404s show up as errors 'favicon.ico - Failed to load resource: the server responded with a status of 404 (Not Found)', ] const browserLogs = await this.driver.manage().logs().get('browser') - const errorEntries = browserLogs.filter((entry) => !ignoredLogTypes.includes(entry.level.toString())) + const errorEntries = browserLogs.filter( + (entry) => !ignoredLogTypes.includes(entry.level.toString()), + ) const errorObjects = errorEntries.map((entry) => entry.toJSON()) - return errorObjects.filter((entry) => !ignoredErrorMessages.some((message) => entry.message.includes(message))) + return errorObjects.filter( + (entry) => + !ignoredErrorMessages.some((message) => + entry.message.includes(message), + ), + ) } } -function collectMetrics () { +function collectMetrics() { const results = { paint: {}, navigation: [], @@ -210,15 +228,17 @@ function collectMetrics () { results.paint[paintEntry.name] = paintEntry.startTime }) - window.performance.getEntriesByType('navigation').forEach((navigationEntry) => { - results.navigation.push({ - domContentLoaded: navigationEntry.domContentLoadedEventEnd, - load: navigationEntry.loadEventEnd, - domInteractive: navigationEntry.domInteractive, - redirectCount: navigationEntry.redirectCount, - type: navigationEntry.type, + window.performance + .getEntriesByType('navigation') + .forEach((navigationEntry) => { + results.navigation.push({ + domContentLoaded: navigationEntry.domContentLoadedEventEnd, + load: navigationEntry.loadEventEnd, + domInteractive: navigationEntry.domInteractive, + redirectCount: navigationEntry.redirectCount, + type: navigationEntry.type, + }) }) - }) return results } diff --git a/test/e2e/webdriver/firefox.js b/test/e2e/webdriver/firefox.js index f5c8426ae..fe578dc63 100644 --- a/test/e2e/webdriver/firefox.js +++ b/test/e2e/webdriver/firefox.js @@ -20,22 +20,19 @@ const GeckoDriverCommand = { * A wrapper around a {@code WebDriver} instance exposing Firefox-specific functionality */ class FirefoxDriver { - /** * Builds a {@link FirefoxDriver} instance * @param {{extensionPath: string}} options - the options for the build * @returns {Promise<{driver: !ThenableWebDriver, extensionUrl: string, extensionId: string}>} */ - static async build ({ extensionPath, responsive, port }) { + static async build({ extensionPath, responsive, port }) { const templateProfile = fs.mkdtempSync(TEMP_PROFILE_PATH_PREFIX) - const options = new firefox.Options() - .setProfile(templateProfile) + const options = new firefox.Options().setProfile(templateProfile) const builder = new Builder() .forBrowser('firefox') .setFirefoxOptions(options) if (port) { - const service = new firefox.ServiceBuilder() - .setPort(port) + const service = new firefox.ServiceBuilder().setPort(port) builder.setFirefoxService(service) } const driver = builder.build() @@ -61,7 +58,7 @@ class FirefoxDriver { * @constructor * @param {!ThenableWebDriver} driver - a {@code WebDriver} instance */ - constructor (driver) { + constructor(driver) { this._driver = driver } @@ -69,8 +66,9 @@ class FirefoxDriver { * Initializes the driver * @returns {Promise} */ - async init () { - await this._driver.getExecutor() + async init() { + await this._driver + .getExecutor() .defineCommand( GeckoDriverCommand.INSTALL_ADDON, 'POST', @@ -83,7 +81,7 @@ class FirefoxDriver { * @param {string} addonPath - the path to the unpacked extension or XPI * @returns {Promise} - the extension ID */ - async installExtension (addonPath) { + async installExtension(addonPath) { const cmd = new Command(GeckoDriverCommand.INSTALL_ADDON) .setParameter('path', path.resolve(addonPath)) .setParameter('temporary', true) @@ -95,9 +93,16 @@ class FirefoxDriver { * Returns the Internal UUID for the given extension * @returns {Promise} - the Internal UUID for the given extension */ - async getInternalId () { + async getInternalId() { await this._driver.get('about:debugging#addons') - return await this._driver.wait(until.elementLocated(By.xpath('//dl/div[contains(., \'Internal UUID\')]/dd')), 1000).getText() + return await this._driver + .wait( + until.elementLocated( + By.xpath("//dl/div[contains(., 'Internal UUID')]/dd"), + ), + 1000, + ) + .getText() } } diff --git a/test/e2e/webdriver/index.js b/test/e2e/webdriver/index.js index 20be5d031..267287ff6 100644 --- a/test/e2e/webdriver/index.js +++ b/test/e2e/webdriver/index.js @@ -4,11 +4,15 @@ const Driver = require('./driver') const ChromeDriver = require('./chrome') const FirefoxDriver = require('./firefox') -async function buildWebDriver ({ responsive, port } = {}) { +async function buildWebDriver({ responsive, port } = {}) { const browser = process.env.SELENIUM_BROWSER const extensionPath = `dist/${browser}` - const { driver: seleniumDriver, extensionId, extensionUrl } = await buildBrowserWebDriver(browser, { extensionPath, responsive, port }) + const { + driver: seleniumDriver, + extensionId, + extensionUrl, + } = await buildBrowserWebDriver(browser, { extensionPath, responsive, port }) await setupFetchMocking(seleniumDriver) const driver = new Driver(seleniumDriver, browser, extensionUrl) await driver.navigate() @@ -21,7 +25,7 @@ async function buildWebDriver ({ responsive, port } = {}) { } } -async function buildBrowserWebDriver (browser, webDriverOptions) { +async function buildBrowserWebDriver(browser, webDriverOptions) { switch (browser) { case Browser.CHROME: { return await ChromeDriver.build(webDriverOptions) @@ -35,15 +39,17 @@ async function buildBrowserWebDriver (browser, webDriverOptions) { } } -async function setupFetchMocking (driver) { +async function setupFetchMocking(driver) { // define fetchMocking script, to be evaluated in the browser - function fetchMocking (mockResponses) { + function fetchMocking(mockResponses) { window.origFetch = window.fetch.bind(window) window.fetch = async (...args) => { const url = args[0] if (url.match(/^http(s)?:\/\/ethgasstation\.info\/json\/ethgasAPI.*/u)) { return { json: async () => clone(mockResponses.ethGasBasic) } - } else if (url.match(/http(s?):\/\/ethgasstation\.info\/json\/predictTable.*/u)) { + } else if ( + url.match(/http(s?):\/\/ethgasstation\.info\/json\/predictTable.*/u) + ) { return { json: async () => clone(mockResponses.ethGasPredictTable) } } else if (url.match(/chromeextensionmm/u)) { return { json: async () => clone(mockResponses.metametrics) } @@ -55,13 +61,17 @@ async function setupFetchMocking (driver) { return window.origFetch(...args) } if (window.chrome && window.chrome.webRequest) { - window.chrome.webRequest.onBeforeRequest.addListener(cancelInfuraRequest, { urls: ['https://*.infura.io/*'] }, ['blocking']) + window.chrome.webRequest.onBeforeRequest.addListener( + cancelInfuraRequest, + { urls: ['https://*.infura.io/*'] }, + ['blocking'], + ) } - function cancelInfuraRequest (requestDetails) { + function cancelInfuraRequest(requestDetails) { console.log(`fetchMocking - Canceling request: "${requestDetails.url}"`) return { cancel: true } } - function clone (obj) { + function clone(obj) { return JSON.parse(JSON.stringify(obj)) } } diff --git a/test/lib/createTxMeta.js b/test/lib/createTxMeta.js index 4dde18f62..715e40862 100644 --- a/test/lib/createTxMeta.js +++ b/test/lib/createTxMeta.js @@ -1,6 +1,6 @@ import { snapshotFromTxMeta } from '../../app/scripts/controllers/transactions/lib/tx-state-history-helpers' -export default function createTxMeta (partialMeta) { +export default function createTxMeta(partialMeta) { const txMeta = { status: 'unapproved', txParams: {}, diff --git a/test/lib/mock-encryptor.js b/test/lib/mock-encryptor.js index 5ea48e1e8..4b9f7faee 100644 --- a/test/lib/mock-encryptor.js +++ b/test/lib/mock-encryptor.js @@ -3,36 +3,34 @@ const mockKey = Buffer.alloc(32) let cacheVal const mockEncryptor = { - - encrypt (_, dataObj) { + encrypt(_, dataObj) { cacheVal = dataObj return Promise.resolve(mockHex) }, - decrypt () { + decrypt() { return Promise.resolve(cacheVal || {}) }, - encryptWithKey (key, dataObj) { + encryptWithKey(key, dataObj) { return this.encrypt(key, dataObj) }, - decryptWithKey (key, text) { + decryptWithKey(key, text) { return this.decrypt(key, text) }, - keyFromPassword () { + keyFromPassword() { return Promise.resolve(mockKey) }, - generateSalt () { + generateSalt() { return 'WHADDASALT!' }, - getRandomValues () { + getRandomValues() { return 'SOO RANDO!!!1' }, - } export default mockEncryptor diff --git a/test/lib/render-helpers.js b/test/lib/render-helpers.js index 09920ee7b..b8d6be450 100644 --- a/test/lib/render-helpers.js +++ b/test/lib/render-helpers.js @@ -6,8 +6,7 @@ import { MemoryRouter } from 'react-router-dom' import PropTypes from 'prop-types' import { LegacyI18nProvider } from '../../ui/app/contexts/i18n' -export function mountWithRouter (component, store = {}, pathname = '/') { - +export function mountWithRouter(component, store = {}, pathname = '/') { // Instantiate router context const router = { history: new MemoryRouter().history, @@ -43,13 +42,10 @@ export function mountWithRouter (component, store = {}, pathname = '/') { return mount(, createContext()) } -export function renderWithProvider (component, store) { - +export function renderWithProvider(component, store) { const Wrapper = () => ( - - { component } - + {component} ) diff --git a/test/lib/wait-until-called.js b/test/lib/wait-until-called.js index 6e9f5e1b4..7a2eb2704 100644 --- a/test/lib/wait-until-called.js +++ b/test/lib/wait-until-called.js @@ -11,7 +11,7 @@ * @param {unknown} [wrappedThis] - The object the stubbed function was called on, if any (i.e. the `this` value) * @returns {Promise} A Promise that resolves when the stub has been called */ -export default function waitUntilCalled (stub, wrappedThis = null) { +export default function waitUntilCalled(stub, wrappedThis = null) { let wasCalled const stubHasBeenCalled = new Promise((resolve) => { wasCalled = resolve diff --git a/test/stub/provider.js b/test/stub/provider.js index 4ff63297a..40fd95258 100644 --- a/test/stub/provider.js +++ b/test/stub/provider.js @@ -3,38 +3,60 @@ import scaffoldMiddleware from 'eth-json-rpc-middleware/scaffold' import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware' import GanacheCore from 'ganache-core' -export function getTestSeed () { +export function getTestSeed() { return 'people carpet cluster attract ankle motor ozone mass dove original primary mask' } -export function getTestAccounts () { +export function getTestAccounts() { return [ - { address: '0x88bb7F89eB5e5b30D3e15a57C68DBe03C6aCCB21', key: Buffer.from('254A8D551474F35CCC816388B4ED4D20B945C96B7EB857A68064CB9E9FB2C092', 'hex') }, - { address: '0x1fe9aAB565Be19629fF4e8541ca2102fb42D7724', key: Buffer.from('6BAB5A4F2A6911AF8EE2BD32C6C05F6643AC48EF6C939CDEAAAE6B1620805A9B', 'hex') }, - { address: '0xbda5c89aa6bA1b352194291AD6822C92AbC87c7B', key: Buffer.from('9B11D7F833648F26CE94D544855558D7053ECD396E4F4563968C232C012879B0', 'hex') }, + { + address: '0x88bb7F89eB5e5b30D3e15a57C68DBe03C6aCCB21', + key: Buffer.from( + '254A8D551474F35CCC816388B4ED4D20B945C96B7EB857A68064CB9E9FB2C092', + 'hex', + ), + }, + { + address: '0x1fe9aAB565Be19629fF4e8541ca2102fb42D7724', + key: Buffer.from( + '6BAB5A4F2A6911AF8EE2BD32C6C05F6643AC48EF6C939CDEAAAE6B1620805A9B', + 'hex', + ), + }, + { + address: '0xbda5c89aa6bA1b352194291AD6822C92AbC87c7B', + key: Buffer.from( + '9B11D7F833648F26CE94D544855558D7053ECD396E4F4563968C232C012879B0', + 'hex', + ), + }, ] } -export function createEngineForTestData () { +export function createEngineForTestData() { return new JsonRpcEngine() } -export function providerFromEngine (engine) { +export function providerFromEngine(engine) { const provider = { sendAsync: engine.handle.bind(engine) } return provider } -export function createTestProviderTools (opts = {}) { +export function createTestProviderTools(opts = {}) { const engine = createEngineForTestData() // handle provided hooks engine.push(scaffoldMiddleware(opts.scaffold || {})) // handle block tracker methods - engine.push(providerAsMiddleware(GanacheCore.provider({ - mnemonic: getTestSeed(), - network_id: opts.networkId, - _chainId: opts.chainId, - _chainIdRpc: opts.chainId, - }))) + engine.push( + providerAsMiddleware( + GanacheCore.provider({ + mnemonic: getTestSeed(), + network_id: opts.networkId, + _chainId: opts.chainId, + _chainIdRpc: opts.chainId, + }), + ), + ) // wrap in standard provider interface const provider = providerFromEngine(engine) return { provider, engine } diff --git a/test/unit-global/frozenPromise.js b/test/unit-global/frozenPromise.js index 594c1350a..6583e1edf 100644 --- a/test/unit-global/frozenPromise.js +++ b/test/unit-global/frozenPromise.js @@ -3,7 +3,6 @@ import '../../app/scripts/lib/freezeGlobals' import assert from 'assert' describe('Promise global is immutable', function () { - it('throws when reassinging promise (syntax 1)', function () { try { // eslint-disable-next-line no-global-assign,no-native-reassign diff --git a/test/unit/actions/set_account_label_test.js b/test/unit/actions/set_account_label_test.js index 67ad701ed..7a79bd0b4 100644 --- a/test/unit/actions/set_account_label_test.js +++ b/test/unit/actions/set_account_label_test.js @@ -26,7 +26,9 @@ describe('SET_ACCOUNT_LABEL', function () { freeze(action) const resultingState = reducers(initialState, action) - assert.equal(resultingState.metamask.identities.foo.name, action.value.label) + assert.equal( + resultingState.metamask.identities.foo.name, + action.value.label, + ) }) }) - diff --git a/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js index a21824688..99b27689f 100644 --- a/test/unit/actions/tx_test.js +++ b/test/unit/actions/tx_test.js @@ -10,8 +10,7 @@ const mockStore = configureMockStore(middlewares) describe('tx confirmation screen', function () { const txId = 1457634084250832 const initialState = { - appState: { - }, + appState: {}, metamask: { unapprovedTxs: { [txId]: { @@ -28,20 +27,22 @@ describe('tx confirmation screen', function () { describe('cancelTx', function () { it('creates COMPLETED_TX with the cancelled transaction ID', async function () { actions._setBackgroundConnection({ - approveTransaction (_, cb) { + approveTransaction(_, cb) { cb(new Error('An error!')) }, - cancelTransaction (_, cb) { + cancelTransaction(_, cb) { cb() }, - getState (cb) { + getState(cb) { cb(null, {}) }, }) await store.dispatch(actions.cancelTx({ id: txId })) const storeActions = store.getActions() - const completedTxAction = storeActions.find(({ type }) => type === actionConstants.COMPLETED_TX) + const completedTxAction = storeActions.find( + ({ type }) => type === actionConstants.COMPLETED_TX, + ) const { id } = completedTxAction.value assert.equal(id, txId) }) diff --git a/test/unit/actions/warning_test.js b/test/unit/actions/warning_test.js index 70aed3c59..a59b40f92 100644 --- a/test/unit/actions/warning_test.js +++ b/test/unit/actions/warning_test.js @@ -15,6 +15,10 @@ describe('action DISPLAY_WARNING', function () { const action = actions.displayWarning(warningText) const resultingState = reducers(initialState, action) - assert.equal(resultingState.appState.warning, warningText, 'warning text set') + assert.equal( + resultingState.appState.warning, + warningText, + 'warning text set', + ) }) }) diff --git a/test/unit/app/account-import-strategies.spec.js b/test/unit/app/account-import-strategies.spec.js index 3c6b6fbef..8918bd064 100644 --- a/test/unit/app/account-import-strategies.spec.js +++ b/test/unit/app/account-import-strategies.spec.js @@ -3,19 +3,27 @@ import ethUtil from 'ethereumjs-util' import accountImporter from '../../../app/scripts/account-import-strategies' describe('Account Import Strategies', function () { - const privkey = '0x4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' - const json = '{"version":3,"id":"dbb54385-0a99-437f-83c0-647de9f244c3","address":"a7f92ce3fba24196cf6f4bd2e1eb3db282ba998c","Crypto":{"ciphertext":"bde13d9ade5c82df80281ca363320ce254a8a3a06535bbf6ffdeaf0726b1312c","cipherparams":{"iv":"fbf93718a57f26051b292f072f2e5b41"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"7ffe00488319dec48e4c49a120ca49c6afbde9272854c64d9541c83fc6acdffe","n":8192,"r":8,"p":1},"mac":"2adfd9c4bc1cdac4c85bddfb31d9e21a684e0e050247a70c5698facf6b7d4681"}}' + const privkey = + '0x4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' + const json = + '{"version":3,"id":"dbb54385-0a99-437f-83c0-647de9f244c3","address":"a7f92ce3fba24196cf6f4bd2e1eb3db282ba998c","Crypto":{"ciphertext":"bde13d9ade5c82df80281ca363320ce254a8a3a06535bbf6ffdeaf0726b1312c","cipherparams":{"iv":"fbf93718a57f26051b292f072f2e5b41"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"7ffe00488319dec48e4c49a120ca49c6afbde9272854c64d9541c83fc6acdffe","n":8192,"r":8,"p":1},"mac":"2adfd9c4bc1cdac4c85bddfb31d9e21a684e0e050247a70c5698facf6b7d4681"}}' describe('private key import', function () { it('imports a private key and strips 0x prefix', async function () { - const importPrivKey = await accountImporter.importAccount('Private Key', [privkey]) + const importPrivKey = await accountImporter.importAccount('Private Key', [ + privkey, + ]) assert.equal(importPrivKey, ethUtil.stripHexPrefix(privkey)) }) it('throws an error for empty string private key', async function () { - await assert.rejects(async () => { - await accountImporter.importAccount('Private Key', ['']) - }, Error, 'no empty strings') + await assert.rejects( + async () => { + await accountImporter.importAccount('Private Key', ['']) + }, + Error, + 'no empty strings', + ) }) it('throws an error for undefined string private key', async function () { @@ -42,14 +50,23 @@ describe('Account Import Strategies', function () { try { await accountImporter.importAccount('JSON File', [json, wrongPassword]) } catch (error) { - assert.equal(error.message, 'Key derivation failed - possibly wrong passphrase') + assert.equal( + error.message, + 'Key derivation failed - possibly wrong passphrase', + ) } }) it('imports json string and password to return a private key', async function () { const fileContentsPassword = 'password1' - const importJson = await accountImporter.importAccount('JSON File', [json, fileContentsPassword]) - assert.equal(importJson, '0x5733876abe94146069ce8bcbabbde2677f2e35fa33e875e92041ed2ac87e5bc7') + const importJson = await accountImporter.importAccount('JSON File', [ + json, + fileContentsPassword, + ]) + assert.equal( + importJson, + '0x5733876abe94146069ce8bcbabbde2677f2e35fa33e875e92041ed2ac87e5bc7', + ) }) }) }) diff --git a/test/unit/app/buy-eth-url.spec.js b/test/unit/app/buy-eth-url.spec.js index 7dc895e8d..749d0a40f 100644 --- a/test/unit/app/buy-eth-url.spec.js +++ b/test/unit/app/buy-eth-url.spec.js @@ -20,8 +20,10 @@ describe('buy-eth-url', function () { it('returns wyre url with address for network 1', function () { const wyreUrl = getBuyEthUrl(mainnet) - assert.equal(wyreUrl, 'https://pay.sendwyre.com/purchase?dest=ethereum:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card') - + assert.equal( + wyreUrl, + 'https://pay.sendwyre.com/purchase?dest=ethereum:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card', + ) }) it('returns metamask ropsten faucet for network 3', function () { @@ -38,5 +40,4 @@ describe('buy-eth-url', function () { const kovanUrl = getBuyEthUrl(kovan) assert.equal(kovanUrl, 'https://github.com/kovan-testnet/faucet') }) - }) diff --git a/test/unit/app/cleanErrorStack.spec.js b/test/unit/app/cleanErrorStack.spec.js index fa793b605..5aa63cb4c 100644 --- a/test/unit/app/cleanErrorStack.spec.js +++ b/test/unit/app/cleanErrorStack.spec.js @@ -2,7 +2,6 @@ import assert from 'assert' import cleanErrorStack from '../../../app/scripts/lib/cleanErrorStack' describe('Clean Error Stack', function () { - const testMessage = 'Test Message' const testError = new Error(testMessage) const undefinedErrorName = new Error(testMessage) @@ -19,7 +18,10 @@ describe('Clean Error Stack', function () { }) it('tests error with undefined name', function () { - assert.equal(cleanErrorStack(undefinedErrorName).toString(), 'Error: Test Message') + assert.equal( + cleanErrorStack(undefinedErrorName).toString(), + 'Error: Test Message', + ) }) it('tests error with blank name', function () { @@ -29,5 +31,4 @@ describe('Clean Error Stack', function () { it('tests error with blank message', function () { assert.equal(cleanErrorStack(blankMsgError), 'Error') }) - }) diff --git a/test/unit/app/controllers/cached-balances-test.js b/test/unit/app/controllers/cached-balances-test.js index f954da63f..8a7fb61ae 100644 --- a/test/unit/app/controllers/cached-balances-test.js +++ b/test/unit/app/controllers/cached-balances-test.js @@ -17,13 +17,21 @@ describe('CachedBalancesController', function () { }, }) - controller._generateBalancesToCache = sinon.stub().callsFake(() => Promise.resolve('mockNewCachedBalances')) + controller._generateBalancesToCache = sinon + .stub() + .callsFake(() => Promise.resolve('mockNewCachedBalances')) await controller.updateCachedBalances({ accounts: 'mockAccounts' }) assert.equal(controller._generateBalancesToCache.callCount, 1) - assert.deepEqual(controller._generateBalancesToCache.args[0], ['mockAccounts', 17]) - assert.equal(controller.store.getState().cachedBalances, 'mockNewCachedBalances') + assert.deepEqual(controller._generateBalancesToCache.args[0], [ + 'mockAccounts', + 17, + ]) + assert.equal( + controller.store.getState().cachedBalances, + 'mockNewCachedBalances', + ) }) }) @@ -51,11 +59,14 @@ describe('CachedBalancesController', function () { }, }) - const result = controller._generateBalancesToCache({ - a: { balance: '0x4' }, - b: { balance: null }, - c: { balance: '0x5' }, - }, 17) + const result = controller._generateBalancesToCache( + { + a: { balance: '0x4' }, + b: { balance: null }, + c: { balance: '0x5' }, + }, + 17, + ) assert.deepEqual(result, { 17: { @@ -89,11 +100,14 @@ describe('CachedBalancesController', function () { }, }) - const result = controller._generateBalancesToCache({ - a: { balance: '0x4' }, - b: { balance: null }, - c: { balance: '0x5' }, - }, 16) + const result = controller._generateBalancesToCache( + { + a: { balance: '0x4' }, + b: { balance: null }, + c: { balance: '0x5' }, + }, + 16, + ) assert.deepEqual(result, { 17: { @@ -133,5 +147,4 @@ describe('CachedBalancesController', function () { assert.equal(updateCachedBalancesSpy.callCount, 1) }) }) - }) diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index 6798703c1..8f3a5a52c 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -7,7 +7,10 @@ import BigNumber from 'bignumber.js' import DetectTokensController from '../../../../app/scripts/controllers/detect-tokens' import NetworkController from '../../../../app/scripts/controllers/network/network' import PreferencesController from '../../../../app/scripts/controllers/preferences' -import { MAINNET, ROPSTEN } from '../../../../app/scripts/controllers/network/enums' +import { + MAINNET, + ROPSTEN, +} from '../../../../app/scripts/controllers/network/enums' describe('DetectTokensController', function () { const sandbox = sinon.createSandbox() @@ -29,7 +32,6 @@ describe('DetectTokensController', function () { '0xbc86727e770de68b1060c91f6bb6945c73e10388', ]) network.initializeProvider(networkControllerProviderConfig) - }) after(function () { @@ -46,7 +48,11 @@ describe('DetectTokensController', function () { it('should be called on every polling period', async function () { const clock = sandbox.useFakeTimers() network.setProviderType(MAINNET) - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) controller.isOpen = true controller.isUnlocked = true @@ -65,7 +71,11 @@ describe('DetectTokensController', function () { it('should not check tokens while on test network', async function () { sandbox.useFakeTimers() network.setProviderType(ROPSTEN) - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) controller.isOpen = true controller.isUnlocked = true @@ -78,55 +88,83 @@ describe('DetectTokensController', function () { it('should check and add tokens while on main network', async function () { sandbox.useFakeTimers() network.setProviderType(MAINNET) - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) controller.isOpen = true controller.isUnlocked = true const contractAddresses = Object.keys(contracts) - const erc20ContractAddresses = contractAddresses - .filter((contractAddress) => contracts[contractAddress].erc20 === true) + const erc20ContractAddresses = contractAddresses.filter( + (contractAddress) => contracts[contractAddress].erc20 === true, + ) const existingTokenAddress = erc20ContractAddresses[0] const existingToken = contracts[existingTokenAddress] - await preferences.addToken(existingTokenAddress, existingToken.symbol, existingToken.decimals) + await preferences.addToken( + existingTokenAddress, + existingToken.symbol, + existingToken.decimals, + ) const tokenAddressToAdd = erc20ContractAddresses[1] const tokenToAdd = contracts[tokenAddressToAdd] - const contractAddresssesToDetect = contractAddresses - .filter((address) => address !== existingTokenAddress) - const indexOfTokenToAdd = contractAddresssesToDetect.indexOf(tokenAddressToAdd) + const contractAddresssesToDetect = contractAddresses.filter( + (address) => address !== existingTokenAddress, + ) + const indexOfTokenToAdd = contractAddresssesToDetect.indexOf( + tokenAddressToAdd, + ) const balances = new Array(contractAddresssesToDetect.length) balances[indexOfTokenToAdd] = new BigNumber(10) - sandbox.stub(controller, '_getTokenBalances') + sandbox + .stub(controller, '_getTokenBalances') .returns(Promise.resolve(balances)) await controller.detectNewTokens() - assert.deepEqual( - preferences.store.getState().tokens, - [ - { address: existingTokenAddress.toLowerCase(), decimals: existingToken.decimals, symbol: existingToken.symbol }, - { address: tokenAddressToAdd.toLowerCase(), decimals: tokenToAdd.decimals, symbol: tokenToAdd.symbol }, - ], - ) + assert.deepEqual(preferences.store.getState().tokens, [ + { + address: existingTokenAddress.toLowerCase(), + decimals: existingToken.decimals, + symbol: existingToken.symbol, + }, + { + address: tokenAddressToAdd.toLowerCase(), + decimals: tokenToAdd.decimals, + symbol: tokenToAdd.symbol, + }, + ]) }) it('should trigger detect new tokens when change address', async function () { sandbox.useFakeTimers() - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) controller.isOpen = true controller.isUnlocked = true const stub = sandbox.stub(controller, 'detectNewTokens') - await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388') + await preferences.setSelectedAddress( + '0xbc86727e770de68b1060c91f6bb6945c73e10388', + ) sandbox.assert.called(stub) }) it('should trigger detect new tokens when submit password', async function () { sandbox.useFakeTimers() - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) controller.isOpen = true controller.selectedAddress = '0x0' const stub = sandbox.stub(controller, 'detectNewTokens') @@ -137,7 +175,11 @@ describe('DetectTokensController', function () { it('should not trigger detect new tokens when not unlocked', async function () { const clock = sandbox.useFakeTimers() network.setProviderType(MAINNET) - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) controller.isOpen = true controller.isUnlocked = false const stub = sandbox.stub(controller, '_getTokenBalances') @@ -148,9 +190,15 @@ describe('DetectTokensController', function () { it('should not trigger detect new tokens when not open', async function () { const clock = sandbox.useFakeTimers() network.setProviderType(MAINNET) - const controller = new DetectTokensController({ preferences, network, keyringMemStore }) + const controller = new DetectTokensController({ + preferences, + network, + keyringMemStore, + }) // trigger state update from preferences controller - await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388') + await preferences.setSelectedAddress( + '0xbc86727e770de68b1060c91f6bb6945c73e10388', + ) controller.isOpen = false controller.isUnlocked = true const stub = sandbox.stub(controller, '_getTokenBalances') diff --git a/test/unit/app/controllers/ens-controller-test.js b/test/unit/app/controllers/ens-controller-test.js index cf57bdf1f..0fbaf33ac 100644 --- a/test/unit/app/controllers/ens-controller-test.js +++ b/test/unit/app/controllers/ens-controller-test.js @@ -12,7 +12,7 @@ describe('EnsController', function () { const currentNetworkId = '3' const networkStore = new ObservableStore(currentNetworkId) const ens = new EnsController({ - provider: { }, + provider: {}, networkStore, }) @@ -117,7 +117,10 @@ describe('EnsController', function () { const ens = new EnsController({ ens: { reverse: sinon.stub().withArgs(address).returns('peaksignal.eth'), - lookup: sinon.stub().withArgs('peaksignal.eth').returns(ZERO_X_ERROR_ADDRESS), + lookup: sinon + .stub() + .withArgs('peaksignal.eth') + .returns(ZERO_X_ERROR_ADDRESS), }, networkStore, }) diff --git a/test/unit/app/controllers/incoming-transactions-test.js b/test/unit/app/controllers/incoming-transactions-test.js index a227cf95f..2f40f43a0 100644 --- a/test/unit/app/controllers/incoming-transactions-test.js +++ b/test/unit/app/controllers/incoming-transactions-test.js @@ -16,14 +16,17 @@ import { ROPSTEN_NETWORK_ID, } from '../../../../app/scripts/controllers/network/enums' -const IncomingTransactionsController = proxyquire('../../../../app/scripts/controllers/incoming-transactions', { - '../lib/random-id': { default: () => 54321 }, -}).default +const IncomingTransactionsController = proxyquire( + '../../../../app/scripts/controllers/incoming-transactions', + { + '../lib/random-id': { default: () => 54321 }, + }, +).default const FAKE_CHAIN_ID = '0x1338' const MOCK_SELECTED_ADDRESS = '0x0101' -function getEmptyInitState () { +function getEmptyInitState() { return { incomingTransactions: {}, incomingTxLastFetchedBlocksByNetwork: { @@ -36,7 +39,7 @@ function getEmptyInitState () { } } -function getNonEmptyInitState () { +function getNonEmptyInitState() { return { incomingTransactions: { '0x123456': { id: 777 }, @@ -51,14 +54,16 @@ function getNonEmptyInitState () { } } -function getMockNetworkController (chainId = FAKE_CHAIN_ID) { +function getMockNetworkController(chainId = FAKE_CHAIN_ID) { return { getCurrentChainId: () => chainId, on: sinon.spy(), } } -function getMockPreferencesController ({ showIncomingTransactions = true } = {}) { +function getMockPreferencesController({ + showIncomingTransactions = true, +} = {}) { return { getSelectedAddress: sinon.stub().returns(MOCK_SELECTED_ADDRESS), store: { @@ -72,7 +77,7 @@ function getMockPreferencesController ({ showIncomingTransactions = true } = {}) } } -function getMockBlockTracker () { +function getMockBlockTracker() { return { addListener: sinon.stub().callsArgWithAsync(1, '0xa'), removeListener: sinon.spy(), @@ -107,7 +112,10 @@ function getMockBlockTracker () { * @param {number} [blockNumber] - The block number for the transaction * @returns {EtherscanTransaction} */ -const getFakeEtherscanTransaction = (toAddress = MOCK_SELECTED_ADDRESS, blockNumber = 10) => { +const getFakeEtherscanTransaction = ( + toAddress = MOCK_SELECTED_ADDRESS, + blockNumber = 10, +) => { return { blockNumber: blockNumber.toString(), from: '0xfake', @@ -123,7 +131,6 @@ const getFakeEtherscanTransaction = (toAddress = MOCK_SELECTED_ADDRESS, blockNum } describe('IncomingTransactionsController', function () { - afterEach(function () { sinon.restore() nock.cleanAll() @@ -131,66 +138,95 @@ describe('IncomingTransactionsController', function () { describe('constructor', function () { it('should set up correct store, listeners and properties in the constructor', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(), - preferencesController: getMockPreferencesController(), - initState: {}, - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(), + preferencesController: getMockPreferencesController(), + initState: {}, + }, + ) sinon.spy(incomingTransactionsController, '_update') - assert.deepEqual(incomingTransactionsController.store.getState(), getEmptyInitState()) + assert.deepEqual( + incomingTransactionsController.store.getState(), + getEmptyInitState(), + ) assert(incomingTransactionsController.networkController.on.calledOnce) - assert.equal(incomingTransactionsController.networkController.on.getCall(0).args[0], 'networkDidChange') - const networkControllerListenerCallback = incomingTransactionsController.networkController.on.getCall(0).args[1] + assert.equal( + incomingTransactionsController.networkController.on.getCall(0).args[0], + 'networkDidChange', + ) + const networkControllerListenerCallback = incomingTransactionsController.networkController.on.getCall( + 0, + ).args[1] assert.equal(incomingTransactionsController._update.callCount, 0) networkControllerListenerCallback('testNetworkType') assert.equal(incomingTransactionsController._update.callCount, 1) - assert.deepEqual(incomingTransactionsController._update.getCall(0).args[0], { - address: '0x0101', - }) + assert.deepEqual( + incomingTransactionsController._update.getCall(0).args[0], + { + address: '0x0101', + }, + ) incomingTransactionsController._update.resetHistory() }) it('should set the store to a provided initial state', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - assert.deepEqual(incomingTransactionsController.store.getState(), getNonEmptyInitState()) + assert.deepEqual( + incomingTransactionsController.store.getState(), + getNonEmptyInitState(), + ) }) }) describe('update events', function () { it('should set up a listener for the latest block', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(), - preferencesController: getMockPreferencesController(), - initState: {}, - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(), + preferencesController: getMockPreferencesController(), + initState: {}, + }, + ) incomingTransactionsController.start() assert(incomingTransactionsController.blockTracker.addListener.calledOnce) - assert.equal(incomingTransactionsController.blockTracker.addListener.getCall(0).args[0], 'latest') + assert.equal( + incomingTransactionsController.blockTracker.addListener.getCall(0) + .args[0], + 'latest', + ) }) it('should update upon latest block when started and on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) - const startBlock = getNonEmptyInitState().incomingTxLastFetchedBlocksByNetwork[ROPSTEN] + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) + const startBlock = getNonEmptyInitState() + .incomingTxLastFetchedBlocksByNetwork[ROPSTEN] nock('https://api-ropsten.etherscan.io') - .get(`/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`) + .get( + `/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`, + ) .reply( 200, JSON.stringify({ @@ -198,8 +234,14 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction()], }), ) - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) incomingTransactionsController.start() await updateStateCalled @@ -210,7 +252,10 @@ describe('IncomingTransactionsController', function () { const actualStateWithoutGenerated = cloneDeep(actualState) delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id - assert.ok(typeof generatedTxId === 'number' && generatedTxId > 0, 'Generated transaction ID should be a positive number') + assert.ok( + typeof generatedTxId === 'number' && generatedTxId > 0, + 'Generated transaction ID should be a positive number', + ) assert.deepStrictEqual( actualStateWithoutGenerated, { @@ -243,15 +288,21 @@ describe('IncomingTransactionsController', function () { }) it('should not update upon latest block when started and not on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) // reply with a valid request for any supported network, so that this test has every opportunity to fail for (const network of [GOERLI, KOVAN, MAINNET, RINKEBY, ROPSTEN]) { - nock(`https://api${network === MAINNET ? '' : `-${network.toLowerCase()}`}.etherscan.io`) + nock( + `https://api${ + network === MAINNET ? '' : `-${network.toLowerCase()}` + }.etherscan.io`, + ) .get(/api.+/u) .reply( 200, @@ -261,10 +312,22 @@ describe('IncomingTransactionsController', function () { }), ) } - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) - const putStateStub = sinon.stub(incomingTransactionsController.store, 'putState') - const putStateCalled = waitUntilCalled(putStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) + const putStateStub = sinon.stub( + incomingTransactionsController.store, + 'putState', + ) + const putStateCalled = waitUntilCalled( + putStateStub, + incomingTransactionsController.store, + ) incomingTransactionsController.start() @@ -283,15 +346,23 @@ describe('IncomingTransactionsController', function () { }) it('should not update upon latest block when started and incoming transactions disabled', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(), - preferencesController: getMockPreferencesController({ showIncomingTransactions: false }), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(), + preferencesController: getMockPreferencesController({ + showIncomingTransactions: false, + }), + initState: getNonEmptyInitState(), + }, + ) // reply with a valid request for any supported network, so that this test has every opportunity to fail for (const network of [GOERLI, KOVAN, MAINNET, RINKEBY, ROPSTEN]) { - nock(`https://api${network === MAINNET ? '' : `-${network.toLowerCase()}`}.etherscan.io`) + nock( + `https://api${ + network === MAINNET ? '' : `-${network.toLowerCase()}` + }.etherscan.io`, + ) .get(/api.+/u) .reply( 200, @@ -301,10 +372,22 @@ describe('IncomingTransactionsController', function () { }), ) } - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) - const putStateStub = sinon.stub(incomingTransactionsController.store, 'putState') - const putStateCalled = waitUntilCalled(putStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) + const putStateStub = sinon.stub( + incomingTransactionsController.store, + 'putState', + ) + const putStateCalled = waitUntilCalled( + putStateStub, + incomingTransactionsController.store, + ) incomingTransactionsController.start() @@ -323,15 +406,21 @@ describe('IncomingTransactionsController', function () { }) it('should not update upon latest block when not started', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) // reply with a valid request for any supported network, so that this test has every opportunity to fail for (const network of [GOERLI, KOVAN, MAINNET, RINKEBY, ROPSTEN]) { - nock(`https://api${network === MAINNET ? '' : `-${network.toLowerCase()}`}.etherscan.io`) + nock( + `https://api${ + network === MAINNET ? '' : `-${network.toLowerCase()}` + }.etherscan.io`, + ) .get(/api.+/u) .reply( 200, @@ -341,10 +430,22 @@ describe('IncomingTransactionsController', function () { }), ) } - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) - const putStateStub = sinon.stub(incomingTransactionsController.store, 'putState') - const putStateCalled = waitUntilCalled(putStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) + const putStateStub = sinon.stub( + incomingTransactionsController.store, + 'putState', + ) + const putStateCalled = waitUntilCalled( + putStateStub, + incomingTransactionsController.store, + ) try { await Promise.race([ @@ -361,15 +462,21 @@ describe('IncomingTransactionsController', function () { }) it('should not update upon latest block when stopped', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) // reply with a valid request for any supported network, so that this test has every opportunity to fail for (const network of [GOERLI, KOVAN, MAINNET, RINKEBY, ROPSTEN]) { - nock(`https://api${network === MAINNET ? '' : `-${network.toLowerCase()}`}.etherscan.io`) + nock( + `https://api${ + network === MAINNET ? '' : `-${network.toLowerCase()}` + }.etherscan.io`, + ) .get(/api.+/u) .reply( 200, @@ -379,10 +486,22 @@ describe('IncomingTransactionsController', function () { }), ) } - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) - const putStateStub = sinon.stub(incomingTransactionsController.store, 'putState') - const putStateCalled = waitUntilCalled(putStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) + const putStateStub = sinon.stub( + incomingTransactionsController.store, + 'putState', + ) + const putStateCalled = waitUntilCalled( + putStateStub, + incomingTransactionsController.store, + ) incomingTransactionsController.stop() @@ -401,16 +520,21 @@ describe('IncomingTransactionsController', function () { }) it('should update when the selected address changes and on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) const NEW_MOCK_SELECTED_ADDRESS = `${MOCK_SELECTED_ADDRESS}9` - const startBlock = getNonEmptyInitState().incomingTxLastFetchedBlocksByNetwork[ROPSTEN] + const startBlock = getNonEmptyInitState() + .incomingTxLastFetchedBlocksByNetwork[ROPSTEN] nock('https://api-ropsten.etherscan.io') - .get(`/api?module=account&action=txlist&address=${NEW_MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`) + .get( + `/api?module=account&action=txlist&address=${NEW_MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`, + ) .reply( 200, JSON.stringify({ @@ -418,10 +542,18 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction(NEW_MOCK_SELECTED_ADDRESS)], }), ) - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) - const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall(1).args[0] + const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall( + 1, + ).args[0] // The incoming transactions controller will always skip the first event // We need to call subscription twice to test the event handling // TODO: stop skipping the first event @@ -435,7 +567,10 @@ describe('IncomingTransactionsController', function () { const actualStateWithoutGenerated = cloneDeep(actualState) delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id - assert.ok(typeof generatedTxId === 'number' && generatedTxId > 0, 'Generated transaction ID should be a positive number') + assert.ok( + typeof generatedTxId === 'number' && generatedTxId > 0, + 'Generated transaction ID should be a positive number', + ) assert.deepStrictEqual( actualStateWithoutGenerated, { @@ -468,16 +603,22 @@ describe('IncomingTransactionsController', function () { }) it('should not update when the selected address changes and not on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: { ...getMockBlockTracker() }, - networkController: getMockNetworkController(), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: { ...getMockBlockTracker() }, + networkController: getMockNetworkController(), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) const NEW_MOCK_SELECTED_ADDRESS = `${MOCK_SELECTED_ADDRESS}9` // reply with a valid request for any supported network, so that this test has every opportunity to fail for (const network of [GOERLI, KOVAN, MAINNET, RINKEBY, ROPSTEN]) { - nock(`https://api${network === MAINNET ? '' : `-${network.toLowerCase()}`}.etherscan.io`) + nock( + `https://api${ + network === MAINNET ? '' : `-${network.toLowerCase()}` + }.etherscan.io`, + ) .get(/api.+/u) .reply( 200, @@ -487,12 +628,26 @@ describe('IncomingTransactionsController', function () { }), ) } - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) - const putStateStub = sinon.stub(incomingTransactionsController.store, 'putState') - const putStateCalled = waitUntilCalled(putStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) + const putStateStub = sinon.stub( + incomingTransactionsController.store, + 'putState', + ) + const putStateCalled = waitUntilCalled( + putStateStub, + incomingTransactionsController.store, + ) - const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall(1).args[0] + const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall( + 1, + ).args[0] // The incoming transactions controller will always skip the first event // We need to call subscription twice to test the event handling // TODO: stop skipping the first event @@ -514,15 +669,20 @@ describe('IncomingTransactionsController', function () { }) it('should update when switching to a supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) - const startBlock = getNonEmptyInitState().incomingTxLastFetchedBlocksByNetwork[ROPSTEN] + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) + const startBlock = getNonEmptyInitState() + .incomingTxLastFetchedBlocksByNetwork[ROPSTEN] nock('https://api-ropsten.etherscan.io') - .get(`/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`) + .get( + `/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`, + ) .reply( 200, JSON.stringify({ @@ -530,11 +690,21 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction()], }), ) - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) - const subscription = incomingTransactionsController.networkController.on.getCall(0).args[1] - incomingTransactionsController.networkController = getMockNetworkController(ROPSTEN_CHAIN_ID) + const subscription = incomingTransactionsController.networkController.on.getCall( + 0, + ).args[1] + incomingTransactionsController.networkController = getMockNetworkController( + ROPSTEN_CHAIN_ID, + ) await subscription(ROPSTEN) await updateStateCalled @@ -544,7 +714,10 @@ describe('IncomingTransactionsController', function () { const actualStateWithoutGenerated = cloneDeep(actualState) delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id - assert.ok(typeof generatedTxId === 'number' && generatedTxId > 0, 'Generated transaction ID should be a positive number') + assert.ok( + typeof generatedTxId === 'number' && generatedTxId > 0, + 'Generated transaction ID should be a positive number', + ) assert.deepStrictEqual( actualStateWithoutGenerated, { @@ -578,15 +751,21 @@ describe('IncomingTransactionsController', function () { it('should not update when switching to an unsupported network', async function () { const networkController = getMockNetworkController(ROPSTEN_CHAIN_ID) - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController, - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController, + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) // reply with a valid request for any supported network, so that this test has every opportunity to fail for (const network of [GOERLI, KOVAN, MAINNET, RINKEBY, ROPSTEN]) { - nock(`https://api${network === MAINNET ? '' : `-${network.toLowerCase()}`}.etherscan.io`) + nock( + `https://api${ + network === MAINNET ? '' : `-${network.toLowerCase()}` + }.etherscan.io`, + ) .get(/api.+/u) .reply( 200, @@ -596,12 +775,26 @@ describe('IncomingTransactionsController', function () { }), ) } - const updateStateStub = sinon.stub(incomingTransactionsController.store, 'updateState') - const updateStateCalled = waitUntilCalled(updateStateStub, incomingTransactionsController.store) - const putStateStub = sinon.stub(incomingTransactionsController.store, 'putState') - const putStateCalled = waitUntilCalled(putStateStub, incomingTransactionsController.store) + const updateStateStub = sinon.stub( + incomingTransactionsController.store, + 'updateState', + ) + const updateStateCalled = waitUntilCalled( + updateStateStub, + incomingTransactionsController.store, + ) + const putStateStub = sinon.stub( + incomingTransactionsController.store, + 'putState', + ) + const putStateCalled = waitUntilCalled( + putStateStub, + incomingTransactionsController.store, + ) - const subscription = incomingTransactionsController.networkController.on.getCall(0).args[1] + const subscription = incomingTransactionsController.networkController.on.getCall( + 0, + ).args[1] networkController.getCurrentChainId = () => FAKE_CHAIN_ID await subscription() @@ -623,12 +816,14 @@ describe('IncomingTransactionsController', function () { describe('_getDataForUpdate', function () { it('should call fetchAll with the correct params when passed a new block number and the current network has no stored block', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getEmptyInitState(), + }, + ) incomingTransactionsController._fetchAll = sinon.stub().returns({}) await incomingTransactionsController._getDataForUpdate({ @@ -639,18 +834,21 @@ describe('IncomingTransactionsController', function () { assert(incomingTransactionsController._fetchAll.calledOnce) - assert.deepEqual(incomingTransactionsController._fetchAll.getCall(0).args, [ - 'fakeAddress', 999, ROPSTEN_CHAIN_ID, - ]) + assert.deepEqual( + incomingTransactionsController._fetchAll.getCall(0).args, + ['fakeAddress', 999, ROPSTEN_CHAIN_ID], + ) }) it('should call fetchAll with the correct params when passed a new block number but the current network has a stored block', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) incomingTransactionsController._fetchAll = sinon.stub().returns({}) await incomingTransactionsController._getDataForUpdate({ @@ -661,18 +859,21 @@ describe('IncomingTransactionsController', function () { assert(incomingTransactionsController._fetchAll.calledOnce) - assert.deepEqual(incomingTransactionsController._fetchAll.getCall(0).args, [ - 'fakeAddress', 4, ROPSTEN_CHAIN_ID, - ]) + assert.deepEqual( + incomingTransactionsController._fetchAll.getCall(0).args, + ['fakeAddress', 4, ROPSTEN_CHAIN_ID], + ) }) it('should return the expected data', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) incomingTransactionsController._fetchAll = sinon.stub().returns({ latestIncomingTxBlockNumber: 444, txs: [{ id: 555 }], @@ -725,60 +926,76 @@ describe('IncomingTransactionsController', function () { } it('should update state with correct blockhash and transactions when passed a truthy latestIncomingTxBlockNumber', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) sinon.spy(incomingTransactionsController.store, 'updateState') - await incomingTransactionsController._updateStateWithNewTxData(MOCK_INPUT_WITH_LASTEST) + await incomingTransactionsController._updateStateWithNewTxData( + MOCK_INPUT_WITH_LASTEST, + ) assert(incomingTransactionsController.store.updateState.calledOnce) - assert.deepEqual(incomingTransactionsController.store.updateState.getCall(0).args[0], { - incomingTxLastFetchedBlocksByNetwork: { - ...MOCK_INPUT_WITH_LASTEST.currentBlocksByNetwork, - [ROPSTEN]: 445, + assert.deepEqual( + incomingTransactionsController.store.updateState.getCall(0).args[0], + { + incomingTxLastFetchedBlocksByNetwork: { + ...MOCK_INPUT_WITH_LASTEST.currentBlocksByNetwork, + [ROPSTEN]: 445, + }, + incomingTransactions: { + '0x123456': { id: 777, hash: '0x123456' }, + '0xfff': { id: 555, hash: '0xfff' }, + }, }, - incomingTransactions: { - '0x123456': { id: 777, hash: '0x123456' }, - '0xfff': { id: 555, hash: '0xfff' }, - }, - }) + ) }) it('should update state with correct blockhash and transactions when passed a falsy latestIncomingTxBlockNumber', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) sinon.spy(incomingTransactionsController.store, 'updateState') - await incomingTransactionsController._updateStateWithNewTxData(MOCK_INPUT_WITHOUT_LASTEST) + await incomingTransactionsController._updateStateWithNewTxData( + MOCK_INPUT_WITHOUT_LASTEST, + ) assert(incomingTransactionsController.store.updateState.calledOnce) - assert.deepEqual(incomingTransactionsController.store.updateState.getCall(0).args[0], { - incomingTxLastFetchedBlocksByNetwork: { - ...MOCK_INPUT_WITH_LASTEST.currentBlocksByNetwork, - [ROPSTEN]: 1112, + assert.deepEqual( + incomingTransactionsController.store.updateState.getCall(0).args[0], + { + incomingTxLastFetchedBlocksByNetwork: { + ...MOCK_INPUT_WITH_LASTEST.currentBlocksByNetwork, + [ROPSTEN]: 1112, + }, + incomingTransactions: { + '0x123456': { id: 777, hash: '0x123456' }, + '0xfff': { id: 555, hash: '0xfff' }, + }, }, - incomingTransactions: { - '0x123456': { id: 777, hash: '0x123456' }, - '0xfff': { id: 555, hash: '0xfff' }, - }, - }) + ) }) }) describe('_fetchTxs', function () { - const mockFetch = sinon.stub().returns(Promise.resolve({ - json: () => Promise.resolve({ someKey: 'someValue' }), - })) + const mockFetch = sinon.stub().returns( + Promise.resolve({ + json: () => Promise.resolve({ someKey: 'someValue' }), + }), + ) let tempFetch beforeEach(function () { tempFetch = window.fetch @@ -791,56 +1008,89 @@ describe('IncomingTransactionsController', function () { }) it('should call fetch with the expected url when passed an address, block number and supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - await incomingTransactionsController._fetchTxs('0xfakeaddress', '789', ROPSTEN_CHAIN_ID) + await incomingTransactionsController._fetchTxs( + '0xfakeaddress', + '789', + ROPSTEN_CHAIN_ID, + ) assert(mockFetch.calledOnce) - assert.equal(mockFetch.getCall(0).args[0], `https://api-${ROPSTEN}.etherscan.io/api?module=account&action=txlist&address=0xfakeaddress&tag=latest&page=1&startBlock=789`) + assert.equal( + mockFetch.getCall(0).args[0], + `https://api-${ROPSTEN}.etherscan.io/api?module=account&action=txlist&address=0xfakeaddress&tag=latest&page=1&startBlock=789`, + ) }) it('should call fetch with the expected url when passed an address, block number and MAINNET', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(MAINNET_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(MAINNET_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - await incomingTransactionsController._fetchTxs('0xfakeaddress', '789', MAINNET_CHAIN_ID) + await incomingTransactionsController._fetchTxs( + '0xfakeaddress', + '789', + MAINNET_CHAIN_ID, + ) assert(mockFetch.calledOnce) - assert.equal(mockFetch.getCall(0).args[0], `https://api.etherscan.io/api?module=account&action=txlist&address=0xfakeaddress&tag=latest&page=1&startBlock=789`) + assert.equal( + mockFetch.getCall(0).args[0], + `https://api.etherscan.io/api?module=account&action=txlist&address=0xfakeaddress&tag=latest&page=1&startBlock=789`, + ) }) it('should call fetch with the expected url when passed an address and supported network, but a falsy block number', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - await incomingTransactionsController._fetchTxs('0xfakeaddress', null, ROPSTEN_CHAIN_ID) + await incomingTransactionsController._fetchTxs( + '0xfakeaddress', + null, + ROPSTEN_CHAIN_ID, + ) assert(mockFetch.calledOnce) - assert.equal(mockFetch.getCall(0).args[0], `https://api-${ROPSTEN}.etherscan.io/api?module=account&action=txlist&address=0xfakeaddress&tag=latest&page=1`) + assert.equal( + mockFetch.getCall(0).args[0], + `https://api-${ROPSTEN}.etherscan.io/api?module=account&action=txlist&address=0xfakeaddress&tag=latest&page=1`, + ) }) it('should return the results from the fetch call, plus the address and currentNetworkID, when passed an address, block number and supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - const result = await incomingTransactionsController._fetchTxs('0xfakeaddress', '789', ROPSTEN_CHAIN_ID) + const result = await incomingTransactionsController._fetchTxs( + '0xfakeaddress', + '789', + ROPSTEN_CHAIN_ID, + ) assert(mockFetch.calledOnce) assert.deepEqual(result, { @@ -853,12 +1103,14 @@ describe('IncomingTransactionsController', function () { describe('_processTxFetchResponse', function () { it('should return a null block number and empty tx array if status is 0', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) const result = incomingTransactionsController._processTxFetchResponse({ status: '0', @@ -873,12 +1125,14 @@ describe('IncomingTransactionsController', function () { }) it('should return a null block number and empty tx array if the passed result array is empty', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) const result = incomingTransactionsController._processTxFetchResponse({ status: '1', @@ -893,12 +1147,14 @@ describe('IncomingTransactionsController', function () { }) it('should return the expected block number and tx list when passed data from a successful fetch', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) incomingTransactionsController._normalizeTxFromEtherscan = (tx) => ({ ...tx, @@ -1012,25 +1268,30 @@ describe('IncomingTransactionsController', function () { describe('_normalizeTxFromEtherscan', function () { it('should return the expected data when the tx is in error', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - const result = incomingTransactionsController._normalizeTxFromEtherscan({ - timeStamp: '4444', - isError: '1', - blockNumber: 333, - from: '0xa', - gas: '11', - gasPrice: '12', - nonce: '13', - to: '0xe', - value: '15', - hash: '0xg', - }, ROPSTEN_CHAIN_ID) + const result = incomingTransactionsController._normalizeTxFromEtherscan( + { + timeStamp: '4444', + isError: '1', + blockNumber: 333, + from: '0xa', + gas: '11', + gasPrice: '12', + nonce: '13', + to: '0xe', + value: '15', + hash: '0xg', + }, + ROPSTEN_CHAIN_ID, + ) assert.deepEqual(result, { blockNumber: 333, @@ -1052,25 +1313,30 @@ describe('IncomingTransactionsController', function () { }) it('should return the expected data when the tx is not in error', function () { - const incomingTransactionsController = new IncomingTransactionsController({ - blockTracker: getMockBlockTracker(), - networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), - preferencesController: getMockPreferencesController(), - initState: getNonEmptyInitState(), - }) + const incomingTransactionsController = new IncomingTransactionsController( + { + blockTracker: getMockBlockTracker(), + networkController: getMockNetworkController(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ) - const result = incomingTransactionsController._normalizeTxFromEtherscan({ - timeStamp: '4444', - isError: '0', - blockNumber: 333, - from: '0xa', - gas: '11', - gasPrice: '12', - nonce: '13', - to: '0xe', - value: '15', - hash: '0xg', - }, ROPSTEN_CHAIN_ID) + const result = incomingTransactionsController._normalizeTxFromEtherscan( + { + timeStamp: '4444', + isError: '0', + blockNumber: 333, + from: '0xa', + gas: '11', + gasPrice: '12', + nonce: '13', + to: '0xe', + value: '15', + hash: '0xg', + }, + ROPSTEN_CHAIN_ID, + ) assert.deepEqual(result, { blockNumber: 333, diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 988665544..611f2fe80 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -17,7 +17,7 @@ const threeBoxSpies = { } class ThreeBoxControllerMock { - constructor () { + constructor() { this.store = { subscribe: () => undefined, getState: () => ({}), @@ -61,19 +61,24 @@ const createLoggerMiddlewareMock = () => (req, res, next) => { next() } -const MetaMaskController = proxyquire('../../../../app/scripts/metamask-controller', { - './controllers/threebox': { default: ThreeBoxControllerMock }, - './lib/createLoggerMiddleware': { default: createLoggerMiddlewareMock }, -}).default +const MetaMaskController = proxyquire( + '../../../../app/scripts/metamask-controller', + { + './controllers/threebox': { default: ThreeBoxControllerMock }, + './lib/createLoggerMiddleware': { default: createLoggerMiddlewareMock }, + }, +).default const currentNetworkId = '42' const DEFAULT_LABEL = 'Account 1' const DEFAULT_LABEL_2 = 'Account 2' -const TEST_SEED = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' +const TEST_SEED = + 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' const TEST_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' const TEST_ADDRESS_2 = '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b' const TEST_ADDRESS_3 = '0xeb9e64b93097bc15f01f13eae97015c57ab64823' -const TEST_SEED_ALT = 'setup olympic issue mobile velvet surge alcohol burger horse view reopen gentle' +const TEST_SEED_ALT = + 'setup olympic issue mobile velvet surge alcohol burger horse view reopen gentle' const TEST_ADDRESS_ALT = '0xc42edfcc21ed14dda456aa0756c153f7985d8813' const CUSTOM_RPC_URL = 'http://localhost:8545' const CUSTOM_RPC_CHAIN_ID = '0x539' @@ -84,7 +89,6 @@ describe('MetaMaskController', function () { const noop = () => undefined beforeEach(function () { - nock('https://min-api.cryptocompare.com') .persist() .get(/.*/u) @@ -94,23 +98,32 @@ describe('MetaMaskController', function () { showUnapprovedTx: noop, showUnconfirmedMessage: noop, encryptor: { - encrypt (_, object) { + encrypt(_, object) { this.object = object return Promise.resolve('mock-encrypted') }, - decrypt () { + decrypt() { return Promise.resolve(this.object) }, }, initState: cloneDeep(firstTimeState), - platform: { showTransactionNotification: () => undefined, getVersion: () => 'foo' }, + platform: { + showTransactionNotification: () => undefined, + getVersion: () => 'foo', + }, extension: ExtensionizerMock, infuraProjectId: 'foo', }) // add sinon method spies - sandbox.spy(metamaskController.keyringController, 'createNewVaultAndKeychain') - sandbox.spy(metamaskController.keyringController, 'createNewVaultAndRestore') + sandbox.spy( + metamaskController.keyringController, + 'createNewVaultAndKeychain', + ) + sandbox.spy( + metamaskController.keyringController, + 'createNewVaultAndRestore', + ) }) afterEach(function () { @@ -123,25 +136,32 @@ describe('MetaMaskController', function () { const password = 'a-fake-password' await metamaskController.createNewVaultAndRestore(password, TEST_SEED) - metamaskController.networkController._baseProviderParams.getAccounts((err, res) => { - assert.ifError(err) - assert.equal(res.length, 1) - assert.equal(res[0], '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') - }) + metamaskController.networkController._baseProviderParams.getAccounts( + (err, res) => { + assert.ifError(err) + assert.equal(res.length, 1) + assert.equal(res[0], '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + }, + ) }) }) describe('#importAccountWithStrategy', function () { - const importPrivkey = '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' + const importPrivkey = + '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' beforeEach(async function () { const password = 'a-fake-password' await metamaskController.createNewVaultAndRestore(password, TEST_SEED) - await metamaskController.importAccountWithStrategy('Private Key', [importPrivkey]) + await metamaskController.importAccountWithStrategy('Private Key', [ + importPrivkey, + ]) }) it('adds private key to keyrings in KeyringController', async function () { - const simpleKeyrings = metamaskController.keyringController.getKeyringsByType('Simple Key Pair') + const simpleKeyrings = metamaskController.keyringController.getKeyringsByType( + 'Simple Key Pair', + ) const privKeyBuffer = simpleKeyrings[0].wallets[0]._privKey const pubKeyBuffer = simpleKeyrings[0].wallets[0]._pubKey const addressBuffer = ethUtil.pubToAddress(pubKeyBuffer) @@ -153,7 +173,10 @@ describe('MetaMaskController', function () { it('adds 1 account', async function () { const keyringAccounts = await metamaskController.keyringController.getAccounts() - assert.equal(keyringAccounts[keyringAccounts.length - 1], '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc') + assert.equal( + keyringAccounts[keyringAccounts.length - 1], + '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', + ) }) }) @@ -171,15 +194,23 @@ describe('MetaMaskController', function () { metamaskController.preferencesController.addAddresses([fakeAddress]) await metamaskController.submitPassword(password) - const identities = Object.keys(metamaskController.preferencesController.store.getState().identities) + const identities = Object.keys( + metamaskController.preferencesController.store.getState().identities, + ) const addresses = await metamaskController.keyringController.getAccounts() identities.forEach((identity) => { - assert.ok(addresses.includes(identity), `addresses should include all IDs: ${identity}`) + assert.ok( + addresses.includes(identity), + `addresses should include all IDs: ${identity}`, + ) }) addresses.forEach((address) => { - assert.ok(identities.includes(address), `identities should include all Addresses: ${address}`) + assert.ok( + identities.includes(address), + `identities should include all Addresses: ${address}`, + ) }) }) @@ -210,7 +241,10 @@ describe('MetaMaskController', function () { await metamaskController.createNewVaultAndKeychain(password) await metamaskController.createNewVaultAndKeychain(password) - assert(metamaskController.keyringController.createNewVaultAndKeychain.calledOnce) + assert( + metamaskController.keyringController.createNewVaultAndKeychain + .calledOnce, + ) selectStub.reset() }) @@ -224,10 +258,15 @@ describe('MetaMaskController', function () { return Promise.resolve('0x0') }) - await metamaskController.createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)).catch(() => null) + await metamaskController + .createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)) + .catch(() => null) await metamaskController.createNewVaultAndRestore(password, TEST_SEED) - assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice) + assert( + metamaskController.keyringController.createNewVaultAndRestore + .calledTwice, + ) }) it('should clear previous identities after vault restoration', async function () { @@ -240,12 +279,12 @@ describe('MetaMaskController', function () { await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED) let endTime = Date.now() - const firstVaultIdentities = cloneDeep(metamaskController.getState().identities) + const firstVaultIdentities = cloneDeep( + metamaskController.getState().identities, + ) assert.ok( - ( - firstVaultIdentities[TEST_ADDRESS].lastSelected >= startTime && - firstVaultIdentities[TEST_ADDRESS].lastSelected <= endTime - ), + firstVaultIdentities[TEST_ADDRESS].lastSelected >= startTime && + firstVaultIdentities[TEST_ADDRESS].lastSelected <= endTime, `'${firstVaultIdentities[TEST_ADDRESS].lastSelected}' expected to be between '${startTime}' and '${endTime}'`, ) delete firstVaultIdentities[TEST_ADDRESS].lastSelected @@ -253,24 +292,32 @@ describe('MetaMaskController', function () { [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, }) - await metamaskController.preferencesController.setAccountLabel(TEST_ADDRESS, 'Account Foo') + await metamaskController.preferencesController.setAccountLabel( + TEST_ADDRESS, + 'Account Foo', + ) - const labelledFirstVaultIdentities = cloneDeep(metamaskController.getState().identities) + const labelledFirstVaultIdentities = cloneDeep( + metamaskController.getState().identities, + ) delete labelledFirstVaultIdentities[TEST_ADDRESS].lastSelected assert.deepEqual(labelledFirstVaultIdentities, { [TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' }, }) startTime = Date.now() - await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT) + await metamaskController.createNewVaultAndRestore( + 'foobar1337', + TEST_SEED_ALT, + ) endTime = Date.now() - const secondVaultIdentities = cloneDeep(metamaskController.getState().identities) + const secondVaultIdentities = cloneDeep( + metamaskController.getState().identities, + ) assert.ok( - ( - secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected >= startTime && - secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected <= endTime - ), + secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected >= startTime && + secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected <= endTime, `'${secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected}' expected to be between '${startTime}' and '${endTime}'`, ) delete secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected @@ -295,7 +342,10 @@ describe('MetaMaskController', function () { await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED) const identities = cloneDeep(metamaskController.getState().identities) - assert.ok(identities[TEST_ADDRESS].lastSelected >= startTime && identities[TEST_ADDRESS].lastSelected <= Date.now()) + assert.ok( + identities[TEST_ADDRESS].lastSelected >= startTime && + identities[TEST_ADDRESS].lastSelected <= Date.now(), + ) delete identities[TEST_ADDRESS].lastSelected assert.deepEqual(identities, { [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, @@ -350,16 +400,20 @@ describe('MetaMaskController', function () { }) describe('preferencesController', function () { - it('defaults useBlockie to false', function () { - assert.equal(metamaskController.preferencesController.store.getState().useBlockie, false) + assert.equal( + metamaskController.preferencesController.store.getState().useBlockie, + false, + ) }) it('setUseBlockie to true', function () { metamaskController.setUseBlockie(true, noop) - assert.equal(metamaskController.preferencesController.store.getState().useBlockie, true) + assert.equal( + metamaskController.preferencesController.store.getState().useBlockie, + true, + ) }) - }) describe('#selectFirstIdentity', function () { @@ -370,11 +424,11 @@ describe('MetaMaskController', function () { identities = { '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { address, - 'name': 'Account 1', + name: 'Account 1', }, '0xc42edfcc21ed14dda456aa0756c153f7985d8813': { - 'address': '0xc42edfcc21ed14dda456aa0756c153f7985d8813', - 'name': 'Account 2', + address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + name: 'Account 2', }, } metamaskController.preferencesController.store.updateState({ identities }) @@ -393,12 +447,18 @@ describe('MetaMaskController', function () { }) describe('connectHardware', function () { - it('should throw if it receives an unknown device name', async function () { try { - await metamaskController.connectHardware('Some random device name', 0, `m/44/0'/0'`) + await metamaskController.connectHardware( + 'Some random device name', + 0, + `m/44/0'/0'`, + ) } catch (e) { - assert.equal(e, 'Error: MetamaskController:getKeyringForDevice - Unknown device') + assert.equal( + e, + 'Error: MetamaskController:getKeyringForDevice - Unknown device', + ) } }) @@ -408,7 +468,10 @@ describe('MetaMaskController', function () { const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Trezor Hardware', ) - assert.equal(metamaskController.keyringController.addNewKeyring.getCall(0).args, 'Trezor Hardware') + assert.equal( + metamaskController.keyringController.addNewKeyring.getCall(0).args, + 'Trezor Hardware', + ) assert.equal(keyrings.length, 1) }) @@ -418,18 +481,26 @@ describe('MetaMaskController', function () { const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Ledger Hardware', ) - assert.equal(metamaskController.keyringController.addNewKeyring.getCall(0).args, 'Ledger Hardware') + assert.equal( + metamaskController.keyringController.addNewKeyring.getCall(0).args, + 'Ledger Hardware', + ) assert.equal(keyrings.length, 1) }) - }) describe('checkHardwareStatus', function () { it('should throw if it receives an unknown device name', async function () { try { - await metamaskController.checkHardwareStatus('Some random device name', `m/44/0'/0'`) + await metamaskController.checkHardwareStatus( + 'Some random device name', + `m/44/0'/0'`, + ) } catch (e) { - assert.equal(e, 'Error: MetamaskController:getKeyringForDevice - Unknown device') + assert.equal( + e, + 'Error: MetamaskController:getKeyringForDevice - Unknown device', + ) } }) @@ -445,7 +516,10 @@ describe('MetaMaskController', function () { try { await metamaskController.forgetDevice('Some random device name') } catch (e) { - assert.equal(e, 'Error: MetamaskController:getKeyringForDevice - Unknown device') + assert.equal( + e, + 'Error: MetamaskController:getKeyringForDevice - Unknown device', + ) } }) @@ -472,10 +546,16 @@ describe('MetaMaskController', function () { windowOpenStub = sinon.stub(window, 'open') windowOpenStub.returns(noop) - addNewAccountStub = sinon.stub(metamaskController.keyringController, 'addNewAccount') + addNewAccountStub = sinon.stub( + metamaskController.keyringController, + 'addNewAccount', + ) addNewAccountStub.returns({}) - getAccountsStub = sinon.stub(metamaskController.keyringController, 'getAccounts') + getAccountsStub = sinon.stub( + metamaskController.keyringController, + 'getAccounts', + ) // Need to return different address to mock the behavior of // adding a new account from the keyring getAccountsStub.onCall(0).returns(Promise.resolve(['0x1'])) @@ -485,8 +565,14 @@ describe('MetaMaskController', function () { sinon.spy(metamaskController.preferencesController, 'setAddresses') sinon.spy(metamaskController.preferencesController, 'setSelectedAddress') sinon.spy(metamaskController.preferencesController, 'setAccountLabel') - await metamaskController.connectHardware('trezor', 0, `m/44/0'/0'`).catch(() => null) - await metamaskController.unlockHardwareWalletAccount(accountToUnlock, 'trezor', `m/44/0'/0'`) + await metamaskController + .connectHardware('trezor', 0, `m/44/0'/0'`) + .catch(() => null) + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + 'trezor', + `m/44/0'/0'`, + ) }) afterEach(function () { @@ -518,13 +604,16 @@ describe('MetaMaskController', function () { }) it('should call preferencesController.setSelectedAddress', async function () { - assert(metamaskController.preferencesController.setSelectedAddress.calledOnce) + assert( + metamaskController.preferencesController.setSelectedAddress.calledOnce, + ) }) it('should call preferencesController.setAccountLabel', async function () { - assert(metamaskController.preferencesController.setAccountLabel.calledOnce) + assert( + metamaskController.preferencesController.setAccountLabel.calledOnce, + ) }) - }) describe('#setCustomRpc', function () { @@ -551,7 +640,8 @@ describe('MetaMaskController', function () { let defaultMetaMaskCurrency beforeEach(function () { - defaultMetaMaskCurrency = metamaskController.currencyRateController.state.currentCurrency + defaultMetaMaskCurrency = + metamaskController.currencyRateController.state.currentCurrency }) it('defaults to usd', function () { @@ -560,7 +650,10 @@ describe('MetaMaskController', function () { it('sets currency to JPY', function () { metamaskController.setCurrentCurrency('JPY', noop) - assert.equal(metamaskController.currencyRateController.state.currentCurrency, 'JPY') + assert.equal( + metamaskController.currencyRateController.state.currentCurrency, + 'JPY', + ) }) }) @@ -599,21 +692,45 @@ describe('MetaMaskController', function () { describe('#resetAccount', function () { it('wipes transactions from only the correct network id and with the selected address', async function () { - const selectedAddressStub = sinon.stub(metamaskController.preferencesController, 'getSelectedAddress') - const getNetworkstub = sinon.stub(metamaskController.txController.txStateManager, 'getNetwork') + const selectedAddressStub = sinon.stub( + metamaskController.preferencesController, + 'getSelectedAddress', + ) + const getNetworkstub = sinon.stub( + metamaskController.txController.txStateManager, + 'getNetwork', + ) selectedAddressStub.returns('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') getNetworkstub.returns(42) metamaskController.txController.txStateManager._saveTxList([ - createTxMeta({ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' } }), - createTxMeta({ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' } }), + createTxMeta({ + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' }, + }), + createTxMeta({ + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' }, + }), createTxMeta({ id: 2, status: 'rejected', metamaskNetworkId: '32' }), - createTxMeta({ id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: { from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4' } }), + createTxMeta({ + id: 3, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams: { from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4' }, + }), ]) await metamaskController.resetAccount() - assert.equal(metamaskController.txController.txStateManager.getTx(1), undefined) + assert.equal( + metamaskController.txController.txStateManager.getTx(1), + undefined, + ) }) }) @@ -625,10 +742,12 @@ describe('MetaMaskController', function () { sinon.stub(metamaskController.preferencesController, 'removeAddress') sinon.stub(metamaskController.accountTracker, 'removeAccount') sinon.stub(metamaskController.keyringController, 'removeAccount') - sinon.stub(metamaskController.permissionsController, 'removeAllAccountPermissions') + sinon.stub( + metamaskController.permissionsController, + 'removeAllAccountPermissions', + ) ret = await metamaskController.removeAccount(addressToRemove) - }) afterEach(function () { @@ -639,16 +758,32 @@ describe('MetaMaskController', function () { }) it('should call preferencesController.removeAddress', async function () { - assert(metamaskController.preferencesController.removeAddress.calledWith(addressToRemove)) + assert( + metamaskController.preferencesController.removeAddress.calledWith( + addressToRemove, + ), + ) }) it('should call accountTracker.removeAccount', async function () { - assert(metamaskController.accountTracker.removeAccount.calledWith([addressToRemove])) + assert( + metamaskController.accountTracker.removeAccount.calledWith([ + addressToRemove, + ]), + ) }) it('should call keyringController.removeAccount', async function () { - assert(metamaskController.keyringController.removeAccount.calledWith(addressToRemove)) + assert( + metamaskController.keyringController.removeAccount.calledWith( + addressToRemove, + ), + ) }) it('should call permissionsController.removeAllAccountPermissions', async function () { - assert(metamaskController.permissionsController.removeAllAccountPermissions.calledWith(addressToRemove)) + assert( + metamaskController.permissionsController.removeAllAccountPermissions.calledWith( + addressToRemove, + ), + ) }) it('should return address', async function () { assert.equal(ret, '0x1') @@ -656,22 +791,21 @@ describe('MetaMaskController', function () { }) describe('#setCurrentLocale', function () { - it('checks the default currentLocale', function () { - const preferenceCurrentLocale = metamaskController.preferencesController.store.getState().currentLocale + const preferenceCurrentLocale = metamaskController.preferencesController.store.getState() + .currentLocale assert.equal(preferenceCurrentLocale, undefined) }) it('sets current locale in preferences controller', function () { metamaskController.setCurrentLocale('ja', noop) - const preferenceCurrentLocale = metamaskController.preferencesController.store.getState().currentLocale + const preferenceCurrentLocale = metamaskController.preferencesController.store.getState() + .currentLocale assert.equal(preferenceCurrentLocale, 'ja') }) - }) describe('#newUnsignedMessage', function () { - let msgParams, metamaskMsgs, messages, msgId const address = '0xc42edfcc21ed14dda456aa0756c153f7985d8813' @@ -683,10 +817,13 @@ describe('MetaMaskController', function () { return Promise.resolve('0x0') }) - await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT) + await metamaskController.createNewVaultAndRestore( + 'foobar1337', + TEST_SEED_ALT, + ) msgParams = { - 'from': address, + from: address, data, } @@ -743,10 +880,13 @@ describe('MetaMaskController', function () { return Promise.resolve('0x0') }) - await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT) + await metamaskController.createNewVaultAndRestore( + 'foobar1337', + TEST_SEED_ALT, + ) msgParams = { - 'from': address, + from: address, data, } @@ -767,7 +907,10 @@ describe('MetaMaskController', function () { }) assert.fail('should have thrown') } catch (error) { - assert.equal(error.message, 'MetaMask Message Signature: from field is required.') + assert.equal( + error.message, + 'MetaMask Message Signature: from field is required.', + ) } }) @@ -794,14 +937,18 @@ describe('MetaMaskController', function () { }) it('errors when signing a message', async function () { - await metamaskController.signPersonalMessage(personalMessages[0].msgParams) + await metamaskController.signPersonalMessage( + personalMessages[0].msgParams, + ) assert.equal(metamaskPersonalMsgs[msgId].status, 'signed') - assert.equal(metamaskPersonalMsgs[msgId].rawSig, '0x6a1b65e2b8ed53cf398a769fad24738f9fbe29841fe6854e226953542c4b6a173473cb152b6b1ae5f06d601d45dd699a129b0a8ca84e78b423031db5baa734741b') + assert.equal( + metamaskPersonalMsgs[msgId].rawSig, + '0x6a1b65e2b8ed53cf398a769fad24738f9fbe29841fe6854e226953542c4b6a173473cb152b6b1ae5f06d601d45dd699a129b0a8ca84e78b423031db5baa734741b', + ) }) }) describe('#setupUntrustedCommunication', function () { - const mockTxParams = { from: TEST_ADDRESS } beforeEach(function () { @@ -824,12 +971,18 @@ describe('MetaMaskController', function () { cb() return } - assert.equal(chunk.data.hostname, (new URL(phishingMessageSender.url)).hostname) + assert.equal( + chunk.data.hostname, + new URL(phishingMessageSender.url).hostname, + ) resolve() cb() }) - metamaskController.setupUntrustedCommunication(streamTest, phishingMessageSender) + metamaskController.setupUntrustedCommunication( + streamTest, + phishingMessageSender, + ) await promise streamTest.end() }) @@ -855,22 +1008,23 @@ describe('MetaMaskController', function () { params: [{ ...mockTxParams }], method: 'eth_sendTransaction', } - streamTest.write({ - name: 'provider', - data: message, - }, null, () => { - setTimeout(() => { - assert.deepStrictEqual( - loggerMiddlewareMock.requests[0], - { + streamTest.write( + { + name: 'provider', + data: message, + }, + null, + () => { + setTimeout(() => { + assert.deepStrictEqual(loggerMiddlewareMock.requests[0], { ...message, origin: 'http://mycrypto.com', tabId: 456, - }, - ) - done() - }) - }) + }) + done() + }) + }, + ) }) it('should add only origin to request if tabId not provided', function (done) { @@ -893,21 +1047,22 @@ describe('MetaMaskController', function () { params: [{ ...mockTxParams }], method: 'eth_sendTransaction', } - streamTest.write({ - name: 'provider', - data: message, - }, null, () => { - setTimeout(() => { - assert.deepStrictEqual( - loggerMiddlewareMock.requests[0], - { + streamTest.write( + { + name: 'provider', + data: message, + }, + null, + () => { + setTimeout(() => { + assert.deepStrictEqual(loggerMiddlewareMock.requests[0], { ...message, origin: 'http://mycrypto.com', - }, - ) - done() - }) - }) + }) + done() + }) + }, + ) }) }) @@ -947,7 +1102,6 @@ describe('MetaMaskController', function () { }) describe('#_onKeyringControllerUpdate', function () { - it('should do nothing if there are no keyrings in state', async function () { const syncAddresses = sinon.fake() const syncWithAddresses = sinon.fake() @@ -978,9 +1132,11 @@ describe('MetaMaskController', function () { const oldState = metamaskController.getState() await metamaskController._onKeyringControllerUpdate({ - keyrings: [{ - accounts: ['0x1', '0x2'], - }], + keyrings: [ + { + accounts: ['0x1', '0x2'], + }, + ], }) assert.deepEqual(syncAddresses.args, [[['0x1', '0x2']]]) @@ -1001,9 +1157,11 @@ describe('MetaMaskController', function () { const oldState = metamaskController.getState() await metamaskController._onKeyringControllerUpdate({ isUnlocked: true, - keyrings: [{ - accounts: ['0x1', '0x2'], - }], + keyrings: [ + { + accounts: ['0x1', '0x2'], + }, + ], }) assert.deepEqual(syncAddresses.args, [[['0x1', '0x2']]]) @@ -1011,10 +1169,9 @@ describe('MetaMaskController', function () { assert.deepEqual(metamaskController.getState(), oldState) }) }) - }) -function deferredPromise () { +function deferredPromise() { let resolve const promise = new Promise((_resolve) => { resolve = _resolve diff --git a/test/unit/app/controllers/network/network-controller-test.js b/test/unit/app/controllers/network/network-controller-test.js index 7971939b0..2fb123fec 100644 --- a/test/unit/app/controllers/network/network-controller-test.js +++ b/test/unit/app/controllers/network/network-controller-test.js @@ -19,7 +19,8 @@ describe('NetworkController', function () { describe('#provider', function () { it('provider should be updatable without reassignment', function () { networkController.initializeProvider(networkControllerProviderConfig) - const providerProxy = networkController.getProviderAndBlockTracker().provider + const providerProxy = networkController.getProviderAndBlockTracker() + .provider assert.equal(providerProxy.test, undefined) providerProxy.setTarget({ test: true }) assert.equal(providerProxy.test, true) @@ -56,7 +57,8 @@ describe('NetworkController', function () { networkController.setProviderType('mainnet') assert.equal( - spy.callCount, 1, + spy.callCount, + 1, 'should have called setNetworkState 2 times', ) assert.ok( @@ -73,40 +75,52 @@ describe('NetworkController', function () { { input: '3', expected: 'Ropsten', - }, { + }, + { input: '4', expected: 'Rinkeby', - }, { + }, + { input: '42', expected: 'Kovan', - }, { + }, + { input: '0x3', expected: 'Ropsten', - }, { + }, + { input: '0x4', expected: 'Rinkeby', - }, { + }, + { input: '0x2a', expected: 'Kovan', - }, { + }, + { input: 'ropsten', expected: 'Ropsten', - }, { + }, + { input: 'rinkeby', expected: 'Rinkeby', - }, { + }, + { input: 'kovan', expected: 'Kovan', - }, { + }, + { input: 'mainnet', expected: 'Ethereum Mainnet', - }, { + }, + { input: 'goerli', expected: 'Goerli', }, ] - tests.forEach(({ input, expected }) => assert.equal(getNetworkDisplayName(input), expected)) + tests.forEach(({ input, expected }) => + assert.equal(getNetworkDisplayName(input), expected), + ) }) }) }) diff --git a/test/unit/app/controllers/network/pending-middleware-test.js b/test/unit/app/controllers/network/pending-middleware-test.js index a339d9b68..36b917d16 100644 --- a/test/unit/app/controllers/network/pending-middleware-test.js +++ b/test/unit/app/controllers/network/pending-middleware-test.js @@ -1,12 +1,17 @@ import assert from 'assert' -import { createPendingNonceMiddleware, createPendingTxMiddleware } from '../../../../../app/scripts/controllers/network/middleware/pending' +import { + createPendingNonceMiddleware, + createPendingTxMiddleware, +} from '../../../../../app/scripts/controllers/network/middleware/pending' import { txMetaStub } from './stubs' describe('PendingNonceMiddleware', function () { describe('#createPendingNonceMiddleware', function () { const getPendingNonce = async () => '0x2' const address = '0xF231D46dD78806E1DD93442cf33C7671f8538748' - const pendingNonceMiddleware = createPendingNonceMiddleware({ getPendingNonce }) + const pendingNonceMiddleware = createPendingNonceMiddleware({ + getPendingNonce, + }) it('should call next if not a eth_getTransactionCount request', function (done) { const req = { method: 'eth_getBlockByNumber' } @@ -19,37 +24,49 @@ describe('PendingNonceMiddleware', function () { pendingNonceMiddleware(req, res, () => done()) }) it('should fill the result with a the "pending" nonce', function (done) { - const req = { method: 'eth_getTransactionCount', params: [address, 'pending'] } + const req = { + method: 'eth_getTransactionCount', + params: [address, 'pending'], + } const res = {} - pendingNonceMiddleware(req, res, () => { - done(new Error('should not have called next')) - }, () => { - assert(res.result === '0x2') - done() - }) + pendingNonceMiddleware( + req, + res, + () => { + done(new Error('should not have called next')) + }, + () => { + assert(res.result === '0x2') + done() + }, + ) }) }) describe('#createPendingTxMiddleware', function () { let returnUndefined = true - const getPendingTransactionByHash = () => (returnUndefined ? undefined : txMetaStub) + const getPendingTransactionByHash = () => + returnUndefined ? undefined : txMetaStub const address = '0xF231D46dD78806E1DD93442cf33C7671f8538748' - const pendingTxMiddleware = createPendingTxMiddleware({ getPendingTransactionByHash }) + const pendingTxMiddleware = createPendingTxMiddleware({ + getPendingTransactionByHash, + }) const spec = { - 'blockHash': null, - 'blockNumber': null, - 'from': '0xf231d46dd78806e1dd93442cf33c7671f8538748', - 'gas': '0x5208', - 'gasPrice': '0x1e8480', - 'hash': '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', - 'input': '0x', - 'nonce': '0x4', - 'to': '0xf231d46dd78806e1dd93442cf33c7671f8538748', - 'transactionIndex': null, - 'value': '0x0', - 'v': '0x2c', - 'r': '0x5f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57', - 's': '0x0259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', + blockHash: null, + blockNumber: null, + from: '0xf231d46dd78806e1dd93442cf33c7671f8538748', + gas: '0x5208', + gasPrice: '0x1e8480', + hash: + '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', + input: '0x', + nonce: '0x4', + to: '0xf231d46dd78806e1dd93442cf33c7671f8538748', + transactionIndex: null, + value: '0x0', + v: '0x2c', + r: '0x5f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57', + s: '0x0259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', } it('should call next if not a eth_getTransactionByHash request', function (done) { const req = { method: 'eth_getBlockByNumber' } @@ -65,14 +82,26 @@ describe('PendingNonceMiddleware', function () { it('should fill the result with a the "pending" tx the result should match the rpc spec', function (done) { returnUndefined = false - const req = { method: 'eth_getTransactionByHash', params: [address, 'pending'] } + const req = { + method: 'eth_getTransactionByHash', + params: [address, 'pending'], + } const res = {} - pendingTxMiddleware(req, res, () => { - done(new Error('should not have called next')) - }, () => { - assert.deepStrictEqual(res.result, spec, new Error('result does not match the spec object')) - done() - }) + pendingTxMiddleware( + req, + res, + () => { + done(new Error('should not have called next')) + }, + () => { + assert.deepStrictEqual( + res.result, + spec, + new Error('result does not match the spec object'), + ) + done() + }, + ) }) }) }) diff --git a/test/unit/app/controllers/network/stubs.js b/test/unit/app/controllers/network/stubs.js index c18d24b5d..39ecc4355 100644 --- a/test/unit/app/controllers/network/stubs.js +++ b/test/unit/app/controllers/network/stubs.js @@ -1,199 +1,204 @@ export const txMetaStub = { - 'firstRetryBlockNumber': '0x51a402', - 'hash': '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', - 'history': [ + firstRetryBlockNumber: '0x51a402', + hash: '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', + history: [ { - 'id': 405984854664302, - 'loadingDefaults': true, - 'metamaskNetworkId': '4', - 'status': 'unapproved', - 'time': 1572395156620, - 'transactionCategory': 'sentEther', - 'txParams': { - 'from': '0xf231d46dd78806e1dd93442cf33c7671f8538748', - 'gas': '0x5208', - 'gasPrice': '0x1e8480', - 'to': '0xf231d46dd78806e1dd93442cf33c7671f8538748', - 'value': '0x0', + id: 405984854664302, + loadingDefaults: true, + metamaskNetworkId: '4', + status: 'unapproved', + time: 1572395156620, + transactionCategory: 'sentEther', + txParams: { + from: '0xf231d46dd78806e1dd93442cf33c7671f8538748', + gas: '0x5208', + gasPrice: '0x1e8480', + to: '0xf231d46dd78806e1dd93442cf33c7671f8538748', + value: '0x0', }, - 'type': 'standard', + type: 'standard', }, [ { - 'op': 'replace', - 'path': '/loadingDefaults', - 'timestamp': 1572395156645, - 'value': false, + op: 'replace', + path: '/loadingDefaults', + timestamp: 1572395156645, + value: false, }, ], [ { - 'note': '#newUnapprovedTransaction - adding the origin', - 'op': 'add', - 'path': '/origin', - 'timestamp': 1572395156645, - 'value': 'MetaMask', + note: '#newUnapprovedTransaction - adding the origin', + op: 'add', + path: '/origin', + timestamp: 1572395156645, + value: 'MetaMask', }, ], [], [ { - 'note': 'txStateManager: setting status to approved', - 'op': 'replace', - 'path': '/status', - 'timestamp': 1572395158240, - 'value': 'approved', + note: 'txStateManager: setting status to approved', + op: 'replace', + path: '/status', + timestamp: 1572395158240, + value: 'approved', }, ], [ { - 'note': 'transactions#approveTransaction', - 'op': 'add', - 'path': '/txParams/nonce', - 'timestamp': 1572395158261, - 'value': '0x4', + note: 'transactions#approveTransaction', + op: 'add', + path: '/txParams/nonce', + timestamp: 1572395158261, + value: '0x4', }, { - 'op': 'add', - 'path': '/nonceDetails', - 'value': { - 'local': { - 'details': { - 'highest': 4, - 'startPoint': 4, + op: 'add', + path: '/nonceDetails', + value: { + local: { + details: { + highest: 4, + startPoint: 4, }, - 'name': 'local', - 'nonce': 4, + name: 'local', + nonce: 4, }, - 'network': { - 'details': { - 'baseCount': 4, - 'blockNumber': '0x51a401', + network: { + details: { + baseCount: 4, + blockNumber: '0x51a401', }, - 'name': 'network', - 'nonce': 4, + name: 'network', + nonce: 4, }, - 'params': { - 'highestLocallyConfirmed': 0, - 'highestSuggested': 4, - 'nextNetworkNonce': 4, + params: { + highestLocallyConfirmed: 0, + highestSuggested: 4, + nextNetworkNonce: 4, }, }, }, ], [ { - 'note': 'transactions#signTransaction: add r, s, v values', - 'op': 'add', - 'path': '/r', - 'timestamp': 1572395158280, - 'value': '0x5f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57', + note: 'transactions#signTransaction: add r, s, v values', + op: 'add', + path: '/r', + timestamp: 1572395158280, + value: + '0x5f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57', }, { - 'op': 'add', - 'path': '/s', - 'value': '0x0259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', + op: 'add', + path: '/s', + value: + '0x0259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', }, { - 'op': 'add', - 'path': '/v', - 'value': '0x2c', + op: 'add', + path: '/v', + value: '0x2c', }, ], [ { - 'note': 'transactions#publishTransaction', - 'op': 'replace', - 'path': '/status', - 'timestamp': 1572395158281, - 'value': 'signed', + note: 'transactions#publishTransaction', + op: 'replace', + path: '/status', + timestamp: 1572395158281, + value: 'signed', }, { - 'op': 'add', - 'path': '/rawTx', - 'value': '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', + op: 'add', + path: '/rawTx', + value: + '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', }, ], [], [ { - 'note': 'transactions#setTxHash', - 'op': 'add', - 'path': '/hash', - 'timestamp': 1572395158570, - 'value': '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', + note: 'transactions#setTxHash', + op: 'add', + path: '/hash', + timestamp: 1572395158570, + value: + '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', }, ], [ { - 'note': 'txStateManager - add submitted time stamp', - 'op': 'add', - 'path': '/submittedTime', - 'timestamp': 1572395158571, - 'value': 1572395158570, + note: 'txStateManager - add submitted time stamp', + op: 'add', + path: '/submittedTime', + timestamp: 1572395158571, + value: 1572395158570, }, ], [ { - 'note': 'txStateManager: setting status to submitted', - 'op': 'replace', - 'path': '/status', - 'timestamp': 1572395158576, - 'value': 'submitted', + note: 'txStateManager: setting status to submitted', + op: 'replace', + path: '/status', + timestamp: 1572395158576, + value: 'submitted', }, ], [ { - 'note': 'transactions/pending-tx-tracker#event: tx:block-update', - 'op': 'add', - 'path': '/firstRetryBlockNumber', - 'timestamp': 1572395168972, - 'value': '0x51a402', + note: 'transactions/pending-tx-tracker#event: tx:block-update', + op: 'add', + path: '/firstRetryBlockNumber', + timestamp: 1572395168972, + value: '0x51a402', }, ], ], - 'id': 405984854664302, - 'loadingDefaults': false, - 'metamaskNetworkId': '4', - 'nonceDetails': { - 'local': { - 'details': { - 'highest': 4, - 'startPoint': 4, + id: 405984854664302, + loadingDefaults: false, + metamaskNetworkId: '4', + nonceDetails: { + local: { + details: { + highest: 4, + startPoint: 4, }, - 'name': 'local', - 'nonce': 4, + name: 'local', + nonce: 4, }, - 'network': { - 'details': { - 'baseCount': 4, - 'blockNumber': '0x51a401', + network: { + details: { + baseCount: 4, + blockNumber: '0x51a401', }, - 'name': 'network', - 'nonce': 4, + name: 'network', + nonce: 4, }, - 'params': { - 'highestLocallyConfirmed': 0, - 'highestSuggested': 4, - 'nextNetworkNonce': 4, + params: { + highestLocallyConfirmed: 0, + highestSuggested: 4, + nextNetworkNonce: 4, }, }, - 'origin': 'MetaMask', - 'r': '0x5f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57', - 'rawTx': '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', - 's': '0x0259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', - 'status': 'submitted', - 'submittedTime': 1572395158570, - 'time': 1572395156620, - 'transactionCategory': 'sentEther', - 'txParams': { - 'from': '0xf231d46dd78806e1dd93442cf33c7671f8538748', - 'gas': '0x5208', - 'gasPrice': '0x1e8480', - 'nonce': '0x4', - 'to': '0xf231d46dd78806e1dd93442cf33c7671f8538748', - 'value': '0x0', + origin: 'MetaMask', + r: '0x5f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57', + rawTx: + '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', + s: '0x0259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a', + status: 'submitted', + submittedTime: 1572395158570, + time: 1572395156620, + transactionCategory: 'sentEther', + txParams: { + from: '0xf231d46dd78806e1dd93442cf33c7671f8538748', + gas: '0x5208', + gasPrice: '0x1e8480', + nonce: '0x4', + to: '0xf231d46dd78806e1dd93442cf33c7671f8538748', + value: '0x0', }, - 'type': 'standard', - 'v': '0x2c', + type: 'standard', + v: '0x2c', } diff --git a/test/unit/app/controllers/permissions/helpers.js b/test/unit/app/controllers/permissions/helpers.js index e920b851d..39bfc20e6 100644 --- a/test/unit/app/controllers/permissions/helpers.js +++ b/test/unit/app/controllers/permissions/helpers.js @@ -12,10 +12,8 @@ import { noop } from './mocks' * @param {string} origin - The origin to grant permissions to. * @param {Object} permissions - The permissions to grant. */ -export function grantPermissions (permController, origin, permissions) { - permController.permissions.grantNewPermissions( - origin, permissions, {}, noop, - ) +export function grantPermissions(permController, origin, permissions) { + permController.permissions.grantNewPermissions(origin, permissions, {}, noop) } /** @@ -25,8 +23,7 @@ export function grantPermissions (permController, origin, permissions) { * @param {PermissionsController} permController - The permissions controller. * @return {Function} A convenient wrapper for the requestUserApproval function. */ -export function getRequestUserApprovalHelper (permController) { - +export function getRequestUserApprovalHelper(permController) { /** * Returns a request object that can be passed to requestUserApproval. * @@ -35,7 +32,9 @@ export function getRequestUserApprovalHelper (permController) { * @returns {Object} The corresponding request object. */ return (id, origin = 'defaultOrigin') => { - return permController.permissions.requestUserApproval({ metadata: { id, origin } }) + return permController.permissions.requestUserApproval({ + metadata: { id, origin }, + }) } } @@ -50,7 +49,7 @@ export function getRequestUserApprovalHelper (permController) { * @returns {Promise} A Promise that resolves once a pending approval * has been set. */ -export function getUserApprovalPromise (permController) { +export function getUserApprovalPromise(permController) { const originalFunction = permController.permissions.requestUserApproval return new Promise((resolveHelperPromise) => { permController.permissions.requestUserApproval = (req) => { @@ -72,65 +71,47 @@ export function getUserApprovalPromise (permController) { * @param {'restricted'|'internal'} methodType - The method log controller method type of the request. * @param {boolean} success - Whether the request succeeded or not. */ -export function validateActivityEntry ( - entry, req, res, methodType, success, -) { - assert.doesNotThrow( - () => { - _validateActivityEntry( - entry, req, res, methodType, success, - ) - }, - 'should have expected activity entry', - ) +export function validateActivityEntry(entry, req, res, methodType, success) { + assert.doesNotThrow(() => { + _validateActivityEntry(entry, req, res, methodType, success) + }, 'should have expected activity entry') } -function _validateActivityEntry ( - entry, req, res, methodType, success, -) { - +function _validateActivityEntry(entry, req, res, methodType, success) { assert.ok(entry, 'entry should exist') assert.equal(entry.id, req.id) assert.equal(entry.method, req.method) assert.equal(entry.origin, req.origin) assert.equal(entry.methodType, methodType) - assert.deepEqual( - entry.request, req, - 'entry.request should equal the request', - ) + assert.deepEqual(entry.request, req, 'entry.request should equal the request') if (res) { - assert.ok( - ( - Number.isInteger(entry.requestTime) && - Number.isInteger(entry.responseTime) - ), + Number.isInteger(entry.requestTime) && + Number.isInteger(entry.responseTime), 'request and response times should be numbers', ) assert.ok( - (entry.requestTime <= entry.responseTime), + entry.requestTime <= entry.responseTime, 'request time should be less than response time', ) assert.equal(entry.success, success) assert.deepEqual( - entry.response, res, + entry.response, + res, 'entry.response should equal the response', ) } else { - assert.ok( Number.isInteger(entry.requestTime) && entry.requestTime > 0, 'entry should have non-zero request time', ) assert.ok( - ( - entry.success === null && + entry.success === null && entry.responseTime === null && - entry.response === null - ), + entry.response === null, 'entry response values should be null', ) } diff --git a/test/unit/app/controllers/permissions/mocks.js b/test/unit/app/controllers/permissions/mocks.js index 578b39911..9040f6b12 100644 --- a/test/unit/app/controllers/permissions/mocks.js +++ b/test/unit/app/controllers/permissions/mocks.js @@ -1,8 +1,7 @@ import { ethErrors, ERROR_CODES } from 'eth-json-rpc-errors' import deepFreeze from 'deep-freeze-strict' -import _getRestrictedMethods - from '../../../../../app/scripts/controllers/permissions/restrictedMethods' +import _getRestrictedMethods from '../../../../../app/scripts/controllers/permissions/restrictedMethods' import { CAVEAT_NAMES, @@ -36,24 +35,20 @@ const keyringAccounts = deepFreeze([ const getKeyringAccounts = async () => [...keyringAccounts] const getIdentities = () => { - return keyringAccounts.reduce( - (identities, address, index) => { - identities[address] = { address, name: `Account ${index}` } - return identities - }, - {}, - ) + return keyringAccounts.reduce((identities, address, index) => { + identities[address] = { address, name: `Account ${index}` } + return identities + }, {}) } // perm controller initialization helper const getRestrictedMethods = (permController) => { return { - // the actual, production restricted methods ..._getRestrictedMethods(permController), // our own dummy method for testing - 'test_method': { + test_method: { description: `This method is only for testing.`, method: (req, res, __, end) => { if (req.params[0]) { @@ -74,7 +69,7 @@ const getUnlockPromise = () => Promise.resolve() * * @returns {Object} A PermissionsController constructor options object. */ -export function getPermControllerOpts () { +export function getPermControllerOpts() { return { showPermissionRequest: noop, getKeyringAccounts, @@ -103,18 +98,17 @@ export function getPermControllerOpts () { * @param {string} extensionId - The extension id for the middleware. * @returns {Function} A Promise-wrapped middleware function with convenient default args. */ -export function getPermissionsMiddleware (permController, origin, extensionId) { +export function getPermissionsMiddleware(permController, origin, extensionId) { const middleware = permController.createMiddleware({ origin, extensionId }) return (req, res = {}, next = noop, end) => { return new Promise((resolve, reject) => { - // eslint-disable-next-line no-param-reassign end = end || _end middleware(req, res, next, end) // emulates json-rpc-engine error handling - function _end (err) { + function _end(err) { if (err || res.error) { reject(err || res.error) } else { @@ -131,7 +125,10 @@ export function getPermissionsMiddleware (permController, origin, extensionId) { * @returns {Function} A function passed to the permissions controller at initialization, * for recording notifications. */ -export const getNotifyDomain = (notifications = {}) => (origin, notification) => { +export const getNotifyDomain = (notifications = {}) => ( + origin, + notification, +) => { notifications[origin].push(notification) } @@ -183,7 +180,6 @@ const ACCOUNTS = { * Helpers for getting mock caveats. */ const CAVEATS = { - /** * Gets a correctly formatted eth_accounts exposedAccounts caveat. * @@ -191,15 +187,18 @@ const CAVEATS = { * @returns {Object} An eth_accounts exposedAccounts caveats */ eth_accounts: (accounts) => { - return [{ - type: CAVEAT_TYPES.limitResponseLength, - value: 1, - name: CAVEAT_NAMES.primaryAccountOnly, - }, { - type: CAVEAT_TYPES.filterResponse, - value: accounts, - name: CAVEAT_NAMES.exposedAccounts, - }] + return [ + { + type: CAVEAT_TYPES.limitResponseLength, + value: 1, + name: CAVEAT_NAMES.primaryAccountOnly, + }, + { + type: CAVEAT_TYPES.filterResponse, + value: accounts, + name: CAVEAT_NAMES.exposedAccounts, + }, + ] }, } @@ -208,7 +207,6 @@ const CAVEATS = { * by permissions controller functions if we used TypeScript. */ const PERMS = { - /** * The argument to approvePermissionsRequest * @param {string} id - The rpc-cap permissions request id. @@ -225,7 +223,6 @@ const PERMS = { * Requested permissions objects, as passed to wallet_requestPermissions. */ requests: { - /** * @returns {Object} A permissions request object with eth_accounts */ @@ -252,7 +249,6 @@ const PERMS = { * Finalized permission requests, as returned by finalizePermissionsRequest */ finalizedRequests: { - /** * @param {Array} accounts - The accounts for the eth_accounts permission caveat * @returns {Object} A finalized permissions request object with eth_accounts and its caveat @@ -281,7 +277,6 @@ const PERMS = { * - wallet_getPermissions */ granted: { - /** * @param {Array} accounts - The accounts for the eth_accounts permission caveat * @returns {Object} A granted permissions object with eth_accounts and its caveat @@ -309,7 +304,6 @@ const PERMS = { * caveats, errors, permissions requests etc. */ export const getters = deepFreeze({ - CAVEATS, PERMS, @@ -318,9 +312,7 @@ export const getters = deepFreeze({ * Getters for errors by the method or workflow that throws them. */ ERRORS: { - validatePermittedAccounts: { - invalidParam: () => { return { name: 'Error', @@ -467,7 +459,6 @@ export const getters = deepFreeze({ * Getters for notifications produced by the permissions controller. */ NOTIFICATIONS: { - /** * Gets a removed accounts notification. * @@ -498,7 +489,6 @@ export const getters = deepFreeze({ * Getters for mock RPC request objects. */ RPC_REQUESTS: { - /** * Gets an arbitrary RPC request object. * @@ -638,16 +628,12 @@ export const constants = deepFreeze({ PERM_NAMES: { ...PERM_NAMES }, - RESTRICTED_METHODS: [ - 'eth_accounts', - 'test_method', - ], + RESTRICTED_METHODS: ['eth_accounts', 'test_method'], /** * Mock permissions history objects. */ EXPECTED_HISTORIES: { - case1: [ { [DOMAINS.a.origin]: { diff --git a/test/unit/app/controllers/permissions/permissions-controller-test.js b/test/unit/app/controllers/permissions/permissions-controller-test.js index f51ed0800..5e593f114 100644 --- a/test/unit/app/controllers/permissions/permissions-controller-test.js +++ b/test/unit/app/controllers/permissions/permissions-controller-test.js @@ -14,10 +14,7 @@ import { addInternalMethodPrefix, } from '../../../../../app/scripts/controllers/permissions' -import { - getRequestUserApprovalHelper, - grantPermissions, -} from './helpers' +import { getRequestUserApprovalHelper, grantPermissions } from './helpers' import { noop, @@ -28,11 +25,7 @@ import { getPermControllerOpts, } from './mocks' -const { - ERRORS, - NOTIFICATIONS, - PERMS, -} = getters +const { ERRORS, NOTIFICATIONS, PERMS } = getters const { ALL_ACCOUNTS, @@ -60,34 +53,35 @@ const initPermController = (notifications = initNotifications()) => { } describe('permissions controller', function () { - describe('getAccounts', function () { - let permController beforeEach(function () { permController = initPermController() grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) }) it('gets permitted accounts for permitted origins', async function () { - const aAccounts = await permController.getAccounts(DOMAINS.a.origin) const bAccounts = await permController.getAccounts(DOMAINS.b.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], + aAccounts, + [ACCOUNTS.a.primary], 'first origin should have correct accounts', ) assert.deepEqual( - bAccounts, [ACCOUNTS.b.primary], + bAccounts, + [ACCOUNTS.b.primary], 'second origin should have correct accounts', ) }) @@ -104,16 +98,16 @@ describe('permissions controller', function () { }) describe('hasPermission', function () { - it('returns correct values', async function () { - const permController = initPermController() grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.test_method(), ) @@ -147,22 +141,23 @@ describe('permissions controller', function () { }) describe('clearPermissions', function () { - it('notifies all appropriate domains and removes permissions', async function () { - const notifications = initNotifications() const permController = initPermController(notifications) grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.c.permitted), ) @@ -171,15 +166,18 @@ describe('permissions controller', function () { let cAccounts = await permController.getAccounts(DOMAINS.c.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], + aAccounts, + [ACCOUNTS.a.primary], 'first origin should have correct accounts', ) assert.deepEqual( - bAccounts, [ACCOUNTS.b.primary], + bAccounts, + [ACCOUNTS.b.primary], 'second origin should have correct accounts', ) assert.deepEqual( - cAccounts, [ACCOUNTS.c.primary], + cAccounts, + [ACCOUNTS.c.primary], 'third origin should have correct accounts', ) @@ -210,40 +208,43 @@ describe('permissions controller', function () { }) assert.deepEqual( - Object.keys(permController.permissions.getDomains()), [], + Object.keys(permController.permissions.getDomains()), + [], 'all domains should be deleted', ) }) }) describe('removePermissionsFor', function () { - let permController, notifications beforeEach(function () { notifications = initNotifications() permController = initPermController(notifications) grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) }) it('removes permissions for multiple domains', async function () { - let aAccounts = await permController.getAccounts(DOMAINS.a.origin) let bAccounts = await permController.getAccounts(DOMAINS.b.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], + aAccounts, + [ACCOUNTS.a.primary], 'first origin should have correct accounts', ) assert.deepEqual( - bAccounts, [ACCOUNTS.b.primary], + bAccounts, + [ACCOUNTS.b.primary], 'second origin should have correct accounts', ) @@ -259,34 +260,38 @@ describe('permissions controller', function () { assert.deepEqual(bAccounts, [], 'second origin should have no accounts') assert.deepEqual( - notifications[DOMAINS.a.origin], [NOTIFICATIONS.removedAccounts()], + notifications[DOMAINS.a.origin], + [NOTIFICATIONS.removedAccounts()], 'first origin should have correct notification', ) assert.deepEqual( - notifications[DOMAINS.b.origin], [NOTIFICATIONS.removedAccounts()], + notifications[DOMAINS.b.origin], + [NOTIFICATIONS.removedAccounts()], 'second origin should have correct notification', ) assert.deepEqual( - Object.keys(permController.permissions.getDomains()), [], + Object.keys(permController.permissions.getDomains()), + [], 'all domains should be deleted', ) }) it('only removes targeted permissions from single domain', async function () { - grantPermissions( - permController, DOMAINS.b.origin, PERMS.finalizedRequests.test_method(), + permController, + DOMAINS.b.origin, + PERMS.finalizedRequests.test_method(), ) - let bPermissions = permController.permissions.getPermissionsForDomain(DOMAINS.b.origin) + let bPermissions = permController.permissions.getPermissionsForDomain( + DOMAINS.b.origin, + ) assert.ok( - ( - bPermissions.length === 2 && + bPermissions.length === 2 && find(bPermissions, { parentCapability: PERM_NAMES.eth_accounts }) && - find(bPermissions, { parentCapability: PERM_NAMES.test_method }) - ), + find(bPermissions, { parentCapability: PERM_NAMES.test_method }), 'origin should have correct permissions', ) @@ -294,19 +299,18 @@ describe('permissions controller', function () { [DOMAINS.b.origin]: [PERM_NAMES.test_method], }) - bPermissions = permController.permissions.getPermissionsForDomain(DOMAINS.b.origin) + bPermissions = permController.permissions.getPermissionsForDomain( + DOMAINS.b.origin, + ) assert.ok( - ( - bPermissions.length === 1 && - find(bPermissions, { parentCapability: PERM_NAMES.eth_accounts }) - ), + bPermissions.length === 1 && + find(bPermissions, { parentCapability: PERM_NAMES.eth_accounts }), 'only targeted permission should have been removed', ) }) it('removes permissions for a single domain, without affecting another', async function () { - permController.removePermissionsFor({ [DOMAINS.b.origin]: [PERM_NAMES.eth_accounts], }) @@ -315,35 +319,39 @@ describe('permissions controller', function () { const bAccounts = await permController.getAccounts(DOMAINS.b.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], + aAccounts, + [ACCOUNTS.a.primary], 'first origin should have correct accounts', ) assert.deepEqual(bAccounts, [], 'second origin should have no accounts') assert.deepEqual( - notifications[DOMAINS.a.origin], [], + notifications[DOMAINS.a.origin], + [], 'first origin should have no notifications', ) assert.deepEqual( - notifications[DOMAINS.b.origin], [NOTIFICATIONS.removedAccounts()], + notifications[DOMAINS.b.origin], + [NOTIFICATIONS.removedAccounts()], 'second origin should have correct notification', ) assert.deepEqual( - Object.keys(permController.permissions.getDomains()), [DOMAINS.a.origin], + Object.keys(permController.permissions.getDomains()), + [DOMAINS.a.origin], 'only first origin should remain', ) }) it('send notification but does not affect permissions for unknown domain', async function () { - // it knows nothing of this origin permController.removePermissionsFor({ [DOMAINS.c.origin]: [PERM_NAMES.eth_accounts], }) assert.deepEqual( - notifications[DOMAINS.c.origin], [NOTIFICATIONS.removedAccounts()], + notifications[DOMAINS.c.origin], + [NOTIFICATIONS.removedAccounts()], 'unknown origin should have notification', ) @@ -351,11 +359,13 @@ describe('permissions controller', function () { const bAccounts = await permController.getAccounts(DOMAINS.b.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], + aAccounts, + [ACCOUNTS.a.primary], 'first origin should have correct accounts', ) assert.deepEqual( - bAccounts, [ACCOUNTS.b.primary], + bAccounts, + [ACCOUNTS.b.primary], 'second origin should have correct accounts', ) @@ -368,23 +378,23 @@ describe('permissions controller', function () { }) describe('validatePermittedAccounts', function () { - let permController beforeEach(function () { permController = initPermController() grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) }) it('throws error on non-array accounts', async function () { - await assert.throws( () => permController.validatePermittedAccounts(undefined), ERRORS.validatePermittedAccounts.invalidParam(), @@ -411,7 +421,6 @@ describe('permissions controller', function () { }) it('throws error on empty array of accounts', async function () { - await assert.throws( () => permController.validatePermittedAccounts([]), ERRORS.validatePermittedAccounts.invalidParam(), @@ -420,7 +429,6 @@ describe('permissions controller', function () { }) it('throws error if any account value is not in keyring', async function () { - const keyringAccounts = await permController.getKeyringAccounts() await assert.throws( @@ -430,14 +438,16 @@ describe('permissions controller', function () { ) await assert.throws( - () => permController.validatePermittedAccounts(keyringAccounts.concat(DUMMY_ACCOUNT)), + () => + permController.validatePermittedAccounts( + keyringAccounts.concat(DUMMY_ACCOUNT), + ), ERRORS.validatePermittedAccounts.nonKeyringAccount(DUMMY_ACCOUNT), 'should throw on non-keyring account with other accounts', ) }) it('succeeds if all accounts are in keyring', async function () { - const keyringAccounts = await permController.getKeyringAccounts() await assert.doesNotThrow( @@ -464,11 +474,13 @@ describe('permissions controller', function () { notifications = initNotifications() permController = initPermController(notifications) grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) }) @@ -483,7 +495,8 @@ describe('permissions controller', function () { it('should throw if given account is not in keyring', async function () { await assert.rejects( - () => permController.addPermittedAccount(DOMAINS.a.origin, DUMMY_ACCOUNT), + () => + permController.addPermittedAccount(DOMAINS.a.origin, DUMMY_ACCOUNT), ERRORS.validatePermittedAccounts.nonKeyringAccount(DUMMY_ACCOUNT), 'should throw on non-keyring account', ) @@ -499,7 +512,8 @@ describe('permissions controller', function () { it('should throw if origin lacks any permissions', async function () { await assert.rejects( - () => permController.addPermittedAccount(DOMAINS.c.origin, EXTRA_ACCOUNT), + () => + permController.addPermittedAccount(DOMAINS.c.origin, EXTRA_ACCOUNT), ERRORS.addPermittedAccount.invalidOrigin(), 'should throw on origin without permissions', ) @@ -507,12 +521,14 @@ describe('permissions controller', function () { it('should throw if origin lacks eth_accounts permission', async function () { grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.test_method(), ) await assert.rejects( - () => permController.addPermittedAccount(DOMAINS.c.origin, EXTRA_ACCOUNT), + () => + permController.addPermittedAccount(DOMAINS.c.origin, EXTRA_ACCOUNT), ERRORS.addPermittedAccount.noEthAccountsPermission(), 'should throw on origin without eth_accounts permission', ) @@ -520,7 +536,11 @@ describe('permissions controller', function () { it('should throw if account is already permitted', async function () { await assert.rejects( - () => permController.addPermittedAccount(DOMAINS.a.origin, ACCOUNTS.a.permitted[0]), + () => + permController.addPermittedAccount( + DOMAINS.a.origin, + ACCOUNTS.a.permitted[0], + ), ERRORS.addPermittedAccount.alreadyPermitted(), 'should throw if account is already permitted', ) @@ -529,10 +549,13 @@ describe('permissions controller', function () { it('should successfully add permitted account', async function () { await permController.addPermittedAccount(DOMAINS.a.origin, EXTRA_ACCOUNT) - const accounts = await permController._getPermittedAccounts(DOMAINS.a.origin) + const accounts = await permController._getPermittedAccounts( + DOMAINS.a.origin, + ) assert.deepEqual( - accounts, [...ACCOUNTS.a.permitted, EXTRA_ACCOUNT], + accounts, + [...ACCOUNTS.a.permitted, EXTRA_ACCOUNT], 'origin should have correct accounts', ) @@ -551,11 +574,13 @@ describe('permissions controller', function () { notifications = initNotifications() permController = initPermController(notifications) grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) }) @@ -570,7 +595,11 @@ describe('permissions controller', function () { it('should throw if given account is not in keyring', async function () { await assert.rejects( - () => permController.removePermittedAccount(DOMAINS.a.origin, DUMMY_ACCOUNT), + () => + permController.removePermittedAccount( + DOMAINS.a.origin, + DUMMY_ACCOUNT, + ), ERRORS.validatePermittedAccounts.nonKeyringAccount(DUMMY_ACCOUNT), 'should throw on non-keyring account', ) @@ -586,7 +615,11 @@ describe('permissions controller', function () { it('should throw if origin lacks any permissions', async function () { await assert.rejects( - () => permController.removePermittedAccount(DOMAINS.c.origin, EXTRA_ACCOUNT), + () => + permController.removePermittedAccount( + DOMAINS.c.origin, + EXTRA_ACCOUNT, + ), ERRORS.removePermittedAccount.invalidOrigin(), 'should throw on origin without permissions', ) @@ -594,12 +627,17 @@ describe('permissions controller', function () { it('should throw if origin lacks eth_accounts permission', async function () { grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.test_method(), ) await assert.rejects( - () => permController.removePermittedAccount(DOMAINS.c.origin, EXTRA_ACCOUNT), + () => + permController.removePermittedAccount( + DOMAINS.c.origin, + EXTRA_ACCOUNT, + ), ERRORS.removePermittedAccount.noEthAccountsPermission(), 'should throw on origin without eth_accounts permission', ) @@ -607,19 +645,29 @@ describe('permissions controller', function () { it('should throw if account is not permitted', async function () { await assert.rejects( - () => permController.removePermittedAccount(DOMAINS.b.origin, ACCOUNTS.c.permitted[0]), + () => + permController.removePermittedAccount( + DOMAINS.b.origin, + ACCOUNTS.c.permitted[0], + ), ERRORS.removePermittedAccount.notPermitted(), 'should throw if account is not permitted', ) }) it('should successfully remove permitted account', async function () { - await permController.removePermittedAccount(DOMAINS.a.origin, ACCOUNTS.a.permitted[1]) + await permController.removePermittedAccount( + DOMAINS.a.origin, + ACCOUNTS.a.permitted[1], + ) - const accounts = await permController._getPermittedAccounts(DOMAINS.a.origin) + const accounts = await permController._getPermittedAccounts( + DOMAINS.a.origin, + ) assert.deepEqual( - accounts, ACCOUNTS.a.permitted.filter((acc) => acc !== ACCOUNTS.a.permitted[1]), + accounts, + ACCOUNTS.a.permitted.filter((acc) => acc !== ACCOUNTS.a.permitted[1]), 'origin should have correct accounts', ) @@ -631,20 +679,25 @@ describe('permissions controller', function () { }) it('should remove eth_accounts permission if removing only permitted account', async function () { - await permController.removePermittedAccount(DOMAINS.b.origin, ACCOUNTS.b.permitted[0]) + await permController.removePermittedAccount( + DOMAINS.b.origin, + ACCOUNTS.b.permitted[0], + ) const accounts = await permController.getAccounts(DOMAINS.b.origin) - assert.deepEqual( - accounts, [], - 'origin should have no accounts', - ) + assert.deepEqual(accounts, [], 'origin should have no accounts') const permission = await permController.permissions.getPermission( - DOMAINS.b.origin, PERM_NAMES.eth_accounts, + DOMAINS.b.origin, + PERM_NAMES.eth_accounts, ) - assert.equal(permission, undefined, 'origin should not have eth_accounts permission') + assert.equal( + permission, + undefined, + 'origin should not have eth_accounts permission', + ) assert.deepEqual( notifications[DOMAINS.b.origin][0], @@ -661,15 +714,18 @@ describe('permissions controller', function () { notifications = initNotifications() permController = initPermController(notifications) grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) grantPermissions( - permController, DOMAINS.b.origin, + permController, + DOMAINS.b.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), ) }) @@ -693,10 +749,13 @@ describe('permissions controller', function () { it('should remove permitted account from single origin', async function () { await permController.removeAllAccountPermissions(ACCOUNTS.a.permitted[1]) - const accounts = await permController._getPermittedAccounts(DOMAINS.a.origin) + const accounts = await permController._getPermittedAccounts( + DOMAINS.a.origin, + ) assert.deepEqual( - accounts, ACCOUNTS.a.permitted.filter((acc) => acc !== ACCOUNTS.a.permitted[1]), + accounts, + ACCOUNTS.a.permitted.filter((acc) => acc !== ACCOUNTS.a.permitted[1]), 'origin should have correct accounts', ) @@ -711,16 +770,10 @@ describe('permissions controller', function () { await permController.removeAllAccountPermissions(ACCOUNTS.b.permitted[0]) const bAccounts = await permController.getAccounts(DOMAINS.b.origin) - assert.deepEqual( - bAccounts, [], - 'first origin should no accounts', - ) + assert.deepEqual(bAccounts, [], 'first origin should no accounts') const cAccounts = await permController.getAccounts(DOMAINS.c.origin) - assert.deepEqual( - cAccounts, [], - 'second origin no accounts', - ) + assert.deepEqual(cAccounts, [], 'second origin no accounts') assert.deepEqual( notifications[DOMAINS.b.origin][0], @@ -740,16 +793,18 @@ describe('permissions controller', function () { const accounts = await permController.getAccounts(DOMAINS.b.origin) - assert.deepEqual( - accounts, [], - 'origin should have no accounts', - ) + assert.deepEqual(accounts, [], 'origin should have no accounts') const permission = await permController.permissions.getPermission( - DOMAINS.b.origin, PERM_NAMES.eth_accounts, + DOMAINS.b.origin, + PERM_NAMES.eth_accounts, ) - assert.equal(permission, undefined, 'origin should not have eth_accounts permission') + assert.equal( + permission, + undefined, + 'origin should not have eth_accounts permission', + ) assert.deepEqual( notifications[DOMAINS.b.origin][0], @@ -760,7 +815,6 @@ describe('permissions controller', function () { }) describe('finalizePermissionsRequest', function () { - let permController beforeEach(function () { @@ -768,10 +822,10 @@ describe('permissions controller', function () { }) it('throws on non-keyring accounts', async function () { - await assert.rejects( permController.finalizePermissionsRequest( - PERMS.requests.eth_accounts(), [DUMMY_ACCOUNT], + PERMS.requests.eth_accounts(), + [DUMMY_ACCOUNT], ), ERRORS.validatePermittedAccounts.nonKeyringAccount(DUMMY_ACCOUNT), 'should throw on non-keyring account', @@ -779,54 +833,52 @@ describe('permissions controller', function () { }) it('adds caveat to eth_accounts permission', async function () { - const perm = await permController.finalizePermissionsRequest( PERMS.requests.eth_accounts(), ACCOUNTS.a.permitted, ) - assert.deepEqual(perm, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted)) + assert.deepEqual( + perm, + PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), + ) }) it('replaces caveat of eth_accounts permission', async function () { - const perm = await permController.finalizePermissionsRequest( PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ACCOUNTS.b.permitted, ) assert.deepEqual( - perm, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), + perm, + PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), 'permission should have correct caveat', ) }) it('handles non-eth_accounts permission', async function () { - const perm = await permController.finalizePermissionsRequest( PERMS.finalizedRequests.test_method(), ACCOUNTS.b.permitted, ) assert.deepEqual( - perm, PERMS.finalizedRequests.test_method(), + perm, + PERMS.finalizedRequests.test_method(), 'permission should have correct caveat', ) }) }) describe('preferences state update', function () { - let permController, notifications, preferences, identities beforeEach(function () { - identities = ALL_ACCOUNTS.reduce( - (identitiesAcc, account) => { - identitiesAcc[account] = {} - return identitiesAcc - }, - {}, - ) + identities = ALL_ACCOUNTS.reduce((identitiesAcc, account) => { + identitiesAcc[account] = {} + return identitiesAcc + }, {}) preferences = { getState: sinon.stub(), subscribe: sinon.stub(), @@ -843,17 +895,21 @@ describe('permissions controller', function () { preferences, }) grantPermissions( - permController, DOMAINS.b.origin, - PERMS.finalizedRequests.eth_accounts([...ACCOUNTS.a.permitted, EXTRA_ACCOUNT]), + permController, + DOMAINS.b.origin, + PERMS.finalizedRequests.eth_accounts([ + ...ACCOUNTS.a.permitted, + EXTRA_ACCOUNT, + ]), ) grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) }) it('should throw if given invalid account', async function () { - assert(preferences.subscribe.calledOnce) assert(preferences.subscribe.firstCall.args.length === 1) const onPreferencesUpdate = preferences.subscribe.firstCall.args[0] @@ -873,11 +929,13 @@ describe('permissions controller', function () { await onPreferencesUpdate({ selectedAddress: DUMMY_ACCOUNT }) assert.deepEqual( - notifications[DOMAINS.b.origin], [], + notifications[DOMAINS.b.origin], + [], 'should not have emitted notification', ) assert.deepEqual( - notifications[DOMAINS.c.origin], [], + notifications[DOMAINS.c.origin], + [], 'should not have emitted notification', ) }) @@ -916,7 +974,8 @@ describe('permissions controller', function () { 'should have emitted notification', ) assert.deepEqual( - notifications[DOMAINS.c.origin], [], + notifications[DOMAINS.c.origin], + [], 'should not have emitted notification', ) }) @@ -943,7 +1002,6 @@ describe('permissions controller', function () { }) describe('approvePermissionsRequest', function () { - let permController, requestUserApproval beforeEach(function () { @@ -952,9 +1010,9 @@ describe('permissions controller', function () { }) it('does nothing if called on non-existing request', async function () { - assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty on init', ) @@ -973,13 +1031,13 @@ describe('permissions controller', function () { ) assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should still be empty after request', ) }) it('rejects request with bad accounts param', async function () { - const request = PERMS.approvedRequest( REQUEST_IDS.a, PERMS.requests.eth_accounts(), @@ -995,13 +1053,13 @@ describe('permissions controller', function () { await rejectionPromise assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty after rejection', ) }) it('rejects request with no permissions', async function () { - const request = PERMS.approvedRequest(REQUEST_IDS.a, {}) const requestRejection = assert.rejects( @@ -1010,92 +1068,113 @@ describe('permissions controller', function () { 'should reject if no permissions in request', ) - await permController.approvePermissionsRequest(request, ACCOUNTS.a.permitted) + await permController.approvePermissionsRequest( + request, + ACCOUNTS.a.permitted, + ) await requestRejection assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty after rejection', ) }) it('approves valid request', async function () { - - const request = PERMS.approvedRequest(REQUEST_IDS.a, PERMS.requests.eth_accounts()) + const request = PERMS.approvedRequest( + REQUEST_IDS.a, + PERMS.requests.eth_accounts(), + ) let perms - const requestApproval = assert.doesNotReject( - async () => { - perms = await requestUserApproval(REQUEST_IDS.a) - }, - 'should not reject single valid request', - ) + const requestApproval = assert.doesNotReject(async () => { + perms = await requestUserApproval(REQUEST_IDS.a) + }, 'should not reject single valid request') - await permController.approvePermissionsRequest(request, ACCOUNTS.a.permitted) + await permController.approvePermissionsRequest( + request, + ACCOUNTS.a.permitted, + ) await requestApproval assert.deepEqual( - perms, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), + perms, + PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), 'should produce expected approved permissions', ) assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty after approval', ) }) it('approves valid requests regardless of order', async function () { - - const request1 = PERMS.approvedRequest(REQUEST_IDS.a, PERMS.requests.eth_accounts()) - const request2 = PERMS.approvedRequest(REQUEST_IDS.b, PERMS.requests.eth_accounts()) - const request3 = PERMS.approvedRequest(REQUEST_IDS.c, PERMS.requests.eth_accounts()) + const request1 = PERMS.approvedRequest( + REQUEST_IDS.a, + PERMS.requests.eth_accounts(), + ) + const request2 = PERMS.approvedRequest( + REQUEST_IDS.b, + PERMS.requests.eth_accounts(), + ) + const request3 = PERMS.approvedRequest( + REQUEST_IDS.c, + PERMS.requests.eth_accounts(), + ) let perms1, perms2 - const approval1 = assert.doesNotReject( - async () => { - perms1 = await requestUserApproval(REQUEST_IDS.a, DOMAINS.a.origin) - }, - 'should not reject request', - ) + const approval1 = assert.doesNotReject(async () => { + perms1 = await requestUserApproval(REQUEST_IDS.a, DOMAINS.a.origin) + }, 'should not reject request') - const approval2 = assert.doesNotReject( - async () => { - perms2 = await requestUserApproval(REQUEST_IDS.b, DOMAINS.b.origin) - }, - 'should not reject request', - ) + const approval2 = assert.doesNotReject(async () => { + perms2 = await requestUserApproval(REQUEST_IDS.b, DOMAINS.b.origin) + }, 'should not reject request') // approve out of order - await permController.approvePermissionsRequest(request2, ACCOUNTS.b.permitted) + await permController.approvePermissionsRequest( + request2, + ACCOUNTS.b.permitted, + ) // add a non-existing request to the mix - await permController.approvePermissionsRequest(request3, ACCOUNTS.c.permitted) - await permController.approvePermissionsRequest(request1, ACCOUNTS.a.permitted) + await permController.approvePermissionsRequest( + request3, + ACCOUNTS.c.permitted, + ) + await permController.approvePermissionsRequest( + request1, + ACCOUNTS.a.permitted, + ) await approval1 await approval2 assert.deepEqual( - perms1, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), + perms1, + PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), 'first request should produce expected approved permissions', ) assert.deepEqual( - perms2, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), + perms2, + PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted), 'second request should produce expected approved permissions', ) assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty after approvals', ) }) }) describe('rejectPermissionsRequest', function () { - let permController, requestUserApproval beforeEach(async function () { @@ -1104,9 +1183,9 @@ describe('permissions controller', function () { }) it('does nothing if called on non-existing request', async function () { - assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty on init', ) @@ -1116,13 +1195,13 @@ describe('permissions controller', function () { ) assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should still be empty after request', ) }) it('rejects single existing request', async function () { - const requestRejection = assert.rejects( requestUserApproval(REQUEST_IDS.a), ERRORS.rejectPermissionsRequest.rejection(), @@ -1133,13 +1212,13 @@ describe('permissions controller', function () { await requestRejection assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty after rejection', ) }) it('rejects requests regardless of order', async function () { - const requestRejection1 = assert.rejects( requestUserApproval(REQUEST_IDS.b, DOMAINS.b.origin), ERRORS.rejectPermissionsRequest.rejection(), @@ -1162,7 +1241,8 @@ describe('permissions controller', function () { await requestRejection2 assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'pending approvals should be empty after approval', ) }) @@ -1170,7 +1250,6 @@ describe('permissions controller', function () { // see permissions-middleware-test for testing the middleware itself describe('createMiddleware', function () { - let permController, clock beforeEach(function () { @@ -1183,7 +1262,6 @@ describe('permissions controller', function () { }) it('should throw on bad origin', function () { - assert.throws( () => permController.createMiddleware({ origin: {} }), ERRORS.createMiddleware.badOrigin(), @@ -1204,62 +1282,52 @@ describe('permissions controller', function () { }) it('should create a middleware', function () { - let middleware - assert.doesNotThrow( - () => { - middleware = permController.createMiddleware({ origin: DOMAINS.a.origin }) - }, - 'should not throw', - ) + assert.doesNotThrow(() => { + middleware = permController.createMiddleware({ + origin: DOMAINS.a.origin, + }) + }, 'should not throw') + + assert.equal(typeof middleware, 'function', 'should return function') assert.equal( - typeof middleware, 'function', - 'should return function', - ) - - assert.equal( - middleware.name, 'engineAsMiddleware', + middleware.name, + 'engineAsMiddleware', 'function name should be "engineAsMiddleware"', ) }) it('should create a middleware with extensionId', function () { - const extensionId = 'fooExtension' let middleware - assert.doesNotThrow( - () => { - middleware = permController.createMiddleware({ - origin: DOMAINS.a.origin, - extensionId, - }) - }, - 'should not throw', - ) + assert.doesNotThrow(() => { + middleware = permController.createMiddleware({ + origin: DOMAINS.a.origin, + extensionId, + }) + }, 'should not throw') + + assert.equal(typeof middleware, 'function', 'should return function') assert.equal( - typeof middleware, 'function', - 'should return function', - ) - - assert.equal( - middleware.name, 'engineAsMiddleware', + middleware.name, + 'engineAsMiddleware', 'function name should be "engineAsMiddleware"', ) const metadataStore = permController.store.getState()[METADATA_STORE_KEY] assert.deepEqual( - metadataStore[DOMAINS.a.origin], { extensionId, lastUpdated: 1 }, + metadataStore[DOMAINS.a.origin], + { extensionId, lastUpdated: 1 }, 'metadata should be stored', ) }) }) describe('notifyAccountsChanged', function () { - let notifications, permController beforeEach(function () { @@ -1269,7 +1337,6 @@ describe('permissions controller', function () { }) it('notifyAccountsChanged records history and sends notification', async function () { - permController.notifyAccountsChanged( DOMAINS.a.origin, ACCOUNTS.a.permitted, @@ -1288,42 +1355,28 @@ describe('permissions controller', function () { }) it('notifyAccountsChanged throws on invalid origin', async function () { - assert.throws( - () => permController.notifyAccountsChanged( - 4, - ACCOUNTS.a.permitted, - ), + () => permController.notifyAccountsChanged(4, ACCOUNTS.a.permitted), ERRORS.notifyAccountsChanged.invalidOrigin(4), 'should throw expected error for non-string origin', ) assert.throws( - () => permController.notifyAccountsChanged( - '', - ACCOUNTS.a.permitted, - ), + () => permController.notifyAccountsChanged('', ACCOUNTS.a.permitted), ERRORS.notifyAccountsChanged.invalidOrigin(''), 'should throw expected error for empty string origin', ) }) it('notifyAccountsChanged throws on invalid accounts', async function () { - assert.throws( - () => permController.notifyAccountsChanged( - DOMAINS.a.origin, - 4, - ), + () => permController.notifyAccountsChanged(DOMAINS.a.origin, 4), ERRORS.notifyAccountsChanged.invalidAccounts(), 'should throw expected error for truthy non-array accounts', ) assert.throws( - () => permController.notifyAccountsChanged( - DOMAINS.a.origin, - null, - ), + () => permController.notifyAccountsChanged(DOMAINS.a.origin, null), ERRORS.notifyAccountsChanged.invalidAccounts(), 'should throw expected error for falsy non-array accounts', ) @@ -1331,10 +1384,9 @@ describe('permissions controller', function () { }) describe('addDomainMetadata', function () { - let permController, clock - function getMockMetadata (size) { + function getMockMetadata(size) { const dummyData = {} for (let i = 0; i < size; i++) { const key = i.toString() @@ -1354,7 +1406,6 @@ describe('permissions controller', function () { }) it('calls setter function with expected new state when adding domain', function () { - permController.store.getState = sinon.fake.returns({ [METADATA_STORE_KEY]: { [DOMAINS.a.origin]: { @@ -1370,12 +1421,12 @@ describe('permissions controller', function () { 'should have called store.getState', ) assert.equal( - permController._setDomainMetadata.getCalls().length, 1, + permController._setDomainMetadata.getCalls().length, + 1, 'should have called _setDomainMetadata once', ) - assert.deepEqual( - permController._setDomainMetadata.lastCall.args, - [{ + assert.deepEqual(permController._setDomainMetadata.lastCall.args, [ + { [DOMAINS.a.origin]: { foo: 'bar', }, @@ -1384,12 +1435,11 @@ describe('permissions controller', function () { host: DOMAINS.b.host, lastUpdated: 1, }, - }], - ) + }, + ]) }) it('calls setter function with expected new states when updating existing domain', function () { - permController.store.getState = sinon.fake.returns({ [METADATA_STORE_KEY]: { [DOMAINS.a.origin]: { @@ -1408,12 +1458,12 @@ describe('permissions controller', function () { 'should have called store.getState', ) assert.equal( - permController._setDomainMetadata.getCalls().length, 1, + permController._setDomainMetadata.getCalls().length, + 1, 'should have called _setDomainMetadata once', ) - assert.deepEqual( - permController._setDomainMetadata.lastCall.args, - [{ + assert.deepEqual(permController._setDomainMetadata.lastCall.args, [ + { [DOMAINS.a.origin]: { foo: 'bar', }, @@ -1423,12 +1473,11 @@ describe('permissions controller', function () { host: DOMAINS.b.host, lastUpdated: 1, }, - }], - ) + }, + ]) }) it('pops metadata on add when too many origins are pending', function () { - sinon.spy(permController._pendingSiteMetadata, 'delete') const mockMetadata = getMockMetadata(METADATA_CACHE_MAX_SIZE) @@ -1462,26 +1511,26 @@ describe('permissions controller', function () { delete expectedMetadata[expectedDeletedOrigin] assert.ok( - permController._pendingSiteMetadata.delete.calledOnceWithExactly(expectedDeletedOrigin), + permController._pendingSiteMetadata.delete.calledOnceWithExactly( + expectedDeletedOrigin, + ), 'should have called _pendingSiteMetadata.delete once', ) assert.equal( - permController._setDomainMetadata.getCalls().length, 1, + permController._setDomainMetadata.getCalls().length, + 1, 'should have called _setDomainMetadata once', ) - assert.deepEqual( - permController._setDomainMetadata.lastCall.args, - [expectedMetadata], - ) + assert.deepEqual(permController._setDomainMetadata.lastCall.args, [ + expectedMetadata, + ]) }) }) describe('_trimDomainMetadata', function () { - const permController = initPermController() it('trims domain metadata for domains without permissions', function () { - const metadataArg = { [DOMAINS.a.origin]: {}, [DOMAINS.b.origin]: {}, @@ -1494,7 +1543,8 @@ describe('permissions controller', function () { const metadataResult = permController._trimDomainMetadata(metadataArg) assert.equal( - permController.permissions.getDomains.getCalls().length, 1, + permController.permissions.getDomains.getCalls().length, + 1, 'should have called permissions.getDomains once', ) assert.deepEqual( @@ -1508,7 +1558,6 @@ describe('permissions controller', function () { }) describe('miscellanea and edge cases', function () { - let permController beforeEach(function () { @@ -1516,18 +1565,21 @@ describe('permissions controller', function () { }) it('requestAccountsPermissionWithId calls _requestAccountsPermission with an explicit request ID', async function () { - const _requestPermissions = sinon.stub(permController, '_requestPermissions').resolves() + const _requestPermissions = sinon + .stub(permController, '_requestPermissions') + .resolves() await permController.requestAccountsPermissionWithId('example.com') - assert.ok(_requestPermissions.calledOnceWithExactly( - sinon.match.object.and(sinon.match.has('origin')), - { eth_accounts: {} }, - sinon.match.string.and(sinon.match.truthy), - )) + assert.ok( + _requestPermissions.calledOnceWithExactly( + sinon.match.object.and(sinon.match.has('origin')), + { eth_accounts: {} }, + sinon.match.string.and(sinon.match.truthy), + ), + ) _requestPermissions.restore() }) it('_addPendingApproval: should throw if adding origin twice', function () { - const id = nanoid() const origin = DOMAINS.a @@ -1542,12 +1594,14 @@ describe('permissions controller', function () { ) assert.equal( - permController.pendingApprovals.size, 1, + permController.pendingApprovals.size, + 1, 'pending approvals should have single entry', ) assert.equal( - permController.pendingApprovalOrigins.size, 1, + permController.pendingApprovalOrigins.size, + 1, 'pending approval origins should have single item', ) diff --git a/test/unit/app/controllers/permissions/permissions-log-controller-test.js b/test/unit/app/controllers/permissions/permissions-log-controller-test.js index 6f9fc104b..ac498a0e0 100644 --- a/test/unit/app/controllers/permissions/permissions-log-controller-test.js +++ b/test/unit/app/controllers/permissions/permissions-log-controller-test.js @@ -3,28 +3,18 @@ import ObservableStore from 'obs-store' import nanoid from 'nanoid' import { useFakeTimers } from 'sinon' -import PermissionsLogController - from '../../../../../app/scripts/controllers/permissions/permissionsLog' +import PermissionsLogController from '../../../../../app/scripts/controllers/permissions/permissionsLog' import { LOG_LIMIT, LOG_METHOD_TYPES, } from '../../../../../app/scripts/controllers/permissions/enums' -import { - validateActivityEntry, -} from './helpers' +import { validateActivityEntry } from './helpers' -import { - constants, - getters, - noop, -} from './mocks' +import { constants, getters, noop } from './mocks' -const { - PERMS, - RPC_REQUESTS, -} = getters +const { PERMS, RPC_REQUESTS } = getters const { ACCOUNTS, @@ -72,9 +62,7 @@ const getSavedMockNext = (arr) => (handler) => { } describe('permissions log', function () { - describe('activity log', function () { - let permLog, logMiddleware beforeEach(function () { @@ -83,7 +71,6 @@ describe('permissions log', function () { }) it('records activity for restricted methods', function () { - let log, req, res // test_method, success @@ -99,8 +86,11 @@ describe('permissions log', function () { assert.equal(log.length, 1, 'log should have single entry') validateActivityEntry( - entry1, { ...req }, { ...res }, - LOG_METHOD_TYPES.restricted, true, + entry1, + { ...req }, + { ...res }, + LOG_METHOD_TYPES.restricted, + true, ) // eth_accounts, failure @@ -116,8 +106,11 @@ describe('permissions log', function () { assert.equal(log.length, 2, 'log should have 2 entries') validateActivityEntry( - entry2, { ...req }, { ...res }, - LOG_METHOD_TYPES.restricted, false, + entry2, + { ...req }, + { ...res }, + LOG_METHOD_TYPES.restricted, + false, ) // eth_requestAccounts, success @@ -133,8 +126,11 @@ describe('permissions log', function () { assert.equal(log.length, 3, 'log should have 3 entries') validateActivityEntry( - entry3, { ...req }, { ...res }, - LOG_METHOD_TYPES.restricted, true, + entry3, + { ...req }, + { ...res }, + LOG_METHOD_TYPES.restricted, + true, ) // test_method, no response @@ -150,8 +146,11 @@ describe('permissions log', function () { assert.equal(log.length, 4, 'log should have 4 entries') validateActivityEntry( - entry4, { ...req }, null, - LOG_METHOD_TYPES.restricted, false, + entry4, + { ...req }, + null, + LOG_METHOD_TYPES.restricted, + false, ) // validate final state @@ -163,7 +162,6 @@ describe('permissions log', function () { }) it('handles responses added out of order', function () { - let log const handlerArray = [] @@ -194,11 +192,12 @@ describe('permissions log', function () { const entry2 = log[1] const entry3 = log[2] assert.ok( - ( - entry1.id === id1 && entry1.response === null && - entry2.id === id2 && entry2.response === null && - entry3.id === id3 && entry3.response === null - ), + entry1.id === id1 && + entry1.response === null && + entry2.id === id2 && + entry2.response === null && + entry3.id === id3 && + entry3.response === null, 'all entries should be in correct order and without responses', ) @@ -215,23 +214,31 @@ describe('permissions log', function () { log = permLog.getActivityLog() validateActivityEntry( - log[0], { ...req, id: id1 }, { ...res1 }, - LOG_METHOD_TYPES.restricted, true, + log[0], + { ...req, id: id1 }, + { ...res1 }, + LOG_METHOD_TYPES.restricted, + true, ) validateActivityEntry( - log[1], { ...req, id: id2 }, { ...res2 }, - LOG_METHOD_TYPES.restricted, true, + log[1], + { ...req, id: id2 }, + { ...res2 }, + LOG_METHOD_TYPES.restricted, + true, ) validateActivityEntry( - log[2], { ...req, id: id3 }, { ...res3 }, - LOG_METHOD_TYPES.restricted, true, + log[2], + { ...req, id: id3 }, + { ...res3 }, + LOG_METHOD_TYPES.restricted, + true, ) }) it('handles a lack of response', function () { - let req = RPC_REQUESTS.test_method(DOMAINS.a.origin) req.id = REQUEST_IDS.a let res = { foo: 'bar' } @@ -244,8 +251,11 @@ describe('permissions log', function () { assert.equal(log.length, 1, 'log should have single entry') validateActivityEntry( - entry1, { ...req }, null, - LOG_METHOD_TYPES.restricted, true, + entry1, + { ...req }, + null, + LOG_METHOD_TYPES.restricted, + true, ) // next request should be handled as normal @@ -259,8 +269,11 @@ describe('permissions log', function () { const entry2 = log[1] assert.equal(log.length, 2, 'log should have 2 entries') validateActivityEntry( - entry2, { ...req }, { ...res }, - LOG_METHOD_TYPES.restricted, true, + entry2, + { ...req }, + { ...res }, + LOG_METHOD_TYPES.restricted, + true, ) // validate final state @@ -269,12 +282,14 @@ describe('permissions log', function () { }) it('ignores expected methods', function () { - let log = permLog.getActivityLog() assert.equal(log.length, 0, 'log should be empty') const res = { foo: 'bar' } - const req1 = RPC_REQUESTS.wallet_sendDomainMetadata(DOMAINS.c.origin, 'foobar') + const req1 = RPC_REQUESTS.wallet_sendDomainMetadata( + DOMAINS.c.origin, + 'foobar', + ) const req2 = RPC_REQUESTS.custom(DOMAINS.b.origin, 'eth_getBlockNumber') const req3 = RPC_REQUESTS.custom(DOMAINS.b.origin, 'net_version') @@ -287,7 +302,6 @@ describe('permissions log', function () { }) it('enforces log limit', function () { - const req = RPC_REQUESTS.test_method(DOMAINS.a.origin) const res = { foo: 'bar' } @@ -301,12 +315,17 @@ describe('permissions log', function () { // check last entry valid let log = permLog.getActivityLog() assert.equal( - log.length, LOG_LIMIT, 'log should have LOG_LIMIT num entries', + log.length, + LOG_LIMIT, + 'log should have LOG_LIMIT num entries', ) validateActivityEntry( - log[LOG_LIMIT - 1], { ...req, id: lastId }, res, - LOG_METHOD_TYPES.restricted, true, + log[LOG_LIMIT - 1], + { ...req, id: lastId }, + res, + LOG_METHOD_TYPES.restricted, + true, ) // store the id of the current second entry @@ -319,24 +338,31 @@ describe('permissions log', function () { // check log length log = permLog.getActivityLog() assert.equal( - log.length, LOG_LIMIT, 'log should have LOG_LIMIT num entries', + log.length, + LOG_LIMIT, + 'log should have LOG_LIMIT num entries', ) // check first and last entries validateActivityEntry( - log[0], { ...req, id: nextFirstId }, res, - LOG_METHOD_TYPES.restricted, true, + log[0], + { ...req, id: nextFirstId }, + res, + LOG_METHOD_TYPES.restricted, + true, ) validateActivityEntry( - log[LOG_LIMIT - 1], { ...req, id: lastId }, res, - LOG_METHOD_TYPES.restricted, true, + log[LOG_LIMIT - 1], + { ...req, id: lastId }, + res, + LOG_METHOD_TYPES.restricted, + true, ) }) }) describe('permissions history', function () { - let permLog, logMiddleware beforeEach(function () { @@ -350,11 +376,11 @@ describe('permissions log', function () { }) it('only updates history on responses', function () { - let permHistory const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ) const res = { result: [PERMS.granted.test_method()] } @@ -369,7 +395,8 @@ describe('permissions log', function () { permHistory = permLog.getHistory() assert.equal( - Object.keys(permHistory).length, 1, + Object.keys(permHistory).length, + 1, 'history should have single origin', ) assert.ok( @@ -379,9 +406,9 @@ describe('permissions log', function () { }) it('ignores malformed permissions requests', function () { - const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ) delete req.params const res = { result: [PERMS.granted.test_method()] } @@ -389,15 +416,19 @@ describe('permissions log', function () { // no params => no response logMiddleware({ ...req }, { ...res }) - assert.deepEqual(permLog.getHistory(), {}, 'history should not have been updated') + assert.deepEqual( + permLog.getHistory(), + {}, + 'history should not have been updated', + ) }) it('records and updates account history as expected', async function () { - let permHistory const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res = { result: [PERMS.granted.eth_accounts(ACCOUNTS.a.permitted)], @@ -433,9 +464,9 @@ describe('permissions log', function () { }) it('handles eth_accounts response without caveats', async function () { - const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res = { result: [PERMS.granted.eth_accounts(ACCOUNTS.a.permitted)], @@ -447,15 +478,16 @@ describe('permissions log', function () { // validate history assert.deepEqual( - permLog.getHistory(), EXPECTED_HISTORIES.case2[0], + permLog.getHistory(), + EXPECTED_HISTORIES.case2[0], 'should have expected history', ) }) it('handles extra caveats for eth_accounts', async function () { - const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res = { result: [PERMS.granted.eth_accounts(ACCOUNTS.a.permitted)], @@ -476,9 +508,9 @@ describe('permissions log', function () { // wallet_requestPermissions returns all permissions approved for the // requesting origin, including old ones it('handles unrequested permissions on the response', async function () { - const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res = { result: [ @@ -499,14 +531,12 @@ describe('permissions log', function () { }) it('does not update history if no new permissions are approved', async function () { - let req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ) let res = { - result: [ - PERMS.granted.test_method(), - ], + result: [PERMS.granted.test_method()], } logMiddleware({ ...req }, { ...res }) @@ -524,12 +554,11 @@ describe('permissions log', function () { clock.tick(1) req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) res = { - result: [ - PERMS.granted.test_method(), - ], + result: [PERMS.granted.test_method()], } logMiddleware({ ...req }, { ...res }) @@ -544,7 +573,6 @@ describe('permissions log', function () { }) it('records and updates history for multiple origins, regardless of response order', async function () { - let permHistory // make first round of requests @@ -555,7 +583,8 @@ describe('permissions log', function () { // first origin round1.push({ req: RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ), res: { result: [PERMS.granted.test_method()], @@ -565,7 +594,8 @@ describe('permissions log', function () { // second origin round1.push({ req: RPC_REQUESTS.requestPermission( - DOMAINS.b.origin, PERM_NAMES.eth_accounts, + DOMAINS.b.origin, + PERM_NAMES.eth_accounts, ), res: { result: [PERMS.granted.eth_accounts(ACCOUNTS.b.permitted)], @@ -599,7 +629,8 @@ describe('permissions log', function () { permHistory = permLog.getHistory() assert.deepEqual( - permHistory, EXPECTED_HISTORIES.case3[0], + permHistory, + EXPECTED_HISTORIES.case3[0], 'should have expected history', ) @@ -613,7 +644,8 @@ describe('permissions log', function () { // first origin round2.push({ req: RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ), res: { result: [PERMS.granted.test_method()], @@ -628,9 +660,7 @@ describe('permissions log', function () { [PERM_NAMES.eth_accounts]: {}, }), res: { - result: [ - PERMS.granted.eth_accounts(ACCOUNTS.b.permitted), - ], + result: [PERMS.granted.eth_accounts(ACCOUNTS.b.permitted)], }, }) @@ -643,7 +673,8 @@ describe('permissions log', function () { permHistory = permLog.getHistory() assert.deepEqual( - permHistory, EXPECTED_HISTORIES.case3[1], + permHistory, + EXPECTED_HISTORIES.case3[1], 'should have expected history', ) }) diff --git a/test/unit/app/controllers/permissions/permissions-middleware-test.js b/test/unit/app/controllers/permissions/permissions-middleware-test.js index 8b56eb764..2888d3da5 100644 --- a/test/unit/app/controllers/permissions/permissions-middleware-test.js +++ b/test/unit/app/controllers/permissions/permissions-middleware-test.js @@ -1,18 +1,11 @@ import { strict as assert } from 'assert' import sinon from 'sinon' -import { - METADATA_STORE_KEY, -} from '../../../../../app/scripts/controllers/permissions/enums' +import { METADATA_STORE_KEY } from '../../../../../app/scripts/controllers/permissions/enums' -import { - PermissionsController, -} from '../../../../../app/scripts/controllers/permissions' +import { PermissionsController } from '../../../../../app/scripts/controllers/permissions' -import { - getUserApprovalPromise, - grantPermissions, -} from './helpers' +import { getUserApprovalPromise, grantPermissions } from './helpers' import { constants, @@ -21,24 +14,23 @@ import { getPermissionsMiddleware, } from './mocks' -const { - CAVEATS, - ERRORS, - PERMS, - RPC_REQUESTS, -} = getters +const { CAVEATS, ERRORS, PERMS, RPC_REQUESTS } = getters -const { - ACCOUNTS, - DOMAINS, - PERM_NAMES, -} = constants +const { ACCOUNTS, DOMAINS, PERM_NAMES } = constants const validatePermission = (perm, name, origin, caveats) => { - assert.equal(name, perm.parentCapability, 'should have expected permission name') + assert.equal( + name, + perm.parentCapability, + 'should have expected permission name', + ) assert.equal(origin, perm.invoker, 'should have expected permission origin') if (caveats) { - assert.deepEqual(caveats, perm.caveats, 'should have expected permission caveats') + assert.deepEqual( + caveats, + perm.caveats, + 'should have expected permission caveats', + ) } else { assert.ok(!perm.caveats, 'should not have any caveats') } @@ -51,9 +43,7 @@ const initPermController = () => { } describe('permissions middleware', function () { - describe('wallet_requestPermissions', function () { - let permController beforeEach(function () { @@ -62,11 +52,14 @@ describe('permissions middleware', function () { }) it('grants permissions on user approval', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res = {} @@ -80,14 +73,21 @@ describe('permissions middleware', function () { await userApprovalPromise assert.equal( - permController.pendingApprovals.size, 1, + permController.pendingApprovals.size, + 1, 'perm controller should have single pending approval', ) const id = permController.pendingApprovals.keys().next().value - const approvedReq = PERMS.approvedRequest(id, PERMS.requests.eth_accounts()) + const approvedReq = PERMS.approvedRequest( + id, + PERMS.requests.eth_accounts(), + ) - await permController.approvePermissionsRequest(approvedReq, ACCOUNTS.a.permitted) + await permController.approvePermissionsRequest( + approvedReq, + ACCOUNTS.a.permitted, + ) await pendingApproval assert.ok( @@ -96,7 +96,8 @@ describe('permissions middleware', function () { ) assert.equal( - res.result.length, 1, + res.result.length, + 1, 'origin should have single approved permission', ) @@ -109,26 +110,31 @@ describe('permissions middleware', function () { const aAccounts = await permController.getAccounts(DOMAINS.a.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], + aAccounts, + [ACCOUNTS.a.primary], 'origin should have correct accounts', ) assert.ok( permController.notifyAccountsChanged.calledOnceWith( - DOMAINS.a.origin, aAccounts, + DOMAINS.a.origin, + aAccounts, ), 'expected notification call should have been made', ) }) it('handles serial approved requests that overwrite existing permissions', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) // create first request const req1 = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res1 = {} @@ -145,9 +151,15 @@ describe('permissions middleware', function () { await userApprovalPromise const id1 = permController.pendingApprovals.keys().next().value - const approvedReq1 = PERMS.approvedRequest(id1, PERMS.requests.eth_accounts()) + const approvedReq1 = PERMS.approvedRequest( + id1, + PERMS.requests.eth_accounts(), + ) - await permController.approvePermissionsRequest(approvedReq1, ACCOUNTS.a.permitted) + await permController.approvePermissionsRequest( + approvedReq1, + ACCOUNTS.a.permitted, + ) await pendingApproval1 assert.ok( @@ -156,7 +168,8 @@ describe('permissions middleware', function () { ) assert.equal( - res1.result.length, 1, + res1.result.length, + 1, 'origin should have single approved permission', ) @@ -169,13 +182,15 @@ describe('permissions middleware', function () { const accounts1 = await permController.getAccounts(DOMAINS.a.origin) assert.deepEqual( - accounts1, [ACCOUNTS.a.primary], + accounts1, + [ACCOUNTS.a.primary], 'origin should have correct accounts', ) assert.ok( permController.notifyAccountsChanged.calledOnceWith( - DOMAINS.a.origin, accounts1, + DOMAINS.a.origin, + accounts1, ), 'expected notification call should have been made', ) @@ -187,9 +202,9 @@ describe('permissions middleware', function () { ...PERMS.requests.test_method(), } - const req2 = RPC_REQUESTS.requestPermissions( - DOMAINS.a.origin, { ...requestedPerms2 }, - ) + const req2 = RPC_REQUESTS.requestPermissions(DOMAINS.a.origin, { + ...requestedPerms2, + }) const res2 = {} // send, approve, and validate second request @@ -207,7 +222,10 @@ describe('permissions middleware', function () { const id2 = permController.pendingApprovals.keys().next().value const approvedReq2 = PERMS.approvedRequest(id2, { ...requestedPerms2 }) - await permController.approvePermissionsRequest(approvedReq2, ACCOUNTS.b.permitted) + await permController.approvePermissionsRequest( + approvedReq2, + ACCOUNTS.b.permitted, + ) await pendingApproval2 assert.ok( @@ -216,7 +234,8 @@ describe('permissions middleware', function () { ) assert.equal( - res2.result.length, 2, + res2.result.length, + 2, 'origin should have single approved permission', ) @@ -235,29 +254,35 @@ describe('permissions middleware', function () { const accounts2 = await permController.getAccounts(DOMAINS.a.origin) assert.deepEqual( - accounts2, [ACCOUNTS.b.primary], + accounts2, + [ACCOUNTS.b.primary], 'origin should have correct accounts', ) assert.equal( - permController.notifyAccountsChanged.callCount, 2, + permController.notifyAccountsChanged.callCount, + 2, 'should have called notification method 2 times in total', ) assert.ok( permController.notifyAccountsChanged.lastCall.calledWith( - DOMAINS.a.origin, accounts2, + DOMAINS.a.origin, + accounts2, ), 'expected notification call should have been made', ) }) it('rejects permissions on user rejection', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) const req = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.eth_accounts, + DOMAINS.a.origin, + PERM_NAMES.eth_accounts, ) const res = {} @@ -274,7 +299,8 @@ describe('permissions middleware', function () { await userApprovalPromise assert.equal( - permController.pendingApprovals.size, 1, + permController.pendingApprovals.size, + 1, 'perm controller should have single pending approval', ) @@ -284,16 +310,15 @@ describe('permissions middleware', function () { await requestRejection assert.ok( - ( - !res.result && res.error && - res.error.message === expectedError.message - ), + !res.result && res.error && res.error.message === expectedError.message, 'response should have expected error and no result', ) const aAccounts = await permController.getAccounts(DOMAINS.a.origin) assert.deepEqual( - aAccounts, [], 'origin should have have correct accounts', + aAccounts, + [], + 'origin should have have correct accounts', ) assert.ok( @@ -303,15 +328,15 @@ describe('permissions middleware', function () { }) it('rejects requests with unknown permissions', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) - - const req = RPC_REQUESTS.requestPermissions( - DOMAINS.a.origin, { - ...PERMS.requests.does_not_exist(), - ...PERMS.requests.test_method(), - }, + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, ) + + const req = RPC_REQUESTS.requestPermissions(DOMAINS.a.origin, { + ...PERMS.requests.does_not_exist(), + ...PERMS.requests.test_method(), + }) const res = {} const expectedError = ERRORS.rejectPermissionsRequest.methodNotFound( @@ -325,15 +350,13 @@ describe('permissions middleware', function () { ) assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'perm controller should have no pending approvals', ) assert.ok( - ( - !res.result && res.error && - res.error.message === expectedError.message - ), + !res.result && res.error && res.error.message === expectedError.message, 'response should have expected error and no result', ) @@ -344,18 +367,24 @@ describe('permissions middleware', function () { }) it('accepts only a single pending permissions request per origin', async function () { - const expectedError = ERRORS.pendingApprovals.requestAlreadyPending() // two middlewares for two origins - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) - const bMiddleware = getPermissionsMiddleware(permController, DOMAINS.b.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) + const bMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.b.origin, + ) // create and start processing first request for first origin const reqA1 = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ) const resA1 = {} @@ -371,7 +400,8 @@ describe('permissions middleware', function () { // create and start processing first request for second origin const reqB1 = RPC_REQUESTS.requestPermission( - DOMAINS.b.origin, PERM_NAMES.test_method, + DOMAINS.b.origin, + PERM_NAMES.test_method, ) const resB1 = {} @@ -385,7 +415,8 @@ describe('permissions middleware', function () { await userApprovalPromise assert.equal( - permController.pendingApprovals.size, 2, + permController.pendingApprovals.size, + 2, 'perm controller should have expected number of pending approvals', ) @@ -393,7 +424,8 @@ describe('permissions middleware', function () { // which should throw const reqA2 = RPC_REQUESTS.requestPermission( - DOMAINS.a.origin, PERM_NAMES.test_method, + DOMAINS.a.origin, + PERM_NAMES.test_method, ) const resA2 = {} @@ -409,17 +441,17 @@ describe('permissions middleware', function () { await requestApprovalFail assert.ok( - ( - !resA2.result && resA2.error && - resA2.error.message === expectedError.message - ), + !resA2.result && + resA2.error && + resA2.error.message === expectedError.message, 'response should have expected error and no result', ) // first requests for both origins should remain assert.equal( - permController.pendingApprovals.size, 2, + permController.pendingApprovals.size, + 2, 'perm controller should have expected number of pending approvals', ) @@ -438,7 +470,8 @@ describe('permissions middleware', function () { 'first response should have result and no error', ) assert.equal( - resA1.result.length, 1, + resA1.result.length, + 1, 'first origin should have single approved permission', ) @@ -447,19 +480,20 @@ describe('permissions middleware', function () { 'second response should have result and no error', ) assert.equal( - resB1.result.length, 1, + resB1.result.length, + 1, 'second origin should have single approved permission', ) assert.equal( - permController.pendingApprovals.size, 0, + permController.pendingApprovals.size, + 0, 'perm controller should have expected number of pending approvals', ) }) }) describe('restricted methods', function () { - let permController beforeEach(function () { @@ -467,8 +501,10 @@ describe('permissions middleware', function () { }) it('prevents restricted method access for unpermitted domain', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) const req = RPC_REQUESTS.test_method(DOMAINS.a.origin) const res = {} @@ -482,27 +518,27 @@ describe('permissions middleware', function () { ) assert.ok( - ( - !res.result && res.error && - res.error.code === expectedError.code - ), + !res.result && res.error && res.error.code === expectedError.code, 'response should have expected error and no result', ) }) it('allows restricted method access for permitted domain', async function () { + const bMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.b.origin, + ) - const bMiddleware = getPermissionsMiddleware(permController, DOMAINS.b.origin) - - grantPermissions(permController, DOMAINS.b.origin, PERMS.finalizedRequests.test_method()) + grantPermissions( + permController, + DOMAINS.b.origin, + PERMS.finalizedRequests.test_method(), + ) const req = RPC_REQUESTS.test_method(DOMAINS.b.origin, true) const res = {} - await assert.doesNotReject( - bMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(bMiddleware(req, res), 'should not reject') assert.ok( res.result && res.result === 1, @@ -512,7 +548,6 @@ describe('permissions middleware', function () { }) describe('eth_accounts', function () { - let permController beforeEach(function () { @@ -520,57 +555,53 @@ describe('permissions middleware', function () { }) it('returns empty array for non-permitted domain', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) const req = RPC_REQUESTS.eth_accounts(DOMAINS.a.origin) const res = {} - await assert.doesNotReject( - aMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(aMiddleware(req, res), 'should not reject') assert.ok( res.result && !res.error, 'response should have result and no error', ) - assert.deepEqual( - res.result, [], - 'response should have correct result', - ) + assert.deepEqual(res.result, [], 'response should have correct result') }) it('returns correct accounts for permitted domain', async function () { - - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) grantPermissions( - permController, DOMAINS.a.origin, + permController, + DOMAINS.a.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted), ) const req = RPC_REQUESTS.eth_accounts(DOMAINS.a.origin) const res = {} - await assert.doesNotReject( - aMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(aMiddleware(req, res), 'should not reject') assert.ok( res.result && !res.error, 'response should have result and no error', ) assert.deepEqual( - res.result, [ACCOUNTS.a.primary], + res.result, + [ACCOUNTS.a.primary], 'response should have correct result', ) }) }) describe('eth_requestAccounts', function () { - let permController beforeEach(function () { @@ -578,10 +609,12 @@ describe('permissions middleware', function () { }) it('requests accounts for unpermitted origin, and approves on user approval', async function () { - const userApprovalPromise = getUserApprovalPromise(permController) - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) const req = RPC_REQUESTS.eth_requestAccounts(DOMAINS.a.origin) const res = {} @@ -594,22 +627,32 @@ describe('permissions middleware', function () { await userApprovalPromise assert.equal( - permController.pendingApprovals.size, 1, + permController.pendingApprovals.size, + 1, 'perm controller should have single pending approval', ) const id = permController.pendingApprovals.keys().next().value - const approvedReq = PERMS.approvedRequest(id, PERMS.requests.eth_accounts()) + const approvedReq = PERMS.approvedRequest( + id, + PERMS.requests.eth_accounts(), + ) - await permController.approvePermissionsRequest(approvedReq, ACCOUNTS.a.permitted) + await permController.approvePermissionsRequest( + approvedReq, + ACCOUNTS.a.permitted, + ) // wait for permission to be granted await pendingApproval - const perms = permController.permissions.getPermissionsForDomain(DOMAINS.a.origin) + const perms = permController.permissions.getPermissionsForDomain( + DOMAINS.a.origin, + ) assert.equal( - perms.length, 1, + perms.length, + 1, 'domain should have correct number of permissions', ) @@ -627,22 +670,27 @@ describe('permissions middleware', function () { ) assert.deepEqual( - res.result, [ACCOUNTS.a.primary], + res.result, + [ACCOUNTS.a.primary], 'result should have correct accounts', ) // we should also be able to get the accounts independently const aAccounts = await permController.getAccounts(DOMAINS.a.origin) assert.deepEqual( - aAccounts, [ACCOUNTS.a.primary], 'origin should have have correct accounts', + aAccounts, + [ACCOUNTS.a.primary], + 'origin should have have correct accounts', ) }) it('requests accounts for unpermitted origin, and rejects on user rejection', async function () { - const userApprovalPromise = getUserApprovalPromise(permController) - const aMiddleware = getPermissionsMiddleware(permController, DOMAINS.a.origin) + const aMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.a.origin, + ) const req = RPC_REQUESTS.eth_requestAccounts(DOMAINS.a.origin) const res = {} @@ -658,7 +706,8 @@ describe('permissions middleware', function () { await userApprovalPromise assert.equal( - permController.pendingApprovals.size, 1, + permController.pendingApprovals.size, + 1, 'perm controller should have single pending approval', ) @@ -668,48 +717,47 @@ describe('permissions middleware', function () { await requestRejection assert.ok( - ( - !res.result && res.error && - res.error.message === expectedError.message - ), + !res.result && res.error && res.error.message === expectedError.message, 'response should have expected error and no result', ) const aAccounts = await permController.getAccounts(DOMAINS.a.origin) assert.deepEqual( - aAccounts, [], 'origin should have have correct accounts', + aAccounts, + [], + 'origin should have have correct accounts', ) }) it('directly returns accounts for permitted domain', async function () { - - const cMiddleware = getPermissionsMiddleware(permController, DOMAINS.c.origin) + const cMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.c.origin, + ) grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.c.permitted), ) const req = RPC_REQUESTS.eth_requestAccounts(DOMAINS.c.origin) const res = {} - await assert.doesNotReject( - cMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(cMiddleware(req, res), 'should not reject') assert.ok( res.result && !res.error, 'response should have result and no error', ) assert.deepEqual( - res.result, [ACCOUNTS.c.primary], + res.result, + [ACCOUNTS.c.primary], 'response should have correct result', ) }) it('rejects new requests when request already pending', async function () { - let unlock const unlockPromise = new Promise((resolve) => { unlock = resolve @@ -717,10 +765,14 @@ describe('permissions middleware', function () { permController.getUnlockPromise = () => unlockPromise - const cMiddleware = getPermissionsMiddleware(permController, DOMAINS.c.origin) + const cMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.c.origin, + ) grantPermissions( - permController, DOMAINS.c.origin, + permController, + DOMAINS.c.origin, PERMS.finalizedRequests.eth_accounts(ACCOUNTS.c.permitted), ) @@ -749,14 +801,14 @@ describe('permissions middleware', function () { 'response should have result and no error', ) assert.deepEqual( - res.result, [ACCOUNTS.c.primary], + res.result, + [ACCOUNTS.c.primary], 'response should have correct result', ) }) }) describe('wallet_sendDomainMetadata', function () { - let permController, clock beforeEach(function () { @@ -769,18 +821,17 @@ describe('permissions middleware', function () { }) it('records domain metadata', async function () { - const name = 'BAZ' - const cMiddleware = getPermissionsMiddleware(permController, DOMAINS.c.origin) + const cMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.c.origin, + ) const req = RPC_REQUESTS.wallet_sendDomainMetadata(DOMAINS.c.origin, name) const res = {} - await assert.doesNotReject( - cMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(cMiddleware(req, res), 'should not reject') assert.ok(res.result, 'result should be true') @@ -800,20 +851,20 @@ describe('permissions middleware', function () { }) it('records domain metadata and preserves extensionId', async function () { - const extensionId = 'fooExtension' const name = 'BAZ' - const cMiddleware = getPermissionsMiddleware(permController, DOMAINS.c.origin, extensionId) + const cMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.c.origin, + extensionId, + ) const req = RPC_REQUESTS.wallet_sendDomainMetadata(DOMAINS.c.origin, name) const res = {} - await assert.doesNotReject( - cMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(cMiddleware(req, res), 'should not reject') assert.ok(res.result, 'result should be true') @@ -827,48 +878,48 @@ describe('permissions middleware', function () { }) it('should not record domain metadata if no name', async function () { - const name = null - const cMiddleware = getPermissionsMiddleware(permController, DOMAINS.c.origin) + const cMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.c.origin, + ) const req = RPC_REQUESTS.wallet_sendDomainMetadata(DOMAINS.c.origin, name) const res = {} - await assert.doesNotReject( - cMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(cMiddleware(req, res), 'should not reject') assert.ok(res.result, 'result should be true') const metadataStore = permController.store.getState()[METADATA_STORE_KEY] assert.deepEqual( - metadataStore, {}, + metadataStore, + {}, 'metadata should not have been added to store', ) }) it('should not record domain metadata if no metadata', async function () { - - const cMiddleware = getPermissionsMiddleware(permController, DOMAINS.c.origin) + const cMiddleware = getPermissionsMiddleware( + permController, + DOMAINS.c.origin, + ) const req = RPC_REQUESTS.wallet_sendDomainMetadata(DOMAINS.c.origin) delete req.domainMetadata const res = {} - await assert.doesNotReject( - cMiddleware(req, res), - 'should not reject', - ) + await assert.doesNotReject(cMiddleware(req, res), 'should not reject') assert.ok(res.result, 'result should be true') const metadataStore = permController.store.getState()[METADATA_STORE_KEY] assert.deepEqual( - metadataStore, {}, + metadataStore, + {}, 'metadata should not have been added to store', ) }) diff --git a/test/unit/app/controllers/permissions/restricted-methods-test.js b/test/unit/app/controllers/permissions/restricted-methods-test.js index 54ba3814f..2b7361110 100644 --- a/test/unit/app/controllers/permissions/restricted-methods-test.js +++ b/test/unit/app/controllers/permissions/restricted-methods-test.js @@ -1,8 +1,7 @@ import { strict as assert } from 'assert' import pify from 'pify' -import getRestrictedMethods - from '../../../../../app/scripts/controllers/permissions/restrictedMethods' +import getRestrictedMethods from '../../../../../app/scripts/controllers/permissions/restrictedMethods' describe('restricted methods', function () { describe('eth_accounts', function () { @@ -23,7 +22,8 @@ describe('restricted methods', function () { ) assert.deepEqual( - res, { error: fooError }, + res, + { error: fooError }, 'response should have expected error and no result', ) }) @@ -40,7 +40,11 @@ describe('restricted methods', function () { const res = {} await assert.rejects(ethAccountsMethod(null, res, null)) assert.ok(res.error instanceof Error, 'result should have error') - assert.deepEqual(Object.keys(res), ['error'], 'result should only contain error') + assert.deepEqual( + Object.keys(res), + ['error'], + 'result should only contain error', + ) }) it('should handle missing identity for second account when sorting', async function () { @@ -55,20 +59,21 @@ describe('restricted methods', function () { const res = {} await assert.rejects(ethAccountsMethod(null, res, null)) assert.ok(res.error instanceof Error, 'result should have error') - assert.deepEqual(Object.keys(res), ['error'], 'result should only contain error') + assert.deepEqual( + Object.keys(res), + ['error'], + 'result should only contain error', + ) }) it('should return accounts in keyring order when none are selected', async function () { const keyringAccounts = ['0x7e57e2', '0x7e57e3', '0x7e57e4', '0x7e57e5'] const restrictedMethods = getRestrictedMethods({ getIdentities: () => { - return keyringAccounts.reduce( - (identities, address) => { - identities[address] = {} - return identities - }, - {}, - ) + return keyringAccounts.reduce((identities, address) => { + identities[address] = {} + return identities + }, {}) }, getKeyringAccounts: async () => [...keyringAccounts], }) @@ -76,20 +81,21 @@ describe('restricted methods', function () { const res = {} await ethAccountsMethod(null, res, null) - assert.deepEqual(res, { result: keyringAccounts }, 'should return accounts in correct order') + assert.deepEqual( + res, + { result: keyringAccounts }, + 'should return accounts in correct order', + ) }) it('should return accounts in keyring order when all have same last selected time', async function () { const keyringAccounts = ['0x7e57e2', '0x7e57e3', '0x7e57e4', '0x7e57e5'] const restrictedMethods = getRestrictedMethods({ getIdentities: () => { - return keyringAccounts.reduce( - (identities, address) => { - identities[address] = { lastSelected: 1000 } - return identities - }, - {}, - ) + return keyringAccounts.reduce((identities, address) => { + identities[address] = { lastSelected: 1000 } + return identities + }, {}) }, getKeyringAccounts: async () => [...keyringAccounts], }) @@ -97,7 +103,11 @@ describe('restricted methods', function () { const res = {} await ethAccountsMethod(null, res, null) - assert.deepEqual(res, { result: keyringAccounts }, 'should return accounts in correct order') + assert.deepEqual( + res, + { result: keyringAccounts }, + 'should return accounts in correct order', + ) }) it('should return accounts sorted by last selected (descending)', async function () { @@ -105,13 +115,10 @@ describe('restricted methods', function () { const expectedResult = keyringAccounts.slice().reverse() const restrictedMethods = getRestrictedMethods({ getIdentities: () => { - return keyringAccounts.reduce( - (identities, address, index) => { - identities[address] = { lastSelected: index * 1000 } - return identities - }, - {}, - ) + return keyringAccounts.reduce((identities, address, index) => { + identities[address] = { lastSelected: index * 1000 } + return identities + }, {}) }, getKeyringAccounts: async () => [...keyringAccounts], }) @@ -119,12 +126,28 @@ describe('restricted methods', function () { const res = {} await ethAccountsMethod(null, res, null) - assert.deepEqual(res, { result: expectedResult }, 'should return accounts in correct order') + assert.deepEqual( + res, + { result: expectedResult }, + 'should return accounts in correct order', + ) }) it('should return accounts sorted by last selected (descending) with unselected accounts last, in keyring order', async function () { - const keyringAccounts = ['0x7e57e2', '0x7e57e3', '0x7e57e4', '0x7e57e5', '0x7e57e6'] - const expectedResult = ['0x7e57e4', '0x7e57e2', '0x7e57e3', '0x7e57e5', '0x7e57e6'] + const keyringAccounts = [ + '0x7e57e2', + '0x7e57e3', + '0x7e57e4', + '0x7e57e5', + '0x7e57e6', + ] + const expectedResult = [ + '0x7e57e4', + '0x7e57e2', + '0x7e57e3', + '0x7e57e5', + '0x7e57e6', + ] const restrictedMethods = getRestrictedMethods({ getIdentities: () => { return { @@ -141,7 +164,11 @@ describe('restricted methods', function () { const res = {} await ethAccountsMethod(null, res, null) - assert.deepEqual(res, { result: expectedResult }, 'should return accounts in correct order') + assert.deepEqual( + res, + { result: expectedResult }, + 'should return accounts in correct order', + ) }) }) }) diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index a1ffe5b7b..e041bb582 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -11,7 +11,10 @@ describe('preferences controller', function () { beforeEach(function () { network = { providerStore: new ObservableStore({ type: 'mainnet' }) } - preferencesController = new PreferencesController({ migrateAddressBookState, network }) + preferencesController = new PreferencesController({ + migrateAddressBookState, + network, + }) }) afterEach(function () { @@ -20,10 +23,7 @@ describe('preferences controller', function () { describe('setAddresses', function () { it('should keep a map of addresses to names and addresses in the store', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) const { identities } = preferencesController.store.getState() assert.deepEqual(identities, { @@ -39,10 +39,7 @@ describe('preferences controller', function () { }) it('should create account tokens for each account in the store', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) const { accountTokens } = preferencesController.store.getState() @@ -53,14 +50,8 @@ describe('preferences controller', function () { }) it('should replace its list of addresses', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) - preferencesController.setAddresses([ - '0xda22le77', - '0x7e57e277', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) + preferencesController.setAddresses(['0xda22le77', '0x7e57e277']) const { identities } = preferencesController.store.getState() assert.deepEqual(identities, { @@ -78,32 +69,29 @@ describe('preferences controller', function () { describe('removeAddress', function () { it('should remove an address from state', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) preferencesController.removeAddress('0xda22le') - assert.equal(preferencesController.store.getState().identities['0xda22le'], undefined) + assert.equal( + preferencesController.store.getState().identities['0xda22le'], + undefined, + ) }) it('should remove an address from state and respective tokens', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) preferencesController.removeAddress('0xda22le') - assert.equal(preferencesController.store.getState().accountTokens['0xda22le'], undefined) + assert.equal( + preferencesController.store.getState().accountTokens['0xda22le'], + undefined, + ) }) it('should switch accounts if the selected address is removed', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) preferencesController.setSelectedAddress('0x7e57e2') preferencesController.removeAddress('0x7e57e2') @@ -114,21 +102,24 @@ describe('preferences controller', function () { describe('setAccountLabel', function () { it('should update a label for the given account', function () { - preferencesController.setAddresses([ - '0xda22le', - '0x7e57e2', - ]) + preferencesController.setAddresses(['0xda22le', '0x7e57e2']) - assert.deepEqual(preferencesController.store.getState().identities['0xda22le'], { - name: 'Account 1', - address: '0xda22le', - }) + assert.deepEqual( + preferencesController.store.getState().identities['0xda22le'], + { + name: 'Account 1', + address: '0xda22le', + }, + ) preferencesController.setAccountLabel('0xda22le', 'Dazzle') - assert.deepEqual(preferencesController.store.getState().identities['0xda22le'], { - name: 'Dazzle', - address: '0xda22le', - }) + assert.deepEqual( + preferencesController.store.getState().identities['0xda22le'], + { + name: 'Dazzle', + address: '0xda22le', + }, + ) }) }) @@ -187,18 +178,23 @@ describe('preferences controller', function () { const symbol = 'ABBR' const decimals = 5 - preferencesController.setAddresses([ - '0x7e57e2', - '0xda22le', - ]) + preferencesController.setAddresses(['0x7e57e2', '0xda22le']) await preferencesController.setSelectedAddress('0x7e57e2') await preferencesController.addToken(address, symbol, decimals) - assert.equal(preferencesController.getTokens().length, 1, 'one token added for 1st address') + assert.equal( + preferencesController.getTokens().length, + 1, + 'one token added for 1st address', + ) await preferencesController.setSelectedAddress('0xda22le') await preferencesController.addToken(address, symbol, decimals) - assert.equal(preferencesController.getTokens().length, 1, 'one token added for 2nd address') + assert.equal( + preferencesController.getTokens().length, + 1, + 'one token added for 2nd address', + ) }) it('should add token per account', async function () { @@ -208,20 +204,25 @@ describe('preferences controller', function () { const symbolSecond = 'ABBB' const decimals = 5 - preferencesController.setAddresses([ - '0x7e57e2', - '0xda22le', - ]) + preferencesController.setAddresses(['0x7e57e2', '0xda22le']) await preferencesController.setSelectedAddress('0x7e57e2') await preferencesController.addToken(addressFirst, symbolFirst, decimals) const tokensFirstAddress = preferencesController.getTokens() await preferencesController.setSelectedAddress('0xda22le') - await preferencesController.addToken(addressSecond, symbolSecond, decimals) + await preferencesController.addToken( + addressSecond, + symbolSecond, + decimals, + ) const tokensSeconAddress = preferencesController.getTokens() - assert.notEqual(tokensFirstAddress, tokensSeconAddress, 'add different tokens for two account and tokens are equal') + assert.notEqual( + tokensFirstAddress, + tokensSeconAddress, + 'add different tokens for two account and tokens are equal', + ) }) it('should add token per network', async function () { @@ -236,10 +237,18 @@ describe('preferences controller', function () { const tokensFirstAddress = preferencesController.getTokens() network.providerStore.updateState({ type: 'rinkeby' }) - await preferencesController.addToken(addressSecond, symbolSecond, decimals) + await preferencesController.addToken( + addressSecond, + symbolSecond, + decimals, + ) const tokensSeconAddress = preferencesController.getTokens() - assert.notEqual(tokensFirstAddress, tokensSeconAddress, 'add different tokens for two networks and tokens are equal') + assert.notEqual( + tokensFirstAddress, + tokensSeconAddress, + 'add different tokens for two networks and tokens are equal', + ) }) }) @@ -269,10 +278,7 @@ describe('preferences controller', function () { }) it('should remove a token from its state on corresponding address', async function () { - preferencesController.setAddresses([ - '0x7e57e2', - '0x7e57e3', - ]) + preferencesController.setAddresses(['0x7e57e2', '0x7e57e3']) await preferencesController.setSelectedAddress('0x7e57e2') await preferencesController.addToken('0xa', 'A', 4) await preferencesController.addToken('0xb', 'B', 5) @@ -291,7 +297,11 @@ describe('preferences controller', function () { await preferencesController.setSelectedAddress('0x7e57e3') const tokensSecond = preferencesController.getTokens() - assert.deepEqual(tokensSecond, initialTokensSecond, 'token deleted for account') + assert.deepEqual( + tokensSecond, + initialTokensSecond, + 'token deleted for account', + ) }) it('should remove a token from its state on corresponding network', async function () { @@ -313,16 +323,17 @@ describe('preferences controller', function () { network.providerStore.updateState({ type: 'rinkeby' }) const tokensSecond = preferencesController.getTokens() - assert.deepEqual(tokensSecond, initialTokensSecond, 'token deleted for network') + assert.deepEqual( + tokensSecond, + initialTokensSecond, + 'token deleted for network', + ) }) }) describe('on setSelectedAddress', function () { it('should update tokens from its state on corresponding address', async function () { - preferencesController.setAddresses([ - '0x7e57e2', - '0x7e57e3', - ]) + preferencesController.setAddresses(['0x7e57e2', '0x7e57e3']) await preferencesController.setSelectedAddress('0x7e57e2') await preferencesController.addToken('0xa', 'A', 4) await preferencesController.addToken('0xb', 'B', 5) @@ -335,15 +346,27 @@ describe('preferences controller', function () { await preferencesController.setSelectedAddress('0x7e57e3') const initialTokensSecond = preferencesController.getTokens() - assert.notDeepEqual(initialTokensFirst, initialTokensSecond, 'tokens not equal for different accounts and tokens') + assert.notDeepEqual( + initialTokensFirst, + initialTokensSecond, + 'tokens not equal for different accounts and tokens', + ) await preferencesController.setSelectedAddress('0x7e57e2') const tokensFirst = preferencesController.getTokens() await preferencesController.setSelectedAddress('0x7e57e3') const tokensSecond = preferencesController.getTokens() - assert.deepEqual(tokensFirst, initialTokensFirst, 'tokens equal for same account') - assert.deepEqual(tokensSecond, initialTokensSecond, 'tokens equal for same account') + assert.deepEqual( + tokensFirst, + initialTokensFirst, + 'tokens equal for same account', + ) + assert.deepEqual( + tokensSecond, + initialTokensSecond, + 'tokens equal for same account', + ) }) }) @@ -358,14 +381,26 @@ describe('preferences controller', function () { await preferencesController.addToken('0xb', 'D', 5) const initialTokensSecond = preferencesController.getTokens() - assert.notDeepEqual(initialTokensFirst, initialTokensSecond, 'tokens not equal for different networks and tokens') + assert.notDeepEqual( + initialTokensFirst, + initialTokensSecond, + 'tokens not equal for different networks and tokens', + ) network.providerStore.updateState({ type: 'mainnet' }) const tokensFirst = preferencesController.getTokens() network.providerStore.updateState({ type: 'rinkeby' }) const tokensSecond = preferencesController.getTokens() - assert.deepEqual(tokensFirst, initialTokensFirst, 'tokens equal for same network') - assert.deepEqual(tokensSecond, initialTokensSecond, 'tokens equal for same network') + assert.deepEqual( + tokensFirst, + initialTokensFirst, + 'tokens equal for same network', + ) + assert.deepEqual( + tokensSecond, + initialTokensSecond, + 'tokens equal for same network', + ) }) }) @@ -377,7 +412,10 @@ describe('preferences controller', function () { req = { params: {} } res = {} asy = { next: sandbox.spy(), end: sandbox.spy() } - stubHandleWatchAssetERC20 = sandbox.stub(preferencesController, '_handleWatchAssetERC20') + stubHandleWatchAssetERC20 = sandbox.stub( + preferencesController, + '_handleWatchAssetERC20', + ) }) after(function () { sandbox.restore() @@ -436,16 +474,26 @@ describe('preferences controller', function () { const image = 'someimage' req.params.options = { address, symbol, decimals, image } - sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) + sandbox + .stub(preferencesController, '_validateERC20AssetParams') + .returns(true) preferencesController.openPopup = async () => undefined await preferencesController._handleWatchAssetERC20(req.params.options) const suggested = preferencesController.getSuggestedTokens() - assert.equal(Object.keys(suggested).length, 1, `one token added ${Object.keys(suggested)}`) + assert.equal( + Object.keys(suggested).length, + 1, + `one token added ${Object.keys(suggested)}`, + ) assert.equal(suggested[address].address, address, 'set address correctly') assert.equal(suggested[address].symbol, symbol, 'set symbol correctly') - assert.equal(suggested[address].decimals, decimals, 'set decimals correctly') + assert.equal( + suggested[address].decimals, + decimals, + 'set decimals correctly', + ) assert.equal(suggested[address].image, image, 'set image correctly') }) @@ -456,7 +504,9 @@ describe('preferences controller', function () { const image = 'someimage' req.params.options = { address, symbol, decimals, image } - sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) + sandbox + .stub(preferencesController, '_validateERC20AssetParams') + .returns(true) preferencesController.openPopup = async () => { await preferencesController.addToken(address, symbol, decimals, image) } @@ -475,14 +525,64 @@ describe('preferences controller', function () { it('should validate ERC20 asset correctly', async function () { const validate = preferencesController._validateERC20AssetParams - assert.doesNotThrow(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 0 })) - assert.throws(() => validate({ symbol: 'ABC', decimals: 0 }), 'missing address should fail') - assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', decimals: 0 }), 'missing symbol should fail') - assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC' }), 'missing decimals should fail') - assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 0 }), 'invalid symbol should fail') - assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: -1 }), 'decimals < 0 should fail') - assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 38 }), 'decimals > 36 should fail') - assert.throws(() => validate({ rawAddress: '0x123', symbol: 'ABC', decimals: 0 }), 'invalid address should fail') + assert.doesNotThrow(() => + validate({ + rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', + symbol: 'ABC', + decimals: 0, + }), + ) + assert.throws( + () => validate({ symbol: 'ABC', decimals: 0 }), + 'missing address should fail', + ) + assert.throws( + () => + validate({ + rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', + decimals: 0, + }), + 'missing symbol should fail', + ) + assert.throws( + () => + validate({ + rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', + symbol: 'ABC', + }), + 'missing decimals should fail', + ) + assert.throws( + () => + validate({ + rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', + symbol: 'ABCDEFGHI', + decimals: 0, + }), + 'invalid symbol should fail', + ) + assert.throws( + () => + validate({ + rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', + symbol: 'ABC', + decimals: -1, + }), + 'decimals < 0 should fail', + ) + assert.throws( + () => + validate({ + rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', + symbol: 'ABC', + decimals: 38, + }), + 'decimals > 36 should fail', + ) + assert.throws( + () => validate({ rawAddress: '0x123', symbol: 'ABC', decimals: 0 }), + 'invalid address should fail', + ) }) }) @@ -493,27 +593,46 @@ describe('preferences controller', function () { }) it('should set the forgottenPassword property in state', function () { - assert.equal(preferencesController.store.getState().forgottenPassword, false) + assert.equal( + preferencesController.store.getState().forgottenPassword, + false, + ) preferencesController.setPasswordForgotten(true) - assert.equal(preferencesController.store.getState().forgottenPassword, true) + assert.equal( + preferencesController.store.getState().forgottenPassword, + true, + ) }) }) describe('#updateRpc', function () { it('should update the rpcDetails properly', async function () { - preferencesController.store.updateState({ frequentRpcListDetail: [{}, { rpcUrl: 'test', chainId: '0x1' }, {}] }) + preferencesController.store.updateState({ + frequentRpcListDetail: [{}, { rpcUrl: 'test', chainId: '0x1' }, {}], + }) await preferencesController.updateRpc({ rpcUrl: 'test', chainId: '0x1' }) - await preferencesController.updateRpc({ rpcUrl: 'test/1', chainId: '0x1' }) - await preferencesController.updateRpc({ rpcUrl: 'test/2', chainId: '0x1' }) - await preferencesController.updateRpc({ rpcUrl: 'test/3', chainId: '0x1' }) + await preferencesController.updateRpc({ + rpcUrl: 'test/1', + chainId: '0x1', + }) + await preferencesController.updateRpc({ + rpcUrl: 'test/2', + chainId: '0x1', + }) + await preferencesController.updateRpc({ + rpcUrl: 'test/3', + chainId: '0x1', + }) const list = preferencesController.getFrequentRpcListDetail() assert.deepEqual(list[1], { rpcUrl: 'test', chainId: '0x1' }) }) it('should migrate address book entries if chainId changes', async function () { - preferencesController.store.updateState({ frequentRpcListDetail: [{}, { rpcUrl: 'test', chainId: '1' }, {}] }) + preferencesController.store.updateState({ + frequentRpcListDetail: [{}, { rpcUrl: 'test', chainId: '1' }, {}], + }) await preferencesController.updateRpc({ rpcUrl: 'test', chainId: '0x1' }) assert(migrateAddressBookState.calledWith('1', '0x1')) }) @@ -524,43 +643,58 @@ describe('preferences controller', function () { preferencesController.addToFrequentRpcList('rpc_url', '0x1') assert.deepEqual( preferencesController.store.getState().frequentRpcListDetail, - [{ - rpcUrl: 'rpc_url', - chainId: '0x1', - ticker: 'ETH', - nickname: '', - rpcPrefs: {}, - }], + [ + { + rpcUrl: 'rpc_url', + chainId: '0x1', + ticker: 'ETH', + nickname: '', + rpcPrefs: {}, + }, + ], ) preferencesController.addToFrequentRpcList('rpc_url', '0x1') assert.deepEqual( preferencesController.store.getState().frequentRpcListDetail, - [{ - rpcUrl: 'rpc_url', - chainId: '0x1', - ticker: 'ETH', - nickname: '', - rpcPrefs: {}, - }], + [ + { + rpcUrl: 'rpc_url', + chainId: '0x1', + ticker: 'ETH', + nickname: '', + rpcPrefs: {}, + }, + ], ) }) it('should throw if chainId is invalid', function () { - assert.throws( - () => { - preferencesController.addToFrequentRpcList('rpc_url', '1') - }, - 'should throw on invalid chainId', - ) + assert.throws(() => { + preferencesController.addToFrequentRpcList('rpc_url', '1') + }, 'should throw on invalid chainId') }) it('should remove custom RPC url from state', function () { preferencesController.addToFrequentRpcList('rpc_url', '0x1') - assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '0x1', ticker: 'ETH', nickname: '', rpcPrefs: {} }]) + assert.deepEqual( + preferencesController.store.getState().frequentRpcListDetail, + [ + { + rpcUrl: 'rpc_url', + chainId: '0x1', + ticker: 'ETH', + nickname: '', + rpcPrefs: {}, + }, + ], + ) preferencesController.removeFromFrequentRpcList('other_rpc_url') preferencesController.removeFromFrequentRpcList('http://localhost:8545') preferencesController.removeFromFrequentRpcList('rpc_url') - assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, []) + assert.deepEqual( + preferencesController.store.getState().frequentRpcListDetail, + [], + ) }) }) diff --git a/test/unit/app/controllers/swaps-test.js b/test/unit/app/controllers/swaps-test.js index 9707b34e6..e7f462852 100644 --- a/test/unit/app/controllers/swaps-test.js +++ b/test/unit/app/controllers/swaps-test.js @@ -4,9 +4,14 @@ import sinon from 'sinon' import { ethers } from 'ethers' import BigNumber from 'bignumber.js' import ObservableStore from 'obs-store' -import { ROPSTEN_NETWORK_ID, MAINNET_NETWORK_ID } from '../../../../app/scripts/controllers/network/enums' +import { + ROPSTEN_NETWORK_ID, + MAINNET_NETWORK_ID, +} from '../../../../app/scripts/controllers/network/enums' import { createTestProviderTools } from '../../../stub/provider' -import SwapsController, { utils } from '../../../../app/scripts/controllers/swaps' +import SwapsController, { + utils, +} from '../../../../app/scripts/controllers/swaps' const MOCK_FETCH_PARAMS = { slippage: 3, @@ -24,12 +29,13 @@ const TEST_AGG_ID_BEST = 'TEST_AGG_BEST' const TEST_AGG_ID_APPROVAL = 'TEST_AGG_APPROVAL' const MOCK_APPROVAL_NEEDED = { - 'data': '0x095ea7b300000000000000000000000095e6f48254609a6ee006f7d493c8e5fb97094cef0000000000000000000000000000000000000000004a817c7ffffffdabf41c00', - 'to': '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - 'amount': '0', - 'from': '0x2369267687A84ac7B494daE2f1542C40E37f4455', - 'gas': '12', - 'gasPrice': '34', + data: + '0x095ea7b300000000000000000000000095e6f48254609a6ee006f7d493c8e5fb97094cef0000000000000000000000000000000000000000004a817c7ffffffdabf41c00', + to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + amount: '0', + from: '0x2369267687A84ac7B494daE2f1542C40E37f4455', + gas: '12', + gasPrice: '34', } const MOCK_QUOTES_APPROVAL_REQUIRED = { @@ -76,7 +82,7 @@ const MOCK_GET_BUFFERED_GAS_LIMIT = async () => ({ simulationFails: undefined, }) -function getMockNetworkController () { +function getMockNetworkController() { return { store: { getState: () => { @@ -134,8 +140,11 @@ describe('SwapsController', function () { // by default, all accounts are external accounts (not contracts) eth_getCode: '0x', } - provider = createTestProviderTools({ scaffold: providerResultStub, networkId: 1, chainId: 1 }) - .provider + provider = createTestProviderTools({ + scaffold: providerResultStub, + networkId: 1, + chainId: 1, + }).provider }) afterEach(function () { @@ -580,7 +589,6 @@ describe('SwapsController', function () { }) describe('_setupSwapsLivenessFetching ', function () { - let clock const EXPECTED_TIME = 600000 @@ -603,15 +611,11 @@ describe('SwapsController', function () { clock = sandbox.useFakeTimers() sandbox.spy(clock, 'setInterval') - sandbox.stub( - SwapsController.prototype, - '_fetchAndSetSwapsLiveness', - ).resolves(undefined) + sandbox + .stub(SwapsController.prototype, '_fetchAndSetSwapsLiveness') + .resolves(undefined) - sandbox.spy( - SwapsController.prototype, - '_setupSwapsLivenessFetching', - ) + sandbox.spy(SwapsController.prototype, '_setupSwapsLivenessFetching') sandbox.spy(window, 'addEventListener') }) @@ -627,12 +631,8 @@ describe('SwapsController', function () { swapsController._setupSwapsLivenessFetching.calledOnce, 'should have called _setupSwapsLivenessFetching once', ) - assert.ok( - window.addEventListener.calledWith('online'), - ) - assert.ok( - window.addEventListener.calledWith('offline'), - ) + assert.ok(window.addEventListener.calledWith('online')) + assert.ok(window.addEventListener.calledWith('offline')) assert.ok( clock.setInterval.calledOnceWithExactly( sinon.match.func, @@ -659,7 +659,8 @@ describe('SwapsController', function () { 'should not have set an interval', ) assert.strictEqual( - getLivenessState(), false, + getLivenessState(), + false, 'swaps feature should be disabled', ) @@ -734,24 +735,21 @@ describe('SwapsController', function () { 'should have called updateState once', ) assert.strictEqual( - getLivenessState(), false, + getLivenessState(), + false, 'swaps feature should be disabled', ) }) }) describe('_fetchAndSetSwapsLiveness', function () { - const getLivenessState = () => { return swapsController.store.getState().swapsState.swapsFeatureIsLive } beforeEach(function () { fetchSwapsFeatureLivenessStub.reset() - sandbox.stub( - SwapsController.prototype, - '_setupSwapsLivenessFetching', - ) + sandbox.stub(SwapsController.prototype, '_setupSwapsLivenessFetching') swapsController = getSwapsController() }) @@ -763,7 +761,9 @@ describe('SwapsController', function () { fetchSwapsFeatureLivenessStub.resolves(true) assert.strictEqual( - getLivenessState(), false, 'liveness should be false on boot', + getLivenessState(), + false, + 'liveness should be false on boot', ) await swapsController._fetchAndSetSwapsLiveness() @@ -773,7 +773,9 @@ describe('SwapsController', function () { 'should have called fetch function once', ) assert.strictEqual( - getLivenessState(), true, 'liveness should be true after call', + getLivenessState(), + true, + 'liveness should be true after call', ) }) @@ -782,7 +784,9 @@ describe('SwapsController', function () { sandbox.spy(swapsController.store, 'updateState') assert.strictEqual( - getLivenessState(), false, 'liveness should be false on boot', + getLivenessState(), + false, + 'liveness should be false on boot', ) await swapsController._fetchAndSetSwapsLiveness() @@ -796,7 +800,9 @@ describe('SwapsController', function () { 'should not have called store.updateState', ) assert.strictEqual( - getLivenessState(), false, 'liveness should remain false after call', + getLivenessState(), + false, + 'liveness should remain false after call', ) }) @@ -806,7 +812,9 @@ describe('SwapsController', function () { sandbox.spy(swapsController.store, 'updateState') assert.strictEqual( - getLivenessState(), false, 'liveness should be false on boot', + getLivenessState(), + false, + 'liveness should be false on boot', ) swapsController._fetchAndSetSwapsLiveness() @@ -821,7 +829,9 @@ describe('SwapsController', function () { 'should not have called store.updateState', ) assert.strictEqual( - getLivenessState(), false, 'liveness should remain false after call', + getLivenessState(), + false, + 'liveness should remain false after call', ) }) @@ -832,18 +842,23 @@ describe('SwapsController', function () { fetchSwapsFeatureLivenessStub.onCall(2).resolves(true) assert.strictEqual( - getLivenessState(), false, 'liveness should be false on boot', + getLivenessState(), + false, + 'liveness should be false on boot', ) swapsController._fetchAndSetSwapsLiveness() await clock.runAllAsync() assert.strictEqual( - fetchSwapsFeatureLivenessStub.callCount, 3, + fetchSwapsFeatureLivenessStub.callCount, + 3, 'should have called fetch function three times', ) assert.strictEqual( - getLivenessState(), true, 'liveness should be true after call', + getLivenessState(), + true, + 'liveness should be true after call', ) }) }) @@ -858,7 +873,8 @@ describe('SwapsController', function () { const median = getMedian(values) assert.strictEqual( - median.toNumber(), 3, + median.toNumber(), + 3, 'should have returned correct median', ) }) @@ -868,129 +884,121 @@ describe('SwapsController', function () { const median = getMedian(values) assert.strictEqual( - median.toNumber(), 2.5, + median.toNumber(), + 2.5, 'should have returned correct median', ) }) it('throws on empty or non-array sample', function () { - assert.throws( - () => getMedian([]), - 'should throw on empty array', - ) + assert.throws(() => getMedian([]), 'should throw on empty array') - assert.throws( - () => getMedian(), - 'should throw on non-array param', - ) + assert.throws(() => getMedian(), 'should throw on non-array param') - assert.throws( - () => getMedian({}), - 'should throw on non-array param', - ) + assert.throws(() => getMedian({}), 'should throw on non-array param') }) }) }) }) -function getMockQuotes () { +function getMockQuotes() { return { [TEST_AGG_ID_1]: { - 'trade': { - 'from': '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', - 'value': '0x0', - 'gas': '0x61a80', // 4e5 - 'to': '0x881D40237659C251811CEC9c364ef91dC08D300C', + trade: { + from: '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', + value: '0x0', + gas: '0x61a80', // 4e5 + to: '0x881D40237659C251811CEC9c364ef91dC08D300C', }, - 'sourceAmount': '10000000000000000000', // 10e18 - 'destinationAmount': '20000000000000000000', // 20e18 - 'error': null, - 'sourceToken': '0x6b175474e89094c44da98b954eedeac495271d0f', - 'destinationToken': '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - 'approvalNeeded': null, - 'maxGas': 600000, - 'averageGas': 120000, - 'estimatedRefund': 80000, - 'fetchTime': 607, - 'aggregator': TEST_AGG_ID_1, - 'aggType': 'AGG', - 'slippage': 2, - 'sourceTokenInfo': { - 'address': '0x6b175474e89094c44da98b954eedeac495271d0f', - 'symbol': 'DAI', - 'decimals': 18, - 'iconUrl': 'https://foo.bar/logo.png', + sourceAmount: '10000000000000000000', // 10e18 + destinationAmount: '20000000000000000000', // 20e18 + error: null, + sourceToken: '0x6b175474e89094c44da98b954eedeac495271d0f', + destinationToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + approvalNeeded: null, + maxGas: 600000, + averageGas: 120000, + estimatedRefund: 80000, + fetchTime: 607, + aggregator: TEST_AGG_ID_1, + aggType: 'AGG', + slippage: 2, + sourceTokenInfo: { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'DAI', + decimals: 18, + iconUrl: 'https://foo.bar/logo.png', }, - 'destinationTokenInfo': { - 'address': '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - 'symbol': 'USDC', - 'decimals': 18, + destinationTokenInfo: { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + symbol: 'USDC', + decimals: 18, }, }, [TEST_AGG_ID_BEST]: { - 'trade': { - 'from': '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', - 'value': '0x0', - 'gas': '0x61a80', - 'to': '0x881D40237659C251811CEC9c364ef91dC08D300C', + trade: { + from: '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', + value: '0x0', + gas: '0x61a80', + to: '0x881D40237659C251811CEC9c364ef91dC08D300C', }, - 'sourceAmount': '10000000000000000000', - 'destinationAmount': '25000000000000000000', // 25e18 - 'error': null, - 'sourceToken': '0x6b175474e89094c44da98b954eedeac495271d0f', - 'destinationToken': '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - 'approvalNeeded': null, - 'maxGas': 1100000, - 'averageGas': 411000, - 'estimatedRefund': 343090, - 'fetchTime': 1003, - 'aggregator': TEST_AGG_ID_BEST, - 'aggType': 'AGG', - 'slippage': 2, - 'sourceTokenInfo': { - 'address': '0x6b175474e89094c44da98b954eedeac495271d0f', - 'symbol': 'DAI', - 'decimals': 18, - 'iconUrl': 'https://foo.bar/logo.png', + sourceAmount: '10000000000000000000', + destinationAmount: '25000000000000000000', // 25e18 + error: null, + sourceToken: '0x6b175474e89094c44da98b954eedeac495271d0f', + destinationToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + approvalNeeded: null, + maxGas: 1100000, + averageGas: 411000, + estimatedRefund: 343090, + fetchTime: 1003, + aggregator: TEST_AGG_ID_BEST, + aggType: 'AGG', + slippage: 2, + sourceTokenInfo: { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'DAI', + decimals: 18, + iconUrl: 'https://foo.bar/logo.png', }, - 'destinationTokenInfo': { - 'address': '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - 'symbol': 'USDC', - 'decimals': 18, + destinationTokenInfo: { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + symbol: 'USDC', + decimals: 18, }, }, [TEST_AGG_ID_2]: { - 'trade': { - 'from': '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', - 'value': '0x0', - 'gas': '0x61a80', - 'to': '0x881D40237659C251811CEC9c364ef91dC08D300C', + trade: { + from: '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', + value: '0x0', + gas: '0x61a80', + to: '0x881D40237659C251811CEC9c364ef91dC08D300C', }, - 'sourceAmount': '10000000000000000000', - 'destinationAmount': '22000000000000000000', // 22e18 - 'error': null, - 'sourceToken': '0x6b175474e89094c44da98b954eedeac495271d0f', - 'destinationToken': '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - 'approvalNeeded': null, - 'maxGas': 368000, - 'averageGas': 197000, - 'estimatedRefund': 18205, - 'fetchTime': 1354, - 'aggregator': TEST_AGG_ID_2, - 'aggType': 'AGG', - 'slippage': 2, - 'sourceTokenInfo': { - 'address': '0x6b175474e89094c44da98b954eedeac495271d0f', - 'symbol': 'DAI', - 'decimals': 18, - 'iconUrl': 'https://foo.bar/logo.png', + sourceAmount: '10000000000000000000', + destinationAmount: '22000000000000000000', // 22e18 + error: null, + sourceToken: '0x6b175474e89094c44da98b954eedeac495271d0f', + destinationToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + approvalNeeded: null, + maxGas: 368000, + averageGas: 197000, + estimatedRefund: 18205, + fetchTime: 1354, + aggregator: TEST_AGG_ID_2, + aggType: 'AGG', + slippage: 2, + sourceTokenInfo: { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'DAI', + decimals: 18, + iconUrl: 'https://foo.bar/logo.png', }, - 'destinationTokenInfo': { - 'address': '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - 'symbol': 'USDC', - 'decimals': 18, + destinationTokenInfo: { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + symbol: 'USDC', + decimals: 18, }, }, } diff --git a/test/unit/app/controllers/transactions/pending-tx-tracker-test.js b/test/unit/app/controllers/transactions/pending-tx-tracker-test.js index bbdc72551..e5756858b 100644 --- a/test/unit/app/controllers/transactions/pending-tx-tracker-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-tracker-test.js @@ -28,17 +28,23 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.on('tx:warning', warningListener) await pendingTxTracker.resubmitPendingTxs('0x1') - assert.ok(getPendingTransactions.calledOnceWithExactly(), 'should call getPendingTransaction') + assert.ok( + getPendingTransactions.calledOnceWithExactly(), + 'should call getPendingTransaction', + ) assert.ok(resubmitTx.notCalled, 'should NOT call _resubmitTx') assert.ok(warningListener.notCalled, "should NOT emit 'tx:warning'") }) it('should resubmit each pending transaction', async function () { - const getPendingTransactions = sinon.stub().returns([{ - id: 1, - }, { - id: 2, - }]) + const getPendingTransactions = sinon.stub().returns([ + { + id: 1, + }, + { + id: 2, + }, + ]) const pendingTxTracker = new PendingTransactionTracker({ query: { getTransactionReceipt: sinon.stub(), @@ -60,15 +66,20 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.on('tx:warning', warningListener) await pendingTxTracker.resubmitPendingTxs('0x1') - assert.ok(getPendingTransactions.calledOnceWithExactly(), 'should call getPendingTransaction') + assert.ok( + getPendingTransactions.calledOnceWithExactly(), + 'should call getPendingTransaction', + ) assert.ok(resubmitTx.calledTwice, 'should call _resubmitTx') assert.ok(warningListener.notCalled, "should NOT emit 'tx:warning'") }) it("should NOT emit 'tx:warning' for known failed resubmission", async function () { - const getPendingTransactions = sinon.stub().returns([{ - id: 1, - }]) + const getPendingTransactions = sinon.stub().returns([ + { + id: 1, + }, + ]) const pendingTxTracker = new PendingTransactionTracker({ query: { getTransactionReceipt: sinon.stub(), @@ -84,21 +95,28 @@ describe('PendingTransactionTracker', function () { publishTransaction: sinon.spy(), confirmTransaction: sinon.spy(), }) - const resubmitTx = sinon.stub(pendingTxTracker, '_resubmitTx').rejects({ message: 'known transaction' }) + const resubmitTx = sinon + .stub(pendingTxTracker, '_resubmitTx') + .rejects({ message: 'known transaction' }) const warningListener = sinon.spy() pendingTxTracker.on('tx:warning', warningListener) await pendingTxTracker.resubmitPendingTxs('0x1') - assert.ok(getPendingTransactions.calledOnceWithExactly(), 'should call getPendingTransaction') + assert.ok( + getPendingTransactions.calledOnceWithExactly(), + 'should call getPendingTransaction', + ) assert.ok(resubmitTx.calledOnce, 'should call _resubmitTx') assert.ok(warningListener.notCalled, "should NOT emit 'tx:warning'") }) it("should emit 'tx:warning' for unknown failed resubmission", async function () { - const getPendingTransactions = sinon.stub().returns([{ - id: 1, - }]) + const getPendingTransactions = sinon.stub().returns([ + { + id: 1, + }, + ]) const pendingTxTracker = new PendingTransactionTracker({ query: { getTransactionReceipt: sinon.stub(), @@ -114,13 +132,18 @@ describe('PendingTransactionTracker', function () { publishTransaction: sinon.spy(), confirmTransaction: sinon.spy(), }) - const resubmitTx = sinon.stub(pendingTxTracker, '_resubmitTx').rejects({ message: 'who dis' }) + const resubmitTx = sinon + .stub(pendingTxTracker, '_resubmitTx') + .rejects({ message: 'who dis' }) const warningListener = sinon.spy() pendingTxTracker.on('tx:warning', warningListener) await pendingTxTracker.resubmitPendingTxs('0x1') - assert.ok(getPendingTransactions.calledOnceWithExactly(), 'should call getPendingTransaction') + assert.ok( + getPendingTransactions.calledOnceWithExactly(), + 'should call getPendingTransaction', + ) assert.ok(resubmitTx.calledOnce, 'should call _resubmitTx') assert.ok(warningListener.calledOnce, "should emit 'tx:warning'") }) @@ -130,7 +153,8 @@ describe('PendingTransactionTracker', function () { it('should call _checkPendingTx for each pending transaction', async function () { const txMeta = { id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'signed', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', @@ -138,7 +162,8 @@ describe('PendingTransactionTracker', function () { value: '0xfffff', }, history: [{}], - rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + rawTx: + '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', } const txList = [1, 2, 3].map((id) => ({ ...txMeta, id })) const pendingTxTracker = new PendingTransactionTracker({ @@ -158,13 +183,27 @@ describe('PendingTransactionTracker', function () { confirmTransaction: () => undefined, }) - const checkPendingTxStub = sinon.stub(pendingTxTracker, '_checkPendingTx').resolves() + const checkPendingTxStub = sinon + .stub(pendingTxTracker, '_checkPendingTx') + .resolves() await pendingTxTracker.updatePendingTxs() assert.ok(checkPendingTxStub.calledThrice) - assert.ok(checkPendingTxStub.firstCall.calledWithExactly(sinon.match.has('id', 1))) - assert.ok(checkPendingTxStub.secondCall.calledWithExactly(sinon.match.has('id', 2))) - assert.ok(checkPendingTxStub.thirdCall.calledWithExactly(sinon.match.has('id', 3))) + assert.ok( + checkPendingTxStub.firstCall.calledWithExactly( + sinon.match.has('id', 1), + ), + ) + assert.ok( + checkPendingTxStub.secondCall.calledWithExactly( + sinon.match.has('id', 2), + ), + ) + assert.ok( + checkPendingTxStub.thirdCall.calledWithExactly( + sinon.match.has('id', 3), + ), + ) }) }) @@ -172,7 +211,8 @@ describe('PendingTransactionTracker', function () { it('should publish a new transaction', async function () { const txMeta = { id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'signed', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', @@ -180,7 +220,8 @@ describe('PendingTransactionTracker', function () { value: '0xfffff', }, history: [{}], - rawTx: '0xf86c808504a817c80086a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + rawTx: + '0xf86c808504a817c80086a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', } const approveTransaction = sinon.spy() const publishTransaction = sinon.spy() @@ -202,14 +243,21 @@ describe('PendingTransactionTracker', function () { await pendingTxTracker._resubmitTx(txMeta) - assert.ok(publishTransaction.calledOnceWithExactly(txMeta.rawTx), 'should call publish transaction with the rawTx') - assert.ok(approveTransaction.notCalled, 'should NOT try to approve transaction') + assert.ok( + publishTransaction.calledOnceWithExactly(txMeta.rawTx), + 'should call publish transaction with the rawTx', + ) + assert.ok( + approveTransaction.notCalled, + 'should NOT try to approve transaction', + ) }) it('should publish the given transaction if more than 2**retryCount blocks have passed', async function () { const txMeta = { id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'signed', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', @@ -217,7 +265,8 @@ describe('PendingTransactionTracker', function () { value: '0xfffff', }, history: [{}], - rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a996e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + rawTx: + '0xf86c808504a817c800827b0d940c62bb85faa3311a996e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', retryCount: 4, firstRetryBlockNumber: '0x1', } @@ -241,14 +290,21 @@ describe('PendingTransactionTracker', function () { await pendingTxTracker._resubmitTx(txMeta, '0x11' /* 16 */) - assert.ok(publishTransaction.calledOnceWithExactly(txMeta.rawTx), 'should try to publish transaction') - assert.ok(approveTransaction.notCalled, 'should NOT try to approve transaction') + assert.ok( + publishTransaction.calledOnceWithExactly(txMeta.rawTx), + 'should try to publish transaction', + ) + assert.ok( + approveTransaction.notCalled, + 'should NOT try to approve transaction', + ) }) it('should NOT publish the given transaction if fewer than 2**retryCount blocks have passed', async function () { const txMeta = { id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'signed', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', @@ -256,7 +312,8 @@ describe('PendingTransactionTracker', function () { value: '0xfffff', }, history: [{}], - rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a996e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + rawTx: + '0xf86c808504a817c800827b0d940c62bb85faa3311a996e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', retryCount: 4, firstRetryBlockNumber: '0x1', } @@ -280,8 +337,14 @@ describe('PendingTransactionTracker', function () { await pendingTxTracker._resubmitTx(txMeta, '0x5') - assert.ok(publishTransaction.notCalled, 'should NOT try to publish transaction') - assert.ok(approveTransaction.notCalled, 'should NOT try to approve transaction') + assert.ok( + publishTransaction.notCalled, + 'should NOT try to publish transaction', + ) + assert.ok( + approveTransaction.notCalled, + 'should NOT try to approve transaction', + ) }) it('should call approveTransaction if the tx is not yet signed', async function () { @@ -305,8 +368,14 @@ describe('PendingTransactionTracker', function () { await pendingTxTracker._resubmitTx({ id: 40 }) - assert.ok(approveTransaction.calledOnceWithExactly(40), 'should call approveTransaction with the tx ID') - assert.ok(publishTransaction.notCalled, 'should NOT try to publish transaction') + assert.ok( + approveTransaction.calledOnceWithExactly(40), + 'should call approveTransaction with the tx ID', + ) + assert.ok( + publishTransaction.notCalled, + 'should NOT try to publish transaction', + ) }) }) @@ -331,17 +400,20 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.DROPPED_BUFFER_COUNT = 0 - assert.ok(await pendingTxTracker._checkIfTxWasDropped({ - id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', - status: 'submitted', - txParams: { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - nonce: '0x1', - value: '0xfffff', - }, - rawTx: '0xf86c808504a817c800827b0d940c62bba0ea0d00cc9789d0d7ff1f471d', - })) + assert.ok( + await pendingTxTracker._checkIfTxWasDropped({ + id: 1, + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'submitted', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x1', + value: '0xfffff', + }, + rawTx: '0xf86c808504a817c800827b0d940c62bba0ea0d00cc9789d0d7ff1f471d', + }), + ) }) it('should return false when the given nonce is the network nonce', async function () { @@ -364,14 +436,16 @@ describe('PendingTransactionTracker', function () { const dropped = await pendingTxTracker._checkIfTxWasDropped({ id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'submitted', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', nonce: '0x1', value: '0xfffff', }, - rawTx: '0xf86c808504a89e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + rawTx: + '0xf86c808504a89e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', }) assert.ok(!dropped, 'should be false') @@ -380,27 +454,34 @@ describe('PendingTransactionTracker', function () { describe('#_checkIfNonceIsTaken', function () { it('should return false if the given nonce is not taken', async function () { - const confirmedTxList = [{ - id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', - status: 'confirmed', - txParams: { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - nonce: '0x1', - value: '0xfffff', + const confirmedTxList = [ + { + id: 1, + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'confirmed', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x1', + value: '0xfffff', + }, + rawTx: + '0xf86c808504a817c800827b0d940c62bb85fa3320e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', }, - rawTx: '0xf86c808504a817c800827b0d940c62bb85fa3320e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', - }, { - id: 2, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', - status: 'confirmed', - txParams: { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - nonce: '0x2', - value: '0xfffff', + { + id: 2, + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'confirmed', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x2', + value: '0xfffff', + }, + rawTx: + '0xf86c808507a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', }, - rawTx: '0xf86c808507a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', - }] + ] const getCompletedTransactions = sinon.stub().returns(confirmedTxList) const pendingTxTracker = new PendingTransactionTracker({ query: sinon.spy(), @@ -423,32 +504,43 @@ describe('PendingTransactionTracker', function () { }, }) - assert.ok(getCompletedTransactions.calledOnceWithExactly('0x1678a085c290ebd122dc42cba69373b5953b831d')) + assert.ok( + getCompletedTransactions.calledOnceWithExactly( + '0x1678a085c290ebd122dc42cba69373b5953b831d', + ), + ) assert.ok(!taken) }) it('should return true if the nonce is taken', async function () { - const confirmedTxList = [{ - id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', - status: 'confirmed', - txParams: { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - nonce: '0x1', - value: '0xfffff', + const confirmedTxList = [ + { + id: 1, + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'confirmed', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x1', + value: '0xfffff', + }, + rawTx: + '0xf86c808504a817c80082ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', }, - rawTx: '0xf86c808504a817c80082ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', - }, { - id: 2, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', - status: 'confirmed', - txParams: { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - nonce: '0x2', - value: '0xfffff', + { + id: 2, + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'confirmed', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x2', + value: '0xfffff', + }, + rawTx: + '0xf86c808504a817c800827b0d940c62bb760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', }, - rawTx: '0xf86c808504a817c800827b0d940c62bb760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', - }] + ] const getCompletedTransactions = sinon.stub().returns(confirmedTxList) const pendingTxTracker = new PendingTransactionTracker({ query: sinon.spy(), @@ -471,7 +563,11 @@ describe('PendingTransactionTracker', function () { }, }) - assert.ok(getCompletedTransactions.calledOnceWithExactly('0x1678a085c290ebd122dc42cba69373b5953b831d')) + assert.ok( + getCompletedTransactions.calledOnceWithExactly( + '0x1678a085c290ebd122dc42cba69373b5953b831d', + ), + ) assert.ok(taken) }) }) @@ -480,7 +576,8 @@ describe('PendingTransactionTracker', function () { it("should emit 'tx:warning' if getTransactionReceipt rejects", async function () { const txMeta = { id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'submitted', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', @@ -550,12 +647,12 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.once('tx:failed', listeners.failed) pendingTxTracker.once('tx:warning', listeners.warning) await pendingTxTracker._checkPendingTx({ - 'status': 'confirmed', - 'history': [{}], - 'txParams': { 'nonce': '0x1' }, - 'id': '456', - 'value': '0x01', - 'hash': '0xbad', + status: 'confirmed', + history: [{}], + txParams: { nonce: '0x1' }, + id: '456', + value: '0x01', + hash: '0xbad', }) assert.ok(listeners.failed.notCalled, "should not emit 'tx:failed'") @@ -595,28 +692,38 @@ describe('PendingTransactionTracker', function () { txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d' }, }) - assert.ok(listeners.failed.calledOnceWithExactly('2', sinon.match.instanceOf(Error)), "should pass txId to 'tx:failed' listener") + assert.ok( + listeners.failed.calledOnceWithExactly( + '2', + sinon.match.instanceOf(Error), + ), + "should pass txId to 'tx:failed' listener", + ) assert.ok(listeners.confirmed.notCalled, "should not emit 'tx:confirmed'") assert.ok(listeners.dropped.notCalled, "should not emit 'tx:dropped'") assert.ok(listeners.warning.notCalled, "should not emit 'tx:warning'") }) it("should emit 'tx:dropped' if another tx with the same nonce succeeds", async function () { - const txs = [{ - 'status': 'confirmed', - 'history': [{}], - 'txParams': { 'nonce': '0x1' }, - 'id': '456', - 'value': '0x01', - 'hash': '0xbad', - }, { - 'status': 'submitted', - 'history': [{}], - 'txParams': { 'nonce': '0x1' }, - 'id': '123', - 'value': '0x02', - 'hash': '0x2a919d2512ec963f524bfd9730fb66b6d5a2e399d1dd957abb5e2b544a12644b', - }] + const txs = [ + { + status: 'confirmed', + history: [{}], + txParams: { nonce: '0x1' }, + id: '456', + value: '0x01', + hash: '0xbad', + }, + { + status: 'submitted', + history: [{}], + txParams: { nonce: '0x1' }, + id: '123', + value: '0x02', + hash: + '0x2a919d2512ec963f524bfd9730fb66b6d5a2e399d1dd957abb5e2b544a12644b', + }, + ] const pendingTxTracker = new PendingTransactionTracker({ query: { getTransactionReceipt: sinon.stub().resolves(null), @@ -654,7 +761,8 @@ describe('PendingTransactionTracker', function () { const nonceBN = new BN(2) const txMeta = { id: 1, - hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + hash: + '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', status: 'submitted', txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index 68c96f108..4effec147 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -15,7 +15,10 @@ import { CONTRACT_INTERACTION_KEY, } from '../../../../../ui/app/helpers/constants/transactions' -import { createTestProviderTools, getTestAccounts } from '../../../../stub/provider' +import { + createTestProviderTools, + getTestAccounts, +} from '../../../../stub/provider' const noop = () => true const currentNetworkId = '42' @@ -31,46 +34,79 @@ describe('Transaction Controller', function () { // by default, all accounts are external accounts (not contracts) eth_getCode: '0x', } - provider = createTestProviderTools({ scaffold: providerResultStub }).provider + provider = createTestProviderTools({ scaffold: providerResultStub }) + .provider fromAccount = getTestAccounts()[0] const blockTrackerStub = new EventEmitter() blockTrackerStub.getCurrentBlock = noop blockTrackerStub.getLatestBlock = noop txController = new TransactionController({ provider, - getGasPrice () { + getGasPrice() { return '0xee6b2800' }, networkStore: new ObservableStore(currentNetworkId), txHistoryLimit: 10, blockTracker: blockTrackerStub, - signTransaction: (ethTx) => new Promise((resolve) => { - ethTx.sign(fromAccount.key) - resolve() - }), + signTransaction: (ethTx) => + new Promise((resolve) => { + ethTx.sign(fromAccount.key) + resolve() + }), getPermittedAccounts: () => undefined, getCurrentChainId: () => currentChainId, getParticipateInMetrics: () => false, }) - txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop }) + txController.nonceTracker.getNonceLock = () => + Promise.resolve({ nextNonce: 0, releaseLock: noop }) }) describe('#getState', function () { it('should return a state object with the right keys and data types', function () { const exposedState = txController.getState() - assert.ok('unapprovedTxs' in exposedState, 'state should have the key unapprovedTxs') - assert.ok('currentNetworkTxList' in exposedState, 'state should have the key currentNetworkTxList') - assert.ok(typeof exposedState?.unapprovedTxs === 'object', 'should be an object') - assert.ok(Array.isArray(exposedState.currentNetworkTxList), 'should be an array') + assert.ok( + 'unapprovedTxs' in exposedState, + 'state should have the key unapprovedTxs', + ) + assert.ok( + 'currentNetworkTxList' in exposedState, + 'state should have the key currentNetworkTxList', + ) + assert.ok( + typeof exposedState?.unapprovedTxs === 'object', + 'should be an object', + ) + assert.ok( + Array.isArray(exposedState.currentNetworkTxList), + 'should be an array', + ) }) }) describe('#getUnapprovedTxCount', function () { it('should return the number of unapproved txs', function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, + { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 2, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 3, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, ]) const unapprovedTxCount = txController.getUnapprovedTxCount() assert.equal(unapprovedTxCount, 3, 'should be 3') @@ -80,9 +116,27 @@ describe('Transaction Controller', function () { describe('#getPendingTxCount', function () { it('should return the number of pending txs', function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, + { + id: 1, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 2, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 3, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, ]) const pendingTxCount = txController.getPendingTxCount() assert.equal(pendingTxCount, 3, 'should be 3') @@ -93,21 +147,78 @@ describe('Transaction Controller', function () { it('should return the number of confirmed txs', function () { const address = '0xc684832530fcbddae4b4230a47e991ddcec2831d' const txParams = { - 'from': address, - 'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d', + from: address, + to: '0xc684832530fcbddae4b4230a47e991ddcec2831d', } txController.txStateManager._saveTxList([ - { id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, - { id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, + { + id: 0, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 1, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 2, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 3, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 4, + status: 'rejected', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 5, + status: 'approved', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 6, + status: 'signed', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 7, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, + { + id: 8, + status: 'failed', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, ]) - assert.equal(txController.nonceTracker.getConfirmedTransactions(address).length, 3) + assert.equal( + txController.nonceTracker.getConfirmedTransactions(address).length, + 3, + ) }) }) @@ -115,8 +226,8 @@ describe('Transaction Controller', function () { let stub, txMeta, txParams beforeEach(function () { txParams = { - 'from': '0xc684832530fcbddae4b4230a47e991ddcec2831d', - 'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d', + from: '0xc684832530fcbddae4b4230a47e991ddcec2831d', + to: '0xc684832530fcbddae4b4230a47e991ddcec2831d', } txMeta = { status: 'unapproved', @@ -126,10 +237,12 @@ describe('Transaction Controller', function () { history: [{}], } txController.txStateManager._saveTxList([txMeta]) - stub = sinon.stub(txController, 'addUnapprovedTransaction').callsFake(() => { - txController.emit('newUnapprovedTx', txMeta) - return Promise.resolve(txController.txStateManager.addTx(txMeta)) - }) + stub = sinon + .stub(txController, 'addUnapprovedTransaction') + .callsFake(() => { + txController.emit('newUnapprovedTx', txMeta) + return Promise.resolve(txController.txStateManager.addTx(txMeta)) + }) }) afterEach(function () { @@ -158,7 +271,9 @@ describe('Transaction Controller', function () { await assert.rejects( () => txController.newUnapprovedTransaction(txParams), - { message: 'MetaMask Tx Signature: User denied transaction signature.' }, + { + message: 'MetaMask Tx Signature: User denied transaction signature.', + }, ) }) }) @@ -168,8 +283,12 @@ describe('Transaction Controller', function () { let getSelectedAddress, getPermittedAccounts beforeEach(function () { - getSelectedAddress = sinon.stub(txController, 'getSelectedAddress').returns(selectedAddress) - getPermittedAccounts = sinon.stub(txController, 'getPermittedAccounts').returns([selectedAddress]) + getSelectedAddress = sinon + .stub(txController, 'getSelectedAddress') + .returns(selectedAddress) + getPermittedAccounts = sinon + .stub(txController, 'getPermittedAccounts') + .returns([selectedAddress]) }) afterEach(function () { @@ -178,13 +297,22 @@ describe('Transaction Controller', function () { }) it('should add an unapproved transaction and return a valid txMeta', async function () { - const txMeta = await txController.addUnapprovedTransaction({ from: selectedAddress }) + const txMeta = await txController.addUnapprovedTransaction({ + from: selectedAddress, + }) assert.ok('id' in txMeta, 'should have a id') assert.ok('time' in txMeta, 'should have a time stamp') - assert.ok('metamaskNetworkId' in txMeta, 'should have a metamaskNetworkId') + assert.ok( + 'metamaskNetworkId' in txMeta, + 'should have a metamaskNetworkId', + ) assert.ok('txParams' in txMeta, 'should have a txParams') assert.ok('history' in txMeta, 'should have a history') - assert.equal(txMeta.txParams.value, '0x0', 'should have added 0x0 as the value') + assert.equal( + txMeta.txParams.value, + '0x0', + 'should have added 0x0 as the value', + ) const memTxMeta = txController.txStateManager.getTx(txMeta.id) assert.deepEqual(txMeta, memTxMeta) @@ -196,18 +324,27 @@ describe('Transaction Controller', function () { assert.ok(txMetaFromEmit, 'txMeta is falsy') done() }) - txController.addUnapprovedTransaction({ from: selectedAddress }) + txController + .addUnapprovedTransaction({ from: selectedAddress }) .catch(done) }) it("should fail if the from address isn't the selected address", async function () { - await assert.rejects(() => txController.addUnapprovedTransaction({ from: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' })) + await assert.rejects(() => + txController.addUnapprovedTransaction({ + from: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2', + }), + ) }) it('should fail if netId is loading', async function () { txController.networkStore = new ObservableStore('loading') await assert.rejects( - () => txController.addUnapprovedTransaction({ from: selectedAddress, to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' }), + () => + txController.addUnapprovedTransaction({ + from: selectedAddress, + to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2', + }), { message: 'MetaMask is having trouble connecting to the network' }, ) }) @@ -216,7 +353,13 @@ describe('Transaction Controller', function () { describe('#addTxGasDefaults', function () { it('should add the tx defaults if their are none', async function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, + { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, ]) const txMeta = { id: 1, @@ -231,8 +374,14 @@ describe('Transaction Controller', function () { providerResultStub.eth_estimateGas = '5209' const txMetaWithDefaults = await txController.addTxGasDefaults(txMeta) - assert.ok(txMetaWithDefaults.txParams.gasPrice, 'should have added the gas price') - assert.ok(txMetaWithDefaults.txParams.gas, 'should have added the gas field') + assert.ok( + txMetaWithDefaults.txParams.gasPrice, + 'should have added the gas price', + ) + assert.ok( + txMetaWithDefaults.txParams.gas, + 'should have added the gas field', + ) }) }) @@ -248,15 +397,21 @@ describe('Transaction Controller', function () { const eventNames = ['update:badge', '1:unapproved'] const listeners = [] eventNames.forEach((eventName) => { - listeners.push(new Promise((resolve) => { - txController.once(eventName, (arg) => { - resolve(arg) - }) - })) + listeners.push( + new Promise((resolve) => { + txController.once(eventName, (arg) => { + resolve(arg) + }) + }), + ) }) Promise.all(listeners) .then((returnValues) => { - assert.deepEqual(returnValues.pop(), txMeta, 'last event 1:unapproved should return txMeta') + assert.deepEqual( + returnValues.pop(), + txMeta, + 'last event 1:unapproved should return txMeta', + ) done() }) .catch(done) @@ -284,12 +439,16 @@ describe('Transaction Controller', function () { providerResultStub.eth_gasPrice = wrongValue providerResultStub.eth_estimateGas = '0x5209' - const signStub = sinon.stub(txController, 'signTransaction').callsFake(() => Promise.resolve()) + const signStub = sinon + .stub(txController, 'signTransaction') + .callsFake(() => Promise.resolve()) - const pubStub = sinon.stub(txController, 'publishTransaction').callsFake(() => { - txController.setTxHash('1', originalValue) - txController.txStateManager.setTxStatusSubmitted('1') - }) + const pubStub = sinon + .stub(txController, 'publishTransaction') + .callsFake(() => { + txController.setTxHash('1', originalValue) + txController.txStateManager.setTxStatusSubmitted('1') + }) await txController.approveTransaction(txMeta.id) const result = txController.txStateManager.getTx(txMeta.id) @@ -298,7 +457,11 @@ describe('Transaction Controller', function () { assert.equal(params.gas, originalValue, 'gas unmodified') assert.equal(params.gasPrice, originalValue, 'gas price unmodified') assert.equal(result.hash, originalValue) - assert.equal(result.status, 'submitted', 'should have reached the submitted status.') + assert.equal( + result.status, + 'submitted', + 'should have reached the submitted status.', + ) signStub.restore() pubStub.restore() }) @@ -306,7 +469,15 @@ describe('Transaction Controller', function () { describe('#sign replay-protected tx', function () { it('prepares a tx with the chainId set', async function () { - txController.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txController.addTx( + { + id: '1', + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) const rawTx = await txController.signTransaction('1') const ethTx = new EthTx(ethUtil.toBuffer(rawTx)) assert.equal(ethTx.getChainId(), 42) @@ -345,13 +516,55 @@ describe('Transaction Controller', function () { describe('#cancelTransaction', function () { it('should emit a status change to rejected', function (done) { txController.txStateManager._saveTxList([ - { id: 0, status: 'unapproved', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, - { id: 1, status: 'rejected', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, - { id: 2, status: 'approved', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, - { id: 3, status: 'signed', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, - { id: 4, status: 'submitted', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, - { id: 5, status: 'confirmed', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, - { id: 6, status: 'failed', txParams: {}, metamaskNetworkId: currentNetworkId, history: [{}] }, + { + id: 0, + status: 'unapproved', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, + { + id: 1, + status: 'rejected', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, + { + id: 2, + status: 'approved', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, + { + id: 3, + status: 'signed', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, + { + id: 4, + status: 'submitted', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, + { + id: 5, + status: 'confirmed', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, + { + id: 6, + status: 'failed', + txParams: {}, + metamaskNetworkId: currentNetworkId, + history: [{}], + }, ]) txController.once('tx:status-update', (txId, status) => { @@ -386,7 +599,13 @@ describe('Transaction Controller', function () { gasPrice: '0xa', } txController.txStateManager._saveTxList([ - { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [{}] }, + { + id: 1, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams, + history: [{}], + }, ]) expectedTxParams = { ...txParams, gasPrice: '0xb' } @@ -405,10 +624,13 @@ describe('Transaction Controller', function () { assert.deepEqual(addTxArgs.txParams, expectedTxParams) const { lastGasPrice, type } = addTxArgs - assert.deepEqual({ lastGasPrice, type }, { - lastGasPrice: '0xa', - type: TRANSACTION_TYPE_RETRY, - }) + assert.deepEqual( + { lastGasPrice, type }, + { + lastGasPrice: '0xa', + type: TRANSACTION_TYPE_RETRY, + }, + ) }) it('should call this.approveTransaction with the id of the returned tx', async function () { @@ -425,17 +647,21 @@ describe('Transaction Controller', function () { assert.deepEqual(result.txParams, expectedTxParams) const { lastGasPrice, type } = result - assert.deepEqual({ lastGasPrice, type }, { - lastGasPrice: '0xa', - type: TRANSACTION_TYPE_RETRY, - }) + assert.deepEqual( + { lastGasPrice, type }, + { + lastGasPrice: '0xa', + type: TRANSACTION_TYPE_RETRY, + }, + ) }) }) describe('#publishTransaction', function () { let hash, txMeta beforeEach(function () { - hash = '0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8' + hash = + '0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8' txMeta = { id: 1, status: 'unapproved', @@ -446,7 +672,8 @@ describe('Transaction Controller', function () { }) it('should publish a tx, updates the rawTx when provided a one', async function () { - const rawTx = '0x477b2e6553c917af0db0388ae3da62965ff1a184558f61b749d1266b2e6d024c' + const rawTx = + '0x477b2e6553c917af0db0388ae3da62965ff1a184558f61b749d1266b2e6d024c' txController.txStateManager.addTx(txMeta) await txController.publishTransaction(txMeta.id, rawTx) const publishedTx = txController.txStateManager.getTx(1) @@ -458,11 +685,15 @@ describe('Transaction Controller', function () { providerResultStub.eth_sendRawTransaction = async (_, __, ___, end) => { end('Transaction Failed: known transaction') } - const rawTx = '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a' + const rawTx = + '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a' txController.txStateManager.addTx(txMeta) await txController.publishTransaction(txMeta.id, rawTx) const publishedTx = txController.txStateManager.getTx(1) - assert.equal(publishedTx.hash, '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09') + assert.equal( + publishedTx.hash, + '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09', + ) assert.equal(publishedTx.status, 'submitted') }) }) @@ -470,18 +701,67 @@ describe('Transaction Controller', function () { describe('#_markNonceDuplicatesDropped', function () { it('should mark all nonce duplicates as dropped without marking the confirmed transaction as dropped', function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, - { id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, - { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, - { id: 4, status: 'submitted', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, - { id: 5, status: 'submitted', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, - { id: 6, status: 'submitted', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, - { id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, history: [{}], txParams: { nonce: '0x01' } }, + { + id: 1, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, + { + id: 2, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, + { + id: 3, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, + { + id: 4, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, + { + id: 5, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, + { + id: 6, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, + { + id: 7, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + history: [{}], + txParams: { nonce: '0x01' }, + }, ]) txController._markNonceDuplicatesDropped(1) const confirmedTx = txController.txStateManager.getTx(1) - const droppedTxs = txController.txStateManager.getFilteredTxList({ nonce: '0x01', status: 'dropped' }) - assert.equal(confirmedTx.status, 'confirmed', 'the confirmedTx should remain confirmed') + const droppedTxs = txController.txStateManager.getFilteredTxList({ + nonce: '0x01', + status: 'dropped', + }) + assert.equal( + confirmedTx.status, + 'confirmed', + 'the confirmedTx should remain confirmed', + ) assert.equal(droppedTxs.length, 6, 'their should be 6 dropped txs') }) }) @@ -492,23 +772,34 @@ describe('Transaction Controller', function () { to: '0xabc', data: '', }) - assert.deepEqual(result, { transactionCategory: SEND_ETHER_ACTION_KEY, getCodeResponse: null }) + assert.deepEqual(result, { + transactionCategory: SEND_ETHER_ACTION_KEY, + getCodeResponse: null, + }) }) it('should return a token transfer transactionCategory when data is for the respective method call', async function () { const result = await txController._determineTransactionCategory({ to: '0xabc', - data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', + data: + '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', + }) + assert.deepEqual(result, { + transactionCategory: TOKEN_METHOD_TRANSFER, + getCodeResponse: undefined, }) - assert.deepEqual(result, { transactionCategory: TOKEN_METHOD_TRANSFER, getCodeResponse: undefined }) }) it('should return a token approve transactionCategory when data is for the respective method call', async function () { const result = await txController._determineTransactionCategory({ to: '0xabc', - data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', + data: + '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', + }) + assert.deepEqual(result, { + transactionCategory: TOKEN_METHOD_APPROVE, + getCodeResponse: undefined, }) - assert.deepEqual(result, { transactionCategory: TOKEN_METHOD_APPROVE, getCodeResponse: undefined }) }) it('should return a contract deployment transactionCategory when to is falsy and there is data', async function () { @@ -516,7 +807,10 @@ describe('Transaction Controller', function () { to: '', data: '0xabd', }) - assert.deepEqual(result, { transactionCategory: DEPLOY_CONTRACT_ACTION_KEY, getCodeResponse: undefined }) + assert.deepEqual(result, { + transactionCategory: DEPLOY_CONTRACT_ACTION_KEY, + getCodeResponse: undefined, + }) }) it('should return a simple send transactionCategory with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () { @@ -524,7 +818,10 @@ describe('Transaction Controller', function () { to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', data: '0xabd', }) - assert.deepEqual(result, { transactionCategory: SEND_ETHER_ACTION_KEY, getCodeResponse: '0x' }) + assert.deepEqual(result, { + transactionCategory: SEND_ETHER_ACTION_KEY, + getCodeResponse: '0x', + }) }) it('should return a simple send transactionCategory with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () { @@ -532,7 +829,10 @@ describe('Transaction Controller', function () { to: '0xabc', data: '0xabd', }) - assert.deepEqual(result, { transactionCategory: SEND_ETHER_ACTION_KEY, getCodeResponse: null }) + assert.deepEqual(result, { + transactionCategory: SEND_ETHER_ACTION_KEY, + getCodeResponse: null, + }) }) it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () { @@ -542,30 +842,36 @@ describe('Transaction Controller', function () { // by default, all accounts are external accounts (not contracts) eth_getCode: '0xa', } - const _provider = createTestProviderTools({ scaffold: _providerResultStub }).provider + const _provider = createTestProviderTools({ + scaffold: _providerResultStub, + }).provider const _fromAccount = getTestAccounts()[0] const _blockTrackerStub = new EventEmitter() _blockTrackerStub.getCurrentBlock = noop _blockTrackerStub.getLatestBlock = noop const _txController = new TransactionController({ provider: _provider, - getGasPrice () { + getGasPrice() { return '0xee6b2800' }, networkStore: new ObservableStore(currentNetworkId), txHistoryLimit: 10, blockTracker: _blockTrackerStub, - signTransaction: (ethTx) => new Promise((resolve) => { - ethTx.sign(_fromAccount.key) - resolve() - }), + signTransaction: (ethTx) => + new Promise((resolve) => { + ethTx.sign(_fromAccount.key) + resolve() + }), getParticipateInMetrics: () => false, }) const result = await _txController._determineTransactionCategory({ to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', data: 'abd', }) - assert.deepEqual(result, { transactionCategory: CONTRACT_INTERACTION_KEY, getCodeResponse: '0x0a' }) + assert.deepEqual(result, { + transactionCategory: CONTRACT_INTERACTION_KEY, + getCodeResponse: '0x0a', + }) }) it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is a contract address and data is falsy', async function () { @@ -575,47 +881,99 @@ describe('Transaction Controller', function () { // by default, all accounts are external accounts (not contracts) eth_getCode: '0xa', } - const _provider = createTestProviderTools({ scaffold: _providerResultStub }).provider + const _provider = createTestProviderTools({ + scaffold: _providerResultStub, + }).provider const _fromAccount = getTestAccounts()[0] const _blockTrackerStub = new EventEmitter() _blockTrackerStub.getCurrentBlock = noop _blockTrackerStub.getLatestBlock = noop const _txController = new TransactionController({ provider: _provider, - getGasPrice () { + getGasPrice() { return '0xee6b2800' }, networkStore: new ObservableStore(currentNetworkId), txHistoryLimit: 10, blockTracker: _blockTrackerStub, - signTransaction: (ethTx) => new Promise((resolve) => { - ethTx.sign(_fromAccount.key) - resolve() - }), + signTransaction: (ethTx) => + new Promise((resolve) => { + ethTx.sign(_fromAccount.key) + resolve() + }), getParticipateInMetrics: () => false, }) const result = await _txController._determineTransactionCategory({ to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', data: '', }) - assert.deepEqual(result, { transactionCategory: CONTRACT_INTERACTION_KEY, getCodeResponse: '0x0a' }) + assert.deepEqual(result, { + transactionCategory: CONTRACT_INTERACTION_KEY, + getCodeResponse: '0x0a', + }) }) }) describe('#getPendingTransactions', function () { it('should show only submitted and approved transactions as pending transaction', function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, - { id: 2, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 3, status: 'approved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 4, status: 'signed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 5, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 6, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, - { id: 7, status: 'failed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] }, + { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + { + id: 2, + status: 'rejected', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 3, + status: 'approved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 4, + status: 'signed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 5, + status: 'submitted', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 6, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, + { + id: 7, + status: 'failed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + history: [{}], + }, ]) - assert.equal(txController.pendingTxTracker.getPendingTransactions().length, 2) - const states = txController.pendingTxTracker.getPendingTransactions().map((tx) => tx.status) + assert.equal( + txController.pendingTxTracker.getPendingTransactions().length, + 2, + ) + const states = txController.pendingTxTracker + .getPendingTransactions() + .map((tx) => tx.status) assert.ok(states.includes('approved'), 'includes approved') assert.ok(states.includes('submitted'), 'includes submitted') }) diff --git a/test/unit/app/controllers/transactions/tx-gas-util-test.js b/test/unit/app/controllers/transactions/tx-gas-util-test.js index 21ba62746..c08b70520 100644 --- a/test/unit/app/controllers/transactions/tx-gas-util-test.js +++ b/test/unit/app/controllers/transactions/tx-gas-util-test.js @@ -7,11 +7,16 @@ describe('txUtils', function () { let txUtils before(function () { - txUtils = new TxUtils(new Proxy({}, { - get: () => { - return () => undefined - }, - })) + txUtils = new TxUtils( + new Proxy( + {}, + { + get: () => { + return () => undefined + }, + }, + ), + ) }) describe('chain Id', function () { @@ -53,7 +58,10 @@ describe('txUtils', function () { // const inputBn = hexToBn(inputHex) const outputBn = hexToBn(output) const expectedBn = hexToBn(inputHex) - assert.ok(outputBn.eq(expectedBn), 'returns the original estimatedGas value') + assert.ok( + outputBn.eq(expectedBn), + 'returns the original estimatedGas value', + ) }) it('buffers up to recommend gas limit recommended ceiling', function () { @@ -67,7 +75,11 @@ describe('txUtils', function () { // const inputBn = hexToBn(inputHex) // const outputBn = hexToBn(output) const expectedHex = bnToHex(ceilGasLimitBn) - assert.equal(output, expectedHex, 'returns the gas limit recommended ceiling value') + assert.equal( + output, + expectedHex, + 'returns the gas limit recommended ceiling value', + ) }) }) }) diff --git a/test/unit/app/controllers/transactions/tx-state-history-helpers-test.js b/test/unit/app/controllers/transactions/tx-state-history-helpers-test.js index 66833a4cd..c11cb17e0 100644 --- a/test/unit/app/controllers/transactions/tx-state-history-helpers-test.js +++ b/test/unit/app/controllers/transactions/tx-state-history-helpers-test.js @@ -37,14 +37,26 @@ describe('Transaction state history helper', function () { const newHistory = migrateFromSnapshotsToDiffs(tx.history) newHistory.forEach((newEntry, index) => { if (index === 0) { - assert.equal(Array.isArray(newEntry), false, 'initial history item IS NOT a json patch obj') + assert.equal( + Array.isArray(newEntry), + false, + 'initial history item IS NOT a json patch obj', + ) } else { - assert.equal(Array.isArray(newEntry), true, 'non-initial history entry IS a json patch obj') + assert.equal( + Array.isArray(newEntry), + true, + 'non-initial history entry IS a json patch obj', + ) } const oldEntry = tx.history[index] const historySubset = newHistory.slice(0, index + 1) const reconstructedValue = replayHistory(historySubset) - assert.deepEqual(oldEntry, reconstructedValue, 'was able to reconstruct old entry from diffs') + assert.deepEqual( + oldEntry, + reconstructedValue, + 'was able to reconstruct old entry from diffs', + ) }) }) }) @@ -53,29 +65,40 @@ describe('Transaction state history helper', function () { describe('#replayHistory', function () { it('replaying history does not mutate the original object', function () { const initialState = { test: true, message: 'hello', value: 1 } - const diff1 = [{ - 'op': 'replace', - 'path': '/message', - 'value': 'haay', - }] - const diff2 = [{ - 'op': 'replace', - 'path': '/value', - 'value': 2, - }] + const diff1 = [ + { + op: 'replace', + path: '/message', + value: 'haay', + }, + ] + const diff2 = [ + { + op: 'replace', + path: '/value', + value: 2, + }, + ] const history = [initialState, diff1, diff2] const beforeStateSnapshot = JSON.stringify(initialState) const latestState = replayHistory(history) const afterStateSnapshot = JSON.stringify(initialState) - assert.notEqual(initialState, latestState, 'initial state is not the same obj as the latest state') - assert.equal(beforeStateSnapshot, afterStateSnapshot, 'initial state is not modified during run') + assert.notEqual( + initialState, + latestState, + 'initial state is not the same obj as the latest state', + ) + assert.equal( + beforeStateSnapshot, + afterStateSnapshot, + 'initial state is not modified during run', + ) }) }) describe('#generateHistoryEntry', function () { - - function generateHistoryEntryTest (note) { + function generateHistoryEntryTest(note) { const prevState = { someValue: 'value 1', foo: { @@ -102,17 +125,29 @@ describe('Transaction state history helper', function () { assert.ok(Array.isArray(result)) assert.equal(result.length, 3) - const expectedEntry1 = { op: 'add', path: '/foo/newPropFirstLevel', value: 'new property - first level' } + const expectedEntry1 = { + op: 'add', + path: '/foo/newPropFirstLevel', + value: 'new property - first level', + } assert.equal(result[0].op, expectedEntry1.op) assert.equal(result[0].path, expectedEntry1.path) assert.equal(result[0].value, expectedEntry1.value) assert.equal(result[0].note, note) assert.ok(result[0].timestamp >= before && result[0].timestamp <= after) - const expectedEntry2 = { op: 'replace', path: '/someValue', value: 'value 2' } + const expectedEntry2 = { + op: 'replace', + path: '/someValue', + value: 'value 2', + } assert.deepEqual(result[1], expectedEntry2) - const expectedEntry3 = { op: 'add', path: '/newPropRoot', value: 'new property - root' } + const expectedEntry3 = { + op: 'add', + path: '/newPropRoot', + value: 'new property - root', + } assert.deepEqual(result[2], expectedEntry3) } diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js index 915e36362..663522b74 100644 --- a/test/unit/app/controllers/transactions/tx-state-manager-test.js +++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js @@ -22,7 +22,12 @@ describe('TransactionStateManager', function () { describe('#setTxStatusSigned', function () { it('sets the tx status to signed', function () { - const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(tx, noop) txStateManager.setTxStatusSigned(1) const result = txStateManager.getTxList() @@ -32,7 +37,12 @@ describe('TransactionStateManager', function () { }) it('should emit a signed event to signal the execution of callback', function () { - const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } const clock = sinon.useFakeTimers() const onSigned = sinon.spy() @@ -48,7 +58,12 @@ describe('TransactionStateManager', function () { describe('#setTxStatusRejected', function () { it('sets the tx status to rejected and removes it from history', function () { - const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(tx) txStateManager.setTxStatusRejected(1) const result = txStateManager.getTxList() @@ -57,7 +72,12 @@ describe('TransactionStateManager', function () { }) it('should emit a rejected event to signal the execution of callback', function () { - const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } const clock = sinon.useFakeTimers() const onSigned = sinon.spy() @@ -113,18 +133,12 @@ describe('TransactionStateManager', function () { const txm = new TxStateManager({ initState: { - transactions: [ - submittedTx, - confirmedTx, - ], + transactions: [submittedTx, confirmedTx], }, getNetwork: () => currentNetworkId, }) - assert.deepEqual(txm.getTxList(), [ - submittedTx, - confirmedTx, - ]) + assert.deepEqual(txm.getTxList(), [submittedTx, confirmedTx]) }) it('should return a list of transactions, limited by N unique nonces when there are NO duplicates', function () { @@ -188,10 +202,7 @@ describe('TransactionStateManager', function () { getNetwork: () => currentNetworkId, }) - assert.deepEqual(txm.getTxList(2), [ - approvedTx2, - confirmedTx3, - ]) + assert.deepEqual(txm.getTxList(2), [approvedTx2, confirmedTx3]) }) it('should return a list of transactions, limited by N unique nonces when there ARE duplicates', function () { @@ -294,16 +305,18 @@ describe('TransactionStateManager', function () { getNetwork: () => currentNetworkId, }) - assert.deepEqual(txm.getTxList(2), [ - ...approvedTx2s, - ...failedTx3s, - ]) + assert.deepEqual(txm.getTxList(2), [...approvedTx2s, ...failedTx3s]) }) }) describe('#addTx', function () { it('adds a tx returned in getTxList', function () { - const tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: 1, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(tx, noop) const result = txStateManager.getTxList() assert.ok(Array.isArray(result)) @@ -334,7 +347,10 @@ describe('TransactionStateManager', function () { [key]: value, }, } - assert.throws(txStateManager.addTx.bind(txStateManager, tx), 'addTx should throw error') + assert.throws( + txStateManager.addTx.bind(txStateManager, tx), + 'addTx should throw error', + ) const result = txStateManager.getTxList() assert.ok(Array.isArray(result), 'txList should be an array') assert.equal(result.length, 0, 'txList should be empty') @@ -343,8 +359,18 @@ describe('TransactionStateManager', function () { }) it('does not override txs from other networks', function () { - const tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } - const tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} } + const tx = { + id: 1, + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } + const tx2 = { + id: 2, + status: 'confirmed', + metamaskNetworkId: otherNetworkId, + txParams: {}, + } txStateManager.addTx(tx, noop) txStateManager.addTx(tx2, noop) const result = txStateManager.getFullTxList() @@ -356,7 +382,13 @@ describe('TransactionStateManager', function () { it('cuts off early txs beyond a limit', function () { const limit = txStateManager.txHistoryLimit for (let i = 0; i < limit + 1; i++) { - const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: i, + time: new Date(), + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(tx, noop) } const result = txStateManager.getTxList() @@ -367,7 +399,13 @@ describe('TransactionStateManager', function () { it('cuts off early txs beyond a limit whether or not it is confirmed or rejected', function () { const limit = txStateManager.txHistoryLimit for (let i = 0; i < limit + 1; i++) { - const tx = { id: i, time: new Date(), status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: i, + time: new Date(), + status: 'rejected', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(tx, noop) } const result = txStateManager.getTxList() @@ -376,25 +414,57 @@ describe('TransactionStateManager', function () { }) it('cuts off early txs beyond a limit but does not cut unapproved txs', function () { - const unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + const unconfirmedTx = { + id: 0, + time: new Date(), + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(unconfirmedTx, noop) const limit = txStateManager.txHistoryLimit for (let i = 1; i < limit + 1; i++) { - const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + const tx = { + id: i, + time: new Date(), + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + } txStateManager.addTx(tx, noop) } const result = txStateManager.getTxList() assert.equal(result.length, limit, `limit of ${limit} txs enforced`) assert.equal(result[0].id, 0, 'first tx should still be there') - assert.equal(result[0].status, 'unapproved', 'first tx should be unapproved') + assert.equal( + result[0].status, + 'unapproved', + 'first tx should be unapproved', + ) assert.equal(result[1].id, 2, 'early txs truncated') }) }) describe('#updateTx', function () { it('replaces the tx with the same id', function () { - txStateManager.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - txStateManager.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txStateManager.addTx( + { + id: '1', + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) + txStateManager.addTx( + { + id: '2', + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) const txMeta = txStateManager.getTx('1') txMeta.hash = 'foo' txStateManager.updateTx(txMeta) @@ -414,7 +484,12 @@ describe('TransactionStateManager', function () { } const invalidValues = [1, true, {}, Symbol('1')] - txStateManager.addTx({ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: validTxParams }) + txStateManager.addTx({ + id: 1, + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: validTxParams, + }) Object.keys(validTxParams).forEach((key) => { for (const value of invalidValues) { @@ -426,7 +501,10 @@ describe('TransactionStateManager', function () { [key]: value, }, } - assert.throws(txStateManager.updateTx.bind(txStateManager, newTx), 'updateTx should throw an error') + assert.throws( + txStateManager.updateTx.bind(txStateManager, newTx), + 'updateTx should throw an error', + ) const result = txStateManager.getTx(1) assert.deepEqual(result, originalTx, 'tx should not be updated') } @@ -450,8 +528,16 @@ describe('TransactionStateManager', function () { const updatedTx = txStateManager.getTx('1') // verify tx was initialized correctly assert.equal(updatedTx.history.length, 1, 'one history item (initial)') - assert.equal(Array.isArray(updatedTx.history[0]), false, 'first history item is initial state') - assert.deepEqual(updatedTx.history[0], snapshotFromTxMeta(updatedTx), 'first history item is initial state') + assert.equal( + Array.isArray(updatedTx.history[0]), + false, + 'first history item is initial state', + ) + assert.deepEqual( + updatedTx.history[0], + snapshotFromTxMeta(updatedTx), + 'first history item is initial state', + ) // modify value and updateTx updatedTx.txParams.gasPrice = desiredGasPrice const before = new Date().getTime() @@ -459,16 +545,47 @@ describe('TransactionStateManager', function () { const after = new Date().getTime() // check updated value const result = txStateManager.getTx('1') - assert.equal(result.txParams.gasPrice, desiredGasPrice, 'gas price updated') + assert.equal( + result.txParams.gasPrice, + desiredGasPrice, + 'gas price updated', + ) // validate history was updated - assert.equal(result.history.length, 2, 'two history items (initial + diff)') - assert.equal(result.history[1].length, 1, 'two history state items (initial + diff)') + assert.equal( + result.history.length, + 2, + 'two history items (initial + diff)', + ) + assert.equal( + result.history[1].length, + 1, + 'two history state items (initial + diff)', + ) - const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice } - assert.deepEqual(result.history[1][0].op, expectedEntry.op, 'two history items (initial + diff) operation') - assert.deepEqual(result.history[1][0].path, expectedEntry.path, 'two history items (initial + diff) path') - assert.deepEqual(result.history[1][0].value, expectedEntry.value, 'two history items (initial + diff) value') - assert.ok(result.history[1][0].timestamp >= before && result.history[1][0].timestamp <= after) + const expectedEntry = { + op: 'replace', + path: '/txParams/gasPrice', + value: desiredGasPrice, + } + assert.deepEqual( + result.history[1][0].op, + expectedEntry.op, + 'two history items (initial + diff) operation', + ) + assert.deepEqual( + result.history[1][0].path, + expectedEntry.path, + 'two history items (initial + diff) path', + ) + assert.deepEqual( + result.history[1][0].value, + expectedEntry.value, + 'two history items (initial + diff) value', + ) + assert.ok( + result.history[1][0].timestamp >= before && + result.history[1][0].timestamp <= after, + ) }) it('does NOT add empty history items', function () { @@ -491,8 +608,24 @@ describe('TransactionStateManager', function () { describe('#getUnapprovedTxList', function () { it('returns unapproved txs in a hash', function () { - txStateManager.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - txStateManager.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txStateManager.addTx( + { + id: '1', + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) + txStateManager.addTx( + { + id: '2', + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) const result = txStateManager.getUnapprovedTxList() assert.equal(typeof result, 'object') assert.equal(result['1'].status, 'unapproved') @@ -502,8 +635,24 @@ describe('TransactionStateManager', function () { describe('#getTx', function () { it('returns a tx with the requested id', function () { - txStateManager.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - txStateManager.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txStateManager.addTx( + { + id: '1', + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) + txStateManager.addTx( + { + id: '2', + status: 'confirmed', + metamaskNetworkId: currentNetworkId, + txParams: {}, + }, + noop, + ) assert.equal(txStateManager.getTx('1').status, 'unapproved') assert.equal(txStateManager.getTx('2').status, 'confirmed') }) @@ -512,55 +661,150 @@ describe('TransactionStateManager', function () { describe('#getFilteredTxList', function () { it('returns a tx with the requested data', function () { const txMetas = [ - { id: 0, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 1, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 2, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 3, status: 'unapproved', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 4, status: 'unapproved', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 5, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 6, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 7, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 8, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 9, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, + { + id: 0, + status: 'unapproved', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 1, + status: 'unapproved', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 2, + status: 'unapproved', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 3, + status: 'unapproved', + txParams: { from: '0xbb', to: '0xaa' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 4, + status: 'unapproved', + txParams: { from: '0xbb', to: '0xaa' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 5, + status: 'confirmed', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 6, + status: 'confirmed', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 7, + status: 'confirmed', + txParams: { from: '0xbb', to: '0xaa' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 8, + status: 'confirmed', + txParams: { from: '0xbb', to: '0xaa' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 9, + status: 'confirmed', + txParams: { from: '0xbb', to: '0xaa' }, + metamaskNetworkId: currentNetworkId, + }, ] txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) let filterParams filterParams = { status: 'unapproved', from: '0xaa' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 3, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 3, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) filterParams = { status: 'unapproved', to: '0xaa' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 2, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 2, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) filterParams = { status: 'confirmed', from: '0xbb' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 3, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 3, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) filterParams = { status: 'confirmed' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 5, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) filterParams = { from: '0xaa' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 5, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) filterParams = { to: '0xaa' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 5, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) filterParams = { status: (status) => status !== 'confirmed' } - assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + assert.equal( + txStateManager.getFilteredTxList(filterParams).length, + 5, + `getFilteredTxList - ${JSON.stringify(filterParams)}`, + ) }) }) describe('#wipeTransactions', function () { - const specificAddress = '0xaa' const otherAddress = '0xbb' it('should remove only the transactions from a specific address', function () { - const txMetas = [ - { id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId }, - { id: 1, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId }, - { id: 2, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId }, + { + id: 0, + status: 'unapproved', + txParams: { from: specificAddress, to: otherAddress }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 1, + status: 'confirmed', + txParams: { from: otherAddress, to: specificAddress }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 2, + status: 'confirmed', + txParams: { from: otherAddress, to: specificAddress }, + metamaskNetworkId: currentNetworkId, + }, ] txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) txStateManager.wipeTransactions(specificAddress) - const transactionsFromCurrentAddress = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from === specificAddress) - const transactionsFromOtherAddresses = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from !== specificAddress) + const transactionsFromCurrentAddress = txStateManager + .getTxList() + .filter((txMeta) => txMeta.txParams.from === specificAddress) + const transactionsFromOtherAddresses = txStateManager + .getTxList() + .filter((txMeta) => txMeta.txParams.from !== specificAddress) assert.equal(transactionsFromCurrentAddress.length, 0) assert.equal(transactionsFromOtherAddresses.length, 2) @@ -568,17 +812,36 @@ describe('TransactionStateManager', function () { it('should not remove the transactions from other networks', function () { const txMetas = [ - { id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId }, - { id: 1, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId }, - { id: 2, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId }, + { + id: 0, + status: 'unapproved', + txParams: { from: specificAddress, to: otherAddress }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 1, + status: 'confirmed', + txParams: { from: specificAddress, to: otherAddress }, + metamaskNetworkId: otherNetworkId, + }, + { + id: 2, + status: 'confirmed', + txParams: { from: specificAddress, to: otherAddress }, + metamaskNetworkId: otherNetworkId, + }, ] txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) txStateManager.wipeTransactions(specificAddress) - const txsFromCurrentNetworkAndAddress = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from === specificAddress) - const txFromOtherNetworks = txStateManager.getFullTxList().filter((txMeta) => txMeta.metamaskNetworkId === otherNetworkId) + const txsFromCurrentNetworkAndAddress = txStateManager + .getTxList() + .filter((txMeta) => txMeta.txParams.from === specificAddress) + const txFromOtherNetworks = txStateManager + .getFullTxList() + .filter((txMeta) => txMeta.metamaskNetworkId === otherNetworkId) assert.equal(txsFromCurrentNetworkAndAddress.length, 0) assert.equal(txFromOtherNetworks.length, 2) @@ -589,30 +852,59 @@ describe('TransactionStateManager', function () { it('should remove the transaction from the storage', function () { txStateManager._saveTxList([{ id: 1 }]) txStateManager._removeTx(1) - assert.ok(!txStateManager.getFullTxList().length, 'txList should be empty') + assert.ok( + !txStateManager.getFullTxList().length, + 'txList should be empty', + ) }) it('should only remove the transaction with ID 1 from the storage', function () { txStateManager._saveTxList([{ id: 1 }, { id: 2 }]) txStateManager._removeTx(1) - assert.equal(txStateManager.getFullTxList()[0].id, 2, 'txList should have a id of 2') + assert.equal( + txStateManager.getFullTxList()[0].id, + 2, + 'txList should have a id of 2', + ) }) }) describe('#clearUnapprovedTxs', function () { it('removes unapproved transactions', function () { const txMetas = [ - { id: 0, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 1, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 2, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: otherNetworkId }, - { id: 3, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: otherNetworkId }, + { + id: 0, + status: 'unapproved', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 1, + status: 'unapproved', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: currentNetworkId, + }, + { + id: 2, + status: 'confirmed', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: otherNetworkId, + }, + { + id: 3, + status: 'confirmed', + txParams: { from: '0xaa', to: '0xbb' }, + metamaskNetworkId: otherNetworkId, + }, ] txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) txStateManager.clearUnapprovedTxs() - const unapprovedTxList = txStateManager.getFullTxList().filter((tx) => tx.status === 'unapproved') + const unapprovedTxList = txStateManager + .getFullTxList() + .filter((tx) => tx.status === 'unapproved') assert.equal(unapprovedTxList.length, 0) }) diff --git a/test/unit/app/controllers/transactions/tx-utils-test.js b/test/unit/app/controllers/transactions/tx-utils-test.js index 6923d53d5..02c5171c7 100644 --- a/test/unit/app/controllers/transactions/tx-utils-test.js +++ b/test/unit/app/controllers/transactions/tx-utils-test.js @@ -38,13 +38,28 @@ describe('txUtils', function () { assert.ok(!normalizedTxParams.chainId, 'there should be no chainId') assert.ok(!normalizedTxParams.to, 'there should be no to address if null') - assert.equal(normalizedTxParams.from.slice(0, 2), '0x', 'from should be hex-prefixed') - assert.equal(normalizedTxParams.data.slice(0, 2), '0x', 'data should be hex-prefixed') - assert.ok(!('random' in normalizedTxParams), 'there should be no random key in normalizedTxParams') + assert.equal( + normalizedTxParams.from.slice(0, 2), + '0x', + 'from should be hex-prefixed', + ) + assert.equal( + normalizedTxParams.data.slice(0, 2), + '0x', + 'data should be hex-prefixed', + ) + assert.ok( + !('random' in normalizedTxParams), + 'there should be no random key in normalizedTxParams', + ) txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402' normalizedTxParams = txUtils.normalizeTxParams(txParams) - assert.equal(normalizedTxParams.to.slice(0, 2), '0x', 'to should be hex-prefixed') + assert.equal( + normalizedTxParams.to.slice(0, 2), + '0x', + 'to should be hex-prefixed', + ) }) }) @@ -55,8 +70,17 @@ describe('txUtils', function () { to: '0x', data: 'bytecode', } - const sanitizedTxParams = txUtils.validateRecipient(zeroRecipientDataTxParams) - assert.deepEqual(sanitizedTxParams, { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', data: 'bytecode' }, 'no recipient with 0x') + const sanitizedTxParams = txUtils.validateRecipient( + zeroRecipientDataTxParams, + ) + assert.deepEqual( + sanitizedTxParams, + { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + data: 'bytecode', + }, + 'no recipient with 0x', + ) }) it('should error when recipient is 0x', function () { @@ -64,38 +88,57 @@ describe('txUtils', function () { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', to: '0x', } - assert.throws(() => { - txUtils.validateRecipient(zeroRecipientTxParams) - }, Error, 'Invalid recipient address') + assert.throws( + () => { + txUtils.validateRecipient(zeroRecipientTxParams) + }, + Error, + 'Invalid recipient address', + ) }) }) describe('#validateFrom', function () { it('should error when from is not a hex string', function () { - // where from is undefined const txParams = {} - assert.throws(() => { - txUtils.validateFrom(txParams) - }, Error, `Invalid from address ${txParams.from} not a string`) + assert.throws( + () => { + txUtils.validateFrom(txParams) + }, + Error, + `Invalid from address ${txParams.from} not a string`, + ) // where from is array txParams.from = [] - assert.throws(() => { - txUtils.validateFrom(txParams) - }, Error, `Invalid from address ${txParams.from} not a string`) + assert.throws( + () => { + txUtils.validateFrom(txParams) + }, + Error, + `Invalid from address ${txParams.from} not a string`, + ) // where from is a object txParams.from = {} - assert.throws(() => { - txUtils.validateFrom(txParams) - }, Error, `Invalid from address ${txParams.from} not a string`) + assert.throws( + () => { + txUtils.validateFrom(txParams) + }, + Error, + `Invalid from address ${txParams.from} not a string`, + ) // where from is a invalid address txParams.from = 'im going to fail' - assert.throws(() => { - txUtils.validateFrom(txParams) - }, Error, `Invalid from address`) + assert.throws( + () => { + txUtils.validateFrom(txParams) + }, + Error, + `Invalid from address`, + ) // should run txParams.from = '0x1678a085c290ebd122dc42cba69373b5953b831d' diff --git a/test/unit/app/fetch-with-timeout.test.js b/test/unit/app/fetch-with-timeout.test.js index af25a329c..89ea2fec9 100644 --- a/test/unit/app/fetch-with-timeout.test.js +++ b/test/unit/app/fetch-with-timeout.test.js @@ -5,9 +5,7 @@ import fetchWithTimeout from '../../../app/scripts/lib/fetch-with-timeout' describe('fetchWithTimeout', function () { it('fetches a url', async function () { - nock('https://api.infura.io') - .get('/money') - .reply(200, '{"hodl": false}') + nock('https://api.infura.io').get('/money').reply(200, '{"hodl": false}') const fetch = fetchWithTimeout() const response = await (await fetch('https://api.infura.io/money')).json() diff --git a/test/unit/app/message-manager-test.js b/test/unit/app/message-manager-test.js index 66eef7b10..348b13716 100644 --- a/test/unit/app/message-manager-test.js +++ b/test/unit/app/message-manager-test.js @@ -29,7 +29,11 @@ describe('Message Manager', function () { describe('#setMsgStatusApproved', function () { it('sets the Msg status to approved', function () { - const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { + id: 1, + status: 'unapproved', + metamaskNetworkId: 'unit test', + } messageManager.addMsg(Msg) messageManager.setMsgStatusApproved(1) const result = messageManager.messages @@ -41,7 +45,11 @@ describe('Message Manager', function () { describe('#rejectMsg', function () { it('sets the Msg status to rejected', function () { - const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { + id: 1, + status: 'unapproved', + metamaskNetworkId: 'unit test', + } messageManager.addMsg(Msg) messageManager.rejectMsg(1) const result = messageManager.messages @@ -53,9 +61,22 @@ describe('Message Manager', function () { describe('#_updateMsg', function () { it('replaces the Msg with the same id', function () { - messageManager.addMsg({ id: '1', status: 'unapproved', metamaskNetworkId: 'unit test' }) - messageManager.addMsg({ id: '2', status: 'approved', metamaskNetworkId: 'unit test' }) - messageManager._updateMsg({ id: '1', status: 'blah', hash: 'foo', metamaskNetworkId: 'unit test' }) + messageManager.addMsg({ + id: '1', + status: 'unapproved', + metamaskNetworkId: 'unit test', + }) + messageManager.addMsg({ + id: '2', + status: 'approved', + metamaskNetworkId: 'unit test', + }) + messageManager._updateMsg({ + id: '1', + status: 'blah', + hash: 'foo', + metamaskNetworkId: 'unit test', + }) const result = messageManager.getMsg('1') assert.equal(result.hash, 'foo') }) @@ -63,8 +84,16 @@ describe('Message Manager', function () { describe('#getUnapprovedMsgs', function () { it('returns unapproved Msgs in a hash', function () { - messageManager.addMsg({ id: '1', status: 'unapproved', metamaskNetworkId: 'unit test' }) - messageManager.addMsg({ id: '2', status: 'approved', metamaskNetworkId: 'unit test' }) + messageManager.addMsg({ + id: '1', + status: 'unapproved', + metamaskNetworkId: 'unit test', + }) + messageManager.addMsg({ + id: '2', + status: 'approved', + metamaskNetworkId: 'unit test', + }) const result = messageManager.getUnapprovedMsgs() assert.equal(typeof result, 'object') assert.equal(result['1'].status, 'unapproved') @@ -74,8 +103,16 @@ describe('Message Manager', function () { describe('#getMsg', function () { it('returns a Msg with the requested id', function () { - messageManager.addMsg({ id: '1', status: 'unapproved', metamaskNetworkId: 'unit test' }) - messageManager.addMsg({ id: '2', status: 'approved', metamaskNetworkId: 'unit test' }) + messageManager.addMsg({ + id: '1', + status: 'unapproved', + metamaskNetworkId: 'unit test', + }) + messageManager.addMsg({ + id: '2', + status: 'approved', + metamaskNetworkId: 'unit test', + }) assert.equal(messageManager.getMsg('1').status, 'unapproved') assert.equal(messageManager.getMsg('2').status, 'approved') }) diff --git a/test/unit/app/nodeify-test.js b/test/unit/app/nodeify-test.js index f6e9a3207..050553e61 100644 --- a/test/unit/app/nodeify-test.js +++ b/test/unit/app/nodeify-test.js @@ -4,7 +4,7 @@ import nodeify from '../../../app/scripts/lib/nodeify' describe('nodeify', function () { const obj = { foo: 'bar', - promiseFunc (a) { + promiseFunc(a) { const solution = this.foo + a return Promise.resolve(solution) }, @@ -29,7 +29,11 @@ describe('nodeify', function () { nodified('baz') done() } catch (err) { - done(new Error('should not have thrown if the last argument is not a function')) + done( + new Error( + 'should not have thrown if the last argument is not a function', + ), + ) } }) diff --git a/test/unit/app/personal-message-manager-test.js b/test/unit/app/personal-message-manager-test.js index d95ca5e14..c9774ddae 100644 --- a/test/unit/app/personal-message-manager-test.js +++ b/test/unit/app/personal-message-manager-test.js @@ -29,7 +29,11 @@ describe('Personal Message Manager', function () { describe('#setMsgStatusApproved', function () { it('sets the Msg status to approved', function () { - const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { + id: 1, + status: 'unapproved', + metamaskNetworkId: 'unit test', + } messageManager.addMsg(Msg) messageManager.setMsgStatusApproved(1) const result = messageManager.messages @@ -41,7 +45,11 @@ describe('Personal Message Manager', function () { describe('#rejectMsg', function () { it('sets the Msg status to rejected', function () { - const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { + id: 1, + status: 'unapproved', + metamaskNetworkId: 'unit test', + } messageManager.addMsg(Msg) messageManager.rejectMsg(1) const result = messageManager.messages @@ -53,9 +61,22 @@ describe('Personal Message Manager', function () { describe('#_updateMsg', function () { it('replaces the Msg with the same id', function () { - messageManager.addMsg({ id: '1', status: 'unapproved', metamaskNetworkId: 'unit test' }) - messageManager.addMsg({ id: '2', status: 'approved', metamaskNetworkId: 'unit test' }) - messageManager._updateMsg({ id: '1', status: 'blah', hash: 'foo', metamaskNetworkId: 'unit test' }) + messageManager.addMsg({ + id: '1', + status: 'unapproved', + metamaskNetworkId: 'unit test', + }) + messageManager.addMsg({ + id: '2', + status: 'approved', + metamaskNetworkId: 'unit test', + }) + messageManager._updateMsg({ + id: '1', + status: 'blah', + hash: 'foo', + metamaskNetworkId: 'unit test', + }) const result = messageManager.getMsg('1') assert.equal(result.hash, 'foo') }) @@ -63,8 +84,16 @@ describe('Personal Message Manager', function () { describe('#getUnapprovedMsgs', function () { it('returns unapproved Msgs in a hash', function () { - messageManager.addMsg({ id: '1', status: 'unapproved', metamaskNetworkId: 'unit test' }) - messageManager.addMsg({ id: '2', status: 'approved', metamaskNetworkId: 'unit test' }) + messageManager.addMsg({ + id: '1', + status: 'unapproved', + metamaskNetworkId: 'unit test', + }) + messageManager.addMsg({ + id: '2', + status: 'approved', + metamaskNetworkId: 'unit test', + }) const result = messageManager.getUnapprovedMsgs() assert.equal(typeof result, 'object') assert.equal(result['1'].status, 'unapproved') @@ -74,8 +103,16 @@ describe('Personal Message Manager', function () { describe('#getMsg', function () { it('returns a Msg with the requested id', function () { - messageManager.addMsg({ id: '1', status: 'unapproved', metamaskNetworkId: 'unit test' }) - messageManager.addMsg({ id: '2', status: 'approved', metamaskNetworkId: 'unit test' }) + messageManager.addMsg({ + id: '1', + status: 'unapproved', + metamaskNetworkId: 'unit test', + }) + messageManager.addMsg({ + id: '2', + status: 'approved', + metamaskNetworkId: 'unit test', + }) assert.equal(messageManager.getMsg('1').status, 'unapproved') assert.equal(messageManager.getMsg('2').status, 'approved') }) diff --git a/test/unit/app/seed-phrase-verifier-test.js b/test/unit/app/seed-phrase-verifier-test.js index 7da97794a..9f569c556 100644 --- a/test/unit/app/seed-phrase-verifier-test.js +++ b/test/unit/app/seed-phrase-verifier-test.js @@ -6,9 +6,7 @@ import seedPhraseVerifier from '../../../app/scripts/lib/seed-phrase-verifier' import mockEncryptor from '../../lib/mock-encryptor' describe('SeedPhraseVerifier', function () { - describe('verifyAccounts', function () { - const password = 'passw0rd1' const hdKeyTree = 'HD Key Tree' @@ -28,7 +26,6 @@ describe('SeedPhraseVerifier', function () { }) it('should be able to verify created account with seed words', async function () { - const createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) @@ -40,7 +37,6 @@ describe('SeedPhraseVerifier', function () { }) it('should be able to verify created account (upper case) with seed words', async function () { - const createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) @@ -54,7 +50,6 @@ describe('SeedPhraseVerifier', function () { }) it('should be able to verify created account (lower case) with seed words', async function () { - const createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) const lowerCaseAccounts = [createdAccounts[0].toLowerCase()] @@ -67,28 +62,31 @@ describe('SeedPhraseVerifier', function () { }) it('should return error with good but different seed words', async function () { - const createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) await primaryKeyring.serialize() - const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + const seedWords = + 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' try { await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) assert.fail('Should reject') } catch (err) { - assert.ok(err.message.indexOf('Not identical accounts!') >= 0, 'Wrong error message') + assert.ok( + err.message.indexOf('Not identical accounts!') >= 0, + 'Wrong error message', + ) } }) it('should return error with undefined existing accounts', async function () { - const createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) await primaryKeyring.serialize() - const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + const seedWords = + 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' try { await seedPhraseVerifier.verifyAccounts(undefined, seedWords) @@ -99,12 +97,12 @@ describe('SeedPhraseVerifier', function () { }) it('should return error with empty accounts array', async function () { - const createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) await primaryKeyring.serialize() - const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + const seedWords = + 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' try { await seedPhraseVerifier.verifyAccounts([], seedWords) @@ -115,7 +113,6 @@ describe('SeedPhraseVerifier', function () { }) it('should be able to verify more than one created account with seed words', async function () { - await keyringController.addNewAccount(primaryKeyring) await keyringController.addNewAccount(primaryKeyring) diff --git a/test/unit/app/typed-message-manager.spec.js b/test/unit/app/typed-message-manager.spec.js index 7598ea185..26abd2150 100644 --- a/test/unit/app/typed-message-manager.spec.js +++ b/test/unit/app/typed-message-manager.spec.js @@ -3,7 +3,13 @@ import sinon from 'sinon' import TypedMessageManager from '../../../app/scripts/lib/typed-message-manager' describe('Typed Message Manager', function () { - let typedMessageManager, msgParamsV1, msgParamsV3, typedMsgs, messages, msgId, numberMsgId + let typedMessageManager, + msgParamsV1, + msgParamsV3, + typedMsgs, + messages, + msgId, + numberMsgId const address = '0xc42edfcc21ed14dda456aa0756c153f7985d8813' @@ -16,47 +22,51 @@ describe('Typed Message Manager', function () { from: address, data: [ { type: 'string', name: 'unit test', value: 'hello there' }, - { type: 'uint32', name: 'A number, but not really a number', value: '$$$' }, + { + type: 'uint32', + name: 'A number, but not really a number', + value: '$$$', + }, ], } msgParamsV3 = { from: address, data: JSON.stringify({ - 'types': { - 'EIP712Domain': [ - { 'name': 'name', 'type': 'string' }, - { 'name': 'version', 'type': 'string' }, - { 'name': 'chainId', 'type': 'uint256' }, - { 'name': 'verifyingContract', 'type': 'address' }, + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, ], - 'Person': [ - { 'name': 'name', 'type': 'string' }, - { 'name': 'wallet', 'type': 'address' }, + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, ], - 'Mail': [ - { 'name': 'from', 'type': 'Person' }, - { 'name': 'to', 'type': 'Person' }, - { 'name': 'contents', 'type': 'string' }, + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, ], }, - 'primaryType': 'Mail', - 'domain': { - 'name': 'Ether Mainl', - 'version': '1', - 'chainId': 1, - 'verifyingContract': '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + primaryType: 'Mail', + domain: { + name: 'Ether Mainl', + version: '1', + chainId: 1, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', }, - 'message': { - 'from': { - 'name': 'Cow', - 'wallet': '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', }, - 'to': { - 'name': 'Bob', - 'wallet': '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', }, - 'contents': 'Hello, Bob!', + contents: 'Hello, Bob!', }, }), } @@ -109,5 +119,4 @@ describe('Typed Message Manager', function () { typedMessageManager.rejectMsg(numberMsgId) assert.equal(messages[0].status, 'rejected') }) - }) diff --git a/test/unit/app/util-test.js b/test/unit/app/util-test.js index 5d25d9b08..f2372576f 100644 --- a/test/unit/app/util-test.js +++ b/test/unit/app/util-test.js @@ -15,42 +15,58 @@ import { describe('app utils', function () { describe('getEnvironmentType', function () { it('should return popup type', function () { - const environmentType = getEnvironmentType('http://extension-id/popup.html') + const environmentType = getEnvironmentType( + 'http://extension-id/popup.html', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_POPUP) }) it('should return notification type', function () { - const environmentType = getEnvironmentType('http://extension-id/notification.html') + const environmentType = getEnvironmentType( + 'http://extension-id/notification.html', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_NOTIFICATION) }) it('should return fullscreen type for home.html', function () { - const environmentType = getEnvironmentType('http://extension-id/home.html') + const environmentType = getEnvironmentType( + 'http://extension-id/home.html', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_FULLSCREEN) }) it('should return fullscreen type for phishing.html', function () { - const environmentType = getEnvironmentType('http://extension-id/phishing.html') + const environmentType = getEnvironmentType( + 'http://extension-id/phishing.html', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_FULLSCREEN) }) it('should return background type', function () { - const environmentType = getEnvironmentType('http://extension-id/_generated_background_page.html') + const environmentType = getEnvironmentType( + 'http://extension-id/_generated_background_page.html', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_BACKGROUND) }) it('should return the correct type for a URL with a hash fragment', function () { - const environmentType = getEnvironmentType('http://extension-id/popup.html#hash') + const environmentType = getEnvironmentType( + 'http://extension-id/popup.html#hash', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_POPUP) }) it('should return the correct type for a URL with query parameters', function () { - const environmentType = getEnvironmentType('http://extension-id/popup.html?param=foo') + const environmentType = getEnvironmentType( + 'http://extension-id/popup.html?param=foo', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_POPUP) }) it('should return the correct type for a URL with query parameters and a hash fragment', function () { - const environmentType = getEnvironmentType('http://extension-id/popup.html?param=foo#hash') + const environmentType = getEnvironmentType( + 'http://extension-id/popup.html?param=foo#hash', + ) assert.equal(environmentType, ENVIRONMENT_TYPE_POPUP) }) }) @@ -58,9 +74,9 @@ describe('app utils', function () { describe('SufficientBalance', function () { it('returns true if max tx cost is equal to balance.', function () { const tx = { - 'value': '0x1', - 'gas': '0x2', - 'gasPrice': '0x3', + value: '0x1', + gas: '0x2', + gasPrice: '0x3', } const balance = '0x8' @@ -70,9 +86,9 @@ describe('app utils', function () { it('returns true if max tx cost is less than balance.', function () { const tx = { - 'value': '0x1', - 'gas': '0x2', - 'gasPrice': '0x3', + value: '0x1', + gas: '0x2', + gasPrice: '0x3', } const balance = '0x9' @@ -82,9 +98,9 @@ describe('app utils', function () { it('returns false if max tx cost is more than balance.', function () { const tx = { - 'value': '0x1', - 'gas': '0x2', - 'gasPrice': '0x3', + value: '0x1', + gas: '0x2', + gasPrice: '0x3', } const balance = '0x6' @@ -96,71 +112,80 @@ describe('app utils', function () { describe('isPrefixedFormattedHexString', function () { it('should return true for valid hex strings', function () { assert.equal( - isPrefixedFormattedHexString('0x1'), true, + isPrefixedFormattedHexString('0x1'), + true, 'should return true', ) assert.equal( - isPrefixedFormattedHexString('0xa'), true, + isPrefixedFormattedHexString('0xa'), + true, 'should return true', ) assert.equal( - isPrefixedFormattedHexString('0xabcd1123fae909aad87452'), true, + isPrefixedFormattedHexString('0xabcd1123fae909aad87452'), + true, 'should return true', ) }) it('should return false for invalid hex strings', function () { assert.equal( - isPrefixedFormattedHexString('0x'), false, + isPrefixedFormattedHexString('0x'), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString('0x0'), false, + isPrefixedFormattedHexString('0x0'), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString('0x01'), false, + isPrefixedFormattedHexString('0x01'), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString(' 0x1'), false, + isPrefixedFormattedHexString(' 0x1'), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString('0x1 '), false, + isPrefixedFormattedHexString('0x1 '), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString('0x1afz'), false, + isPrefixedFormattedHexString('0x1afz'), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString('z'), false, + isPrefixedFormattedHexString('z'), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString(2), false, + isPrefixedFormattedHexString(2), + false, 'should return false', ) assert.equal( - isPrefixedFormattedHexString(['0x1']), false, + isPrefixedFormattedHexString(['0x1']), + false, 'should return false', ) - assert.equal( - isPrefixedFormattedHexString(), false, - 'should return false', - ) + assert.equal(isPrefixedFormattedHexString(), false, 'should return false') }) }) }) diff --git a/test/unit/localhostState.js b/test/unit/localhostState.js index 13bd7af3c..8b0c68507 100644 --- a/test/unit/localhostState.js +++ b/test/unit/localhostState.js @@ -1,4 +1,3 @@ - /** * @typedef {Object} FirstTimeState * @property {Object} config Initial configuration parameters diff --git a/test/unit/migrations/021-test.js b/test/unit/migrations/021-test.js index bc18d6cfe..028e0e99d 100644 --- a/test/unit/migrations/021-test.js +++ b/test/unit/migrations/021-test.js @@ -4,12 +4,14 @@ import migration21 from '../../../app/scripts/migrations/021' describe('wallet2 is migrated successfully with out the BlacklistController', function () { it('should delete BlacklistController key', function (done) { - migration21.migrate(wallet2) + migration21 + .migrate(wallet2) .then((migratedData) => { assert.equal(migratedData.meta.version, 21) assert(!migratedData.data.BlacklistController) assert(!migratedData.data.RecentBlocks) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/022-test.js b/test/unit/migrations/022-test.js index 8f33d62e2..1c146fa36 100644 --- a/test/unit/migrations/022-test.js +++ b/test/unit/migrations/022-test.js @@ -1,15 +1,15 @@ import assert from 'assert' import migration22 from '../../../app/scripts/migrations/022' -const properTime = (new Date()).getTime() +const properTime = new Date().getTime() const storage = { - 'meta': {}, - 'data': { - 'TransactionController': { - 'transactions': [ - { 'status': 'submitted' }, - { 'status': 'submitted', 'submittedTime': properTime }, - { 'status': 'confirmed' }, + meta: {}, + data: { + TransactionController: { + transactions: [ + { status: 'submitted' }, + { status: 'submitted', submittedTime: properTime }, + { status: 'confirmed' }, ], }, }, @@ -17,9 +17,14 @@ const storage = { describe('storage is migrated successfully where transactions that are submitted have submittedTimes', function () { it('should add submittedTime key on the txMeta if appropriate', function (done) { - migration22.migrate(storage) + migration22 + .migrate(storage) .then((migratedData) => { - const [txMeta1, txMeta2, txMeta3] = migratedData.data.TransactionController.transactions + const [ + txMeta1, + txMeta2, + txMeta3, + ] = migratedData.data.TransactionController.transactions assert.equal(migratedData.meta.version, 22) // should have written a submitted time assert(txMeta1.submittedTime) @@ -28,6 +33,7 @@ describe('storage is migrated successfully where transactions that are submitted // should not have written a submitted time assert(!txMeta3.submittedTime) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/023-test.js b/test/unit/migrations/023-test.js index 49f40b033..89a90925d 100644 --- a/test/unit/migrations/023-test.js +++ b/test/unit/migrations/023-test.js @@ -2,11 +2,10 @@ import assert from 'assert' import migration23 from '../../../app/scripts/migrations/023' const storage = { - 'meta': {}, - 'data': { - 'TransactionController': { - 'transactions': [ - ], + meta: {}, + data: { + TransactionController: { + transactions: [], }, }, } @@ -26,12 +25,7 @@ const txStates = [ 'dropped', ] -const deletableTxStates = [ - 'confirmed', - 'rejected', - 'failed', - 'dropped', -] +const deletableTxStates = ['confirmed', 'rejected', 'failed', 'dropped'] let nonDeletableCount = 0 @@ -60,42 +54,65 @@ storage.data.TransactionController.transactions = transactions describe('storage is migrated successfully and the proper transactions are remove from state', function () { it('should remove transactions that are unneeded', function (done) { - migration23.migrate(storage) + migration23 + .migrate(storage) .then((migratedData) => { let leftoverNonDeletableTxCount = 0 - const migratedTransactions = migratedData.data.TransactionController.transactions + const migratedTransactions = + migratedData.data.TransactionController.transactions migratedTransactions.forEach((tx) => { if (!deletableTxStates.find((s) => s === tx.status)) { leftoverNonDeletableTxCount += 1 } }) - assert.equal(leftoverNonDeletableTxCount, nonDeletableCount, "migration shouldn't delete transactions we want to keep") - assert((migratedTransactions.length >= 40), `should be equal or greater to 40 if they are non deletable states got ${migratedTransactions.length} transactions`) + assert.equal( + leftoverNonDeletableTxCount, + nonDeletableCount, + "migration shouldn't delete transactions we want to keep", + ) + assert( + migratedTransactions.length >= 40, + `should be equal or greater to 40 if they are non deletable states got ${migratedTransactions.length} transactions`, + ) done() - }).catch(done) + }) + .catch(done) }) it('should not remove any transactions because 40 is the expected limit', function (done) { storage.meta.version = 22 storage.data.TransactionController.transactions = transactions40 - migration23.migrate(storage) + migration23 + .migrate(storage) .then((migratedData) => { - const migratedTransactions = migratedData.data.TransactionController.transactions + const migratedTransactions = + migratedData.data.TransactionController.transactions - assert.equal(migratedTransactions.length, 40, "migration shouldn't delete when at limit") + assert.equal( + migratedTransactions.length, + 40, + "migration shouldn't delete when at limit", + ) done() - }).catch(done) + }) + .catch(done) }) it('should not remove any transactions because 20 txs is under the expected limit', function (done) { storage.meta.version = 22 storage.data.TransactionController.transactions = transactions20 - migration23.migrate(storage) + migration23 + .migrate(storage) .then((migratedData) => { - const migratedTransactions = migratedData.data.TransactionController.transactions - assert.equal(migratedTransactions.length, 20, "migration shouldn't delete when under limit") + const migratedTransactions = + migratedData.data.TransactionController.transactions + assert.equal( + migratedTransactions.length, + 20, + "migration shouldn't delete when under limit", + ) done() - }).catch(done) + }) + .catch(done) }) - }) diff --git a/test/unit/migrations/024-test.js b/test/unit/migrations/024-test.js index 446f85f07..23a2a8bea 100644 --- a/test/unit/migrations/024-test.js +++ b/test/unit/migrations/024-test.js @@ -7,11 +7,10 @@ const firstTimeState = { data, } const storage = { - 'meta': {}, - 'data': { - 'TransactionController': { - 'transactions': [ - ], + meta: {}, + data: { + TransactionController: { + transactions: [], }, }, } @@ -19,33 +18,50 @@ const storage = { const transactions = [] while (transactions.length <= 10) { - transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, status: 'unapproved' }) - transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, status: 'confirmed' }) + transactions.push({ + txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, + status: 'unapproved', + }) + transactions.push({ + txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, + status: 'confirmed', + }) } storage.data.TransactionController.transactions = transactions describe('storage is migrated successfully and the txParams.from are lowercase', function () { it('should lowercase the from for unapproved txs', function (done) { - migration24.migrate(storage) + migration24 + .migrate(storage) .then((migratedData) => { - const migratedTransactions = migratedData.data.TransactionController.transactions + const migratedTransactions = + migratedData.data.TransactionController.transactions migratedTransactions.forEach((tx) => { if (tx.status === 'unapproved') { - assert.equal(tx.txParams.from, '0x8acce2391c0d510a6c5e5d8f819a678f79b7e675') + assert.equal( + tx.txParams.from, + '0x8acce2391c0d510a6c5e5d8f819a678f79b7e675', + ) } else { - assert.equal(tx.txParams.from, '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675') + assert.equal( + tx.txParams.from, + '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675', + ) } }) done() - }).catch(done) + }) + .catch(done) }) it('should migrate first time state', function (done) { - migration24.migrate(firstTimeState) + migration24 + .migrate(firstTimeState) .then((migratedData) => { assert.equal(migratedData.meta.version, 24) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/025-test.js b/test/unit/migrations/025-test.js index 2cd3381ca..d734df962 100644 --- a/test/unit/migrations/025-test.js +++ b/test/unit/migrations/025-test.js @@ -8,11 +8,10 @@ const firstTimeState = { } const storage = { - 'meta': {}, - 'data': { - 'TransactionController': { - 'transactions': [ - ], + meta: {}, + data: { + TransactionController: { + transactions: [], }, }, } @@ -20,17 +19,29 @@ const storage = { const transactions = [] while (transactions.length <= 10) { - transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675', random: 'stuff', chainId: 2 }, status: 'unapproved' }) - transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, status: 'confirmed' }) + transactions.push({ + txParams: { + from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675', + random: 'stuff', + chainId: 2, + }, + status: 'unapproved', + }) + transactions.push({ + txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, + status: 'confirmed', + }) } storage.data.TransactionController.transactions = transactions describe('storage is migrated successfully and the txParams.from are lowercase', function () { it('should lowercase the from for unapproved txs', function (done) { - migration25.migrate(storage) + migration25 + .migrate(storage) .then((migratedData) => { - const migratedTransactions = migratedData.data.TransactionController.transactions + const migratedTransactions = + migratedData.data.TransactionController.transactions migratedTransactions.forEach((tx) => { if (tx.status === 'unapproved') { assert(!tx.txParams.random) @@ -40,14 +51,17 @@ describe('storage is migrated successfully and the txParams.from are lowercase', } }) done() - }).catch(done) + }) + .catch(done) }) it('should migrate first time state', function (done) { - migration25.migrate(firstTimeState) + migration25 + .migrate(firstTimeState) .then((migratedData) => { assert.equal(migratedData.meta.version, 25) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/026-test.js b/test/unit/migrations/026-test.js index 3227e3394..9168ea493 100644 --- a/test/unit/migrations/026-test.js +++ b/test/unit/migrations/026-test.js @@ -3,11 +3,11 @@ import firstTimeState from '../../../app/scripts/first-time-state' import migration26 from '../../../app/scripts/migrations/026' const oldStorage = { - 'meta': { 'version': 25 }, - 'data': { - 'PreferencesController': {}, - 'KeyringController': { - 'walletNicknames': { + meta: { version: 25 }, + data: { + PreferencesController: {}, + KeyringController: { + walletNicknames: { '0x1e77e2': 'Test Account 1', '0x7e57e2': 'Test Account 2', }, @@ -17,27 +17,33 @@ const oldStorage = { describe('migration #26', function () { it('should move the identities from KeyringController', function (done) { - migration26.migrate(oldStorage) + migration26 + .migrate(oldStorage) .then((newStorage) => { const { identities } = newStorage.data.PreferencesController assert.deepEqual(identities, { '0x1e77e2': { name: 'Test Account 1', address: '0x1e77e2' }, '0x7e57e2': { name: 'Test Account 2', address: '0x7e57e2' }, }) - assert.strictEqual(newStorage.data.KeyringController.walletNicknames, undefined) + assert.strictEqual( + newStorage.data.KeyringController.walletNicknames, + undefined, + ) done() }) .catch(done) }) it('should successfully migrate first time state', function (done) { - migration26.migrate({ - meta: {}, - data: firstTimeState, - }) + migration26 + .migrate({ + meta: {}, + data: firstTimeState, + }) .then((migratedData) => { assert.equal(migratedData.meta.version, migration26.version) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/027-test.js b/test/unit/migrations/027-test.js index 959f30374..6fd3be159 100644 --- a/test/unit/migrations/027-test.js +++ b/test/unit/migrations/027-test.js @@ -3,11 +3,10 @@ import firstTimeState from '../../../app/scripts/first-time-state' import migration27 from '../../../app/scripts/migrations/027' const oldStorage = { - 'meta': {}, - 'data': { - 'TransactionController': { - 'transactions': [ - ], + meta: {}, + data: { + TransactionController: { + transactions: [], }, }, } @@ -24,10 +23,16 @@ oldStorage.data.TransactionController.transactions = transactions describe('migration #27', function () { it('should remove rejected transactions', function (done) { - migration27.migrate(oldStorage) + migration27 + .migrate(oldStorage) .then((newStorage) => { - const newTransactions = newStorage.data.TransactionController.transactions - assert.equal(newTransactions.length, 6, 'transactions is expected to have the length of 6') + const newTransactions = + newStorage.data.TransactionController.transactions + assert.equal( + newTransactions.length, + 6, + 'transactions is expected to have the length of 6', + ) newTransactions.forEach((txMeta) => { if (txMeta.status === 'rejected') { done(new Error('transaction was found with a status of rejected')) @@ -39,13 +44,15 @@ describe('migration #27', function () { }) it('should successfully migrate first time state', function (done) { - migration27.migrate({ - meta: {}, - data: firstTimeState, - }) + migration27 + .migrate({ + meta: {}, + data: firstTimeState, + }) .then((migratedData) => { assert.equal(migratedData.meta.version, migration27.version) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/028-test.js b/test/unit/migrations/028-test.js index b352f0a29..caa8c86bf 100644 --- a/test/unit/migrations/028-test.js +++ b/test/unit/migrations/028-test.js @@ -3,11 +3,14 @@ import firstTimeState from '../../../app/scripts/first-time-state' import migration28 from '../../../app/scripts/migrations/028' const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [{ address: '0xa', symbol: 'A', decimals: 4 }, { address: '0xb', symbol: 'B', decimals: 4 }], - 'identities': { + meta: {}, + data: { + PreferencesController: { + tokens: [ + { address: '0xa', symbol: 'A', decimals: 4 }, + { address: '0xb', symbol: 'B', decimals: 4 }, + ], + identities: { '0x6d14': {}, '0x3695': {}, }, @@ -17,31 +20,62 @@ const oldStorage = { describe('migration #28', function () { it('should add corresponding tokens to accountTokens', function (done) { - migration28.migrate(oldStorage) + migration28 + .migrate(oldStorage) .then((newStorage) => { const newTokens = newStorage.data.PreferencesController.tokens - const newAccountTokens = newStorage.data.PreferencesController.accountTokens + const newAccountTokens = + newStorage.data.PreferencesController.accountTokens - const testTokens = [{ address: '0xa', symbol: 'A', decimals: 4 }, { address: '0xb', symbol: 'B', decimals: 4 }] - assert.equal(newTokens.length, 0, 'tokens is expected to have the length of 0') - assert.equal(newAccountTokens['0x6d14'].mainnet.length, 2, 'tokens for address is expected to have the length of 2') - assert.equal(newAccountTokens['0x3695'].mainnet.length, 2, 'tokens for address is expected to have the length of 2') - assert.equal(Object.keys(newAccountTokens).length, 2, 'account tokens should be created for all identities') - assert.deepEqual(newAccountTokens['0x6d14'].mainnet, testTokens, 'tokens for address should be the same than before') - assert.deepEqual(newAccountTokens['0x3695'].mainnet, testTokens, 'tokens for address should be the same than before') + const testTokens = [ + { address: '0xa', symbol: 'A', decimals: 4 }, + { address: '0xb', symbol: 'B', decimals: 4 }, + ] + assert.equal( + newTokens.length, + 0, + 'tokens is expected to have the length of 0', + ) + assert.equal( + newAccountTokens['0x6d14'].mainnet.length, + 2, + 'tokens for address is expected to have the length of 2', + ) + assert.equal( + newAccountTokens['0x3695'].mainnet.length, + 2, + 'tokens for address is expected to have the length of 2', + ) + assert.equal( + Object.keys(newAccountTokens).length, + 2, + 'account tokens should be created for all identities', + ) + assert.deepEqual( + newAccountTokens['0x6d14'].mainnet, + testTokens, + 'tokens for address should be the same than before', + ) + assert.deepEqual( + newAccountTokens['0x3695'].mainnet, + testTokens, + 'tokens for address should be the same than before', + ) done() }) .catch(done) }) it('should successfully migrate first time state', function (done) { - migration28.migrate({ - meta: {}, - data: firstTimeState, - }) + migration28 + .migrate({ + meta: {}, + data: firstTimeState, + }) .then((migratedData) => { assert.equal(migratedData.meta.version, migration28.version) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/029-test.js b/test/unit/migrations/029-test.js index ccde6b4cb..f3aacf8ed 100644 --- a/test/unit/migrations/029-test.js +++ b/test/unit/migrations/029-test.js @@ -1,17 +1,17 @@ import assert from 'assert' import migration29 from '../../../app/scripts/migrations/029' -const properTime = (new Date()).getTime() +const properTime = new Date().getTime() const storage = { - 'meta': {}, - 'data': { - 'TransactionController': { - 'transactions': [ - { 'status': 'approved', id: 1, submittedTime: 0 }, - { 'status': 'approved', id: 2, submittedTime: properTime }, - { 'status': 'confirmed', id: 3, submittedTime: properTime }, - { 'status': 'submitted', id: 4, submittedTime: properTime }, - { 'status': 'submitted', id: 5, submittedTime: 0 }, + meta: {}, + data: { + TransactionController: { + transactions: [ + { status: 'approved', id: 1, submittedTime: 0 }, + { status: 'approved', id: 2, submittedTime: properTime }, + { status: 'confirmed', id: 3, submittedTime: properTime }, + { status: 'submitted', id: 4, submittedTime: properTime }, + { status: 'submitted', id: 5, submittedTime: 0 }, ], }, }, @@ -19,14 +19,18 @@ const storage = { describe('storage is migrated successfully where transactions that are submitted have submittedTimes', function () { it('should auto fail transactions more than 12 hours old', function (done) { - migration29.migrate(storage) + migration29 + .migrate(storage) .then((migratedData) => { const txs = migratedData.data.TransactionController.transactions const [txMeta1] = txs assert.equal(migratedData.meta.version, 29) assert.equal(txMeta1.status, 'failed', 'old tx is auto failed') - assert(txMeta1.err.message.includes('too long'), 'error message assigned') + assert( + txMeta1.err.message.includes('too long'), + 'error message assigned', + ) txs.forEach((tx) => { if (tx.id === 1) { @@ -36,6 +40,7 @@ describe('storage is migrated successfully where transactions that are submitted }) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/030-test.js b/test/unit/migrations/030-test.js index 6d0271f0d..24acbfba2 100644 --- a/test/unit/migrations/030-test.js +++ b/test/unit/migrations/030-test.js @@ -16,8 +16,18 @@ const storage = { }, PreferencesController: { frequentRpcListDetail: [ - { chainId: 'fail', nickname: '', rpcUrl: 'http://127.0.0.1:8545', ticker: '' }, - { chainId: '1', nickname: '', rpcUrl: 'https://api.myetherwallet.com/eth', ticker: 'ETH' }, + { + chainId: 'fail', + nickname: '', + rpcUrl: 'http://127.0.0.1:8545', + ticker: '', + }, + { + chainId: '1', + nickname: '', + rpcUrl: 'https://api.myetherwallet.com/eth', + ticker: 'ETH', + }, ], }, }, @@ -25,14 +35,27 @@ const storage = { describe('storage is migrated successfully', function () { it('should work', function (done) { - migrationTemplate.migrate(storage) + migrationTemplate + .migrate(storage) .then((migratedData) => { assert.equal(migratedData.meta.version, 30) - assert.equal(migratedData.data.PreferencesController.frequentRpcListDetail[0].chainId, undefined) - assert.equal(migratedData.data.PreferencesController.frequentRpcListDetail[1].chainId, '1') - assert.equal(migratedData.data.NetworkController.provider.chainId, undefined) + assert.equal( + migratedData.data.PreferencesController.frequentRpcListDetail[0] + .chainId, + undefined, + ) + assert.equal( + migratedData.data.PreferencesController.frequentRpcListDetail[1] + .chainId, + '1', + ) + assert.equal( + migratedData.data.NetworkController.provider.chainId, + undefined, + ) assert.equal(migratedData.data.NetworkController.network, undefined) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/migrations/031-test.js b/test/unit/migrations/031-test.js index 5c9f7d20b..2110fc373 100644 --- a/test/unit/migrations/031-test.js +++ b/test/unit/migrations/031-test.js @@ -4,28 +4,35 @@ import migration31 from '../../../app/scripts/migrations/031' describe('migration #31', function () { it('should set completedOnboarding to true if vault exists', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [{ address: '0xa', symbol: 'A', decimals: 4 }, { address: '0xb', symbol: 'B', decimals: 4 }], - 'identities': { + meta: {}, + data: { + PreferencesController: { + tokens: [ + { address: '0xa', symbol: 'A', decimals: 4 }, + { address: '0xb', symbol: 'B', decimals: 4 }, + ], + identities: { '0x6d14': {}, '0x3695': {}, }, }, - 'KeyringController': { - 'vault': { - 'data': 'test0', - 'iv': 'test1', - 'salt': 'test2', + KeyringController: { + vault: { + data: 'test0', + iv: 'test1', + salt: 'test2', }, }, }, } - migration31.migrate(oldStorage) + migration31 + .migrate(oldStorage) .then((newStorage) => { - assert.equal(newStorage.data.PreferencesController.completedOnboarding, true) + assert.equal( + newStorage.data.PreferencesController.completedOnboarding, + true, + ) done() }) .catch(done) @@ -33,22 +40,29 @@ describe('migration #31', function () { it('should set completedOnboarding to false if vault does not exist', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [{ address: '0xa', symbol: 'A', decimals: 4 }, { address: '0xb', symbol: 'B', decimals: 4 }], - 'identities': { + meta: {}, + data: { + PreferencesController: { + tokens: [ + { address: '0xa', symbol: 'A', decimals: 4 }, + { address: '0xb', symbol: 'B', decimals: 4 }, + ], + identities: { '0x6d14': {}, '0x3695': {}, }, }, - 'KeyringController': {}, + KeyringController: {}, }, } - migration31.migrate(oldStorage) + migration31 + .migrate(oldStorage) .then((newStorage) => { - assert.equal(newStorage.data.PreferencesController.completedOnboarding, false) + assert.equal( + newStorage.data.PreferencesController.completedOnboarding, + false, + ) done() }) .catch(done) diff --git a/test/unit/migrations/033-test.js b/test/unit/migrations/033-test.js index 4456a7e4a..b09846f0f 100644 --- a/test/unit/migrations/033-test.js +++ b/test/unit/migrations/033-test.js @@ -3,10 +3,10 @@ import migration33 from '../../../app/scripts/migrations/033' describe('Migration to delete notice controller', function () { const oldStorage = { - 'meta': {}, - 'data': { - 'NoticeController': { - 'noticesList': [ + meta: {}, + data: { + NoticeController: { + noticesList: [ { id: 0, read: false, @@ -32,9 +32,8 @@ describe('Migration to delete notice controller', function () { } it('removes notice controller from state', function () { - migration33.migrate(oldStorage) - .then((newStorage) => { - assert.equal(newStorage.data.NoticeController, undefined) - }) + migration33.migrate(oldStorage).then((newStorage) => { + assert.equal(newStorage.data.NoticeController, undefined) + }) }) }) diff --git a/test/unit/migrations/034-test.js b/test/unit/migrations/034-test.js index 64af34b2e..74de274cf 100644 --- a/test/unit/migrations/034-test.js +++ b/test/unit/migrations/034-test.js @@ -4,16 +4,17 @@ import migration34 from '../../../app/scripts/migrations/034' describe('migration #34', function () { it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 33, + meta: { + version: 33, }, - 'data': {}, + data: {}, } - migration34.migrate(oldStorage) + migration34 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 34, + version: 34, }) done() }) @@ -22,22 +23,23 @@ describe('migration #34', function () { it('should set migratedPrivacyMode & privacyMode if featureFlags.privacyMode was false', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'featureFlags': { - 'privacyMode': false, + meta: {}, + data: { + PreferencesController: { + featureFlags: { + privacyMode: false, }, }, }, } - migration34.migrate(oldStorage) + migration34 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, { - 'migratedPrivacyMode': true, - 'featureFlags': { - 'privacyMode': true, + migratedPrivacyMode: true, + featureFlags: { + privacyMode: true, }, }) done() @@ -47,18 +49,19 @@ describe('migration #34', function () { it('should NOT change any state if migratedPrivacyMode is already set to true', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'migratedPrivacyMode': true, - 'featureFlags': { - 'privacyMode': true, + meta: {}, + data: { + PreferencesController: { + migratedPrivacyMode: true, + featureFlags: { + privacyMode: true, }, }, }, } - migration34.migrate(oldStorage) + migration34 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -68,18 +71,19 @@ describe('migration #34', function () { it('should NOT change any state if migratedPrivacyMode is already set to false', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'migratedPrivacyMode': false, - 'featureFlags': { - 'privacyMode': true, + meta: {}, + data: { + PreferencesController: { + migratedPrivacyMode: false, + featureFlags: { + privacyMode: true, }, }, }, } - migration34.migrate(oldStorage) + migration34 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -89,11 +93,12 @@ describe('migration #34', function () { it('should NOT change any state if PreferencesController is missing', function (done) { const oldStorage = { - 'meta': {}, - 'data': {}, + meta: {}, + data: {}, } - migration34.migrate(oldStorage) + migration34 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -103,17 +108,18 @@ describe('migration #34', function () { it('should NOT change any state if featureFlags.privacyMode is already true', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'featureFlags': { - 'privacyMode': true, + meta: {}, + data: { + PreferencesController: { + featureFlags: { + privacyMode: true, }, }, }, } - migration34.migrate(oldStorage) + migration34 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() diff --git a/test/unit/migrations/035-test.js b/test/unit/migrations/035-test.js index 02f5c5314..263b2e2df 100644 --- a/test/unit/migrations/035-test.js +++ b/test/unit/migrations/035-test.js @@ -10,10 +10,11 @@ describe('migration #35', function () { data: {}, } - migration35.migrate(oldStorage) + migration35 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 35, + version: 35, }) done() }) @@ -30,7 +31,8 @@ describe('migration #35', function () { }, } - migration35.migrate(oldStorage) + migration35 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, {}) done() @@ -48,7 +50,8 @@ describe('migration #35', function () { }, } - migration35.migrate(oldStorage) + migration35 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, {}) done() @@ -85,7 +88,8 @@ describe('migration #35', function () { }, } - migration35.migrate(oldStorage) + migration35 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() diff --git a/test/unit/migrations/036-test.js b/test/unit/migrations/036-test.js index e1666e612..380de627b 100644 --- a/test/unit/migrations/036-test.js +++ b/test/unit/migrations/036-test.js @@ -4,16 +4,17 @@ import migration36 from '../../../app/scripts/migrations/036' describe('migration #36', function () { it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 35, + meta: { + version: 35, }, - 'data': {}, + data: {}, } - migration36.migrate(oldStorage) + migration36 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 36, + version: 36, }) done() }) @@ -22,21 +23,21 @@ describe('migration #36', function () { it('should remove privacyMode if featureFlags.privacyMode was false', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'featureFlags': { - 'privacyMode': false, + meta: {}, + data: { + PreferencesController: { + featureFlags: { + privacyMode: false, }, }, }, } - migration36.migrate(oldStorage) + migration36 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, { - 'featureFlags': { - }, + featureFlags: {}, }) done() }) @@ -45,21 +46,21 @@ describe('migration #36', function () { it('should remove privacyMode if featureFlags.privacyMode was true', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'featureFlags': { - 'privacyMode': true, + meta: {}, + data: { + PreferencesController: { + featureFlags: { + privacyMode: true, }, }, }, } - migration36.migrate(oldStorage) + migration36 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, { - 'featureFlags': { - }, + featureFlags: {}, }) done() }) @@ -68,17 +69,17 @@ describe('migration #36', function () { it('should NOT change any state if privacyMode does not exist', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'migratedPrivacyMode': true, - 'featureFlags': { - }, + meta: {}, + data: { + PreferencesController: { + migratedPrivacyMode: true, + featureFlags: {}, }, }, } - migration36.migrate(oldStorage) + migration36 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -88,11 +89,12 @@ describe('migration #36', function () { it('should NOT change any state if PreferencesController is missing', function (done) { const oldStorage = { - 'meta': {}, - 'data': {}, + meta: {}, + data: {}, } - migration36.migrate(oldStorage) + migration36 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -102,14 +104,14 @@ describe('migration #36', function () { it('should NOT change any state if featureFlags is missing', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - }, + meta: {}, + data: { + PreferencesController: {}, }, } - migration36.migrate(oldStorage) + migration36 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() diff --git a/test/unit/migrations/037-test.js b/test/unit/migrations/037-test.js index f67f8eb3f..861ab4cd1 100644 --- a/test/unit/migrations/037-test.js +++ b/test/unit/migrations/037-test.js @@ -4,16 +4,17 @@ import migration37 from '../../../app/scripts/migrations/037' describe('migration #37', function () { it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 36, + meta: { + version: 36, }, - 'data': {}, + data: {}, } - migration37.migrate(oldStorage) + migration37 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 37, + version: 37, }) done() }) @@ -22,10 +23,10 @@ describe('migration #37', function () { it('should transform old state to new format', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'AddressBookController': { - 'addressBook': { + meta: {}, + data: { + AddressBookController: { + addressBook: { '0x1De7e54679bfF0c23856FbF547b2394e723FCA91': { address: '0x1De7e54679bfF0c23856FbF547b2394e723FCA91', chainId: '4', @@ -50,10 +51,11 @@ describe('migration #37', function () { }, } - migration37.migrate(oldStorage) + migration37 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.AddressBookController.addressBook, { - '4': { + 4: { '0x1De7e54679bfF0c23856FbF547b2394e723FCA91': { address: '0x1De7e54679bfF0c23856FbF547b2394e723FCA91', chainId: '4', @@ -69,7 +71,7 @@ describe('migration #37', function () { name: 'account 2', }, }, - '2': { + 2: { '0x1De7e54679bfF0c23856FbF547b2394e723FCA93': { address: '0x1De7e54679bfF0c23856FbF547b2394e723FCA93', chainId: '2', @@ -86,10 +88,10 @@ describe('migration #37', function () { it('ens validation test', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'AddressBookController': { - 'addressBook': { + meta: {}, + data: { + AddressBookController: { + addressBook: { '0x1De7e54679bfF0c23856FbF547b2394e723FCA91': { address: '0x1De7e54679bfF0c23856FbF547b2394e723FCA91', chainId: '4', @@ -101,10 +103,11 @@ describe('migration #37', function () { }, } - migration37.migrate(oldStorage) + migration37 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.AddressBookController.addressBook, { - '4': { + 4: { '0x1De7e54679bfF0c23856FbF547b2394e723FCA91': { address: '0x1De7e54679bfF0c23856FbF547b2394e723FCA91', chainId: '4', diff --git a/test/unit/migrations/038-test.js b/test/unit/migrations/038-test.js index 0060f9f51..2c727a352 100644 --- a/test/unit/migrations/038-test.js +++ b/test/unit/migrations/038-test.js @@ -4,16 +4,17 @@ import migration38 from '../../../app/scripts/migrations/038' describe('migration #38', function () { it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 37, + meta: { + version: 37, }, - 'data': {}, + data: {}, } - migration38.migrate(oldStorage) + migration38 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 38, + version: 38, }) done() }) @@ -22,13 +23,17 @@ describe('migration #38', function () { it('should add a fullScreenVsPopup property set to either "control" or "fullScreen"', function (done) { const oldStorage = { - 'meta': {}, - 'data': {}, + meta: {}, + data: {}, } - migration38.migrate(oldStorage) + migration38 + .migrate(oldStorage) .then((newStorage) => { - assert.equal(newStorage.data.ABTestController.abTests.fullScreenVsPopup, 'control') + assert.equal( + newStorage.data.ABTestController.abTests.fullScreenVsPopup, + 'control', + ) done() }) .catch(done) @@ -36,21 +41,22 @@ describe('migration #38', function () { it('should leave the fullScreenVsPopup property unchanged if it exists', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'ABTestController': { + meta: {}, + data: { + ABTestController: { abTests: { - 'fullScreenVsPopup': 'fullScreen', + fullScreenVsPopup: 'fullScreen', }, }, }, } - migration38.migrate(oldStorage) + migration38 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.ABTestController, { abTests: { - 'fullScreenVsPopup': 'fullScreen', + fullScreenVsPopup: 'fullScreen', }, }) done() diff --git a/test/unit/migrations/039-test.js b/test/unit/migrations/039-test.js index 400a7a3ae..70b00da5f 100644 --- a/test/unit/migrations/039-test.js +++ b/test/unit/migrations/039-test.js @@ -4,16 +4,17 @@ import migration39 from '../../../app/scripts/migrations/039' describe('migration #39', function () { it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 38, + meta: { + version: 38, }, - 'data': {}, + data: {}, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 39, + version: 39, }) done() }) @@ -22,42 +23,51 @@ describe('migration #39', function () { it('should update old DAI token symbol to SAI in tokens', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [{ - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'DAI', - }, { - 'address': '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - 'symbol': 'BAT', - 'decimals': 18, - }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'symbol': 'META', - 'decimals': 18, - }], + meta: {}, + data: { + PreferencesController: { + tokens: [ + { + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'DAI', + }, + { + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + symbol: 'BAT', + decimals: 18, + }, + { + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + symbol: 'META', + decimals: 18, + }, + ], }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, { - 'tokens': [{ - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'SAI', - }, { - 'address': '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - 'symbol': 'BAT', - 'decimals': 18, - }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'symbol': 'META', - 'decimals': 18, - }], + tokens: [ + { + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'SAI', + }, + { + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + symbol: 'BAT', + decimals: 18, + }, + { + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + symbol: 'META', + decimals: 18, + }, + ], }) done() }) @@ -66,40 +76,40 @@ describe('migration #39', function () { it('should update old DAI token symbol to SAI in accountTokens', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'accountTokens': { + meta: {}, + data: { + PreferencesController: { + accountTokens: { '0x7250739de134d33ec7ab1ee592711e15098c9d2d': { - 'mainnet': [ + mainnet: [ { - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'DAI', + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'DAI', }, ], }, '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': { - 'mainnet': [], - 'rinkeby': [], + mainnet: [], + rinkeby: [], }, '0x8e5d75d60224ea0c33d1041e75de68b1c3cb6dd5': {}, '0xb3958fb96c8201486ae20be1d5c9f58083df343a': { - 'mainnet': [ + mainnet: [ { - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'DAI', + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'DAI', }, { - 'address': '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - 'decimals': 18, - 'symbol': 'BAT', + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + decimals: 18, + symbol: 'BAT', }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'decimals': 18, - 'symbol': 'META', + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + decimals: 18, + symbol: 'META', }, ], }, @@ -108,40 +118,41 @@ describe('migration #39', function () { }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data.PreferencesController, { - 'accountTokens': { + accountTokens: { '0x7250739de134d33ec7ab1ee592711e15098c9d2d': { - 'mainnet': [ + mainnet: [ { - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'SAI', + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'SAI', }, ], }, '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': { - 'mainnet': [], - 'rinkeby': [], + mainnet: [], + rinkeby: [], }, '0x8e5d75d60224ea0c33d1041e75de68b1c3cb6dd5': {}, '0xb3958fb96c8201486ae20be1d5c9f58083df343a': { - 'mainnet': [ + mainnet: [ { - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'SAI', + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'SAI', }, { - 'address': '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - 'decimals': 18, - 'symbol': 'BAT', + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + decimals: 18, + symbol: 'BAT', }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'decimals': 18, - 'symbol': 'META', + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + decimals: 18, + symbol: 'META', }, ], }, @@ -154,15 +165,16 @@ describe('migration #39', function () { it('should NOT change any state if accountTokens is not an object', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'accountTokens': [], + meta: {}, + data: { + PreferencesController: { + accountTokens: [], }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -172,33 +184,29 @@ describe('migration #39', function () { it('should NOT change any state if accountTokens is an object with invalid values', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'accountTokens': { + meta: {}, + data: { + PreferencesController: { + accountTokens: { '0x7250739de134d33ec7ab1ee592711e15098c9d2d': [ { - 'address': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - 'decimals': 18, - 'symbol': 'DAI', + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + decimals: 18, + symbol: 'DAI', }, ], '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359': null, '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': { - 'mainnet': [ - null, - undefined, - [], - 42, - ], - 'rinkeby': null, + mainnet: [null, undefined, [], 42], + rinkeby: null, }, }, }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -208,40 +216,40 @@ describe('migration #39', function () { it('should NOT change any state if accountTokens includes the new DAI token', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'accountTokens': { + meta: {}, + data: { + PreferencesController: { + accountTokens: { '0x7250739de134d33ec7ab1ee592711e15098c9d2d': { - 'mainnet': [ + mainnet: [ { - 'address': '0x6B175474E89094C44Da98b954EedeAC495271d0F', - 'decimals': 18, - 'symbol': 'DAI', + address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + decimals: 18, + symbol: 'DAI', }, ], }, '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': { - 'mainnet': [], - 'rinkeby': [], + mainnet: [], + rinkeby: [], }, '0x8e5d75d60224ea0c33d1041e75de68b1c3cb6dd5': {}, '0xb3958fb96c8201486ae20be1d5c9f58083df343a': { - 'mainnet': [ + mainnet: [ { - 'address': '0x6B175474E89094C44Da98b954EedeAC495271d0F', - 'decimals': 18, - 'symbol': 'DAI', + address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + decimals: 18, + symbol: 'DAI', }, { - 'address': '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - 'decimals': 18, - 'symbol': 'BAT', + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + decimals: 18, + symbol: 'BAT', }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'decimals': 18, - 'symbol': 'META', + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + decimals: 18, + symbol: 'META', }, ], }, @@ -250,7 +258,8 @@ describe('migration #39', function () { }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -260,23 +269,27 @@ describe('migration #39', function () { it('should NOT change any state if tokens includes the new DAI token', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [{ - 'address': '0x6B175474E89094C44Da98b954EedeAC495271d0F', - 'symbol': 'DAI', - 'decimals': 18, - }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'symbol': 'META', - 'decimals': 18, - }], + meta: {}, + data: { + PreferencesController: { + tokens: [ + { + address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + symbol: 'DAI', + decimals: 18, + }, + { + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + symbol: 'META', + decimals: 18, + }, + ], }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -286,23 +299,27 @@ describe('migration #39', function () { it('should NOT change any state if tokens does not include DAI', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [{ - 'address': '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - 'symbol': 'BAT', - 'decimals': 18, - }, { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'symbol': 'META', - 'decimals': 18, - }], + meta: {}, + data: { + PreferencesController: { + tokens: [ + { + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + symbol: 'BAT', + decimals: 18, + }, + { + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + symbol: 'META', + decimals: 18, + }, + ], }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -312,20 +329,16 @@ describe('migration #39', function () { it('should NOT change any state if a tokens property has invalid entries', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': [ - null, - [], - undefined, - 42, - ], + meta: {}, + data: { + PreferencesController: { + tokens: [null, [], undefined, 42], }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -335,15 +348,16 @@ describe('migration #39', function () { it('should NOT change any state if a tokens property is not an array', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': {}, + meta: {}, + data: { + PreferencesController: { + tokens: {}, }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -353,15 +367,16 @@ describe('migration #39', function () { it('should NOT change any state if a tokens property is null', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - 'tokens': null, + meta: {}, + data: { + PreferencesController: { + tokens: null, }, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -371,14 +386,14 @@ describe('migration #39', function () { it('should NOT change any state if a tokens property is missing', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - }, + meta: {}, + data: { + PreferencesController: {}, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -388,14 +403,14 @@ describe('migration #39', function () { it('should NOT change any state if a accountTokens property is missing', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'PreferencesController': { - }, + meta: {}, + data: { + PreferencesController: {}, }, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() @@ -405,11 +420,12 @@ describe('migration #39', function () { it('should NOT change any state if PreferencesController is missing', function (done) { const oldStorage = { - 'meta': {}, - 'data': {}, + meta: {}, + data: {}, } - migration39.migrate(oldStorage) + migration39 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, oldStorage.data) done() diff --git a/test/unit/migrations/040-test.js b/test/unit/migrations/040-test.js index 215deb5b7..fd4f48193 100644 --- a/test/unit/migrations/040-test.js +++ b/test/unit/migrations/040-test.js @@ -2,19 +2,19 @@ import assert from 'assert' import migration40 from '../../../app/scripts/migrations/040' describe('migration #40', function () { - it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 39, + meta: { + version: 39, }, - 'data': {}, + data: {}, } - migration40.migrate(oldStorage) + migration40 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 40, + version: 40, }) done() }) @@ -23,14 +23,15 @@ describe('migration #40', function () { it('should delete ProviderApprovalController storage key', function (done) { const oldStorage = { - 'meta': {}, - 'data': { - 'ProviderApprovalController': {}, - 'foo': 'bar', + meta: {}, + data: { + ProviderApprovalController: {}, + foo: 'bar', }, } - migration40.migrate(oldStorage) + migration40 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { foo: 'bar' }) done() @@ -40,11 +41,12 @@ describe('migration #40', function () { it('should do nothing if no ProviderApprovalController storage key', function (done) { const oldStorage = { - 'meta': {}, - 'data': { foo: 'bar' }, + meta: {}, + data: { foo: 'bar' }, } - migration40.migrate(oldStorage) + migration40 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { foo: 'bar' }) done() diff --git a/test/unit/migrations/041-test.js b/test/unit/migrations/041-test.js index 98ef4316d..7b95dfa3f 100644 --- a/test/unit/migrations/041-test.js +++ b/test/unit/migrations/041-test.js @@ -2,19 +2,19 @@ import assert from 'assert' import migration41 from '../../../app/scripts/migrations/041' describe('migration #41', function () { - it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 40, + meta: { + version: 40, }, - 'data': {}, + data: {}, } - migration41.migrate(oldStorage) + migration41 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 41, + version: 41, }) done() }) @@ -36,7 +36,8 @@ describe('migration #41', function () { }, } - migration41.migrate(oldStorage) + migration41 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { PreferencesController: { @@ -61,7 +62,8 @@ describe('migration #41', function () { }, } - migration41.migrate(oldStorage) + migration41 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { foo: 'bar', @@ -82,7 +84,8 @@ describe('migration #41', function () { }, } - migration41.migrate(oldStorage) + migration41 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { PreferencesController: { diff --git a/test/unit/migrations/042-test.js b/test/unit/migrations/042-test.js index 14a61d95e..0c2cbf01a 100644 --- a/test/unit/migrations/042-test.js +++ b/test/unit/migrations/042-test.js @@ -2,19 +2,19 @@ import assert from 'assert' import migration42 from '../../../app/scripts/migrations/042' describe('migration #42', function () { - it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 41, + meta: { + version: 41, }, - 'data': {}, + data: {}, } - migration42.migrate(oldStorage) + migration42 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 42, + version: 42, }) done() }) @@ -33,7 +33,8 @@ describe('migration #42', function () { }, } - migration42.migrate(oldStorage) + migration42 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { AppStateController: { @@ -55,7 +56,8 @@ describe('migration #42', function () { }, } - migration42.migrate(oldStorage) + migration42 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { foo: 'bar', diff --git a/test/unit/migrations/043-test.js b/test/unit/migrations/043-test.js index e8b2039e3..5a25e676c 100644 --- a/test/unit/migrations/043-test.js +++ b/test/unit/migrations/043-test.js @@ -2,18 +2,17 @@ import { strict as assert } from 'assert' import migration43 from '../../../app/scripts/migrations/043' describe('migration #43', function () { - it('should update the version metadata', async function () { const oldStorage = { - 'meta': { - 'version': 42, + meta: { + version: 42, }, - 'data': {}, + data: {}, } const newStorage = await migration43.migrate(oldStorage) assert.deepEqual(newStorage.meta, { - 'version': 43, + version: 43, }) }) diff --git a/test/unit/migrations/044-test.js b/test/unit/migrations/044-test.js index 08a609854..0fe8a9648 100644 --- a/test/unit/migrations/044-test.js +++ b/test/unit/migrations/044-test.js @@ -4,15 +4,15 @@ import migration44 from '../../../app/scripts/migrations/044' describe('migration #44', function () { it('should update the version metadata', async function () { const oldStorage = { - 'meta': { - 'version': 43, + meta: { + version: 43, }, - 'data': {}, + data: {}, } const newStorage = await migration44.migrate(oldStorage) assert.deepEqual(newStorage.meta, { - 'version': 44, + version: 44, }) }) diff --git a/test/unit/migrations/045-test.js b/test/unit/migrations/045-test.js index 650e06f38..6547203da 100644 --- a/test/unit/migrations/045-test.js +++ b/test/unit/migrations/045-test.js @@ -4,16 +4,17 @@ import migration45 from '../../../app/scripts/migrations/045' describe('migration #45', function () { it('should update the version metadata', function (done) { const oldStorage = { - 'meta': { - 'version': 44, + meta: { + version: 44, }, - 'data': {}, + data: {}, } - migration45.migrate(oldStorage) + migration45 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.meta, { - 'version': 45, + version: 45, }) done() }) @@ -32,7 +33,8 @@ describe('migration #45', function () { }, } - migration45.migrate(oldStorage) + migration45 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { PreferencesController: { @@ -58,7 +60,8 @@ describe('migration #45', function () { }, } - migration45.migrate(oldStorage) + migration45 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { PreferencesController: { @@ -80,7 +83,8 @@ describe('migration #45', function () { }, } - migration45.migrate(oldStorage) + migration45 + .migrate(oldStorage) .then((newStorage) => { assert.deepEqual(newStorage.data, { foo: 'bar', diff --git a/test/unit/migrations/046-test.js b/test/unit/migrations/046-test.js index ddb406c14..0c327eb8a 100644 --- a/test/unit/migrations/046-test.js +++ b/test/unit/migrations/046-test.js @@ -4,15 +4,15 @@ import migration46 from '../../../app/scripts/migrations/046' describe('migration #46', function () { it('should update the version metadata', async function () { const oldStorage = { - 'meta': { - 'version': 45, + meta: { + version: 45, }, - 'data': {}, + data: {}, } const newStorage = await migration46.migrate(oldStorage) assert.deepEqual(newStorage.meta, { - 'version': 46, + version: 46, }) }) diff --git a/test/unit/migrations/047-test.js b/test/unit/migrations/047-test.js index 4ee0e320a..bdaf66175 100644 --- a/test/unit/migrations/047-test.js +++ b/test/unit/migrations/047-test.js @@ -4,15 +4,15 @@ import migration47 from '../../../app/scripts/migrations/047' describe('migration #47', function () { it('should update the version metadata', async function () { const oldStorage = { - 'meta': { - 'version': 46, + meta: { + version: 46, }, - 'data': {}, + data: {}, } const newStorage = await migration47.migrate(oldStorage) assert.deepEqual(newStorage.meta, { - 'version': 47, + version: 47, }) }) diff --git a/test/unit/migrations/048-test.js b/test/unit/migrations/048-test.js index ec7f16181..bf96a0715 100644 --- a/test/unit/migrations/048-test.js +++ b/test/unit/migrations/048-test.js @@ -10,24 +10,26 @@ const localhostNetwork = { } const expectedPreferencesState = { PreferencesController: { - frequentRpcListDetail: [{ - ...localhostNetwork, - }], + frequentRpcListDetail: [ + { + ...localhostNetwork, + }, + ], }, } describe('migration #48', function () { it('should update the version metadata', async function () { const oldStorage = { - 'meta': { - 'version': 47, + meta: { + version: 47, }, - 'data': {}, + data: {}, } const newStorage = await migration48.migrate(oldStorage) assert.deepEqual(newStorage.meta, { - 'version': 48, + version: 48, }) }) @@ -252,9 +254,7 @@ describe('migration #48', function () { meta: {}, data: { PreferencesController: { - frequentRpcListDetail: [ - ...existingList, - ], + frequentRpcListDetail: [...existingList], }, foo: 'bar', }, @@ -263,10 +263,7 @@ describe('migration #48', function () { const newStorage = await migration48.migrate(oldStorage) assert.deepEqual(newStorage.data, { PreferencesController: { - frequentRpcListDetail: [ - { ...localhostNetwork }, - ...existingList, - ], + frequentRpcListDetail: [{ ...localhostNetwork }, ...existingList], }, foo: 'bar', }) @@ -355,20 +352,20 @@ describe('migration #48', function () { data: { AddressBookController: { addressBook: { - '1': { - 'address1': { + 1: { + address1: { chainId: '1', foo: 'bar', }, }, - '100': { - 'address1': { + 100: { + address1: { chainId: '100', foo: 'bar', }, }, '0x2': { - 'address2': { + address2: { chainId: '0x2', foo: 'bar', }, @@ -388,19 +385,19 @@ describe('migration #48', function () { AddressBookController: { addressBook: { '0x1': { - 'address1': { + address1: { chainId: '0x1', foo: 'bar', }, }, '0x64': { - 'address1': { + address1: { chainId: '0x64', foo: 'bar', }, }, '0x2': { - 'address2': { + address2: { chainId: '0x2', foo: 'bar', }, @@ -420,27 +417,27 @@ describe('migration #48', function () { data: { AddressBookController: { addressBook: { - '2': { - 'address1': { + 2: { + address1: { chainId: '2', key2: 'kaplar', key3: 'value3', key4: null, foo: 'bar', }, - 'address2': { + address2: { chainId: '2', foo: 'bar', }, }, '0x2': { - 'address1': { + address1: { chainId: '0x2', key1: 'value1', key2: 'value2', foo: 'bar', }, - 'address3': { + address3: { chainId: '0x2', foo: 'bar', }, @@ -460,7 +457,7 @@ describe('migration #48', function () { AddressBookController: { addressBook: { '0x2': { - 'address1': { + address1: { chainId: '0x2', key1: 'value1', key2: 'value2', @@ -468,11 +465,11 @@ describe('migration #48', function () { key4: '', foo: 'bar', }, - 'address2': { + address2: { chainId: '0x2', foo: 'bar', }, - 'address3': { + address3: { chainId: '0x2', foo: 'bar', }, @@ -493,7 +490,7 @@ describe('migration #48', function () { AddressBookController: { addressBook: { '0x1': { foo: { bar: 'baz' } }, - 'kaplar': { foo: { bar: 'baz' } }, + kaplar: { foo: { bar: 'baz' } }, }, bar: { baz: 'buzz', @@ -509,7 +506,7 @@ describe('migration #48', function () { AddressBookController: { addressBook: { '0x1': { foo: { bar: 'baz' } }, - 'kaplar': { foo: { bar: 'baz' } }, + kaplar: { foo: { bar: 'baz' } }, }, bar: { baz: 'buzz', @@ -626,9 +623,11 @@ describe('migration #48', function () { }, bar: 'baz', // from other migration - frequentRpcListDetail: [{ - ...localhostNetwork, - }], + frequentRpcListDetail: [ + { + ...localhostNetwork, + }, + ], }, foo: 'bar', }) diff --git a/test/unit/migrations/migrations-test.js b/test/unit/migrations/migrations-test.js index 29d941edb..a61376145 100644 --- a/test/unit/migrations/migrations-test.js +++ b/test/unit/migrations/migrations-test.js @@ -23,83 +23,230 @@ describe('wallet1 is migrated successfully', function () { it('should convert providers', function () { wallet1.data.config.provider = { type: 'etherscan', rpcTarget: null } - return migration2.migrate(wallet1) + return migration2 + .migrate(wallet1) .then((secondResult) => { const secondData = secondResult.data - assert.equal(secondData.config.provider.type, 'rpc', 'provider should be rpc') - assert.equal(secondData.config.provider.rpcTarget, 'https://rpc.metamask.io/', 'main provider should be our rpc') + assert.equal( + secondData.config.provider.type, + 'rpc', + 'provider should be rpc', + ) + assert.equal( + secondData.config.provider.rpcTarget, + 'https://rpc.metamask.io/', + 'main provider should be our rpc', + ) secondResult.data.config.provider.rpcTarget = oldTestRpc return migration3.migrate(secondResult) - }).then((thirdResult) => { - assert.equal(thirdResult.data.config.provider.rpcTarget, newTestRpc, 'config.provider.rpcTarget should be set to the proper testrpc url.') + }) + .then((thirdResult) => { + assert.equal( + thirdResult.data.config.provider.rpcTarget, + newTestRpc, + 'config.provider.rpcTarget should be set to the proper testrpc url.', + ) return migration4.migrate(thirdResult) - }).then((fourthResult) => { + }) + .then((fourthResult) => { const fourthData = fourthResult.data - assert.equal(fourthData.config.provider.rpcTarget, null, 'old rpcTarget should not exist.') - assert.equal(fourthData.config.provider.type, 'testnet', 'config.provider should be set to testnet.') + assert.equal( + fourthData.config.provider.rpcTarget, + null, + 'old rpcTarget should not exist.', + ) + assert.equal( + fourthData.config.provider.type, + 'testnet', + 'config.provider should be set to testnet.', + ) return migration5.migrate(vault4) - }).then((fifthResult) => { + }) + .then((fifthResult) => { const fifthData = fifthResult.data assert.equal(fifthData.vault, null, 'old vault should not exist') - assert.equal(fifthData.walletNicknames, null, 'old walletNicknames should not exist') - assert.equal(fifthData.config.selectedAccount, null, 'old config.selectedAccount should not exist') - assert.equal(fifthData.KeyringController.vault, vault4.data.vault, 'KeyringController.vault should exist') - assert.equal(fifthData.KeyringController.selectedAccount, vault4.data.config.selectedAccount, 'KeyringController.selectedAccount should have moved') - assert.equal(fifthData.KeyringController.walletNicknames['0x0beb674745816b125fbc07285d39fd373e64895c'], vault4.data.walletNicknames['0x0beb674745816b125fbc07285d39fd373e64895c'], 'KeyringController.walletNicknames should have moved') + assert.equal( + fifthData.walletNicknames, + null, + 'old walletNicknames should not exist', + ) + assert.equal( + fifthData.config.selectedAccount, + null, + 'old config.selectedAccount should not exist', + ) + assert.equal( + fifthData.KeyringController.vault, + vault4.data.vault, + 'KeyringController.vault should exist', + ) + assert.equal( + fifthData.KeyringController.selectedAccount, + vault4.data.config.selectedAccount, + 'KeyringController.selectedAccount should have moved', + ) + assert.equal( + fifthData.KeyringController.walletNicknames[ + '0x0beb674745816b125fbc07285d39fd373e64895c' + ], + vault4.data.walletNicknames[ + '0x0beb674745816b125fbc07285d39fd373e64895c' + ], + 'KeyringController.walletNicknames should have moved', + ) vault5 = fifthResult return migration6.migrate(fifthResult) - }).then((sixthResult) => { - assert.equal(sixthResult.data.KeyringController.selectedAccount, null, 'old selectedAccount should not exist') - assert.equal(sixthResult.data.PreferencesController.selectedAddress, vault5.data.KeyringController.selectedAccount, 'selectedAccount should have moved') + }) + .then((sixthResult) => { + assert.equal( + sixthResult.data.KeyringController.selectedAccount, + null, + 'old selectedAccount should not exist', + ) + assert.equal( + sixthResult.data.PreferencesController.selectedAddress, + vault5.data.KeyringController.selectedAccount, + 'selectedAccount should have moved', + ) vault6 = sixthResult return migration7.migrate(sixthResult) - }).then((seventhResult) => { - assert.equal(seventhResult.data.transactions, null, 'old transactions should not exist') - assert.equal(seventhResult.data.gasMultiplier, null, 'old gasMultiplier should not exist') - assert.equal(seventhResult.data.TransactionManager.transactions[0].id, vault6.data.transactions[0].id, 'transactions should have moved') - assert.equal(seventhResult.data.TransactionManager.gasMultiplier, vault6.data.gasMultiplier, 'gasMultiplier should have moved') + }) + .then((seventhResult) => { + assert.equal( + seventhResult.data.transactions, + null, + 'old transactions should not exist', + ) + assert.equal( + seventhResult.data.gasMultiplier, + null, + 'old gasMultiplier should not exist', + ) + assert.equal( + seventhResult.data.TransactionManager.transactions[0].id, + vault6.data.transactions[0].id, + 'transactions should have moved', + ) + assert.equal( + seventhResult.data.TransactionManager.gasMultiplier, + vault6.data.gasMultiplier, + 'gasMultiplier should have moved', + ) vault7 = seventhResult return migration8.migrate(seventhResult) - }).then((eighthResult) => { - assert.equal(eighthResult.data.noticesList, null, 'old noticesList should not exist') - assert.equal(eighthResult.data.NoticeController.noticesList[0].title, vault7.data.noticesList[0].title, 'noticesList should have moved') + }) + .then((eighthResult) => { + assert.equal( + eighthResult.data.noticesList, + null, + 'old noticesList should not exist', + ) + assert.equal( + eighthResult.data.NoticeController.noticesList[0].title, + vault7.data.noticesList[0].title, + 'noticesList should have moved', + ) vault8 = eighthResult return migration9.migrate(eighthResult) - }).then((ninthResult) => { - assert.equal(ninthResult.data.currentFiat, null, 'old currentFiat should not exist') - assert.equal(ninthResult.data.fiatCurrency, null, 'old fiatCurrency should not exist') - assert.equal(ninthResult.data.conversionRate, null, 'old conversionRate should not exist') - assert.equal(ninthResult.data.conversionDate, null, 'old conversionDate should not exist') + }) + .then((ninthResult) => { + assert.equal( + ninthResult.data.currentFiat, + null, + 'old currentFiat should not exist', + ) + assert.equal( + ninthResult.data.fiatCurrency, + null, + 'old fiatCurrency should not exist', + ) + assert.equal( + ninthResult.data.conversionRate, + null, + 'old conversionRate should not exist', + ) + assert.equal( + ninthResult.data.conversionDate, + null, + 'old conversionDate should not exist', + ) - assert.equal(ninthResult.data.CurrencyController.currentCurrency, vault8.data.fiatCurrency, 'currentFiat should have moved') - assert.equal(ninthResult.data.CurrencyController.conversionRate, vault8.data.conversionRate, 'conversionRate should have moved') - assert.equal(ninthResult.data.CurrencyController.conversionDate, vault8.data.conversionDate, 'conversionDate should have moved') + assert.equal( + ninthResult.data.CurrencyController.currentCurrency, + vault8.data.fiatCurrency, + 'currentFiat should have moved', + ) + assert.equal( + ninthResult.data.CurrencyController.conversionRate, + vault8.data.conversionRate, + 'conversionRate should have moved', + ) + assert.equal( + ninthResult.data.CurrencyController.conversionDate, + vault8.data.conversionDate, + 'conversionDate should have moved', + ) vault9 = ninthResult return migration10.migrate(ninthResult) - }).then((tenthResult) => { - assert.equal(tenthResult.data.shapeShiftTxList, null, 'old shapeShiftTxList should not exist') - assert.equal(tenthResult.data.ShapeShiftController.shapeShiftTxList[0].transaction, vault9.data.shapeShiftTxList[0].transaction) + }) + .then((tenthResult) => { + assert.equal( + tenthResult.data.shapeShiftTxList, + null, + 'old shapeShiftTxList should not exist', + ) + assert.equal( + tenthResult.data.ShapeShiftController.shapeShiftTxList[0].transaction, + vault9.data.shapeShiftTxList[0].transaction, + ) return migration11.migrate(tenthResult) - }).then((eleventhResult) => { - assert.equal(eleventhResult.data.isDisclaimerConfirmed, null, 'isDisclaimerConfirmed should not exist') - assert.equal(eleventhResult.data.TOSHash, null, 'TOSHash should not exist') + }) + .then((eleventhResult) => { + assert.equal( + eleventhResult.data.isDisclaimerConfirmed, + null, + 'isDisclaimerConfirmed should not exist', + ) + assert.equal( + eleventhResult.data.TOSHash, + null, + 'TOSHash should not exist', + ) return migration12.migrate(eleventhResult) - }).then((twelfthResult) => { - assert.equal(twelfthResult.data.NoticeController.noticesList[0].body, '', 'notices that have been read should have an empty body.') - assert.equal(twelfthResult.data.NoticeController.noticesList[1].body, 'nonempty', 'notices that have not been read should not have an empty body.') + }) + .then((twelfthResult) => { + assert.equal( + twelfthResult.data.NoticeController.noticesList[0].body, + '', + 'notices that have been read should have an empty body.', + ) + assert.equal( + twelfthResult.data.NoticeController.noticesList[1].body, + 'nonempty', + 'notices that have not been read should not have an empty body.', + ) - assert.equal(twelfthResult.data.config.provider.type, 'testnet', 'network is originally testnet.') + assert.equal( + twelfthResult.data.config.provider.type, + 'testnet', + 'network is originally testnet.', + ) return migration13.migrate(twelfthResult) - }).then((thirteenthResult) => { - assert.equal(thirteenthResult.data.config.provider.type, 'ropsten', 'network has been changed to ropsten.') + }) + .then((thirteenthResult) => { + assert.equal( + thirteenthResult.data.config.provider.type, + 'ropsten', + 'network has been changed to ropsten.', + ) }) }) }) diff --git a/test/unit/migrations/migrator-test.js b/test/unit/migrations/migrator-test.js index 87468d917..7c5001596 100644 --- a/test/unit/migrations/migrator-test.js +++ b/test/unit/migrations/migrator-test.js @@ -41,7 +41,6 @@ const firstTimeState = { describe('migrations', function () { describe('liveMigrations require list', function () { - let migrationNumbers before(function () { @@ -49,7 +48,7 @@ describe('migrations', function () { migrationNumbers = fileNames .reduce((acc, filename) => { const name = filename.split('.')[0] - if ((/^\d+$/u).test(name)) { + if (/^\d+$/u.test(name)) { acc.push(name) } return acc @@ -60,7 +59,10 @@ describe('migrations', function () { it('should include all migrations', function () { migrationNumbers.forEach((num) => { const migration = liveMigrations.find((m) => m.version === num) - assert(migration, `migration not included in 'migrations/index.js': ${num}`) + assert( + migration, + `migration not included in 'migrations/index.js': ${num}`, + ) }) }) @@ -69,7 +71,7 @@ describe('migrations', function () { const testNumbers = fileNames .reduce((acc, filename) => { const name = filename.split('-test.')[0] - if ((/^\d+$/u).test(name)) { + if (/^\d+$/u.test(name)) { acc.push(name) } return acc @@ -78,7 +80,10 @@ describe('migrations', function () { migrationNumbers.forEach((num) => { if (num >= 33) { - assert.ok(testNumbers.includes(num), `no test found for migration: ${num}`) + assert.ok( + testNumbers.includes(num), + `no test found for migration: ${num}`, + ) } }) }) @@ -100,12 +105,14 @@ describe('migrations', function () { it('should emit an error', async function () { const migrator = new Migrator({ - migrations: [{ - version: 1, - async migrate () { - throw new Error('test') + migrations: [ + { + version: 1, + async migrate() { + throw new Error('test') + }, }, - }], + ], }) await assert.rejects(migrator.migrateData({ meta: { version: 0 } })) }) diff --git a/test/unit/migrations/template-test.js b/test/unit/migrations/template-test.js index e08ddf287..ca74b30f0 100644 --- a/test/unit/migrations/template-test.js +++ b/test/unit/migrations/template-test.js @@ -8,10 +8,12 @@ const storage = { describe('storage is migrated successfully', function () { it('should work', function (done) { - migrationTemplate.migrate(storage) + migrationTemplate + .migrate(storage) .then((migratedData) => { assert.equal(migratedData.meta.version, 0) done() - }).catch(done) + }) + .catch(done) }) }) diff --git a/test/unit/responsive/components/dropdown-test.js b/test/unit/responsive/components/dropdown-test.js index eff359a1f..fc550a6fd 100644 --- a/test/unit/responsive/components/dropdown-test.js +++ b/test/unit/responsive/components/dropdown-test.js @@ -7,7 +7,6 @@ import { renderWithProvider } from '../../../lib/render-helpers' import { Dropdown } from '../../../../ui/app/components/app/dropdowns/components/dropdown' describe('Dropdown components', function () { - const mockState = { metamask: {}, } @@ -33,7 +32,8 @@ describe('Dropdown components', function () {
  • Item 1
  • Item 2
  • -
    , store, + , + store, ) const item1 = getByText(/Item 1/u) @@ -41,5 +41,4 @@ describe('Dropdown components', function () { assert.ok(onClickSpy.calledOnce) }) - }) diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js index ff8d74155..2890e258d 100644 --- a/test/unit/ui/app/actions.spec.js +++ b/test/unit/ui/app/actions.spec.js @@ -25,19 +25,19 @@ const extensionMock = { } describe('Actions', function () { - const noop = () => undefined const currentNetworkId = '42' let background, metamaskController - const TEST_SEED = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + const TEST_SEED = + 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' const password = 'a-fake-password' - const importPrivkey = '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' + const importPrivkey = + '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' beforeEach(async function () { - metamaskController = new MetaMaskController({ extension: extensionMock, platform: { getVersion: () => 'foo' }, @@ -46,11 +46,11 @@ describe('Actions', function () { showUnapprovedTx: noop, showUnconfirmedMessage: noop, encryptor: { - encrypt (_, object) { + encrypt(_, object) { this.object = object return Promise.resolve('mock-encrypted') }, - decrypt () { + decrypt() { return Promise.resolve(this.object) }, }, @@ -65,7 +65,9 @@ describe('Actions', function () { await metamaskController.createNewVaultAndRestore(password, TEST_SEED) - await metamaskController.importAccountWithStrategy('Private Key', [importPrivkey]) + await metamaskController.importAccountWithStrategy('Private Key', [ + importPrivkey, + ]) background = metamaskController.getApi() @@ -75,7 +77,6 @@ describe('Actions', function () { }) describe('#tryUnlockMetamask', function () { - let submitPasswordSpy, verifySeedPhraseSpy afterEach(function () { @@ -84,7 +85,6 @@ describe('Actions', function () { }) it('calls submitPassword and verifySeedPhrase', async function () { - const store = mockStore() submitPasswordSpy = sinon.spy(background, 'submitPassword') @@ -96,7 +96,6 @@ describe('Actions', function () { }) it('errors on submitPassword will fail', async function () { - const store = mockStore() const expectedActions = [ @@ -135,8 +134,12 @@ describe('Actions', function () { assert.fail('Should have thrown error') } catch (_) { const actions1 = store.getActions() - const warning = actions1.filter((action) => action.type === 'DISPLAY_WARNING') - const unlockFailed = actions1.filter((action) => action.type === 'UNLOCK_FAILED') + const warning = actions1.filter( + (action) => action.type === 'DISPLAY_WARNING', + ) + const unlockFailed = actions1.filter( + (action) => action.type === 'UNLOCK_FAILED', + ) assert.deepEqual(warning, displayWarningError) assert.deepEqual(unlockFailed, unlockFailedError) } @@ -144,7 +147,6 @@ describe('Actions', function () { }) describe('#createNewVaultAndRestore', function () { - let createNewVaultAndRestoreSpy afterEach(function () { @@ -152,10 +154,12 @@ describe('Actions', function () { }) it('restores new vault', async function () { - const store = mockStore() - createNewVaultAndRestoreSpy = sinon.spy(background, 'createNewVaultAndRestore') + createNewVaultAndRestoreSpy = sinon.spy( + background, + 'createNewVaultAndRestore', + ) try { await store.dispatch(actions.createNewVaultAndRestore()) @@ -174,7 +178,10 @@ describe('Actions', function () { { type: 'HIDE_LOADING_INDICATION' }, ] - createNewVaultAndRestoreSpy = sinon.stub(background, 'createNewVaultAndRestore') + createNewVaultAndRestoreSpy = sinon.stub( + background, + 'createNewVaultAndRestore', + ) createNewVaultAndRestoreSpy.callsFake((_, __, callback) => { callback(new Error('error')) @@ -225,7 +232,6 @@ describe('Actions', function () { } catch (_) { assert.deepEqual(store.getActions(), expectedActions) } - }) }) @@ -250,11 +256,11 @@ describe('Actions', function () { removeAccountStub = sinon.stub(background, 'removeAccount') removeAccountStub.callsFake((_, callback) => callback()) - await store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc')) + await store.dispatch( + actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'), + ) assert(removeAccountStub.calledOnce) - const actionTypes = store - .getActions() - .map((action) => action.type) + const actionTypes = store.getActions().map((action) => action.type) assert.deepEqual(actionTypes, expectedActions) }) @@ -273,20 +279,18 @@ describe('Actions', function () { }) try { - await store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc')) + await store.dispatch( + actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'), + ) assert.fail('Should have thrown error') } catch (_) { - const actionTypes = store - .getActions() - .map((action) => action.type) + const actionTypes = store.getActions().map((action) => action.type) assert.deepEqual(actionTypes, expectedActions) } - }) }) describe('#resetAccount', function () { - let resetAccountSpy afterEach(function () { @@ -294,7 +298,6 @@ describe('Actions', function () { }) it('resets account', async function () { - const store = mockStore() const expectedActions = [ @@ -334,7 +337,6 @@ describe('Actions', function () { }) describe('#importNewAccount', function () { - let importAccountWithStrategySpy afterEach(function () { @@ -344,11 +346,16 @@ describe('Actions', function () { it('calls importAccountWithStrategies in background', async function () { const store = mockStore() - importAccountWithStrategySpy = sinon.spy(background, 'importAccountWithStrategy') + importAccountWithStrategySpy = sinon.spy( + background, + 'importAccountWithStrategy', + ) - await store.dispatch(actions.importNewAccount('Private Key', [ - 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3', - ])) + await store.dispatch( + actions.importNewAccount('Private Key', [ + 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3', + ]), + ) assert(importAccountWithStrategySpy.calledOnce) }) @@ -356,12 +363,18 @@ describe('Actions', function () { const store = mockStore() const expectedActions = [ - { type: 'SHOW_LOADING_INDICATION', value: 'This may take a while, please be patient.' }, + { + type: 'SHOW_LOADING_INDICATION', + value: 'This may take a while, please be patient.', + }, { type: 'HIDE_LOADING_INDICATION' }, { type: 'DISPLAY_WARNING', value: 'error' }, ] - importAccountWithStrategySpy = sinon.stub(background, 'importAccountWithStrategy') + importAccountWithStrategySpy = sinon.stub( + background, + 'importAccountWithStrategy', + ) importAccountWithStrategySpy.callsFake((_, __, callback) => { callback(new Error('error')) }) @@ -376,7 +389,6 @@ describe('Actions', function () { }) describe('#addNewAccount', function () { - it('Adds a new account', async function () { const store = mockStore({ metamask: { identities: {} } }) @@ -385,11 +397,9 @@ describe('Actions', function () { await store.dispatch(actions.addNewAccount()) assert(addNewAccountSpy.calledOnce) }) - }) describe('#checkHardwareStatus', function () { - let checkHardwareStatusSpy afterEach(function () { @@ -397,16 +407,20 @@ describe('Actions', function () { }) it('calls checkHardwareStatus in background', async function () { - checkHardwareStatusSpy = sinon.stub(background, 'checkHardwareStatus') + checkHardwareStatusSpy = sinon + .stub(background, 'checkHardwareStatus') .callsArgWith(2, null) const store = mockStore() - await store.dispatch(actions.checkHardwareStatus('ledger', `m/44'/60'/0'/0`)) + await store.dispatch( + actions.checkHardwareStatus('ledger', `m/44'/60'/0'/0`), + ) assert.equal(checkHardwareStatusSpy.calledOnce, true) }) it('shows loading indicator and displays error', async function () { - checkHardwareStatusSpy = sinon.stub(background, 'checkHardwareStatus') + checkHardwareStatusSpy = sinon + .stub(background, 'checkHardwareStatus') .callsArgWith(2, new Error('error')) const store = mockStore() @@ -425,7 +439,6 @@ describe('Actions', function () { }) describe('#forgetDevice', function () { - let forgetDeviceSpy afterEach(function () { @@ -433,17 +446,18 @@ describe('Actions', function () { }) it('calls forgetDevice in background', async function () { - forgetDeviceSpy = sinon.stub(background, 'forgetDevice') + forgetDeviceSpy = sinon + .stub(background, 'forgetDevice') .callsArgWith(1, null) const store = mockStore() await store.dispatch(actions.forgetDevice('ledger')) assert.equal(forgetDeviceSpy.calledOnce, true) - }) it('shows loading indicator and displays error', async function () { - forgetDeviceSpy = sinon.stub(background, 'forgetDevice') + forgetDeviceSpy = sinon + .stub(background, 'forgetDevice') .callsArgWith(1, new Error('error')) const store = mockStore() @@ -462,7 +476,6 @@ describe('Actions', function () { }) describe('#connectHardware', function () { - let connectHardwareSpy afterEach(function () { @@ -470,22 +483,28 @@ describe('Actions', function () { }) it('calls connectHardware in background', async function () { - connectHardwareSpy = sinon.stub(background, 'connectHardware') + connectHardwareSpy = sinon + .stub(background, 'connectHardware') .callsArgWith(3, null) const store = mockStore() - await store.dispatch(actions.connectHardware('ledger', 0, `m/44'/60'/0'/0`)) + await store.dispatch( + actions.connectHardware('ledger', 0, `m/44'/60'/0'/0`), + ) assert.equal(connectHardwareSpy.calledOnce, true) - }) it('shows loading indicator and displays error', async function () { - connectHardwareSpy = sinon.stub(background, 'connectHardware') + connectHardwareSpy = sinon + .stub(background, 'connectHardware') .callsArgWith(3, new Error('error')) const store = mockStore() const expectedActions = [ - { type: 'SHOW_LOADING_INDICATION', value: 'Looking for your Ledger...' }, + { + type: 'SHOW_LOADING_INDICATION', + value: 'Looking for your Ledger...', + }, { type: 'DISPLAY_WARNING', value: 'error' }, ] @@ -499,7 +518,6 @@ describe('Actions', function () { }) describe('#unlockHardwareWalletAccount', function () { - let unlockHardwareWalletAccountSpy afterEach(function () { @@ -507,17 +525,20 @@ describe('Actions', function () { }) it('calls unlockHardwareWalletAccount in background', async function () { - unlockHardwareWalletAccountSpy = sinon.stub(background, 'unlockHardwareWalletAccount') + unlockHardwareWalletAccountSpy = sinon + .stub(background, 'unlockHardwareWalletAccount') .callsArgWith(3, null) const store = mockStore() - await store.dispatch(actions.unlockHardwareWalletAccount('ledger', 0, `m/44'/60'/0'/0`)) + await store.dispatch( + actions.unlockHardwareWalletAccount('ledger', 0, `m/44'/60'/0'/0`), + ) assert.equal(unlockHardwareWalletAccountSpy.calledOnce, true) - }) it('shows loading indicator and displays error', async function () { - unlockHardwareWalletAccountSpy = sinon.stub(background, 'unlockHardwareWalletAccount') + unlockHardwareWalletAccountSpy = sinon + .stub(background, 'unlockHardwareWalletAccount') .callsArgWith(3, new Error('error')) const store = mockStore() @@ -536,7 +557,6 @@ describe('Actions', function () { }) describe('#setCurrentCurrency', function () { - let setCurrentCurrencySpy afterEach(function () { @@ -544,7 +564,8 @@ describe('Actions', function () { }) it('calls setCurrentCurrency', async function () { - setCurrentCurrencySpy = sinon.stub(background, 'setCurrentCurrency') + setCurrentCurrencySpy = sinon + .stub(background, 'setCurrentCurrency') .callsArgWith(1, null, {}) const store = mockStore() @@ -553,7 +574,8 @@ describe('Actions', function () { }) it('throws if setCurrentCurrency throws', async function () { - setCurrentCurrencySpy = sinon.stub(background, 'setCurrentCurrency') + setCurrentCurrencySpy = sinon + .stub(background, 'setCurrentCurrency') .callsArgWith(1, new Error('error')) const store = mockStore() const expectedActions = [ @@ -568,12 +590,12 @@ describe('Actions', function () { }) describe('#signMsg', function () { - let signMessageSpy, metamaskMsgs, msgId, messages const msgParams = { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0', + data: + '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0', } beforeEach(function () { @@ -594,7 +616,6 @@ describe('Actions', function () { signMessageSpy = sinon.spy(background, 'signMessage') await store.dispatch(actions.signMsg(msgParams)) assert(signMessageSpy.calledOnce) - }) it('errors when signMessage in background throws', async function () { @@ -617,16 +638,15 @@ describe('Actions', function () { assert.deepEqual(store.getActions(), expectedActions) } }) - }) describe('#signPersonalMsg', function () { - let signPersonalMessageSpy, metamaskMsgs, msgId, personalMessages const msgParams = { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0', + data: + '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0', } beforeEach(function () { @@ -648,7 +668,6 @@ describe('Actions', function () { await store.dispatch(actions.signPersonalMsg(msgParams)) assert(signPersonalMessageSpy.calledOnce) - }) it('throws if signPersonalMessage throws', async function () { @@ -671,7 +690,6 @@ describe('Actions', function () { assert.deepEqual(store.getActions(), expectedActions) } }) - }) describe('#signTypedMsg', function () { @@ -680,39 +698,39 @@ describe('Actions', function () { const msgParamsV3 = { from: '0x0DCD5D886577d5081B0c52e242Ef29E70Be3E7bc', data: JSON.stringify({ - 'types': { - 'EIP712Domain': [ - { 'name': 'name', 'type': 'string' }, - { 'name': 'version', 'type': 'string' }, - { 'name': 'chainId', 'type': 'uint256' }, - { 'name': 'verifyingContract', 'type': 'address' }, + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, ], - 'Person': [ - { 'name': 'name', 'type': 'string' }, - { 'name': 'wallet', 'type': 'address' }, + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, ], - 'Mail': [ - { 'name': 'from', 'type': 'Person' }, - { 'name': 'to', 'type': 'Person' }, - { 'name': 'contents', 'type': 'string' }, + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, ], }, - 'primaryType': 'Mail', - 'domain': { - 'name': 'Ether Mainl', - 'version': '1', - 'verifyingContract': '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + primaryType: 'Mail', + domain: { + name: 'Ether Mainl', + version: '1', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', }, - 'message': { - 'from': { - 'name': 'Cow', - 'wallet': '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', }, - 'to': { - 'name': 'Bob', - 'wallet': '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', }, - 'contents': 'Hello, Bob!', + contents: 'Hello, Bob!', }, }), } @@ -730,7 +748,8 @@ describe('Actions', function () { }) it('calls signTypedMsg in background with no error', async function () { - signTypedMsgSpy = sinon.stub(background, 'signTypedMessage') + signTypedMsgSpy = sinon + .stub(background, 'signTypedMessage') .callsArgWith(1, null, defaultState) const store = mockStore() @@ -739,7 +758,8 @@ describe('Actions', function () { }) it('returns expected actions with error', async function () { - signTypedMsgSpy = sinon.stub(background, 'signTypedMessage') + signTypedMsgSpy = sinon + .stub(background, 'signTypedMessage') .callsArgWith(1, new Error('error')) const store = mockStore() const expectedActions = [ @@ -755,11 +775,9 @@ describe('Actions', function () { assert.deepEqual(store.getActions(), expectedActions) } }) - }) describe('#signTx', function () { - let sendTransactionSpy beforeEach(function () { @@ -798,7 +816,10 @@ describe('Actions', function () { const expectedActions = [ { type: 'GAS_LOADING_STARTED' }, - { type: 'UPDATE_SEND_ERRORS', value: { gasLoadingError: 'gasLoadingError' } }, + { + type: 'UPDATE_SEND_ERRORS', + value: { gasLoadingError: 'gasLoadingError' }, + }, { type: 'GAS_LOADING_FINISHED' }, ] @@ -858,18 +879,22 @@ describe('Actions', function () { }) describe('#updateTransaction', function () { - let updateTransactionSpy const txParams = { - 'from': '0x1', - 'gas': '0x5208', - 'gasPrice': '0x3b9aca00', - 'to': '0x2', - 'value': '0x0', + from: '0x1', + gas: '0x5208', + gasPrice: '0x3b9aca00', + to: '0x2', + value: '0x0', } - const txData = { id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams } + const txData = { + id: '1', + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams, + } beforeEach(async function () { await metamaskController.txController.txStateManager.addTx(txData) @@ -888,7 +913,11 @@ describe('Actions', function () { const resultantActions = store.getActions() assert.ok(updateTransactionSpy.calledOnce) - assert.deepEqual(resultantActions[1], { type: 'UPDATE_TRANSACTION_PARAMS', id: txData.id, value: txParams }) + assert.deepEqual(resultantActions[1], { + type: 'UPDATE_TRANSACTION_PARAMS', + id: txData.id, + value: txParams, + }) }) it('rejects with error message', async function () { @@ -944,7 +973,6 @@ describe('Actions', function () { } catch (error) { assert.deepEqual(store.getActions(), expectedActions) } - }) }) @@ -956,16 +984,22 @@ describe('Actions', function () { }) it('calls setSelectedAddress in background', async function () { - setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress') + setSelectedAddressSpy = sinon + .stub(background, 'setSelectedAddress') .callsArgWith(1, null) const store = mockStore() - await store.dispatch(actions.setSelectedAddress('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc')) + await store.dispatch( + actions.setSelectedAddress( + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + ), + ) assert(setSelectedAddressSpy.calledOnce) }) it('errors when setSelectedAddress throws', async function () { - setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress') + setSelectedAddressSpy = sinon + .stub(background, 'setSelectedAddress') .callsArgWith(1, new Error('error')) const store = mockStore() const expectedActions = [ @@ -976,7 +1010,6 @@ describe('Actions', function () { await store.dispatch(actions.setSelectedAddress()) assert.deepEqual(store.getActions(), expectedActions) - }) }) @@ -988,18 +1021,26 @@ describe('Actions', function () { }) it('#showAccountDetail', async function () { - setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress') + setSelectedAddressSpy = sinon + .stub(background, 'setSelectedAddress') .callsArgWith(1, null) - const store = mockStore({ activeTab: {}, metamask: { alertEnabledness: {}, selectedAddress: '0x123' } }) + const store = mockStore({ + activeTab: {}, + metamask: { alertEnabledness: {}, selectedAddress: '0x123' }, + }) await store.dispatch(actions.showAccountDetail()) assert(setSelectedAddressSpy.calledOnce) }) it('displays warning if setSelectedAddress throws', async function () { - setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress') + setSelectedAddressSpy = sinon + .stub(background, 'setSelectedAddress') .callsArgWith(1, new Error('error')) - const store = mockStore({ activeTab: {}, metamask: { alertEnabledness: {}, selectedAddress: '0x123' } }) + const store = mockStore({ + activeTab: {}, + metamask: { alertEnabledness: {}, selectedAddress: '0x123' }, + }) const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -1019,8 +1060,7 @@ describe('Actions', function () { }) it('calls addToken in background', async function () { - addTokenSpy = sinon.stub(background, 'addToken') - .callsArgWith(4, null) + addTokenSpy = sinon.stub(background, 'addToken').callsArgWith(4, null) const store = mockStore() await store.dispatch(actions.addToken()) @@ -1028,7 +1068,8 @@ describe('Actions', function () { }) it('errors when addToken in background throws', async function () { - addTokenSpy = sinon.stub(background, 'addToken') + addTokenSpy = sinon + .stub(background, 'addToken') .callsArgWith(4, new Error('error')) const store = mockStore() const expectedActions = [ @@ -1047,7 +1088,6 @@ describe('Actions', function () { }) describe('#removeToken', function () { - let removeTokenSpy afterEach(function () { @@ -1055,7 +1095,8 @@ describe('Actions', function () { }) it('calls removeToken in background', async function () { - removeTokenSpy = sinon.stub(background, 'removeToken') + removeTokenSpy = sinon + .stub(background, 'removeToken') .callsArgWith(1, null) const store = mockStore() await store.dispatch(actions.removeToken()) @@ -1063,7 +1104,8 @@ describe('Actions', function () { }) it('errors when removeToken in background fails', async function () { - removeTokenSpy = sinon.stub(background, 'removeToken') + removeTokenSpy = sinon + .stub(background, 'removeToken') .callsArgWith(1, new Error('error')) const store = mockStore() const expectedActions = [ @@ -1094,14 +1136,16 @@ describe('Actions', function () { }) it('calls setProviderType', async function () { - setProviderTypeSpy = sinon.stub(background, 'setProviderType') + setProviderTypeSpy = sinon + .stub(background, 'setProviderType') .callsArgWith(1, null) await store.dispatch(actions.setProviderType()) assert(setProviderTypeSpy.calledOnce) }) it('displays warning when setProviderType throws', async function () { - setProviderTypeSpy = sinon.stub(background, 'setProviderType') + setProviderTypeSpy = sinon + .stub(background, 'setProviderType') .callsArgWith(1, new Error('error')) const expectedActions = [ { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' }, @@ -1121,7 +1165,8 @@ describe('Actions', function () { }) it('calls setRpcTarget', async function () { - setRpcTargetSpy = sinon.stub(background, 'setCustomRpc') + setRpcTargetSpy = sinon + .stub(background, 'setCustomRpc') .callsArgWith(4, null) const store = mockStore() await store.dispatch(actions.setRpcTarget('http://localhost:8545')) @@ -1129,7 +1174,8 @@ describe('Actions', function () { }) it('displays warning when setRpcTarget throws', async function () { - setRpcTargetSpy = sinon.stub(background, 'setCustomRpc') + setRpcTargetSpy = sinon + .stub(background, 'setCustomRpc') .callsArgWith(4, new Error('error')) const store = mockStore() const expectedActions = [ @@ -1143,7 +1189,8 @@ describe('Actions', function () { describe('#addToAddressBook', function () { it('calls setAddressBook', async function () { - const addToAddressBookSpy = sinon.stub(background, 'setAddressBook') + const addToAddressBookSpy = sinon + .stub(background, 'setAddressBook') .callsArgWith(4, null, true) const store = mockStore() await store.dispatch(actions.addToAddressBook('test')) @@ -1165,13 +1212,22 @@ describe('Actions', function () { const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, - { type: 'SHOW_PRIVATE_KEY', value: '7ec73b91bb20f209a7ff2d32f542c3420b4fccf14abcc7840d2eff0ebcb18505' }, + { + type: 'SHOW_PRIVATE_KEY', + value: + '7ec73b91bb20f209a7ff2d32f542c3420b4fccf14abcc7840d2eff0ebcb18505', + }, ] verifyPasswordSpy = sinon.spy(background, 'verifyPassword') exportAccountSpy = sinon.spy(background, 'exportAccount') - await store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc')) + await store.dispatch( + actions.exportAccount( + password, + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + ), + ) assert(verifyPasswordSpy.calledOnce) assert(exportAccountSpy.calledOnce) assert.deepEqual(store.getActions(), expectedActions) @@ -1191,7 +1247,12 @@ describe('Actions', function () { }) try { - await store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc')) + await store.dispatch( + actions.exportAccount( + password, + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + ), + ) assert.fail('Should have thrown error') } catch (_) { assert.deepEqual(store.getActions(), expectedActions) @@ -1203,7 +1264,10 @@ describe('Actions', function () { const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, - { type: 'DISPLAY_WARNING', value: 'Had a problem exporting the account.' }, + { + type: 'DISPLAY_WARNING', + value: 'Had a problem exporting the account.', + }, ] exportAccountSpy = sinon.stub(background, 'exportAccount') @@ -1212,7 +1276,12 @@ describe('Actions', function () { }) try { - await store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc')) + await store.dispatch( + actions.exportAccount( + password, + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + ), + ) assert.fail('Should have thrown error') } catch (_) { assert.deepEqual(store.getActions(), expectedActions) @@ -1222,10 +1291,16 @@ describe('Actions', function () { describe('#setAccountLabel', function () { it('calls setAccountLabel', async function () { - const setAccountLabelSpy = sinon.stub(background, 'setAccountLabel') + const setAccountLabelSpy = sinon + .stub(background, 'setAccountLabel') .callsArgWith(2, null) const store = mockStore() - await store.dispatch(actions.setAccountLabel('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', 'test')) + await store.dispatch( + actions.setAccountLabel( + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + 'test', + ), + ) assert(setAccountLabelSpy.calledOnce) }) }) @@ -1238,7 +1313,8 @@ describe('Actions', function () { }) it('calls setFeatureFlag in the background', async function () { - setFeatureFlagSpy = sinon.stub(background, 'setFeatureFlag') + setFeatureFlagSpy = sinon + .stub(background, 'setFeatureFlag') .callsArgWith(2, null) const store = mockStore() @@ -1247,7 +1323,8 @@ describe('Actions', function () { }) it('errors when setFeatureFlag in background throws', async function () { - setFeatureFlagSpy = sinon.stub(background, 'setFeatureFlag') + setFeatureFlagSpy = sinon + .stub(background, 'setFeatureFlag') .callsArgWith(2, new Error('error')) const store = mockStore() const expectedActions = [ @@ -1316,10 +1393,9 @@ describe('Actions', function () { let setCurrentLocaleSpy beforeEach(function () { - sinon.stub(window, 'fetch') - .resolves({ - json: async () => enLocale, - }) + sinon.stub(window, 'fetch').resolves({ + json: async () => enLocale, + }) }) afterEach(function () { @@ -1333,7 +1409,10 @@ describe('Actions', function () { const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, - { type: 'SET_CURRENT_LOCALE', value: { locale: 'en', messages: enLocale } }, + { + type: 'SET_CURRENT_LOCALE', + value: { locale: 'en', messages: enLocale }, + }, { type: 'HIDE_LOADING_INDICATION' }, ] @@ -1360,19 +1439,23 @@ describe('Actions', function () { } catch (_) { assert.deepEqual(store.getActions(), expectedActions) } - }) }) describe('#markPasswordForgotten', function () { it('calls markPasswordForgotten', async function () { const store = mockStore() - const markPasswordForgottenSpy = sinon.stub(background, 'markPasswordForgotten').callsArg(0) + const markPasswordForgottenSpy = sinon + .stub(background, 'markPasswordForgotten') + .callsArg(0) await store.dispatch(actions.markPasswordForgotten()) const resultantActions = store.getActions() - assert.deepEqual(resultantActions[1], { type: 'FORGOT_PASSWORD', value: true }) + assert.deepEqual(resultantActions[1], { + type: 'FORGOT_PASSWORD', + value: true, + }) assert.ok(markPasswordForgottenSpy.calledOnce) markPasswordForgottenSpy.restore() }) @@ -1381,12 +1464,17 @@ describe('Actions', function () { describe('#unMarkPasswordForgotten', function () { it('calls unMarkPasswordForgotten', async function () { const store = mockStore() - const unMarkPasswordForgottenSpy = sinon.stub(background, 'unMarkPasswordForgotten').callsArg(0) + const unMarkPasswordForgottenSpy = sinon + .stub(background, 'unMarkPasswordForgotten') + .callsArg(0) await store.dispatch(actions.unMarkPasswordForgotten()) const resultantActions = store.getActions() - assert.deepEqual(resultantActions[0], { type: 'FORGOT_PASSWORD', value: false }) + assert.deepEqual(resultantActions[0], { + type: 'FORGOT_PASSWORD', + value: false, + }) assert.ok(unMarkPasswordForgottenSpy.calledOnce) unMarkPasswordForgottenSpy.restore() }) diff --git a/test/unit/ui/app/reducers/app.spec.js b/test/unit/ui/app/reducers/app.spec.js index 7ba811cc3..3cf350b7f 100644 --- a/test/unit/ui/app/reducers/app.spec.js +++ b/test/unit/ui/app/reducers/app.spec.js @@ -5,7 +5,6 @@ import * as actionConstants from '../../../../../ui/app/store/actionConstants' const actions = actionConstants describe('App State', function () { - const metamaskState = { selectedAddress: '0xAddress', identities: { @@ -42,9 +41,9 @@ describe('App State', function () { it('opens sidebar', function () { const value = { - 'transitionName': 'sidebar-right', - 'type': 'wallet-view', - 'isOpen': true, + transitionName: 'sidebar-right', + type: 'wallet-view', + isOpen: true, } const state = reduceApp(metamaskState, { type: actions.SIDEBAR_OPEN, @@ -151,7 +150,6 @@ describe('App State', function () { assert.equal(state.accountDetail.accountExport, 'none') assert.equal(state.accountDetail.privateKey, '') assert.equal(state.warning, null) - }) it('shows account detail', function () { @@ -163,7 +161,6 @@ describe('App State', function () { assert.equal(state.accountDetail.subview, 'transactions') // default assert.equal(state.accountDetail.accountExport, 'none') // default assert.equal(state.accountDetail.privateKey, '') // default - }) it('clears account details', function () { @@ -214,7 +211,6 @@ describe('App State', function () { assert.equal(state.txId, 2) assert.equal(state.warning, null) assert.equal(state.isLoading, false) - }) it('completes tx continues to show pending txs current view context', function () { diff --git a/test/unit/ui/app/reducers/metamask.spec.js b/test/unit/ui/app/reducers/metamask.spec.js index f662d8173..c36ad1bb9 100644 --- a/test/unit/ui/app/reducers/metamask.spec.js +++ b/test/unit/ui/app/reducers/metamask.spec.js @@ -3,7 +3,6 @@ import reduceMetamask from '../../../../../ui/app/ducks/metamask/metamask' import * as actionConstants from '../../../../../ui/app/store/actionConstants' describe('MetaMask Reducers', function () { - it('init state', function () { const initState = reduceMetamask(undefined, {}) assert(initState) @@ -22,29 +21,37 @@ describe('MetaMask Reducers', function () { }) it('sets rpc target', function () { - const state = reduceMetamask({}, { - type: actionConstants.SET_RPC_TARGET, - value: 'https://custom.rpc', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.SET_RPC_TARGET, + value: 'https://custom.rpc', + }, + ) assert.equal(state.provider.rpcUrl, 'https://custom.rpc') }) it('sets provider type', function () { - const state = reduceMetamask({}, { - type: actionConstants.SET_PROVIDER_TYPE, - value: 'provider type', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.SET_PROVIDER_TYPE, + value: 'provider type', + }, + ) assert.equal(state.provider.type, 'provider type') }) it('shows account detail', function () { - - const state = reduceMetamask({}, { - type: actionConstants.SHOW_ACCOUNT_DETAIL, - value: 'test address', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.SHOW_ACCOUNT_DETAIL, + value: 'test address', + }, + ) assert.equal(state.isUnlocked, true) assert.equal(state.isInitialized, true) @@ -52,15 +59,20 @@ describe('MetaMask Reducers', function () { }) it('sets account label', function () { - const state = reduceMetamask({}, { - type: actionConstants.SET_ACCOUNT_LABEL, - value: { - account: 'test account', - label: 'test label', + const state = reduceMetamask( + {}, + { + type: actionConstants.SET_ACCOUNT_LABEL, + value: { + account: 'test account', + label: 'test label', + }, }, - }) + ) - assert.deepEqual(state.identities, { 'test account': { name: 'test label' } }) + assert.deepEqual(state.identities, { + 'test account': { name: 'test label' }, + }) }) it('sets current fiat', function () { @@ -70,10 +82,13 @@ describe('MetaMask Reducers', function () { conversionDate: new Date(2018, 9), } - const state = reduceMetamask({}, { - type: actionConstants.SET_CURRENT_FIAT, - value, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.SET_CURRENT_FIAT, + value, + }, + ) assert.equal(state.currentCurrency, value.currentCurrency) assert.equal(state.conversionRate, value.conversionRate) @@ -82,100 +97,129 @@ describe('MetaMask Reducers', function () { it('updates tokens', function () { const newTokens = { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'decimals': 18, - 'symbol': 'META', + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + decimals: 18, + symbol: 'META', } - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_TOKENS, - newTokens, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_TOKENS, + newTokens, + }, + ) assert.deepEqual(state.tokens, newTokens) }) it('updates send gas limit', function () { - - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_GAS_LIMIT, - value: '0xGasLimit', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_GAS_LIMIT, + value: '0xGasLimit', + }, + ) assert.equal(state.send.gasLimit, '0xGasLimit') }) it('updates send gas price', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_GAS_PRICE, - value: '0xGasPrice', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_GAS_PRICE, + value: '0xGasPrice', + }, + ) assert.equal(state.send.gasPrice, '0xGasPrice') }) it('toggles account menu ', function () { - const state = reduceMetamask({}, { - type: actionConstants.TOGGLE_ACCOUNT_MENU, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.TOGGLE_ACCOUNT_MENU, + }, + ) assert.equal(state.isAccountMenuOpen, true) }) it('updates gas total', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_GAS_TOTAL, - value: '0xGasTotal', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_GAS_TOTAL, + value: '0xGasTotal', + }, + ) assert.equal(state.send.gasTotal, '0xGasTotal') }) it('updates send token balance', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND_TOKEN_BALANCE, - value: '0xTokenBalance', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND_TOKEN_BALANCE, + value: '0xTokenBalance', + }, + ) assert.equal(state.send.tokenBalance, '0xTokenBalance') }) it('updates data', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND_HEX_DATA, - value: '0xData', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND_HEX_DATA, + value: '0xData', + }, + ) assert.equal(state.send.data, '0xData') }) it('updates send to', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND_TO, - value: { - to: '0xAddress', - nickname: 'nickname', + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND_TO, + value: { + to: '0xAddress', + nickname: 'nickname', + }, }, - }) + ) assert.equal(state.send.to, '0xAddress') assert.equal(state.send.toNickname, 'nickname') }) it('update send amount', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND_AMOUNT, - value: '0xAmount', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND_AMOUNT, + value: '0xAmount', + }, + ) assert.equal(state.send.amount, '0xAmount') }) it('updates max mode', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_MAX_MODE, - value: true, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_MAX_MODE, + value: true, + }, + ) assert.equal(state.send.maxModeOn, true) }) @@ -198,18 +242,20 @@ describe('MetaMask Reducers', function () { ensResolutionError: '', } - const sendState = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND, - value, - }) + const sendState = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND, + value, + }, + ) assert.deepEqual(sendState.send, value) }) it('clears send', function () { const initStateSend = { - send: - { + send: { gasLimit: null, gasPrice: null, gasTotal: null, @@ -269,62 +315,77 @@ describe('MetaMask Reducers', function () { }) it('sets blockies', function () { - const state = reduceMetamask({}, { - type: actionConstants.SET_USE_BLOCKIE, - value: true, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.SET_USE_BLOCKIE, + value: true, + }, + ) assert.equal(state.useBlockie, true) }) it('updates an arbitrary feature flag', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_FEATURE_FLAGS, - value: { - foo: true, + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_FEATURE_FLAGS, + value: { + foo: true, + }, }, - }) + ) assert.equal(state.featureFlags.foo, true) }) it('close welcome screen', function () { - const state = reduceMetamask({}, { - type: actionConstants.CLOSE_WELCOME_SCREEN, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.CLOSE_WELCOME_SCREEN, + }, + ) assert.equal(state.welcomeScreenSeen, true) }) it('sets current locale', function () { - const state = reduceMetamask({}, { - type: actionConstants.SET_CURRENT_LOCALE, - value: { locale: 'ge' }, - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.SET_CURRENT_LOCALE, + value: { locale: 'ge' }, + }, + ) assert.equal(state.currentLocale, 'ge') }) it('sets pending tokens ', function () { const payload = { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'decimals': 18, - 'symbol': 'META', + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + decimals: 18, + symbol: 'META', } - const pendingTokensState = reduceMetamask({}, { - type: actionConstants.SET_PENDING_TOKENS, - payload, - }) + const pendingTokensState = reduceMetamask( + {}, + { + type: actionConstants.SET_PENDING_TOKENS, + payload, + }, + ) assert.deepEqual(pendingTokensState.pendingTokens, payload) }) it('clears pending tokens', function () { const payload = { - 'address': '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - 'decimals': 18, - 'symbol': 'META', + address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + decimals: 18, + symbol: 'META', } const pendingTokensState = { @@ -339,20 +400,26 @@ describe('MetaMask Reducers', function () { }) it('update ensResolution', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND_ENS_RESOLUTION, - payload: '0x1337', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND_ENS_RESOLUTION, + payload: '0x1337', + }, + ) assert.deepEqual(state.send.ensResolution, '0x1337') assert.deepEqual(state.send.ensResolutionError, '') }) it('update ensResolutionError', function () { - const state = reduceMetamask({}, { - type: actionConstants.UPDATE_SEND_ENS_RESOLUTION_ERROR, - payload: 'ens name not found', - }) + const state = reduceMetamask( + {}, + { + type: actionConstants.UPDATE_SEND_ENS_RESOLUTION_ERROR, + payload: 'ens name not found', + }, + ) assert.deepEqual(state.send.ensResolutionError, 'ens name not found') assert.deepEqual(state.send.ensResolution, null) diff --git a/test/unit/ui/etherscan-prefix-for-network.spec.js b/test/unit/ui/etherscan-prefix-for-network.spec.js index 4b0867678..1b3ce7b34 100644 --- a/test/unit/ui/etherscan-prefix-for-network.spec.js +++ b/test/unit/ui/etherscan-prefix-for-network.spec.js @@ -2,7 +2,6 @@ import assert from 'assert' import { getEtherscanNetworkPrefix } from '../../../ui/lib/etherscan-prefix-for-network' describe('Etherscan Network Prefix', function () { - it('returns empty string as default value', function () { assert.equal(getEtherscanNetworkPrefix(), '') }) @@ -26,5 +25,4 @@ describe('Etherscan Network Prefix', function () { it('returs goerli as prefix for networkId of 5', function () { assert.equal(getEtherscanNetworkPrefix('5'), 'goerli.') }) - }) diff --git a/ui/app/components/app/account-list-item/account-list-item.js b/ui/app/components/app/account-list-item/account-list-item.js index 7e001f7d6..5823e2923 100644 --- a/ui/app/components/app/account-list-item/account-list-item.js +++ b/ui/app/components/app/account-list-item/account-list-item.js @@ -4,7 +4,7 @@ import { checksumAddress } from '../../../helpers/utils/util' import Identicon from '../../ui/identicon' import AccountMismatchWarning from '../../ui/account-mismatch-warning/account-mismatch-warning.component' -export default function AccountListItem ({ +export default function AccountListItem({ account, className, displayAddress = false, @@ -18,7 +18,6 @@ export default function AccountListItem ({ className={`account-list-item ${className}`} onClick={() => handleClick && handleClick({ name, address, balance })} > -
    -
    { name || address }
    +
    {name || address}
    - {icon &&
    { icon }
    } + {icon &&
    {icon}
    }
    {displayAddress && name && (
    - { checksumAddress(address) } + {checksumAddress(address)}
    )} diff --git a/ui/app/components/app/account-list-item/tests/account-list-item-component.test.js b/ui/app/components/app/account-list-item/tests/account-list-item-component.test.js index d42bd7bc9..4c65e3b70 100644 --- a/ui/app/components/app/account-list-item/tests/account-list-item-component.test.js +++ b/ui/app/components/app/account-list-item/tests/account-list-item-component.test.js @@ -11,21 +11,28 @@ describe('AccountListItem Component', function () { describe('render', function () { before(function () { - checksumAddressStub = sinon.stub(utils, 'checksumAddress').returns('mockCheckSumAddress') + checksumAddressStub = sinon + .stub(utils, 'checksumAddress') + .returns('mockCheckSumAddress') propsMethodSpies = { handleClick: sinon.spy(), } }) beforeEach(function () { - wrapper = shallow(( + wrapper = shallow( } - /> - ), { context: { t: (str) => `${str}_t` } }) + />, + { context: { t: (str) => `${str}_t` } }, + ) }) afterEach(function () { @@ -48,65 +55,96 @@ describe('AccountListItem Component', function () { assert.equal(propsMethodSpies.handleClick.callCount, 0) onClick() assert.equal(propsMethodSpies.handleClick.callCount, 1) - assert.deepEqual( - propsMethodSpies.handleClick.getCall(0).args, - [{ address: 'mockAddress', name: 'mockName', balance: 'mockBalance' }], - ) + assert.deepEqual(propsMethodSpies.handleClick.getCall(0).args, [ + { address: 'mockAddress', name: 'mockName', balance: 'mockBalance' }, + ]) }) it('should have a top row div', function () { - assert.equal(wrapper.find('.mockClassName > .account-list-item__top-row').length, 1) - assert(wrapper.find('.mockClassName > .account-list-item__top-row').is('div')) + assert.equal( + wrapper.find('.mockClassName > .account-list-item__top-row').length, + 1, + ) + assert( + wrapper.find('.mockClassName > .account-list-item__top-row').is('div'), + ) }) it('should have an identicon, name and icon in the top row', function () { - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') + const topRow = wrapper.find( + '.mockClassName > .account-list-item__top-row', + ) assert.equal(topRow.find(Identicon).length, 1) assert.equal(topRow.find('.account-list-item__account-name').length, 1) assert.equal(topRow.find('.account-list-item__icon').length, 1) }) it('should show the account name if it exists', function () { - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert.equal(topRow.find('.account-list-item__account-name').text(), 'mockName') + const topRow = wrapper.find( + '.mockClassName > .account-list-item__top-row', + ) + assert.equal( + topRow.find('.account-list-item__account-name').text(), + 'mockName', + ) }) it('should show the account address if there is no name', function () { wrapper.setProps({ account: { address: 'addressButNoName' } }) - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert.equal(topRow.find('.account-list-item__account-name').text(), 'addressButNoName') + const topRow = wrapper.find( + '.mockClassName > .account-list-item__top-row', + ) + assert.equal( + topRow.find('.account-list-item__account-name').text(), + 'addressButNoName', + ) }) it('should render the passed icon', function () { - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') + const topRow = wrapper.find( + '.mockClassName > .account-list-item__top-row', + ) assert(topRow.find('.account-list-item__icon').childAt(0).is('i')) - assert(topRow.find('.account-list-item__icon').childAt(0).hasClass('mockIcon')) + assert( + topRow.find('.account-list-item__icon').childAt(0).hasClass('mockIcon'), + ) }) it('should not render an icon if none is passed', function () { wrapper.setProps({ icon: null }) - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') + const topRow = wrapper.find( + '.mockClassName > .account-list-item__top-row', + ) assert.equal(topRow.find('.account-list-item__icon').length, 0) }) it('should render the account address as a checksumAddress if displayAddress is true and name is provided', function () { wrapper.setProps({ displayAddress: true }) - assert.equal(wrapper.find('.account-list-item__account-address').length, 1) - assert.equal(wrapper.find('.account-list-item__account-address').text(), 'mockCheckSumAddress') - assert.deepEqual( - checksumAddressStub.getCall(0).args, - ['mockAddress'], + assert.equal( + wrapper.find('.account-list-item__account-address').length, + 1, ) + assert.equal( + wrapper.find('.account-list-item__account-address').text(), + 'mockCheckSumAddress', + ) + assert.deepEqual(checksumAddressStub.getCall(0).args, ['mockAddress']) }) it('should not render the account address as a checksumAddress if displayAddress is false', function () { wrapper.setProps({ displayAddress: false }) - assert.equal(wrapper.find('.account-list-item__account-address').length, 0) + assert.equal( + wrapper.find('.account-list-item__account-address').length, + 0, + ) }) it('should not render the account address as a checksumAddress if name is not provided', function () { wrapper.setProps({ account: { address: 'someAddressButNoName' } }) - assert.equal(wrapper.find('.account-list-item__account-address').length, 0) + assert.equal( + wrapper.find('.account-list-item__account-address').length, + 0, + ) }) }) }) diff --git a/ui/app/components/app/account-menu/account-menu.component.js b/ui/app/components/app/account-menu/account-menu.component.js index b4f5a2b32..b6739f08f 100644 --- a/ui/app/components/app/account-menu/account-menu.component.js +++ b/ui/app/components/app/account-menu/account-menu.component.js @@ -21,31 +21,25 @@ import { import TextField from '../../ui/text-field' import SearchIcon from '../../ui/search-icon' -export function AccountMenuItem (props) { - const { - icon, - children, - text, - subText, - className, - onClick, - } = props +export function AccountMenuItem(props) { + const { icon, children, text, subText, className, onClick } = props const itemClassName = classnames('account-menu__item', className, { 'account-menu__item--clickable': Boolean(onClick), }) - return children - ?
    {children}
    - : ( -
    - {icon ?
    {icon}
    : null} - {text ?
    {text}
    : null} - {subText ?
    {subText}
    : null} -
    - ) + return children ? ( +
    + {children} +
    + ) : ( +
    + {icon ?
    {icon}
    : null} + {text ?
    {text}
    : null} + {subText ? ( +
    {subText}
    + ) : null} +
    + ) } AccountMenuItem.propTypes = { @@ -97,7 +91,7 @@ export default class AccountMenu extends Component { ], }) - componentDidUpdate (prevProps, prevState) { + componentDidUpdate(prevProps, prevState) { const { isAccountMenuOpen: prevIsAccountMenuOpen } = prevProps const { searchQuery: prevSearchQuery } = prevState const { isAccountMenuOpen } = this.props @@ -115,7 +109,7 @@ export default class AccountMenu extends Component { } } - renderAccountsSearch () { + renderAccountsSearch() { const inputAdornment = ( {this.context.t('noAccountsFound')}

    + return ( +

    + {this.context.t('noAccountsFound')} +

    + ) } return filteredIdentities.map((identity) => { @@ -172,7 +170,10 @@ export default class AccountMenu extends Component { const simpleAddress = identity.address.substring(2).toLowerCase() const keyring = keyrings.find((kr) => { - return kr.accounts.includes(simpleAddress) || kr.accounts.includes(identity.address) + return ( + kr.accounts.includes(simpleAddress) || + kr.accounts.includes(identity.address) + ) }) const addressDomains = addressConnectedDomainMap[identity.address] || {} const iconAndNameForOpenDomain = addressDomains[originOfCurrentTab] @@ -193,37 +194,33 @@ export default class AccountMenu extends Component { key={identity.address} >
    - { isSelected &&
    } + {isSelected &&
    }
    - +
    -
    - { identity.name || '' } -
    +
    {identity.name || ''}
    - { this.renderKeyringType(keyring) } - { iconAndNameForOpenDomain - ? ( -
    - -
    - ) - : null - } + {this.renderKeyringType(keyring)} + {iconAndNameForOpenDomain ? ( +
    + +
    + ) : null}
    ) }) } - renderKeyringType (keyring) { + renderKeyringType(keyring) { const { t } = this.context // Sometimes keyrings aren't loaded yet @@ -246,18 +243,14 @@ export default class AccountMenu extends Component { return null } - return ( -
    - { label } -
    - ) + return
    {label}
    } - resetSearchQuery () { + resetSearchQuery() { this.setSearchQuery('') } - setSearchQuery (searchQuery) { + setSearchQuery(searchQuery) { this.setState({ searchQuery }) } @@ -284,25 +277,27 @@ export default class AccountMenu extends Component { this.setShouldShowScrollButton() } - renderScrollButton () { + renderScrollButton() { const { shouldShowScrollButton } = this.state - return shouldShowScrollButton && ( -
    - scroll down -
    + return ( + shouldShowScrollButton && ( +
    + scroll down +
    + ) ) } - render () { + render() { const { t, metricsEvent } = this.context const { shouldShowAccountsSearch, @@ -317,12 +312,10 @@ export default class AccountMenu extends Component { } return ( -
    +
    - { t('myAccounts') } + {t('myAccounts')}
    @@ -343,9 +336,9 @@ export default class AccountMenu extends Component { this.accountsRef = ref }} > - { this.renderAccounts() } + {this.renderAccounts()}
    - { this.renderScrollButton() } + {this.renderScrollButton()}
    - )} + } text={t('createAccount')} /> - )} + } text={t('importAccount')} /> - )} + } text={t('connectHardwareWallet')} />
    @@ -418,9 +411,7 @@ export default class AccountMenu extends Component { toggleAccountMenu() history.push(ABOUT_US_ROUTE) }} - icon={ - - } + icon={} text={t('infoHelp')} /> - )} + } text={t('settings')} />
    diff --git a/ui/app/components/app/account-menu/account-menu.container.js b/ui/app/components/app/account-menu/account-menu.container.js index c08537264..2ce69b256 100644 --- a/ui/app/components/app/account-menu/account-menu.container.js +++ b/ui/app/components/app/account-menu/account-menu.container.js @@ -22,8 +22,10 @@ import AccountMenu from './account-menu.component' */ const SHOW_SEARCH_ACCOUNTS_MIN_COUNT = 5 -function mapStateToProps (state) { - const { metamask: { isAccountMenuOpen } } = state +function mapStateToProps(state) { + const { + metamask: { isAccountMenuOpen }, + } = state const accounts = getMetaMaskAccountsOrdered(state) const origin = getOriginOfCurrentTab(state) const selectedAddress = getSelectedAddress(state) @@ -39,7 +41,7 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { toggleAccountMenu: () => dispatch(toggleAccountMenu()), showAccountDetail: (address) => { diff --git a/ui/app/components/app/account-menu/tests/account-menu.test.js b/ui/app/components/app/account-menu/tests/account-menu.test.js index 6c4fd3a72..70dba281f 100644 --- a/ui/app/components/app/account-menu/tests/account-menu.test.js +++ b/ui/app/components/app/account-menu/tests/account-menu.test.js @@ -7,7 +7,6 @@ import { mountWithRouter } from '../../../../../../test/lib/render-helpers' import AccountMenu from '..' describe('Account Menu', function () { - let wrapper const mockStore = { @@ -41,15 +40,11 @@ describe('Account Menu', function () { keyrings: [ { type: 'HD Key Tree', - accounts: [ - '0xAdress', - ], + accounts: ['0xAdress'], }, { type: 'Simple Key Pair', - accounts: [ - '0xImportedAddress', - ], + accounts: ['0xImportedAddress'], }, ], prevIsAccountMenuOpen: false, @@ -60,14 +55,14 @@ describe('Account Menu', function () { history: { push: sinon.spy(), }, - } before(function () { wrapper = mountWithRouter( - , store, + , + store, ) }) @@ -83,12 +78,16 @@ describe('Account Menu', function () { }) it('renders user preference currency display balance from account balance', function () { - const accountBalance = wrapper.find('.currency-display-component.account-menu__balance') + const accountBalance = wrapper.find( + '.currency-display-component.account-menu__balance', + ) assert.equal(accountBalance.length, 2) }) it('simulate click', function () { - const click = wrapper.find('.account-menu__account.account-menu__item--clickable') + const click = wrapper.find( + '.account-menu__account.account-menu__item--clickable', + ) click.first().simulate('click') assert(props.showAccountDetail.calledOnce) @@ -147,7 +146,6 @@ describe('Account Menu', function () { }) describe('Connect Hardware Wallet', function () { - let connectHardwareWallet it('renders import account item', function () { @@ -158,12 +156,14 @@ describe('Account Menu', function () { it('calls toggle menu and push /new-account/connect route to history', function () { connectHardwareWallet.simulate('click') assert(props.toggleAccountMenu.calledOnce) - assert.equal(props.history.push.getCall(0).args[0], '/new-account/connect') + assert.equal( + props.history.push.getCall(0).args[0], + '/new-account/connect', + ) }) }) describe('Info & Help', function () { - let infoHelp it('renders import account item', function () { @@ -179,7 +179,6 @@ describe('Account Menu', function () { }) describe('Settings', function () { - let settings it('renders import account item', function () { diff --git a/ui/app/components/app/add-token-button/add-token-button.component.js b/ui/app/components/app/add-token-button/add-token-button.component.js index 1ddf2b1ff..6073faef0 100644 --- a/ui/app/components/app/add-token-button/add-token-button.component.js +++ b/ui/app/components/app/add-token-button/add-token-button.component.js @@ -5,7 +5,7 @@ import { useI18nContext } from '../../../hooks/useI18nContext' import { ADD_TOKEN_ROUTE } from '../../../helpers/constants/routes' import Button from '../../ui/button' -export default function AddTokenButton () { +export default function AddTokenButton() { const addTokenEvent = useMetricEvent({ eventOpts: { category: 'Navigation', diff --git a/ui/app/components/app/alerts/alerts.js b/ui/app/components/app/alerts/alerts.js index 9aa63418f..f5034073d 100644 --- a/ui/app/components/app/alerts/alerts.js +++ b/ui/app/components/app/alerts/alerts.js @@ -8,18 +8,18 @@ import InvalidCustomNetworkAlert from './invalid-custom-network-alert' import UnconnectedAccountAlert from './unconnected-account-alert' const Alerts = ({ history }) => { - const _invalidCustomNetworkAlertIsOpen = useSelector(invalidCustomNetworkAlertIsOpen) - const _unconnectedAccountAlertIsOpen = useSelector(unconnectedAccountAlertIsOpen) + const _invalidCustomNetworkAlertIsOpen = useSelector( + invalidCustomNetworkAlertIsOpen, + ) + const _unconnectedAccountAlertIsOpen = useSelector( + unconnectedAccountAlertIsOpen, + ) if (_invalidCustomNetworkAlertIsOpen) { - return ( - - ) + return } if (_unconnectedAccountAlertIsOpen) { - return ( - - ) + return } return null diff --git a/ui/app/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.js b/ui/app/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.js index 5c23d58b3..40cad2a0f 100644 --- a/ui/app/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.js +++ b/ui/app/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.js @@ -13,10 +13,7 @@ import Button from '../../../ui/button' import { useI18nContext } from '../../../../hooks/useI18nContext' import { NETWORKS_ROUTE } from '../../../../helpers/constants/routes' -const { - ERROR, - LOADING, -} = ALERT_STATE +const { ERROR, LOADING } = ALERT_STATE const InvalidCustomNetworkAlert = ({ history }) => { const t = useI18nContext() @@ -28,15 +25,11 @@ const InvalidCustomNetworkAlert = ({ history }) => { const footer = ( <> - { - alertState === ERROR - ? ( -
    - { t('failureMessage') } -
    - ) - : null - } + {alertState === ERROR ? ( +
    + {t('failureMessage')} +
    + ) : null}
    @@ -72,19 +65,17 @@ const InvalidCustomNetworkAlert = ({ history }) => {

    {t('invalidCustomNetworkAlertContent1', [networkName])}

    {t('invalidCustomNetworkAlertContent2')}

    - { - t('invalidCustomNetworkAlertContent3', [( - global.platform.openTab({ url: 'https://chainid.network' }) - } - > - chainId.network - - )]) - } + {t('invalidCustomNetworkAlertContent3', [ + + global.platform.openTab({ url: 'https://chainid.network' }) + } + > + chainId.network + , + ])}

    ) diff --git a/ui/app/components/app/alerts/unconnected-account-alert/tests/unconnected-account-alert.test.js b/ui/app/components/app/alerts/unconnected-account-alert/tests/unconnected-account-alert.test.js index ff85ed553..fff6504bb 100644 --- a/ui/app/components/app/alerts/unconnected-account-alert/tests/unconnected-account-alert.test.js +++ b/ui/app/components/app/alerts/unconnected-account-alert/tests/unconnected-account-alert.test.js @@ -13,7 +13,6 @@ import * as actions from '../../../../../store/actions' import UnconnectedAccountAlert from '..' describe('Unconnected Account Alert', function () { - const network = '123' const selectedAddress = '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b' @@ -41,7 +40,7 @@ describe('Unconnected Account Alert', function () { } const cachedBalances = { - '123': { + 123: { '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': '0x0', '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': '0x0', }, @@ -87,9 +86,7 @@ describe('Unconnected Account Alert', function () { { name: 'exposedAccounts', type: 'filterResponse', - value: [ - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ], + value: ['0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'], }, ], invoker: 'https://test.dapp', @@ -112,7 +109,6 @@ describe('Unconnected Account Alert', function () { }) it('checks that checkbox is checked', function () { - const store = configureMockStore()(mockState) const { getByRole } = renderWithProvider(, store) @@ -140,7 +136,10 @@ describe('Unconnected Account Alert', function () { const store = configureMockStore([thunk])(mockState) - const { getByText, getByRole } = renderWithProvider(, store) + const { getByText, getByRole } = renderWithProvider( + , + store, + ) const dismissButton = getByText(/dismiss/u) const dontShowCheckbox = getByRole('checkbox') @@ -149,10 +148,14 @@ describe('Unconnected Account Alert', function () { fireEvent.click(dismissButton) setImmediate(() => { - assert.equal(store.getActions()[0].type, 'unconnectedAccount/disableAlertRequested') - assert.equal(store.getActions()[1].type, 'unconnectedAccount/disableAlertSucceeded') + assert.equal( + store.getActions()[0].type, + 'unconnectedAccount/disableAlertRequested', + ) + assert.equal( + store.getActions()[1].type, + 'unconnectedAccount/disableAlertSucceeded', + ) }) - }) - }) diff --git a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js index 3ed29ba04..ce6e236aa 100644 --- a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js +++ b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js @@ -23,10 +23,7 @@ import Tooltip from '../../../ui/tooltip' import ConnectedAccountsList from '../../connected-accounts-list' import { useI18nContext } from '../../../../hooks/useI18nContext' -const { - ERROR, - LOADING, -} = ALERT_STATE +const { ERROR, LOADING } = ALERT_STATE const UnconnectedAccountAlert = () => { const t = useI18nContext() @@ -46,15 +43,11 @@ const UnconnectedAccountAlert = () => { const footer = ( <> - { - alertState === ERROR - ? ( -
    - { t('failureMessage') } -
    - ) - : null - } + {alertState === ERROR ? ( +
    + {t('failureMessage')} +
    + ) : null}
    { className="unconnected-account-alert__checkbox-label" htmlFor="unconnectedAccount_dontShowThisAgain" > - { t('dontShowThisAgain') } + {t('dontShowThisAgain')} { rounded className="unconnected-account-alert__dismiss-button" > - { t('dismiss') } + {t('dismiss')}
    @@ -92,7 +85,9 @@ const UnconnectedAccountAlert = () => { return ( { - if (!disabled) { - !isAccountMenuOpen && this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Home', - name: 'Opened Main Menu', - }, - }) - toggleAccountMenu() - } - }} - > - -
    + return ( + isUnlocked && ( +
    { + if (!disabled) { + !isAccountMenuOpen && + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Home', + name: 'Opened Main Menu', + }, + }) + toggleAccountMenu() + } + }} + > + +
    + ) ) } - render () { + render() { const { history, network, @@ -93,7 +102,9 @@ export default class AppHeader extends PureComponent { return (
    - { - !hideNetworkIndicator && ( -
    - this.handleNetworkIndicatorClick(event)} - disabled={disabled || disableNetworkIndicator} - /> -
    - ) - } - { this.renderAccountMenu() } + {!hideNetworkIndicator && ( +
    + this.handleNetworkIndicatorClick(event)} + disabled={disabled || disableNetworkIndicator} + /> +
    + )} + {this.renderAccountMenu()}
    diff --git a/ui/app/components/app/app-header/tests/app-header.test.js b/ui/app/components/app/app-header/tests/app-header.test.js index 76ece07a7..0bb9ed9df 100644 --- a/ui/app/components/app/app-header/tests/app-header.test.js +++ b/ui/app/components/app/app-header/tests/app-header.test.js @@ -26,14 +26,12 @@ describe('App Header', function () { } beforeEach(function () { - wrapper = shallow( - , { - context: { - t: (str) => str, - metricsEvent: () => undefined, - }, + wrapper = shallow(, { + context: { + t: (str) => str, + metricsEvent: () => undefined, }, - ) + }) }) afterEach(function () { @@ -81,7 +79,6 @@ describe('App Header', function () { }) describe('Account Menu', function () { - it('toggles account menu', function () { const accountMenu = wrapper.find('.account-menu__icon') accountMenu.simulate('click') @@ -95,5 +92,4 @@ describe('App Header', function () { assert(props.toggleAccountMenu.notCalled) }) }) - }) diff --git a/ui/app/components/app/asset-list-item/asset-list-item.js b/ui/app/components/app/asset-list-item/asset-list-item.js index 7119cbaa7..27e7eab34 100644 --- a/ui/app/components/app/asset-list-item/asset-list-item.js +++ b/ui/app/components/app/asset-list-item/asset-list-item.js @@ -36,27 +36,23 @@ const AssetListItem = ({ name: 'Clicked Send: Token', }, }) - const titleIcon = warning - ? ( - - - - ) - : null + const titleIcon = warning ? ( + + + + ) : null - const midContent = warning - ? ( - <> - -
    {warning}
    - - ) - : null + const midContent = warning ? ( + <> + +
    {warning}
    + + ) : null const sendTokenButton = useMemo(() => { if (tokenAddress === null || tokenAddress === undefined) { @@ -69,11 +65,13 @@ const AssetListItem = ({ onClick={(e) => { e.stopPropagation() sendTokenEvent() - dispatch(updateSendToken({ - address: tokenAddress, - decimals: tokenDecimals, - symbol: tokenSymbol, - })) + dispatch( + updateSendToken({ + address: tokenAddress, + decimals: tokenDecimals, + symbol: tokenSymbol, + }), + ) history.push(SEND_ROUTE) }} > @@ -94,30 +92,30 @@ const AssetListItem = ({

    {primary}

    {tokenSymbol}

    - )} + } titleIcon={titleIcon} subtitle={

    {secondary}

    } onClick={onClick} - icon={( + icon={ - )} + } midContent={midContent} - rightContent={( + rightContent={ <> {sendTokenButton} - )} + } /> ) } diff --git a/ui/app/components/app/asset-list/asset-list.js b/ui/app/components/app/asset-list/asset-list.js index 12d54e9dc..09314413c 100644 --- a/ui/app/components/app/asset-list/asset-list.js +++ b/ui/app/components/app/asset-list/asset-list.js @@ -9,12 +9,18 @@ import AssetListItem from '../asset-list-item' import { PRIMARY, SECONDARY } from '../../../helpers/constants/common' import { useMetricEvent } from '../../../hooks/useMetricEvent' import { useUserPreferencedCurrency } from '../../../hooks/useUserPreferencedCurrency' -import { getCurrentAccountWithSendEtherInfo, getNativeCurrency, getShouldShowFiat } from '../../../selectors' +import { + getCurrentAccountWithSendEtherInfo, + getNativeCurrency, + getShouldShowFiat, +} from '../../../selectors' import { useCurrencyDisplay } from '../../../hooks/useCurrencyDisplay' const AssetList = ({ onClickAsset }) => { const history = useHistory() - const selectedAccountBalance = useSelector((state) => getCurrentAccountWithSendEtherInfo(state).balance) + const selectedAccountBalance = useSelector( + (state) => getCurrentAccountWithSendEtherInfo(state).balance, + ) const nativeCurrency = useSelector(getNativeCurrency) const showFiat = useSelector(getShouldShowFiat) const selectTokenEvent = useMetricEvent({ @@ -41,14 +47,17 @@ const AssetList = ({ onClickAsset }) => { numberOfDecimals: secondaryNumberOfDecimals, } = useUserPreferencedCurrency(SECONDARY, { ethNumberOfDecimals: 4 }) - const [primaryCurrencyDisplay] = useCurrencyDisplay( - selectedAccountBalance, - { numberOfDecimals: primaryNumberOfDecimals, currency: primaryCurrency }, - ) + const [primaryCurrencyDisplay] = useCurrencyDisplay(selectedAccountBalance, { + numberOfDecimals: primaryNumberOfDecimals, + currency: primaryCurrency, + }) const [secondaryCurrencyDisplay] = useCurrencyDisplay( selectedAccountBalance, - { numberOfDecimals: secondaryNumberOfDecimals, currency: secondaryCurrency }, + { + numberOfDecimals: secondaryNumberOfDecimals, + currency: secondaryCurrency, + }, ) return ( diff --git a/ui/app/components/app/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js b/ui/app/components/app/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js index 0cdb53a32..89d851a97 100644 --- a/ui/app/components/app/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js @@ -18,57 +18,48 @@ const ConfirmDetailRow = (props) => { return (
    -
    - { label } -
    +
    {label}
    - { - headerText && ( -
    onHeaderClick && onHeaderClick()} - > - { headerText } -
    - ) - } - { - primaryText - ? ( -
    - { primaryText } -
    - ) : ( - - ) - } - { - secondaryText - ? ( -
    - { secondaryText } -
    - ) : ( - - ) - } + {headerText && ( +
    onHeaderClick && onHeaderClick()} + > + {headerText} +
    + )} + {primaryText ? ( +
    + {primaryText} +
    + ) : ( + + )} + {secondaryText ? ( +
    {secondaryText}
    + ) : ( + + )}
    ) diff --git a/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js b/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js index d431033c3..add78407c 100644 --- a/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js +++ b/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js @@ -33,27 +33,59 @@ describe('Confirm Detail Row Component', function () { }) it('should render the label as a child of the confirm-detail-row__label', function () { - assert.equal(wrapper.find('.confirm-detail-row > .confirm-detail-row__label').childAt(0).text(), 'mockLabel') + assert.equal( + wrapper + .find('.confirm-detail-row > .confirm-detail-row__label') + .childAt(0) + .text(), + 'mockLabel', + ) }) it('should render the headerText as a child of the confirm-detail-row__header-text', function () { - assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__header-text').childAt(0).text(), 'mockHeaderText') + assert.equal( + wrapper + .find( + '.confirm-detail-row__details > .confirm-detail-row__header-text', + ) + .childAt(0) + .text(), + 'mockHeaderText', + ) }) it('should render the primaryText as a child of the confirm-detail-row__primary', function () { - assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__primary').childAt(0).text(), 'mockFiatText') + assert.equal( + wrapper + .find('.confirm-detail-row__details > .confirm-detail-row__primary') + .childAt(0) + .text(), + 'mockFiatText', + ) }) it('should render the ethText as a child of the confirm-detail-row__secondary', function () { - assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__secondary').childAt(0).text(), 'mockEthText') + assert.equal( + wrapper + .find('.confirm-detail-row__details > .confirm-detail-row__secondary') + .childAt(0) + .text(), + 'mockEthText', + ) }) it('should set the fiatTextColor on confirm-detail-row__primary', function () { - assert.equal(wrapper.find('.confirm-detail-row__primary').props().style.color, 'mockColor') + assert.equal( + wrapper.find('.confirm-detail-row__primary').props().style.color, + 'mockColor', + ) }) it('should assure the confirm-detail-row__header-text classname is correct', function () { - assert.equal(wrapper.find('.confirm-detail-row__header-text').props().className, 'confirm-detail-row__header-text mockHeaderClass') + assert.equal( + wrapper.find('.confirm-detail-row__header-text').props().className, + 'confirm-detail-row__header-text mockHeaderClass', + ) }) it('should call onHeaderClick when headerText div gets clicked', function () { diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index bf226df7e..9a6c3f5c5 100644 --- a/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -34,32 +34,31 @@ export default class ConfirmPageContainerContent extends Component { rejectNText: PropTypes.string, } - renderContent () { + renderContent() { const { detailsComponent, dataComponent } = this.props if (detailsComponent && dataComponent) { return this.renderTabs() } return detailsComponent || dataComponent - } - renderTabs () { + renderTabs() { const { detailsComponent, dataComponent } = this.props return ( - { detailsComponent } + {detailsComponent} - { dataComponent } + {dataComponent} ) } - render () { + render() { const { action, errorKey, @@ -88,40 +87,30 @@ export default class ConfirmPageContainerContent extends Component { return (
    - { - warning && ( - - ) - } - { - summaryComponent || ( - - ) - } - { this.renderContent() } - { - (errorKey || errorMessage) && ( -
    - -
    - ) - } + {warning && } + {summaryComponent || ( + + )} + {this.renderContent()} + {(errorKey || errorMessage) && ( +
    + +
    + )} - {unapprovedTxCount > 1 && ( - - {rejectNText} - - )} + {unapprovedTxCount > 1 && {rejectNText}} -
    ) } diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js index 85cbc0076..dfa7b63fb 100644 --- a/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js @@ -20,39 +20,31 @@ const ConfirmPageContainerSummary = (props) => { return (
    -
    - { action } -
    - { - nonce && ( -
    - { `#${nonce}` } -
    - ) - } +
    {action}
    + {nonce && ( +
    + {`#${nonce}`} +
    + )}
    - { - identiconAddress && ( - - ) - } + {identiconAddress && ( + + )}
    - { titleComponent || title } + {titleComponent || title}
    - { - hideSubtitle || ( -
    - { subtitleComponent || subtitle } -
    - ) - } + {hideSubtitle || ( +
    + {subtitleComponent || subtitle} +
    + )}
    ) } diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js index 8865fb976..d235ad3b4 100644 --- a/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js @@ -9,7 +9,7 @@ const ConfirmPageContainerWarning = (props) => { src="/images/alert.svg" />
    - { props.warning } + {props.warning}
    ) diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js index f2e2c0f2b..92d94f937 100644 --- a/ui/app/components/app/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js @@ -11,7 +11,7 @@ import { shortenAddress } from '../../../../helpers/utils/util' import AccountMismatchWarning from '../../../ui/account-mismatch-warning/account-mismatch-warning.component' import { useI18nContext } from '../../../../hooks/useI18nContext' -export default function ConfirmPageContainerHeader ({ +export default function ConfirmPageContainerHeader({ onEdit, showEdit, accountAddress, @@ -20,7 +20,8 @@ export default function ConfirmPageContainerHeader ({ }) { const t = useI18nContext() const windowType = getEnvironmentType() - const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION && + const isFullScreen = + windowType !== ENVIRONMENT_TYPE_NOTIFICATION && windowType !== ENVIRONMENT_TYPE_POPUP if (!showEdit && isFullScreen) { @@ -29,43 +30,35 @@ export default function ConfirmPageContainerHeader ({ return (
    - { showAccountInHeader - ? ( -
    -
    - -
    -
    - { shortenAddress(accountAddress) } -
    - + {showAccountInHeader ? ( +
    +
    +
    - ) - : ( -
    + {shortenAddress(accountAddress)} +
    + +
    + ) : ( +
    + + onEdit()} > - - onEdit()} - > - { t('edit') } - -
    - ) - } - { !isFullScreen && } + {t('edit')} + +
    + )} + {!isFullScreen && }
    - { children } + {children}
    ) } diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js index 0adc54fdb..f8f4e3ae8 100755 --- a/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js @@ -2,7 +2,18 @@ import React from 'react' import PropTypes from 'prop-types' const ConfirmPageContainerNavigation = (props) => { - const { onNextTx, totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation, firstTx, lastTx, ofText, requestsWaitingText } = props + const { + onNextTx, + totalTx, + positionOfCurrentTx, + nextTxId, + prevTxId, + showNavigation, + firstTx, + lastTx, + ofText, + requestsWaitingText, + } = props return (
    { data-testid="next-page" onClick={() => onNextTx(nextTxId)} > - +
    onNextTx(lastTx)} > - +
    diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container.component.js index baf75bbd3..45c32b3b6 100644 --- a/ui/app/components/app/confirm-page-container/confirm-page-container.component.js +++ b/ui/app/components/app/confirm-page-container/confirm-page-container.component.js @@ -2,7 +2,11 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import SenderToRecipient from '../../ui/sender-to-recipient' import { PageContainerFooter } from '../../ui/page-container' -import { ConfirmPageContainerHeader, ConfirmPageContainerContent, ConfirmPageContainerNavigation } from '.' +import { + ConfirmPageContainerHeader, + ConfirmPageContainerContent, + ConfirmPageContainerNavigation, +} from '.' export default class ConfirmPageContainer extends Component { static contextTypes = { @@ -58,7 +62,7 @@ export default class ConfirmPageContainer extends Component { disabled: PropTypes.bool, } - render () { + render() { const { showEdit, onEdit, @@ -102,7 +106,8 @@ export default class ConfirmPageContainer extends Component { hideSenderToRecipient, showAccountInHeader, } = this.props - const renderAssetImage = contentComponent || (!contentComponent && !identiconAddress) + const renderAssetImage = + contentComponent || (!contentComponent && !identiconAddress) return (
    @@ -124,68 +129,61 @@ export default class ConfirmPageContainer extends Component { showAccountInHeader={showAccountInHeader} accountAddress={fromAddress} > - { hideSenderToRecipient - ? null - : ( - - ) - } - - { - contentComponent || ( - - ) - } - { - contentComponent && ( - - {unapprovedTxCount > 1 && ( - - {this.context.t('rejectTxsN', [unapprovedTxCount])} - - )} - - ) - } + )} + + {contentComponent || ( + + )} + {contentComponent && ( + + {unapprovedTxCount > 1 && ( + + {this.context.t('rejectTxsN', [unapprovedTxCount])} + + )} + + )}
    ) } diff --git a/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js b/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js index cfff63c1c..8a1fc0852 100644 --- a/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js +++ b/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js @@ -23,15 +23,8 @@ export default class ConnectedAccountsListItem extends PureComponent { action: null, } - render () { - const { - address, - className, - name, - status, - action, - options, - } = this.props + render() { + const { address, className, name, status, action, options } = this.props return (
    @@ -45,16 +38,12 @@ export default class ConnectedAccountsListItem extends PureComponent {

    {name}

    - { - status - ? ( -

    -    - {status} -

    - ) - : null - } + {status ? ( +

    +    + {status} +

    + ) : null} {action}
    diff --git a/ui/app/components/app/connected-accounts-list/connected-accounts-list-options/connected-accounts-list-options.component.js b/ui/app/components/app/connected-accounts-list/connected-accounts-list-options/connected-accounts-list-options.component.js index 0fcc2d818..c647bca40 100644 --- a/ui/app/components/app/connected-accounts-list/connected-accounts-list-options/connected-accounts-list-options.component.js +++ b/ui/app/components/app/connected-accounts-list/connected-accounts-list-options/connected-accounts-list-options.component.js @@ -2,25 +2,34 @@ import PropTypes from 'prop-types' import React, { useState } from 'react' import { Menu } from '../../../ui/menu' -const ConnectedAccountsListOptions = ({ children, onShowOptions, onHideOptions, show }) => { +const ConnectedAccountsListOptions = ({ + children, + onShowOptions, + onHideOptions, + show, +}) => { const [optionsButtonElement, setOptionsButtonElement] = useState(null) return ( <> - ) } diff --git a/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js b/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js index 17034f32d..253027959 100644 --- a/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js +++ b/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js @@ -18,7 +18,9 @@ const mapStateToProps = (state) => { const originOfCurrentTab = getOriginOfCurrentTab(state) const selectedAddressDomainMap = addressConnectedDomainMap[selectedAddress] - const currentTabIsConnectedToSelectedAddress = Boolean(selectedAddressDomainMap && selectedAddressDomainMap[originOfCurrentTab]) + const currentTabIsConnectedToSelectedAddress = Boolean( + selectedAddressDomainMap && selectedAddressDomainMap[originOfCurrentTab], + ) let status if (currentTabIsConnectedToSelectedAddress) { diff --git a/ui/app/components/app/contact-list/contact-list.component.js b/ui/app/components/app/contact-list/contact-list.component.js index 0e151d23d..3b62741e6 100644 --- a/ui/app/components/app/contact-list/contact-list.component.js +++ b/ui/app/components/app/contact-list/contact-list.component.js @@ -21,7 +21,7 @@ export default class ContactList extends PureComponent { isShowingAllRecent: false, } - renderRecents () { + renderRecents() { const { t } = this.context const { isShowingAllRecent } = this.state const nonContacts = this.props.searchForRecents() @@ -36,22 +36,20 @@ export default class ContactList extends PureComponent { onSelect={this.props.selectRecipient} selectedAddress={this.props.selectedAddress} /> - { - showLoadMore && ( - - ) - } + {showLoadMore && ( + + )} ) } - renderAddressBook () { + renderAddressBook() { const contacts = this.props.searchForContacts() const contactGroups = contacts.reduce((acc, contact) => { @@ -62,8 +60,7 @@ export default class ContactList extends PureComponent { return acc }, {}) - return Object - .entries(contactGroups) + return Object.entries(contactGroups) .sort(([letter1], [letter2]) => { if (letter1 > letter2) { return 1 @@ -83,7 +80,7 @@ export default class ContactList extends PureComponent { )) } - renderMyAccounts () { + renderMyAccounts() { const myAccounts = this.props.searchForMyAccounts() return ( @@ -95,7 +92,7 @@ export default class ContactList extends PureComponent { ) } - render () { + render() { const { children, searchForRecents, @@ -105,10 +102,10 @@ export default class ContactList extends PureComponent { return (
    - { children || null } - { searchForRecents && this.renderRecents() } - { searchForContacts && this.renderAddressBook() } - { searchForMyAccounts && this.renderMyAccounts() } + {children || null} + {searchForRecents && this.renderRecents()} + {searchForContacts && this.renderAddressBook()} + {searchForMyAccounts && this.renderMyAccounts()}
    ) } diff --git a/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js b/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js index 9614b16a9..a50b2eea3 100644 --- a/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js +++ b/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js @@ -4,11 +4,16 @@ import classnames from 'classnames' import Identicon from '../../../ui/identicon' import { ellipsify } from '../../../../pages/send/send.utils' -function addressesEqual (address1, address2) { +function addressesEqual(address1, address2) { return String(address1).toLowerCase() === String(address2).toLowerCase() } -export default function RecipientGroup ({ label, items, onSelect, selectedAddress }) { +export default function RecipientGroup({ + label, + items, + onSelect, + selectedAddress, +}) { if (!items || !items.length) { return null } @@ -20,42 +25,46 @@ export default function RecipientGroup ({ label, items, onSelect, selectedAddres {label} )} - { - items.map(({ address, name }) => ( -
    onSelect(address, name)} - className={classnames({ - 'send__select-recipient-wrapper__group-item': !addressesEqual(address, selectedAddress), - 'send__select-recipient-wrapper__group-item--selected': addressesEqual(address, selectedAddress), - })} - > - -
    -
    - {name || ellipsify(address)} -
    - { - name && ( -
    - {ellipsify(address)} -
    - ) - } + {items.map(({ address, name }) => ( +
    onSelect(address, name)} + className={classnames({ + 'send__select-recipient-wrapper__group-item': !addressesEqual( + address, + selectedAddress, + ), + 'send__select-recipient-wrapper__group-item--selected': addressesEqual( + address, + selectedAddress, + ), + })} + > + +
    +
    + {name || ellipsify(address)}
    + {name && ( +
    + {ellipsify(address)} +
    + )}
    - )) - } +
    + ))}
    ) } RecipientGroup.propTypes = { label: PropTypes.string, - items: PropTypes.arrayOf(PropTypes.shape({ - address: PropTypes.string.isRequired, - name: PropTypes.string, - })), + items: PropTypes.arrayOf( + PropTypes.shape({ + address: PropTypes.string.isRequired, + name: PropTypes.string, + }), + ), onSelect: PropTypes.func.isRequired, selectedAddress: PropTypes.string, } diff --git a/ui/app/components/app/dropdowns/components/dropdown.js b/ui/app/components/app/dropdowns/components/dropdown.js index b0b9cac99..52a4af4ef 100644 --- a/ui/app/components/app/dropdowns/components/dropdown.js +++ b/ui/app/components/app/dropdowns/components/dropdown.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import MenuDroppo from '../../menu-droppo' export class Dropdown extends Component { - render () { + render() { const { containerClassName, isOpen, @@ -18,7 +18,8 @@ export class Dropdown extends Component { borderRadius: '4px', padding: '8px 16px', background: 'rgba(0, 0, 0, 0.8)', - boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', ...innerStyle, + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + ...innerStyle, } return ( @@ -41,7 +42,7 @@ export class Dropdown extends Component { li.dropdown-menu-item { color: rgb(185, 185, 185); } `} - { children } + {children} ) } @@ -62,7 +63,7 @@ Dropdown.propTypes = { } export class DropdownMenuItem extends Component { - render () { + render() { const { onClick, closeMenu, children, style } = this.props return ( @@ -72,7 +73,7 @@ export class DropdownMenuItem extends Component { onClick() closeMenu() }} - style={({ + style={{ listStyle: 'none', padding: '8px 0px', fontSize: '18px', @@ -81,8 +82,9 @@ export class DropdownMenuItem extends Component { display: 'flex', justifyContent: 'flex-start', alignItems: 'center', - color: 'white', ...style, - })} + color: 'white', + ...style, + }} > {children} diff --git a/ui/app/components/app/dropdowns/components/network-dropdown-icon.js b/ui/app/components/app/dropdowns/components/network-dropdown-icon.js index d15212001..2201651b8 100644 --- a/ui/app/components/app/dropdowns/components/network-dropdown-icon.js +++ b/ui/app/components/app/dropdowns/components/network-dropdown-icon.js @@ -1,40 +1,32 @@ import PropTypes from 'prop-types' import React from 'react' -function NetworkDropdownIcon (props) { - const { - backgroundColor, - isSelected, - innerBorder, - diameter, - loading, - } = props +function NetworkDropdownIcon(props) { + const { backgroundColor, isSelected, innerBorder, diameter, loading } = props - return loading - ? ( - + + + ) : ( +
    +
    - - - ) - : ( -
    -
    -
    - ) + /> +
    + ) } NetworkDropdownIcon.defaultProps = { diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index 507e9f3b3..e55f77afc 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -4,15 +4,16 @@ import { connect } from 'react-redux' import { withRouter } from 'react-router-dom' import { compose } from 'redux' import * as actions from '../../../store/actions' -import { - openAlert as displayInvalidCustomNetworkAlert, -} from '../../../ducks/alerts/invalid-custom-network' +import { openAlert as displayInvalidCustomNetworkAlert } from '../../../ducks/alerts/invalid-custom-network' import { NETWORKS_ROUTE, NETWORKS_FORM_ROUTE, } from '../../../helpers/constants/routes' import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../app/scripts/lib/enums' -import { getEnvironmentType, isPrefixedFormattedHexString } from '../../../../../app/scripts/lib/util' +import { + getEnvironmentType, + isPrefixedFormattedHexString, +} from '../../../../../app/scripts/lib/util' import { Dropdown, DropdownMenuItem } from './components/dropdown' import NetworkDropdownIcon from './components/network-dropdown-icon' @@ -26,7 +27,7 @@ const notToggleElementClassnames = [ 'network-component', ] -function mapStateToProps (state) { +function mapStateToProps(state) { return { provider: state.metamask.provider, frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], @@ -34,7 +35,7 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { setProviderType: (type) => { dispatch(actions.setProviderType(type)) @@ -53,11 +54,13 @@ function mapDispatchToProps (dispatch) { dispatch(displayInvalidCustomNetworkAlert(networkName)) }, showConfirmDeleteNetworkModal: ({ target, onConfirm }) => { - return dispatch(actions.showModal({ - name: 'CONFIRM_DELETE_NETWORK', - target, - onConfirm, - })) + return dispatch( + actions.showModal({ + name: 'CONFIRM_DELETE_NETWORK', + target, + onConfirm, + }), + ) }, } } @@ -87,8 +90,11 @@ class NetworkDropdown extends Component { showConfirmDeleteNetworkModal: PropTypes.func.isRequired, } - handleClick (newProviderType) { - const { provider: { type: providerType }, setProviderType } = this.props + handleClick(newProviderType) { + const { + provider: { type: providerType }, + setProviderType, + } = this.props const { metricsEvent } = this.context metricsEvent({ @@ -105,14 +111,13 @@ class NetworkDropdown extends Component { setProviderType(newProviderType) } - renderCustomRpcList (rpcListDetail, provider) { + renderCustomRpcList(rpcListDetail, provider) { const reversedRpcListDetail = rpcListDetail.slice().reverse() return reversedRpcListDetail.map((entry) => { const { rpcUrl, chainId, ticker = 'ETH', nickname = '' } = entry - const isCurrentRpcTarget = ( + const isCurrentRpcTarget = provider.type === 'rpc' && rpcUrl === provider.rpcUrl - ) return ( - { - isCurrentRpcTarget - ? - :
    - } - + {isCurrentRpcTarget ? ( + + ) : ( +
    + )} + {nickname || rpcUrl} - { - isCurrentRpcTarget - ? null - : ( - { - e.stopPropagation() - this.props.showConfirmDeleteNetworkModal({ - target: rpcUrl, - onConfirm: () => undefined, - }) - }} - /> - ) - } + {isCurrentRpcTarget ? null : ( + { + e.stopPropagation() + this.props.showConfirmDeleteNetworkModal({ + target: rpcUrl, + onConfirm: () => undefined, + }) + }} + /> + )}
    ) }) } - getNetworkName () { + getNetworkName() { const { provider } = this.props const providerName = provider.type @@ -191,7 +193,7 @@ class NetworkDropdown extends Component { return name } - render () { + render() { const { provider: { type: providerType, rpcUrl: activeNetwork }, setNetworksTabAddMode, @@ -211,7 +213,9 @@ class NetworkDropdown extends Component { onClickOutside={(event) => { const { classList } = event.target const isInClassList = (className) => classList.contains(className) - const notToggleElementIndex = notToggleElementClassnames.findIndex(isInClassList) + const notToggleElementIndex = notToggleElementClassnames.findIndex( + isInClassList, + ) if (notToggleElementIndex === -1) { this.props.hideNetworkDropdown() @@ -244,18 +248,19 @@ class NetworkDropdown extends Component { onClick={() => this.handleClick('mainnet')} style={{ ...dropdownMenuItemStyle, borderColor: '#038789' }} > - { - providerType === 'mainnet' - ? - :
    - } - + {providerType === 'mainnet' ? ( + + ) : ( +
    + )} + {this.context.t('mainnet')} @@ -267,18 +272,19 @@ class NetworkDropdown extends Component { onClick={() => this.handleClick('ropsten')} style={dropdownMenuItemStyle} > - { - providerType === 'ropsten' - ? - :
    - } - + {providerType === 'ropsten' ? ( + + ) : ( +
    + )} + {this.context.t('ropsten')} @@ -290,18 +296,19 @@ class NetworkDropdown extends Component { onClick={() => this.handleClick('kovan')} style={dropdownMenuItemStyle} > - { - providerType === 'kovan' - ? - :
    - } - + {providerType === 'kovan' ? ( + + ) : ( +
    + )} + {this.context.t('kovan')} @@ -313,18 +320,19 @@ class NetworkDropdown extends Component { onClick={() => this.handleClick('rinkeby')} style={dropdownMenuItemStyle} > - { - providerType === 'rinkeby' - ? - :
    - } - + {providerType === 'rinkeby' ? ( + + ) : ( +
    + )} + {this.context.t('rinkeby')} @@ -336,18 +344,19 @@ class NetworkDropdown extends Component { onClick={() => this.handleClick('goerli')} style={dropdownMenuItemStyle} > - { - providerType === 'goerli' - ? - :
    - } - + {providerType === 'goerli' ? ( + + ) : ( +
    + )} + {this.context.t('goerli')} @@ -367,18 +376,19 @@ class NetworkDropdown extends Component { }} style={dropdownMenuItemStyle} > - { - activeNetwork === 'custom' - ? - :
    - } - + {activeNetwork === 'custom' ? ( + + ) : ( +
    + )} + {this.context.t('customRPC')} diff --git a/ui/app/components/app/dropdowns/simple-dropdown.js b/ui/app/components/app/dropdowns/simple-dropdown.js index a8de50851..a1a97a8b6 100644 --- a/ui/app/components/app/dropdowns/simple-dropdown.js +++ b/ui/app/components/app/dropdowns/simple-dropdown.js @@ -14,7 +14,7 @@ class SimpleDropdown extends Component { isOpen: false, } - getDisplayValue () { + getDisplayValue() { const { selectedOption, options } = this.props const matchesOption = (option) => option.value === selectedOption const matchingOption = options.find(matchesOption) @@ -23,17 +23,17 @@ class SimpleDropdown extends Component { : selectedOption } - handleClose () { + handleClose() { this.setState({ isOpen: false }) } - toggleOpen () { + toggleOpen() { this.setState((prevState) => ({ isOpen: !prevState.isOpen, })) } - renderOptions () { + renderOptions() { const { options, onSelect, selectedOption } = this.props return ( @@ -49,7 +49,8 @@ class SimpleDropdown extends Component { {options.map((option) => (
    { @@ -69,13 +70,15 @@ class SimpleDropdown extends Component { ) } - render () { + render() { const { placeholder } = this.props const { isOpen } = this.state return (
    this.toggleOpen()}> -
    {this.getDisplayValue() || placeholder || 'Select'}
    +
    + {this.getDisplayValue() || placeholder || 'Select'} +
    {isOpen && this.renderOptions()}
    diff --git a/ui/app/components/app/dropdowns/tests/dropdown.test.js b/ui/app/components/app/dropdowns/tests/dropdown.test.js index 20d736800..e362104ba 100644 --- a/ui/app/components/app/dropdowns/tests/dropdown.test.js +++ b/ui/app/components/app/dropdowns/tests/dropdown.test.js @@ -15,8 +15,7 @@ describe('Dropdown', function () { onClick={onClickSpy} style={{ test: 'style' }} closeMenu={closeMenuSpy} - > - , + />, ) }) @@ -33,5 +32,4 @@ describe('Dropdown', function () { assert.equal(onClickSpy.callCount, 1) assert.equal(closeMenuSpy.callCount, 1) }) - }) diff --git a/ui/app/components/app/dropdowns/tests/network-dropdown-icon.test.js b/ui/app/components/app/dropdowns/tests/network-dropdown-icon.test.js index 370ed334f..f0370b148 100644 --- a/ui/app/components/app/dropdowns/tests/network-dropdown-icon.test.js +++ b/ui/app/components/app/dropdowns/tests/network-dropdown-icon.test.js @@ -5,14 +5,14 @@ import NetworkDropdownIcon from '../components/network-dropdown-icon' describe('Network Dropdown Icon', function () { it('adds style props based on props', function () { - const wrapper = shallow(( + const wrapper = shallow( - )) + />, + ) const styleProp = wrapper.find('.menu-icon-circle').children().prop('style') assert.equal(styleProp.background, 'red') assert.equal(styleProp.border, 'none') diff --git a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js index 6897e942a..09bec2615 100644 --- a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js +++ b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js @@ -27,9 +27,7 @@ describe('Network Dropdown', function () { const store = createMockStore(mockState) beforeEach(function () { - wrapper = mountWithRouter( - , - ) + wrapper = mountWithRouter() }) it('checks for network droppo class', function () { @@ -39,7 +37,6 @@ describe('Network Dropdown', function () { it('renders only one child when networkDropdown is false in state', function () { assert.equal(wrapper.children().length, 1) }) - }) describe('NetworkDropdown in appState is true', function () { @@ -47,7 +44,7 @@ describe('Network Dropdown', function () { metamask: { network: '1', provider: { - 'type': 'test', + type: 'test', }, frequentRpcListDetail: [ { chainId: '0x1a', rpcUrl: 'http://localhost:7545' }, @@ -55,15 +52,13 @@ describe('Network Dropdown', function () { ], }, appState: { - 'networkDropdownOpen': true, + networkDropdownOpen: true, }, } const store = createMockStore(mockState) beforeEach(function () { - wrapper = mountWithRouter( - , - ) + wrapper = mountWithRouter() }) it('renders 8 DropDownMenuItems ', function () { @@ -71,31 +66,52 @@ describe('Network Dropdown', function () { }) it('checks background color for first NetworkDropdownIcon', function () { - assert.equal(wrapper.find(NetworkDropdownIcon).at(0).prop('backgroundColor'), '#29B6AF') // Ethereum Mainnet Teal + assert.equal( + wrapper.find(NetworkDropdownIcon).at(0).prop('backgroundColor'), + '#29B6AF', + ) // Ethereum Mainnet Teal }) it('checks background color for second NetworkDropdownIcon', function () { - assert.equal(wrapper.find(NetworkDropdownIcon).at(1).prop('backgroundColor'), '#ff4a8d') // Ropsten Red + assert.equal( + wrapper.find(NetworkDropdownIcon).at(1).prop('backgroundColor'), + '#ff4a8d', + ) // Ropsten Red }) it('checks background color for third NetworkDropdownIcon', function () { - assert.equal(wrapper.find(NetworkDropdownIcon).at(2).prop('backgroundColor'), '#7057ff') // Kovan Purple + assert.equal( + wrapper.find(NetworkDropdownIcon).at(2).prop('backgroundColor'), + '#7057ff', + ) // Kovan Purple }) it('checks background color for fourth NetworkDropdownIcon', function () { - assert.equal(wrapper.find(NetworkDropdownIcon).at(3).prop('backgroundColor'), '#f6c343') // Rinkeby Yellow + assert.equal( + wrapper.find(NetworkDropdownIcon).at(3).prop('backgroundColor'), + '#f6c343', + ) // Rinkeby Yellow }) it('checks background color for fifth NetworkDropdownIcon', function () { - assert.equal(wrapper.find(NetworkDropdownIcon).at(4).prop('backgroundColor'), '#3099f2') // Goerli Blue + assert.equal( + wrapper.find(NetworkDropdownIcon).at(4).prop('backgroundColor'), + '#3099f2', + ) // Goerli Blue }) it('checks background color for sixth NetworkDropdownIcon', function () { - assert.equal(wrapper.find(NetworkDropdownIcon).at(5).prop('backgroundColor'), '#d6d9dc') // "Custom network grey" + assert.equal( + wrapper.find(NetworkDropdownIcon).at(5).prop('backgroundColor'), + '#d6d9dc', + ) // "Custom network grey" }) it('checks dropdown for frequestRPCList from state', function () { - assert.equal(wrapper.find(DropdownMenuItem).at(6).text(), '✓http://localhost:7545') + assert.equal( + wrapper.find(DropdownMenuItem).at(6).text(), + '✓http://localhost:7545', + ) }) }) }) diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js index 5886f75d9..a7c3270d0 100644 --- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js +++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js @@ -26,7 +26,7 @@ export default class AdvancedGasInputs extends Component { minimumGasLimit: Number(MIN_GAS_LIMIT_DEC), } - constructor (props) { + constructor(props) { super(props) this.state = { gasPrice: this.props.customGasPrice, @@ -36,8 +36,11 @@ export default class AdvancedGasInputs extends Component { this.changeGasLimit = debounce(this.changeGasLimit, 500) } - componentDidUpdate (prevProps) { - const { customGasPrice: prevCustomGasPrice, customGasLimit: prevCustomGasLimit } = prevProps + componentDidUpdate(prevProps) { + const { + customGasPrice: prevCustomGasPrice, + customGasLimit: prevCustomGasLimit, + } = prevProps const { customGasPrice, customGasLimit } = this.props const { gasPrice, gasLimit } = this.state @@ -67,7 +70,12 @@ export default class AdvancedGasInputs extends Component { this.props.updateCustomGasPrice(Number(e.target.value)) } - gasPriceError ({ insufficientBalance, customPriceIsSafe, isSpeedUp, gasPrice }) { + gasPriceError({ + insufficientBalance, + customPriceIsSafe, + isSpeedUp, + gasPrice, + }) { const { t } = this.context if (insufficientBalance) { @@ -90,7 +98,7 @@ export default class AdvancedGasInputs extends Component { return {} } - gasLimitError ({ insufficientBalance, gasLimit, minimumGasLimit }) { + gasLimitError({ insufficientBalance, gasLimit, minimumGasLimit }) { const { t } = this.context if (insufficientBalance) { @@ -108,11 +116,19 @@ export default class AdvancedGasInputs extends Component { return {} } - renderGasInput ({ value, onChange, errorComponent, errorType, label, customMessageComponent, tooltipTitle }) { + renderGasInput({ + value, + onChange, + errorComponent, + errorType, + label, + customMessageComponent, + tooltipTitle, + }) { return (
    - { label } + {label} @@ -120,8 +136,10 @@ export default class AdvancedGasInputs extends Component {
    onChange({ target: { value: Math.max(value - 1, 0) } })} + onClick={() => + onChange({ target: { value: Math.max(value - 1, 0) } }) + } >
    - { errorComponent || customMessageComponent } + {errorComponent || customMessageComponent}
    ) } - render () { + render() { const { insufficientBalance, customPriceIsSafe, @@ -161,18 +186,22 @@ export default class AdvancedGasInputs extends Component { customGasLimitMessage, minimumGasLimit, } = this.props - const { - gasPrice, - gasLimit, - } = this.state + const { gasPrice, gasLimit } = this.state const { errorText: gasPriceErrorText, errorType: gasPriceErrorType, - } = this.gasPriceError({ insufficientBalance, customPriceIsSafe, isSpeedUp, gasPrice }) + } = this.gasPriceError({ + insufficientBalance, + customPriceIsSafe, + isSpeedUp, + gasPrice, + }) const gasPriceErrorComponent = gasPriceErrorType ? ( -
    - { gasPriceErrorText } +
    + {gasPriceErrorText}
    ) : null @@ -181,30 +210,30 @@ export default class AdvancedGasInputs extends Component { errorType: gasLimitErrorType, } = this.gasLimitError({ insufficientBalance, gasLimit, minimumGasLimit }) const gasLimitErrorComponent = gasLimitErrorType ? ( -
    - { gasLimitErrorText } +
    + {gasLimitErrorText}
    ) : null - const gasLimitCustomMessageComponent = customGasLimitMessage - ? ( -
    - { customGasLimitMessage } -
    - ) - : null + const gasLimitCustomMessageComponent = customGasLimitMessage ? ( +
    + {customGasLimitMessage} +
    + ) : null return (
    - { this.renderGasInput({ + {this.renderGasInput({ label: this.context.t('gasPrice'), tooltipTitle: this.context.t('gasPriceInfoTooltipContent'), value: this.state.gasPrice, onChange: this.onChangeGasPrice, errorComponent: gasPriceErrorComponent, errorType: gasPriceErrorType, - }) } - { this.renderGasInput({ + })} + {this.renderGasInput({ label: this.context.t('gasLimit'), tooltipTitle: this.context.t('gasLimitInfoTooltipContent'), value: this.state.gasLimit, @@ -212,7 +241,7 @@ export default class AdvancedGasInputs extends Component { errorComponent: gasLimitErrorComponent, customMessageComponent: gasLimitCustomMessageComponent, errorType: gasLimitErrorType, - }) } + })}
    ) } diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js index 2b17a7847..949f23fea 100644 --- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js +++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js @@ -6,23 +6,29 @@ import { } from '../../../../helpers/utils/conversions.util' import AdvancedGasInputs from './advanced-gas-inputs.component' -function convertGasPriceForInputs (gasPriceInHexWEI) { +function convertGasPriceForInputs(gasPriceInHexWEI) { return Number(hexWEIToDecGWEI(gasPriceInHexWEI)) } -function convertGasLimitForInputs (gasLimitInHexWEI) { +function convertGasLimitForInputs(gasLimitInHexWEI) { return parseInt(gasLimitInHexWEI, 16) || 0 } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { customGasPrice, customGasLimit, updateCustomGasPrice, updateCustomGasLimit } = ownProps + const { + customGasPrice, + customGasLimit, + updateCustomGasPrice, + updateCustomGasLimit, + } = ownProps return { ...ownProps, ...stateProps, ...dispatchProps, customGasPrice: convertGasPriceForInputs(customGasPrice), customGasLimit: convertGasLimitForInputs(customGasLimit), - updateCustomGasPrice: (price) => updateCustomGasPrice(decGWEIToHexWEI(price)), + updateCustomGasPrice: (price) => + updateCustomGasPrice(decGWEIToHexWEI(price)), updateCustomGasLimit: (limit) => updateCustomGasLimit(decimalToHex(limit)), } } diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/tests/advanced-gas-input-component.test.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/tests/advanced-gas-input-component.test.js index b47a224a6..161237c90 100644 --- a/ui/app/components/app/gas-customization/advanced-gas-inputs/tests/advanced-gas-input-component.test.js +++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/tests/advanced-gas-input-component.test.js @@ -23,15 +23,11 @@ describe('Advanced Gas Inputs', function () { beforeEach(function () { clock = sinon.useFakeTimers() - wrapper = mount( - , { - context: { - t: (str) => str, - }, + wrapper = mount(, { + context: { + t: (str) => str, }, - ) + }) }) afterEach(function () { @@ -78,7 +74,9 @@ describe('Advanced Gas Inputs', function () { it('errors when insufficientBalance under gas price and gas limit', function () { wrapper.setProps({ insufficientBalance: true }) - const renderError = wrapper.find('.advanced-gas-inputs__gas-edit-row__error-text') + const renderError = wrapper.find( + '.advanced-gas-inputs__gas-edit-row__error-text', + ) assert.equal(renderError.length, 2) assert.equal(renderError.at(0).text(), 'insufficientBalance') @@ -88,7 +86,9 @@ describe('Advanced Gas Inputs', function () { it('errors zero gas price / speed up', function () { wrapper.setProps({ isSpeedUp: true }) - const renderError = wrapper.find('.advanced-gas-inputs__gas-edit-row__error-text') + const renderError = wrapper.find( + '.advanced-gas-inputs__gas-edit-row__error-text', + ) assert.equal(renderError.length, 2) assert.equal(renderError.at(0).text(), 'zeroGasPriceOnSpeedUpError') @@ -98,7 +98,9 @@ describe('Advanced Gas Inputs', function () { it('warns when custom gas price is too low', function () { wrapper.setProps({ customPriceIsSafe: false }) - const renderWarning = wrapper.find('.advanced-gas-inputs__gas-edit-row__warning-text') + const renderWarning = wrapper.find( + '.advanced-gas-inputs__gas-edit-row__warning-text', + ) assert.equal(renderWarning.length, 1) assert.equal(renderWarning.text(), 'gasPriceExtremelyLow') diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js index 176fd9b12..2af146562 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js @@ -1,8 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { - decGWEIToHexWEI, -} from '../../../../../helpers/utils/conversions.util' +import { decGWEIToHexWEI } from '../../../../../helpers/utils/conversions.util' import Loading from '../../../../ui/loading-screen' import GasPriceChart from '../../gas-price-chart' import AdvancedGasInputs from '../../advanced-gas-inputs' @@ -30,18 +28,20 @@ export default class AdvancedTabContent extends Component { minimumGasLimit: PropTypes.number.isRequired, } - renderDataSummary (transactionFee, timeRemaining) { + renderDataSummary(transactionFee, timeRemaining) { return (
    - { this.context.t('newTransactionFee') } - ~{ this.context.t('transactionTime') } + {this.context.t('newTransactionFee')} + ~{this.context.t('transactionTime')}
    {transactionFee}
    -
    {timeRemaining}
    +
    + {timeRemaining} +
    ) @@ -52,7 +52,7 @@ export default class AdvancedTabContent extends Component { updateCustomGasPrice(decGWEIToHexWEI(price)) } - render () { + render() { const { t } = this.context const { updateCustomGasPrice, @@ -73,7 +73,7 @@ export default class AdvancedTabContent extends Component { return (
    - { this.renderDataSummary(transactionFee, timeRemaining) } + {this.renderDataSummary(transactionFee, timeRemaining)}
    - { isEthereumNetwork - ? ( -
    -
    { t('liveGasPricePredictions') }
    - {gasEstimatesLoading - ? - : - } -
    - { t('slower') } - { t('faster') } -
    + {isEthereumNetwork ? ( +
    +
    + {t('liveGasPricePredictions')}
    - ) - :
    { t('chartOnlyAvailableEth') }
    - } + {gasEstimatesLoading ? ( + + ) : ( + + )} +
    + {t('slower')} + {t('faster')} +
    +
    + ) : ( +
    + {t('chartOnlyAvailableEth')} +
    + )}
    ) diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js index 4668ced0b..26ba4813e 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js @@ -17,7 +17,7 @@ describe('AdvancedTabContent Component', function () { } sinon.spy(AdvancedTabContent.prototype, 'renderDataSummary') - wrapper = shallow(( + wrapper = shallow( - )) + />, + ) }) afterEach(function () { @@ -46,14 +46,28 @@ describe('AdvancedTabContent Component', function () { const advancedTabChildren = wrapper.children() assert.equal(advancedTabChildren.length, 2) - assert(advancedTabChildren.at(0).hasClass('advanced-tab__transaction-data-summary')) + assert( + advancedTabChildren + .at(0) + .hasClass('advanced-tab__transaction-data-summary'), + ) assert(advancedTabChildren.at(1).hasClass('advanced-tab__fee-chart')) const feeChartDiv = advancedTabChildren.at(1) - assert(feeChartDiv.childAt(1).childAt(0).hasClass('advanced-tab__fee-chart__title')) + assert( + feeChartDiv + .childAt(1) + .childAt(0) + .hasClass('advanced-tab__fee-chart__title'), + ) assert(feeChartDiv.childAt(1).childAt(1).is(GasPriceChart)) - assert(feeChartDiv.childAt(1).childAt(2).hasClass('advanced-tab__fee-chart__speed-buttons')) + assert( + feeChartDiv + .childAt(1) + .childAt(2) + .hasClass('advanced-tab__fee-chart__speed-buttons'), + ) }) it('should render a loading component instead of the chart if gasEstimatesLoading is true', function () { @@ -61,18 +75,34 @@ describe('AdvancedTabContent Component', function () { const advancedTabChildren = wrapper.children() assert.equal(advancedTabChildren.length, 2) - assert(advancedTabChildren.at(0).hasClass('advanced-tab__transaction-data-summary')) + assert( + advancedTabChildren + .at(0) + .hasClass('advanced-tab__transaction-data-summary'), + ) assert(advancedTabChildren.at(1).hasClass('advanced-tab__fee-chart')) const feeChartDiv = advancedTabChildren.at(1) - assert(feeChartDiv.childAt(1).childAt(0).hasClass('advanced-tab__fee-chart__title')) + assert( + feeChartDiv + .childAt(1) + .childAt(0) + .hasClass('advanced-tab__fee-chart__title'), + ) assert(feeChartDiv.childAt(1).childAt(1).is(Loading)) - assert(feeChartDiv.childAt(1).childAt(2).hasClass('advanced-tab__fee-chart__speed-buttons')) + assert( + feeChartDiv + .childAt(1) + .childAt(2) + .hasClass('advanced-tab__fee-chart__speed-buttons'), + ) }) it('should call renderDataSummary with the expected params', function () { - const renderDataSummaryArgs = AdvancedTabContent.prototype.renderDataSummary.getCall(0).args + const renderDataSummaryArgs = AdvancedTabContent.prototype.renderDataSummary.getCall( + 0, + ).args assert.deepEqual(renderDataSummaryArgs, ['$0.25', 21500]) }) }) @@ -81,7 +111,9 @@ describe('AdvancedTabContent Component', function () { let dataSummary beforeEach(function () { - dataSummary = shallow(wrapper.instance().renderDataSummary('mockTotalFee', 'mockMsRemaining')) + dataSummary = shallow( + wrapper.instance().renderDataSummary('mockTotalFee', 'mockMsRemaining'), + ) }) it('should render the transaction-data-summary root node', function () { @@ -90,18 +122,26 @@ describe('AdvancedTabContent Component', function () { it('should render titles of the data', function () { const titlesNode = dataSummary.children().at(0) - assert(titlesNode.hasClass('advanced-tab__transaction-data-summary__titles')) + assert( + titlesNode.hasClass('advanced-tab__transaction-data-summary__titles'), + ) assert.equal(titlesNode.children().at(0).text(), 'newTransactionFee') assert.equal(titlesNode.children().at(1).text(), '~transactionTime') }) it('should render the data', function () { const dataNode = dataSummary.children().at(1) - assert(dataNode.hasClass('advanced-tab__transaction-data-summary__container')) + assert( + dataNode.hasClass('advanced-tab__transaction-data-summary__container'), + ) assert.equal(dataNode.children().at(0).text(), 'mockTotalFee') - assert(dataNode.children().at(1).hasClass('advanced-tab__transaction-data-summary__time-remaining')) + assert( + dataNode + .children() + .at(1) + .hasClass('advanced-tab__transaction-data-summary__time-remaining'), + ) assert.equal(dataNode.children().at(1).text(), 'mockMsRemaining') }) }) - }) diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js index 5a80e4c98..7ef85e7a4 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js @@ -12,25 +12,30 @@ export default class BasicTabContent extends Component { gasPriceButtonGroupProps: PropTypes.object, } - render () { + render() { const { t } = this.context const { gasPriceButtonGroupProps } = this.props return (
    -
    { t('estimatedProcessingTimes') }
    -
    { t('selectAHigherGasFee') }
    - {gasPriceButtonGroupProps.loading - ? - : ( - - ) - } -
    { t('acceleratingATransaction') }
    +
    + {t('estimatedProcessingTimes')} +
    +
    + {t('selectAHigherGasFee')} +
    + {gasPriceButtonGroupProps.loading ? ( + + ) : ( + + )} +
    + {t('acceleratingATransaction')} +
    ) } diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js index f8cec8a0c..388dd97b2 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js @@ -42,15 +42,20 @@ describe('BasicTabContent Component', function () { let wrapper beforeEach(function () { - wrapper = shallow(( + wrapper = shallow( - )) + />, + ) }) it('should have a title', function () { - assert(wrapper.find('.basic-tab-content').childAt(0).hasClass('basic-tab-content__title')) + assert( + wrapper + .find('.basic-tab-content') + .childAt(0) + .hasClass('basic-tab-content__title'), + ) }) it('should render a GasPriceButtonGroup compenent', function () { @@ -67,17 +72,32 @@ describe('BasicTabContent Component', function () { showCheck, } = wrapper.find(GasPriceButtonGroup).props() assert.equal(wrapper.find(GasPriceButtonGroup).length, 1) - assert.equal(buttonDataLoading, mockGasPriceButtonGroupProps.buttonDataLoading) + assert.equal( + buttonDataLoading, + mockGasPriceButtonGroupProps.buttonDataLoading, + ) assert.equal(className, mockGasPriceButtonGroupProps.className) - assert.equal(noButtonActiveByDefault, mockGasPriceButtonGroupProps.noButtonActiveByDefault) + assert.equal( + noButtonActiveByDefault, + mockGasPriceButtonGroupProps.noButtonActiveByDefault, + ) assert.equal(showCheck, mockGasPriceButtonGroupProps.showCheck) - assert.deepEqual(gasButtonInfo, mockGasPriceButtonGroupProps.gasButtonInfo) - assert.equal(JSON.stringify(handleGasPriceSelection), JSON.stringify(mockGasPriceButtonGroupProps.handleGasPriceSelection)) + assert.deepEqual( + gasButtonInfo, + mockGasPriceButtonGroupProps.gasButtonInfo, + ) + assert.equal( + JSON.stringify(handleGasPriceSelection), + JSON.stringify(mockGasPriceButtonGroupProps.handleGasPriceSelection), + ) }) it('should render a loading component instead of the GasPriceButtonGroup if gasPriceButtonGroupProps.loading is true', function () { wrapper.setProps({ - gasPriceButtonGroupProps: { ...mockGasPriceButtonGroupProps, loading: true }, + gasPriceButtonGroupProps: { + ...mockGasPriceButtonGroupProps, + loading: true, + }, }) assert.equal(wrapper.find(GasPriceButtonGroup).length, 0) diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js index 58aa30a87..13e77bb90 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js @@ -3,9 +3,7 @@ import PropTypes from 'prop-types' import PageContainer from '../../../ui/page-container' import { Tabs, Tab } from '../../../ui/tabs' import { calcGasTotal } from '../../../../pages/send/send.utils' -import { - sumHexWEIsToRenderableFiat, -} from '../../../../helpers/utils/conversions.util' +import { sumHexWEIsToRenderableFiat } from '../../../../helpers/utils/conversions.util' import AdvancedTabContent from './advanced-tab-content' import BasicTabContent from './basic-tab-content' @@ -34,16 +32,16 @@ export default class GasModalPageContainer extends Component { newTotalEth: PropTypes.string, sendAmount: PropTypes.string, transactionFee: PropTypes.string, - extraInfoRow: PropTypes.shape({ label: PropTypes.string, value: PropTypes.string }), + extraInfoRow: PropTypes.shape({ + label: PropTypes.string, + value: PropTypes.string, + }), }), onSubmit: PropTypes.func, customModalGasPriceInHex: PropTypes.string, customModalGasLimitInHex: PropTypes.string, cancelAndClose: PropTypes.func, - blockTime: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), + blockTime: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), customPriceIsSafe: PropTypes.bool, isSpeedUp: PropTypes.bool, isRetry: PropTypes.bool, @@ -61,27 +59,25 @@ export default class GasModalPageContainer extends Component { selectedTab: 'Basic', } - componentDidMount () { + componentDidMount() { const promise = this.props.hideBasic ? Promise.resolve(this.props.blockTime) - : this.props.fetchBasicGasAndTimeEstimates() - .then((basicEstimates) => basicEstimates.blockTime) + : this.props + .fetchBasicGasAndTimeEstimates() + .then((basicEstimates) => basicEstimates.blockTime) - promise - .then((blockTime) => { - this.props.fetchGasEstimates(blockTime) - }) + promise.then((blockTime) => { + this.props.fetchGasEstimates(blockTime) + }) } - renderBasicTabContent (gasPriceButtonGroupProps) { + renderBasicTabContent(gasPriceButtonGroupProps) { return ( - + ) } - renderAdvancedTabContent () { + renderAdvancedTabContent() { const { updateCustomGasPrice, updateCustomGasLimit, @@ -94,9 +90,7 @@ export default class GasModalPageContainer extends Component { customPriceIsSafe, isSpeedUp, isRetry, - infoRowProps: { - transactionFee, - }, + infoRowProps: { transactionFee }, isEthereumNetwork, customGasLimitMessage, minimumGasLimit, @@ -123,37 +117,61 @@ export default class GasModalPageContainer extends Component { ) } - renderInfoRows (newTotalFiat, newTotalEth, sendAmount, transactionFee, extraInfoRow) { + renderInfoRows( + newTotalFiat, + newTotalEth, + sendAmount, + transactionFee, + extraInfoRow, + ) { return (
    - {this.context.t('sendAmount')} - {sendAmount} + + {this.context.t('sendAmount')} + + + {sendAmount} +
    - {this.context.t('transactionFee')} - {transactionFee} + + {this.context.t('transactionFee')} + + + {transactionFee} +
    {extraInfoRow && (
    - {extraInfoRow.label} - {extraInfoRow.value} + + {extraInfoRow.label} + + + {extraInfoRow.value} +
    )}
    - {this.context.t('newTotal')} - {newTotalEth} + + {this.context.t('newTotal')} + + + {newTotalEth} +
    - {newTotalFiat} + + {newTotalFiat} +
    ) } - renderTabs () { + renderTabs() { const { gasPriceButtonGroupProps, hideBasic, @@ -186,8 +204,14 @@ export default class GasModalPageContainer extends Component { {tabsToRender.map(({ name, content }, i) => (
    - { content } - { this.renderInfoRows(newTotalFiat, newTotalEth, sendAmount, transactionFee, extraInfoRow) } + {content} + {this.renderInfoRows( + newTotalFiat, + newTotalEth, + sendAmount, + transactionFee, + extraInfoRow, + )}
    ))} @@ -195,7 +219,7 @@ export default class GasModalPageContainer extends Component { ) } - render () { + render() { const { cancelAndClose, onSubmit, @@ -225,11 +249,17 @@ export default class GasModalPageContainer extends Component { }) } if (this.props.isSwap) { - const newSwapGasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) + const newSwapGasTotal = calcGasTotal( + customModalGasLimitInHex, + customModalGasPriceInHex, + ) let speedSet = '' if (this.state.selectedTab === 'Basic') { const { gasButtonInfo } = this.props.gasPriceButtonGroupProps - const selectedGasButtonInfo = gasButtonInfo.find(({ priceInHexWei }) => priceInHexWei === customModalGasPriceInHex) + const selectedGasButtonInfo = gasButtonInfo.find( + ({ priceInHexWei }) => + priceInHexWei === customModalGasPriceInHex, + ) speedSet = selectedGasButtonInfo?.gasEstimateType || '' } @@ -239,11 +269,24 @@ export default class GasModalPageContainer extends Component { properties: { speed_set: speedSet, gas_mode: this.state.selectedTab, - gas_fees: sumHexWEIsToRenderableFiat([this.props.value, newSwapGasTotal, this.props.customTotalSupplement], 'usd', this.props.conversionRate)?.slice(1), + gas_fees: sumHexWEIsToRenderableFiat( + [ + this.props.value, + newSwapGasTotal, + this.props.customTotalSupplement, + ], + 'usd', + this.props.conversionRate, + )?.slice(1), }, }) } - onSubmit(customModalGasLimitInHex, customModalGasPriceInHex, this.state.selectedTab, this.context.mixPanelTrack) + onSubmit( + customModalGasLimitInHex, + customModalGasPriceInHex, + this.state.selectedTab, + this.context.mixPanelTrack, + ) }} submitText={this.context.t('save')} headerCloseText={this.context.t('close')} diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index 2be9e0067..7b8fd9d33 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -55,9 +55,7 @@ import { sumHexWEIsToRenderableFiat, } from '../../../../helpers/utils/conversions.util' import { getRenderableTimeEstimate } from '../../../../helpers/utils/gas-time-estimates.util' -import { - formatETHFee, -} from '../../../../helpers/utils/formatters' +import { formatETHFee } from '../../../../helpers/utils/formatters' import { calcGasTotal, isBalanceSufficient, @@ -81,7 +79,9 @@ const mapStateToProps = (state, ownProps) => { const { transaction = {} } = ownProps const selectedTransaction = isSwap ? txData - : currentNetworkTxList.find(({ id }) => id === (transaction.id || txData.id)) + : currentNetworkTxList.find( + ({ id }) => id === (transaction.id || txData.id), + ) const buttonDataLoading = getBasicGasEstimateLoadingStatus(state) const gasEstimatesLoading = getGasEstimatesLoadingStatus(state) const sendToken = getSendToken(state) @@ -90,17 +90,25 @@ const mapStateToProps = (state, ownProps) => { const txParams = selectedTransaction?.txParams ? selectedTransaction.txParams : { - gas: send.gasLimit || '0x5208', - gasPrice: send.gasPrice || getFastPriceEstimateInHexWEI(state, true), - value: sendToken ? '0x0' : send.amount, - } + gas: send.gasLimit || '0x5208', + gasPrice: send.gasPrice || getFastPriceEstimateInHexWEI(state, true), + value: sendToken ? '0x0' : send.amount, + } const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = txParams const customModalGasPriceInHex = getCustomGasPrice(state) || currentGasPrice - const customModalGasLimitInHex = getCustomGasLimit(state) || currentGasLimit || '0x5208' - const customGasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) + const customModalGasLimitInHex = + getCustomGasLimit(state) || currentGasLimit || '0x5208' + const customGasTotal = calcGasTotal( + customModalGasLimitInHex, + customModalGasPriceInHex, + ) - const gasButtonInfo = getRenderableBasicEstimateData(state, customModalGasLimitInHex, useFastestButtons) + const gasButtonInfo = getRenderableBasicEstimateData( + state, + customModalGasLimitInHex, + useFastestButtons, + ) const currentCurrency = getCurrentCurrency(state) const conversionRate = getConversionRate(state) @@ -126,24 +134,36 @@ const mapStateToProps = (state, ownProps) => { const isSendTokenSet = Boolean(sendToken) - const newTotalEth = maxModeOn && !isSendTokenSet - ? sumHexWEIsToRenderableEth([balance, '0x0']) - : sumHexWEIsToRenderableEth([value, customGasTotal, customTotalSupplement]) + const newTotalEth = + maxModeOn && !isSendTokenSet + ? sumHexWEIsToRenderableEth([balance, '0x0']) + : sumHexWEIsToRenderableEth([ + value, + customGasTotal, + customTotalSupplement, + ]) - const sendAmount = maxModeOn && !isSendTokenSet - ? subtractHexWEIsFromRenderableEth(balance, customGasTotal) - : sumHexWEIsToRenderableEth([value, '0x0']) + const sendAmount = + maxModeOn && !isSendTokenSet + ? subtractHexWEIsFromRenderableEth(balance, customGasTotal) + : sumHexWEIsToRenderableEth([value, '0x0']) - const insufficientBalance = maxModeOn ? false : !isBalanceSufficient({ - amount: value, - gasTotal: customGasTotal, - balance, - conversionRate, - }) + const insufficientBalance = maxModeOn + ? false + : !isBalanceSufficient({ + amount: value, + gasTotal: customGasTotal, + balance, + conversionRate, + }) let currentTimeEstimate = '' try { - currentTimeEstimate = getRenderableTimeEstimate(customGasPrice, gasPrices, estimatedTimes) + currentTimeEstimate = getRenderableTimeEstimate( + customGasPrice, + gasPrices, + estimatedTimes, + ) } catch (error) { captureException(error) } @@ -164,7 +184,10 @@ const mapStateToProps = (state, ownProps) => { maxModeOn, gasPriceButtonGroupProps: { buttonDataLoading, - defaultActiveButtonIndex: getDefaultActiveButtonIndex(gasButtonInfo, customModalGasPriceInHex), + defaultActiveButtonIndex: getDefaultActiveButtonIndex( + gasButtonInfo, + customModalGasPriceInHex, + ), gasButtonInfo, }, gasChartProps: { @@ -180,9 +203,11 @@ const mapStateToProps = (state, ownProps) => { currentCurrency, conversionRate, ), - originalTotalEth: sumHexWEIsToRenderableEth( - [value, customGasTotal, customTotalSupplement], - ), + originalTotalEth: sumHexWEIsToRenderableEth([ + value, + customGasTotal, + customTotalSupplement, + ]), newTotalFiat: showFiat ? newTotalFiat : '', newTotalEth, transactionFee: sumHexWEIsToRenderableEth(['0x0', customGasTotal]), @@ -209,7 +234,8 @@ const mapStateToProps = (state, ownProps) => { } const mapDispatchToProps = (dispatch) => { - const updateCustomGasPrice = (newPrice) => dispatch(setCustomGasPrice(addHexPrefix(newPrice))) + const updateCustomGasPrice = (newPrice) => + dispatch(setCustomGasPrice(addHexPrefix(newPrice))) return { cancelAndClose: () => { @@ -218,7 +244,8 @@ const mapDispatchToProps = (dispatch) => { }, hideModal: () => dispatch(hideModal()), updateCustomGasPrice, - updateCustomGasLimit: (newLimit) => dispatch(setCustomGasLimit(addHexPrefix(newLimit))), + updateCustomGasLimit: (newLimit) => + dispatch(setCustomGasLimit(addHexPrefix(newLimit))), setGasData: (newLimit, newPrice) => { dispatch(setGasLimit(newLimit)) dispatch(setGasPrice(newPrice)) @@ -237,7 +264,8 @@ const mapDispatchToProps = (dispatch) => { hideGasButtonGroup: () => dispatch(hideGasButtonGroup()), hideSidebar: () => dispatch(hideSidebar()), fetchGasEstimates: (blockTime) => dispatch(fetchGasEstimates(blockTime)), - fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()), + fetchBasicGasAndTimeEstimates: () => + dispatch(fetchBasicGasAndTimeEstimates()), setGasTotal: (total) => dispatch(setGasTotal(total)), setAmountToMax: (maxAmountDataObject) => { dispatch(updateSendErrors({ amount: null })) @@ -334,37 +362,42 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { dispatchHideSidebar() } }, - disableSave: ( + disableSave: insufficientBalance || (isSpeedUp && customGasPrice === 0) || - customGasLimit < minimumGasLimit - ), + customGasLimit < minimumGasLimit, } } -export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(GasModalPageContainer) +export default connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(GasModalPageContainer) -function isConfirm (state) { +function isConfirm(state) { return Boolean(Object.keys(state.confirmTransaction.txData).length) } -function calcCustomGasPrice (customGasPriceInHex) { +function calcCustomGasPrice(customGasPriceInHex) { return Number(hexWEIToDecGWEI(customGasPriceInHex)) } -function calcCustomGasLimit (customGasLimitInHex) { +function calcCustomGasLimit(customGasLimitInHex) { return parseInt(customGasLimitInHex, 16) } -function sumHexWEIsToRenderableEth (hexWEIs) { +function sumHexWEIsToRenderableEth(hexWEIs) { const hexWEIsSum = hexWEIs.filter((n) => n).reduce(addHexes) - return formatETHFee(getValueFromWeiHex({ - value: hexWEIsSum, - toCurrency: 'ETH', - numberOfDecimals: 6, - })) + return formatETHFee( + getValueFromWeiHex({ + value: hexWEIsSum, + toCurrency: 'ETH', + numberOfDecimals: 6, + }), + ) } -function subtractHexWEIsFromRenderableEth (aHexWEI, bHexWEI) { +function subtractHexWEIsFromRenderableEth(aHexWEI, bHexWEI) { return formatETHFee(subtractHexWEIsToDec(aHexWEI, bHexWEI)) } diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js index ef1d1e311..efcb53768 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js @@ -16,7 +16,9 @@ const mockBasicGasEstimates = { const propsMethodSpies = { cancelAndClose: sinon.spy(), onSubmit: sinon.spy(), - fetchBasicGasAndTimeEstimates: sinon.stub().returns(Promise.resolve(mockBasicGasEstimates)), + fetchBasicGasAndTimeEstimates: sinon + .stub() + .returns(Promise.resolve(mockBasicGasEstimates)), fetchGasEstimates: sinon.spy(), } @@ -64,11 +66,13 @@ describe('GasModalPageContainer Component', function () { let wrapper beforeEach(function () { - wrapper = shallow(( + wrapper = shallow( 'mockupdateCustomGasPrice'} updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} @@ -81,8 +85,8 @@ describe('GasModalPageContainer Component', function () { customGasLimitInHex="mockCustomGasLimitInHex" insufficientBalance={false} disableSave={false} - /> - )) + />, + ) }) afterEach(function () { @@ -103,7 +107,10 @@ describe('GasModalPageContainer Component', function () { wrapper.instance().componentDidMount() await timeout(250) assert.equal(propsMethodSpies.fetchGasEstimates.callCount, 1) - assert.equal(propsMethodSpies.fetchGasEstimates.getCall(0).args[0], 'mockBlockTime') + assert.equal( + propsMethodSpies.fetchGasEstimates.getCall(0).args[0], + 'mockBlockTime', + ) }) }) @@ -113,21 +120,14 @@ describe('GasModalPageContainer Component', function () { }) it('should pass correct props to PageContainer', function () { - const { - title, - subtitle, - disabled, - } = wrapper.find(PageContainer).props() + const { title, subtitle, disabled } = wrapper.find(PageContainer).props() assert.equal(title, 'customGas') assert.equal(subtitle, 'customGasSubTitle') assert.equal(disabled, false) }) it('should pass the correct onCancel and onClose methods to PageContainer', function () { - const { - onCancel, - onClose, - } = wrapper.find(PageContainer).props() + const { onCancel, onClose } = wrapper.find(PageContainer).props() assert.equal(propsMethodSpies.cancelAndClose.callCount, 0) onCancel() assert.equal(propsMethodSpies.cancelAndClose.callCount, 1) @@ -137,13 +137,18 @@ describe('GasModalPageContainer Component', function () { it('should pass the correct renderTabs property to PageContainer', function () { sinon.stub(GP, 'renderTabs').returns('mockTabs') - const renderTabsWrapperTester = shallow(( + const renderTabsWrapperTester = shallow( - ), { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }) - const { tabsComponent } = renderTabsWrapperTester.find(PageContainer).props() + />, + { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, + ) + const { tabsComponent } = renderTabsWrapperTester + .find(PageContainer) + .props() assert.equal(tabsComponent, 'mockTabs') GasModalPageContainer.prototype.renderTabs.restore() }) @@ -184,16 +189,30 @@ describe('GasModalPageContainer Component', function () { assert.equal(GP.renderInfoRows.callCount, 2) - assert.deepEqual(GP.renderInfoRows.getCall(0).args, ['mockNewTotalFiat', 'mockNewTotalEth', 'mockSendAmount', 'mockTransactionFee', { label: 'mockLabel', value: 'mockValue' }]) - assert.deepEqual(GP.renderInfoRows.getCall(1).args, ['mockNewTotalFiat', 'mockNewTotalEth', 'mockSendAmount', 'mockTransactionFee', { label: 'mockLabel', value: 'mockValue' }]) + assert.deepEqual(GP.renderInfoRows.getCall(0).args, [ + 'mockNewTotalFiat', + 'mockNewTotalEth', + 'mockSendAmount', + 'mockTransactionFee', + { label: 'mockLabel', value: 'mockValue' }, + ]) + assert.deepEqual(GP.renderInfoRows.getCall(1).args, [ + 'mockNewTotalFiat', + 'mockNewTotalEth', + 'mockSendAmount', + 'mockTransactionFee', + { label: 'mockLabel', value: 'mockValue' }, + ]) }) it('should not render the basic tab if hideBasic is true', function () { - wrapper = shallow(( + wrapper = shallow( 'mockupdateCustomGasPrice'} updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} @@ -207,8 +226,8 @@ describe('GasModalPageContainer Component', function () { insufficientBalance={false} disableSave={false} hideBasic - /> - )) + />, + ) const renderTabsResult = wrapper.instance().renderTabs() const renderedTabs = shallow(renderTabsResult) @@ -220,7 +239,9 @@ describe('GasModalPageContainer Component', function () { describe('renderBasicTabContent', function () { it('should render', function () { - const renderBasicTabContentResult = wrapper.instance().renderBasicTabContent(mockGasPriceButtonGroupProps) + const renderBasicTabContentResult = wrapper + .instance() + .renderBasicTabContent(mockGasPriceButtonGroupProps) assert.deepEqual( renderBasicTabContentResult.props.gasPriceButtonGroupProps, @@ -232,24 +253,35 @@ describe('GasModalPageContainer Component', function () { describe('renderInfoRows', function () { it('should render the info rows with the passed data', function () { const baseClassName = 'gas-modal-content__info-row' - const renderedInfoRowsContainer = shallow(wrapper.instance().renderInfoRows( - 'mockNewTotalFiat', - ' mockNewTotalEth', - ' mockSendAmount', - ' mockTransactionFee', - )) + const renderedInfoRowsContainer = shallow( + wrapper + .instance() + .renderInfoRows( + 'mockNewTotalFiat', + ' mockNewTotalEth', + ' mockSendAmount', + ' mockTransactionFee', + ), + ) assert(renderedInfoRowsContainer.childAt(0).hasClass(baseClassName)) const renderedInfoRows = renderedInfoRowsContainer.childAt(0).children() assert.equal(renderedInfoRows.length, 4) assert(renderedInfoRows.at(0).hasClass(`${baseClassName}__send-info`)) - assert(renderedInfoRows.at(1).hasClass(`${baseClassName}__transaction-info`)) + assert( + renderedInfoRows.at(1).hasClass(`${baseClassName}__transaction-info`), + ) assert(renderedInfoRows.at(2).hasClass(`${baseClassName}__total-info`)) - assert(renderedInfoRows.at(3).hasClass(`${baseClassName}__fiat-total-info`)) + assert( + renderedInfoRows.at(3).hasClass(`${baseClassName}__fiat-total-info`), + ) assert.equal(renderedInfoRows.at(0).text(), 'sendAmount mockSendAmount') - assert.equal(renderedInfoRows.at(1).text(), 'transactionFee mockTransactionFee') + assert.equal( + renderedInfoRows.at(1).text(), + 'transactionFee mockTransactionFee', + ) assert.equal(renderedInfoRows.at(2).text(), 'newTotal mockNewTotalEth') assert.equal(renderedInfoRows.at(3).text(), 'mockNewTotalFiat') }) diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js index 00e15f943..d591d2f12 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js @@ -36,8 +36,10 @@ proxyquire('../gas-modal-page-container.container.js', { }, }, '../../../../selectors': { - getBasicGasEstimateLoadingStatus: (s) => `mockBasicGasEstimateLoadingStatus:${Object.keys(s).length}`, - getRenderableBasicEstimateData: (s) => `mockRenderableBasicEstimateData:${Object.keys(s).length}`, + getBasicGasEstimateLoadingStatus: (s) => + `mockBasicGasEstimateLoadingStatus:${Object.keys(s).length}`, + getRenderableBasicEstimateData: (s) => + `mockRenderableBasicEstimateData:${Object.keys(s).length}`, getDefaultActiveButtonIndex: (a, b) => a + b, getCurrentEthBalance: (state) => state.metamask.balance || '0x0', getSendToken: () => null, @@ -50,7 +52,6 @@ proxyquire('../gas-modal-page-container.container.js', { }) describe('gas-modal-page-container container', function () { - describe('mapStateToProps()', function () { it('should map the correct properties to props', function () { const baseMockState = { @@ -83,14 +84,16 @@ describe('gas-modal-page-container container', function () { provider: { type: 'mainnet', }, - currentNetworkTxList: [{ - id: 34, - txParams: { - gas: '0x1600000', - gasPrice: '0x3200000', - value: '0x640000000000000', + currentNetworkTxList: [ + { + id: 34, + txParams: { + gas: '0x1600000', + gasPrice: '0x3200000', + value: '0x640000000000000', + }, }, - }], + ], }, gas: { basicEstimates: { @@ -135,7 +138,7 @@ describe('gas-modal-page-container container', function () { customGasTotal: 'aaaaaaa955555556', customPriceIsSafe: true, gasChartProps: { - 'currentPrice': 4.294967295, + currentPrice: 4.294967295, estimatedTimes: [31, 62, 93, 124], estimatedTimesMax: 31, gasPrices: [3, 4, 5, 6], @@ -175,16 +178,37 @@ describe('gas-modal-page-container container', function () { } const baseMockOwnProps = { transaction: { id: 34 } } const tests = [ - { mockState: baseMockState, expectedResult: baseExpectedResult, mockOwnProps: baseMockOwnProps }, { - mockState: { ...baseMockState, metamask: { ...baseMockState.metamask, balance: '0xfffffffffffffffffffff' } }, - expectedResult: { ...baseExpectedResult, balance: '0xfffffffffffffffffffff', insufficientBalance: false }, + mockState: baseMockState, + expectedResult: baseExpectedResult, + mockOwnProps: baseMockOwnProps, + }, + { + mockState: { + ...baseMockState, + metamask: { + ...baseMockState.metamask, + balance: '0xfffffffffffffffffffff', + }, + }, + expectedResult: { + ...baseExpectedResult, + balance: '0xfffffffffffffffffffff', + insufficientBalance: false, + }, mockOwnProps: baseMockOwnProps, }, { mockState: baseMockState, - mockOwnProps: { ...baseMockOwnProps, transaction: { id: 34, status: 'submitted' } }, - expectedResult: { ...baseExpectedResult, isSpeedUp: true, transaction: { id: 34 } }, + mockOwnProps: { + ...baseMockOwnProps, + transaction: { id: 34, status: 'submitted' }, + }, + expectedResult: { + ...baseExpectedResult, + isSpeedUp: true, + transaction: { id: 34 }, + }, }, { mockState: { @@ -258,7 +282,6 @@ describe('gas-modal-page-container container', function () { assert.deepEqual(result, expectedResult) }) }) - }) describe('mapDispatchToProps()', function () { @@ -298,14 +321,20 @@ describe('gas-modal-page-container container', function () { mapDispatchToPropsObject.updateCustomGasPrice('ffff') assert(dispatchSpy.calledOnce) assert(gasActionSpies.setCustomGasPrice.calledOnce) - assert.equal(gasActionSpies.setCustomGasPrice.getCall(0).args[0], '0xffff') + assert.equal( + gasActionSpies.setCustomGasPrice.getCall(0).args[0], + '0xffff', + ) }) it('should dispatch a setCustomGasPrice action', function () { mapDispatchToPropsObject.updateCustomGasPrice('0xffff') assert(dispatchSpy.calledOnce) assert(gasActionSpies.setCustomGasPrice.calledOnce) - assert.equal(gasActionSpies.setCustomGasPrice.getCall(0).args[0], '0xffff') + assert.equal( + gasActionSpies.setCustomGasPrice.getCall(0).args[0], + '0xffff', + ) }) }) @@ -314,7 +343,10 @@ describe('gas-modal-page-container container', function () { mapDispatchToPropsObject.updateCustomGasLimit('0x10') assert(dispatchSpy.calledOnce) assert(gasActionSpies.setCustomGasLimit.calledOnce) - assert.equal(gasActionSpies.setCustomGasLimit.getCall(0).args[0], '0x10') + assert.equal( + gasActionSpies.setCustomGasLimit.getCall(0).args[0], + '0x10', + ) }) }) @@ -339,7 +371,6 @@ describe('gas-modal-page-container container', function () { assert.equal(actionSpies.setGasPrice.getCall(0).args[0], 'aaaa') }) }) - }) describe('mergeProps', function () { @@ -386,8 +417,14 @@ describe('gas-modal-page-container container', function () { assert.equal(result.isConfirm, true) assert.equal(result.someOtherStateProp, 'baz') - assert.equal(result.gasPriceButtonGroupProps.someGasPriceButtonGroupProp, 'foo') - assert.equal(result.gasPriceButtonGroupProps.anotherGasPriceButtonGroupProp, 'bar') + assert.equal( + result.gasPriceButtonGroupProps.someGasPriceButtonGroupProp, + 'foo', + ) + assert.equal( + result.gasPriceButtonGroupProps.anotherGasPriceButtonGroupProp, + 'bar', + ) assert.equal(result.someOwnProp, 123) assert.equal(dispatchProps.updateConfirmTxGasAndCalculate.callCount, 0) @@ -412,12 +449,22 @@ describe('gas-modal-page-container container', function () { }) it('should return the expected props when isConfirm is false', function () { - const result = mergeProps({ ...stateProps, isConfirm: false }, dispatchProps, ownProps) + const result = mergeProps( + { ...stateProps, isConfirm: false }, + dispatchProps, + ownProps, + ) assert.equal(result.isConfirm, false) assert.equal(result.someOtherStateProp, 'baz') - assert.equal(result.gasPriceButtonGroupProps.someGasPriceButtonGroupProp, 'foo') - assert.equal(result.gasPriceButtonGroupProps.anotherGasPriceButtonGroupProp, 'bar') + assert.equal( + result.gasPriceButtonGroupProps.someGasPriceButtonGroupProp, + 'foo', + ) + assert.equal( + result.gasPriceButtonGroupProps.anotherGasPriceButtonGroupProp, + 'bar', + ) assert.equal(result.someOwnProp, 123) assert.equal(dispatchProps.updateConfirmTxGasAndCalculate.callCount, 0) @@ -429,7 +476,10 @@ describe('gas-modal-page-container container', function () { assert.equal(dispatchProps.updateConfirmTxGasAndCalculate.callCount, 0) assert.equal(dispatchProps.setGasData.callCount, 1) - assert.deepEqual(dispatchProps.setGasData.getCall(0).args, ['mockNewLimit', 'mockNewPrice']) + assert.deepEqual(dispatchProps.setGasData.getCall(0).args, [ + 'mockNewLimit', + 'mockNewPrice', + ]) assert.equal(dispatchProps.hideGasButtonGroup.callCount, 1) assert.equal(dispatchProps.cancelAndClose.callCount, 1) @@ -443,7 +493,11 @@ describe('gas-modal-page-container container', function () { }) it('should dispatch the expected actions from obSubmit when isConfirm is false and isSpeedUp is true', function () { - const result = mergeProps({ ...stateProps, isSpeedUp: true, isConfirm: false }, dispatchProps, ownProps) + const result = mergeProps( + { ...stateProps, isSpeedUp: true, isConfirm: false }, + dispatchProps, + ownProps, + ) result.onSubmit() @@ -456,5 +510,4 @@ describe('gas-modal-page-container container', function () { assert.equal(dispatchProps.hideSidebar.callCount, 1) }) }) - }) diff --git a/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js b/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js index 8cf327013..6630844bb 100644 --- a/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js +++ b/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js @@ -5,7 +5,8 @@ import Button from '../../../ui/button' import { GAS_ESTIMATE_TYPES } from '../../../../helpers/constants/common' const GAS_OBJECT_PROPTYPES_SHAPE = { - gasEstimateType: PropTypes.oneOf(Object.values(GAS_ESTIMATE_TYPES)).isRequired, + gasEstimateType: PropTypes.oneOf(Object.values(GAS_ESTIMATE_TYPES)) + .isRequired, feeInPrimaryCurrency: PropTypes.string, feeInSecondaryCurrency: PropTypes.string, timeEstimate: PropTypes.string, @@ -21,14 +22,16 @@ export default class GasPriceButtonGroup extends Component { buttonDataLoading: PropTypes.bool, className: PropTypes.string, defaultActiveButtonIndex: PropTypes.number, - gasButtonInfo: PropTypes.arrayOf(PropTypes.shape(GAS_OBJECT_PROPTYPES_SHAPE)), + gasButtonInfo: PropTypes.arrayOf( + PropTypes.shape(GAS_OBJECT_PROPTYPES_SHAPE), + ), handleGasPriceSelection: PropTypes.func, newActiveButtonIndex: PropTypes.number, noButtonActiveByDefault: PropTypes.bool, showCheck: PropTypes.bool, } - gasEstimateTypeLabel (gasEstimateType) { + gasEstimateTypeLabel(gasEstimateType) { if (gasEstimateType === GAS_ESTIMATE_TYPES.SLOW) { return this.context.t('slow') } else if (gasEstimateType === GAS_ESTIMATE_TYPES.AVERAGE) { @@ -41,45 +44,67 @@ export default class GasPriceButtonGroup extends Component { throw new Error(`Unrecognized gas estimate type: ${gasEstimateType}`) } - renderButtonContent ({ - gasEstimateType, - feeInPrimaryCurrency, - feeInSecondaryCurrency, - timeEstimate, - }, { - className, - showCheck, - }) { + renderButtonContent( + { + gasEstimateType, + feeInPrimaryCurrency, + feeInSecondaryCurrency, + timeEstimate, + }, + { className, showCheck }, + ) { return (
    - { gasEstimateType &&
    { this.gasEstimateTypeLabel(gasEstimateType) }
    } - { timeEstimate &&
    { timeEstimate }
    } - { feeInPrimaryCurrency &&
    { feeInPrimaryCurrency }
    } - { feeInSecondaryCurrency &&
    { feeInSecondaryCurrency }
    } - { showCheck &&
    } + {gasEstimateType && ( +
    + {this.gasEstimateTypeLabel(gasEstimateType)} +
    + )} + {timeEstimate && ( +
    {timeEstimate}
    + )} + {feeInPrimaryCurrency && ( +
    + {feeInPrimaryCurrency} +
    + )} + {feeInSecondaryCurrency && ( +
    + {feeInSecondaryCurrency} +
    + )} + {showCheck && ( +
    + +
    + )}
    ) } - renderButton ({ - priceInHexWei, - ...renderableGasInfo - }, { - buttonDataLoading: _, - handleGasPriceSelection, - ...buttonContentPropsAndFlags - }, index) { + renderButton( + { priceInHexWei, ...renderableGasInfo }, + { + buttonDataLoading: _, + handleGasPriceSelection, + ...buttonContentPropsAndFlags + }, + index, + ) { return ( ) } - render () { + render() { const { gasButtonInfo, defaultActiveButtonIndex = 1, @@ -89,19 +114,21 @@ export default class GasPriceButtonGroup extends Component { ...buttonPropsAndFlags } = this.props - return ( - buttonDataLoading - ?
    {this.context.t('loading')}
    - : ( - - {gasButtonInfo.map((obj, index) => this.renderButton(obj, buttonPropsAndFlags, index))} - - ) + return buttonDataLoading ? ( +
    + {this.context.t('loading')} +
    + ) : ( + + {gasButtonInfo.map((obj, index) => + this.renderButton(obj, buttonPropsAndFlags, index), + )} + ) } } diff --git a/ui/app/components/app/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js b/ui/app/components/app/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js index 4cd44066c..f8b2ec6b5 100644 --- a/ui/app/components/app/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js +++ b/ui/app/components/app/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js @@ -43,18 +43,15 @@ describe('GasPriceButtonGroup Component', function () { mockButtonPropsAndFlags = { className: mockGasPriceButtonGroupProps.className, - handleGasPriceSelection: mockGasPriceButtonGroupProps.handleGasPriceSelection, + handleGasPriceSelection: + mockGasPriceButtonGroupProps.handleGasPriceSelection, showCheck: mockGasPriceButtonGroupProps.showCheck, } sinon.spy(GasPriceButtonGroup.prototype, 'renderButton') sinon.spy(GasPriceButtonGroup.prototype, 'renderButtonContent') - wrapper = shallow(( - - )) + wrapper = shallow() }) afterEach(function () { @@ -77,7 +74,7 @@ describe('GasPriceButtonGroup Component', function () { assert.equal(noButtonActiveByDefault, true) }) - function renderButtonArgsTest (i, mockPropsAndFlags) { + function renderButtonArgsTest(i, mockPropsAndFlags) { assert.deepEqual( GasPriceButtonGroup.prototype.renderButton.getCall(i).args, [ @@ -120,9 +117,15 @@ describe('GasPriceButtonGroup Component', function () { }) it('should call the correct method when clicked', function () { - assert.equal(mockGasPriceButtonGroupProps.handleGasPriceSelection.callCount, 0) + assert.equal( + mockGasPriceButtonGroupProps.handleGasPriceSelection.callCount, + 0, + ) wrappedRenderButtonResult.props().onClick() - assert.equal(mockGasPriceButtonGroupProps.handleGasPriceSelection.callCount, 1) + assert.equal( + mockGasPriceButtonGroupProps.handleGasPriceSelection.callCount, + 1, + ) assert.deepEqual( mockGasPriceButtonGroupProps.handleGasPriceSelection.getCall(0).args, [mockGasPriceButtonGroupProps.gasButtonInfo[0].priceInHexWei], @@ -130,16 +133,16 @@ describe('GasPriceButtonGroup Component', function () { }) it('should call this.renderButtonContent with the correct args', function () { - assert.equal(GasPriceButtonGroup.prototype.renderButtonContent.callCount, 1) + assert.equal( + GasPriceButtonGroup.prototype.renderButtonContent.callCount, + 1, + ) const { feeInPrimaryCurrency, feeInSecondaryCurrency, timeEstimate, } = mockGasPriceButtonGroupProps.gasButtonInfo[0] - const { - showCheck, - className, - } = mockGasPriceButtonGroupProps + const { showCheck, className } = mockGasPriceButtonGroupProps assert.deepEqual( GasPriceButtonGroup.prototype.renderButtonContent.getCall(0).args, [ @@ -159,75 +162,140 @@ describe('GasPriceButtonGroup Component', function () { describe('renderButtonContent', function () { it('should render a label if passed a gasEstimateType', function () { - const renderButtonContentResult = wrapper.instance().renderButtonContent({ - gasEstimateType: 'SLOW', - }, { - className: 'someClass', - }) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) - assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1) - assert.equal(wrappedRenderButtonContentResult.find('.someClass__label').text(), 'slow') + const renderButtonContentResult = wrapper.instance().renderButtonContent( + { + gasEstimateType: 'SLOW', + }, + { + className: 'someClass', + }, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) + assert.equal( + wrappedRenderButtonContentResult.childAt(0).children().length, + 1, + ) + assert.equal( + wrappedRenderButtonContentResult.find('.someClass__label').text(), + 'slow', + ) }) it('should render a feeInPrimaryCurrency if passed a feeInPrimaryCurrency', function () { - const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({ - feeInPrimaryCurrency: 'mockFeeInPrimaryCurrency', - }, { - className: 'someClass', - }) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) - assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1) - assert.equal(wrappedRenderButtonContentResult.find('.someClass__primary-currency').text(), 'mockFeeInPrimaryCurrency') + const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent( + { + feeInPrimaryCurrency: 'mockFeeInPrimaryCurrency', + }, + { + className: 'someClass', + }, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) + assert.equal( + wrappedRenderButtonContentResult.childAt(0).children().length, + 1, + ) + assert.equal( + wrappedRenderButtonContentResult + .find('.someClass__primary-currency') + .text(), + 'mockFeeInPrimaryCurrency', + ) }) it('should render a feeInSecondaryCurrency if passed a feeInSecondaryCurrency', function () { - const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({ - feeInSecondaryCurrency: 'mockFeeInSecondaryCurrency', - }, { - className: 'someClass', - }) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) - assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1) - assert.equal(wrappedRenderButtonContentResult.find('.someClass__secondary-currency').text(), 'mockFeeInSecondaryCurrency') + const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent( + { + feeInSecondaryCurrency: 'mockFeeInSecondaryCurrency', + }, + { + className: 'someClass', + }, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) + assert.equal( + wrappedRenderButtonContentResult.childAt(0).children().length, + 1, + ) + assert.equal( + wrappedRenderButtonContentResult + .find('.someClass__secondary-currency') + .text(), + 'mockFeeInSecondaryCurrency', + ) }) it('should render a timeEstimate if passed a timeEstimate', function () { - const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({ - timeEstimate: 'mockTimeEstimate', - }, { - className: 'someClass', - }) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) - assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1) - assert.equal(wrappedRenderButtonContentResult.find('.someClass__time-estimate').text(), 'mockTimeEstimate') + const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent( + { + timeEstimate: 'mockTimeEstimate', + }, + { + className: 'someClass', + }, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) + assert.equal( + wrappedRenderButtonContentResult.childAt(0).children().length, + 1, + ) + assert.equal( + wrappedRenderButtonContentResult + .find('.someClass__time-estimate') + .text(), + 'mockTimeEstimate', + ) }) it('should render a check if showCheck is true', function () { - const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({}, { - className: 'someClass', - showCheck: true, - }) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) + const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent( + {}, + { + className: 'someClass', + showCheck: true, + }, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) assert.equal(wrappedRenderButtonContentResult.find('.fa-check').length, 1) }) it('should render all elements if all args passed', function () { - const renderButtonContentResult = wrapper.instance().renderButtonContent({ - gasEstimateType: 'SLOW', - feeInPrimaryCurrency: 'mockFeeInPrimaryCurrency', - feeInSecondaryCurrency: 'mockFeeInSecondaryCurrency', - timeEstimate: 'mockTimeEstimate', - }, { - className: 'someClass', - showCheck: true, - }) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) + const renderButtonContentResult = wrapper.instance().renderButtonContent( + { + gasEstimateType: 'SLOW', + feeInPrimaryCurrency: 'mockFeeInPrimaryCurrency', + feeInSecondaryCurrency: 'mockFeeInSecondaryCurrency', + timeEstimate: 'mockTimeEstimate', + }, + { + className: 'someClass', + showCheck: true, + }, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) assert.equal(wrappedRenderButtonContentResult.children().length, 5) }) it('should render no elements if all args passed', function () { - const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({}, {}) - const wrappedRenderButtonContentResult = shallow(renderButtonContentResult) + const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent( + {}, + {}, + ) + const wrappedRenderButtonContentResult = shallow( + renderButtonContentResult, + ) assert.equal(wrappedRenderButtonContentResult.children().length, 0) }) }) diff --git a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.component.js b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.component.js index ef5f9e074..e01001ebf 100644 --- a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.component.js +++ b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.component.js @@ -24,7 +24,7 @@ export default class GasPriceChart extends Component { updateCustomGasPrice: PropTypes.func, } - renderChart () { + renderChart() { const { currentPrice, gasPrices, @@ -33,7 +33,13 @@ export default class GasPriceChart extends Component { estimatedTimesMax, updateCustomGasPrice, } = this.props - const chart = generateChart(gasPrices, estimatedTimes, gasPricesMax, estimatedTimesMax, this.context.t) + const chart = generateChart( + gasPrices, + estimatedTimes, + gasPricesMax, + estimatedTimesMax, + this.context.t, + ) setTimeout(function () { setTickPosition('y', 0, -5, 8) setTickPosition('y', 1, -3, -5) @@ -44,9 +50,15 @@ export default class GasPriceChart extends Component { const { x: yAxisX } = getCoordinateData('.c3-axis-y-label') const { x: tickX } = getCoordinateData('.c3-axis-x .tick') - d3.select('.c3-axis-x .tick').attr('transform', `translate(${(domainX - tickX) / 2}, 0)`) + d3.select('.c3-axis-x .tick').attr( + 'transform', + `translate(${(domainX - tickX) / 2}, 0)`, + ) d3.select('.c3-axis-x-label').attr('transform', 'translate(0,-15)') - d3.select('.c3-axis-y-label').attr('transform', `translate(${domainX - yAxisX - 12}, 2) rotate(-90)`) + d3.select('.c3-axis-y-label').attr( + 'transform', + `translate(${domainX - yAxisX - 12}, 2) rotate(-90)`, + ) d3.select('.c3-xgrid-focus line').attr('y2', 98) d3.select('.c3-chart').on('mouseout', () => { @@ -58,7 +70,9 @@ export default class GasPriceChart extends Component { updateCustomGasPrice(newGasPrice) }) - const { x: chartXStart, width: chartWidth } = getCoordinateData('.c3-areas-data1') + const { x: chartXStart, width: chartWidth } = getCoordinateData( + '.c3-areas-data1', + ) handleChartUpdate({ chart, @@ -82,7 +96,7 @@ export default class GasPriceChart extends Component { this.chart = chart } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { gasPrices, currentPrice: newPrice } = this.props if (prevProps.currentPrice !== newPrice) { @@ -95,11 +109,11 @@ export default class GasPriceChart extends Component { } } - componentDidMount () { + componentDidMount() { this.renderChart() } - render () { + render() { return (
    diff --git a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js index 4651b70f8..6fa809686 100644 --- a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js +++ b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js @@ -8,7 +8,14 @@ import { bigNumDiv, } from '../../../../helpers/utils/gas-time-estimates.util' -export function handleMouseMove ({ xMousePos, chartXStart, chartWidth, gasPrices, estimatedTimes, chart }) { +export function handleMouseMove({ + xMousePos, + chartXStart, + chartWidth, + gasPrices, + estimatedTimes, + chart, +}) { const { currentPosValue, newTimeEstimate } = getNewXandTimeEstimate({ xMousePos, chartXStart, @@ -23,19 +30,26 @@ export function handleMouseMove ({ xMousePos, chartXStart, chartWidth, gasPrices } const indexOfNewCircle = estimatedTimes.length + 1 - const dataUIObj = generateDataUIObj(currentPosValue, indexOfNewCircle, newTimeEstimate) + const dataUIObj = generateDataUIObj( + currentPosValue, + indexOfNewCircle, + newTimeEstimate, + ) chart.internal.overlayPoint(dataUIObj, indexOfNewCircle) - chart.internal.showTooltip([dataUIObj], d3.select('.c3-areas-data1')._groups[0]) + chart.internal.showTooltip( + [dataUIObj], + d3.select('.c3-areas-data1')._groups[0], + ) chart.internal.showXGridFocus([dataUIObj]) } -export function getCoordinateData (selector) { +export function getCoordinateData(selector) { const node = d3.select(selector).node() return node ? node.getBoundingClientRect() : {} } -export function generateDataUIObj (x, index, value) { +export function generateDataUIObj(x, index, value) { return { x, value, @@ -45,7 +59,7 @@ export function generateDataUIObj (x, index, value) { } } -export function handleChartUpdate ({ chart, gasPrices, newPrice, cssId }) { +export function handleChartUpdate({ chart, gasPrices, newPrice, cssId }) { const { closestLowerValueIndex, closestLowerValue, @@ -67,11 +81,20 @@ export function handleChartUpdate ({ chart, gasPrices, newPrice, cssId }) { } } -export function getNewXandTimeEstimate ({ xMousePos, chartXStart, chartWidth, gasPrices, estimatedTimes }) { +export function getNewXandTimeEstimate({ + xMousePos, + chartXStart, + chartWidth, + gasPrices, + estimatedTimes, +}) { const chartMouseXPos = bigNumMinus(xMousePos, chartXStart) const posPercentile = bigNumDiv(chartMouseXPos, chartWidth) - const currentPosValue = (bigNumMinus(gasPrices[gasPrices.length - 1], gasPrices[0])) + const currentPosValue = bigNumMinus( + gasPrices[gasPrices.length - 1], + gasPrices[0], + ) .times(newBigSigDig(posPercentile)) .plus(newBigSigDig(gasPrices[0])) .toNumber() @@ -85,22 +108,22 @@ export function getNewXandTimeEstimate ({ xMousePos, chartXStart, chartWidth, ga return !closestHigherValue || !closestLowerValue ? { - currentPosValue: null, - newTimeEstimate: null, - } + currentPosValue: null, + newTimeEstimate: null, + } : { - currentPosValue, - newTimeEstimate: extrapolateY({ - higherY: estimatedTimes[closestHigherValueIndex], - lowerY: estimatedTimes[closestLowerValueIndex], - higherX: closestHigherValue, - lowerX: closestLowerValue, - xForExtrapolation: currentPosValue, - }), - } + currentPosValue, + newTimeEstimate: extrapolateY({ + higherY: estimatedTimes[closestHigherValueIndex], + lowerY: estimatedTimes[closestLowerValueIndex], + higherX: closestHigherValue, + lowerX: closestLowerValue, + xForExtrapolation: currentPosValue, + }), + } } -export function hideDataUI (chart, dataNodeId) { +export function hideDataUI(chart, dataNodeId) { const overLayedCircle = d3.select(dataNodeId) if (!overLayedCircle.empty()) { overLayedCircle.remove() @@ -109,7 +132,7 @@ export function hideDataUI (chart, dataNodeId) { chart.internal.hideXGridFocus() } -export function setTickPosition (axis, n, newPosition, secondNewPosition) { +export function setTickPosition(axis, n, newPosition, secondNewPosition) { const positionToShift = axis === 'y' ? 'x' : 'y' const secondPositionToShift = axis === 'y' ? 'y' : 'x' d3.select('#chart') @@ -125,14 +148,23 @@ export function setTickPosition (axis, n, newPosition, secondNewPosition) { } /* eslint-disable @babel/no-invalid-this */ -export function appendOrUpdateCircle ({ data, itemIndex, cx, cy, cssId, appendOnly }) { +export function appendOrUpdateCircle({ + data, + itemIndex, + cx, + cy, + cssId, + appendOnly, +}) { const circle = this.main .select(`.c3-selected-circles${this.getTargetSelectorSuffix(data.id)}`) .selectAll(`.c3-selected-circle-${itemIndex}`) if (appendOnly || circle.empty()) { - circle.data([data]) - .enter().append('circle') + circle + .data([data]) + .enter() + .append('circle') .attr('class', () => this.generateClass('c3-selected-circle', itemIndex)) .attr('id', cssId) .attr('cx', cx) @@ -140,14 +172,12 @@ export function appendOrUpdateCircle ({ data, itemIndex, cx, cy, cssId, appendOn .attr('stroke', () => this.color(data)) .attr('r', 6) } else { - circle.data([data]) - .attr('cx', cx) - .attr('cy', cy) + circle.data([data]).attr('cx', cx).attr('cy', cy) } } /* eslint-enable @babel/no-invalid-this */ -export function setSelectedCircle ({ +export function setSelectedCircle({ chart, newPrice, closestLowerValueIndex, @@ -157,8 +187,12 @@ export function setSelectedCircle ({ }) { const numberOfValues = chart.internal.data.xs.data1.length - const { x: lowerX, y: lowerY } = getCoordinateData(`.c3-circle-${closestLowerValueIndex}`) - let { x: higherX, y: higherY } = getCoordinateData(`.c3-circle-${closestHigherValueIndex}`) + const { x: lowerX, y: lowerY } = getCoordinateData( + `.c3-circle-${closestLowerValueIndex}`, + ) + let { x: higherX, y: higherY } = getCoordinateData( + `.c3-circle-${closestHigherValueIndex}`, + ) let count = closestHigherValueIndex + 1 if (lowerX && higherX) { @@ -174,7 +208,13 @@ export function setSelectedCircle ({ .div(bigNumMinus(closestHigherValue, closestLowerValue)) .plus(newBigSigDig(lowerX)) - const newTimeEstimate = extrapolateY({ higherY, lowerY, higherX, lowerX, xForExtrapolation: currentX }) + const newTimeEstimate = extrapolateY({ + higherY, + lowerY, + higherX, + lowerX, + xForExtrapolation: currentX, + }) chart.internal.selectPoint( generateDataUIObj(currentX.toNumber(), numberOfValues, newTimeEstimate), @@ -182,7 +222,12 @@ export function setSelectedCircle ({ ) } -export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimatedTimesMax) { +export function generateChart( + gasPrices, + estimatedTimes, + gasPricesMax, + estimatedTimesMax, +) { const gasPricesMaxPadded = gasPricesMax + 1 const chart = c3.generate({ size: { @@ -215,7 +260,7 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate tick: { values: [Math.floor(gasPrices[0]), Math.ceil(gasPricesMax)], outer: false, - format (val) { + format(val) { return `${val} GWEI` }, }, @@ -228,7 +273,10 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate y: { padding: { top: 7, bottom: 7 }, tick: { - values: [Math.floor(estimatedTimesMax * 0.05), Math.ceil(estimatedTimesMax * 0.97)], + values: [ + Math.floor(estimatedTimesMax * 0.05), + Math.ceil(estimatedTimesMax * 0.97), + ], outer: false, }, label: { @@ -259,42 +307,59 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate format: { title: (v) => v.toPrecision(4), }, - contents (d) { + contents(d) { const titleFormat = this.config.tooltip_format_title let text d.forEach((el) => { if (el && (el.value || el.value === 0) && !text) { - text = `` + text = `
    ${titleFormat(el.x)}
    ` } }) return `${text}
    ${titleFormat( + el.x, + )}
    ` }, - position () { + position() { if (d3.select('#overlayed-circle').empty()) { return { top: -100, left: -100 } } - const { x: circleX, y: circleY, width: circleWidth } = getCoordinateData('#overlayed-circle') - const { x: chartXStart, y: chartYStart } = getCoordinateData('.c3-chart') + const { + x: circleX, + y: circleY, + width: circleWidth, + } = getCoordinateData('#overlayed-circle') + const { x: chartXStart, y: chartYStart } = getCoordinateData( + '.c3-chart', + ) // TODO: Confirm the below constants work with all data sets and screen sizes const flipTooltip = circleY - circleWidth < chartYStart + 5 - d3 - .select('.tooltip-arrow') - .style('margin-top', flipTooltip ? '-16px' : '4px') + d3.select('.tooltip-arrow').style( + 'margin-top', + flipTooltip ? '-16px' : '4px', + ) return { - top: bigNumMinus(circleY, chartYStart).minus(19).plus(flipTooltip ? circleWidth + 38 : 0).toNumber(), - left: bigNumMinus(circleX, chartXStart).plus(newBigSigDig(circleWidth)).minus(bigNumDiv(gasPricesMaxPadded, 50)).toNumber(), + top: bigNumMinus(circleY, chartYStart) + .minus(19) + .plus(flipTooltip ? circleWidth + 38 : 0) + .toNumber(), + left: bigNumMinus(circleX, chartXStart) + .plus(newBigSigDig(circleWidth)) + .minus(bigNumDiv(gasPricesMaxPadded, 50)) + .toNumber(), } }, show: true, }, }) - chart.internal.selectPoint = function (data, itemIndex = (data.index || 0)) { - const { x: chartXStart, y: chartYStart } = getCoordinateData('.c3-areas-data1') + chart.internal.selectPoint = function (data, itemIndex = data.index || 0) { + const { x: chartXStart, y: chartYStart } = getCoordinateData( + '.c3-areas-data1', + ) d3.select('#set-circle').remove() @@ -319,19 +384,37 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate } chart.internal.showTooltip = function (selectedData, element) { - const dataToShow = selectedData.filter((d) => d && (d.value || d.value === 0)) + const dataToShow = selectedData.filter( + (d) => d && (d.value || d.value === 0), + ) if (dataToShow.length) { - this.tooltip.html( - this.config.tooltip_contents.call(this, selectedData, this.axis.getXAxisTickFormat(), this.getYFormat(), this.color), - ).style('display', 'flex') + this.tooltip + .html( + this.config.tooltip_contents.call( + this, + selectedData, + this.axis.getXAxisTickFormat(), + this.getYFormat(), + this.color, + ), + ) + .style('display', 'flex') // Get tooltip dimensions const tWidth = this.tooltip.property('offsetWidth') const tHeight = this.tooltip.property('offsetHeight') - const position = this.config.tooltip_position.call(this, dataToShow, tWidth, tHeight, element) + const position = this.config.tooltip_position.call( + this, + dataToShow, + tWidth, + tHeight, + element, + ) // Set tooltip - this.tooltip.style('top', `${position.top}px`).style('left', `${position.left}px`) + this.tooltip + .style('top', `${position.top}px`) + .style('left', `${position.left}px`) } } diff --git a/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js b/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js index d95fa63a1..6256b8734 100644 --- a/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js +++ b/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js @@ -5,7 +5,7 @@ import sinon from 'sinon' import * as d3 from 'd3' import shallow from '../../../../../../lib/shallow-with-context' -function timeout (time) { +function timeout(time) { return new Promise((resolve) => { setTimeout(resolve, time) }) @@ -47,7 +47,9 @@ describe('GasPriceChart Component', function () { generateChart: sinon.stub().returns({ mockChart: true }), generateDataUIObj: sinon.spy(), getAdjacentGasPrices: sinon.spy(), - getCoordinateData: sinon.stub().returns({ x: 'mockCoordinateX', width: 'mockWidth' }), + getCoordinateData: sinon + .stub() + .returns({ x: 'mockCoordinateX', width: 'mockWidth' }), getNewXandTimeEstimate: sinon.spy(), handleChartUpdate: sinon.spy(), hideDataUI: sinon.spy(), @@ -67,13 +69,11 @@ describe('GasPriceChart Component', function () { GasPriceChart = proxyquire('../gas-price-chart.component.js', { './gas-price-chart.utils.js': gasPriceChartUtilsSpies, - 'd3': { + d3: { ...d3, - select (...args) { + select(...args) { const result = d3.select(...args) - return result.empty() - ? mockSelectReturn - : result + return result.empty() ? mockSelectReturn : result }, event: { clientX: 'mockClientX', @@ -118,12 +118,17 @@ describe('GasPriceChart Component', function () { it('should call handleChartUpdate with the correct props', function () { gasPriceChartUtilsSpies.handleChartUpdate.resetHistory() wrapper.instance().componentDidUpdate({ currentPrice: 7 }) - assert.deepEqual(gasPriceChartUtilsSpies.handleChartUpdate.getCall(0).args, [{ - chart: { mockChart: true }, - gasPrices: [1.5, 2.5, 4, 8], - newPrice: 6, - cssId: '#set-circle', - }]) + assert.deepEqual( + gasPriceChartUtilsSpies.handleChartUpdate.getCall(0).args, + [ + { + chart: { mockChart: true }, + gasPrices: [1.5, 2.5, 4, 8], + newPrice: 6, + cssId: '#set-circle', + }, + ], + ) }) it('should not call handleChartUpdate if props.currentPrice has not changed', function () { @@ -141,10 +146,22 @@ describe('GasPriceChart Component', function () { wrapper.instance().renderChart(testProps) await timeout(0) assert.equal(gasPriceChartUtilsSpies.setTickPosition.callCount, 4) - assert.deepEqual(gasPriceChartUtilsSpies.setTickPosition.getCall(0).args, ['y', 0, -5, 8]) - assert.deepEqual(gasPriceChartUtilsSpies.setTickPosition.getCall(1).args, ['y', 1, -3, -5]) - assert.deepEqual(gasPriceChartUtilsSpies.setTickPosition.getCall(2).args, ['x', 0, 3]) - assert.deepEqual(gasPriceChartUtilsSpies.setTickPosition.getCall(3).args, ['x', 1, 3, -8]) + assert.deepEqual( + gasPriceChartUtilsSpies.setTickPosition.getCall(0).args, + ['y', 0, -5, 8], + ) + assert.deepEqual( + gasPriceChartUtilsSpies.setTickPosition.getCall(1).args, + ['y', 1, -3, -5], + ) + assert.deepEqual( + gasPriceChartUtilsSpies.setTickPosition.getCall(2).args, + ['x', 0, 3], + ) + assert.deepEqual( + gasPriceChartUtilsSpies.setTickPosition.getCall(3).args, + ['x', 1, 3, -8], + ) }) it('should call handleChartUpdate with the correct props', async function () { @@ -152,12 +169,17 @@ describe('GasPriceChart Component', function () { gasPriceChartUtilsSpies.handleChartUpdate.resetHistory() wrapper.instance().renderChart(testProps) await timeout(0) - assert.deepEqual(gasPriceChartUtilsSpies.handleChartUpdate.getCall(0).args, [{ - chart: { mockChart: true }, - gasPrices: [1.5, 2.5, 4, 8], - newPrice: 6, - cssId: '#set-circle', - }]) + assert.deepEqual( + gasPriceChartUtilsSpies.handleChartUpdate.getCall(0).args, + [ + { + chart: { mockChart: true }, + gasPrices: [1.5, 2.5, 4, 8], + newPrice: 6, + cssId: '#set-circle', + }, + ], + ) }) it('should add three events to the chart', async function () { @@ -186,7 +208,10 @@ describe('GasPriceChart Component', function () { assert.equal(gasPriceChartUtilsSpies.hideDataUI.callCount, 0) mouseoutEventArgs[1]() assert.equal(gasPriceChartUtilsSpies.hideDataUI.callCount, 1) - assert.deepEqual(gasPriceChartUtilsSpies.hideDataUI.getCall(0).args, [{ mockChart: true }, '#overlayed-circle']) + assert.deepEqual(gasPriceChartUtilsSpies.hideDataUI.getCall(0).args, [ + { mockChart: true }, + '#overlayed-circle', + ]) }) it('should updateCustomGasPrice on click', async function () { @@ -199,7 +224,10 @@ describe('GasPriceChart Component', function () { assert.equal(propsMethodSpies.updateCustomGasPrice.callCount, 0) mouseoutEventArgs[1]() assert.equal(propsMethodSpies.updateCustomGasPrice.callCount, 1) - assert.equal(propsMethodSpies.updateCustomGasPrice.getCall(0).args[0], 'mockX') + assert.equal( + propsMethodSpies.updateCustomGasPrice.getCall(0).args[0], + 'mockX', + ) }) it('should handle mousemove', async function () { @@ -212,14 +240,19 @@ describe('GasPriceChart Component', function () { assert.equal(gasPriceChartUtilsSpies.handleMouseMove.callCount, 0) mouseoutEventArgs[1]() assert.equal(gasPriceChartUtilsSpies.handleMouseMove.callCount, 1) - assert.deepEqual(gasPriceChartUtilsSpies.handleMouseMove.getCall(0).args, [{ - xMousePos: 'mockClientX', - chartXStart: 'mockCoordinateX', - chartWidth: 'mockWidth', - gasPrices: testProps.gasPrices, - estimatedTimes: testProps.estimatedTimes, - chart: { mockChart: true }, - }]) + assert.deepEqual( + gasPriceChartUtilsSpies.handleMouseMove.getCall(0).args, + [ + { + xMousePos: 'mockClientX', + chartXStart: 'mockCoordinateX', + chartWidth: 'mockWidth', + gasPrices: testProps.gasPrices, + estimatedTimes: testProps.estimatedTimes, + chart: { mockChart: true }, + }, + ], + ) }) }) }) diff --git a/ui/app/components/app/gas-customization/gas-slider/gas-slider.component.js b/ui/app/components/app/gas-customization/gas-slider/gas-slider.component.js index 1e072d300..db5c01b8b 100644 --- a/ui/app/components/app/gas-customization/gas-slider/gas-slider.component.js +++ b/ui/app/components/app/gas-customization/gas-slider/gas-slider.component.js @@ -12,16 +12,8 @@ export default class GasSlider extends Component { min: PropTypes.number, } - render () { - const { - onChange, - lowLabel, - highLabel, - value, - step, - max, - min, - } = this.props + render() { + const { onChange, lowLabel, highLabel, value, step, max, min } = this.props return (
    diff --git a/ui/app/components/app/home-notification/home-notification.component.js b/ui/app/components/app/home-notification/home-notification.component.js index d2f1598d7..2bb89eafe 100644 --- a/ui/app/components/app/home-notification/home-notification.component.js +++ b/ui/app/components/app/home-notification/home-notification.component.js @@ -34,8 +34,16 @@ export default class HomeNotification extends PureComponent { this.props.onIgnore() } - render () { - const { descriptionText, acceptText, onAccept, ignoreText, onIgnore, infoText, classNames = [] } = this.props + render() { + const { + descriptionText, + acceptText, + onAccept, + ignoreText, + onIgnore, + infoText, + classNames = [], + } = this.props return (
    @@ -46,65 +54,46 @@ export default class HomeNotification extends PureComponent { alt="" src="images/icons/connect.svg" /> -
    - { descriptionText } -
    +
    {descriptionText}
    - { - infoText ? ( - - {infoText} -

    - )} - offset={-36} - distance={36} - animation="none" - position="top" - arrow - theme="tippy-tooltip-home" - > - -
    - ) : ( - null - ) - } + {infoText ? ( + {infoText}

    + } + offset={-36} + distance={36} + animation="none" + position="top" + arrow + theme="tippy-tooltip-home" + > + +
    + ) : null}
    - { - (onAccept && acceptText) ? ( - - ) : ( - null - ) - } - { - (onIgnore && ignoreText) ? ( - - ) : ( - null - ) - } + {onAccept && acceptText ? ( + + ) : null} + {onIgnore && ignoreText ? ( + + ) : null}
    ) diff --git a/ui/app/components/app/info-box/info-box.component.js b/ui/app/components/app/info-box/info-box.component.js index 163869ef5..84e8c3b63 100644 --- a/ui/app/components/app/info-box/info-box.component.js +++ b/ui/app/components/app/info-box/info-box.component.js @@ -16,7 +16,7 @@ export default class InfoBox extends Component { isShowing: true, } - handleClose () { + handleClose() { const { onClose } = this.props if (onClose) { @@ -26,20 +26,15 @@ export default class InfoBox extends Component { } } - render () { + render() { const { title, description } = this.props - return this.state.isShowing - ? ( -
    -
    this.handleClose()} - /> -
    {title}
    -
    {description}
    -
    - ) - : null + return this.state.isShowing ? ( +
    +
    this.handleClose()} /> +
    {title}
    +
    {description}
    +
    + ) : null } } diff --git a/ui/app/components/app/info-box/tests/info-box.test.js b/ui/app/components/app/info-box/tests/info-box.test.js index 5ad89b4fd..031ac62f4 100644 --- a/ui/app/components/app/info-box/tests/info-box.test.js +++ b/ui/app/components/app/info-box/tests/info-box.test.js @@ -6,7 +6,6 @@ import { shallow } from 'enzyme' import InfoBox from '..' describe('InfoBox', function () { - let wrapper const props = { diff --git a/ui/app/components/app/loading-network-screen/loading-network-screen.component.js b/ui/app/components/app/loading-network-screen/loading-network-screen.component.js index f20916346..1eb95eedf 100644 --- a/ui/app/components/app/loading-network-screen/loading-network-screen.component.js +++ b/ui/app/components/app/loading-network-screen/loading-network-screen.component.js @@ -19,13 +19,19 @@ export default class LoadingNetworkScreen extends PureComponent { providerId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), showNetworkDropdown: PropTypes.func, setProviderArgs: PropTypes.array, - lastSelectedProvider: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + lastSelectedProvider: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object, + ]), setProviderType: PropTypes.func, isLoadingNetwork: PropTypes.bool, } componentDidMount = () => { - this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 15000) + this.cancelCallTimeout = setTimeout( + this.cancelCall, + this.props.cancelTime || 15000, + ) } getConnectingLabel = function (loadingMessage) { @@ -60,7 +66,7 @@ export default class LoadingNetworkScreen extends PureComponent { return (
    😞 - { this.context.t('somethingWentWrong') } + {this.context.t('somethingWentWrong')}
    @@ -102,7 +111,10 @@ export default class LoadingNetworkScreen extends PureComponent { if (provider.type !== prevProvider.type) { window.clearTimeout(this.cancelCallTimeout) this.setState({ showErrorScreen: false }) - this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 15000) + this.cancelCallTimeout = setTimeout( + this.cancelCall, + this.props.cancelTime || 15000, + ) } } @@ -110,19 +122,23 @@ export default class LoadingNetworkScreen extends PureComponent { window.clearTimeout(this.cancelCallTimeout) } - render () { + render() { const { lastSelectedProvider, setProviderType } = this.props return ( setProviderType(lastSelectedProvider || 'ropsten')} /> - )} + } showLoadingSpinner={!this.state.showErrorScreen} - loadingMessage={this.state.showErrorScreen ? this.renderErrorScreenContent() : this.getConnectingLabel(this.props.loadingMessage)} + loadingMessage={ + this.state.showErrorScreen + ? this.renderErrorScreenContent() + : this.getConnectingLabel(this.props.loadingMessage) + } /> ) } diff --git a/ui/app/components/app/loading-network-screen/loading-network-screen.container.js b/ui/app/components/app/loading-network-screen/loading-network-screen.container.js index 7662ae64f..994edd175 100644 --- a/ui/app/components/app/loading-network-screen/loading-network-screen.container.js +++ b/ui/app/components/app/loading-network-screen/loading-network-screen.container.js @@ -4,19 +4,12 @@ import { getNetworkIdentifier } from '../../../selectors' import LoadingNetworkScreen from './loading-network-screen.component' const mapStateToProps = (state) => { - const { - loadingMessage, - lastSelectedProvider, - } = state.appState - const { - provider, - network, - } = state.metamask + const { loadingMessage, lastSelectedProvider } = state.appState + const { provider, network } = state.metamask const { rpcUrl, chainId, ticker, nickname, type } = provider - const setProviderArgs = type === 'rpc' - ? [rpcUrl, chainId, ticker, nickname] - : [provider.type] + const setProviderArgs = + type === 'rpc' ? [rpcUrl, chainId, ticker, nickname] : [provider.type] return { isLoadingNetwork: network === 'loading', @@ -37,4 +30,7 @@ const mapDispatchToProps = (dispatch) => { } } -export default connect(mapStateToProps, mapDispatchToProps)(LoadingNetworkScreen) +export default connect( + mapStateToProps, + mapDispatchToProps, +)(LoadingNetworkScreen) diff --git a/ui/app/components/app/menu-bar/account-options-menu.js b/ui/app/components/app/menu-bar/account-options-menu.js index 241f6dc92..60ca1c598 100644 --- a/ui/app/components/app/menu-bar/account-options-menu.js +++ b/ui/app/components/app/menu-bar/account-options-menu.js @@ -7,13 +7,18 @@ import { showModal } from '../../../store/actions' import { CONNECTED_ROUTE } from '../../../helpers/constants/routes' import { Menu, MenuItem } from '../../ui/menu' import getAccountLink from '../../../../lib/account-link' -import { getCurrentKeyring, getCurrentNetwork, getRpcPrefsForCurrentProvider, getSelectedIdentity } from '../../../selectors' +import { + getCurrentKeyring, + getCurrentNetwork, + getRpcPrefsForCurrentProvider, + getSelectedIdentity, +} from '../../../selectors' import { useI18nContext } from '../../../hooks/useI18nContext' import { useMetricEvent } from '../../../hooks/useMetricEvent' import { getEnvironmentType } from '../../../../../app/scripts/lib/util' import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../app/scripts/lib/enums' -export default function AccountOptionsMenu ({ anchorElement, onClose }) { +export default function AccountOptionsMenu({ anchorElement, onClose }) { const t = useI18nContext() const dispatch = useDispatch() const history = useHistory() @@ -60,22 +65,18 @@ export default function AccountOptionsMenu ({ anchorElement, onClose }) { className="account-options-menu" onHide={onClose} > - { - getEnvironmentType() === ENVIRONMENT_TYPE_FULLSCREEN - ? null - : ( - { - openFullscreenEvent() - global.platform.openExtensionInBrowser() - onClose() - }} - iconClassName="fas fa-expand-alt" - > - { t('expandView') } - - ) - } + {getEnvironmentType() === ENVIRONMENT_TYPE_FULLSCREEN ? null : ( + { + openFullscreenEvent() + global.platform.openExtensionInBrowser() + onClose() + }} + iconClassName="fas fa-expand-alt" + > + {t('expandView')} + + )} { @@ -85,30 +86,26 @@ export default function AccountOptionsMenu ({ anchorElement, onClose }) { }} iconClassName="fas fa-qrcode" > - { t('accountDetails') } + {t('accountDetails')} { viewOnEtherscanEvent() - global.platform.openTab({ url: getAccountLink(address, network, rpcPrefs) }) + global.platform.openTab({ + url: getAccountLink(address, network, rpcPrefs), + }) onClose() }} subtitle={ - rpcPrefs.blockExplorerUrl - ? ( - - { rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/u)[1] } - - ) - : null + rpcPrefs.blockExplorerUrl ? ( + + {rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/u)[1]} + + ) : null } iconClassName="fas fa-external-link-alt" > - { - rpcPrefs.blockExplorerUrl - ? t('viewinExplorer') - : t('viewOnEtherscan') - } + {rpcPrefs.blockExplorerUrl ? t('viewinExplorer') : t('viewOnEtherscan')} - { t('connectedSites') } + {t('connectedSites')} - { - isRemovable - ? ( - { - dispatch(showModal({ name: 'CONFIRM_REMOVE_ACCOUNT', identity: selectedIdentity })) - onClose() - }} - iconClassName="fas fa-trash-alt" - > - { t('removeAccount') } - - ) - : null - } + {isRemovable ? ( + { + dispatch( + showModal({ + name: 'CONFIRM_REMOVE_ACCOUNT', + identity: selectedIdentity, + }), + ) + onClose() + }} + iconClassName="fas fa-trash-alt" + > + {t('removeAccount')} + + ) : null} ) } diff --git a/ui/app/components/app/menu-bar/menu-bar.js b/ui/app/components/app/menu-bar/menu-bar.js index 8c4f5c8b9..d9d13fcb1 100644 --- a/ui/app/components/app/menu-bar/menu-bar.js +++ b/ui/app/components/app/menu-bar/menu-bar.js @@ -12,7 +12,7 @@ import { useMetricEvent } from '../../../hooks/useMetricEvent' import { getOriginOfCurrentTab } from '../../../selectors' import AccountOptionsMenu from './account-options-menu' -export default function MenuBar () { +export default function MenuBar() { const t = useI18nContext() const openAccountOptionsEvent = useMetricEvent({ eventOpts: { @@ -22,19 +22,25 @@ export default function MenuBar () { }, }) const history = useHistory() - const [accountOptionsButtonElement, setAccountOptionsButtonElement] = useState(null) + const [ + accountOptionsButtonElement, + setAccountOptionsButtonElement, + ] = useState(null) const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false) const origin = useSelector(getOriginOfCurrentTab) - const showStatus = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP && origin && origin !== extension.runtime.id + const showStatus = + getEnvironmentType() === ENVIRONMENT_TYPE_POPUP && + origin && + origin !== extension.runtime.id return (
    - { - showStatus - ? history.push(CONNECTED_ACCOUNTS_ROUTE)} /> - : null - } + {showStatus ? ( + history.push(CONNECTED_ACCOUNTS_ROUTE)} + /> + ) : null} @@ -49,14 +55,12 @@ export default function MenuBar () { }} /> - { - accountOptionsMenuOpen && ( - setAccountOptionsMenuOpen(false)} - /> - ) - } + {accountOptionsMenuOpen && ( + setAccountOptionsMenuOpen(false)} + /> + )}
    ) } diff --git a/ui/app/components/app/menu-bar/tests/menu-bar.test.js b/ui/app/components/app/menu-bar/tests/menu-bar.test.js index 1212977be..9df845409 100644 --- a/ui/app/components/app/menu-bar/tests/menu-bar.test.js +++ b/ui/app/components/app/menu-bar/tests/menu-bar.test.js @@ -19,9 +19,7 @@ const initState = { keyrings: [ { type: 'HD Key Tree', - accounts: [ - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ], + accounts: ['0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'], }, ], frequentRpcListDetail: [], diff --git a/ui/app/components/app/menu-droppo.js b/ui/app/components/app/menu-droppo.js index 35d7b458e..558dacfe8 100644 --- a/ui/app/components/app/menu-droppo.js +++ b/ui/app/components/app/menu-droppo.js @@ -16,7 +16,7 @@ export default class MenuDroppoComponent extends Component { speed: PropTypes.string, } - renderPrimary () { + renderPrimary() { const { isOpen } = this.props if (!isOpen) { return null @@ -31,7 +31,7 @@ export default class MenuDroppoComponent extends Component { ) } - manageListeners () { + manageListeners() { const { isOpen, onClickOutside } = this.props if (isOpen) { @@ -44,14 +44,16 @@ export default class MenuDroppoComponent extends Component { // eslint-disable-next-line react/no-find-dom-node const container = findDOMNode(this) - if (target !== container && + if ( + target !== container && !isDescendant(this.container, event.target) && - this.outsideClickHandler) { + this.outsideClickHandler + ) { this.outsideClickHandler(event) } } - componentDidMount () { + componentDidMount() { if (this && document.body) { document.body.addEventListener('click', this.globalClickOccurred) // eslint-disable-next-line react/no-find-dom-node @@ -60,17 +62,17 @@ export default class MenuDroppoComponent extends Component { } } - componentWillUnmount () { + componentWillUnmount() { if (this && document.body) { document.body.removeEventListener('click', this.globalClickOccurred) } } - render () { + render() { const { containerClassName = '', style } = this.props const speed = this.props.speed || '300ms' const { useCssTransition } = this.props - const zIndex = ('zIndex' in this.props) ? this.props.zIndex : 0 + const zIndex = 'zIndex' in this.props ? this.props.zIndex : 0 this.manageListeners() @@ -81,8 +83,12 @@ export default class MenuDroppoComponent extends Component { } return ( -
    - - { - useCssTransition - ? ( - - {this.renderPrimary()} - - ) - : this.renderPrimary() - } + {useCssTransition ? ( + + {this.renderPrimary()} + + ) : ( + this.renderPrimary() + )}
    ) } } -function isDescendant (parent, child) { +function isDescendant(parent, child) { let node = child.parentNode while (node !== null) { if (node === parent) { diff --git a/ui/app/components/app/modal/modal-content/modal-content.component.js b/ui/app/components/app/modal/modal-content/modal-content.component.js index ecec0ee5b..8f011e18f 100644 --- a/ui/app/components/app/modal/modal-content/modal-content.component.js +++ b/ui/app/components/app/modal/modal-content/modal-content.component.js @@ -7,25 +7,15 @@ export default class ModalContent extends PureComponent { description: PropTypes.string, } - render () { + render() { const { title, description } = this.props return (
    - { - title && ( -
    - { title } -
    - ) - } - { - description && ( -
    - { description } -
    - ) - } + {title &&
    {title}
    } + {description && ( +
    {description}
    + )}
    ) } diff --git a/ui/app/components/app/modal/modal-content/tests/modal-content.component.test.js b/ui/app/components/app/modal/modal-content/tests/modal-content.component.test.js index 058727cc2..de40a39bd 100644 --- a/ui/app/components/app/modal/modal-content/tests/modal-content.component.test.js +++ b/ui/app/components/app/modal/modal-content/tests/modal-content.component.test.js @@ -5,11 +5,7 @@ import ModalContent from '../modal-content.component' describe('ModalContent Component', function () { it('should render a title', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.equal(wrapper.find('.modal-content__title').length, 1) assert.equal(wrapper.find('.modal-content__title').text(), 'Modal Title') @@ -17,28 +13,27 @@ describe('ModalContent Component', function () { }) it('should render a description', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.equal(wrapper.find('.modal-content__title').length, 0) assert.equal(wrapper.find('.modal-content__description').length, 1) - assert.equal(wrapper.find('.modal-content__description').text(), 'Modal Description') + assert.equal( + wrapper.find('.modal-content__description').text(), + 'Modal Description', + ) }) it('should render both a title and a description', function () { const wrapper = shallow( - , + , ) assert.equal(wrapper.find('.modal-content__title').length, 1) assert.equal(wrapper.find('.modal-content__title').text(), 'Modal Title') assert.equal(wrapper.find('.modal-content__description').length, 1) - assert.equal(wrapper.find('.modal-content__description').text(), 'Modal Description') + assert.equal( + wrapper.find('.modal-content__description').text(), + 'Modal Description', + ) }) }) diff --git a/ui/app/components/app/modal/modal.component.js b/ui/app/components/app/modal/modal.component.js index 5e2ad00f5..57137270c 100644 --- a/ui/app/components/app/modal/modal.component.js +++ b/ui/app/components/app/modal/modal.component.js @@ -28,7 +28,7 @@ export default class Modal extends PureComponent { cancelType: 'default', } - render () { + render() { const { children, headerText, @@ -47,49 +47,36 @@ export default class Modal extends PureComponent { return (
    - { - headerText && ( -
    -
    - { headerText } -
    -
    -
    - ) - } + {headerText && ( +
    +
    {headerText}
    +
    +
    + )}
    - { children } + {children}
    - { - hideFooter - ? null - : ( -
    - { - onCancel && ( - - ) - } - -
    - ) - } + {hideFooter ? null : ( +
    + {onCancel && ( + + )} + +
    + )}
    ) } diff --git a/ui/app/components/app/modal/tests/modal.component.test.js b/ui/app/components/app/modal/tests/modal.component.test.js index 5dceb4292..fe55b61bd 100644 --- a/ui/app/components/app/modal/tests/modal.component.test.js +++ b/ui/app/components/app/modal/tests/modal.component.test.js @@ -93,7 +93,10 @@ describe('Modal Component', function () { ) assert.ok(wrapper.find('.modal-container__header')) - assert.equal(wrapper.find('.modal-container__header-text').text(), 'My Header') + assert.equal( + wrapper.find('.modal-container__header-text').text(), + 'My Header', + ) assert.equal(handleCancel.callCount, 0) assert.equal(handleSubmit.callCount, 0) wrapper.find('.modal-container__header-close').simulate('click') diff --git a/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js b/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js index 1e5f634a5..71350b9a3 100644 --- a/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js +++ b/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js @@ -20,7 +20,7 @@ export default class AccountDetailsModal extends Component { t: PropTypes.func, } - render () { + render() { const { selectedIdentity, network, @@ -61,27 +61,27 @@ export default class AccountDetailsModal extends Component { type="secondary" className="account-details-modal__button" onClick={() => { - global.platform.openTab({ url: getAccountLink(address, network, rpcPrefs) }) + global.platform.openTab({ + url: getAccountLink(address, network, rpcPrefs), + }) }} > {rpcPrefs.blockExplorerUrl - ? this.context.t('blockExplorerView', [rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/u)[1]]) - : this.context.t('viewOnEtherscan') - } + ? this.context.t('blockExplorerView', [ + rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/u)[1], + ]) + : this.context.t('viewOnEtherscan')} - {exportPrivateKeyFeatureEnabled - ? ( - - ) - : null - } + {exportPrivateKeyFeatureEnabled ? ( + + ) : null} ) } diff --git a/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js b/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js index 807fad84e..b29e99c54 100644 --- a/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js +++ b/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js @@ -17,8 +17,10 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - showExportPrivateKeyModal: () => dispatch(showModal({ name: 'EXPORT_PRIVATE_KEY' })), - setAccountLabel: (address, label) => dispatch(setAccountLabel(address, label)), + showExportPrivateKeyModal: () => + dispatch(showModal({ name: 'EXPORT_PRIVATE_KEY' })), + setAccountLabel: (address, label) => + dispatch(setAccountLabel(address, label)), } } diff --git a/ui/app/components/app/modals/account-modal-container/account-modal-container.component.js b/ui/app/components/app/modals/account-modal-container/account-modal-container.component.js index 93f4ae25b..2ad338b23 100644 --- a/ui/app/components/app/modals/account-modal-container/account-modal-container.component.js +++ b/ui/app/components/app/modals/account-modal-container/account-modal-container.component.js @@ -3,7 +3,7 @@ import React from 'react' import classnames from 'classnames' import Identicon from '../../../ui/identicon' -export default function AccountModalContainer (props, context) { +export default function AccountModalContainer(props, context) { const { className, selectedIdentity, @@ -14,18 +14,20 @@ export default function AccountModalContainer (props, context) { } = props return ( -
    +
    - +
    {showBackButton && (
    - {context.t('back')} + + {context.t('back')} +
    )}
    - )} - { - privateKey - ? ( - - ) - : ( - - ) - } + {privateKey ? ( + + ) : ( + + )}
    ) } - render () { + render() { const { selectedIdentity, warning, @@ -139,10 +137,7 @@ export default class ExportPrivateKeyModal extends Component { } = this.props const { name, address } = selectedIdentity - const { - privateKey, - showWarning, - } = this.state + const { privateKey, showWarning } = this.state return (
    - {this.context.t('showPrivateKeys')} + + {this.context.t('showPrivateKeys')} +
    {this.renderPasswordLabel(privateKey)} {this.renderPasswordInput(privateKey)} - { - (showWarning && warning) - ? {warning} - : null - } + {showWarning && warning ? ( + + {warning} + + ) : null} +
    +
    + {this.context.t('privateKeyWarning')}
    -
    {this.context.t('privateKeyWarning')}
    {this.renderButtons(privateKey, address, hideModal)} ) diff --git a/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.container.js b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.container.js index a8c3dd9ca..59a0252a1 100644 --- a/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.container.js +++ b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.container.js @@ -1,11 +1,17 @@ import { connect } from 'react-redux' -import { exportAccount, hideWarning, showModal, hideModal, clearAccountDetails } from '../../../../store/actions' +import { + exportAccount, + hideWarning, + showModal, + hideModal, + clearAccountDetails, +} from '../../../../store/actions' import { getSelectedIdentity } from '../../../../selectors' import ExportPrivateKeyModal from './export-private-key-modal.component' -function mapStateToPropsFactory () { +function mapStateToPropsFactory() { let selectedIdentity = null - return function mapStateToProps (state) { + return function mapStateToProps(state) { // We should **not** change the identity displayed here even if it changes from underneath us. // If we do, we will be showing the user one private key and a **different** address and name. // Note that the selected identity **will** change from underneath us when we unlock the keyring @@ -20,20 +26,23 @@ function mapStateToPropsFactory () { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { exportAccount: (password, address) => { - return dispatch(exportAccount(password, address)) - .then((res) => { - dispatch(hideWarning()) - return res - }) + return dispatch(exportAccount(password, address)).then((res) => { + dispatch(hideWarning()) + return res + }) }, - showAccountDetailModal: () => dispatch(showModal({ name: 'ACCOUNT_DETAILS' })), + showAccountDetailModal: () => + dispatch(showModal({ name: 'ACCOUNT_DETAILS' })), hideModal: () => dispatch(hideModal()), hideWarning: () => dispatch(hideWarning()), clearAccountDetails: () => dispatch(clearAccountDetails()), } } -export default connect(mapStateToPropsFactory, mapDispatchToProps)(ExportPrivateKeyModal) +export default connect( + mapStateToPropsFactory, + mapDispatchToProps, +)(ExportPrivateKeyModal) diff --git a/ui/app/components/app/modals/fade-modal.js b/ui/app/components/app/modals/fade-modal.js index 72d1c7288..0b4edeb43 100644 --- a/ui/app/components/app/modals/fade-modal.js +++ b/ui/app/components/app/modals/fade-modal.js @@ -5,7 +5,6 @@ let index = 0 let extraSheet const insertRule = (css) => { - if (!extraSheet) { // First time, create an extra stylesheet for adding rules extraSheet = document.createElement('style') @@ -88,11 +87,11 @@ const animation = { const endEvents = ['transitionend', 'animationend'] -function addEventListener (node, eventName, eventListener) { +function addEventListener(node, eventName, eventListener) { node.addEventListener(eventName, eventListener, false) } -function removeEventListener (node, eventName, eventListener) { +function removeEventListener(node, eventName, eventListener) { node.removeEventListener(eventName, eventListener, false) } @@ -172,7 +171,7 @@ class FadeModal extends Component { return this.state.hidden } - render () { + render() { if (this.state.hidden) { return null } @@ -180,25 +179,31 @@ class FadeModal extends Component { const { willHide } = this.state const { modalStyle } = this.props const backdropStyle = { - animationName: willHide ? animation.hideBackdropAnimation : animation.showBackdropAnimation, - animationTimingFunction: (willHide ? animation.hide : animation.show).animationTimingFunction, ...this.props.backdropStyle, + animationName: willHide + ? animation.hideBackdropAnimation + : animation.showBackdropAnimation, + animationTimingFunction: (willHide ? animation.hide : animation.show) + .animationTimingFunction, + ...this.props.backdropStyle, } const contentStyle = { - animationDuration: (willHide ? animation.hide : animation.show).animationDuration, - animationName: willHide ? animation.hideContentAnimation : animation.showContentAnimation, - animationTimingFunction: (willHide ? animation.hide : animation.show).animationTimingFunction, ...this.props.contentStyle, + animationDuration: (willHide ? animation.hide : animation.show) + .animationDuration, + animationName: willHide + ? animation.hideContentAnimation + : animation.showContentAnimation, + animationTimingFunction: (willHide ? animation.hide : animation.show) + .animationTimingFunction, + ...this.props.contentStyle, } - const backdrop = this.props.backdrop - ? ( -
    - ) : undefined + const backdrop = this.props.backdrop ? ( +
    + ) : undefined if (willHide) { this.addTransitionListener(this.content, this.leave) @@ -219,7 +224,6 @@ class FadeModal extends Component { {backdrop} ) - } leave = () => { @@ -243,9 +247,12 @@ class FadeModal extends Component { hidden: false, }) - setTimeout(function () { - this.addTransitionListener(this.content, this.enter) - }.bind(this), 0) + setTimeout( + function () { + this.addTransitionListener(this.content, this.enter) + }.bind(this), + 0, + ) } hide = () => { @@ -267,9 +274,10 @@ class FadeModal extends Component { } closeOnEsc = (event) => { - if (this.props.keyboard && - (event.key === 'Escape' || - event.keyCode === 27)) { + if ( + this.props.keyboard && + (event.key === 'Escape' || event.keyCode === 27) + ) { this.hide() } } diff --git a/ui/app/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.js b/ui/app/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.js index 2e042a842..592528038 100644 --- a/ui/app/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.js +++ b/ui/app/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.js @@ -5,21 +5,20 @@ import * as actions from '../../../../store/actions' import Identicon from '../../../ui/identicon' import Button from '../../../ui/button' -function mapStateToProps (state) { +function mapStateToProps(state) { return { token: state.appState.modal.modalState.props.token, assetImages: state.metamask.assetImages, } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { hideModal: () => dispatch(actions.hideModal()), hideToken: (address) => { - dispatch(actions.removeToken(address)) - .then(() => { - dispatch(actions.hideModal()) - }) + dispatch(actions.removeToken(address)).then(() => { + dispatch(actions.hideModal()) + }) }, } } @@ -41,7 +40,7 @@ class HideTokenConfirmationModal extends Component { state = {} - render () { + render() { const { token, hideToken, hideModal, assetImages } = this.props const { symbol, address } = token const image = assetImages[address] @@ -86,4 +85,7 @@ class HideTokenConfirmationModal extends Component { } } -export default connect(mapStateToProps, mapDispatchToProps)(HideTokenConfirmationModal) +export default connect( + mapStateToProps, + mapDispatchToProps, +)(HideTokenConfirmationModal) diff --git a/ui/app/components/app/modals/loading-network-error/loading-network-error.component.js b/ui/app/components/app/modals/loading-network-error/loading-network-error.component.js index 6cac4942f..9f5d1ad07 100644 --- a/ui/app/components/app/modals/loading-network-error/loading-network-error.component.js +++ b/ui/app/components/app/modals/loading-network-error/loading-network-error.component.js @@ -7,13 +7,8 @@ const LoadingNetworkError = (props, context) => { const { hideModal } = props return ( - hideModal()} - submitText={t('tryAgain')} - > - + hideModal()} submitText={t('tryAgain')}> + ) } diff --git a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js index 3e1610965..df326978d 100644 --- a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js +++ b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js @@ -14,7 +14,7 @@ export default class MetaMetricsOptInModal extends Component { t: PropTypes.func, } - render () { + render() { const { metricsEvent, t } = this.context const { setParticipateInMetaMetrics, hideModal } = this.props @@ -26,14 +26,18 @@ export default class MetaMetricsOptInModal extends Component {
    -
    Help Us Improve MetaMask
    +
    + Help Us Improve MetaMask +
    - MetaMask would like to gather usage data to better understand how our users interact with the extension. This data - will be used to continually improve the usability and user experience of our product and the Ethereum ecosystem. + MetaMask would like to gather usage data to better understand + how our users interact with the extension. This data will be + used to continually improve the usability and user experience of + our product and the Ethereum ecosystem.
    - MetaMask will.. + MetaMask will..
    @@ -52,73 +56,83 @@ export default class MetaMetricsOptInModal extends Component {
    - Maintain a public aggregate dashboard to educate the community + Maintain a public aggregate dashboard to educate the + community
    - Never collect keys, addresses, transactions, balances, hashes, or any personal information + Never{' '} + collect keys, addresses, transactions, balances, hashes, or + any personal information
    - Never collect your full IP address + Never{' '} + collect your full IP address
    - Never sell data for profit. Ever! + Never sell + data for profit. Ever!
    - This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679. For more information in relation to our privacy practices, please see our  + This data is aggregated and is therefore anonymous for the + purposes of General Data Protection Regulation (EU) 2016/679. For + more information in relation to our privacy practices, please see + our  Privacy Policy here - . + + .
    { - setParticipateInMetaMetrics(false) - .then(() => { - metricsEvent({ + setParticipateInMetaMetrics(false).then(() => { + metricsEvent( + { eventOpts: { category: 'Onboarding', action: 'Metrics Option', name: 'Metrics Opt Out', }, isOptIn: true, - }, { + }, + { excludeMetaMetricsId: true, - }) - hideModal() - }) + }, + ) + hideModal() + }) }} cancelText={t('noThanks')} hideCancel={false} onSubmit={() => { - setParticipateInMetaMetrics(true) - .then(() => { - metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Metrics Option', - name: 'Metrics Opt In', - }, - isOptIn: true, - }) - hideModal() + setParticipateInMetaMetrics(true).then(() => { + metricsEvent({ + eventOpts: { + category: 'Onboarding', + action: 'Metrics Option', + name: 'Metrics Opt In', + }, + isOptIn: true, }) + hideModal() + }) }} submitText={t('affirmAgree')} submitButtonType="confirm" diff --git a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js index 8cef4a076..bb1322903 100644 --- a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js +++ b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js @@ -14,7 +14,8 @@ const mapStateToProps = (_, ownProps) => { const mapDispatchToProps = (dispatch) => { return { - setParticipateInMetaMetrics: (val) => dispatch(setParticipateInMetaMetrics(val)), + setParticipateInMetaMetrics: (val) => + dispatch(setParticipateInMetaMetrics(val)), } } diff --git a/ui/app/components/app/modals/metametrics-opt-in-modal/tests/metametrics-opt-in-modal.test.js b/ui/app/components/app/modals/metametrics-opt-in-modal/tests/metametrics-opt-in-modal.test.js index 9945ca73f..ec113f108 100644 --- a/ui/app/components/app/modals/metametrics-opt-in-modal/tests/metametrics-opt-in-modal.test.js +++ b/ui/app/components/app/modals/metametrics-opt-in-modal/tests/metametrics-opt-in-modal.test.js @@ -15,14 +15,12 @@ describe('MetaMetrics Opt In', function () { } beforeEach(function () { - wrapper = mount( - , { - context: { - metricsEvent: () => undefined, - t: (key) => messages[key].message, - }, + wrapper = mount(, { + context: { + metricsEvent: () => undefined, + t: (key) => messages[key].message, }, - ) + }) }) afterEach(function () { @@ -43,7 +41,9 @@ describe('MetaMetrics Opt In', function () { }) it('passes true to setParticipateInMetaMetrics and hides modal', function (done) { - const affirmAgree = wrapper.find('.btn-primary.page-container__footer-button') + const affirmAgree = wrapper.find( + '.btn-primary.page-container__footer-button', + ) affirmAgree.simulate('click') setImmediate(() => { @@ -53,5 +53,4 @@ describe('MetaMetrics Opt In', function () { done() }) }) - }) diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js index bc747f529..aac8e501a 100644 --- a/ui/app/components/app/modals/modal.js +++ b/ui/app/components/app/modals/modal.js @@ -361,14 +361,14 @@ const BACKDROPSTYLE = { backgroundColor: 'rgba(0, 0, 0, 0.5)', } -function mapStateToProps (state) { +function mapStateToProps(state) { return { active: state.appState.modal.open, modalState: state.appState.modal.modalState, } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { hideModal: (customOnHideOpts) => { dispatch(actions.hideModal()) @@ -379,7 +379,6 @@ function mapDispatchToProps (dispatch) { hideWarning: () => { dispatch(actions.hideWarning()) }, - } } @@ -391,15 +390,15 @@ class Modal extends Component { modalState: PropTypes.object.isRequired, } - hide () { + hide() { this.modalRef.hide() } - show () { + show() { this.modalRef.show() } - UNSAFE_componentWillReceiveProps (nextProps, _) { + UNSAFE_componentWillReceiveProps(nextProps, _) { if (nextProps.active) { this.show() } else if (this.props.active) { @@ -407,10 +406,11 @@ class Modal extends Component { } } - render () { + render() { const modal = MODALS[this.props.modalState.name || 'DEFAULT'] const { contents: children, disableBackdropClick = false } = modal - const modalStyle = modal[isMobileView() ? 'mobileModalStyle' : 'laptopModalStyle'] + const modalStyle = + modal[isMobileView() ? 'mobileModalStyle' : 'laptopModalStyle'] const contentStyle = modal.contentStyle || {} return ( diff --git a/ui/app/components/app/modals/new-account-modal/new-account-modal.component.js b/ui/app/components/app/modals/new-account-modal/new-account-modal.component.js index f560036ad..612947249 100644 --- a/ui/app/components/app/modals/new-account-modal/new-account-modal.component.js +++ b/ui/app/components/app/modals/new-account-modal/new-account-modal.component.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types' import Button from '../../../ui/button/button.component' export default class NewAccountModal extends Component { - static contextTypes = { t: PropTypes.func, } @@ -15,7 +14,9 @@ export default class NewAccountModal extends Component { } state = { - alias: this.context.t('newAccountNumberName', [this.props.newAccountNumber]), + alias: this.context.t('newAccountNumberName', [ + this.props.newAccountNumber, + ]), } onChange = (e) => { @@ -25,8 +26,7 @@ export default class NewAccountModal extends Component { } onSubmit = () => { - this.props.onSave(this.state.alias) - .then(this.props.hideModal) + this.props.onSave(this.state.alias).then(this.props.hideModal) } onKeyPress = (e) => { @@ -35,7 +35,7 @@ export default class NewAccountModal extends Component { } } - render () { + render() { const { t } = this.context return ( @@ -62,10 +62,7 @@ export default class NewAccountModal extends Component { />
    - ') + assert.equal( + blockExplorerLink.html(), + '', + ) }) }) diff --git a/ui/app/components/app/modals/transaction-confirmed/tests/transaction-confirmed.test.js b/ui/app/components/app/modals/transaction-confirmed/tests/transaction-confirmed.test.js index 971ed324c..f4d35faca 100644 --- a/ui/app/components/app/modals/transaction-confirmed/tests/transaction-confirmed.test.js +++ b/ui/app/components/app/modals/transaction-confirmed/tests/transaction-confirmed.test.js @@ -11,7 +11,8 @@ describe('Transaction Confirmed', function () { hideModal: sinon.spy(), } const wrapper = mount( - , { + , + { context: { t: (str) => str, }, diff --git a/ui/app/components/app/modals/transaction-confirmed/transaction-confirmed.component.js b/ui/app/components/app/modals/transaction-confirmed/transaction-confirmed.component.js index 0a98eb1a1..e34c4dc4d 100644 --- a/ui/app/components/app/modals/transaction-confirmed/transaction-confirmed.component.js +++ b/ui/app/components/app/modals/transaction-confirmed/transaction-confirmed.component.js @@ -22,21 +22,18 @@ export default class TransactionConfirmed extends PureComponent { } } - render () { + render() { const { t } = this.context return ( - +
    - { `${t('confirmed')}!` } + {`${t('confirmed')}!`}
    - { t('initialTransactionConfirmed') } + {t('initialTransactionConfirmed')}
    diff --git a/ui/app/components/app/multiple-notifications/multiple-notifications.component.js b/ui/app/components/app/multiple-notifications/multiple-notifications.component.js index 410bef6a9..e8dcebf13 100644 --- a/ui/app/components/app/multiple-notifications/multiple-notifications.component.js +++ b/ui/app/components/app/multiple-notifications/multiple-notifications.component.js @@ -17,7 +17,7 @@ export default class MultipleNotifications extends PureComponent { showAll: false, } - render () { + render() { const { showAll } = this.state const { children, classNames } = this.props @@ -33,7 +33,7 @@ export default class MultipleNotifications extends PureComponent { 'home-notification-wrapper--show-first': !showAll, })} > - { childrenToRender } + {childrenToRender}
    this.setState({ showAll: !showAll })} @@ -41,7 +41,7 @@ export default class MultipleNotifications extends PureComponent { {childrenToRender.length > 1 ? ( ) : null} diff --git a/ui/app/components/app/network-display/network-display.component.js b/ui/app/components/app/network-display/network-display.component.js index eb89755c3..0838ddc57 100644 --- a/ui/app/components/app/network-display/network-display.component.js +++ b/ui/app/components/app/network-display/network-display.component.js @@ -32,49 +32,56 @@ export default class NetworkDisplay extends Component { t: PropTypes.func, } - renderNetworkIcon () { + renderNetworkIcon() { const { network } = this.props const networkClass = networkIdToTypeMap[network] - return networkClass - ?
    - : ( -
    - ) + return networkClass ? ( +
    + ) : ( +
    + ) } - render () { - const { colored, network, provider: { type, nickname } } = this.props + render() { + const { + colored, + network, + provider: { type, nickname }, + } = this.props const networkClass = networkIdToTypeMap[network] return (
    - { - networkClass - ?
    - : ( -
    - ) - } + {networkClass ? ( +
    + ) : ( +
    + )}
    - { type === 'rpc' && nickname ? nickname : this.context.t(type) } + {type === 'rpc' && nickname ? nickname : this.context.t(type)}
    ) diff --git a/ui/app/components/app/network.js b/ui/app/components/app/network.js index f66a0182a..387dbb536 100644 --- a/ui/app/components/app/network.js +++ b/ui/app/components/app/network.js @@ -3,7 +3,13 @@ import React, { Component } from 'react' import classnames from 'classnames' import NetworkDropdownIcon from './dropdowns/components/network-dropdown-icon' -function NetworkIndicator ({ disabled, children, hoverText, onClick, providerName }) { +function NetworkIndicator({ + disabled, + children, + hoverText, + onClick, + providerName, +}) { return (
    + + + + + - { - networkNumber === 'loading' - ? ( - onClick(event)}> - - - ) - : ( - - ) - } + {networkNumber === 'loading' ? ( + onClick(event)} + > + + + ) : ( + + )}
    {providerNick || t('privateNetwork')}
    diff --git a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js index 94895e92d..650b9333b 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js @@ -5,7 +5,6 @@ import Tooltip from '../../../ui/tooltip' import CheckBox from '../../../ui/check-box' export default class PermissionPageContainerContent extends PureComponent { - static propTypes = { domainMetadata: PropTypes.shape({ extensionId: PropTypes.string, @@ -29,19 +28,18 @@ export default class PermissionPageContainerContent extends PureComponent { t: PropTypes.func, } - renderRequestedPermissions () { - const { - selectedPermissions, onPermissionToggle, - } = this.props + renderRequestedPermissions() { + const { selectedPermissions, onPermissionToggle } = this.props const { t } = this.context const items = Object.keys(selectedPermissions).map((permissionName) => { - const description = t(permissionName) // don't allow deselecting eth_accounts const isDisabled = permissionName === 'eth_accounts' const isChecked = Boolean(selectedPermissions[permissionName]) - const title = isChecked ? t('permissionCheckedIconDescription') : t('permissionUncheckedIconDescription') + const title = isChecked + ? t('permissionCheckedIconDescription') + : t('permissionUncheckedIconDescription') return (
    - { selectedIdentities.slice(0, 6).map((identity, index) => { + {selectedIdentities.slice(0, 6).map((identity, index) => { return ( -
    - { this.getAccountDescriptor(identity) } +
    + {this.getAccountDescriptor(identity)}
    ) - }) } - { selectedIdentities.length > 6 + })} + {selectedIdentities.length > 6 ? t('plusXMore', [selectedIdentities.length - 6]) - : null - } + : null}
    - )} + } > - { textContent } + {textContent} ) } - getTitle () { - const { domainMetadata, selectedIdentities, allIdentitiesSelected } = this.props + getTitle() { + const { + domainMetadata, + selectedIdentities, + allIdentitiesSelected, + } = this.props const { t } = this.context if (domainMetadata.extensionId) { return t('externalExtension', [domainMetadata.extensionId]) } else if (allIdentitiesSelected) { - return t( - 'connectToAll', - [this.renderAccountTooltip(t('connectToAllAccounts'))], - ) + return t('connectToAll', [ + this.renderAccountTooltip(t('connectToAllAccounts')), + ]) } else if (selectedIdentities.length > 1) { - return t( - 'connectToMultiple', - [ - this.renderAccountTooltip(t('connectToMultipleNumberOfAccounts', [selectedIdentities.length])), - ], - ) + return t('connectToMultiple', [ + this.renderAccountTooltip( + t('connectToMultipleNumberOfAccounts', [selectedIdentities.length]), + ), + ]) } - return t('connectTo', [ - this.getAccountDescriptor(selectedIdentities[0]), - ]) + return t('connectTo', [this.getAccountDescriptor(selectedIdentities[0])]) } - render () { + render() { const { domainMetadata } = this.props const { t } = this.context @@ -143,14 +142,15 @@ export default class PermissionPageContainerContent extends PureComponent { icon={domainMetadata.icon} iconName={domainMetadata.name} headerTitle={title} - headerText={ domainMetadata.extensionId - ? t('allowExternalExtensionTo', [domainMetadata.extensionId]) - : t('allowThisSiteTo') + headerText={ + domainMetadata.extensionId + ? t('allowExternalExtensionTo', [domainMetadata.extensionId]) + : t('allowThisSiteTo') } siteOrigin={domainMetadata.origin} />
    - { this.renderRequestedPermissions() } + {this.renderRequestedPermissions()}
    diff --git a/ui/app/components/app/permission-page-container/permission-page-container.component.js b/ui/app/components/app/permission-page-container/permission-page-container.component.js index 8598ab976..14441adfa 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container.component.js @@ -6,7 +6,6 @@ import PermissionsConnectFooter from '../permissions-connect-footer' import { PermissionPageContainerContent } from '.' export default class PermissionPageContainer extends Component { - static propTypes = { approvePermissionsRequest: PropTypes.func.isRequired, rejectPermissionsRequest: PropTypes.func.isRequired, @@ -41,7 +40,7 @@ export default class PermissionPageContainer extends Component { ), } - componentDidUpdate () { + componentDidUpdate() { const newMethodNames = this.getRequestedMethodNames(this.props) if (!isEqual(Object.keys(this.state.selectedPermissions), newMethodNames)) { @@ -52,17 +51,14 @@ export default class PermissionPageContainer extends Component { } } - getRequestedMethodState (methodNames) { - return methodNames.reduce( - (acc, methodName) => { - acc[methodName] = true - return acc - }, - {}, - ) + getRequestedMethodState(methodNames) { + return methodNames.reduce((acc, methodName) => { + acc[methodName] = true + return acc + }, {}) } - getRequestedMethodNames (props) { + getRequestedMethodNames(props) { return Object.keys(props.request.permissions || {}) } @@ -75,7 +71,7 @@ export default class PermissionPageContainer extends Component { }) } - componentDidMount () { + componentDidMount() { this.context.metricsEvent({ eventOpts: { category: 'Auth', @@ -92,7 +88,10 @@ export default class PermissionPageContainer extends Component { onSubmit = () => { const { - request: _request, approvePermissionsRequest, rejectPermissionsRequest, selectedIdentities, + request: _request, + approvePermissionsRequest, + rejectPermissionsRequest, + selectedIdentities, } = this.props const request = { @@ -107,13 +106,16 @@ export default class PermissionPageContainer extends Component { }) if (Object.keys(request.permissions).length > 0) { - approvePermissionsRequest(request, selectedIdentities.map((selectedIdentity) => selectedIdentity.address)) + approvePermissionsRequest( + request, + selectedIdentities.map((selectedIdentity) => selectedIdentity.address), + ) } else { rejectPermissionsRequest(request.metadata.id) } } - render () { + render() { const { requestMetadata, targetDomainMetadata, diff --git a/ui/app/components/app/permission-page-container/permission-page-container.container.js b/ui/app/components/app/permission-page-container/permission-page-container.container.js index bae0f43d9..e0b3ff49f 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container.container.js +++ b/ui/app/components/app/permission-page-container/permission-page-container.container.js @@ -6,7 +6,9 @@ const mapStateToProps = (state, ownProps) => { const { selectedIdentities } = ownProps const allIdentities = getMetaMaskIdentities(state) - const allIdentitiesSelected = Object.keys(selectedIdentities).length === Object.keys(allIdentities).length && selectedIdentities.length > 1 + const allIdentitiesSelected = + Object.keys(selectedIdentities).length === + Object.keys(allIdentities).length && selectedIdentities.length > 1 return { allIdentitiesSelected, diff --git a/ui/app/components/app/permissions-connect-footer/permissions-connect-footer.component.js b/ui/app/components/app/permissions-connect-footer/permissions-connect-footer.component.js index 7bc2a8afd..5a1aef1a4 100644 --- a/ui/app/components/app/permissions-connect-footer/permissions-connect-footer.component.js +++ b/ui/app/components/app/permissions-connect-footer/permissions-connect-footer.component.js @@ -6,18 +6,22 @@ export default class PermissionsConnectFooter extends Component { t: PropTypes.func, } - render () { + render() { const { t } = this.context return (
    -
    { t('onlyConnectTrust') }
    +
    {t('onlyConnectTrust')}
    { - global.platform.openTab({ url: 'https://medium.com/metamask/privacy-mode-is-now-enabled-by-default-1c1c957f4d57' }) + global.platform.openTab({ + url: + 'https://medium.com/metamask/privacy-mode-is-now-enabled-by-default-1c1c957f4d57', + }) }} - >{ t('learnMore') } + > + {t('learnMore')}
    diff --git a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js index c1bc5d775..0a71d0d61 100644 --- a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js +++ b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js @@ -17,28 +17,24 @@ export default class PermissionsConnectHeader extends Component { headerText: '', } - renderHeaderIcon () { + renderHeaderIcon() { const { icon, iconName, siteOrigin } = this.props return (
    - +
    {siteOrigin}
    ) } - render () { + render() { const { headerTitle, headerText } = this.props return (
    - { this.renderHeaderIcon() } -
    - { headerTitle } -
    -
    - { headerText } -
    + {this.renderHeaderIcon()} +
    {headerTitle}
    +
    {headerText}
    ) } diff --git a/ui/app/components/app/selected-account/selected-account.component.js b/ui/app/components/app/selected-account/selected-account.component.js index c1756b5ee..36ce7c46c 100644 --- a/ui/app/components/app/selected-account/selected-account.component.js +++ b/ui/app/components/app/selected-account/selected-account.component.js @@ -18,18 +18,18 @@ class SelectedAccount extends Component { selectedIdentity: PropTypes.object.isRequired, } - componentDidMount () { + componentDidMount() { this.copyTimeout = null } - componentWillUnmount () { + componentWillUnmount() { if (this.copyTimeout) { clearTimeout(this.copyTimeout) this.copyTimeout = null } } - render () { + render() { const { t } = this.context const { selectedIdentity } = this.props const checksummedAddress = checksumAddress(selectedIdentity.address) @@ -39,21 +39,26 @@ class SelectedAccount extends Component {
    { this.setState({ copied: true }) - this.copyTimeout = setTimeout(() => this.setState({ copied: false }), 3000) + this.copyTimeout = setTimeout( + () => this.setState({ copied: false }), + 3000, + ) copyToClipboard(checksummedAddress) }} >
    - { selectedIdentity.name } + {selectedIdentity.name}
    - { shortenAddress(checksummedAddress) } + {shortenAddress(checksummedAddress)}
    diff --git a/ui/app/components/app/selected-account/tests/selected-account-component.test.js b/ui/app/components/app/selected-account/tests/selected-account-component.test.js index 943ccf00a..d0a608f3e 100644 --- a/ui/app/components/app/selected-account/tests/selected-account-component.test.js +++ b/ui/app/components/app/selected-account/tests/selected-account-component.test.js @@ -5,13 +5,20 @@ import SelectedAccount from '../selected-account.component' describe('SelectedAccount Component', function () { it('should render checksummed address', function () { - const wrapper = render(( + const wrapper = render( - ), { context: { t: () => undefined } }) + selectedIdentity={{ + name: 'testName', + address: '0x1b82543566f41a7db9a9a75fc933c340ffb55c9d', + }} + />, + { context: { t: () => undefined } }, + ) // Checksummed version of address is displayed - assert.equal(wrapper.find('.selected-account__address').text(), '0x1B82...5C9D') + assert.equal( + wrapper.find('.selected-account__address').text(), + '0x1B82...5C9D', + ) assert.equal(wrapper.find('.selected-account__name').text(), 'testName') }) }) diff --git a/ui/app/components/app/sidebars/sidebar.component.js b/ui/app/components/app/sidebars/sidebar.component.js index 3f514001a..12dee2c05 100644 --- a/ui/app/components/app/sidebars/sidebar.component.js +++ b/ui/app/components/app/sidebars/sidebar.component.js @@ -4,7 +4,6 @@ import ReactCSSTransitionGroup from 'react-transition-group/CSSTransitionGroup' import CustomizeGas from '../gas-customization/gas-modal-page-container' export default class Sidebar extends Component { - static propTypes = { sidebarOpen: PropTypes.bool, hideSidebar: PropTypes.func, @@ -15,7 +14,7 @@ export default class Sidebar extends Component { onOverlayClose: PropTypes.func, } - renderOverlay () { + renderOverlay() { const { onOverlayClose } = this.props return ( @@ -29,25 +28,28 @@ export default class Sidebar extends Component { ) } - renderSidebarContent () { + renderSidebarContent() { const { type, sidebarProps = {} } = this.props const { transaction = {} } = sidebarProps switch (type) { case 'customize-gas': - return
    + return ( +
    + +
    + ) default: return null } - } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { if (!prevProps.sidebarShouldClose && this.props.sidebarShouldClose) { this.props.hideSidebar() } } - render () { + render() { const { transitionName, sidebarOpen, sidebarShouldClose } = this.props return ( @@ -57,11 +59,12 @@ export default class Sidebar extends Component { transitionEnterTimeout={300} transitionLeaveTimeout={200} > - { sidebarOpen && !sidebarShouldClose ? this.renderSidebarContent() : null } + {sidebarOpen && !sidebarShouldClose + ? this.renderSidebarContent() + : null} - { sidebarOpen && !sidebarShouldClose ? this.renderOverlay() : null } + {sidebarOpen && !sidebarShouldClose ? this.renderOverlay() : null}
    ) } - } diff --git a/ui/app/components/app/sidebars/tests/sidebars-component.test.js b/ui/app/components/app/sidebars/tests/sidebars-component.test.js index ea9958775..22a7cbc2c 100644 --- a/ui/app/components/app/sidebars/tests/sidebars-component.test.js +++ b/ui/app/components/app/sidebars/tests/sidebars-component.test.js @@ -15,14 +15,14 @@ describe('Sidebar Component', function () { let wrapper beforeEach(function () { - wrapper = shallow(( + wrapper = shallow( - )) + />, + ) }) afterEach(function () { @@ -85,7 +85,16 @@ describe('Sidebar Component', function () { assert(wrapper.children().at(1).hasClass('sidebar-overlay')) assert.equal(wrapper.children().at(0).children().length, 1) assert(wrapper.children().at(0).children().at(0).hasClass('sidebar-left')) - assert(wrapper.children().at(0).children().at(0).children().at(0).is(CustomizeGas)) + assert( + wrapper + .children() + .at(0) + .children() + .at(0) + .children() + .at(0) + .is(CustomizeGas), + ) }) }) }) diff --git a/ui/app/components/app/signature-request-original/signature-request-original.component.js b/ui/app/components/app/signature-request-original/signature-request-original.component.js index 31c214e38..b961f4def 100644 --- a/ui/app/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/app/components/app/signature-request-original/signature-request-original.component.js @@ -4,7 +4,10 @@ import ethUtil from 'ethereumjs-util' import classnames from 'classnames' import { ObjectInspector } from 'react-inspector' -import { ENVIRONMENT_TYPE_NOTIFICATION, MESSAGE_TYPE } from '../../../../../app/scripts/lib/enums' +import { + ENVIRONMENT_TYPE_NOTIFICATION, + MESSAGE_TYPE, +} from '../../../../../app/scripts/lib/enums' import { getEnvironmentType } from '../../../../../app/scripts/lib/util' import Identicon from '../../ui/identicon' import AccountListItem from '../account-list-item' @@ -73,7 +76,7 @@ export default class SignatureRequestOriginal extends Component {
    - { this.context.t('sigRequest') } + {this.context.t('sigRequest')}
    @@ -89,13 +92,11 @@ export default class SignatureRequestOriginal extends Component { return (
    - { `${this.context.t('account')}:` } + {`${this.context.t('account')}:`}
    - +
    ) @@ -103,7 +104,9 @@ export default class SignatureRequestOriginal extends Component { renderBalance = () => { const { conversionRate } = this.props - const { fromAccount: { balance } } = this.state + const { + fromAccount: { balance }, + } = this.state const balanceInEther = conversionUtil(balance, { fromNumericBase: 'hex', @@ -116,10 +119,10 @@ export default class SignatureRequestOriginal extends Component { return (
    - { `${this.context.t('balance')}:` } + {`${this.context.t('balance')}:`}
    - { `${balanceInEther} ETH` } + {`${balanceInEther} ETH`}
    ) @@ -130,10 +133,7 @@ export default class SignatureRequestOriginal extends Component { return (
    - +
    ) } @@ -141,9 +141,9 @@ export default class SignatureRequestOriginal extends Component { renderAccountInfo = () => { return (
    - { this.renderAccount() } - { this.renderRequestIcon() } - { this.renderBalance() } + {this.renderAccount()} + {this.renderRequestIcon()} + {this.renderBalance()}
    ) } @@ -152,7 +152,7 @@ export default class SignatureRequestOriginal extends Component { return (
    - { this.context.t('yourSigRequested') } + {this.context.t('yourSigRequested')}
    ) @@ -172,30 +172,22 @@ export default class SignatureRequestOriginal extends Component { const { domain, message } = JSON.parse(data) return (
    - { - domain - ? ( -
    -

    - Domain -

    - -
    - ) - : '' - } - { - message - ? ( -
    -

    - Message -

    - -
    - ) - : '' - } + {domain ? ( +
    +

    Domain

    + +
    + ) : ( + '' + )} + {message ? ( +
    +

    Message

    + +
    + ) : ( + '' + )}
    ) } @@ -205,10 +197,15 @@ export default class SignatureRequestOriginal extends Component { let notice = `${this.context.t('youSign')}:` const { txData } = this.props - const { type, msgParams: { data } } = txData + const { + type, + msgParams: { data }, + } = txData if (type === MESSAGE_TYPE.PERSONAL_SIGN) { - rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }] + rows = [ + { name: this.context.t('message'), value: this.msgHexToText(data) }, + ] } else if (type === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA) { rows = data } else if (type === MESSAGE_TYPE.ETH_SIGN) { @@ -218,57 +215,57 @@ export default class SignatureRequestOriginal extends Component { return (
    - { this.renderAccountInfo() } - { this.renderRequestInfo() } + {this.renderAccountInfo()} + {this.renderRequestInfo()}
    - { notice } - { - type === MESSAGE_TYPE.ETH_SIGN - ? ( - { - global.platform.openTab({ - url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751', - }) - }} - > - { this.context.t('learnMore') } - - ) - : null - } + {notice} + {type === MESSAGE_TYPE.ETH_SIGN ? ( + { + global.platform.openTab({ + url: + 'https://metamask.zendesk.com/hc/en-us/articles/360015488751', + }) + }} + > + {this.context.t('learnMore')} + + ) : null}
    - { - rows.map(({ name, value }, index) => { - if (typeof value === 'boolean') { - // eslint-disable-next-line no-param-reassign - value = value.toString() - } - return ( -
    -
    - { `${name}:` } -
    -
    - { value } -
    -
    - ) - }) - } + {rows.map(({ name, value }, index) => { + if (typeof value === 'boolean') { + // eslint-disable-next-line no-param-reassign + value = value.toString() + } + return ( +
    +
    {`${name}:`}
    +
    {value}
    +
    + ) + })}
    ) } renderFooter = () => { - const { cancel, clearConfirmTransaction, history, mostRecentOverviewPage, sign } = this.props + const { + cancel, + clearConfirmTransaction, + history, + mostRecentOverviewPage, + sign, + } = this.props return (
    @@ -290,7 +287,7 @@ export default class SignatureRequestOriginal extends Component { history.push(mostRecentOverviewPage) }} > - { this.context.t('cancel') } + {this.context.t('cancel')}
    ) @@ -320,9 +317,9 @@ export default class SignatureRequestOriginal extends Component { render = () => { return (
    - { this.renderHeader() } - { this.renderBody() } - { this.renderFooter() } + {this.renderHeader()} + {this.renderBody()} + {this.renderFooter()}
    ) } diff --git a/ui/app/components/app/signature-request-original/signature-request-original.container.js b/ui/app/components/app/signature-request-original/signature-request-original.container.js index 8d0a397ef..9a421aa67 100644 --- a/ui/app/components/app/signature-request-original/signature-request-original.container.js +++ b/ui/app/components/app/signature-request-original/signature-request-original.container.js @@ -13,7 +13,7 @@ import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/conf import { getMostRecentOverviewPage } from '../../../ducks/history/history' import SignatureRequestOriginal from './signature-request-original.component' -function mapStateToProps (state) { +function mapStateToProps(state) { return { requester: null, requesterAddress: null, @@ -24,14 +24,14 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { goHome: () => dispatch(goHome()), clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), } } -function mergeProps (stateProps, dispatchProps, ownProps) { +function mergeProps(stateProps, dispatchProps, ownProps) { const { signPersonalMessage, signTypedMessage, @@ -45,7 +45,10 @@ function mergeProps (stateProps, dispatchProps, ownProps) { const { allAccounts } = stateProps delete stateProps.allAccounts - const { type, msgParams: { from } } = txData + const { + type, + msgParams: { from }, + } = txData const fromAccount = getAccountByAddress(allAccounts, from) diff --git a/ui/app/components/app/signature-request/signature-request-footer/signature-request-footer.component.js b/ui/app/components/app/signature-request/signature-request-footer/signature-request-footer.component.js index 591b9a03a..0f925e3e3 100644 --- a/ui/app/components/app/signature-request/signature-request-footer/signature-request-footer.component.js +++ b/ui/app/components/app/signature-request/signature-request-footer/signature-request-footer.component.js @@ -12,12 +12,16 @@ export default class SignatureRequestFooter extends PureComponent { t: PropTypes.func, } - render () { + render() { const { cancelAction, signAction } = this.props return (
    - - + +
    ) } diff --git a/ui/app/components/app/signature-request/signature-request-header/signature-request-header.component.js b/ui/app/components/app/signature-request/signature-request-header/signature-request-header.component.js index 2ec74748c..42468d276 100644 --- a/ui/app/components/app/signature-request/signature-request-header/signature-request-header.component.js +++ b/ui/app/components/app/signature-request/signature-request-header/signature-request-header.component.js @@ -8,17 +8,13 @@ export default class SignatureRequestHeader extends PureComponent { fromAccount: PropTypes.object, } - render () { + render() { const { fromAccount } = this.props return (
    - {fromAccount && ( - - )} + {fromAccount && }
    diff --git a/ui/app/components/app/signature-request/signature-request-message/signature-request-message.component.js b/ui/app/components/app/signature-request/signature-request-message/signature-request-message.component.js index 5c4b455d3..27a3e2563 100644 --- a/ui/app/components/app/signature-request/signature-request-message/signature-request-message.component.js +++ b/ui/app/components/app/signature-request/signature-request-message/signature-request-message.component.js @@ -11,36 +11,45 @@ export default class SignatureRequestMessage extends PureComponent { t: PropTypes.func, } - renderNode (data) { + renderNode(data) { return (
    {Object.entries(data).map(([label, value], i) => (
    - {label}: - { - typeof value === 'object' && value !== null ? - this.renderNode(value) - : {value} - } + + {label}:{' '} + + {typeof value === 'object' && value !== null ? ( + this.renderNode(value) + ) : ( + + {value} + + )}
    ))}
    ) } - render () { + render() { const { data } = this.props return (
    -
    {this.context.t('signatureRequest1')}
    +
    + {this.context.t('signatureRequest1')} +
    -
    {this.context.t('signatureRequest1')}
    +
    + {this.context.t('signatureRequest1')} +
    {this.renderNode(data)}
    diff --git a/ui/app/components/app/signature-request/signature-request.component.js b/ui/app/components/app/signature-request/signature-request.component.js index d3a42107c..712c5e8c2 100644 --- a/ui/app/components/app/signature-request/signature-request.component.js +++ b/ui/app/components/app/signature-request/signature-request.component.js @@ -26,7 +26,7 @@ export default class SignatureRequest extends PureComponent { metricsEvent: PropTypes.func, } - componentDidMount () { + componentDidMount() { const { clearConfirmTransaction, cancel } = this.props const { metricsEvent } = this.context if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { @@ -44,14 +44,19 @@ export default class SignatureRequest extends PureComponent { } } - formatWallet (wallet) { - return `${wallet.slice(0, 8)}...${wallet.slice(wallet.length - 8, wallet.length)}` + formatWallet(wallet) { + return `${wallet.slice(0, 8)}...${wallet.slice( + wallet.length - 8, + wallet.length, + )}` } - render () { + render() { const { fromAccount, - txData: { msgParams: { data, origin } }, + txData: { + msgParams: { data, origin }, + }, cancel, sign, } = this.props @@ -62,18 +67,23 @@ export default class SignatureRequest extends PureComponent {
    -
    {this.context.t('sigRequest')}
    -
    -
    { domain.name && domain.name[0] }
    -
    - +
    + {this.context.t('sigRequest')} +
    +
    +
    + {domain.name && domain.name[0]} +
    +
    + +
    +
    + {domain.name}
    -
    {domain.name}
    {origin}
    -
    {this.formatWallet(fromAddress)}
    +
    + {this.formatWallet(fromAddress)} +
    diff --git a/ui/app/components/app/signature-request/signature-request.container.js b/ui/app/components/app/signature-request/signature-request.container.js index 939741904..0a521db4b 100644 --- a/ui/app/components/app/signature-request/signature-request.container.js +++ b/ui/app/components/app/signature-request/signature-request.container.js @@ -1,26 +1,24 @@ import { connect } from 'react-redux' import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck' -import { - accountsWithSendEtherInfoSelector, -} from '../../../selectors' +import { accountsWithSendEtherInfoSelector } from '../../../selectors' import { getAccountByAddress } from '../../../helpers/utils/util' import { MESSAGE_TYPE } from '../../../../../app/scripts/lib/enums' import SignatureRequest from './signature-request.component' -function mapStateToProps (state) { +function mapStateToProps(state) { return { // not forwarded to component allAccounts: accountsWithSendEtherInfoSelector(state), } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), } } -function mergeProps (stateProps, dispatchProps, ownProps) { +function mergeProps(stateProps, dispatchProps, ownProps) { const { allAccounts } = stateProps const { signPersonalMessage, @@ -32,7 +30,10 @@ function mergeProps (stateProps, dispatchProps, ownProps) { txData, } = ownProps - const { type, msgParams: { from } } = txData + const { + type, + msgParams: { from }, + } = txData const fromAccount = getAccountByAddress(allAccounts, from) @@ -60,4 +61,8 @@ function mergeProps (stateProps, dispatchProps, ownProps) { } } -export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(SignatureRequest) +export default connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(SignatureRequest) diff --git a/ui/app/components/app/signature-request/tests/signature-request.test.js b/ui/app/components/app/signature-request/tests/signature-request.test.js index 5d2874833..331abac04 100644 --- a/ui/app/components/app/signature-request/tests/signature-request.test.js +++ b/ui/app/components/app/signature-request/tests/signature-request.test.js @@ -7,7 +7,7 @@ describe('Signature Request Component', function () { describe('render', function () { const fromAddress = '0x123456789abcdef' it('should render a div with one child', function () { - const wrapper = shallow(( + const wrapper = shallow( undefined} cancel={() => undefined} @@ -19,8 +19,8 @@ describe('Signature Request Component', function () { }, }} fromAccount={{ address: fromAddress }} - /> - )) + />, + ) assert(wrapper.is('div')) assert.equal(wrapper.length, 1) diff --git a/ui/app/components/app/tab-bar/tab-bar.js b/ui/app/components/app/tab-bar/tab-bar.js index 6abd56936..15083cb85 100644 --- a/ui/app/components/app/tab-bar/tab-bar.js +++ b/ui/app/components/app/tab-bar/tab-bar.js @@ -17,7 +17,9 @@ const TabBar = (props) => { >
    {content}
    -
    {description}
    +
    + {description} +
    diff --git a/ui/app/components/app/tests/signature-request.test.js b/ui/app/components/app/tests/signature-request.test.js index 9efd70973..f95bed3af 100644 --- a/ui/app/components/app/tests/signature-request.test.js +++ b/ui/app/components/app/tests/signature-request.test.js @@ -20,9 +20,7 @@ describe('Signature Request', function () { balance: '0x03', }, }, - cachedBalances: { - - }, + cachedBalances: {}, selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', }, } @@ -42,7 +40,8 @@ describe('Signature Request', function () { txData: { msgParams: { id: 1, - data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":"4","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}', + data: + '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":"4","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}', from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', origin: 'test.domain', }, @@ -56,7 +55,8 @@ describe('Signature Request', function () { wrapper = mountWithRouter( - , store, + , + store, ) }) @@ -77,5 +77,4 @@ describe('Signature Request', function () { assert(props.sign.calledOnce) }) - }) diff --git a/ui/app/components/app/token-cell/token-cell.js b/ui/app/components/app/token-cell/token-cell.js index f97287d2d..9a7673588 100644 --- a/ui/app/components/app/token-cell/token-cell.js +++ b/ui/app/components/app/token-cell/token-cell.js @@ -7,7 +7,7 @@ import { getSelectedAddress } from '../../../selectors' import { useI18nContext } from '../../../hooks/useI18nContext' import { useTokenFiatAmount } from '../../../hooks/useTokenFiatAmount' -export default function TokenCell ({ +export default function TokenCell({ address, decimals, outdatedBalance, @@ -21,25 +21,25 @@ export default function TokenCell ({ const formattedFiat = useTokenFiatAmount(address, string, symbol) - const warning = outdatedBalance - ? ( - - { t('troubleTokenBalances') } - - { t('here') } - - - ) - : null + const warning = outdatedBalance ? ( + + {t('troubleTokenBalances')} + + {t('here')} + + + ) : null return ( - ) } diff --git a/ui/app/components/app/token-cell/token-cell.test.js b/ui/app/components/app/token-cell/token-cell.test.js index 0e49a14cc..1e876cfb3 100644 --- a/ui/app/components/app/token-cell/token-cell.test.js +++ b/ui/app/components/app/token-cell/token-cell.test.js @@ -20,7 +20,7 @@ describe('Token Cell', function () { contractExchangeRates: { '0xAnotherToken': 0.015, }, - conversionRate: 7.00, + conversionRate: 7.0, preferences: {}, provider: { chainId: '1', diff --git a/ui/app/components/app/token-list/token-list.js b/ui/app/components/app/token-list/token-list.js index b71e6930b..8e4ead9f9 100644 --- a/ui/app/components/app/token-list/token-list.js +++ b/ui/app/components/app/token-list/token-list.js @@ -9,7 +9,7 @@ import { useTokenTracker } from '../../../hooks/useTokenTracker' import { getAssetImages } from '../../../selectors' import { getTokens } from '../../../ducks/metamask/metamask' -export default function TokenList ({ onTokenClick }) { +export default function TokenList({ onTokenClick }) { const t = useI18nContext() const assetImages = useSelector(getAssetImages) // use `isEqual` comparison function because the token array is serialized diff --git a/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.component.test.js b/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.component.test.js index 9b3c39792..ec5cbb3df 100644 --- a/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.component.test.js +++ b/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.component.test.js @@ -8,25 +8,32 @@ describe('TransactionActivityLog Component', function () { const activities = [ { eventKey: 'transactionCreated', - hash: '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', + hash: + '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', id: 2005383477493174, timestamp: 1543957986150, value: '0x2386f26fc10000', - }, { + }, + { eventKey: 'transactionSubmitted', - hash: '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', + hash: + '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', id: 2005383477493174, timestamp: 1543957987853, value: '0x1319718a5000', - }, { + }, + { eventKey: 'transactionResubmitted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + hash: + '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', id: 2005383477493175, timestamp: 1543957991563, value: '0x1502634b5800', - }, { + }, + { eventKey: 'transactionConfirmed', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + hash: + '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', id: 2005383477493175, timestamp: 1543958029960, value: '0x1502634b5800', @@ -59,21 +66,26 @@ describe('TransactionActivityLog Component', function () { id: 1, timestamp: 1, value: '0x1', - }, { + }, + { eventKey: 'transactionSubmitted', hash: '0xa', id: 1, timestamp: 2, value: '0x1', - }, { + }, + { eventKey: 'transactionResubmitted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + hash: + '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', id: 2, timestamp: 3, value: '0x1', - }, { + }, + { eventKey: 'transactionCancelAttempted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + hash: + '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', id: 3, timestamp: 4, value: '0x1', @@ -97,7 +109,10 @@ describe('TransactionActivityLog Component', function () { assert.ok(wrapper.hasClass('transaction-activity-log')) assert.ok(wrapper.hasClass('test-class')) - assert.equal(wrapper.find('.transaction-activity-log__action-link').length, 2) + assert.equal( + wrapper.find('.transaction-activity-log__action-link').length, + 2, + ) }) it('should not render inline retry and cancel buttons for newer pending transactions', function () { @@ -108,21 +123,26 @@ describe('TransactionActivityLog Component', function () { id: 1, timestamp: 1, value: '0x1', - }, { + }, + { eventKey: 'transactionSubmitted', hash: '0xa', id: 1, timestamp: 2, value: '0x1', - }, { + }, + { eventKey: 'transactionResubmitted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + hash: + '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', id: 2, timestamp: 3, value: '0x1', - }, { + }, + { eventKey: 'transactionCancelAttempted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + hash: + '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', id: 3, timestamp: 4, value: '0x1', @@ -146,6 +166,9 @@ describe('TransactionActivityLog Component', function () { assert.ok(wrapper.hasClass('transaction-activity-log')) assert.ok(wrapper.hasClass('test-class')) - assert.equal(wrapper.find('.transaction-activity-log__action-link').length, 0) + assert.equal( + wrapper.find('.transaction-activity-log__action-link').length, + 0, + ) }) }) diff --git a/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.container.test.js b/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.container.test.js index 6d72794f3..b756a5962 100644 --- a/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.container.test.js +++ b/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.container.test.js @@ -22,7 +22,10 @@ describe('TransactionActivityLog container', function () { }, } - assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45, nativeCurrency: 'ETH' }) + assert.deepEqual(mapStateToProps(mockState), { + conversionRate: 280.45, + nativeCurrency: 'ETH', + }) }) }) }) diff --git a/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.util.test.js b/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.util.test.js index 7e4a4313a..b36d14c5f 100644 --- a/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.util.test.js +++ b/ui/app/components/app/transaction-activity-log/tests/transaction-activity-log.util.test.js @@ -1,5 +1,8 @@ import assert from 'assert' -import { combineTransactionHistories, getActivities } from '../transaction-activity-log.util' +import { + combineTransactionHistories, + getActivities, +} from '../transaction-activity-log.util' describe('TransactionActivityLog utils', function () { describe('combineTransactionHistories', function () { @@ -10,26 +13,57 @@ describe('TransactionActivityLog utils', function () { it('should return activities for an array of transactions', function () { const transactions = [ { - hash: '0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3', + hash: + '0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3', history: [ { - 'id': 6400627574331058, - 'time': 1543958845581, - 'status': 'unapproved', - 'metamaskNetworkId': '3', - 'loadingDefaults': true, - 'txParams': { - 'from': '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706', - 'to': '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', - 'value': '0x2386f26fc10000', - 'gas': '0x5208', - 'gasPrice': '0x3b9aca00', + id: 6400627574331058, + time: 1543958845581, + status: 'unapproved', + metamaskNetworkId: '3', + loadingDefaults: true, + txParams: { + from: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706', + to: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', + value: '0x2386f26fc10000', + gas: '0x5208', + gasPrice: '0x3b9aca00', }, - 'type': 'standard', + type: 'standard', }, - [{ 'op': 'replace', 'path': '/status', 'value': 'approved', 'note': 'txStateManager: setting status to approved', 'timestamp': 1543958847813 }], - [{ 'op': 'replace', 'path': '/status', 'value': 'submitted', 'note': 'txStateManager: setting status to submitted', 'timestamp': 1543958848147 }], - [{ 'op': 'replace', 'path': '/status', 'value': 'dropped', 'note': 'txStateManager: setting status to dropped', 'timestamp': 1543958897181 }, { 'op': 'add', 'path': '/replacedBy', 'value': '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33' }], + [ + { + op: 'replace', + path: '/status', + value: 'approved', + note: 'txStateManager: setting status to approved', + timestamp: 1543958847813, + }, + ], + [ + { + op: 'replace', + path: '/status', + value: 'submitted', + note: 'txStateManager: setting status to submitted', + timestamp: 1543958848147, + }, + ], + [ + { + op: 'replace', + path: '/status', + value: 'dropped', + note: 'txStateManager: setting status to dropped', + timestamp: 1543958897181, + }, + { + op: 'add', + path: '/replacedBy', + value: + '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', + }, + ], ], id: 6400627574331058, loadingDefaults: false, @@ -46,31 +80,81 @@ describe('TransactionActivityLog utils', function () { value: '0x2386f26fc10000', }, type: 'standard', - }, { - hash: '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', + }, + { + hash: + '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', history: [ { - 'id': 6400627574331060, - 'time': 1543958857697, - 'status': 'unapproved', - 'metamaskNetworkId': '3', - 'loadingDefaults': false, - 'txParams': { - 'from': '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706', - 'to': '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', - 'value': '0x2386f26fc10000', - 'gas': '0x5208', - 'gasPrice': '0x3b9aca00', - 'nonce': '0x32', + id: 6400627574331060, + time: 1543958857697, + status: 'unapproved', + metamaskNetworkId: '3', + loadingDefaults: false, + txParams: { + from: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706', + to: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', + value: '0x2386f26fc10000', + gas: '0x5208', + gasPrice: '0x3b9aca00', + nonce: '0x32', }, - 'lastGasPrice': '0x4190ab00', - 'type': 'retry', + lastGasPrice: '0x4190ab00', + type: 'retry', }, - [{ 'op': 'replace', 'path': '/txParams/gasPrice', 'value': '0x481f2280', 'note': 'confTx: user approved transaction', 'timestamp': 1543958859470 }], - [{ 'op': 'replace', 'path': '/status', 'value': 'approved', 'note': 'txStateManager: setting status to approved', 'timestamp': 1543958859485 }], - [{ 'op': 'replace', 'path': '/status', 'value': 'signed', 'note': 'transactions#publishTransaction', 'timestamp': 1543958859889 }], - [{ 'op': 'replace', 'path': '/status', 'value': 'submitted', 'note': 'txStateManager: setting status to submitted', 'timestamp': 1543958860061 }], [{ 'op': 'add', 'path': '/firstRetryBlockNumber', 'value': '0x45a0fd', 'note': 'transactions/pending-tx-tracker#event: tx:block-update', 'timestamp': 1543958896466 }], - [{ 'op': 'replace', 'path': '/status', 'value': 'confirmed', 'timestamp': 1543958897165 }], + [ + { + op: 'replace', + path: '/txParams/gasPrice', + value: '0x481f2280', + note: 'confTx: user approved transaction', + timestamp: 1543958859470, + }, + ], + [ + { + op: 'replace', + path: '/status', + value: 'approved', + note: 'txStateManager: setting status to approved', + timestamp: 1543958859485, + }, + ], + [ + { + op: 'replace', + path: '/status', + value: 'signed', + note: 'transactions#publishTransaction', + timestamp: 1543958859889, + }, + ], + [ + { + op: 'replace', + path: '/status', + value: 'submitted', + note: 'txStateManager: setting status to submitted', + timestamp: 1543958860061, + }, + ], + [ + { + op: 'add', + path: '/firstRetryBlockNumber', + value: '0x45a0fd', + note: 'transactions/pending-tx-tracker#event: tx:block-update', + timestamp: 1543958896466, + }, + ], + [ + { + op: 'replace', + path: '/status', + value: 'confirmed', + timestamp: 1543958897165, + }, + ], ], id: 6400627574331060, lastGasPrice: '0x4190ab00', @@ -97,25 +181,32 @@ describe('TransactionActivityLog utils', function () { const expected = [ { id: 6400627574331058, - hash: '0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3', + hash: + '0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3', eventKey: 'transactionCreated', timestamp: 1543958845581, value: '0x2386f26fc10000', - }, { + }, + { id: 6400627574331058, - hash: '0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3', + hash: + '0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3', eventKey: 'transactionSubmitted', timestamp: 1543958848147, value: '0x1319718a5000', - }, { + }, + { id: 6400627574331060, - hash: '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', + hash: + '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', eventKey: 'transactionResubmitted', timestamp: 1543958860061, value: '0x171c3a061400', - }, { + }, + { id: 6400627574331060, - hash: '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', + hash: + '0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33', eventKey: 'transactionConfirmed', timestamp: 1543958897165, value: '0x171c3a061400', @@ -145,7 +236,7 @@ describe('TransactionActivityLog utils', function () { assert.deepEqual(getActivities(transaction), []) }) - it('should return activities for a transaction\'s history', function () { + it("should return activities for a transaction's history", function () { const transaction = { history: [ { @@ -228,7 +319,8 @@ describe('TransactionActivityLog utils', function () { { op: 'add', path: '/rawTx', - value: '0xf86b81a4843b9aca008252089450a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706872386f26fc10000802aa007b30119fc4fc5954fad727895b7e3ba80a78d197e95703cc603bcf017879151a01c50beda40ffaee541da9c05b9616247074f25f392800e0ad6c7a835d5366edf', + value: + '0xf86b81a4843b9aca008252089450a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706872386f26fc10000802aa007b30119fc4fc5954fad727895b7e3ba80a78d197e95703cc603bcf017879151a01c50beda40ffaee541da9c05b9616247074f25f392800e0ad6c7a835d5366edf', }, ], [], @@ -238,7 +330,8 @@ describe('TransactionActivityLog utils', function () { op: 'add', path: '/hash', timestamp: 1535507564658, - value: '0x7acc4987b5c0dfa8d423798a8c561138259de1f98a62e3d52e7e83c0e0dd9fb7', + value: + '0x7acc4987b5c0dfa8d423798a8c561138259de1f98a62e3d52e7e83c0e0dd9fb7', }, ], [ @@ -293,25 +386,25 @@ describe('TransactionActivityLog utils', function () { const expectedResult = [ { - 'eventKey': 'transactionCreated', - 'timestamp': 1535507561452, - 'value': '0x2386f26fc10000', - 'id': 1, - 'hash': '0xabc', + eventKey: 'transactionCreated', + timestamp: 1535507561452, + value: '0x2386f26fc10000', + id: 1, + hash: '0xabc', }, { - 'eventKey': 'transactionSubmitted', - 'timestamp': 1535507564665, - 'value': '0x2632e314a000', - 'id': 1, - 'hash': '0xabc', + eventKey: 'transactionSubmitted', + timestamp: 1535507564665, + value: '0x2632e314a000', + id: 1, + hash: '0xabc', }, { - 'eventKey': 'transactionConfirmed', - 'timestamp': 1535507615993, - 'value': '0x2632e314a000', - 'id': 1, - 'hash': '0xabc', + eventKey: 'transactionConfirmed', + timestamp: 1535507615993, + value: '0x2632e314a000', + id: 1, + hash: '0xabc', }, ] diff --git a/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js b/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js index 6124325be..0ba312f8c 100644 --- a/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js +++ b/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js @@ -34,21 +34,13 @@ export default class TransactionActivityLogIcon extends PureComponent { eventKey: PropTypes.oneOf(Object.keys(imageHash)), } - render () { + render() { const { className, eventKey } = this.props const imagePath = imageHash[eventKey] return (
    - { - imagePath && ( - - ) - } + {imagePath && }
    ) } diff --git a/ui/app/components/app/transaction-activity-log/transaction-activity-log.component.js b/ui/app/components/app/transaction-activity-log/transaction-activity-log.component.js index 9d071b432..9320a1ac2 100644 --- a/ui/app/components/app/transaction-activity-log/transaction-activity-log.component.js +++ b/ui/app/components/app/transaction-activity-log/transaction-activity-log.component.js @@ -1,7 +1,10 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import { getEthConversionFromWeiHex, getValueFromWeiHex } from '../../../helpers/utils/conversions.util' +import { + getEthConversionFromWeiHex, + getValueFromWeiHex, +} from '../../../helpers/utils/conversions.util' import { formatDate } from '../../../helpers/utils/util' import { getEtherscanNetworkPrefix } from '../../../../lib/etherscan-prefix-for-network' import TransactionActivityLogIcon from './transaction-activity-log-icon' @@ -36,63 +39,70 @@ export default class TransactionActivityLog extends PureComponent { global.platform.openTab({ url: etherscanUrl }) } - renderInlineRetry (index) { + renderInlineRetry(index) { const { t } = this.context - const { inlineRetryIndex, primaryTransaction = {}, onRetry, isEarliestNonce } = this.props + const { + inlineRetryIndex, + primaryTransaction = {}, + onRetry, + isEarliestNonce, + } = this.props const { status } = primaryTransaction - return isEarliestNonce && status !== CONFIRMED_STATUS && index === inlineRetryIndex - ? ( -
    - { t('speedUpTransaction') } -
    - ) : null + return isEarliestNonce && + status !== CONFIRMED_STATUS && + index === inlineRetryIndex ? ( +
    + {t('speedUpTransaction')} +
    + ) : null } - renderInlineCancel (index) { + renderInlineCancel(index) { const { t } = this.context - const { inlineCancelIndex, primaryTransaction = {}, onCancel, isEarliestNonce } = this.props + const { + inlineCancelIndex, + primaryTransaction = {}, + onCancel, + isEarliestNonce, + } = this.props const { status } = primaryTransaction - return isEarliestNonce && status !== CONFIRMED_STATUS && index === inlineCancelIndex - ? ( -
    - { t('speedUpCancellation') } -
    - ) : null + return isEarliestNonce && + status !== CONFIRMED_STATUS && + index === inlineCancelIndex ? ( +
    + {t('speedUpCancellation')} +
    + ) : null } - renderActivity (activity, index) { + renderActivity(activity, index) { const { conversionRate, nativeCurrency } = this.props const { eventKey, value, timestamp, hash } = activity - const ethValue = index === 0 - ? `${getValueFromWeiHex({ - value, - fromCurrency: 'ETH', - toCurrency: 'ETH', - conversionRate, - numberOfDecimals: 6, - })} ${nativeCurrency}` - : getEthConversionFromWeiHex({ - value, - fromCurrency: 'ETH', - conversionRate, - numberOfDecimals: 3, - }) - const formattedTimestamp = formatDate(timestamp, 'T \'on\' M/d/y') - const activityText = this.context.t(eventKey, [ethValue, formattedTimestamp]) + const ethValue = + index === 0 + ? `${getValueFromWeiHex({ + value, + fromCurrency: 'ETH', + toCurrency: 'ETH', + conversionRate, + numberOfDecimals: 6, + })} ${nativeCurrency}` + : getEthConversionFromWeiHex({ + value, + fromCurrency: 'ETH', + conversionRate, + numberOfDecimals: 3, + }) + const formattedTimestamp = formatDate(timestamp, "T 'on' M/d/y") + const activityText = this.context.t(eventKey, [ + ethValue, + formattedTimestamp, + ]) return ( -
    +
    this.handleActivityClick(hash)} > - { activityText } + {activityText}
    - { this.renderInlineRetry(index) } - { this.renderInlineCancel(index) } + {this.renderInlineRetry(index)} + {this.renderInlineCancel(index)}
    ) } - render () { + render() { const { t } = this.context const { className, activities } = this.props @@ -123,10 +133,12 @@ export default class TransactionActivityLog extends PureComponent { return (
    - { t('activityLog') } + {t('activityLog')}
    - { activities.map((activity, index) => this.renderActivity(activity, index)) } + {activities.map((activity, index) => + this.renderActivity(activity, index), + )}
    ) diff --git a/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js b/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js index df7a3dc20..07339193d 100644 --- a/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js +++ b/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js @@ -8,7 +8,8 @@ import { TRANSACTION_CANCEL_ATTEMPTED_EVENT, } from './transaction-activity-log.constants' -const matchesEventKey = (matchEventKey) => ({ eventKey }) => eventKey === matchEventKey +const matchesEventKey = (matchEventKey) => ({ eventKey }) => + eventKey === matchEventKey const mapStateToProps = (state) => { return { @@ -19,16 +20,19 @@ const mapStateToProps = (state) => { const mergeProps = (stateProps, dispatchProps, ownProps) => { const { - transactionGroup: { - transactions = [], - primaryTransaction, - } = {}, + transactionGroup: { transactions = [], primaryTransaction } = {}, ...restOwnProps } = ownProps const activities = combineTransactionHistories(transactions) - const inlineRetryIndex = findLastIndex(activities, matchesEventKey(TRANSACTION_RESUBMITTED_EVENT)) - const inlineCancelIndex = findLastIndex(activities, matchesEventKey(TRANSACTION_CANCEL_ATTEMPTED_EVENT)) + const inlineRetryIndex = findLastIndex( + activities, + matchesEventKey(TRANSACTION_RESUBMITTED_EVENT), + ) + const inlineCancelIndex = findLastIndex( + activities, + matchesEventKey(TRANSACTION_CANCEL_ATTEMPTED_EVENT), + ) return { ...stateProps, @@ -41,4 +45,8 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { } } -export default connect(mapStateToProps, null, mergeProps)(TransactionActivityLog) +export default connect( + mapStateToProps, + null, + mergeProps, +)(TransactionActivityLog) diff --git a/ui/app/components/app/transaction-activity-log/transaction-activity-log.util.js b/ui/app/components/app/transaction-activity-log/transaction-activity-log.util.js index ed07e1ee4..aa17ee348 100644 --- a/ui/app/components/app/transaction-activity-log/transaction-activity-log.util.js +++ b/ui/app/components/app/transaction-activity-log/transaction-activity-log.util.js @@ -49,7 +49,7 @@ const statusHash = { * transactionCreated activity. * @returns {Array} */ -export function getActivities (transaction, isFirstTransaction = false) { +export function getActivities(transaction, isFirstTransaction = false) { const { id, hash, @@ -65,7 +65,10 @@ export function getActivities (transaction, isFirstTransaction = false) { const historyActivities = history.reduce((acc, base, index) => { // First history item should be transaction creation if (index === 0 && !Array.isArray(base) && base.txParams) { - const { time: timestamp, txParams: { value, gas = '0x0', gasPrice = '0x0' } = {} } = base + const { + time: timestamp, + txParams: { value, gas = '0x0', gasPrice = '0x0' } = {}, + } = base // The cached gas limit and gas price are used to display the gas fee in the activity log. We // need to cache these values because the status update history events don't provide us with // the latest gas limit and gas price. @@ -94,9 +97,16 @@ export function getActivities (transaction, isFirstTransaction = false) { if (path in eventPathsHash && op === REPLACE_OP) { switch (path) { case STATUS_PATH: { - const gasFee = cachedGasLimit === '0x0' && cachedGasPrice === '0x0' - ? getHexGasTotal({ gasLimit: paramsGasLimit, gasPrice: paramsGasPrice }) - : getHexGasTotal({ gasLimit: cachedGasLimit, gasPrice: cachedGasPrice }) + const gasFee = + cachedGasLimit === '0x0' && cachedGasPrice === '0x0' + ? getHexGasTotal({ + gasLimit: paramsGasLimit, + gasPrice: paramsGasPrice, + }) + : getHexGasTotal({ + gasLimit: cachedGasLimit, + gasPrice: cachedGasPrice, + }) if (value in statusHash) { let eventKey = statusHash[value] @@ -141,8 +151,10 @@ export function getActivities (transaction, isFirstTransaction = false) { cachedGasPrice = value } - if (lastEventKey === TRANSACTION_SUBMITTED_EVENT || - lastEventKey === TRANSACTION_RESUBMITTED_EVENT) { + if ( + lastEventKey === TRANSACTION_SUBMITTED_EVENT || + lastEventKey === TRANSACTION_RESUBMITTED_EVENT + ) { lastEvent.value = getHexGasTotal({ gasLimit: cachedGasLimit, gasPrice: cachedGasPrice, @@ -173,7 +185,11 @@ export function getActivities (transaction, isFirstTransaction = false) { // If txReceipt.status is '0x0', that means that an on-chain error occurred for the transaction, // so we add an error entry to the Activity Log. return status === '0x0' - ? historyActivities.concat({ id, hash, eventKey: TRANSACTION_ERRORED_EVENT }) + ? historyActivities.concat({ + id, + hash, + eventKey: TRANSACTION_ERRORED_EVENT, + }) : historyActivities } @@ -186,11 +202,15 @@ export function getActivities (transaction, isFirstTransaction = false) { * @param {Array} activities - List of sorted activities generated from the getActivities function. * @returns {Array} */ -function filterSortedActivities (activities) { +function filterSortedActivities(activities) { const filteredActivities = [] - const hasConfirmedActivity = Boolean(activities.find(({ eventKey }) => ( - eventKey === TRANSACTION_CONFIRMED_EVENT || eventKey === TRANSACTION_CANCEL_SUCCESS_EVENT - ))) + const hasConfirmedActivity = Boolean( + activities.find( + ({ eventKey }) => + eventKey === TRANSACTION_CONFIRMED_EVENT || + eventKey === TRANSACTION_CANCEL_SUCCESS_EVENT, + ), + ) let addedDroppedActivity = false activities.forEach((activity) => { @@ -212,7 +232,7 @@ function filterSortedActivities (activities) { * @param {Array} transactions - Array of txMeta transaction objects. * @returns {Array} */ -export function combineTransactionHistories (transactions = []) { +export function combineTransactionHistories(transactions = []) { if (!transactions.length) { return [] } diff --git a/ui/app/components/app/transaction-breakdown/tests/transaction-breakdown.component.test.js b/ui/app/components/app/transaction-breakdown/tests/transaction-breakdown.component.test.js index 608ba34b9..668ed28aa 100644 --- a/ui/app/components/app/transaction-breakdown/tests/transaction-breakdown.component.test.js +++ b/ui/app/components/app/transaction-breakdown/tests/transaction-breakdown.component.test.js @@ -20,10 +20,7 @@ describe('TransactionBreakdown Component', function () { } const wrapper = shallow( - , + , { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ) diff --git a/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js b/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js index f25773e58..e3083e504 100644 --- a/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js +++ b/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js @@ -7,33 +7,36 @@ import Button from '../../../../ui/button' describe('TransactionBreakdownRow Component', function () { it('should render text properly', function () { const wrapper = shallow( - + Test , { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ) assert.ok(wrapper.hasClass('transaction-breakdown-row')) - assert.equal(wrapper.find('.transaction-breakdown-row__title').text(), 'test') - assert.equal(wrapper.find('.transaction-breakdown-row__value').text(), 'Test') + assert.equal( + wrapper.find('.transaction-breakdown-row__title').text(), + 'test', + ) + assert.equal( + wrapper.find('.transaction-breakdown-row__value').text(), + 'Test', + ) }) it('should render components properly', function () { const wrapper = shallow( - - + + , { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ) assert.ok(wrapper.hasClass('transaction-breakdown-row')) - assert.equal(wrapper.find('.transaction-breakdown-row__title').text(), 'test') + assert.equal( + wrapper.find('.transaction-breakdown-row__title').text(), + 'test', + ) assert.ok(wrapper.find('.transaction-breakdown-row__value').find(Button)) }) }) diff --git a/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js b/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js index c11ff8efa..ce652f02d 100644 --- a/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js +++ b/ui/app/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js @@ -9,17 +9,13 @@ export default class TransactionBreakdownRow extends PureComponent { className: PropTypes.string, } - render () { + render() { const { title, children, className } = this.props return (
    -
    - { title } -
    -
    - { children } -
    +
    {title}
    +
    {children}
    ) } diff --git a/ui/app/components/app/transaction-breakdown/transaction-breakdown.component.js b/ui/app/components/app/transaction-breakdown/transaction-breakdown.component.js index 68ac17546..3e4259f4b 100644 --- a/ui/app/components/app/transaction-breakdown/transaction-breakdown.component.js +++ b/ui/app/components/app/transaction-breakdown/transaction-breakdown.component.js @@ -29,75 +29,75 @@ export default class TransactionBreakdown extends PureComponent { showFiat: true, } - render () { + render() { const { t } = this.context - const { gas, gasPrice, primaryCurrency, className, nonce, nativeCurrency, showFiat, totalInHex, gasUsed, isTokenApprove } = this.props + const { + gas, + gasPrice, + primaryCurrency, + className, + nonce, + nativeCurrency, + showFiat, + totalInHex, + gasUsed, + isTokenApprove, + } = this.props return (
    -
    - { t('transaction') } -
    +
    {t('transaction')}
    - {typeof nonce === 'undefined' - ? null - : ( - - ) - } + {typeof nonce === 'undefined' ? null : ( + + )} - {primaryCurrency} + + {primaryCurrency} + - {typeof gas === 'undefined' - ? '?' - : ( - - ) - } + {typeof gas === 'undefined' ? ( + '?' + ) : ( + + )} - { - typeof gasUsed === 'string' && ( - - - - ) - } + {typeof gasUsed === 'string' && ( + + + + )} - {typeof gasPrice === 'undefined' - ? '?' - : ( - - ) - } + {typeof gasPrice === 'undefined' ? ( + '?' + ) : ( + + )}
    @@ -106,15 +106,13 @@ export default class TransactionBreakdown extends PureComponent { type={PRIMARY} value={totalInHex} /> - { - showFiat && ( - - ) - } + {showFiat && ( + + )}
    diff --git a/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js b/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js index 17c00f38f..76ae90617 100644 --- a/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js +++ b/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js @@ -1,5 +1,9 @@ import { connect } from 'react-redux' -import { getIsMainnet, getNativeCurrency, getPreferences } from '../../../selectors' +import { + getIsMainnet, + getNativeCurrency, + getPreferences, +} from '../../../selectors' import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util' import { sumHexes } from '../../../helpers/utils/transactions.util' import { TOKEN_METHOD_APPROVE } from '../../../helpers/constants/transactions' @@ -7,19 +11,23 @@ import TransactionBreakdown from './transaction-breakdown.component' const mapStateToProps = (state, ownProps) => { const { transaction, transactionCategory } = ownProps - const { txParams: { gas, gasPrice, value } = {}, txReceipt: { gasUsed } = {} } = transaction + const { + txParams: { gas, gasPrice, value } = {}, + txReceipt: { gasUsed } = {}, + } = transaction const { showFiatInTestnets } = getPreferences(state) const isMainnet = getIsMainnet(state) const isTokenApprove = transactionCategory === TOKEN_METHOD_APPROVE const gasLimit = typeof gasUsed === 'string' ? gasUsed : gas - const hexGasTotal = (gasLimit && gasPrice && getHexGasTotal({ gasLimit, gasPrice })) || '0x0' + const hexGasTotal = + (gasLimit && gasPrice && getHexGasTotal({ gasLimit, gasPrice })) || '0x0' const totalInHex = sumHexes(hexGasTotal, value) return { nativeCurrency: getNativeCurrency(state), - showFiat: (isMainnet || Boolean(showFiatInTestnets)), + showFiat: isMainnet || Boolean(showFiatInTestnets), totalInHex, gas, gasPrice, diff --git a/ui/app/components/app/transaction-icon/transaction-icon.js b/ui/app/components/app/transaction-icon/transaction-icon.js index 688215e36..4941ea78f 100644 --- a/ui/app/components/app/transaction-icon/transaction-icon.js +++ b/ui/app/components/app/transaction-icon/transaction-icon.js @@ -45,8 +45,7 @@ const COLOR_MAP = { [DROPPED_STATUS]: FAIL_COLOR, } -export default function TransactionIcon ({ status, category }) { - +export default function TransactionIcon({ status, category }) { const color = COLOR_MAP[status] || OK_COLOR const Icon = ICON_MAP[category] diff --git a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js index 7ee511524..debba6573 100644 --- a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -1,9 +1,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import copyToClipboard from 'copy-to-clipboard' -import { - getBlockExplorerUrlForTx, -} from '../../../helpers/utils/transactions.util' +import { getBlockExplorerUrlForTx } from '../../../helpers/utils/transactions.util' import SenderToRecipient from '../../ui/sender-to-recipient' import { FLAT_VARIANT } from '../../ui/sender-to-recipient/sender-to-recipient.constants' import TransactionActivityLog from '../transaction-activity-log' @@ -49,7 +47,10 @@ export default class TransactionListItemDetails extends PureComponent { } handleEtherscanClick = () => { - const { transactionGroup: { primaryTransaction }, rpcPrefs } = this.props + const { + transactionGroup: { primaryTransaction }, + rpcPrefs, + } = this.props const { hash, metamaskNetworkId } = primaryTransaction this.context.metricsEvent({ @@ -60,7 +61,9 @@ export default class TransactionListItemDetails extends PureComponent { }, }) - global.platform.openTab({ url: getBlockExplorerUrlForTx(metamaskNetworkId, hash, rpcPrefs) }) + global.platform.openTab({ + url: getBlockExplorerUrlForTx(metamaskNetworkId, hash, rpcPrefs), + }) } handleCancel = (event) => { @@ -94,7 +97,7 @@ export default class TransactionListItemDetails extends PureComponent { }) } - componentDidMount () { + componentDidMount() { const { recipientAddress, tryReverseResolveAddress } = this.props if (recipientAddress) { @@ -102,44 +105,39 @@ export default class TransactionListItemDetails extends PureComponent { } } - renderCancel () { + renderCancel() { const { t } = this.context - const { - showCancel, - cancelDisabled, - } = this.props + const { showCancel, cancelDisabled } = this.props if (!showCancel) { return null } - return cancelDisabled - ? ( - -
    - -
    -
    - ) - : ( - - ) + return cancelDisabled ? ( + +
    + +
    +
    + ) : ( + + ) } - render () { + render() { const { t } = this.context const { justCopied } = this.state const { @@ -157,31 +155,34 @@ export default class TransactionListItemDetails extends PureComponent { onClose, recipientNickname, } = this.props - const { primaryTransaction: transaction, initialTransaction: { transactionCategory } } = transactionGroup + const { + primaryTransaction: transaction, + initialTransaction: { transactionCategory }, + } = transactionGroup const { hash } = transaction return (
    -
    { t('details') }
    +
    {t('details')}
    - { - showSpeedUp && ( - - ) - } - { this.renderCancel() } + {showSpeedUp && ( + + )} + {this.renderCancel()} - { - showRetry && ( - - - - ) - } + {showRetry && ( + + + + )}
    diff --git a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.container.js b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.container.js index 6bea44d2a..55fcf8582 100644 --- a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.container.js +++ b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.container.js @@ -1,14 +1,15 @@ import { connect } from 'react-redux' import { checksumAddress } from '../../../helpers/utils/util' import { tryReverseResolveAddress } from '../../../store/actions' -import { getAddressBook, getRpcPrefsForCurrentProvider } from '../../../selectors' +import { + getAddressBook, + getRpcPrefsForCurrentProvider, +} from '../../../selectors' import TransactionListItemDetails from './transaction-list-item-details.component' const mapStateToProps = (state, ownProps) => { const { metamask } = state - const { - ensResolutionsByAddress, - } = metamask + const { ensResolutionsByAddress } = metamask const { recipientAddress, senderAddress } = ownProps let recipientEns if (recipientAddress) { @@ -41,4 +42,7 @@ const mapDispatchToProps = (dispatch) => { } } -export default connect(mapStateToProps, mapDispatchToProps)(TransactionListItemDetails) +export default connect( + mapStateToProps, + mapDispatchToProps, +)(TransactionListItemDetails) diff --git a/ui/app/components/app/transaction-list-item/transaction-list-item.component.js b/ui/app/components/app/transaction-list-item/transaction-list-item.component.js index 9953df9d4..6b276d9f4 100644 --- a/ui/app/components/app/transaction-list-item/transaction-list-item.component.js +++ b/ui/app/components/app/transaction-list-item/transaction-list-item.component.js @@ -27,16 +27,27 @@ import TransactionIcon from '../transaction-icon' import { useTransactionTimeRemaining } from '../../../hooks/useTransactionTimeRemaining' import IconWithLabel from '../../ui/icon-with-label' -export default function TransactionListItem ({ transactionGroup, isEarliestNonce = false }) { +export default function TransactionListItem({ + transactionGroup, + isEarliestNonce = false, +}) { const t = useI18nContext() const history = useHistory() const { hasCancelled } = transactionGroup const [showDetails, setShowDetails] = useState(false) - const { initialTransaction: { id }, primaryTransaction: { err, gasPrice, status, submittedTime } } = transactionGroup - const [cancelEnabled, cancelTransaction] = useCancelTransaction(transactionGroup) + const { + initialTransaction: { id }, + primaryTransaction: { err, gasPrice, status, submittedTime }, + } = transactionGroup + const [cancelEnabled, cancelTransaction] = useCancelTransaction( + transactionGroup, + ) const retryTransaction = useRetryTransaction(transactionGroup) - const shouldShowSpeedUp = useShouldShowSpeedUp(transactionGroup, isEarliestNonce) + const shouldShowSpeedUp = useShouldShowSpeedUp( + transactionGroup, + isEarliestNonce, + ) const { title, @@ -53,7 +64,12 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce isSubmitted, } = useTransactionDisplayData(transactionGroup) - const timeRemaining = useTransactionTimeRemaining(isSubmitted, isEarliestNonce, submittedTime, gasPrice) + const timeRemaining = useTransactionTimeRemaining( + isSubmitted, + isEarliestNonce, + submittedTime, + gasPrice, + ) const isSignatureReq = category === TRANSACTION_CATEGORY_SIGNATURE_REQUEST const isApproval = category === TRANSACTION_CATEGORY_APPROVAL @@ -61,7 +77,11 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce const isSwap = category === TRANSACTION_CATEGORY_SWAP const className = classnames('transaction-list-item', { - 'transaction-list-item--unconfirmed': isPending || [FAILED_STATUS, DROPPED_STATUS, REJECTED_STATUS].includes(displayedStatusKey), + 'transaction-list-item--unconfirmed': + isPending || + [FAILED_STATUS, DROPPED_STATUS, REJECTED_STATUS].includes( + displayedStatusKey, + ), }) const toggleShowDetails = useCallback(() => { @@ -80,24 +100,28 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce className="transaction-list-item__header-button" disabled={!cancelEnabled} > - { t('cancel') } + {t('cancel')} ) if (hasCancelled || !isPending || isUnapproved) { return null } - return cancelEnabled - ? btn - : ( - -
    - {btn} -
    -
    - ) - - }, [isPending, t, isUnapproved, cancelEnabled, cancelTransaction, hasCancelled]) + return cancelEnabled ? ( + btn + ) : ( + +
    {btn}
    +
    + ) + }, [ + isPending, + t, + isUnapproved, + cancelEnabled, + cancelTransaction, + hasCancelled, + ]) const speedUpButton = useMemo(() => { if (!shouldShowSpeedUp || !isPending || isUnapproved) { @@ -110,7 +134,7 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce onClick={retryTransaction} className="transaction-list-item-details__header-button" > - { t('speedUp') } + {t('speedUp')} ) }, [shouldShowSpeedUp, isUnapproved, t, isPending, retryTransaction]) @@ -121,14 +145,20 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce onClick={toggleShowDetails} className={className} title={title} - titleIcon={!isUnapproved && isPending && isEarliestNonce && ( - } - label={timeRemaining} - /> - )} - icon={} - subtitle={( + titleIcon={ + !isUnapproved && + isPending && + isEarliestNonce && ( + } + label={timeRemaining} + /> + ) + } + icon={ + + } + subtitle={

    - + {subtitle}

    - )} - rightContent={!isSignatureReq && !isApproval && ( - <> -

    {primaryCurrency}

    -

    {secondaryCurrency}

    - - )} + } + rightContent={ + !isSignatureReq && + !isApproval && ( + <> +

    + {primaryCurrency} +

    +

    + {secondaryCurrency} +

    + + ) + } >
    {speedUpButton} diff --git a/ui/app/components/app/transaction-list/transaction-list.component.js b/ui/app/components/app/transaction-list/transaction-list.component.js index 9af3afe31..2f8cf6308 100644 --- a/ui/app/components/app/transaction-list/transaction-list.component.js +++ b/ui/app/components/app/transaction-list/transaction-list.component.js @@ -5,23 +5,25 @@ import { nonceSortedCompletedTransactionsSelector, nonceSortedPendingTransactionsSelector, } from '../../../selectors/transactions' -import { - getFeatureFlags, -} from '../../../selectors/selectors' +import { getFeatureFlags } from '../../../selectors/selectors' import * as actions from '../../../ducks/gas/gas.duck' import { useI18nContext } from '../../../hooks/useI18nContext' import TransactionListItem from '../transaction-list-item' import Button from '../../ui/button' -import { TOKEN_CATEGORY_HASH, TRANSACTION_CATEGORY_SWAP } from '../../../helpers/constants/transactions' +import { + TOKEN_CATEGORY_HASH, + TRANSACTION_CATEGORY_SWAP, +} from '../../../helpers/constants/transactions' import { SWAPS_CONTRACT_ADDRESS } from '../../../helpers/constants/swaps' const PAGE_INCREMENT = 10 const getTransactionGroupRecipientAddressFilter = (recipientAddress) => { return ({ initialTransaction: { txParams } }) => { - return txParams?.to === recipientAddress || ( - txParams?.to === SWAPS_CONTRACT_ADDRESS && - txParams.data.match(recipientAddress.slice(2)) + return ( + txParams?.to === recipientAddress || + (txParams?.to === SWAPS_CONTRACT_ADDRESS && + txParams.data.match(recipientAddress.slice(2))) ) } } @@ -41,106 +43,160 @@ const tokenTransactionFilter = ({ return true } -const getFilteredTransactionGroups = (transactionGroups, hideTokenTransactions, tokenAddress) => { +const getFilteredTransactionGroups = ( + transactionGroups, + hideTokenTransactions, + tokenAddress, +) => { if (hideTokenTransactions) { return transactionGroups.filter(tokenTransactionFilter) } else if (tokenAddress) { - return transactionGroups.filter(getTransactionGroupRecipientAddressFilter(tokenAddress)) + return transactionGroups.filter( + getTransactionGroupRecipientAddressFilter(tokenAddress), + ) } return transactionGroups } -export default function TransactionList ({ hideTokenTransactions, tokenAddress }) { +export default function TransactionList({ + hideTokenTransactions, + tokenAddress, +}) { const [limit, setLimit] = useState(PAGE_INCREMENT) const t = useI18nContext() const dispatch = useDispatch() - const unfilteredPendingTransactions = useSelector(nonceSortedPendingTransactionsSelector) - const unfilteredCompletedTransactions = useSelector(nonceSortedCompletedTransactionsSelector) - const { transactionTime: transactionTimeFeatureActive } = useSelector(getFeatureFlags) + const unfilteredPendingTransactions = useSelector( + nonceSortedPendingTransactionsSelector, + ) + const unfilteredCompletedTransactions = useSelector( + nonceSortedCompletedTransactionsSelector, + ) + const { transactionTime: transactionTimeFeatureActive } = useSelector( + getFeatureFlags, + ) const pendingTransactions = useMemo( - () => getFilteredTransactionGroups(unfilteredPendingTransactions, hideTokenTransactions, tokenAddress), + () => + getFilteredTransactionGroups( + unfilteredPendingTransactions, + hideTokenTransactions, + tokenAddress, + ), [hideTokenTransactions, tokenAddress, unfilteredPendingTransactions], ) const completedTransactions = useMemo( - () => getFilteredTransactionGroups(unfilteredCompletedTransactions, hideTokenTransactions, tokenAddress), + () => + getFilteredTransactionGroups( + unfilteredCompletedTransactions, + hideTokenTransactions, + tokenAddress, + ), [hideTokenTransactions, tokenAddress, unfilteredCompletedTransactions], ) - const { fetchGasEstimates, fetchBasicGasAndTimeEstimates } = useMemo(() => ({ - fetchGasEstimates: (blockTime) => dispatch(actions.fetchGasEstimates(blockTime)), - fetchBasicGasAndTimeEstimates: () => dispatch(actions.fetchBasicGasAndTimeEstimates()), - }), [dispatch]) + const { fetchGasEstimates, fetchBasicGasAndTimeEstimates } = useMemo( + () => ({ + fetchGasEstimates: (blockTime) => + dispatch(actions.fetchGasEstimates(blockTime)), + fetchBasicGasAndTimeEstimates: () => + dispatch(actions.fetchBasicGasAndTimeEstimates()), + }), + [dispatch], + ) // keep track of previous values from state. // loaded is used here to determine if our effect has ran at least once. - const prevState = useRef({ loaded: false, pendingTransactions, transactionTimeFeatureActive }) + const prevState = useRef({ + loaded: false, + pendingTransactions, + transactionTimeFeatureActive, + }) useEffect(() => { const { loaded } = prevState.current - const pendingTransactionAdded = pendingTransactions.length > 0 && prevState.current.pendingTransactions.length === 0 - const transactionTimeFeatureWasActivated = !prevState.current.transactionTimeFeatureActive && transactionTimeFeatureActive - if (transactionTimeFeatureActive && pendingTransactions.length > 0 && (loaded === false || transactionTimeFeatureWasActivated || pendingTransactionAdded)) { - fetchBasicGasAndTimeEstimates() - .then(({ blockTime }) => fetchGasEstimates(blockTime)) + const pendingTransactionAdded = + pendingTransactions.length > 0 && + prevState.current.pendingTransactions.length === 0 + const transactionTimeFeatureWasActivated = + !prevState.current.transactionTimeFeatureActive && + transactionTimeFeatureActive + if ( + transactionTimeFeatureActive && + pendingTransactions.length > 0 && + (loaded === false || + transactionTimeFeatureWasActivated || + pendingTransactionAdded) + ) { + fetchBasicGasAndTimeEstimates().then(({ blockTime }) => + fetchGasEstimates(blockTime), + ) } - prevState.current = { loaded: true, pendingTransactions, transactionTimeFeatureActive } - }, [fetchGasEstimates, fetchBasicGasAndTimeEstimates, transactionTimeFeatureActive, pendingTransactions]) + prevState.current = { + loaded: true, + pendingTransactions, + transactionTimeFeatureActive, + } + }, [ + fetchGasEstimates, + fetchBasicGasAndTimeEstimates, + transactionTimeFeatureActive, + pendingTransactions, + ]) - const viewMore = useCallback(() => setLimit((prev) => prev + PAGE_INCREMENT), []) + const viewMore = useCallback( + () => setLimit((prev) => prev + PAGE_INCREMENT), + [], + ) const pendingLength = pendingTransactions.length return (
    - { - pendingLength > 0 && ( -
    -
    - { `${t('queue')} (${pendingTransactions.length})` } -
    - { - pendingTransactions.map((transactionGroup, index) => ( - - )) - } + {pendingLength > 0 && ( +
    +
    + {`${t('queue')} (${pendingTransactions.length})`}
    - ) - } + {pendingTransactions.map((transactionGroup, index) => ( + + ))} +
    + )}
    - { - pendingLength > 0 - ? ( -
    - { t('history') } -
    - ) - : null - } - { - completedTransactions.length > 0 - ? completedTransactions.slice(0, limit).map((transactionGroup, index) => ( + {pendingLength > 0 ? ( +
    {t('history')}
    + ) : null} + {completedTransactions.length > 0 ? ( + completedTransactions + .slice(0, limit) + .map((transactionGroup, index) => ( )) - : ( -
    -
    - { t('noTransactions') } -
    -
    - ) - } + ) : ( +
    +
    + {t('noTransactions')} +
    +
    + )} {completedTransactions.length > limit && ( - + )}
    diff --git a/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js b/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js index 51d02b451..d468d8d5f 100644 --- a/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js +++ b/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js @@ -13,10 +13,7 @@ describe('TransactionStatus Component', function () { it('should render CONFIRMED properly', function () { const wrapper = mount( - , + , ) assert.ok(wrapper) @@ -39,11 +36,7 @@ describe('TransactionStatus Component', function () { it('should render PENDING properly', function () { const wrapper = mount( - , + , ) assert.ok(wrapper) @@ -51,26 +44,24 @@ describe('TransactionStatus Component', function () { }) it('should render QUEUED properly', function () { - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) - assert.ok(wrapper.find('.transaction-status--queued').length, 'queued className not found') + assert.ok( + wrapper.find('.transaction-status--queued').length, + 'queued className not found', + ) assert.equal(wrapper.text(), 'QUEUED') }) it('should render UNAPPROVED properly', function () { - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) - assert.ok(wrapper.find('.transaction-status--unapproved').length, 'unapproved className not found') + assert.ok( + wrapper.find('.transaction-status--unapproved').length, + 'unapproved className not found', + ) assert.equal(wrapper.text(), 'UNAPPROVED') }) diff --git a/ui/app/components/app/transaction-status/transaction-status.component.js b/ui/app/components/app/transaction-status/transaction-status.component.js index 692745db3..9cd013118 100644 --- a/ui/app/components/app/transaction-status/transaction-status.component.js +++ b/ui/app/components/app/transaction-status/transaction-status.component.js @@ -45,7 +45,13 @@ const statusToClassNameHash = { [PENDING_PSEUDO_STATUS]: 'transaction-status--pending', } -export default function TransactionStatus ({ status, date, error, isEarliestNonce, className }) { +export default function TransactionStatus({ + status, + date, + error, + isEarliestNonce, + className, +}) { const t = useI18nContext() const tooltipText = error?.rpc?.message || error?.message let statusKey = status @@ -59,9 +65,13 @@ export default function TransactionStatus ({ status, date, error, isEarliestNonc - { statusText } + {statusText} ) } diff --git a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js index d9f271e10..41b8ac862 100644 --- a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js +++ b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js @@ -11,12 +11,12 @@ describe('UserPreferencedCurrencyDisplay Component', function () { describe('rendering', function () { beforeEach(function () { sinon.stub(currencyHook, 'useCurrencyDisplay').returns(['1', {}]) - sinon.stub(currencyPrefHook, 'useUserPreferencedCurrency').returns({ currency: 'ETH', decimals: 6 }) + sinon + .stub(currencyPrefHook, 'useUserPreferencedCurrency') + .returns({ currency: 'ETH', decimals: 6 }) }) it('should render properly', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find(CurrencyDisplay).length, 1) @@ -24,11 +24,7 @@ describe('UserPreferencedCurrencyDisplay Component', function () { it('should pass all props to the CurrencyDisplay child component', function () { const wrapper = shallow( - , + , ) assert.ok(wrapper) diff --git a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js index fd7072239..c858b66b6 100644 --- a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js +++ b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js @@ -4,7 +4,7 @@ import { PRIMARY, SECONDARY, ETH } from '../../../helpers/constants/common' import CurrencyDisplay from '../../ui/currency-display' import { useUserPreferencedCurrency } from '../../../hooks/useUserPreferencedCurrency' -export default function UserPreferencedCurrencyDisplay ({ +export default function UserPreferencedCurrencyDisplay({ 'data-testid': dataTestId, ethLogoHeight = 12, ethNumberOfDecimals, @@ -14,14 +14,16 @@ export default function UserPreferencedCurrencyDisplay ({ type, ...restProps }) { - const { currency, numberOfDecimals } = useUserPreferencedCurrency(type, { ethNumberOfDecimals, fiatNumberOfDecimals, numberOfDecimals: propsNumberOfDecimals }) + const { currency, numberOfDecimals } = useUserPreferencedCurrency(type, { + ethNumberOfDecimals, + fiatNumberOfDecimals, + numberOfDecimals: propsNumberOfDecimals, + }) const prefixComponent = useMemo(() => { - return currency === ETH && showEthLogo && ( - + return ( + currency === ETH && + showEthLogo && ) }, [currency, showEthLogo, ethLogoHeight]) @@ -48,6 +50,12 @@ UserPreferencedCurrencyDisplay.propTypes = { showEthLogo: PropTypes.bool, ethLogoHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), type: PropTypes.oneOf([PRIMARY, SECONDARY]), - ethNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - fiatNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + ethNumberOfDecimals: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + ]), + fiatNumberOfDecimals: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + ]), } diff --git a/ui/app/components/app/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js b/ui/app/components/app/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js index 3241008e4..63b9d42a5 100644 --- a/ui/app/components/app/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js +++ b/ui/app/components/app/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js @@ -7,9 +7,7 @@ import CurrencyInput from '../../../ui/currency-input' describe('UserPreferencedCurrencyInput Component', function () { describe('rendering', function () { it('should render properly', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find(CurrencyInput).length, 1) @@ -17,9 +15,7 @@ describe('UserPreferencedCurrencyInput Component', function () { it('should render useFiat for CurrencyInput based on preferences.useNativeCurrencyAsPrimaryCurrency', function () { const wrapper = shallow( - , + , ) assert.ok(wrapper) diff --git a/ui/app/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js b/ui/app/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js index 7c0ec1734..f92a74b1d 100644 --- a/ui/app/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js +++ b/ui/app/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js @@ -7,7 +7,7 @@ export default class UserPreferencedCurrencyInput extends PureComponent { useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, } - render () { + render() { const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props return ( diff --git a/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js b/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js index c75cfbf33..6e26b6dec 100644 --- a/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js +++ b/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js @@ -12,7 +12,7 @@ export default class UserPreferencedTokenInput extends PureComponent { useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, } - render () { + render() { const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props return ( diff --git a/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js b/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js index daddded7f..1d8799d30 100644 --- a/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js +++ b/ui/app/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js @@ -11,7 +11,9 @@ const mapStateToProps = (state) => { } } -const UserPreferencedTokenInputContainer = connect(mapStateToProps)(UserPreferencedTokenInput) +const UserPreferencedTokenInputContainer = connect(mapStateToProps)( + UserPreferencedTokenInput, +) UserPreferencedTokenInputContainer.propTypes = { token: PropTypes.shape({ diff --git a/ui/app/components/app/wallet-overview/eth-overview.js b/ui/app/components/app/wallet-overview/eth-overview.js index ce24a74e4..b707e1924 100644 --- a/ui/app/components/app/wallet-overview/eth-overview.js +++ b/ui/app/components/app/wallet-overview/eth-overview.js @@ -6,18 +6,33 @@ import { useHistory } from 'react-router-dom' import Identicon from '../../ui/identicon' import { I18nContext } from '../../../contexts/i18n' -import { SEND_ROUTE, BUILD_QUOTE_ROUTE } from '../../../helpers/constants/routes' -import { useMetricEvent, useNewMetricEvent } from '../../../hooks/useMetricEvent' +import { + SEND_ROUTE, + BUILD_QUOTE_ROUTE, +} from '../../../helpers/constants/routes' +import { + useMetricEvent, + useNewMetricEvent, +} from '../../../hooks/useMetricEvent' import { useSwapsEthToken } from '../../../hooks/useSwapsEthToken' import Tooltip from '../../ui/tooltip' import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display' import { PRIMARY, SECONDARY } from '../../../helpers/constants/common' import { showModal } from '../../../store/actions' -import { isBalanceCached, getSelectedAccount, getShouldShowFiat, getCurrentNetworkId, getCurrentKeyring } from '../../../selectors/selectors' +import { + isBalanceCached, + getSelectedAccount, + getShouldShowFiat, + getCurrentNetworkId, + getCurrentKeyring, +} from '../../../selectors/selectors' import SwapIcon from '../../ui/icon/swap-icon.component' import BuyIcon from '../../ui/icon/overview-buy-icon.component' import SendIcon from '../../ui/icon/overview-send-icon.component' -import { getSwapsFeatureLiveness, setSwapsFromToken } from '../../../ducks/swaps/swaps' +import { + getSwapsFeatureLiveness, + setSwapsFromToken, +} from '../../../ducks/swaps/swaps' import IconButton from '../../ui/icon-button' import { MAINNET_NETWORK_ID } from '../../../../../app/scripts/controllers/network/enums' import WalletOverview from './wallet-overview' @@ -47,14 +62,22 @@ const EthOverview = ({ className }) => { const selectedAccount = useSelector(getSelectedAccount) const { balance } = selectedAccount const networkId = useSelector(getCurrentNetworkId) - const enteredSwapsEvent = useNewMetricEvent({ event: 'Swaps Opened', properties: { source: 'Main View', active_currency: 'ETH' }, category: 'swaps' }) + const enteredSwapsEvent = useNewMetricEvent({ + event: 'Swaps Opened', + properties: { source: 'Main View', active_currency: 'ETH' }, + category: 'swaps', + }) const swapsEnabled = useSelector(getSwapsFeatureLiveness) const swapsEthToken = useSwapsEthToken() return ( + balance={ +
    { ethNumberOfDecimals={4} hideTitle /> - { - balanceIsCached ? * : null - } + {balanceIsCached ? ( + * + ) : null}
    - { - showFiat && ( - - ) - } + {showFiat && ( + + )}
    - )} - buttons={( + } + buttons={ <> { } } }} - label={ t('swap') } + label={t('swap')} tooltipRender={(contents) => ( - + {contents} )} /> ) : null} - )} + } className={className} icon={} /> diff --git a/ui/app/components/app/wallet-overview/token-overview.js b/ui/app/components/app/wallet-overview/token-overview.js index 1d499e1b4..fe7f29087 100644 --- a/ui/app/components/app/wallet-overview/token-overview.js +++ b/ui/app/components/app/wallet-overview/token-overview.js @@ -7,13 +7,26 @@ import Identicon from '../../ui/identicon' import Tooltip from '../../ui/tooltip' import CurrencyDisplay from '../../ui/currency-display' import { I18nContext } from '../../../contexts/i18n' -import { SEND_ROUTE, BUILD_QUOTE_ROUTE } from '../../../helpers/constants/routes' -import { useMetricEvent, useNewMetricEvent } from '../../../hooks/useMetricEvent' +import { + SEND_ROUTE, + BUILD_QUOTE_ROUTE, +} from '../../../helpers/constants/routes' +import { + useMetricEvent, + useNewMetricEvent, +} from '../../../hooks/useMetricEvent' import { useTokenTracker } from '../../../hooks/useTokenTracker' import { useTokenFiatAmount } from '../../../hooks/useTokenFiatAmount' import { updateSendToken } from '../../../store/actions' -import { getSwapsFeatureLiveness, setSwapsFromToken } from '../../../ducks/swaps/swaps' -import { getAssetImages, getCurrentKeyring, getCurrentNetworkId } from '../../../selectors/selectors' +import { + getSwapsFeatureLiveness, + setSwapsFromToken, +} from '../../../ducks/swaps/swaps' +import { + getAssetImages, + getCurrentKeyring, + getCurrentNetworkId, +} from '../../../selectors/selectors' import { MAINNET_NETWORK_ID } from '../../../../../app/scripts/controllers/network/enums' import SwapIcon from '../../ui/icon/swap-icon.component' @@ -40,34 +53,38 @@ const TokenOverview = ({ className, token }) => { const { tokensWithBalances } = useTokenTracker([token]) const balanceToRender = tokensWithBalances[0]?.string const balance = tokensWithBalances[0]?.balance - const formattedFiatBalance = useTokenFiatAmount(token.address, balanceToRender, token.symbol) + const formattedFiatBalance = useTokenFiatAmount( + token.address, + balanceToRender, + token.symbol, + ) const networkId = useSelector(getCurrentNetworkId) - const enteredSwapsEvent = useNewMetricEvent({ event: 'Swaps Opened', properties: { source: 'Token View', active_currency: token.symbol }, category: 'swaps' }) + const enteredSwapsEvent = useNewMetricEvent({ + event: 'Swaps Opened', + properties: { source: 'Token View', active_currency: token.symbol }, + category: 'swaps', + }) const swapsEnabled = useSelector(getSwapsFeatureLiveness) return ( - { - formattedFiatBalance - ? ( - - ) - : null - } + {formattedFiatBalance ? ( + + ) : null}
    - )} - buttons={( + } + buttons={ <> { onClick={() => { if (networkId === MAINNET_NETWORK_ID) { enteredSwapsEvent() - dispatch(setSwapsFromToken({ - ...token, - iconUrl: assetImages[token.address], - balance, - string: balanceToRender, - })) + dispatch( + setSwapsFromToken({ + ...token, + iconUrl: assetImages[token.address], + balance, + string: balanceToRender, + }), + ) if (usingHardwareWallet) { global.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE) } else { @@ -101,24 +120,28 @@ const TokenOverview = ({ className, token }) => { } } }} - label={ t('swap') } + label={t('swap')} tooltipRender={(contents) => ( - + {contents} )} /> ) : null} - )} + } className={className} - icon={( + icon={ - )} + } /> ) } diff --git a/ui/app/components/app/wallet-overview/wallet-overview.js b/ui/app/components/app/wallet-overview/wallet-overview.js index 30bbd1529..b4ca1b4ff 100644 --- a/ui/app/components/app/wallet-overview/wallet-overview.js +++ b/ui/app/components/app/wallet-overview/wallet-overview.js @@ -6,12 +6,10 @@ const WalletOverview = ({ balance, buttons, className, icon }) => { return (
    - { icon } - { balance } -
    -
    - { buttons } + {icon} + {balance}
    +
    {buttons}
    ) } diff --git a/ui/app/components/ui/account-mismatch-warning/account-mismatch-warning.component.js b/ui/app/components/ui/account-mismatch-warning/account-mismatch-warning.component.js index fc20a9900..4e7e9c966 100644 --- a/ui/app/components/ui/account-mismatch-warning/account-mismatch-warning.component.js +++ b/ui/app/components/ui/account-mismatch-warning/account-mismatch-warning.component.js @@ -6,7 +6,7 @@ import { getSelectedAccount } from '../../../selectors' import InfoIcon from '../icon/info-icon.component' import { useI18nContext } from '../../../hooks/useI18nContext' -export default function AccountMismatchWarning ({ address }) { +export default function AccountMismatchWarning({ address }) { const selectedAccount = useSelector(getSelectedAccount) const t = useI18nContext() if (selectedAccount.address === address) { @@ -20,7 +20,9 @@ export default function AccountMismatchWarning ({ address }) { wrapperClassName="account-mismatch-warning__tooltip-wrapper" containerClassName="account-mismatch-warning__tooltip-container" > -
    +
    + +
    ) } diff --git a/ui/app/components/ui/alert-circle-icon/alert-circle-icon.component.js b/ui/app/components/ui/alert-circle-icon/alert-circle-icon.component.js index 8569f873d..7c8a37aaa 100644 --- a/ui/app/components/ui/alert-circle-icon/alert-circle-icon.component.js +++ b/ui/app/components/ui/alert-circle-icon/alert-circle-icon.component.js @@ -18,9 +18,7 @@ export default class AlertCircleIcon extends Component { type: PropTypes.oneOf(Object.keys(typeConfig)).isRequired, } - render () { - return ( - - ) + render() { + return } } diff --git a/ui/app/components/ui/alert-circle-icon/alert-circle-icon.stories.js b/ui/app/components/ui/alert-circle-icon/alert-circle-icon.stories.js index 9f873bf2b..8b2dd5574 100644 --- a/ui/app/components/ui/alert-circle-icon/alert-circle-icon.stories.js +++ b/ui/app/components/ui/alert-circle-icon/alert-circle-icon.stories.js @@ -5,14 +5,6 @@ export default { title: 'AlertCircleIcon', } -export const dangerCircleIcon = () => ( - -) +export const dangerCircleIcon = () => -export const warningCircleIcon = () => ( - -) +export const warningCircleIcon = () => diff --git a/ui/app/components/ui/alert/index.js b/ui/app/components/ui/alert/index.js index 437bf492b..e04778569 100644 --- a/ui/app/components/ui/alert/index.js +++ b/ui/app/components/ui/alert/index.js @@ -9,7 +9,7 @@ class Alert extends Component { className: '', } - UNSAFE_componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps(nextProps) { if (!this.props.visible && nextProps.visible) { this.animateIn(nextProps.msg) } else if (this.props.visible && !nextProps.visible) { @@ -17,7 +17,7 @@ class Alert extends Component { } } - animateIn (msg) { + animateIn(msg) { this.setState({ msg, visible: true, @@ -25,7 +25,7 @@ class Alert extends Component { }) } - animateOut () { + animateOut() { this.setState({ msg: null, className: 'hidden', @@ -34,10 +34,9 @@ class Alert extends Component { setTimeout((_) => { this.setState({ visible: false }) }, 500) - } - render () { + render() { if (this.state.visible) { return (
    @@ -51,7 +50,6 @@ class Alert extends Component { Alert.propTypes = { visible: PropTypes.bool.isRequired, - msg: PropTypes.string, /* eslint-disable-line react/no-unused-prop-types */ + msg: PropTypes.string /* eslint-disable-line react/no-unused-prop-types */, } export default Alert - diff --git a/ui/app/components/ui/alert/tests/alert.test.js b/ui/app/components/ui/alert/tests/alert.test.js index 70aaa5e16..f69a59b06 100644 --- a/ui/app/components/ui/alert/tests/alert.test.js +++ b/ui/app/components/ui/alert/tests/alert.test.js @@ -8,9 +8,7 @@ describe('Alert', function () { let wrapper beforeEach(function () { - wrapper = shallow( - , - ) + wrapper = shallow() }) it('renders nothing with no visible boolean in state', function () { diff --git a/ui/app/components/ui/breadcrumbs/breadcrumbs.component.js b/ui/app/components/ui/breadcrumbs/breadcrumbs.component.js index c407e4ead..192fb1f42 100644 --- a/ui/app/components/ui/breadcrumbs/breadcrumbs.component.js +++ b/ui/app/components/ui/breadcrumbs/breadcrumbs.component.js @@ -9,20 +9,22 @@ export default class Breadcrumbs extends PureComponent { total: PropTypes.number, } - render () { + render() { const { className, currentIndex, total } = this.props return (
    - { - Array(total).fill().map((_, i) => ( + {Array(total) + .fill() + .map((_, i) => (
    - )) - } + ))}
    ) } diff --git a/ui/app/components/ui/breadcrumbs/tests/breadcrumbs.component.test.js b/ui/app/components/ui/breadcrumbs/tests/breadcrumbs.component.test.js index 63b9a3f51..cbbbfd8e2 100644 --- a/ui/app/components/ui/breadcrumbs/tests/breadcrumbs.component.test.js +++ b/ui/app/components/ui/breadcrumbs/tests/breadcrumbs.component.test.js @@ -5,18 +5,22 @@ import Breadcrumbs from '../breadcrumbs.component' describe('Breadcrumbs Component', function () { it('should render with the correct colors', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find('.breadcrumbs').length, 1) assert.equal(wrapper.find('.breadcrumb').length, 3) - assert.equal(wrapper.find('.breadcrumb').at(0).props().style.backgroundColor, '#FFFFFF') - assert.equal(wrapper.find('.breadcrumb').at(1).props().style.backgroundColor, '#D8D8D8') - assert.equal(wrapper.find('.breadcrumb').at(2).props().style.backgroundColor, '#FFFFFF') + assert.equal( + wrapper.find('.breadcrumb').at(0).props().style.backgroundColor, + '#FFFFFF', + ) + assert.equal( + wrapper.find('.breadcrumb').at(1).props().style.backgroundColor, + '#D8D8D8', + ) + assert.equal( + wrapper.find('.breadcrumb').at(2).props().style.backgroundColor, + '#FFFFFF', + ) }) }) diff --git a/ui/app/components/ui/button-group/button-group.component.js b/ui/app/components/ui/button-group/button-group.component.js index 2de7730ce..d3082ae61 100644 --- a/ui/app/components/ui/button-group/button-group.component.js +++ b/ui/app/components/ui/button-group/button-group.component.js @@ -26,57 +26,67 @@ export default class ButtonGroup extends PureComponent { : this.props.defaultActiveButtonIndex, } - componentDidUpdate (_, prevState) { + componentDidUpdate(_, prevState) { // Provides an API for dynamically updating the activeButtonIndex - if (typeof this.props.newActiveButtonIndex === 'number' && prevState.activeButtonIndex !== this.props.newActiveButtonIndex) { + if ( + typeof this.props.newActiveButtonIndex === 'number' && + prevState.activeButtonIndex !== this.props.newActiveButtonIndex + ) { this.setState({ activeButtonIndex: this.props.newActiveButtonIndex }) } } - handleButtonClick (activeButtonIndex) { + handleButtonClick(activeButtonIndex) { this.setState({ activeButtonIndex }) } - renderButtons () { + renderButtons() { const { children, disabled, variant } = this.props return React.Children.map(children, (child, index) => { - return child && ( - + return ( + child && ( + + ) ) }) } - render () { + render() { const { className, style, variant } = this.props return (
    - { this.renderButtons() } + {this.renderButtons()}
    ) } diff --git a/ui/app/components/ui/button-group/button-group.stories.js b/ui/app/components/ui/button-group/button-group.stories.js index b92eaeb7c..38c538092 100644 --- a/ui/app/components/ui/button-group/button-group.stories.js +++ b/ui/app/components/ui/button-group/button-group.stories.js @@ -15,38 +15,16 @@ export const withButtons = () => ( disabled={boolean('Disabled', false)} defaultActiveButtonIndex={1} > - - - + + + ) export const withDisabledButton = () => ( - - - + @@ -58,16 +36,8 @@ export const radioButtons = () => ( defaultActiveButtonIndex={1} variant="radiogroup" > - - + + , + , , , ] @@ -23,16 +25,16 @@ describe('ButtonGroup Component', function () { }) beforeEach(function () { - wrapper = shallow(( + wrapper = shallow( {mockButtons} - - )) + , + ) }) afterEach(function () { @@ -79,7 +81,7 @@ describe('ButtonGroup Component', function () { assert.deepEqual(childButtons.get(1), activeChildButton.get(0)) }) - it('should call handleButtonClick and the respective button\'s onClick method when a button is clicked', function () { + it("should call handleButtonClick and the respective button's onClick method when a button is clicked", function () { assert.equal(ButtonGroup.prototype.handleButtonClick.callCount, 0) assert.equal(childButtonSpies.onClick.callCount, 0) const childButtons = wrapper.find('.button-group__button') @@ -109,7 +111,9 @@ describe('ButtonGroup Component', function () { describe('render', function () { it('should render a div with the expected class and style', function () { assert.equal(wrapper.find('div').at(0).props().className, 'someClassName') - assert.deepEqual(wrapper.find('div').at(0).props().style, { color: 'red' }) + assert.deepEqual(wrapper.find('div').at(0).props().style, { + color: 'red', + }) }) it('should call renderButtons when rendering', function () { diff --git a/ui/app/components/ui/button/button.component.js b/ui/app/components/ui/button/button.component.js index c82e52c2a..52b267517 100644 --- a/ui/app/components/ui/button/button.component.js +++ b/ui/app/components/ui/button/button.component.js @@ -25,7 +25,16 @@ const typeHash = { 'first-time': CLASSNAME_FIRST_TIME, } -const Button = ({ type, submit, large, children, icon, rounded, className, ...buttonProps }) => { +const Button = ({ + type, + submit, + large, + children, + icon, + rounded, + className, + ...buttonProps +}) => { // To support using the Button component to render styled links that are semantic html // we swap the html tag we use to render this component and delete any buttonProps that // we know to be erroneous attributes for a link. We will likely want to extract Link @@ -45,10 +54,10 @@ const Button = ({ type, submit, large, children, icon, rounded, className, ...bu rounded && CLASSNAME_ROUNDED, className, )} - { ...buttonProps } + {...buttonProps} > {icon && {icon}} - { children } + {children} ) } diff --git a/ui/app/components/ui/button/button.stories.js b/ui/app/components/ui/button/button.stories.js index c19551835..25fc853de 100644 --- a/ui/app/components/ui/button/button.stories.js +++ b/ui/app/components/ui/button/button.stories.js @@ -66,4 +66,3 @@ export const dangerPrimaryType = () => ( {text('text', 'Click me')} ) - diff --git a/ui/app/components/ui/card/card.component.js b/ui/app/components/ui/card/card.component.js index bb7241da1..c4e96e511 100644 --- a/ui/app/components/ui/card/card.component.js +++ b/ui/app/components/ui/card/card.component.js @@ -10,15 +10,13 @@ export default class Card extends PureComponent { children: PropTypes.node, } - render () { + render() { const { className, overrideClassName, title } = this.props return ( -
    -
    - { title } -
    - { this.props.children } +
    +
    {title}
    + {this.props.children}
    ) } diff --git a/ui/app/components/ui/card/tests/card.component.test.js b/ui/app/components/ui/card/tests/card.component.test.js index 9eb104351..4fc92252a 100644 --- a/ui/app/components/ui/card/tests/card.component.test.js +++ b/ui/app/components/ui/card/tests/card.component.test.js @@ -6,10 +6,7 @@ import Card from '../card.component' describe('Card Component', function () { it('should render a card with a title and child element', function () { const wrapper = shallow( - +
    Child
    , ) diff --git a/ui/app/components/ui/check-box/check-box.component.js b/ui/app/components/ui/check-box/check-box.component.js index 4a7457140..360787902 100644 --- a/ui/app/components/ui/check-box/check-box.component.js +++ b/ui/app/components/ui/check-box/check-box.component.js @@ -13,9 +13,7 @@ export const { CHECKED, INDETERMINATE, UNCHECKED } = CHECKBOX_STATE const CheckBox = ({ className, disabled, id, onClick, checked, title }) => { if (typeof checked === 'boolean') { // eslint-disable-next-line no-param-reassign - checked = checked - ? CHECKBOX_STATE.CHECKED - : CHECKBOX_STATE.UNCHECKED + checked = checked ? CHECKBOX_STATE.CHECKED : CHECKBOX_STATE.UNCHECKED } const ref = useRef(null) useLayoutEffect(() => { @@ -27,17 +25,19 @@ const CheckBox = ({ className, disabled, id, onClick, checked, title }) => { checked={checked === CHECKBOX_STATE.CHECKED} className={classnames('check-box', className, { 'far fa-square': checked === CHECKBOX_STATE.UNCHECKED, - 'fa fa-check-square check-box__checked': checked === CHECKBOX_STATE.CHECKED, - 'fa fa-minus-square check-box__indeterminate': checked === CHECKBOX_STATE.INDETERMINATE, + 'fa fa-check-square check-box__checked': + checked === CHECKBOX_STATE.CHECKED, + 'fa fa-minus-square check-box__indeterminate': + checked === CHECKBOX_STATE.INDETERMINATE, })} disabled={disabled} id={id} onClick={ onClick ? (event) => { - event.preventDefault() - onClick() - } + event.preventDefault() + onClick() + } : null } readOnly @@ -53,7 +53,8 @@ CheckBox.propTypes = { disabled: PropTypes.bool, id: PropTypes.string, onClick: PropTypes.func, - checked: PropTypes.oneOf([...Object.keys(CHECKBOX_STATE), true, false]).isRequired, + checked: PropTypes.oneOf([...Object.keys(CHECKBOX_STATE), true, false]) + .isRequired, title: PropTypes.string, } diff --git a/ui/app/components/ui/check-box/check-box.stories.js b/ui/app/components/ui/check-box/check-box.stories.js index 7a573a14c..20647f780 100644 --- a/ui/app/components/ui/check-box/check-box.stories.js +++ b/ui/app/components/ui/check-box/check-box.stories.js @@ -1,7 +1,11 @@ import React from 'react' import { action } from '@storybook/addon-actions' import { boolean, select, text } from '@storybook/addon-knobs/react' -import CheckBox, { CHECKED, INDETERMINATE, UNCHECKED } from './check-box.component' +import CheckBox, { + CHECKED, + INDETERMINATE, + UNCHECKED, +} from './check-box.component' export default { title: 'Check Box', diff --git a/ui/app/components/ui/check-box/index.js b/ui/app/components/ui/check-box/index.js index fc4dfd2f8..9a7460d6a 100644 --- a/ui/app/components/ui/check-box/index.js +++ b/ui/app/components/ui/check-box/index.js @@ -1 +1,6 @@ -export { default, CHECKED, INDETERMINATE, UNCHECKED } from './check-box.component' +export { + default, + CHECKED, + INDETERMINATE, + UNCHECKED, +} from './check-box.component' diff --git a/ui/app/components/ui/circle-icon/circle-icon.component.js b/ui/app/components/ui/circle-icon/circle-icon.component.js index 047245535..e019aa99e 100644 --- a/ui/app/components/ui/circle-icon/circle-icon.component.js +++ b/ui/app/components/ui/circle-icon/circle-icon.component.js @@ -15,13 +15,8 @@ export default class CircleIcon extends PureComponent { circleClass: '', } - render () { - const { - size, - circleClass, - iconSize, - iconSource, - } = this.props + render() { + const { size, circleClass, iconSize, iconSource } = this.props return (
    - { prefixComponent } - { parts.prefix }{ parts.value } - { - parts.suffix && ( - - { parts.suffix } - - ) - } + {prefixComponent} + + {parts.prefix} + {parts.value} + + {parts.suffix && ( + + {parts.suffix} + + )}
    ) } diff --git a/ui/app/components/ui/currency-display/tests/currency-display.component.test.js b/ui/app/components/ui/currency-display/tests/currency-display.component.test.js index 68bac84cf..9e023aef3 100644 --- a/ui/app/components/ui/currency-display/tests/currency-display.component.test.js +++ b/ui/app/components/ui/currency-display/tests/currency-display.component.test.js @@ -15,27 +15,27 @@ describe('CurrencyDisplay Component', function () { })) }) it('should render text with a className', function () { - const wrapper = shallow(( + const wrapper = shallow( - )) + />, + ) assert.ok(wrapper.hasClass('currency-display')) assert.equal(wrapper.text(), '$123.45') }) it('should render text with a prefix', function () { - const wrapper = shallow(( + const wrapper = shallow( - )) + />, + ) assert.ok(wrapper.hasClass('currency-display')) assert.equal(wrapper.text(), '-$123.45') diff --git a/ui/app/components/ui/currency-input/currency-input.component.js b/ui/app/components/ui/currency-input/currency-input.component.js index f17fb5792..5fc3b991d 100644 --- a/ui/app/components/ui/currency-input/currency-input.component.js +++ b/ui/app/components/ui/currency-input/currency-input.component.js @@ -2,7 +2,10 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import UnitInput from '../unit-input' import CurrencyDisplay from '../currency-display' -import { getValueFromWeiHex, getWeiHexFromDecimalValue } from '../../../helpers/utils/conversions.util' +import { + getValueFromWeiHex, + getWeiHexFromDecimalValue, +} from '../../../helpers/utils/conversions.util' import { ETH } from '../../../helpers/constants/common' /** @@ -28,7 +31,7 @@ export default class CurrencyInput extends PureComponent { nativeSuffix: PropTypes.string, } - constructor (props) { + constructor(props) { super(props) const { value: hexValue } = props @@ -41,26 +44,34 @@ export default class CurrencyInput extends PureComponent { } } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { value: prevPropsHexValue } = prevProps const { value: propsHexValue } = this.props const { hexValue: stateHexValue } = this.state - if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) { + if ( + prevPropsHexValue !== propsHexValue && + propsHexValue !== stateHexValue + ) { const decimalValue = this.getDecimalValue(this.props) this.setState({ hexValue: propsHexValue, decimalValue }) } } - getDecimalValue (props) { + getDecimalValue(props) { const { value: hexValue, currentCurrency, conversionRate } = props const decimalValueString = this.shouldUseFiat() ? getValueFromWeiHex({ - value: hexValue, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, - }) + value: hexValue, + toCurrency: currentCurrency, + conversionRate, + numberOfDecimals: 2, + }) : getValueFromWeiHex({ - value: hexValue, toCurrency: ETH, numberOfDecimals: 6, - }) + value: hexValue, + toCurrency: ETH, + numberOfDecimals: 6, + }) return Number(decimalValueString) || 0 } @@ -84,21 +95,31 @@ export default class CurrencyInput extends PureComponent { } handleChange = (decimalValue) => { - const { currentCurrency: fromCurrency, conversionRate, onChange } = this.props + const { + currentCurrency: fromCurrency, + conversionRate, + onChange, + } = this.props const hexValue = this.shouldUseFiat() ? getWeiHexFromDecimalValue({ - value: decimalValue, fromCurrency, conversionRate, invertConversionRate: true, - }) + value: decimalValue, + fromCurrency, + conversionRate, + invertConversionRate: true, + }) : getWeiHexFromDecimalValue({ - value: decimalValue, fromCurrency: ETH, fromDenomination: ETH, conversionRate, - }) + value: decimalValue, + fromCurrency: ETH, + fromDenomination: ETH, + conversionRate, + }) this.setState({ hexValue, decimalValue }) onChange(hexValue) } - renderConversionComponent () { + renderConversionComponent() { const { currentCurrency, nativeCurrency, hideFiat } = this.props const { hexValue } = this.state let currency, numberOfDecimals @@ -106,7 +127,7 @@ export default class CurrencyInput extends PureComponent { if (hideFiat) { return (
    - { this.context.t('noConversionRateAvailable') } + {this.context.t('noConversionRateAvailable')}
    ) } @@ -131,7 +152,7 @@ export default class CurrencyInput extends PureComponent { ) } - render () { + render() { const { fiatSuffix, nativeSuffix, maxModeOn, ...restProps } = this.props const { decimalValue } = this.state @@ -142,14 +163,11 @@ export default class CurrencyInput extends PureComponent { onChange={this.handleChange} value={decimalValue} maxModeOn={maxModeOn} - actionComponent={( -
    - )} + actionComponent={ +
    + } > - { this.renderConversionComponent() } + {this.renderConversionComponent()} ) } diff --git a/ui/app/components/ui/currency-input/currency-input.container.js b/ui/app/components/ui/currency-input/currency-input.container.js index 581e1c1a2..3a5719929 100644 --- a/ui/app/components/ui/currency-input/currency-input.container.js +++ b/ui/app/components/ui/currency-input/currency-input.container.js @@ -8,7 +8,9 @@ import { import CurrencyInput from './currency-input.component' const mapStateToProps = (state) => { - const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state + const { + metamask: { nativeCurrency, currentCurrency, conversionRate }, + } = state const { showFiatInTestnets } = getPreferences(state) const isMainnet = getIsMainnet(state) const maxModeOn = getSendMaxModeState(state) @@ -17,7 +19,7 @@ const mapStateToProps = (state) => { nativeCurrency, currentCurrency, conversionRate, - hideFiat: (!isMainnet && !showFiatInTestnets), + hideFiat: !isMainnet && !showFiatInTestnets, maxModeOn, } } diff --git a/ui/app/components/ui/currency-input/tests/currency-input.component.test.js b/ui/app/components/ui/currency-input/tests/currency-input.component.test.js index 1e7936978..d4d88be02 100644 --- a/ui/app/components/ui/currency-input/tests/currency-input.component.test.js +++ b/ui/app/components/ui/currency-input/tests/currency-input.component.test.js @@ -12,9 +12,7 @@ import CurrencyDisplay from '../../currency-display' describe('CurrencyInput Component', function () { describe('rendering', function () { it('should render properly without a suffix', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find(UnitInput).length, 1) @@ -76,7 +74,10 @@ describe('CurrencyInput Component', function () { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$231.06USD', + ) }) it('should render properly with a fiat value', function () { @@ -110,7 +111,10 @@ describe('CurrencyInput Component', function () { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') + assert.equal( + wrapper.find('.currency-display-component').text(), + '0.004328ETH', + ) }) it('should render properly with a native value when hideFiat is true', function () { @@ -149,7 +153,10 @@ describe('CurrencyInput Component', function () { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH') assert.equal(wrapper.find('.unit-input__input').props().value, '0.004328') - assert.equal(wrapper.find('.currency-input__conversion-component').text(), 'noConversionRateAvailable_t') + assert.equal( + wrapper.find('.currency-input__conversion-component').text(), + 'noConversionRateAvailable_t', + ) }) }) @@ -190,14 +197,20 @@ describe('CurrencyInput Component', function () { const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance() assert.equal(currencyInputInstance.state.decimalValue, 0) assert.equal(currencyInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$0.00USD', + ) const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000')) - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$231.06USD', + ) assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000') }) @@ -238,7 +251,10 @@ describe('CurrencyInput Component', function () { input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('f602f2234d0ea')) - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') + assert.equal( + wrapper.find('.currency-display-component').text(), + '0.004328ETH', + ) assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea') }) @@ -307,20 +323,29 @@ describe('CurrencyInput Component', function () { const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance() assert.equal(currencyInputInstance.state.decimalValue, 0) assert.equal(currencyInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$0.00USD', + ) const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000')) - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$231.06USD', + ) assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000') const swap = wrapper.find('.currency-input__swap-component') swap.simulate('click') - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') + assert.equal( + wrapper.find('.currency-display-component').text(), + '0.004328ETH', + ) }) }) }) diff --git a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js index 1806d6425..3dac9add0 100644 --- a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js +++ b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js @@ -45,7 +45,8 @@ describe('CurrencyInput container', function () { }, // Test # 2 { - comment: 'should return correct props when not in mainnet and showFiatInTestnets is false', + comment: + 'should return correct props when not in mainnet and showFiatInTestnets is false', mockState: { metamask: { conversionRate: 280.45, @@ -72,7 +73,8 @@ describe('CurrencyInput container', function () { }, // Test # 3 { - comment: 'should return correct props when not in mainnet and showFiatInTestnets is true', + comment: + 'should return correct props when not in mainnet and showFiatInTestnets is true', mockState: { metamask: { conversionRate: 280.45, @@ -99,7 +101,8 @@ describe('CurrencyInput container', function () { }, // Test # 4 { - comment: 'should return correct props when in mainnet and showFiatInTestnets is true', + comment: + 'should return correct props when in mainnet and showFiatInTestnets is true', mockState: { metamask: { conversionRate: 280.45, @@ -179,10 +182,19 @@ describe('CurrencyInput container', function () { }, ] - tests.forEach(({ mock: { stateProps, dispatchProps, ownProps }, expected, comment }) => { - it(comment, function () { - assert.deepEqual(mergeProps(stateProps, dispatchProps, ownProps), expected) - }) - }) + tests.forEach( + ({ + mock: { stateProps, dispatchProps, ownProps }, + expected, + comment, + }) => { + it(comment, function () { + assert.deepEqual( + mergeProps(stateProps, dispatchProps, ownProps), + expected, + ) + }) + }, + ) }) }) diff --git a/ui/app/components/ui/dialog/index.js b/ui/app/components/ui/dialog/index.js index 50b777a7a..672d83337 100644 --- a/ui/app/components/ui/dialog/index.js +++ b/ui/app/components/ui/dialog/index.js @@ -2,7 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -export default function Dialog (props) { +export default function Dialog(props) { const { children, type, className, onClick } = props return (
    - { children } + {children}
    ) } diff --git a/ui/app/components/ui/dropdown/dropdown.js b/ui/app/components/ui/dropdown/dropdown.js index be4a052a4..db75be922 100644 --- a/ui/app/components/ui/dropdown/dropdown.js +++ b/ui/app/components/ui/dropdown/dropdown.js @@ -2,7 +2,15 @@ import React, { useCallback } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -const Dropdown = ({ className, disabled, onChange, options, selectedOption, style, title }) => { +const Dropdown = ({ + className, + disabled, + onChange, + options, + selectedOption, + style, + title, +}) => { const _onChange = useCallback( (event) => { event.preventDefault() @@ -21,18 +29,13 @@ const Dropdown = ({ className, disabled, onChange, options, selectedOption, styl style={style} value={selectedOption} > - { - options.map((option) => { - return ( - - ) - }) - } + {options.map((option) => { + return ( + + ) + })} ) } diff --git a/ui/app/components/ui/dropdown/dropdown.stories.js b/ui/app/components/ui/dropdown/dropdown.stories.js index 1ecb31bc9..e5771623f 100644 --- a/ui/app/components/ui/dropdown/dropdown.stories.js +++ b/ui/app/components/ui/dropdown/dropdown.stories.js @@ -16,7 +16,10 @@ const namedOptions = unnamedOptions.map((option, index) => { }) const namedOptionsWithVeryLongNames = unnamedOptions.map((option, index) => { - return { ...option, name: `Option ${index} with a very${', very'.repeat(index)} long name` } + return { + ...option, + name: `Option ${index} with a very${', very'.repeat(index)} long name`, + } }) export const simple = () => ( @@ -26,13 +29,11 @@ export const simple = () => ( onChange={action('Selection changed')} options={namedOptions} required={boolean('Required', false)} - selectedOption={ - select( - 'Selected Option', - namedOptions.map((option) => option.value), - namedOptions[0].value, - ) - } + selectedOption={select( + 'Selected Option', + namedOptions.map((option) => option.value), + namedOptions[0].value, + )} /> ) @@ -43,13 +44,11 @@ export const optionsWithoutNames = () => ( onChange={action('Selection changed')} options={unnamedOptions} required={boolean('Required', false)} - selectedOption={ - select( - 'Selected Option', - unnamedOptions.map((option) => option.value), - unnamedOptions[0].value, - ) - } + selectedOption={select( + 'Selected Option', + unnamedOptions.map((option) => option.value), + unnamedOptions[0].value, + )} /> ) @@ -60,13 +59,11 @@ export const optionsWithLongNames = () => ( onChange={action('Selection changed')} options={namedOptionsWithVeryLongNames} required={boolean('Required', false)} - selectedOption={ - select( - 'Selected Option', - namedOptionsWithVeryLongNames.map((option) => option.value), - namedOptionsWithVeryLongNames[0].value, - ) - } + selectedOption={select( + 'Selected Option', + namedOptionsWithVeryLongNames.map((option) => option.value), + namedOptionsWithVeryLongNames[0].value, + )} /> ) @@ -77,13 +74,11 @@ export const optionsWithLongNamesAndShortWidth = () => ( onChange={action('Selection changed')} options={namedOptionsWithVeryLongNames} required={boolean('Required', false)} - selectedOption={ - select( - 'Selected Option', - namedOptionsWithVeryLongNames.map((option) => option.value), - namedOptionsWithVeryLongNames[0].value, - ) - } + selectedOption={select( + 'Selected Option', + namedOptionsWithVeryLongNames.map((option) => option.value), + namedOptionsWithVeryLongNames[0].value, + )} style={{ width: '200px' }} /> ) diff --git a/ui/app/components/ui/editable-label/editable-label.js b/ui/app/components/ui/editable-label/editable-label.js index d1788472e..e082082b1 100644 --- a/ui/app/components/ui/editable-label/editable-label.js +++ b/ui/app/components/ui/editable-label/editable-label.js @@ -14,21 +14,22 @@ class EditableLabel extends Component { value: this.props.defaultValue || '', } - handleSubmit () { + handleSubmit() { const { value } = this.state if (value === '') { return } - Promise.resolve(this.props.onSubmit(value)) - .then(() => this.setState({ isEditing: false })) + Promise.resolve(this.props.onSubmit(value)).then(() => + this.setState({ isEditing: false }), + ) } - renderEditing () { + renderEditing() { const { value } = this.state - return [( + return [ - ), ( + />,
    - this.handleSubmit()} /> -
    - )] + this.handleSubmit()} + /> +
    , + ] } - renderReadonly () { - return [( -
    {this.state.value}
    - ), ( + renderReadonly() { + return [ +
    + {this.state.value} +
    ,
    - this.setState({ isEditing: true })} /> -
    - )] + this.setState({ isEditing: true })} + /> +
    , + ] } - render () { + render() { const { isEditing } = this.state const { className } = this.props return (
    - { - isEditing - ? this.renderEditing() - : this.renderReadonly() - } + {isEditing ? this.renderEditing() : this.renderReadonly()}
    ) } diff --git a/ui/app/components/ui/error-message/error-message.component.js b/ui/app/components/ui/error-message/error-message.component.js index b4464c33b..e4d39ee4f 100644 --- a/ui/app/components/ui/error-message/error-message.component.js +++ b/ui/app/components/ui/error-message/error-message.component.js @@ -7,13 +7,8 @@ const ErrorMessage = (props, context) => { return (
    - -
    - { `ALERT: ${error}` } -
    + +
    {`ALERT: ${error}`}
    ) } diff --git a/ui/app/components/ui/error-message/tests/error-message.component.test.js b/ui/app/components/ui/error-message/tests/error-message.component.test.js index 8e4025bc7..5bf05d876 100644 --- a/ui/app/components/ui/error-message/tests/error-message.component.test.js +++ b/ui/app/components/ui/error-message/tests/error-message.component.test.js @@ -7,30 +7,30 @@ describe('ErrorMessage Component', function () { const t = (key) => `translate ${key}` it('should render a message from props.errorMessage', function () { - const wrapper = shallow( - , - { context: { t } }, - ) + const wrapper = shallow(, { + context: { t }, + }) assert.ok(wrapper) assert.equal(wrapper.find('.error-message').length, 1) assert.equal(wrapper.find('.error-message__icon').length, 1) - assert.equal(wrapper.find('.error-message__text').text(), 'ALERT: This is an error.') + assert.equal( + wrapper.find('.error-message__text').text(), + 'ALERT: This is an error.', + ) }) it('should render a message translated from props.errorKey', function () { - const wrapper = shallow( - , - { context: { t } }, - ) + const wrapper = shallow(, { + context: { t }, + }) assert.ok(wrapper) assert.equal(wrapper.find('.error-message').length, 1) assert.equal(wrapper.find('.error-message__icon').length, 1) - assert.equal(wrapper.find('.error-message__text').text(), 'ALERT: translate testKey') + assert.equal( + wrapper.find('.error-message__text').text(), + 'ALERT: translate testKey', + ) }) }) diff --git a/ui/app/components/ui/export-text-container/export-text-container.component.js b/ui/app/components/ui/export-text-container/export-text-container.component.js index 1bd4d4e2f..2afa20575 100644 --- a/ui/app/components/ui/export-text-container/export-text-container.component.js +++ b/ui/app/components/ui/export-text-container/export-text-container.component.js @@ -5,7 +5,7 @@ import Copy from '../icon/copy-icon.component' import { useI18nContext } from '../../../hooks/useI18nContext' import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard' -function ExportTextContainer ({ text = '' }) { +function ExportTextContainer({ text = '' }) { const t = useI18nContext() const [copied, handleCopy] = useCopyToClipboard() diff --git a/ui/app/components/ui/hex-to-decimal/hex-to-decimal.component.js b/ui/app/components/ui/hex-to-decimal/hex-to-decimal.component.js index f03aaf255..69ddea055 100644 --- a/ui/app/components/ui/hex-to-decimal/hex-to-decimal.component.js +++ b/ui/app/components/ui/hex-to-decimal/hex-to-decimal.component.js @@ -8,14 +8,10 @@ export default class HexToDecimal extends PureComponent { value: PropTypes.string, } - render () { + render() { const { className, value } = this.props const decimalValue = hexToDecimal(value) - return ( -
    - { decimalValue } -
    - ) + return
    {decimalValue}
    } } diff --git a/ui/app/components/ui/hex-to-decimal/tests/hex-to-decimal.component.test.js b/ui/app/components/ui/hex-to-decimal/tests/hex-to-decimal.component.test.js index 683bb29d5..3d8086630 100644 --- a/ui/app/components/ui/hex-to-decimal/tests/hex-to-decimal.component.test.js +++ b/ui/app/components/ui/hex-to-decimal/tests/hex-to-decimal.component.test.js @@ -5,24 +5,18 @@ import HexToDecimal from '../hex-to-decimal.component' describe('HexToDecimal Component', function () { it('should render a prefixed hex as a decimal with a className', function () { - const wrapper = shallow(( - - )) + const wrapper = shallow( + , + ) assert.ok(wrapper.hasClass('hex-to-decimal')) assert.equal(wrapper.text(), '12345') }) it('should render an unprefixed hex as a decimal with a className', function () { - const wrapper = shallow(( - - )) + const wrapper = shallow( + , + ) assert.ok(wrapper.hasClass('hex-to-decimal')) assert.equal(wrapper.text(), '6789') diff --git a/ui/app/components/ui/icon-border/icon-border.js b/ui/app/components/ui/icon-border/icon-border.js index 5911cf918..f320a04b8 100644 --- a/ui/app/components/ui/icon-border/icon-border.js +++ b/ui/app/components/ui/icon-border/icon-border.js @@ -1,11 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' -export default function IconBorder ({ children, size }) { +export default function IconBorder({ children, size }) { const borderStyle = { height: `${size}px`, width: `${size}px` } return (
    - { children } + {children}
    ) } diff --git a/ui/app/components/ui/icon-button/icon-button.js b/ui/app/components/ui/icon-button/icon-button.js index 16767bf5e..7d95fa8d4 100644 --- a/ui/app/components/ui/icon-button/icon-button.js +++ b/ui/app/components/ui/icon-button/icon-button.js @@ -4,20 +4,28 @@ import classNames from 'classnames' const defaultRender = (inner) => inner -export default function IconButton ({ onClick, Icon, disabled, label, tooltipRender, className, ...props }) { +export default function IconButton({ + onClick, + Icon, + disabled, + label, + tooltipRender, + className, + ...props +}) { const renderWrapper = tooltipRender ?? defaultRender return ( - +
    ) @@ -63,9 +58,18 @@ export const pending = () => ( icon={} title={text('title', 'Hatch Turtles')} className="list-item" - subtitleStatus={Unapproved · } + subtitleStatus={ + + Unapproved ·{' '} + + } subtitle={text('subtitle', 'Turtlefarm.com')} - rightContent={} + rightContent={ + + } /> ) @@ -75,7 +79,12 @@ export const approve = () => ( title={text('title', 'Approve spend limit')} className="list-item" subtitle={text('subtitle', 'Sept 20 · oxuniverse.com')} - rightContent={} + rightContent={ + + } /> ) @@ -85,6 +94,11 @@ export const receive = () => ( title={text('title', 'Hatch Turtles')} className="list-item" subtitle={text('subtitle', 'Sept 20 · From: 00X4...3058')} - rightContent={} + rightContent={ + + } /> ) diff --git a/ui/app/components/ui/list-item/tests/list-item.test.js b/ui/app/components/ui/list-item/tests/list-item.test.js index fc998e369..94d42ea3c 100644 --- a/ui/app/components/ui/list-item/tests/list-item.test.js +++ b/ui/app/components/ui/list-item/tests/list-item.test.js @@ -41,19 +41,31 @@ describe('ListItem', function () { assert.equal(wrapper.find('.list-item__heading h2').text(), TITLE) }) it(`renders "I am a list item" subtitle`, function () { - assert.equal(wrapper.find('.list-item__subheading').text(), 'I am a list item') + assert.equal( + wrapper.find('.list-item__subheading').text(), + 'I am a list item', + ) }) it('attaches external className', function () { assert(wrapper.props().className.includes(CLASSNAME)) }) it('renders content on the right side of the list item', function () { - assert.equal(wrapper.find('.list-item__right-content p').text(), 'Content rendered to the right') + assert.equal( + wrapper.find('.list-item__right-content p').text(), + 'Content rendered to the right', + ) }) it('renders content in the middle of the list item', function () { - assert.equal(wrapper.find('.list-item__mid-content p').text(), 'Content rendered in the middle') + assert.equal( + wrapper.find('.list-item__mid-content p').text(), + 'Content rendered in the middle', + ) }) it('renders list item actions', function () { - assert.equal(wrapper.find('.list-item__actions button').text(), 'I am a button') + assert.equal( + wrapper.find('.list-item__actions button').text(), + 'I am a button', + ) }) it('renders the title icon', function () { assert(wrapper.find(Preloader)) diff --git a/ui/app/components/ui/loading-screen/loading-screen.component.js b/ui/app/components/ui/loading-screen/loading-screen.component.js index 457f2dcbd..c3b590a14 100644 --- a/ui/app/components/ui/loading-screen/loading-screen.component.js +++ b/ui/app/components/ui/loading-screen/loading-screen.component.js @@ -14,22 +14,28 @@ class LoadingScreen extends Component { header: PropTypes.element, } - renderMessage () { + renderMessage() { const { loadingMessage } = this.props if (!loadingMessage) { return null } - return isValidElement(loadingMessage) ? loadingMessage : {loadingMessage} + return isValidElement(loadingMessage) ? ( + loadingMessage + ) : ( + {loadingMessage} + ) } - render () { + render() { return (
    {this.props.header}
    - {this.props.showLoadingSpinner && } + {this.props.showLoadingSpinner && ( + + )} {this.renderMessage()}
    diff --git a/ui/app/components/ui/lock-icon/lock-icon.component.js b/ui/app/components/ui/lock-icon/lock-icon.component.js index 7724b75dd..bc8828e20 100644 --- a/ui/app/components/ui/lock-icon/lock-icon.component.js +++ b/ui/app/components/ui/lock-icon/lock-icon.component.js @@ -1,6 +1,6 @@ import React from 'react' -export default function LockIcon (props) { +export default function LockIcon(props) { return ( { - const horizontalMiddle = left + (width / 2) - const verticalMiddle = top + (height / 2) + const horizontalMiddle = left + width / 2 + const verticalMiddle = top + height / 2 return { up: { x: horizontalMiddle, y: top - height }, - down: { x: horizontalMiddle, y: top + (height * 2) }, + down: { x: horizontalMiddle, y: top + height * 2 }, left: { x: left - width, y: verticalMiddle }, - right: { x: left + (width * 2), y: verticalMiddle }, + right: { x: left + width * 2, y: verticalMiddle }, middle: { x: horizontalMiddle, y: verticalMiddle }, } } @@ -33,7 +33,7 @@ export default class Mascot extends Component { lookAtDirection: null, } - constructor (props) { + constructor(props) { super(props) const { width, height, followMouse } = props @@ -47,29 +47,37 @@ export default class Mascot extends Component { this.mascotContainer = createRef() - this.refollowMouse = debounce(this.logo.setFollowMouse.bind(this.logo, true), 1000) + this.refollowMouse = debounce( + this.logo.setFollowMouse.bind(this.logo, true), + 1000, + ) this.unfollowMouse = this.logo.setFollowMouse.bind(this.logo, false) } - handleAnimationEvents () { + handleAnimationEvents() { // only setup listeners once if (this.animations) { return } this.animations = this.props.animationEventEmitter this.animations.on('point', this.lookAt.bind(this)) - this.animations.on('setFollowMouse', this.logo.setFollowMouse.bind(this.logo)) + this.animations.on( + 'setFollowMouse', + this.logo.setFollowMouse.bind(this.logo), + ) } - lookAt (target) { + lookAt(target) { this.unfollowMouse() this.logo.lookAt(target) this.refollowMouse() } - componentDidMount () { + componentDidMount() { this.mascotContainer.current.appendChild(this.logo.container) - this.directionTargetMap = directionTargetGenerator(this.mascotContainer.current.getBoundingClientRect()) + this.directionTargetMap = directionTargetGenerator( + this.mascotContainer.current.getBoundingClientRect(), + ) const { lookAtTarget, lookAtDirection } = this.props @@ -80,13 +88,20 @@ export default class Mascot extends Component { } } - componentDidUpdate (prevProps) { - const { lookAtTarget: prevTarget = {}, lookAtDirection: prevDirection = null, followMouse: prevFollowMouse } = prevProps + componentDidUpdate(prevProps) { + const { + lookAtTarget: prevTarget = {}, + lookAtDirection: prevDirection = null, + followMouse: prevFollowMouse, + } = prevProps const { lookAtTarget = {}, followMouse, lookAtDirection } = this.props if (lookAtDirection && prevDirection !== lookAtDirection) { this.logo.lookAtAndRender(this.directionTargetMap[lookAtDirection]) - } else if (lookAtTarget?.x !== prevTarget?.x || lookAtTarget?.y !== prevTarget?.y) { + } else if ( + lookAtTarget?.x !== prevTarget?.x || + lookAtTarget?.y !== prevTarget?.y + ) { this.logo.lookAtAndRender(lookAtTarget) } if (prevFollowMouse !== followMouse) { @@ -95,23 +110,18 @@ export default class Mascot extends Component { } } - componentWillUnmount () { + componentWillUnmount() { this.animations = this.props.animationEventEmitter this.animations.removeAllListeners() this.logo.container.remove() this.logo.stopAnimation() } - render () { + render() { // this is a bit hacky // the event emitter is on `this.props` // and we dont get that until render this.handleAnimationEvents() - return ( -
    - ) + return
    } } diff --git a/ui/app/components/ui/mascot/mascot.stories.js b/ui/app/components/ui/mascot/mascot.stories.js index 0ce1ab09a..ad698370b 100644 --- a/ui/app/components/ui/mascot/mascot.stories.js +++ b/ui/app/components/ui/mascot/mascot.stories.js @@ -24,7 +24,7 @@ export default { title: 'Mascot', } -export function Demo () { +export function Demo() { const [lookAtDirection, setLookAtDirection] = useState(null) const [followMouseMode, setFollowMouseMode] = useState(false) const [clickToLookMode, setClickToLookMode] = useState(false) @@ -40,7 +40,9 @@ export function Demo () {
    { - const isButtonClick = event.target.classList.contains('button-group__button') + const isButtonClick = event.target.classList.contains( + 'button-group__button', + ) if (clickToLookMode && !isButtonClick) { setLookAtDirection(null) setClickedTarget({ x: event.clientX, y: event.clientY }) @@ -60,21 +62,11 @@ export function Demo () { style={{ width: '300px', flexFlow: 'column' }} defaultActiveButtonIndex={4} > - - - - - + + + + + ) diff --git a/ui/app/components/ui/menu/menu.js b/ui/app/components/ui/menu/menu.js index 9682a8cc6..c093cf80c 100644 --- a/ui/app/components/ui/menu/menu.js +++ b/ui/app/components/ui/menu/menu.js @@ -4,11 +4,23 @@ import { createPortal } from 'react-dom' import { usePopper } from 'react-popper' import classnames from 'classnames' -const Menu = ({ anchorElement, children, className, onHide, popperOptions }) => { +const Menu = ({ + anchorElement, + children, + className, + onHide, + popperOptions, +}) => { const [popperElement, setPopperElement] = useState(null) - const popoverContainerElement = useRef(document.getElementById('popover-content')) + const popoverContainerElement = useRef( + document.getElementById('popover-content'), + ) - const { attributes, styles } = usePopper(anchorElement, popperElement, popperOptions) + const { attributes, styles } = usePopper( + anchorElement, + popperElement, + popperOptions, + ) return createPortal( <> @@ -19,7 +31,7 @@ const Menu = ({ anchorElement, children, className, onHide, popperOptions }) => style={styles.popper} {...attributes.popper} > - { children } + {children}
    , popoverContainerElement.current, diff --git a/ui/app/components/ui/menu/menu.stories.js b/ui/app/components/ui/menu/menu.stories.js index 02eb2186a..59b73b701 100644 --- a/ui/app/components/ui/menu/menu.stories.js +++ b/ui/app/components/ui/menu/menu.stories.js @@ -8,12 +8,14 @@ export default { export const Basic = () => { return ( - - Menu Item 1 + + + Menu Item 1 + Menu Item 2 - Menu Item 3 + + Menu Item 3 + ) } @@ -23,13 +25,17 @@ export const Anchored = () => { return ( <> - - Menu Item 1 + + + Menu Item 1 + Menu Item 2 - Menu Item 3 + + Menu Item 3 + ) diff --git a/ui/app/components/ui/metafox-logo/metafox-logo.component.js b/ui/app/components/ui/metafox-logo/metafox-logo.component.js index 4b1509c6e..6a9838543 100644 --- a/ui/app/components/ui/metafox-logo/metafox-logo.component.js +++ b/ui/app/components/ui/metafox-logo/metafox-logo.component.js @@ -12,7 +12,7 @@ export default class MetaFoxLogo extends PureComponent { onClick: undefined, } - render () { + render() { const { onClick, unsetIconHeight } = this.props const iconProps = unsetIconHeight ? {} : { height: 42, width: 42 } @@ -26,12 +26,18 @@ export default class MetaFoxLogo extends PureComponent {
    ) diff --git a/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js b/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js index acdf4c1c7..ab2fd753b 100644 --- a/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js +++ b/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js @@ -4,22 +4,29 @@ import { mount } from 'enzyme' import MetaFoxLogo from '..' describe('MetaFoxLogo', function () { - it('sets icon height and width to 42 by default', function () { - const wrapper = mount( - , - ) + const wrapper = mount() - assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('width'), 42) - assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('height'), 42) + assert.equal( + wrapper.find('img.app-header__metafox-logo--icon').prop('width'), + 42, + ) + assert.equal( + wrapper.find('img.app-header__metafox-logo--icon').prop('height'), + 42, + ) }) it('does not set icon height and width when unsetIconHeight is true', function () { - const wrapper = mount( - , - ) + const wrapper = mount() - assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('width'), null) - assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('height'), null) + assert.equal( + wrapper.find('img.app-header__metafox-logo--icon').prop('width'), + null, + ) + assert.equal( + wrapper.find('img.app-header__metafox-logo--icon').prop('height'), + null, + ) }) }) diff --git a/ui/app/components/ui/page-container/page-container-content.component.js b/ui/app/components/ui/page-container/page-container-content.component.js index 476e25e5c..c833c76bf 100644 --- a/ui/app/components/ui/page-container/page-container-content.component.js +++ b/ui/app/components/ui/page-container/page-container-content.component.js @@ -2,17 +2,11 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' export default class PageContainerContent extends Component { - static propTypes = { children: PropTypes.node.isRequired, } - render () { - return ( -
    - {this.props.children} -
    - ) + render() { + return
    {this.props.children}
    } - } diff --git a/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js index 3f59498c6..9278f4e25 100644 --- a/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js +++ b/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js @@ -4,7 +4,6 @@ import classnames from 'classnames' import Button from '../../button' export default class PageContainerFooter extends Component { - static propTypes = { children: PropTypes.node, onCancel: PropTypes.func, @@ -24,7 +23,7 @@ export default class PageContainerFooter extends Component { t: PropTypes.func, } - render () { + render() { const { children, onCancel, @@ -42,40 +41,41 @@ export default class PageContainerFooter extends Component { return (
    -
    {!hideCancel && ( )}
    {children && ( -
    - {children} -
    +
    {children}
    )} -
    ) } - } diff --git a/ui/app/components/ui/page-container/page-container-footer/tests/page-container-footer.component.test.js b/ui/app/components/ui/page-container/page-container-footer/tests/page-container-footer.component.test.js index 8a5cf1114..ff41417a3 100644 --- a/ui/app/components/ui/page-container/page-container-footer/tests/page-container-footer.component.test.js +++ b/ui/app/components/ui/page-container/page-container-footer/tests/page-container-footer.component.test.js @@ -11,7 +11,7 @@ describe('Page Footer', function () { const onSubmit = sinon.spy() beforeEach(function () { - wrapper = shallow(( + wrapper = shallow( - )) + />, + ) }) it('renders page container footer', function () { @@ -43,34 +43,46 @@ describe('Page Footer', function () { }) describe('Cancel Button', function () { - it('has button type of default', function () { - assert.equal(wrapper.find('.page-container__footer-button').first().prop('type'), 'default') + assert.equal( + wrapper.find('.page-container__footer-button').first().prop('type'), + 'default', + ) }) it('has children text of Cancel', function () { - assert.equal(wrapper.find('.page-container__footer-button').first().prop('children'), 'Cancel') + assert.equal( + wrapper.find('.page-container__footer-button').first().prop('children'), + 'Cancel', + ) }) it('should call cancel when click is simulated', function () { wrapper.find('.page-container__footer-button').first().prop('onClick')() assert.equal(onCancel.callCount, 1) }) - }) describe('Submit Button', function () { - it('assigns button type based on props', function () { - assert.equal(wrapper.find('.page-container__footer-button').last().prop('type'), 'Test Type') + assert.equal( + wrapper.find('.page-container__footer-button').last().prop('type'), + 'Test Type', + ) }) it('has disabled prop', function () { - assert.equal(wrapper.find('.page-container__footer-button').last().prop('disabled'), false) + assert.equal( + wrapper.find('.page-container__footer-button').last().prop('disabled'), + false, + ) }) it('has children text when submitText prop exists', function () { - assert.equal(wrapper.find('.page-container__footer-button').last().prop('children'), 'Submit') + assert.equal( + wrapper.find('.page-container__footer-button').last().prop('children'), + 'Submit', + ) }) it('should call submit when click is simulated', function () { diff --git a/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js b/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js index 5d5a88a9e..0f715a027 100644 --- a/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js +++ b/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js @@ -17,34 +17,44 @@ export default class PageContainerHeader extends Component { className: PropTypes.string, } - renderTabs () { + renderTabs() { const { tabs } = this.props - return tabs && ( -
      - { tabs } -
    + return tabs &&
      {tabs}
    + } + + renderHeaderRow() { + const { + showBackButton, + onBackButtonClick, + backButtonStyles, + backButtonString, + } = this.props + + return ( + showBackButton && ( +
    + + {backButtonString || 'Back'} + +
    + ) ) } - renderHeaderRow () { - const { showBackButton, onBackButtonClick, backButtonStyles, backButtonString } = this.props - - return showBackButton && ( -
    - - { backButtonString || 'Back' } - -
    - ) - } - - render () { - const { title, subtitle, onClose, tabs, headerCloseText, className } = this.props + render() { + const { + title, + subtitle, + onClose, + tabs, + headerCloseText, + className, + } = this.props return (
    + {this.renderHeaderRow()} - { this.renderHeaderRow() } + {title &&
    {title}
    } - { - title && ( -
    - { title } -
    + {subtitle &&
    {subtitle}
    } + + {onClose && headerCloseText ? ( + + ) : ( + onClose && ( +
    onClose()} + /> ) - } + )} - { - subtitle && ( -
    - { subtitle } -
    - ) - } - - { - onClose && headerCloseText - ? - : onClose && ( -
    onClose()} - /> - ) - } - - { this.renderTabs() } + {this.renderTabs()}
    ) } - } diff --git a/ui/app/components/ui/page-container/page-container-header/tests/page-container-header.component.test.js b/ui/app/components/ui/page-container/page-container-header/tests/page-container-header.component.test.js index b544e6f4c..ab035c641 100644 --- a/ui/app/components/ui/page-container/page-container-header/tests/page-container-header.component.test.js +++ b/ui/app/components/ui/page-container/page-container-header/tests/page-container-header.component.test.js @@ -12,7 +12,7 @@ describe('Page Container Header', function () { onBackButtonClick = sinon.spy() onClose = sinon.spy() - wrapper = shallow(( + wrapper = shallow( - )) + />, + ) }) describe('Render Header Row', function () { - it('renders back button', function () { assert.equal(wrapper.find('.page-container__back-button').length, 1) assert.equal(wrapper.find('.page-container__back-button').text(), 'Back') }) it('ensures style prop', function () { - assert.equal(wrapper.find('.page-container__back-button').props().style, style) + assert.equal( + wrapper.find('.page-container__back-button').props().style, + style, + ) }) it('should call back button when click is simulated', function () { @@ -80,5 +82,4 @@ describe('Page Container Header', function () { assert.equal(onClose.callCount, 1) }) }) - }) diff --git a/ui/app/components/ui/page-container/page-container.component.js b/ui/app/components/ui/page-container/page-container.component.js index fd3b2eede..eb1280b3b 100644 --- a/ui/app/components/ui/page-container/page-container.component.js +++ b/ui/app/components/ui/page-container/page-container.component.js @@ -33,11 +33,11 @@ export default class PageContainer extends PureComponent { activeTabIndex: this.props.defaultActiveTabIndex || 0, } - handleTabClick (activeTabIndex) { + handleTabClick(activeTabIndex) { this.setState({ activeTabIndex }) } - renderTabs () { + renderTabs() { const { tabsComponent } = this.props if (!tabsComponent) { @@ -46,18 +46,25 @@ export default class PageContainer extends PureComponent { const numberOfTabs = React.Children.count(tabsComponent.props.children) - return React.Children.map(tabsComponent.props.children, (child, tabIndex) => { - return child && React.cloneElement(child, { - onClick: (index) => this.handleTabClick(index), - tabIndex, - isActive: numberOfTabs > 1 && tabIndex === this.state.activeTabIndex, - key: tabIndex, - className: 'page-container__tab', - }) - }) + return React.Children.map( + tabsComponent.props.children, + (child, tabIndex) => { + return ( + child && + React.cloneElement(child, { + onClick: (index) => this.handleTabClick(index), + tabIndex, + isActive: + numberOfTabs > 1 && tabIndex === this.state.activeTabIndex, + key: tabIndex, + className: 'page-container__tab', + }) + ) + }, + ) } - renderActiveTabContent () { + renderActiveTabContent() { const { tabsComponent } = this.props let { children } = tabsComponent.props children = children.filter((child) => child) @@ -68,7 +75,7 @@ export default class PageContainer extends PureComponent { : children.props.children } - renderContent () { + renderContent() { const { contentComponent, tabsComponent } = this.props if (contentComponent) { @@ -79,7 +86,7 @@ export default class PageContainer extends PureComponent { return null } - render () { + render() { const { title, subtitle, @@ -111,9 +118,7 @@ export default class PageContainer extends PureComponent { headerCloseText={headerCloseText} />
    -
    - { this.renderContent() } -
    +
    {this.renderContent()}
    - { CustomBackground - ? - :
    - } + {CustomBackground ? ( + + ) : ( +
    + )}
    - { showArrow ?
    : null} + {showArrow ?
    : null}

    - { - onBack - ? ( -

    - { subtitle ?

    {subtitle}

    : null } + {subtitle ? ( +

    {subtitle}

    + ) : null}
    - { - children - ? ( -
    - {children} -
    - ) - : null - } - { - footer - ? ( -
    - {footer} -
    - ) - : null - } + {children ? ( +
    + {children} +
    + ) : null} + {footer ? ( +
    + {footer} +
    + ) : null}
    ) @@ -94,7 +85,7 @@ export default class PopoverPortal extends PureComponent { instanceNode = document.createElement('div') - componentDidMount () { + componentDidMount() { if (!this.rootNode) { return } @@ -102,7 +93,7 @@ export default class PopoverPortal extends PureComponent { this.rootNode.appendChild(this.instanceNode) } - componentWillUnmount () { + componentWillUnmount() { if (!this.rootNode) { return } @@ -110,7 +101,7 @@ export default class PopoverPortal extends PureComponent { this.rootNode.removeChild(this.instanceNode) } - render () { + render() { const children = return this.rootNode ? ReactDOM.createPortal(children, this.instanceNode) diff --git a/ui/app/components/ui/popover/popover.stories.js b/ui/app/components/ui/popover/popover.stories.js index 5108e1f96..f81aa69e2 100644 --- a/ui/app/components/ui/popover/popover.stories.js +++ b/ui/app/components/ui/popover/popover.stories.js @@ -27,8 +27,37 @@ export const approve = () => ( footer={} >
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Semper eget duis at tellus at urna condimentum. Posuere urna nec tincidunt praesent semper. Arcu dictum varius duis at. A lacus vestibulum sed arcu. Orci porta non pulvinar neque laoreet suspendisse interdum. Pretium fusce id velit ut. Ut consequat semper viverra nam libero justo laoreet sit. In ante metus dictum at tempor commodo ullamcorper a lacus. Posuere morbi leo urna molestie at elementum eu facilisis sed. Libero enim sed faucibus turpis in eu mi bibendum neque. Amet massa vitae tortor condimentum lacinia quis. Pretium viverra suspendisse potenti nullam ac. Pellentesque elit eget gravida cum sociis natoque penatibus. Proin libero nunc consequat interdum varius sit amet. Est ultricies integer quis auctor elit sed vulputate. Ornare arcu odio ut sem nulla pharetra. Eget nullam non nisi est sit. Leo vel fringilla est ullamcorper eget nulla.

    -

    Mattis pellentesque id nibh tortor id. Commodo sed egestas egestas fringilla phasellus. Semper eget duis at tellus at urna. Tristique nulla aliquet enim tortor at auctor urna nunc. Pellentesque habitant morbi tristique senectus et netus et. Turpis egestas sed tempus urna et pharetra pharetra massa massa. Mi eget mauris pharetra et ultrices neque ornare aenean. Facilisis volutpat est velit egestas dui id ornare arcu odio. Lacus sed turpis tincidunt id aliquet risus feugiat in. Cras tincidunt lobortis feugiat vivamus. Blandit libero volutpat sed cras ornare arcu. Facilisi morbi tempus iaculis urna id volutpat. Risus viverra adipiscing at in tellus. Leo vel orci porta non pulvinar neque. Malesuada fames ac turpis egestas integer. Euismod nisi porta lorem mollis aliquam.

    +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Semper + eget duis at tellus at urna condimentum. Posuere urna nec tincidunt + praesent semper. Arcu dictum varius duis at. A lacus vestibulum sed + arcu. Orci porta non pulvinar neque laoreet suspendisse interdum. + Pretium fusce id velit ut. Ut consequat semper viverra nam libero + justo laoreet sit. In ante metus dictum at tempor commodo ullamcorper + a lacus. Posuere morbi leo urna molestie at elementum eu facilisis + sed. Libero enim sed faucibus turpis in eu mi bibendum neque. Amet + massa vitae tortor condimentum lacinia quis. Pretium viverra + suspendisse potenti nullam ac. Pellentesque elit eget gravida cum + sociis natoque penatibus. Proin libero nunc consequat interdum varius + sit amet. Est ultricies integer quis auctor elit sed vulputate. Ornare + arcu odio ut sem nulla pharetra. Eget nullam non nisi est sit. Leo vel + fringilla est ullamcorper eget nulla. +

    +

    + Mattis pellentesque id nibh tortor id. Commodo sed egestas egestas + fringilla phasellus. Semper eget duis at tellus at urna. Tristique + nulla aliquet enim tortor at auctor urna nunc. Pellentesque habitant + morbi tristique senectus et netus et. Turpis egestas sed tempus urna + et pharetra pharetra massa massa. Mi eget mauris pharetra et ultrices + neque ornare aenean. Facilisis volutpat est velit egestas dui id + ornare arcu odio. Lacus sed turpis tincidunt id aliquet risus feugiat + in. Cras tincidunt lobortis feugiat vivamus. Blandit libero volutpat + sed cras ornare arcu. Facilisi morbi tempus iaculis urna id volutpat. + Risus viverra adipiscing at in tellus. Leo vel orci porta non pulvinar + neque. Malesuada fames ac turpis egestas integer. Euismod nisi porta + lorem mollis aliquam. +

    diff --git a/ui/app/components/ui/pulse-loader/pulse-loader.js b/ui/app/components/ui/pulse-loader/pulse-loader.js index b1cc13731..afc8af89d 100644 --- a/ui/app/components/ui/pulse-loader/pulse-loader.js +++ b/ui/app/components/ui/pulse-loader/pulse-loader.js @@ -1,6 +1,6 @@ import React from 'react' -export default function PulseLoader () { +export default function PulseLoader() { return (
    diff --git a/ui/app/components/ui/pulse-loader/pulse-loader.stories.js b/ui/app/components/ui/pulse-loader/pulse-loader.stories.js index 4823ac604..6adb4f441 100644 --- a/ui/app/components/ui/pulse-loader/pulse-loader.stories.js +++ b/ui/app/components/ui/pulse-loader/pulse-loader.stories.js @@ -5,4 +5,4 @@ export default { title: 'PulseLoader', } -export const common = () => () +export const common = () => diff --git a/ui/app/components/ui/qr-code/qr-code.js b/ui/app/components/ui/qr-code/qr-code.js index c00885341..e81822130 100644 --- a/ui/app/components/ui/qr-code/qr-code.js +++ b/ui/app/components/ui/qr-code/qr-code.js @@ -8,7 +8,7 @@ import { checksumAddress } from '../../../helpers/utils/util' export default connect(mapStateToProps)(QrCodeView) -function mapStateToProps (state) { +function mapStateToProps(state) { return { // Qr code is not fetched from state. 'message' and 'data' props are passed instead. buyView: state.appState.buyView, @@ -16,41 +16,33 @@ function mapStateToProps (state) { } } -function QrCodeView (props) { +function QrCodeView(props) { const { message, data } = props.Qr - const address = `${isHexPrefixed(data) ? 'ethereum:' : ''}${checksumAddress(data)}` + const address = `${isHexPrefixed(data) ? 'ethereum:' : ''}${checksumAddress( + data, + )}` const qrImage = qrCode(4, 'M') qrImage.addData(address) qrImage.make() return (
    - { - Array.isArray(message) - ? ( -
    - {props.Qr.message.map((msg, index) => ( -
    - {msg} -
    - ))} + {Array.isArray(message) ? ( +
    + {props.Qr.message.map((msg, index) => ( +
    + {msg}
    + ))} +
    + ) : ( + message &&
    {message}
    + )} + {props.warning + ? props.warning && ( + {props.warning} ) - : message && ( -
    - {message} -
    - ) - } - { - props.warning - ? (props.warning && ( - - {props.warning} - - )) - : null - } + : null}
    + diff --git a/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js b/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js index de7e54745..242ccb3fd 100644 --- a/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js +++ b/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js @@ -7,7 +7,11 @@ import Identicon from '../identicon' import { checksumAddress, shortenAddress } from '../../../helpers/utils/util' import AccountMismatchWarning from '../account-mismatch-warning/account-mismatch-warning.component' import { useI18nContext } from '../../../hooks/useI18nContext' -import { DEFAULT_VARIANT, CARDS_VARIANT, FLAT_VARIANT } from './sender-to-recipient.constants' +import { + DEFAULT_VARIANT, + CARDS_VARIANT, + FLAT_VARIANT, +} from './sender-to-recipient.constants' const variantHash = { [DEFAULT_VARIANT]: 'sender-to-recipient--default', @@ -15,7 +19,7 @@ const variantHash = { [FLAT_VARIANT]: 'sender-to-recipient--flat', } -function SenderAddress ({ +function SenderAddress({ addressOnly, checksummedSenderAddress, senderName, @@ -27,18 +31,21 @@ function SenderAddress ({ const [addressCopied, setAddressCopied] = useState(false) let tooltipHtml =

    {t('copiedExclamation')}

    if (!addressCopied) { - tooltipHtml = addressOnly - ?

    {t('copyAddress')}

    - : ( -

    - {shortenAddress(checksummedSenderAddress)}
    - {t('copyAddress')} -

    - ) + tooltipHtml = addressOnly ? ( +

    {t('copyAddress')}

    + ) : ( +

    + {shortenAddress(checksummedSenderAddress)} +
    + {t('copyAddress')} +

    + ) } return (
    { setAddressCopied(true) copyToClipboard(checksummedSenderAddress) @@ -49,10 +56,7 @@ function SenderAddress ({ > {!addressOnly && (
    - +
    )} setAddressCopied(false)} >
    - { - addressOnly - ? {`${t('from')}: ${senderName || checksummedSenderAddress}`} - : senderName - } + {addressOnly ? ( + + {`${t('from')}: ${senderName || checksummedSenderAddress}`} + + ) : ( + senderName + )}
    - {warnUserOnAccountMismatch && } + {warnUserOnAccountMismatch && ( + + )}
    ) } @@ -84,7 +92,7 @@ SenderAddress.propTypes = { warnUserOnAccountMismatch: PropTypes.bool, } -function RecipientWithAddress ({ +function RecipientWithAddress({ checksummedRecipientAddress, assetImage, onRecipientClick, @@ -103,7 +111,8 @@ function RecipientWithAddress ({ } else { tooltipHtml = (

    - {shortenAddress(checksummedRecipientAddress)}
    + {shortenAddress(checksummedRecipientAddress)} +
    {t('copyAddress')}

    ) @@ -138,12 +147,13 @@ function RecipientWithAddress ({ onHidden={() => setAddressCopied(false)} >
    - { addressOnly ? `${t('to')}: ` : '' } - { - addressOnly - ? (recipientNickname || recipientEns || checksummedRecipientAddress) - : (recipientNickname || recipientEns || recipientName || t('newContract')) - } + {addressOnly ? `${t('to')}: ` : ''} + {addressOnly + ? recipientNickname || recipientEns || checksummedRecipientAddress + : recipientNickname || + recipientEns || + recipientName || + t('newContract')}
    @@ -160,33 +170,25 @@ RecipientWithAddress.propTypes = { onRecipientClick: PropTypes.func, } -function Arrow ({ variant }) { - return variant === DEFAULT_VARIANT - ? ( -
    -
    - -
    +function Arrow({ variant }) { + return variant === DEFAULT_VARIANT ? ( +
    +
    +
    - ) : ( -
    - -
    - ) +
    + ) : ( +
    + +
    + ) } Arrow.propTypes = { variant: PropTypes.oneOf([DEFAULT_VARIANT, CARDS_VARIANT, FLAT_VARIANT]), } -export default function SenderToRecipient ({ +export default function SenderToRecipient({ senderAddress, addressOnly, assetImage, @@ -215,27 +217,22 @@ export default function SenderToRecipient ({ warnUserOnAccountMismatch={warnUserOnAccountMismatch} /> - {recipientAddress - ? ( - - ) - : ( -
    - { !addressOnly && } -
    - {t('newContract') } -
    -
    - ) - } + {recipientAddress ? ( + + ) : ( +
    + {!addressOnly && } +
    {t('newContract')}
    +
    + )}
    ) } diff --git a/ui/app/components/ui/site-icon/site-icon.js b/ui/app/components/ui/site-icon/site-icon.js index 2ddc9f344..e0a690c6e 100644 --- a/ui/app/components/ui/site-icon/site-icon.js +++ b/ui/app/components/ui/site-icon/site-icon.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import IconBorder from '../icon-border' import IconWithFallback from '../icon-with-fallback' -export default function SiteIcon ({ icon, name, size }) { +export default function SiteIcon({ icon, name, size }) { const iconSize = Math.floor(size * 0.75) return ( diff --git a/ui/app/components/ui/snackbar/snackbar.component.js b/ui/app/components/ui/snackbar/snackbar.component.js index 48b39c59f..c9da15dba 100644 --- a/ui/app/components/ui/snackbar/snackbar.component.js +++ b/ui/app/components/ui/snackbar/snackbar.component.js @@ -3,11 +3,7 @@ import PropTypes from 'prop-types' import classnames from 'classnames' const Snackbar = ({ className = '', content }) => { - return ( -
    - { content } -
    - ) + return
    {content}
    } Snackbar.propTypes = { diff --git a/ui/app/components/ui/spinner/spinner.component.js b/ui/app/components/ui/spinner/spinner.component.js index 4ad2a21fe..4e002bfb2 100644 --- a/ui/app/components/ui/spinner/spinner.component.js +++ b/ui/app/components/ui/spinner/spinner.component.js @@ -4,65 +4,146 @@ import PropTypes from 'prop-types' const Spinner = ({ className = '', color = '#000000' }) => { return (
    - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/ui/app/components/ui/tabs/tab/tab.component.js b/ui/app/components/ui/tabs/tab/tab.component.js index 55f1533b6..02c9c0b9b 100644 --- a/ui/app/components/ui/tabs/tab/tab.component.js +++ b/ui/app/components/ui/tabs/tab/tab.component.js @@ -15,21 +15,17 @@ const Tab = (props) => { return (
  • { event.preventDefault() onClick(tabIndex) }} > - { name } + {name}
  • ) } diff --git a/ui/app/components/ui/tabs/tabs.component.js b/ui/app/components/ui/tabs/tabs.component.js index c524759fc..2f1f7583e 100644 --- a/ui/app/components/ui/tabs/tabs.component.js +++ b/ui/app/components/ui/tabs/tabs.component.js @@ -17,38 +17,47 @@ export default class Tabs extends Component { } state = { - activeTabIndex: Math.max(this._findChildByName(this.props.defaultActiveTabName), 0), + activeTabIndex: Math.max( + this._findChildByName(this.props.defaultActiveTabName), + 0, + ), } - handleTabClick (tabIndex, tabName) { + handleTabClick(tabIndex, tabName) { const { onTabClick } = this.props const { activeTabIndex } = this.state if (tabIndex !== activeTabIndex) { - this.setState({ - activeTabIndex: tabIndex, - }, () => { - if (onTabClick) { - onTabClick(tabName) - } - }) + this.setState( + { + activeTabIndex: tabIndex, + }, + () => { + if (onTabClick) { + onTabClick(tabName) + } + }, + ) } } - renderTabs () { + renderTabs() { const numberOfTabs = React.Children.count(this.props.children) return React.Children.map(this.props.children, (child, index) => { const tabName = child?.props.name - return child && React.cloneElement(child, { - onClick: (idx) => this.handleTabClick(idx, tabName), - tabIndex: index, - isActive: numberOfTabs > 1 && index === this.state.activeTabIndex, - }) + return ( + child && + React.cloneElement(child, { + onClick: (idx) => this.handleTabClick(idx, tabName), + tabIndex: index, + isActive: numberOfTabs > 1 && index === this.state.activeTabIndex, + }) + ) }) } - renderActiveTabContent () { + renderActiveTabContent() { const { children } = this.props const { activeTabIndex } = this.state @@ -64,16 +73,14 @@ export default class Tabs extends Component { : children.props.children } - render () { + render() { const { tabsClassName } = this.props return (
      - { this.renderTabs() } + {this.renderTabs()}
    -
    - { this.renderActiveTabContent() } -
    +
    {this.renderActiveTabContent()}
    ) } @@ -84,7 +91,9 @@ export default class Tabs extends Component { * @returns {number} the index of the child with the given name * @private */ - _findChildByName (name) { - return React.Children.toArray(this.props.children).findIndex((c) => c?.props.name === name) + _findChildByName(name) { + return React.Children.toArray(this.props.children).findIndex( + (c) => c?.props.name === name, + ) } } diff --git a/ui/app/components/ui/tabs/tabs.stories.js b/ui/app/components/ui/tabs/tabs.stories.js index 2cf40736c..f69d38103 100644 --- a/ui/app/components/ui/tabs/tabs.stories.js +++ b/ui/app/components/ui/tabs/tabs.stories.js @@ -7,45 +7,26 @@ export default { title: 'Tabs', } -function renderTab (id) { +function renderTab(id) { return ( - + {text(`Tab ${id} Contents`, `Contents of Tab ${id}`)} ) } export const twoTabs = () => { - return ( - - { - ['A', 'B'] - .map(renderTab) - } - - ) + return {['A', 'B'].map(renderTab)} } export const manyTabs = () => { - return ( - - { - ['A', 'B', 'C', 'D', 'E'] - .map(renderTab) - } - - ) + return {['A', 'B', 'C', 'D', 'E'].map(renderTab)} } export const singleTab = () => { return ( - + {text('Contents', 'Contents of tab')} diff --git a/ui/app/components/ui/text-field/text-field.component.js b/ui/app/components/ui/text-field/text-field.component.js index 558ce1478..88d51d6e6 100644 --- a/ui/app/components/ui/text-field/text-field.component.js +++ b/ui/app/components/ui/text-field/text-field.component.js @@ -109,7 +109,12 @@ const getMaterialThemeInputProps = ({ const getMaterialWhitePaddedThemeInputProps = ({ dir, - classes: { materialWhitePaddedRoot, materialWhitePaddedFocused, materialWhitePaddedInput, materialWhitePaddedUnderline }, + classes: { + materialWhitePaddedRoot, + materialWhitePaddedFocused, + materialWhitePaddedInput, + materialWhitePaddedUnderline, + }, startAdornment, }) => ({ InputProps: { @@ -128,7 +133,16 @@ const getMaterialWhitePaddedThemeInputProps = ({ const getBorderedThemeInputProps = ({ dir, - classes: { formLabel, formLabelFocused, materialError, largeInputLabel, inputLabel, inputRoot, input, inputFocused }, + classes: { + formLabel, + formLabelFocused, + materialError, + largeInputLabel, + inputLabel, + inputRoot, + input, + inputFocused, + }, largeLabel, startAdornment, }) => ({ @@ -156,8 +170,8 @@ const getBorderedThemeInputProps = ({ }) const themeToInputProps = { - 'material': getMaterialThemeInputProps, - 'bordered': getBorderedThemeInputProps, + material: getMaterialThemeInputProps, + bordered: getBorderedThemeInputProps, 'material-white-padded': getMaterialWhitePaddedThemeInputProps, } @@ -170,7 +184,12 @@ const TextField = ({ dir, ...textFieldProps }) => { - const inputProps = themeToInputProps[theme]({ classes, startAdornment, largeLabel, dir }) + const inputProps = themeToInputProps[theme]({ + classes, + startAdornment, + largeLabel, + dir, + }) return ( ( - -) +export const text = () => -export const password = () => ( - -) +export const password = () => export const error = () => ( - + ) export const mascaraText = () => ( - + ) export const materialText = () => ( - + ) export const materialPassword = () => ( - + ) export const materialError = () => ( - + ) diff --git a/ui/app/components/ui/token-balance/token-balance.js b/ui/app/components/ui/token-balance/token-balance.js index e439c2d36..dcb7aaa99 100644 --- a/ui/app/components/ui/token-balance/token-balance.js +++ b/ui/app/components/ui/token-balance/token-balance.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import CurrencyDisplay from '../currency-display' import { useTokenTracker } from '../../../hooks/useTokenTracker' -export default function TokenBalance ({ className, token }) { +export default function TokenBalance({ className, token }) { const { tokensWithBalances } = useTokenTracker([token]) const { string, symbol } = tokensWithBalances[0] || {} diff --git a/ui/app/components/ui/token-currency-display/token-currency-display.component.js b/ui/app/components/ui/token-currency-display/token-currency-display.component.js index b8e46614a..69a314e47 100644 --- a/ui/app/components/ui/token-currency-display/token-currency-display.component.js +++ b/ui/app/components/ui/token-currency-display/token-currency-display.component.js @@ -3,7 +3,12 @@ import PropTypes from 'prop-types' import CurrencyDisplay from '../currency-display' import { useTokenDisplayValue } from '../../../hooks/useTokenDisplayValue' -export default function TokenCurrencyDisplay ({ className, transactionData, token, prefix }) { +export default function TokenCurrencyDisplay({ + className, + transactionData, + token, + prefix, +}) { const displayValue = useTokenDisplayValue(transactionData, token) return ( diff --git a/ui/app/components/ui/token-input/tests/token-input.component.test.js b/ui/app/components/ui/token-input/tests/token-input.component.test.js index a7cda504f..52668a1cc 100644 --- a/ui/app/components/ui/token-input/tests/token-input.component.test.js +++ b/ui/app/components/ui/token-input/tests/token-input.component.test.js @@ -43,8 +43,14 @@ describe('TokenInput Component', function () { assert.ok(wrapper) assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') - assert.equal(wrapper.find('.currency-input__conversion-component').length, 1) - assert.equal(wrapper.find('.currency-input__conversion-component').text(), 'translate noConversionRateAvailable') + assert.equal( + wrapper.find('.currency-input__conversion-component').length, + 1, + ) + assert.equal( + wrapper.find('.currency-input__conversion-component').text(), + 'translate noConversionRateAvailable', + ) }) it('should render properly with tokenExchangeRates', function () { @@ -145,7 +151,10 @@ describe('TokenInput Component', function () { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$462.12USD', + ) }) it('should render properly with a token value for fiat, but hideConversion is true', function () { @@ -186,7 +195,10 @@ describe('TokenInput Component', function () { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-input__conversion-component').text(), 'translate noConversionRateAvailable') + assert.equal( + wrapper.find('.currency-input__conversion-component').text(), + 'translate noConversionRateAvailable', + ) }) }) @@ -270,14 +282,20 @@ describe('TokenInput Component', function () { const tokenInputInstance = wrapper.find(TokenInput).at(0).instance() assert.equal(tokenInputInstance.state.decimalValue, 0) assert.equal(tokenInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$0.00USD', + ) const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('2710')) - assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD') + assert.equal( + wrapper.find('.currency-display-component').text(), + '$462.12USD', + ) assert.equal(tokenInputInstance.state.decimalValue, 1) assert.equal(tokenInputInstance.state.hexValue, '2710') }) diff --git a/ui/app/components/ui/token-input/token-input.component.js b/ui/app/components/ui/token-input/token-input.component.js index 785601171..c0b67c4d7 100644 --- a/ui/app/components/ui/token-input/token-input.component.js +++ b/ui/app/components/ui/token-input/token-input.component.js @@ -4,7 +4,10 @@ import ethUtil from 'ethereumjs-util' import UnitInput from '../unit-input' import CurrencyDisplay from '../currency-display' import { getWeiHexFromDecimalValue } from '../../../helpers/utils/conversions.util' -import { conversionUtil, multiplyCurrencies } from '../../../helpers/utils/conversion-util' +import { + conversionUtil, + multiplyCurrencies, +} from '../../../helpers/utils/conversion-util' import { ETH } from '../../../helpers/constants/common' /** @@ -31,7 +34,7 @@ export default class TokenInput extends PureComponent { tokenExchangeRates: PropTypes.object, } - constructor (props) { + constructor(props) { super(props) const { value: hexValue } = props @@ -43,18 +46,21 @@ export default class TokenInput extends PureComponent { } } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { value: prevPropsHexValue } = prevProps const { value: propsHexValue } = this.props const { hexValue: stateHexValue } = this.state - if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) { + if ( + prevPropsHexValue !== propsHexValue && + propsHexValue !== stateHexValue + ) { const decimalValue = this.getValue(this.props) this.setState({ hexValue: propsHexValue, decimalValue }) } } - getValue (props) { + getValue(props) { const { value: hexValue, token: { decimals, symbol } = {} } = props const multiplier = Math.pow(10, Number(decimals || 0)) @@ -73,14 +79,22 @@ export default class TokenInput extends PureComponent { const { token: { decimals } = {}, onChange } = this.props const multiplier = Math.pow(10, Number(decimals || 0)) - const hexValue = multiplyCurrencies(decimalValue || 0, multiplier, { toNumericBase: 'hex' }) + const hexValue = multiplyCurrencies(decimalValue || 0, multiplier, { + toNumericBase: 'hex', + }) this.setState({ hexValue, decimalValue }) onChange(hexValue) } - renderConversionComponent () { - const { tokenExchangeRates, showFiat, currentCurrency, hideConversion, token } = this.props + renderConversionComponent() { + const { + tokenExchangeRates, + showFiat, + currentCurrency, + hideConversion, + token, + } = this.props const { decimalValue } = this.state const tokenExchangeRate = tokenExchangeRates?.[token.address] || 0 @@ -89,7 +103,7 @@ export default class TokenInput extends PureComponent { if (hideConversion) { return (
    - { this.context.t('noConversionRateAvailable') } + {this.context.t('noConversionRateAvailable')}
    ) } @@ -104,29 +118,28 @@ export default class TokenInput extends PureComponent { numberOfDecimals = 6 } - const decimalEthValue = (decimalValue * tokenExchangeRate) || 0 + const decimalEthValue = decimalValue * tokenExchangeRate || 0 const hexWeiValue = getWeiHexFromDecimalValue({ value: decimalEthValue, fromCurrency: ETH, fromDenomination: ETH, }) - return tokenExchangeRate - ? ( - - ) : ( -
    - { this.context.t('noConversionRateAvailable') } -
    - ) + return tokenExchangeRate ? ( + + ) : ( +
    + {this.context.t('noConversionRateAvailable')} +
    + ) } - render () { + render() { const { token, ...restProps } = this.props const { decimalValue } = this.state @@ -137,7 +150,7 @@ export default class TokenInput extends PureComponent { onChange={this.handleChange} value={decimalValue} > - { this.renderConversionComponent() } + {this.renderConversionComponent()} ) } diff --git a/ui/app/components/ui/token-input/token-input.container.js b/ui/app/components/ui/token-input/token-input.container.js index f20670d31..eac410000 100644 --- a/ui/app/components/ui/token-input/token-input.container.js +++ b/ui/app/components/ui/token-input/token-input.container.js @@ -8,14 +8,16 @@ import { import TokenInput from './token-input.component' const mapStateToProps = (state) => { - const { metamask: { currentCurrency } } = state + const { + metamask: { currentCurrency }, + } = state const { showFiatInTestnets } = getPreferences(state) const isMainnet = getIsMainnet(state) return { currentCurrency, tokenExchangeRates: getTokenExchangeRates(state), - hideConversion: (!isMainnet && !showFiatInTestnets), + hideConversion: !isMainnet && !showFiatInTestnets, } } diff --git a/ui/app/components/ui/tooltip/tooltip.js b/ui/app/components/ui/tooltip/tooltip.js index e6b5726d4..b9319f166 100644 --- a/ui/app/components/ui/tooltip/tooltip.js +++ b/ui/app/components/ui/tooltip/tooltip.js @@ -28,15 +28,8 @@ export default class Tooltip extends PureComponent { interactive: PropTypes.bool, offset: PropTypes.number, onHidden: PropTypes.func, - position: PropTypes.oneOf([ - 'top', - 'right', - 'bottom', - 'left', - ]), - size: PropTypes.oneOf([ - 'small', 'regular', 'big', - ]), + position: PropTypes.oneOf(['top', 'right', 'bottom', 'left']), + size: PropTypes.oneOf(['small', 'regular', 'big']), title: PropTypes.string, trigger: PropTypes.any, wrapperClassName: PropTypes.string, @@ -44,7 +37,7 @@ export default class Tooltip extends PureComponent { theme: PropTypes.string, } - render () { + render() { const { arrow, children, @@ -64,11 +57,7 @@ export default class Tooltip extends PureComponent { } = this.props if (!title && !html) { - return ( -
    - {children} -
    - ) + return
    {children}
    } return ( diff --git a/ui/app/components/ui/unit-input/tests/unit-input.component.test.js b/ui/app/components/ui/unit-input/tests/unit-input.component.test.js index 0b92fc5a0..c759f496f 100644 --- a/ui/app/components/ui/unit-input/tests/unit-input.component.test.js +++ b/ui/app/components/ui/unit-input/tests/unit-input.component.test.js @@ -7,20 +7,14 @@ import UnitInput from '../unit-input.component' describe('UnitInput Component', function () { describe('rendering', function () { it('should render properly without a suffix', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find('.unit-input__suffix').length, 0) }) it('should render properly with a suffix', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find('.unit-input__suffix').length, 1) @@ -30,9 +24,7 @@ describe('UnitInput Component', function () { it('should render properly with a child component', function () { const wrapper = shallow( -
    - TESTCOMPONENT -
    +
    TESTCOMPONENT
    , ) @@ -42,11 +34,7 @@ describe('UnitInput Component', function () { }) it('should render with an error class when props.error === true', function () { - const wrapper = shallow( - , - ) + const wrapper = shallow() assert.ok(wrapper) assert.equal(wrapper.find('.unit-input--error').length, 1) @@ -63,9 +51,7 @@ describe('UnitInput Component', function () { }) it('should focus the input on component click', function () { - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) const handleFocusSpy = sinon.spy(wrapper.instance(), 'handleFocus') @@ -77,11 +63,7 @@ describe('UnitInput Component', function () { }) it('should call onChange on input changes with the value', function () { - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) assert.equal(handleChangeSpy.callCount, 0) @@ -93,22 +75,14 @@ describe('UnitInput Component', function () { }) it('should set the component state value with props.value', function () { - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) assert.equal(wrapper.state('value'), 123) }) it('should update the component state value with props.value', function () { - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) assert.equal(handleChangeSpy.callCount, 0) diff --git a/ui/app/components/ui/unit-input/unit-input.component.js b/ui/app/components/ui/unit-input/unit-input.component.js index 6a9b76e7c..7e084a3bb 100644 --- a/ui/app/components/ui/unit-input/unit-input.component.js +++ b/ui/app/components/ui/unit-input/unit-input.component.js @@ -29,7 +29,7 @@ export default class UnitInput extends PureComponent { value: this.props.value, } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { value: prevPropsValue } = prevProps const { value: propsValue } = this.props const { value: stateValue } = this.state @@ -55,20 +55,31 @@ export default class UnitInput extends PureComponent { this.props.onChange(value) } - getInputWidth (value) { + getInputWidth(value) { const valueString = String(value) const valueLength = valueString.length || 1 const decimalPointDeficit = valueString.match(/\./u) ? -0.5 : 0 return `${valueLength + decimalPointDeficit + 0.5}ch` } - render () { - const { error, placeholder, suffix, actionComponent, children, maxModeOn } = this.props + render() { + const { + error, + placeholder, + suffix, + actionComponent, + children, + maxModeOn, + } = this.props const { value } = this.state return (
    @@ -76,7 +87,9 @@ export default class UnitInput extends PureComponent { - { - suffix && ( -
    - { suffix } -
    - ) - } + {suffix &&
    {suffix}
    }
    - { children } + {children}
    {actionComponent}
    diff --git a/ui/app/components/ui/url-icon/url-icon.js b/ui/app/components/ui/url-icon/url-icon.js index 197f9d855..115eb5fe1 100644 --- a/ui/app/components/ui/url-icon/url-icon.js +++ b/ui/app/components/ui/url-icon/url-icon.js @@ -3,12 +3,7 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import IconWithFallback from '../icon-with-fallback' -export default function UrlIcon ({ - url, - className, - name, - fallbackClassName, -}) { +export default function UrlIcon({ url, className, name, fallbackClassName }) { return ( `[${key}]`) @@ -13,17 +16,12 @@ export const I18nProvider = (props) => { const en = useSelector(getEnLocaleMessages) const t = useMemo(() => { - return (key, ...args) => ( + return (key, ...args) => getMessage(currentLocale, current, key, ...args) || getMessage(currentLocale, en, key, ...args) - ) }, [currentLocale, current, en]) - return ( - - { props.children } - - ) + return {props.children} } I18nProvider.propTypes = { @@ -49,13 +47,13 @@ export class LegacyI18nProvider extends Component { t: PropTypes.func, } - getChildContext () { + getChildContext() { return { t: this.context, } } - render () { + render() { return this.props.children } } diff --git a/ui/app/contexts/metametrics.js b/ui/app/contexts/metametrics.js index eb0c8e476..32969827f 100644 --- a/ui/app/contexts/metametrics.js +++ b/ui/app/contexts/metametrics.js @@ -1,4 +1,11 @@ -import React, { Component, createContext, useEffect, useCallback, useState, useMemo } from 'react' +import React, { + Component, + createContext, + useEffect, + useCallback, + useState, + useMemo, +} from 'react' import { useSelector } from 'react-redux' import PropTypes from 'prop-types' import { useHistory } from 'react-router-dom' @@ -12,20 +19,20 @@ import { getCurrentChainId, } from '../selectors/selectors' import { getSendToken } from '../selectors/send' -import { - txDataSelector, -} from '../selectors/confirm-transaction' +import { txDataSelector } from '../selectors/confirm-transaction' import { getEnvironmentType } from '../../../app/scripts/lib/util' import { getTrackMetaMetricsEvent } from '../../../shared/modules/metametrics' import { getCurrentLocale } from '../ducks/metamask/metamask' export const MetaMetricsContext = createContext(() => { captureException( - Error(`MetaMetrics context function was called from a react node that is not a descendant of a MetaMetrics context provider`), + Error( + `MetaMetrics context function was called from a react node that is not a descendant of a MetaMetrics context provider`, + ), ) }) -export function MetaMetricsProvider ({ children }) { +export function MetaMetricsProvider({ children }) { const txData = useSelector(txDataSelector) || {} const network = useSelector(getCurrentNetworkId) const environmentType = getEnvironmentType() @@ -35,23 +42,29 @@ export function MetaMetricsProvider ({ children }) { const accountType = useSelector(getAccountType) const confirmTransactionOrigin = txData.origin const metaMetricsId = useSelector((state) => state.metamask.metaMetricsId) - const participateInMetaMetrics = useSelector((state) => state.metamask.participateInMetaMetrics) - const metaMetricsSendCount = useSelector((state) => state.metamask.metaMetricsSendCount) + const participateInMetaMetrics = useSelector( + (state) => state.metamask.participateInMetaMetrics, + ) + const metaMetricsSendCount = useSelector( + (state) => state.metamask.metaMetricsSendCount, + ) const numberOfTokens = useSelector(getNumberOfTokens) const numberOfAccounts = useSelector(getNumberOfAccounts) const history = useHistory() const [state, setState] = useState(() => ({ - currentPath: (new URL(window.location.href)).pathname, + currentPath: new URL(window.location.href).pathname, previousPath: '', })) const { currentPath } = state useEffect(() => { - const unlisten = history.listen(() => setState((prevState) => ({ - currentPath: (new URL(window.location.href)).pathname, - previousPath: prevState.currentPath, - }))) + const unlisten = history.listen(() => + setState((prevState) => ({ + currentPath: new URL(window.location.href).pathname, + previousPath: prevState.currentPath, + })), + ) // remove this listener if the component is no longer mounted return unlisten }, [history]) @@ -63,7 +76,9 @@ export function MetaMetricsProvider ({ children }) { * @returns undefined */ const trackEvent = useMemo(() => { - const referrer = confirmTransactionOrigin ? { url: confirmTransactionOrigin } : undefined + const referrer = confirmTransactionOrigin + ? { url: confirmTransactionOrigin } + : undefined const page = { path: currentPath, } @@ -80,41 +95,51 @@ export function MetaMetricsProvider ({ children }) { metaMetricsId, metaMetricsSendCount, })) - }, [network, chainId, locale, environmentType, participateInMetaMetrics, currentPath, confirmTransactionOrigin, metaMetricsId, metaMetricsSendCount]) - - const metricsEvent = useCallback((config = {}, overrides = {}) => { - const { eventOpts = {} } = config - - return trackEvent({ - event: eventOpts.name, - category: eventOpts.category, - isOptIn: config.isOptIn, - excludeMetaMetricsId: eventOpts.excludeMetaMetricsId ?? overrides.excludeMetaMetricsId ?? false, - metaMetricsId: config.metaMetricsId, - matomoEvent: true, - properties: { - action: eventOpts.action, - number_of_tokens: numberOfTokens, - number_of_accounts: numberOfAccounts, - active_currency: activeCurrency, - account_type: accountType, - is_new_visit: config.is_new_visit, - // the properties coming from this key will not match our standards for - // snake_case on properties, and they may be redundant and/or not in the - // proper location (origin not as a referrer, for example). This is a temporary - // solution to not lose data, and the entire event system will be reworked in - // forthcoming PRs to deprecate the old Matomo events in favor of the new schema. - ...config.customVariables, - }, - }) }, [ - accountType, - activeCurrency, - numberOfTokens, - numberOfAccounts, - trackEvent, + network, + chainId, + locale, + environmentType, + participateInMetaMetrics, + currentPath, + confirmTransactionOrigin, + metaMetricsId, + metaMetricsSendCount, ]) + const metricsEvent = useCallback( + (config = {}, overrides = {}) => { + const { eventOpts = {} } = config + + return trackEvent({ + event: eventOpts.name, + category: eventOpts.category, + isOptIn: config.isOptIn, + excludeMetaMetricsId: + eventOpts.excludeMetaMetricsId ?? + overrides.excludeMetaMetricsId ?? + false, + metaMetricsId: config.metaMetricsId, + matomoEvent: true, + properties: { + action: eventOpts.action, + number_of_tokens: numberOfTokens, + number_of_accounts: numberOfAccounts, + active_currency: activeCurrency, + account_type: accountType, + is_new_visit: config.is_new_visit, + // the properties coming from this key will not match our standards for + // snake_case on properties, and they may be redundant and/or not in the + // proper location (origin not as a referrer, for example). This is a temporary + // solution to not lose data, and the entire event system will be reworked in + // forthcoming PRs to deprecate the old Matomo events in favor of the new schema. + ...config.customVariables, + }, + }) + }, + [accountType, activeCurrency, numberOfTokens, numberOfAccounts, trackEvent], + ) + return ( {children} @@ -139,13 +164,13 @@ export class LegacyMetaMetricsProvider extends Component { metricsEvent: PropTypes.func, } - getChildContext () { + getChildContext() { return { metricsEvent: this.context, } } - render () { + render() { return this.props.children } } diff --git a/ui/app/contexts/metametrics.new.js b/ui/app/contexts/metametrics.new.js index 2afbb712a..724318bdd 100644 --- a/ui/app/contexts/metametrics.new.js +++ b/ui/app/contexts/metametrics.new.js @@ -3,7 +3,13 @@ * MetaMetrics is our own brand, and should remain aptly named regardless of the underlying * metrics system. This file implements Segment analytics tracking. */ -import React, { useRef, Component, createContext, useEffect, useMemo } from 'react' +import React, { + useRef, + Component, + createContext, + useEffect, + useMemo, +} from 'react' import { useSelector } from 'react-redux' import PropTypes from 'prop-types' import { useLocation, matchPath, useRouteMatch } from 'react-router-dom' @@ -14,31 +20,49 @@ import { omit } from 'lodash' import { getEnvironmentType } from '../../../app/scripts/lib/util' import { PATH_NAME_MAP } from '../helpers/constants/routes' import { getCurrentLocale } from '../ducks/metamask/metamask' -import { getCurrentChainId, getMetricsNetworkIdentifier, txDataSelector } from '../selectors' -import { getTrackMetaMetricsEvent, METAMETRICS_ANONYMOUS_ID, segment } from '../../../shared/modules/metametrics' +import { + getCurrentChainId, + getMetricsNetworkIdentifier, + txDataSelector, +} from '../selectors' +import { + getTrackMetaMetricsEvent, + METAMETRICS_ANONYMOUS_ID, + segment, +} from '../../../shared/modules/metametrics' export const MetaMetricsContext = createContext(() => { captureException( - Error(`MetaMetrics context function was called from a react node that is not a descendant of a MetaMetrics context provider`), + Error( + `MetaMetrics context function was called from a react node that is not a descendant of a MetaMetrics context provider`, + ), ) }) const PATHS_TO_CHECK = Object.keys(PATH_NAME_MAP) -function useSegmentContext () { - const match = useRouteMatch({ path: PATHS_TO_CHECK, exact: true, strict: true }) +function useSegmentContext() { + const match = useRouteMatch({ + path: PATHS_TO_CHECK, + exact: true, + strict: true, + }) const txData = useSelector(txDataSelector) || {} const confirmTransactionOrigin = txData.origin - const referrer = confirmTransactionOrigin ? { - url: confirmTransactionOrigin, - } : undefined + const referrer = confirmTransactionOrigin + ? { + url: confirmTransactionOrigin, + } + : undefined - const page = match ? { - path: match.path, - title: PATH_NAME_MAP[match.path], - url: match.path, - } : undefined + const page = match + ? { + path: match.path, + title: PATH_NAME_MAP[match.path], + url: match.path, + } + : undefined return { page, @@ -46,10 +70,14 @@ function useSegmentContext () { } } -export function MetaMetricsProvider ({ children }) { +export function MetaMetricsProvider({ children }) { const metaMetricsId = useSelector((state) => state.metamask.metaMetricsId) - const participateInMetaMetrics = useSelector((state) => state.metamask.participateInMetaMetrics) - const metaMetricsSendCount = useSelector((state) => state.metamask.metaMetricsSendCount) + const participateInMetaMetrics = useSelector( + (state) => state.metamask.participateInMetaMetrics, + ) + const metaMetricsSendCount = useSelector( + (state) => state.metamask.metaMetricsSendCount, + ) const locale = useSelector(getCurrentLocale) const location = useLocation() const context = useSegmentContext() @@ -73,7 +101,15 @@ export function MetaMetricsProvider ({ children }) { metaMetricsId, metaMetricsSendCount, })) - }, [network, participateInMetaMetrics, locale, metaMetricsId, metaMetricsSendCount, chainId, context]) + }, [ + network, + participateInMetaMetrics, + locale, + metaMetricsId, + metaMetricsSendCount, + chainId, + context, + ]) // Used to prevent double tracking page calls const previousMatch = useRef() @@ -87,13 +123,18 @@ export function MetaMetricsProvider ({ children }) { useEffect(() => { const environmentType = getEnvironmentType() if ( - (participateInMetaMetrics === null && location.pathname.startsWith('/initialize')) || + (participateInMetaMetrics === null && + location.pathname.startsWith('/initialize')) || participateInMetaMetrics ) { // Events that happen during initialization before the user opts into MetaMetrics will be anonymous const idTrait = metaMetricsId ? 'userId' : 'anonymousId' const idValue = metaMetricsId ?? METAMETRICS_ANONYMOUS_ID - const match = matchPath(location.pathname, { path: PATHS_TO_CHECK, exact: true, strict: true }) + const match = matchPath(location.pathname, { + path: PATHS_TO_CHECK, + exact: true, + strict: true, + }) // Start by checking for a missing match route. If this falls through to the else if, then we know we // have a matched route for tracking. if (!match) { @@ -109,7 +150,11 @@ export function MetaMetricsProvider ({ children }) { } } else if ( previousMatch.current !== match.path && - !(environmentType === 'notification' && match.path === '/' && previousMatch.current === undefined) + !( + environmentType === 'notification' && + match.path === '/' && + previousMatch.current === undefined + ) ) { // When a notification window is open by a Dapp we do not want to track the initial home route load that can // sometimes happen. To handle this we keep track of the previousMatch, and we skip the event track in the event @@ -160,13 +205,13 @@ export class LegacyMetaMetricsProvider extends Component { trackEvent: PropTypes.func, } - getChildContext () { + getChildContext() { return { trackEvent: this.context, } } - render () { + render() { return this.props.children } } diff --git a/ui/app/ducks/alerts/invalid-custom-network.js b/ui/app/ducks/alerts/invalid-custom-network.js index 62e06f14c..aa7ba3cdb 100644 --- a/ui/app/ducks/alerts/invalid-custom-network.js +++ b/ui/app/ducks/alerts/invalid-custom-network.js @@ -43,9 +43,6 @@ export const alertIsOpen = (state) => state[name].state !== ALERT_STATE.CLOSED // Actions / action-creators -const { - openAlert, - dismissAlert, -} = actions +const { openAlert, dismissAlert } = actions export { openAlert, dismissAlert } diff --git a/ui/app/ducks/alerts/unconnected-account.js b/ui/app/ducks/alerts/unconnected-account.js index 9b150dc71..58ca9a569 100644 --- a/ui/app/ducks/alerts/unconnected-account.js +++ b/ui/app/ducks/alerts/unconnected-account.js @@ -8,10 +8,7 @@ import { setAlertEnabledness, setSelectedAddress, } from '../../store/actions' -import { - getOriginOfCurrentTab, - getSelectedAddress, -} from '../../selectors' +import { getOriginOfCurrentTab, getSelectedAddress } from '../../selectors' import { ALERT_STATE } from './enums' // Constants diff --git a/ui/app/ducks/app/app.js b/ui/app/ducks/app/app.js index 2b905a1ac..913142761 100644 --- a/ui/app/ducks/app/app.js +++ b/ui/app/ducks/app/app.js @@ -3,7 +3,7 @@ import * as actionConstants from '../../store/actionConstants' // actionConstants const SET_THREEBOX_LAST_UPDATED = 'metamask/app/SET_THREEBOX_LAST_UPDATED' -export default function reduceApp (state = {}, action) { +export default function reduceApp(state = {}, action) { // default state const appState = { shouldClose: false, @@ -161,7 +161,7 @@ export default function reduceApp (state = {}, action) { warning: null, } - // accounts + // accounts case actionConstants.GO_HOME: return { @@ -177,7 +177,9 @@ export default function reduceApp (state = {}, action) { case actionConstants.SHOW_ACCOUNT_DETAIL: return { ...appState, - forgottenPassword: appState.forgottenPassword ? !appState.forgottenPassword : null, + forgottenPassword: appState.forgottenPassword + ? !appState.forgottenPassword + : null, accountDetail: { subview: 'transactions', accountExport: 'none', @@ -366,7 +368,7 @@ export default function reduceApp (state = {}, action) { } // Action Creators -export function setThreeBoxLastUpdated (lastUpdated) { +export function setThreeBoxLastUpdated(lastUpdated) { return { type: SET_THREEBOX_LAST_UPDATED, value: lastUpdated, diff --git a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js index b62110fdc..66fc445d7 100644 --- a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js +++ b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js @@ -16,10 +16,7 @@ import { hexGreaterThan, } from '../../helpers/utils/confirm-tx.util' -import { - getTokenData, - sumHexes, -} from '../../helpers/utils/transactions.util' +import { getTokenData, sumHexes } from '../../helpers/utils/transactions.util' import { conversionUtil } from '../../helpers/utils/conversion-util' @@ -33,7 +30,9 @@ const CLEAR_TOKEN_DATA = createActionType('CLEAR_TOKEN_DATA') const UPDATE_METHOD_DATA = createActionType('UPDATE_METHOD_DATA') const CLEAR_METHOD_DATA = createActionType('CLEAR_METHOD_DATA') const CLEAR_CONFIRM_TRANSACTION = createActionType('CLEAR_CONFIRM_TRANSACTION') -const UPDATE_TRANSACTION_AMOUNTS = createActionType('UPDATE_TRANSACTION_AMOUNTS') +const UPDATE_TRANSACTION_AMOUNTS = createActionType( + 'UPDATE_TRANSACTION_AMOUNTS', +) const UPDATE_TRANSACTION_FEES = createActionType('UPDATE_TRANSACTION_FEES') const UPDATE_TRANSACTION_TOTALS = createActionType('UPDATE_TRANSACTION_TOTALS') const UPDATE_TOKEN_PROPS = createActionType('UPDATE_TOKEN_PROPS') @@ -66,7 +65,7 @@ const initState = { } // Reducer -export default function reducer (state = initState, action = {}) { +export default function reducer(state = initState, action = {}) { switch (action.type) { case UPDATE_TX_DATA: return { @@ -105,16 +104,27 @@ export default function reducer (state = initState, action = {}) { methodData: {}, } case UPDATE_TRANSACTION_AMOUNTS: { - const { fiatTransactionAmount, ethTransactionAmount, hexTransactionAmount } = action.payload + const { + fiatTransactionAmount, + ethTransactionAmount, + hexTransactionAmount, + } = action.payload return { ...state, - fiatTransactionAmount: fiatTransactionAmount || state.fiatTransactionAmount, - ethTransactionAmount: ethTransactionAmount || state.ethTransactionAmount, - hexTransactionAmount: hexTransactionAmount || state.hexTransactionAmount, + fiatTransactionAmount: + fiatTransactionAmount || state.fiatTransactionAmount, + ethTransactionAmount: + ethTransactionAmount || state.ethTransactionAmount, + hexTransactionAmount: + hexTransactionAmount || state.hexTransactionAmount, } } case UPDATE_TRANSACTION_FEES: { - const { fiatTransactionFee, ethTransactionFee, hexTransactionFee } = action.payload + const { + fiatTransactionFee, + ethTransactionFee, + hexTransactionFee, + } = action.payload return { ...state, fiatTransactionFee: fiatTransactionFee || state.fiatTransactionFee, @@ -123,10 +133,15 @@ export default function reducer (state = initState, action = {}) { } } case UPDATE_TRANSACTION_TOTALS: { - const { fiatTransactionTotal, ethTransactionTotal, hexTransactionTotal } = action.payload + const { + fiatTransactionTotal, + ethTransactionTotal, + hexTransactionTotal, + } = action.payload return { ...state, - fiatTransactionTotal: fiatTransactionTotal || state.fiatTransactionTotal, + fiatTransactionTotal: + fiatTransactionTotal || state.fiatTransactionTotal, ethTransactionTotal: ethTransactionTotal || state.ethTransactionTotal, hexTransactionTotal: hexTransactionTotal || state.hexTransactionTotal, } @@ -170,96 +185,98 @@ export default function reducer (state = initState, action = {}) { } // Action Creators -export function updateTxData (txData) { +export function updateTxData(txData) { return { type: UPDATE_TX_DATA, payload: txData, } } -export function clearTxData () { +export function clearTxData() { return { type: CLEAR_TX_DATA, } } -export function updateTokenData (tokenData) { +export function updateTokenData(tokenData) { return { type: UPDATE_TOKEN_DATA, payload: tokenData, } } -export function clearTokenData () { +export function clearTokenData() { return { type: CLEAR_TOKEN_DATA, } } -export function updateMethodData (methodData) { +export function updateMethodData(methodData) { return { type: UPDATE_METHOD_DATA, payload: methodData, } } -export function clearMethodData () { +export function clearMethodData() { return { type: CLEAR_METHOD_DATA, } } -export function updateTransactionAmounts (amounts) { +export function updateTransactionAmounts(amounts) { return { type: UPDATE_TRANSACTION_AMOUNTS, payload: amounts, } } -export function updateTransactionFees (fees) { +export function updateTransactionFees(fees) { return { type: UPDATE_TRANSACTION_FEES, payload: fees, } } -export function updateTransactionTotals (totals) { +export function updateTransactionTotals(totals) { return { type: UPDATE_TRANSACTION_TOTALS, payload: totals, } } -export function updateTokenProps (tokenProps) { +export function updateTokenProps(tokenProps) { return { type: UPDATE_TOKEN_PROPS, payload: tokenProps, } } -export function updateNonce (nonce) { +export function updateNonce(nonce) { return { type: UPDATE_NONCE, payload: nonce, } } -export function updateToSmartContract (toSmartContract) { +export function updateToSmartContract(toSmartContract) { return { type: UPDATE_TO_SMART_CONTRACT, payload: toSmartContract, } } -export function setFetchingData (isFetching) { +export function setFetchingData(isFetching) { return { type: isFetching ? FETCH_DATA_START : FETCH_DATA_END, } } -export function updateGasAndCalculate ({ gasLimit, gasPrice }) { +export function updateGasAndCalculate({ gasLimit, gasPrice }) { return (dispatch, getState) => { - const { confirmTransaction: { txData } } = getState() + const { + confirmTransaction: { txData }, + } = getState() const newTxData = { ...txData, txParams: { @@ -273,13 +290,16 @@ export function updateGasAndCalculate ({ gasLimit, gasPrice }) { } } -function increaseFromLastGasPrice (txData) { +function increaseFromLastGasPrice(txData) { const { lastGasPrice, txParams: { gasPrice: previousGasPrice } = {} } = txData // Set the minimum to a 10% increase from the lastGasPrice. const minimumGasPrice = increaseLastGasPrice(lastGasPrice) const gasPriceBelowMinimum = hexGreaterThan(minimumGasPrice, previousGasPrice) - const gasPrice = (!previousGasPrice || gasPriceBelowMinimum) ? minimumGasPrice : previousGasPrice + const gasPrice = + !previousGasPrice || gasPriceBelowMinimum + ? minimumGasPrice + : previousGasPrice return { ...txData, @@ -290,7 +310,7 @@ function increaseFromLastGasPrice (txData) { } } -export function updateTxDataAndCalculate (txData) { +export function updateTxDataAndCalculate(txData) { return (dispatch, getState) => { const state = getState() const currentCurrency = currentCurrencySelector(state) @@ -299,20 +319,32 @@ export function updateTxDataAndCalculate (txData) { dispatch(updateTxData(txData)) - const { txParams: { value = '0x0', gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData + const { + txParams: { value = '0x0', gas: gasLimit = '0x0', gasPrice = '0x0' } = {}, + } = txData const fiatTransactionAmount = getValueFromWeiHex({ - value, fromCurrency: nativeCurrency, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, + value, + fromCurrency: nativeCurrency, + toCurrency: currentCurrency, + conversionRate, + numberOfDecimals: 2, }) const ethTransactionAmount = getValueFromWeiHex({ - value, fromCurrency: nativeCurrency, toCurrency: nativeCurrency, conversionRate, numberOfDecimals: 6, + value, + fromCurrency: nativeCurrency, + toCurrency: nativeCurrency, + conversionRate, + numberOfDecimals: 6, }) - dispatch(updateTransactionAmounts({ - fiatTransactionAmount, - ethTransactionAmount, - hexTransactionAmount: value, - })) + dispatch( + updateTransactionAmounts({ + fiatTransactionAmount, + ethTransactionAmount, + hexTransactionAmount: value, + }), + ) const hexTransactionFee = getHexGasTotal({ gasLimit, gasPrice }) @@ -331,24 +363,37 @@ export function updateTxDataAndCalculate (txData) { conversionRate, }) - dispatch(updateTransactionFees({ fiatTransactionFee, ethTransactionFee, hexTransactionFee })) + dispatch( + updateTransactionFees({ + fiatTransactionFee, + ethTransactionFee, + hexTransactionFee, + }), + ) - const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount) + const fiatTransactionTotal = addFiat( + fiatTransactionFee, + fiatTransactionAmount, + ) const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount) const hexTransactionTotal = sumHexes(value, hexTransactionFee) - dispatch(updateTransactionTotals({ - fiatTransactionTotal, - ethTransactionTotal, - hexTransactionTotal, - })) + dispatch( + updateTransactionTotals({ + fiatTransactionTotal, + ethTransactionTotal, + hexTransactionTotal, + }), + ) } } -export function setTransactionToConfirm (transactionId) { +export function setTransactionToConfirm(transactionId) { return (dispatch, getState) => { const state = getState() - const unconfirmedTransactionsHash = unconfirmedTransactionsHashSelector(state) + const unconfirmedTransactionsHash = unconfirmedTransactionsHashSelector( + state, + ) const transaction = unconfirmedTransactionsHash[transactionId] if (!transaction) { @@ -358,7 +403,9 @@ export function setTransactionToConfirm (transactionId) { if (transaction.txParams) { const { lastGasPrice } = transaction - const txData = lastGasPrice ? increaseFromLastGasPrice(transaction) : transaction + const txData = lastGasPrice + ? increaseFromLastGasPrice(transaction) + : transaction dispatch(updateTxDataAndCalculate(txData)) const { txParams } = transaction @@ -384,7 +431,7 @@ export function setTransactionToConfirm (transactionId) { } } -export function clearConfirmTransaction () { +export function clearConfirmTransaction() { return { type: CLEAR_CONFIRM_TRANSACTION, } diff --git a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js index 60ada9797..441fb8563 100644 --- a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js +++ b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js @@ -33,15 +33,20 @@ const UPDATE_TOKEN_DATA = 'metamask/confirm-transaction/UPDATE_TOKEN_DATA' const CLEAR_TOKEN_DATA = 'metamask/confirm-transaction/CLEAR_TOKEN_DATA' const UPDATE_METHOD_DATA = 'metamask/confirm-transaction/UPDATE_METHOD_DATA' const CLEAR_METHOD_DATA = 'metamask/confirm-transaction/CLEAR_METHOD_DATA' -const UPDATE_TRANSACTION_AMOUNTS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS' -const UPDATE_TRANSACTION_FEES = 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES' -const UPDATE_TRANSACTION_TOTALS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS' +const UPDATE_TRANSACTION_AMOUNTS = + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS' +const UPDATE_TRANSACTION_FEES = + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES' +const UPDATE_TRANSACTION_TOTALS = + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS' const UPDATE_TOKEN_PROPS = 'metamask/confirm-transaction/UPDATE_TOKEN_PROPS' const UPDATE_NONCE = 'metamask/confirm-transaction/UPDATE_NONCE' -const UPDATE_TO_SMART_CONTRACT = 'metamask/confirm-transaction/UPDATE_TO_SMART_CONTRACT' +const UPDATE_TO_SMART_CONTRACT = + 'metamask/confirm-transaction/UPDATE_TO_SMART_CONTRACT' const FETCH_DATA_START = 'metamask/confirm-transaction/FETCH_DATA_START' const FETCH_DATA_END = 'metamask/confirm-transaction/FETCH_DATA_END' -const CLEAR_CONFIRM_TRANSACTION = 'metamask/confirm-transaction/CLEAR_CONFIRM_TRANSACTION' +const CLEAR_CONFIRM_TRANSACTION = + 'metamask/confirm-transaction/CLEAR_CONFIRM_TRANSACTION' describe('Confirm Transaction Duck', function () { describe('State changes', function () { @@ -293,13 +298,21 @@ describe('Confirm Transaction Duck', function () { it('should set fetchingData to false when receiving a FETCH_DATA_END action', function () { assert.deepEqual( - ConfirmTransactionReducer({ fetchingData: true }, { type: FETCH_DATA_END }), + ConfirmTransactionReducer( + { fetchingData: true }, + { type: FETCH_DATA_END }, + ), { fetchingData: false }, ) }) it('should clear confirmTransaction when receiving a FETCH_DATA_END action', function () { - assert.deepEqual(ConfirmTransactionReducer(mockState, { type: CLEAR_CONFIRM_TRANSACTION }), initialState) + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_CONFIRM_TRANSACTION, + }), + initialState, + ) }) }) @@ -311,10 +324,7 @@ describe('Confirm Transaction Duck', function () { payload: txData, } - assert.deepEqual( - actions.updateTxData(txData), - expectedAction, - ) + assert.deepEqual(actions.updateTxData(txData), expectedAction) }) it('should create an action to clear txData', function () { @@ -322,10 +332,7 @@ describe('Confirm Transaction Duck', function () { type: CLEAR_TX_DATA, } - assert.deepEqual( - actions.clearTxData(), - expectedAction, - ) + assert.deepEqual(actions.clearTxData(), expectedAction) }) it('should create an action to update tokenData', function () { @@ -335,10 +342,7 @@ describe('Confirm Transaction Duck', function () { payload: tokenData, } - assert.deepEqual( - actions.updateTokenData(tokenData), - expectedAction, - ) + assert.deepEqual(actions.updateTokenData(tokenData), expectedAction) }) it('should create an action to clear tokenData', function () { @@ -346,10 +350,7 @@ describe('Confirm Transaction Duck', function () { type: CLEAR_TOKEN_DATA, } - assert.deepEqual( - actions.clearTokenData(), - expectedAction, - ) + assert.deepEqual(actions.clearTokenData(), expectedAction) }) it('should create an action to update methodData', function () { @@ -359,10 +360,7 @@ describe('Confirm Transaction Duck', function () { payload: methodData, } - assert.deepEqual( - actions.updateMethodData(methodData), - expectedAction, - ) + assert.deepEqual(actions.updateMethodData(methodData), expectedAction) }) it('should create an action to clear methodData', function () { @@ -370,10 +368,7 @@ describe('Confirm Transaction Duck', function () { type: CLEAR_METHOD_DATA, } - assert.deepEqual( - actions.clearMethodData(), - expectedAction, - ) + assert.deepEqual(actions.clearMethodData(), expectedAction) }) it('should create an action to update transaction amounts', function () { @@ -425,10 +420,7 @@ describe('Confirm Transaction Duck', function () { payload: tokenProps, } - assert.deepEqual( - actions.updateTokenProps(tokenProps), - expectedAction, - ) + assert.deepEqual(actions.updateTokenProps(tokenProps), expectedAction) }) it('should create an action to update nonce', function () { @@ -438,10 +430,7 @@ describe('Confirm Transaction Duck', function () { payload: nonce, } - assert.deepEqual( - actions.updateNonce(nonce), - expectedAction, - ) + assert.deepEqual(actions.updateNonce(nonce), expectedAction) }) it('should create an action to set fetchingData to true', function () { @@ -449,10 +438,7 @@ describe('Confirm Transaction Duck', function () { type: FETCH_DATA_START, } - assert.deepEqual( - actions.setFetchingData(true), - expectedAction, - ) + assert.deepEqual(actions.setFetchingData(true), expectedAction) }) it('should create an action to set fetchingData to false', function () { @@ -460,10 +446,7 @@ describe('Confirm Transaction Duck', function () { type: FETCH_DATA_END, } - assert.deepEqual( - actions.setFetchingData(false), - expectedAction, - ) + assert.deepEqual(actions.setFetchingData(false), expectedAction) }) it('should create an action to clear confirmTransaction', function () { @@ -471,19 +454,20 @@ describe('Confirm Transaction Duck', function () { type: CLEAR_CONFIRM_TRANSACTION, } - assert.deepEqual( - actions.clearConfirmTransaction(), - expectedAction, - ) + assert.deepEqual(actions.clearConfirmTransaction(), expectedAction) }) }) describe('Thunk actions', function () { beforeEach(function () { global.eth = { - getCode: sinon.stub().callsFake( - (address) => Promise.resolve(address && address.match(/isContract/u) ? 'not-0x' : '0x'), - ), + getCode: sinon + .stub() + .callsFake((address) => + Promise.resolve( + address && address.match(/isContract/u) ? 'not-0x' : '0x', + ), + ), } }) @@ -535,11 +519,15 @@ describe('Confirm Transaction Duck', function () { 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', ] - store.dispatch(actions.updateGasAndCalculate({ gasLimit: '0x2', gasPrice: '0x25' })) + store.dispatch( + actions.updateGasAndCalculate({ gasLimit: '0x2', gasPrice: '0x25' }), + ) const storeActions = store.getActions() assert.equal(storeActions.length, expectedActions.length) - storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + storeActions.forEach((action, index) => + assert.equal(action.type, expectedActions[index]), + ) }) it('updates txData and updates gas values in confirmTransaction', function () { @@ -603,7 +591,9 @@ describe('Confirm Transaction Duck', function () { const storeActions = store.getActions() assert.equal(storeActions.length, expectedActions.length) - storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + storeActions.forEach((action, index) => + assert.equal(action.type, expectedActions[index]), + ) }) it('updates confirmTransaction transaction', function () { @@ -648,7 +638,9 @@ describe('Confirm Transaction Duck', function () { const storeActions = store.getActions() assert.equal(storeActions.length, expectedActions.length) - storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + storeActions.forEach((action, index) => + assert.equal(action.type, expectedActions[index]), + ) }) }) }) diff --git a/ui/app/ducks/gas/gas-duck.test.js b/ui/app/ducks/gas/gas-duck.test.js index d7ae9b873..6db54d12a 100644 --- a/ui/app/ducks/gas/gas-duck.test.js +++ b/ui/app/ducks/gas/gas-duck.test.js @@ -45,35 +45,116 @@ describe('Gas Duck', function () { standard: 20, } const mockPredictTableResponse = [ - { expectedTime: 400, expectedWait: 40, gasprice: 0.25, somethingElse: 'foobar' }, - { expectedTime: 200, expectedWait: 20, gasprice: 0.5, somethingElse: 'foobar' }, - { expectedTime: 100, expectedWait: 10, gasprice: 1, somethingElse: 'foobar' }, - { expectedTime: 75, expectedWait: 7.5, gasprice: 1.5, somethingElse: 'foobar' }, + { + expectedTime: 400, + expectedWait: 40, + gasprice: 0.25, + somethingElse: 'foobar', + }, + { + expectedTime: 200, + expectedWait: 20, + gasprice: 0.5, + somethingElse: 'foobar', + }, + { + expectedTime: 100, + expectedWait: 10, + gasprice: 1, + somethingElse: 'foobar', + }, + { + expectedTime: 75, + expectedWait: 7.5, + gasprice: 1.5, + somethingElse: 'foobar', + }, { expectedTime: 50, expectedWait: 5, gasprice: 2, somethingElse: 'foobar' }, - { expectedTime: 35, expectedWait: 4.5, gasprice: 3, somethingElse: 'foobar' }, - { expectedTime: 34, expectedWait: 4.4, gasprice: 3.1, somethingElse: 'foobar' }, - { expectedTime: 25, expectedWait: 4.2, gasprice: 3.5, somethingElse: 'foobar' }, + { + expectedTime: 35, + expectedWait: 4.5, + gasprice: 3, + somethingElse: 'foobar', + }, + { + expectedTime: 34, + expectedWait: 4.4, + gasprice: 3.1, + somethingElse: 'foobar', + }, + { + expectedTime: 25, + expectedWait: 4.2, + gasprice: 3.5, + somethingElse: 'foobar', + }, { expectedTime: 20, expectedWait: 4, gasprice: 4, somethingElse: 'foobar' }, - { expectedTime: 19, expectedWait: 3.9, gasprice: 4.1, somethingElse: 'foobar' }, + { + expectedTime: 19, + expectedWait: 3.9, + gasprice: 4.1, + somethingElse: 'foobar', + }, { expectedTime: 15, expectedWait: 3, gasprice: 7, somethingElse: 'foobar' }, - { expectedTime: 14, expectedWait: 2.9, gasprice: 7.1, somethingElse: 'foobar' }, - { expectedTime: 12, expectedWait: 2.5, gasprice: 8, somethingElse: 'foobar' }, - { expectedTime: 10, expectedWait: 2, gasprice: 10, somethingElse: 'foobar' }, - { expectedTime: 9, expectedWait: 1.9, gasprice: 10.1, somethingElse: 'foobar' }, + { + expectedTime: 14, + expectedWait: 2.9, + gasprice: 7.1, + somethingElse: 'foobar', + }, + { + expectedTime: 12, + expectedWait: 2.5, + gasprice: 8, + somethingElse: 'foobar', + }, + { + expectedTime: 10, + expectedWait: 2, + gasprice: 10, + somethingElse: 'foobar', + }, + { + expectedTime: 9, + expectedWait: 1.9, + gasprice: 10.1, + somethingElse: 'foobar', + }, { expectedTime: 5, expectedWait: 1, gasprice: 15, somethingElse: 'foobar' }, - { expectedTime: 4, expectedWait: 0.9, gasprice: 15.1, somethingElse: 'foobar' }, - { expectedTime: 2, expectedWait: 0.8, gasprice: 17, somethingElse: 'foobar' }, - { expectedTime: 1.1, expectedWait: 0.6, gasprice: 19.9, somethingElse: 'foobar' }, - { expectedTime: 1, expectedWait: 0.5, gasprice: 20, somethingElse: 'foobar' }, + { + expectedTime: 4, + expectedWait: 0.9, + gasprice: 15.1, + somethingElse: 'foobar', + }, + { + expectedTime: 2, + expectedWait: 0.8, + gasprice: 17, + somethingElse: 'foobar', + }, + { + expectedTime: 1.1, + expectedWait: 0.6, + gasprice: 19.9, + somethingElse: 'foobar', + }, + { + expectedTime: 1, + expectedWait: 0.5, + gasprice: 20, + somethingElse: 'foobar', + }, ] - const fakeFetch = (url) => new Promise((resolve) => { - const dataToResolve = url.match(/ethgasAPI/u) - ? mockEthGasApiResponse - : mockPredictTableResponse - resolve({ - json: () => Promise.resolve(dataToResolve), + const fakeFetch = (url) => + new Promise((resolve) => { + const dataToResolve = url.match(/ethgasAPI/u) + ? mockEthGasApiResponse + : mockPredictTableResponse + resolve({ + json: () => Promise.resolve(dataToResolve), + }) }) - }) beforeEach(function () { tempFetch = window.fetch @@ -121,20 +202,28 @@ describe('Gas Duck', function () { basicPriceAndTimeEstimatesLastRetrieved: 0, basicPriceEstimatesLastRetrieved: 0, } - const BASIC_GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED' - const BASIC_GAS_ESTIMATE_LOADING_STARTED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_STARTED' - const GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/GAS_ESTIMATE_LOADING_FINISHED' - const GAS_ESTIMATE_LOADING_STARTED = 'metamask/gas/GAS_ESTIMATE_LOADING_STARTED' + const BASIC_GAS_ESTIMATE_LOADING_FINISHED = + 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED' + const BASIC_GAS_ESTIMATE_LOADING_STARTED = + 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_STARTED' + const GAS_ESTIMATE_LOADING_FINISHED = + 'metamask/gas/GAS_ESTIMATE_LOADING_FINISHED' + const GAS_ESTIMATE_LOADING_STARTED = + 'metamask/gas/GAS_ESTIMATE_LOADING_STARTED' const RESET_CUSTOM_GAS_STATE = 'metamask/gas/RESET_CUSTOM_GAS_STATE' const SET_BASIC_GAS_ESTIMATE_DATA = 'metamask/gas/SET_BASIC_GAS_ESTIMATE_DATA' const SET_CUSTOM_GAS_ERRORS = 'metamask/gas/SET_CUSTOM_GAS_ERRORS' const SET_CUSTOM_GAS_LIMIT = 'metamask/gas/SET_CUSTOM_GAS_LIMIT' const SET_CUSTOM_GAS_PRICE = 'metamask/gas/SET_CUSTOM_GAS_PRICE' const SET_CUSTOM_GAS_TOTAL = 'metamask/gas/SET_CUSTOM_GAS_TOTAL' - const SET_PRICE_AND_TIME_ESTIMATES = 'metamask/gas/SET_PRICE_AND_TIME_ESTIMATES' - const SET_API_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_API_ESTIMATES_LAST_RETRIEVED' - const SET_BASIC_API_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_BASIC_API_ESTIMATES_LAST_RETRIEVED' - const SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED' + const SET_PRICE_AND_TIME_ESTIMATES = + 'metamask/gas/SET_PRICE_AND_TIME_ESTIMATES' + const SET_API_ESTIMATES_LAST_RETRIEVED = + 'metamask/gas/SET_API_ESTIMATES_LAST_RETRIEVED' + const SET_BASIC_API_ESTIMATES_LAST_RETRIEVED = + 'metamask/gas/SET_BASIC_API_ESTIMATES_LAST_RETRIEVED' + const SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED = + 'metamask/gas/SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED' describe('GasReducer()', function () { it('should initialize state', function () { @@ -245,7 +334,10 @@ describe('Gas Duck', function () { type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: 1700000000000, }), - { basicPriceAndTimeEstimatesLastRetrieved: 1700000000000, ...mockState }, + { + basicPriceAndTimeEstimatesLastRetrieved: 1700000000000, + ...mockState, + }, ) }) @@ -269,13 +361,17 @@ describe('Gas Duck', function () { describe('basicGasEstimatesLoadingStarted', function () { it('should create the correct action', function () { - assert.deepEqual(basicGasEstimatesLoadingStarted(), { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }) + assert.deepEqual(basicGasEstimatesLoadingStarted(), { + type: BASIC_GAS_ESTIMATE_LOADING_STARTED, + }) }) }) describe('basicGasEstimatesLoadingFinished', function () { it('should create the correct action', function () { - assert.deepEqual(basicGasEstimatesLoadingFinished(), { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }) + assert.deepEqual(basicGasEstimatesLoadingFinished(), { + type: BASIC_GAS_ESTIMATE_LOADING_FINISHED, + }) }) }) @@ -286,21 +382,20 @@ describe('Gas Duck', function () { await fetchBasicGasEstimates()(mockDistpatch, () => ({ gas: { ...initState, basicPriceAEstimatesLastRetrieved: 1000000 }, })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED }], - ) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok( - window.fetch.getCall(0).args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), + window.fetch + .getCall(0) + .args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), 'should fetch ETH Gas Station', ) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: 2000000 }], - ) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: 2000000 }, + ]) + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: SET_BASIC_GAS_ESTIMATE_DATA, value: { average: 2, @@ -310,12 +405,11 @@ describe('Gas Duck', function () { fastest: 4, safeLow: 1, }, - }], - ) - assert.deepEqual( - mockDistpatch.getCall(3).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(3).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) it('should fetch recently retrieved estimates from local storage', async function () { @@ -334,15 +428,15 @@ describe('Gas Duck', function () { safeLow: 15, }) - await fetchBasicGasEstimates()(mockDistpatch, () => ({ gas: { ...initState } })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED }], - ) + await fetchBasicGasEstimates()(mockDistpatch, () => ({ + gas: { ...initState }, + })) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok(window.fetch.notCalled) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_BASIC_GAS_ESTIMATE_DATA, value: { average: 25, @@ -352,12 +446,11 @@ describe('Gas Duck', function () { fastest: 45, safeLow: 15, }, - }], - ) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) it('should fallback to network if retrieving estimates from local storage fails', async function () { @@ -366,22 +459,23 @@ describe('Gas Duck', function () { .withArgs('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') .returns(2000000 - 1) // one second ago from "now" - await fetchBasicGasEstimates()(mockDistpatch, () => ({ gas: { ...initState } })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED }], - ) + await fetchBasicGasEstimates()(mockDistpatch, () => ({ + gas: { ...initState }, + })) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok( - window.fetch.getCall(0).args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), + window.fetch + .getCall(0) + .args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), 'should fetch ETH Gas Station', ) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: 2000000 }], - ) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: 2000000 }, + ]) + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: SET_BASIC_GAS_ESTIMATE_DATA, value: { average: 2, @@ -391,12 +485,11 @@ describe('Gas Duck', function () { fastest: 4, safeLow: 1, }, - }], - ) - assert.deepEqual( - mockDistpatch.getCall(3).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(3).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) }) @@ -411,23 +504,22 @@ describe('Gas Duck', function () { }, metamask: { provider: { type: 'ropsten' } }, })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED }], - ) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok( - window.fetch.getCall(0).args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), + window.fetch + .getCall(0) + .args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), 'should fetch ETH Gas Station', ) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }], - ) + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }, + ]) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: SET_BASIC_GAS_ESTIMATE_DATA, value: { average: 2, @@ -442,12 +534,11 @@ describe('Gas Duck', function () { safeLowWait: 'mockSafeLowWait', speed: 'mockSpeed', }, - }], - ) - assert.deepEqual( - mockDistpatch.getCall(3).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(3).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) it('should fetch recently retrieved estimates from local storage', async function () { @@ -477,15 +568,13 @@ describe('Gas Duck', function () { }, metamask: { provider: { type: 'ropsten' } }, })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED }], - ) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok(window.fetch.notCalled) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_BASIC_GAS_ESTIMATE_DATA, value: { average: 5, @@ -500,12 +589,11 @@ describe('Gas Duck', function () { safeLowWait: 'mockSafeLowWait', speed: 'mockSpeed', }, - }], - ) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) it('should fallback to network if retrieving estimates from local storage fails', async function () { @@ -520,23 +608,22 @@ describe('Gas Duck', function () { }, metamask: { provider: { type: 'ropsten' } }, })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED }], - ) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok( - window.fetch.getCall(0).args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), + window.fetch + .getCall(0) + .args[0].startsWith('https://ethgasstation.info/json/ethgasAPI.json'), 'should fetch ETH Gas Station', ) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }], - ) + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }, + ]) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: SET_BASIC_GAS_ESTIMATE_DATA, value: { average: 2, @@ -551,12 +638,11 @@ describe('Gas Duck', function () { safeLowWait: 'mockSafeLowWait', speed: 'mockSpeed', }, - }], - ) - assert.deepEqual( - mockDistpatch.getCall(3).args, - [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(3).args, [ + { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) }) @@ -571,31 +657,46 @@ describe('Gas Duck', function () { }, metamask: { provider: { type: 'ropsten' } }, })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: GAS_ESTIMATE_LOADING_STARTED }], - ) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.ok( - window.fetch.getCall(0).args[0].startsWith('https://ethgasstation.info/json/predictTable.json'), + window.fetch + .getCall(0) + .args[0].startsWith( + 'https://ethgasstation.info/json/predictTable.json', + ), 'should fetch ETH Gas Station', ) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ type: SET_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }], - ) + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }, + ]) - const { type: thirdDispatchCallType, value: priceAndTimeEstimateResult } = mockDistpatch.getCall(2).args[0] + const { + type: thirdDispatchCallType, + value: priceAndTimeEstimateResult, + } = mockDistpatch.getCall(2).args[0] assert.equal(thirdDispatchCallType, SET_PRICE_AND_TIME_ESTIMATES) - assert(priceAndTimeEstimateResult.length < ((mockPredictTableResponse.length * 3) - 2)) - assert(!priceAndTimeEstimateResult.find((d) => d.expectedTime > 100)) - assert(!priceAndTimeEstimateResult.find((d, _, a) => a[a + 1] && d.expectedTime > a[a + 1].expectedTime)) - assert(!priceAndTimeEstimateResult.find((d, _, a) => a[a + 1] && d.gasprice > a[a + 1].gasprice)) - - assert.deepEqual( - mockDistpatch.getCall(3).args, - [{ type: GAS_ESTIMATE_LOADING_FINISHED }], + assert( + priceAndTimeEstimateResult.length < + mockPredictTableResponse.length * 3 - 2, ) + assert(!priceAndTimeEstimateResult.find((d) => d.expectedTime > 100)) + assert( + !priceAndTimeEstimateResult.find( + (d, _, a) => a[a + 1] && d.expectedTime > a[a + 1].expectedTime, + ), + ) + assert( + !priceAndTimeEstimateResult.find( + (d, _, a) => a[a + 1] && d.gasprice > a[a + 1].gasprice, + ), + ) + + assert.deepEqual(mockDistpatch.getCall(3).args, [ + { type: GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) it('should not call fetch if the estimates were retrieved < 75000 ms ago', async function () { @@ -605,23 +706,23 @@ describe('Gas Duck', function () { gas: { ...initState, priceAndTimeEstimatesLastRetrieved: Date.now(), - priceAndTimeEstimates: [{ - expectedTime: '10', - expectedWait: 2, - gasprice: 50, - }], + priceAndTimeEstimates: [ + { + expectedTime: '10', + expectedWait: 2, + gasprice: 50, + }, + ], }, metamask: { provider: { type: 'ropsten' } }, })) - assert.deepEqual( - mockDistpatch.getCall(0).args, - [{ type: GAS_ESTIMATE_LOADING_STARTED }], - ) + assert.deepEqual(mockDistpatch.getCall(0).args, [ + { type: GAS_ESTIMATE_LOADING_STARTED }, + ]) assert.equal(window.fetch.callCount, 0) - assert.deepEqual( - mockDistpatch.getCall(1).args, - [{ + assert.deepEqual(mockDistpatch.getCall(1).args, [ + { type: SET_PRICE_AND_TIME_ESTIMATES, value: [ { @@ -630,31 +731,27 @@ describe('Gas Duck', function () { gasprice: 50, }, ], - - }], - ) - assert.deepEqual( - mockDistpatch.getCall(2).args, - [{ type: GAS_ESTIMATE_LOADING_FINISHED }], - ) + }, + ]) + assert.deepEqual(mockDistpatch.getCall(2).args, [ + { type: GAS_ESTIMATE_LOADING_FINISHED }, + ]) }) }) describe('gasEstimatesLoadingStarted', function () { it('should create the correct action', function () { - assert.deepEqual( - gasEstimatesLoadingStarted(), - { type: GAS_ESTIMATE_LOADING_STARTED }, - ) + assert.deepEqual(gasEstimatesLoadingStarted(), { + type: GAS_ESTIMATE_LOADING_STARTED, + }) }) }) describe('gasEstimatesLoadingFinished', function () { it('should create the correct action', function () { - assert.deepEqual( - gasEstimatesLoadingFinished(), - { type: GAS_ESTIMATE_LOADING_FINISHED }, - ) + assert.deepEqual(gasEstimatesLoadingFinished(), { + type: GAS_ESTIMATE_LOADING_FINISHED, + }) }) }) @@ -662,71 +759,71 @@ describe('Gas Duck', function () { it('should create the correct action', function () { assert.deepEqual( setPricesAndTimeEstimates('mockPricesAndTimeEstimates'), - { type: SET_PRICE_AND_TIME_ESTIMATES, value: 'mockPricesAndTimeEstimates' }, + { + type: SET_PRICE_AND_TIME_ESTIMATES, + value: 'mockPricesAndTimeEstimates', + }, ) }) }) describe('setBasicGasEstimateData', function () { it('should create the correct action', function () { - assert.deepEqual( - setBasicGasEstimateData('mockBasicEstimatData'), - { type: SET_BASIC_GAS_ESTIMATE_DATA, value: 'mockBasicEstimatData' }, - ) + assert.deepEqual(setBasicGasEstimateData('mockBasicEstimatData'), { + type: SET_BASIC_GAS_ESTIMATE_DATA, + value: 'mockBasicEstimatData', + }) }) }) describe('setCustomGasPrice', function () { it('should create the correct action', function () { - assert.deepEqual( - setCustomGasPrice('mockCustomGasPrice'), - { type: SET_CUSTOM_GAS_PRICE, value: 'mockCustomGasPrice' }, - ) + assert.deepEqual(setCustomGasPrice('mockCustomGasPrice'), { + type: SET_CUSTOM_GAS_PRICE, + value: 'mockCustomGasPrice', + }) }) }) describe('setCustomGasLimit', function () { it('should create the correct action', function () { - assert.deepEqual( - setCustomGasLimit('mockCustomGasLimit'), - { type: SET_CUSTOM_GAS_LIMIT, value: 'mockCustomGasLimit' }, - ) + assert.deepEqual(setCustomGasLimit('mockCustomGasLimit'), { + type: SET_CUSTOM_GAS_LIMIT, + value: 'mockCustomGasLimit', + }) }) }) describe('setCustomGasTotal', function () { it('should create the correct action', function () { - assert.deepEqual( - setCustomGasTotal('mockCustomGasTotal'), - { type: SET_CUSTOM_GAS_TOTAL, value: 'mockCustomGasTotal' }, - ) + assert.deepEqual(setCustomGasTotal('mockCustomGasTotal'), { + type: SET_CUSTOM_GAS_TOTAL, + value: 'mockCustomGasTotal', + }) }) }) describe('setCustomGasErrors', function () { it('should create the correct action', function () { - assert.deepEqual( - setCustomGasErrors('mockErrorObject'), - { type: SET_CUSTOM_GAS_ERRORS, value: 'mockErrorObject' }, - ) + assert.deepEqual(setCustomGasErrors('mockErrorObject'), { + type: SET_CUSTOM_GAS_ERRORS, + value: 'mockErrorObject', + }) }) }) describe('setApiEstimatesLastRetrieved', function () { it('should create the correct action', function () { - assert.deepEqual( - setApiEstimatesLastRetrieved(1234), - { type: SET_API_ESTIMATES_LAST_RETRIEVED, value: 1234 }, - ) + assert.deepEqual(setApiEstimatesLastRetrieved(1234), { + type: SET_API_ESTIMATES_LAST_RETRIEVED, + value: 1234, + }) }) }) describe('resetCustomGasState', function () { it('should create the correct action', function () { - assert.deepEqual( - resetCustomGasState(), - { type: RESET_CUSTOM_GAS_STATE }, - ) + assert.deepEqual(resetCustomGasState(), { type: RESET_CUSTOM_GAS_STATE }) }) }) }) diff --git a/ui/app/ducks/gas/gas.duck.js b/ui/app/ducks/gas/gas.duck.js index 9d83a66e0..5a937e744 100644 --- a/ui/app/ducks/gas/gas.duck.js +++ b/ui/app/ducks/gas/gas.duck.js @@ -4,17 +4,16 @@ import { loadLocalStorageData, saveLocalStorageData, } from '../../../lib/local-storage-helpers' -import { - decGWEIToHexWEI, -} from '../../helpers/utils/conversions.util' -import { - isEthereumNetwork, -} from '../../selectors' +import { decGWEIToHexWEI } from '../../helpers/utils/conversions.util' +import { isEthereumNetwork } from '../../selectors' // Actions -const BASIC_GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED' -const BASIC_GAS_ESTIMATE_LOADING_STARTED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_STARTED' -const GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/GAS_ESTIMATE_LOADING_FINISHED' +const BASIC_GAS_ESTIMATE_LOADING_FINISHED = + 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED' +const BASIC_GAS_ESTIMATE_LOADING_STARTED = + 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_STARTED' +const GAS_ESTIMATE_LOADING_FINISHED = + 'metamask/gas/GAS_ESTIMATE_LOADING_FINISHED' const GAS_ESTIMATE_LOADING_STARTED = 'metamask/gas/GAS_ESTIMATE_LOADING_STARTED' const RESET_CUSTOM_GAS_STATE = 'metamask/gas/RESET_CUSTOM_GAS_STATE' const RESET_CUSTOM_DATA = 'metamask/gas/RESET_CUSTOM_DATA' @@ -24,9 +23,12 @@ const SET_CUSTOM_GAS_LIMIT = 'metamask/gas/SET_CUSTOM_GAS_LIMIT' const SET_CUSTOM_GAS_PRICE = 'metamask/gas/SET_CUSTOM_GAS_PRICE' const SET_CUSTOM_GAS_TOTAL = 'metamask/gas/SET_CUSTOM_GAS_TOTAL' const SET_PRICE_AND_TIME_ESTIMATES = 'metamask/gas/SET_PRICE_AND_TIME_ESTIMATES' -const SET_API_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_API_ESTIMATES_LAST_RETRIEVED' -const SET_BASIC_API_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_BASIC_API_ESTIMATES_LAST_RETRIEVED' -const SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED' +const SET_API_ESTIMATES_LAST_RETRIEVED = + 'metamask/gas/SET_API_ESTIMATES_LAST_RETRIEVED' +const SET_BASIC_API_ESTIMATES_LAST_RETRIEVED = + 'metamask/gas/SET_BASIC_API_ESTIMATES_LAST_RETRIEVED' +const SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED = + 'metamask/gas/SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED' const initState = { customData: { @@ -56,7 +58,7 @@ const initState = { } // Reducer -export default function reducer (state = initState, action) { +export default function reducer(state = initState, action) { switch (action.type) { case BASIC_GAS_ESTIMATE_LOADING_STARTED: return { @@ -148,60 +150,67 @@ export default function reducer (state = initState, action) { } // Action Creators -export function basicGasEstimatesLoadingStarted () { +export function basicGasEstimatesLoadingStarted() { return { type: BASIC_GAS_ESTIMATE_LOADING_STARTED, } } -export function basicGasEstimatesLoadingFinished () { +export function basicGasEstimatesLoadingFinished() { return { type: BASIC_GAS_ESTIMATE_LOADING_FINISHED, } } -export function gasEstimatesLoadingStarted () { +export function gasEstimatesLoadingStarted() { return { type: GAS_ESTIMATE_LOADING_STARTED, } } -export function gasEstimatesLoadingFinished () { +export function gasEstimatesLoadingFinished() { return { type: GAS_ESTIMATE_LOADING_FINISHED, } } -async function queryEthGasStationBasic () { - const apiKey = process.env.ETH_GAS_STATION_API_KEY ? `?api-key=${process.env.ETH_GAS_STATION_API_KEY}` : '' +async function queryEthGasStationBasic() { + const apiKey = process.env.ETH_GAS_STATION_API_KEY + ? `?api-key=${process.env.ETH_GAS_STATION_API_KEY}` + : '' const url = `https://ethgasstation.info/json/ethgasAPI.json${apiKey}` return await window.fetch(url, { - 'headers': {}, - 'referrer': 'http://ethgasstation.info/json/', - 'referrerPolicy': 'no-referrer-when-downgrade', - 'body': null, - 'method': 'GET', - 'mode': 'cors', + headers: {}, + referrer: 'http://ethgasstation.info/json/', + referrerPolicy: 'no-referrer-when-downgrade', + body: null, + method: 'GET', + mode: 'cors', }) } -async function queryEthGasStationPredictionTable () { - const apiKey = process.env.ETH_GAS_STATION_API_KEY ? `?api-key=${process.env.ETH_GAS_STATION_API_KEY}` : '' +async function queryEthGasStationPredictionTable() { + const apiKey = process.env.ETH_GAS_STATION_API_KEY + ? `?api-key=${process.env.ETH_GAS_STATION_API_KEY}` + : '' const url = `https://ethgasstation.info/json/predictTable.json${apiKey}` return await window.fetch(url, { - 'headers': {}, - 'referrer': 'http://ethgasstation.info/json/', - 'referrerPolicy': 'no-referrer-when-downgrade', - 'body': null, - 'method': 'GET', - 'mode': 'cors', + headers: {}, + referrer: 'http://ethgasstation.info/json/', + referrerPolicy: 'no-referrer-when-downgrade', + body: null, + method: 'GET', + mode: 'cors', }) } -export function fetchBasicGasEstimates () { +export function fetchBasicGasEstimates() { return async (dispatch, getState) => { const { basicPriceEstimatesLastRetrieved } = getState().gas - const timeLastRetrieved = basicPriceEstimatesLastRetrieved || loadLocalStorageData('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') || 0 + const timeLastRetrieved = + basicPriceEstimatesLastRetrieved || + loadLocalStorageData('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') || + 0 dispatch(basicGasEstimatesLoadingStarted()) @@ -210,7 +219,8 @@ export function fetchBasicGasEstimates () { basicEstimates = await fetchExternalBasicGasEstimates(dispatch) } else { const cachedBasicEstimates = loadLocalStorageData('BASIC_PRICE_ESTIMATES') - basicEstimates = cachedBasicEstimates || await fetchExternalBasicGasEstimates(dispatch) + basicEstimates = + cachedBasicEstimates || (await fetchExternalBasicGasEstimates(dispatch)) } dispatch(setBasicGasEstimateData(basicEstimates)) @@ -220,7 +230,7 @@ export function fetchBasicGasEstimates () { } } -async function fetchExternalBasicGasEstimates (dispatch) { +async function fetchExternalBasicGasEstimates(dispatch) { const response = await queryEthGasStationBasic() const { @@ -237,7 +247,7 @@ async function fetchExternalBasicGasEstimates (dispatch) { fastTimes10, fastestTimes10, safeLowTimes10, - ].map((price) => (new BigNumber(price)).div(10).toNumber()) + ].map((price) => new BigNumber(price).div(10).toNumber()) const basicEstimates = { safeLow, @@ -256,10 +266,13 @@ async function fetchExternalBasicGasEstimates (dispatch) { return basicEstimates } -export function fetchBasicGasAndTimeEstimates () { +export function fetchBasicGasAndTimeEstimates() { return async (dispatch, getState) => { const { basicPriceAndTimeEstimatesLastRetrieved } = getState().gas - const timeLastRetrieved = basicPriceAndTimeEstimatesLastRetrieved || loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') || 0 + const timeLastRetrieved = + basicPriceAndTimeEstimatesLastRetrieved || + loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') || + 0 dispatch(basicGasEstimatesLoadingStarted()) @@ -267,8 +280,12 @@ export function fetchBasicGasAndTimeEstimates () { if (Date.now() - timeLastRetrieved > 75000) { basicEstimates = await fetchExternalBasicGasAndTimeEstimates(dispatch) } else { - const cachedBasicEstimates = loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES') - basicEstimates = cachedBasicEstimates || await fetchExternalBasicGasAndTimeEstimates(dispatch) + const cachedBasicEstimates = loadLocalStorageData( + 'BASIC_GAS_AND_TIME_API_ESTIMATES', + ) + basicEstimates = + cachedBasicEstimates || + (await fetchExternalBasicGasAndTimeEstimates(dispatch)) } dispatch(setBasicGasEstimateData(basicEstimates)) @@ -277,7 +294,7 @@ export function fetchBasicGasAndTimeEstimates () { } } -async function fetchExternalBasicGasAndTimeEstimates (dispatch) { +async function fetchExternalBasicGasAndTimeEstimates(dispatch) { const response = await queryEthGasStationBasic() const { @@ -298,7 +315,7 @@ async function fetchExternalBasicGasAndTimeEstimates (dispatch) { fastTimes10, fastestTimes10, safeLowTimes10, - ].map((price) => (new BigNumber(price)).div(10).toNumber()) + ].map((price) => new BigNumber(price).div(10).toNumber()) const basicEstimates = { average, @@ -316,13 +333,16 @@ async function fetchExternalBasicGasAndTimeEstimates (dispatch) { const timeRetrieved = Date.now() saveLocalStorageData(basicEstimates, 'BASIC_GAS_AND_TIME_API_ESTIMATES') - saveLocalStorageData(timeRetrieved, 'BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') + saveLocalStorageData( + timeRetrieved, + 'BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED', + ) dispatch(setBasicApiEstimatesLastRetrieved(timeRetrieved)) return basicEstimates } -function extrapolateY ({ higherY, lowerY, higherX, lowerX, xForExtrapolation }) { +function extrapolateY({ higherY, lowerY, higherX, lowerX, xForExtrapolation }) { /* eslint-disable no-param-reassign */ higherY = new BigNumber(higherY, 10) lowerY = new BigNumber(lowerY, 10) @@ -330,29 +350,35 @@ function extrapolateY ({ higherY, lowerY, higherX, lowerX, xForExtrapolation }) lowerX = new BigNumber(lowerX, 10) xForExtrapolation = new BigNumber(xForExtrapolation, 10) /* eslint-enable no-param-reassign */ - const slope = (higherY.minus(lowerY)).div(higherX.minus(lowerX)) - const newTimeEstimate = slope.times(higherX.minus(xForExtrapolation)).minus(higherY).negated() + const slope = higherY.minus(lowerY).div(higherX.minus(lowerX)) + const newTimeEstimate = slope + .times(higherX.minus(xForExtrapolation)) + .minus(higherY) + .negated() return Number(newTimeEstimate.toPrecision(10)) } -function getRandomArbitrary (minStr, maxStr) { +function getRandomArbitrary(minStr, maxStr) { const min = new BigNumber(minStr, 10) const max = new BigNumber(maxStr, 10) const random = new BigNumber(String(Math.random()), 10) return new BigNumber(random.times(max.minus(min)).plus(min)).toPrecision(10) } -function calcMedian (list) { - const medianPos = (Math.floor(list.length / 2) + Math.ceil(list.length / 2)) / 2 +function calcMedian(list) { + const medianPos = + (Math.floor(list.length / 2) + Math.ceil(list.length / 2)) / 2 return medianPos === Math.floor(medianPos) ? (list[medianPos - 1] + list[medianPos]) / 2 : list[Math.floor(medianPos)] } -function quartiles (data) { +function quartiles(data) { const lowerHalf = data.slice(0, Math.floor(data.length / 2)) - const upperHalf = data.slice(Math.floor(data.length / 2) + (data.length % 2 === 0 ? 0 : 1)) + const upperHalf = data.slice( + Math.floor(data.length / 2) + (data.length % 2 === 0 ? 0 : 1), + ) const median = calcMedian(data) const lowerQuartile = calcMedian(lowerHalf) const upperQuartile = calcMedian(upperHalf) @@ -363,18 +389,20 @@ function quartiles (data) { } } -function inliersByIQR (data, prop) { - const { lowerQuartile, upperQuartile } = quartiles(data.map((d) => (prop ? d[prop] : d))) +function inliersByIQR(data, prop) { + const { lowerQuartile, upperQuartile } = quartiles( + data.map((d) => (prop ? d[prop] : d)), + ) const IQR = upperQuartile - lowerQuartile - const lowerBound = lowerQuartile - (1.5 * IQR) - const upperBound = upperQuartile + (1.5 * IQR) + const lowerBound = lowerQuartile - 1.5 * IQR + const upperBound = upperQuartile + 1.5 * IQR return data.filter((d) => { const value = prop ? d[prop] : d return value >= lowerBound && value <= upperBound }) } -export function fetchGasEstimates (blockTime) { +export function fetchGasEstimates(blockTime) { return (dispatch, getState) => { const state = getState() @@ -386,63 +414,104 @@ export function fetchGasEstimates (blockTime) { priceAndTimeEstimatesLastRetrieved, priceAndTimeEstimates, } = state.gas - const timeLastRetrieved = priceAndTimeEstimatesLastRetrieved || loadLocalStorageData('GAS_API_ESTIMATES_LAST_RETRIEVED') || 0 + const timeLastRetrieved = + priceAndTimeEstimatesLastRetrieved || + loadLocalStorageData('GAS_API_ESTIMATES_LAST_RETRIEVED') || + 0 dispatch(gasEstimatesLoadingStarted()) - const promiseToFetch = Date.now() - timeLastRetrieved > 75000 - ? queryEthGasStationPredictionTable() - .then((r) => r.json()) - .then((r) => { - const estimatedPricesAndTimes = r.map(({ expectedTime, expectedWait, gasprice }) => ({ expectedTime, expectedWait, gasprice })) - const estimatedTimeWithUniquePrices = uniqBy(estimatedPricesAndTimes, ({ expectedTime }) => expectedTime) + const promiseToFetch = + Date.now() - timeLastRetrieved > 75000 + ? queryEthGasStationPredictionTable() + .then((r) => r.json()) + .then((r) => { + const estimatedPricesAndTimes = r.map( + ({ expectedTime, expectedWait, gasprice }) => ({ + expectedTime, + expectedWait, + gasprice, + }), + ) + const estimatedTimeWithUniquePrices = uniqBy( + estimatedPricesAndTimes, + ({ expectedTime }) => expectedTime, + ) - const withSupplementalTimeEstimates = flatten(estimatedTimeWithUniquePrices.map(({ expectedWait, gasprice }, i, arr) => { - const next = arr[i + 1] - if (!next) { - return [{ expectedWait, gasprice }] - } - const supplementalPrice = getRandomArbitrary(gasprice, next.gasprice) - const supplementalTime = extrapolateY({ - higherY: next.expectedWait, - lowerY: expectedWait, - higherX: next.gasprice, - lowerX: gasprice, - xForExtrapolation: supplementalPrice, + const withSupplementalTimeEstimates = flatten( + estimatedTimeWithUniquePrices.map( + ({ expectedWait, gasprice }, i, arr) => { + const next = arr[i + 1] + if (!next) { + return [{ expectedWait, gasprice }] + } + const supplementalPrice = getRandomArbitrary( + gasprice, + next.gasprice, + ) + const supplementalTime = extrapolateY({ + higherY: next.expectedWait, + lowerY: expectedWait, + higherX: next.gasprice, + lowerX: gasprice, + xForExtrapolation: supplementalPrice, + }) + const supplementalPrice2 = getRandomArbitrary( + supplementalPrice, + next.gasprice, + ) + const supplementalTime2 = extrapolateY({ + higherY: next.expectedWait, + lowerY: supplementalTime, + higherX: next.gasprice, + lowerX: supplementalPrice, + xForExtrapolation: supplementalPrice2, + }) + return [ + { expectedWait, gasprice }, + { + expectedWait: supplementalTime, + gasprice: supplementalPrice, + }, + { + expectedWait: supplementalTime2, + gasprice: supplementalPrice2, + }, + ] + }, + ), + ) + const withOutliersRemoved = inliersByIQR( + withSupplementalTimeEstimates.slice(0).reverse(), + 'expectedWait', + ).reverse() + const timeMappedToSeconds = withOutliersRemoved.map( + ({ expectedWait, gasprice }) => { + const expectedTime = new BigNumber(expectedWait) + .times(Number(blockTime), 10) + .toNumber() + return { + expectedTime, + gasprice: new BigNumber(gasprice, 10).toNumber(), + } + }, + ) + + const timeRetrieved = Date.now() + dispatch(setApiEstimatesLastRetrieved(timeRetrieved)) + saveLocalStorageData( + timeRetrieved, + 'GAS_API_ESTIMATES_LAST_RETRIEVED', + ) + saveLocalStorageData(timeMappedToSeconds, 'GAS_API_ESTIMATES') + + return timeMappedToSeconds }) - const supplementalPrice2 = getRandomArbitrary(supplementalPrice, next.gasprice) - const supplementalTime2 = extrapolateY({ - higherY: next.expectedWait, - lowerY: supplementalTime, - higherX: next.gasprice, - lowerX: supplementalPrice, - xForExtrapolation: supplementalPrice2, - }) - return [ - { expectedWait, gasprice }, - { expectedWait: supplementalTime, gasprice: supplementalPrice }, - { expectedWait: supplementalTime2, gasprice: supplementalPrice2 }, - ] - })) - const withOutliersRemoved = inliersByIQR(withSupplementalTimeEstimates.slice(0).reverse(), 'expectedWait').reverse() - const timeMappedToSeconds = withOutliersRemoved.map(({ expectedWait, gasprice }) => { - const expectedTime = (new BigNumber(expectedWait)).times(Number(blockTime), 10).toNumber() - return { - expectedTime, - gasprice: (new BigNumber(gasprice, 10).toNumber()), - } - }) - - const timeRetrieved = Date.now() - dispatch(setApiEstimatesLastRetrieved(timeRetrieved)) - saveLocalStorageData(timeRetrieved, 'GAS_API_ESTIMATES_LAST_RETRIEVED') - saveLocalStorageData(timeMappedToSeconds, 'GAS_API_ESTIMATES') - - return timeMappedToSeconds - }) - : Promise.resolve(priceAndTimeEstimates.length - ? priceAndTimeEstimates - : loadLocalStorageData('GAS_API_ESTIMATES')) + : Promise.resolve( + priceAndTimeEstimates.length + ? priceAndTimeEstimates + : loadLocalStorageData('GAS_API_ESTIMATES'), + ) return promiseToFetch.then((estimates) => { dispatch(setPricesAndTimeEstimates(estimates)) @@ -451,7 +520,7 @@ export function fetchGasEstimates (blockTime) { } } -export function setCustomGasPriceForRetry (newPrice) { +export function setCustomGasPriceForRetry(newPrice) { return (dispatch) => { if (newPrice === '0x0') { const { fast } = loadLocalStorageData('BASIC_PRICE_ESTIMATES') @@ -462,73 +531,73 @@ export function setCustomGasPriceForRetry (newPrice) { } } -export function setBasicGasEstimateData (basicGasEstimateData) { +export function setBasicGasEstimateData(basicGasEstimateData) { return { type: SET_BASIC_GAS_ESTIMATE_DATA, value: basicGasEstimateData, } } -export function setPricesAndTimeEstimates (estimatedPricesAndTimes) { +export function setPricesAndTimeEstimates(estimatedPricesAndTimes) { return { type: SET_PRICE_AND_TIME_ESTIMATES, value: estimatedPricesAndTimes, } } -export function setCustomGasPrice (newPrice) { +export function setCustomGasPrice(newPrice) { return { type: SET_CUSTOM_GAS_PRICE, value: newPrice, } } -export function setCustomGasLimit (newLimit) { +export function setCustomGasLimit(newLimit) { return { type: SET_CUSTOM_GAS_LIMIT, value: newLimit, } } -export function setCustomGasTotal (newTotal) { +export function setCustomGasTotal(newTotal) { return { type: SET_CUSTOM_GAS_TOTAL, value: newTotal, } } -export function setCustomGasErrors (newErrors) { +export function setCustomGasErrors(newErrors) { return { type: SET_CUSTOM_GAS_ERRORS, value: newErrors, } } -export function setApiEstimatesLastRetrieved (retrievalTime) { +export function setApiEstimatesLastRetrieved(retrievalTime) { return { type: SET_API_ESTIMATES_LAST_RETRIEVED, value: retrievalTime, } } -export function setBasicApiEstimatesLastRetrieved (retrievalTime) { +export function setBasicApiEstimatesLastRetrieved(retrievalTime) { return { type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: retrievalTime, } } -export function setBasicPriceEstimatesLastRetrieved (retrievalTime) { +export function setBasicPriceEstimatesLastRetrieved(retrievalTime) { return { type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: retrievalTime, } } -export function resetCustomGasState () { +export function resetCustomGasState() { return { type: RESET_CUSTOM_GAS_STATE } } -export function resetCustomData () { +export function resetCustomData() { return { type: RESET_CUSTOM_DATA } } diff --git a/ui/app/ducks/history/history.js b/ui/app/ducks/history/history.js index 9b716375b..e74576f7f 100644 --- a/ui/app/ducks/history/history.js +++ b/ui/app/ducks/history/history.js @@ -31,7 +31,8 @@ export default reducer // Selectors -export const getMostRecentOverviewPage = (state) => state[name].mostRecentOverviewPage +export const getMostRecentOverviewPage = (state) => + state[name].mostRecentOverviewPage // Actions / action-creators diff --git a/ui/app/ducks/locale/locale.js b/ui/app/ducks/locale/locale.js index 5eecbad9b..e7f14c40a 100644 --- a/ui/app/ducks/locale/locale.js +++ b/ui/app/ducks/locale/locale.js @@ -1,6 +1,6 @@ import * as actionConstants from '../../store/actionConstants' -export default function reduceLocaleMessages (state = {}, { type, value }) { +export default function reduceLocaleMessages(state = {}, { type, value }) { switch (type) { case actionConstants.SET_CURRENT_LOCALE: return { diff --git a/ui/app/ducks/metamask/metamask.js b/ui/app/ducks/metamask/metamask.js index f9c259f82..61abf2559 100644 --- a/ui/app/ducks/metamask/metamask.js +++ b/ui/app/ducks/metamask/metamask.js @@ -1,7 +1,7 @@ import * as actionConstants from '../../store/actionConstants' import { ALERT_TYPES } from '../../../../app/scripts/controllers/alert' -export default function reduceMetamask (state = {}, action) { +export default function reduceMetamask(state = {}, action) { const metamaskState = { isInitialized: false, isUnlocked: false, @@ -50,7 +50,6 @@ export default function reduceMetamask (state = {}, action) { } switch (action.type) { - case actionConstants.UPDATE_METAMASK_STATE: return { ...metamaskState, ...action.value } @@ -206,7 +205,8 @@ export default function reduceMetamask (state = {}, action) { } // erase token-related state when switching back to native currency if (newSend.editingTransactionId && !newSend.token) { - const unapprovedTx = newSend?.unapprovedTxs?.[newSend.editingTransactionId] || {} + const unapprovedTx = + newSend?.unapprovedTxs?.[newSend.editingTransactionId] || {} const txParams = unapprovedTx.txParams || {} Object.assign(newSend, { tokenBalance: null, @@ -375,10 +375,13 @@ export const getCurrentLocale = (state) => state.metamask.currentLocale export const getAlertEnabledness = (state) => state.metamask.alertEnabledness -export const getInvalidCustomNetworkAlertEnabledness = (state) => getAlertEnabledness(state)[ALERT_TYPES.invalidCustomNetwork] +export const getInvalidCustomNetworkAlertEnabledness = (state) => + getAlertEnabledness(state)[ALERT_TYPES.invalidCustomNetwork] -export const getUnconnectedAccountAlertEnabledness = (state) => getAlertEnabledness(state)[ALERT_TYPES.unconnectedAccount] +export const getUnconnectedAccountAlertEnabledness = (state) => + getAlertEnabledness(state)[ALERT_TYPES.unconnectedAccount] -export const getUnconnectedAccountAlertShown = (state) => state.metamask.unconnectedAccountAlertShownOrigins +export const getUnconnectedAccountAlertShown = (state) => + state.metamask.unconnectedAccountAlertShownOrigins export const getTokens = (state) => state.metamask.tokens diff --git a/ui/app/ducks/send/send-duck.test.js b/ui/app/ducks/send/send-duck.test.js index 9731d5b2c..3c7ca415a 100644 --- a/ui/app/ducks/send/send-duck.test.js +++ b/ui/app/ducks/send/send-duck.test.js @@ -59,7 +59,10 @@ describe('Send Duck', function () { it('should set gasButtonGroupShown to true when receiving a SHOW_GAS_BUTTON_GROUP action', function () { assert.deepEqual( - SendReducer({ ...mockState, gasButtonGroupShown: false }, { type: SHOW_GAS_BUTTON_GROUP }), + SendReducer( + { ...mockState, gasButtonGroupShown: false }, + { type: SHOW_GAS_BUTTON_GROUP }, + ), { gasButtonGroupShown: true, ...mockState }, ) }) @@ -120,6 +123,9 @@ describe('Send Duck', function () { }) describe('updateSendErrors', function () { - assert.deepEqual(updateSendErrors('mockErrorObject'), { type: UPDATE_SEND_ERRORS, value: 'mockErrorObject' }) + assert.deepEqual(updateSendErrors('mockErrorObject'), { + type: UPDATE_SEND_ERRORS, + value: 'mockErrorObject', + }) }) }) diff --git a/ui/app/ducks/send/send.duck.js b/ui/app/ducks/send/send.duck.js index fce3ee3e9..c5202d442 100644 --- a/ui/app/ducks/send/send.duck.js +++ b/ui/app/ducks/send/send.duck.js @@ -13,7 +13,7 @@ const initState = { } // Reducer -export default function reducer (state = initState, action) { +export default function reducer(state = initState, action) { switch (action.type) { case OPEN_TO_DROPDOWN: return { @@ -51,29 +51,29 @@ export default function reducer (state = initState, action) { } // Action Creators -export function openToDropdown () { +export function openToDropdown() { return { type: OPEN_TO_DROPDOWN } } -export function closeToDropdown () { +export function closeToDropdown() { return { type: CLOSE_TO_DROPDOWN } } -export function showGasButtonGroup () { +export function showGasButtonGroup() { return { type: SHOW_GAS_BUTTON_GROUP } } -export function hideGasButtonGroup () { +export function hideGasButtonGroup() { return { type: HIDE_GAS_BUTTON_GROUP } } -export function updateSendErrors (errorObject) { +export function updateSendErrors(errorObject) { return { type: UPDATE_SEND_ERRORS, value: errorObject, } } -export function resetSendState () { +export function resetSendState() { return { type: RESET_SEND_STATE } } diff --git a/ui/app/ducks/swaps/swaps.js b/ui/app/ducks/swaps/swaps.js index 94c2d2af2..ca298e4f2 100644 --- a/ui/app/ducks/swaps/swaps.js +++ b/ui/app/ducks/swaps/swaps.js @@ -20,10 +20,23 @@ import { resetBackgroundSwapsState, setSwapsLiveness, } from '../../store/actions' -import { AWAITING_SWAP_ROUTE, BUILD_QUOTE_ROUTE, LOADING_QUOTES_ROUTE, SWAPS_ERROR_ROUTE, SWAPS_MAINTENANCE_ROUTE } from '../../helpers/constants/routes' +import { + AWAITING_SWAP_ROUTE, + BUILD_QUOTE_ROUTE, + LOADING_QUOTES_ROUTE, + SWAPS_ERROR_ROUTE, + SWAPS_MAINTENANCE_ROUTE, +} from '../../helpers/constants/routes' import { fetchSwapsFeatureLiveness } from '../../pages/swaps/swaps.util' import { calcGasTotal } from '../../pages/send/send.utils' -import { decimalToHex, getValueFromWeiHex, hexMax, decGWEIToHexWEI, hexToDecimal, hexWEIToDecGWEI } from '../../helpers/utils/conversions.util' +import { + decimalToHex, + getValueFromWeiHex, + hexMax, + decGWEIToHexWEI, + hexToDecimal, + hexWEIToDecGWEI, +} from '../../helpers/utils/conversions.util' import { calcTokenAmount } from '../../helpers/utils/token-util' import { getFastPriceEstimateInHexWEI, @@ -39,7 +52,11 @@ import { SWAPS_FETCH_ORDER_CONFLICT, } from '../../helpers/constants/swaps' import { SWAP, SWAP_APPROVAL } from '../../helpers/constants/transactions' -import { fetchBasicGasAndTimeEstimates, fetchGasEstimates, resetCustomGasState } from '../gas/gas.duck' +import { + fetchBasicGasAndTimeEstimates, + fetchGasEstimates, + resetCustomGasState, +} from '../gas/gas.duck' import { formatCurrency } from '../../helpers/utils/confirm-tx.util' const initialState = { @@ -110,25 +127,31 @@ export const getToToken = (state) => state.swaps.toToken export const getFetchingQuotes = (state) => state.swaps.fetchingQuotes -export const getQuotesFetchStartTime = (state) => state.swaps.quotesFetchStartTime +export const getQuotesFetchStartTime = (state) => + state.swaps.quotesFetchStartTime // Background selectors const getSwapsState = (state) => state.metamask.swapsState -export const getSwapsFeatureLiveness = (state) => state.metamask.swapsState.swapsFeatureIsLive +export const getSwapsFeatureLiveness = (state) => + state.metamask.swapsState.swapsFeatureIsLive -export const getBackgroundSwapRouteState = (state) => state.metamask.swapsState.routeState +export const getBackgroundSwapRouteState = (state) => + state.metamask.swapsState.routeState -export const getCustomSwapsGas = (state) => state.metamask.swapsState.customMaxGas +export const getCustomSwapsGas = (state) => + state.metamask.swapsState.customMaxGas -export const getCustomSwapsGasPrice = (state) => state.metamask.swapsState.customGasPrice +export const getCustomSwapsGasPrice = (state) => + state.metamask.swapsState.customGasPrice export const getFetchParams = (state) => state.metamask.swapsState.fetchParams export const getQuotes = (state) => state.metamask.swapsState.quotes -export const getQuotesLastFetched = (state) => state.metamask.swapsState.quotesLastFetched +export const getQuotesLastFetched = (state) => + state.metamask.swapsState.quotesLastFetched export const getSelectedQuote = (state) => { const { selectedAggId, quotes } = getSwapsState(state) @@ -137,11 +160,13 @@ export const getSelectedQuote = (state) => { export const getSwapsErrorKey = (state) => getSwapsState(state)?.errorKey -export const getShowQuoteLoadingScreen = (state) => state.swaps.showQuoteLoadingScreen +export const getShowQuoteLoadingScreen = (state) => + state.swaps.showQuoteLoadingScreen export const getSwapsTokens = (state) => state.metamask.swapsState.tokens -export const getSwapsWelcomeMessageSeenStatus = (state) => state.metamask.swapsWelcomeMessageHasBeenShown +export const getSwapsWelcomeMessageSeenStatus = (state) => + state.metamask.swapsWelcomeMessageHasBeenShown export const getTopQuote = (state) => { const { topAggId, quotes } = getSwapsState(state) @@ -152,11 +177,13 @@ export const getApproveTxId = (state) => state.metamask.swapsState.approveTxId export const getTradeTxId = (state) => state.metamask.swapsState.tradeTxId -export const getUsedQuote = (state) => getSelectedQuote(state) || getTopQuote(state) +export const getUsedQuote = (state) => + getSelectedQuote(state) || getTopQuote(state) // Compound selectors -export const getDestinationTokenInfo = (state) => getFetchParams(state)?.metaData?.destinationTokenInfo +export const getDestinationTokenInfo = (state) => + getFetchParams(state)?.metaData?.destinationTokenInfo export const getSwapsTradeTxParams = (state) => { const { selectedAggId, topAggId, quotes } = getSwapsState(state) @@ -231,7 +258,6 @@ export const prepareToLeaveSwaps = () => { dispatch(resetCustomGasState()) dispatch(clearSwapsState()) await dispatch(resetBackgroundSwapsState()) - } } @@ -240,11 +266,15 @@ export const fetchAndSetSwapsGasPriceInfo = () => { const basicEstimates = await dispatch(fetchBasicGasAndTimeEstimates()) dispatch(setSwapsTxGasPrice(decGWEIToHexWEI(basicEstimates.fastest))) await dispatch(fetchGasEstimates(basicEstimates.blockTime)) - } } -export const fetchQuotesAndSetQuoteState = (history, inputValue, maxSlippage, metaMetricsEvent) => { +export const fetchQuotesAndSetQuoteState = ( + history, + inputValue, + maxSlippage, + metaMetricsEvent, +) => { return async (dispatch, getState) => { let swapsFeatureIsLive = false try { @@ -263,15 +293,21 @@ export const fetchQuotesAndSetQuoteState = (history, inputValue, maxSlippage, me const fetchParams = getFetchParams(state) const selectedAccount = getSelectedAccount(state) const balanceError = getBalanceError(state) - const fetchParamsFromToken = fetchParams?.metaData?.sourceTokenInfo?.symbol === 'ETH' ? - { - ...ETH_SWAPS_TOKEN_OBJECT, - string: getValueFromWeiHex({ value: selectedAccount.balance, numberOfDecimals: 4, toDenomination: 'ETH' }), - balance: hexToDecimal(selectedAccount.balance), - } : - fetchParams?.metaData?.sourceTokenInfo + const fetchParamsFromToken = + fetchParams?.metaData?.sourceTokenInfo?.symbol === 'ETH' + ? { + ...ETH_SWAPS_TOKEN_OBJECT, + string: getValueFromWeiHex({ + value: selectedAccount.balance, + numberOfDecimals: 4, + toDenomination: 'ETH', + }), + balance: hexToDecimal(selectedAccount.balance), + } + : fetchParams?.metaData?.sourceTokenInfo const selectedFromToken = getFromToken(state) || fetchParamsFromToken || {} - const selectedToToken = getToToken(state) || fetchParams?.metaData?.destinationTokenInfo || {} + const selectedToToken = + getToToken(state) || fetchParams?.metaData?.destinationTokenInfo || {} const { address: fromTokenAddress, symbol: fromTokenSymbol, @@ -294,16 +330,41 @@ export const fetchQuotesAndSetQuoteState = (history, inputValue, maxSlippage, me let destinationTokenAddedForSwap = false if (toTokenSymbol !== 'ETH' && !contractExchangeRates[toTokenAddress]) { destinationTokenAddedForSwap = true - await dispatch(addToken(toTokenAddress, toTokenSymbol, toTokenDecimals, toTokenIconUrl, true)) + await dispatch( + addToken( + toTokenAddress, + toTokenSymbol, + toTokenDecimals, + toTokenIconUrl, + true, + ), + ) } - if (fromTokenSymbol !== 'ETH' && !contractExchangeRates[fromTokenAddress] && fromTokenBalance && (new BigNumber(fromTokenBalance, 16)).gt(0)) { - dispatch(addToken(fromTokenAddress, fromTokenSymbol, fromTokenDecimals, fromTokenIconUrl, true)) + if ( + fromTokenSymbol !== 'ETH' && + !contractExchangeRates[fromTokenAddress] && + fromTokenBalance && + new BigNumber(fromTokenBalance, 16).gt(0) + ) { + dispatch( + addToken( + fromTokenAddress, + fromTokenSymbol, + fromTokenDecimals, + fromTokenIconUrl, + true, + ), + ) } const swapsTokens = getSwapsTokens(state) - const sourceTokenInfo = swapsTokens?.find(({ address }) => address === fromTokenAddress) || selectedFromToken - const destinationTokenInfo = swapsTokens?.find(({ address }) => address === toTokenAddress) || selectedToToken + const sourceTokenInfo = + swapsTokens?.find(({ address }) => address === fromTokenAddress) || + selectedFromToken + const destinationTokenInfo = + swapsTokens?.find(({ address }) => address === toTokenAddress) || + selectedToToken dispatch(setFromToken(selectedFromToken)) @@ -330,27 +391,32 @@ export const fetchQuotesAndSetQuoteState = (history, inputValue, maxSlippage, me const fetchStartTime = Date.now() dispatch(setQuotesFetchStartTime(fetchStartTime)) - const fetchAndSetQuotesPromise = dispatch(fetchAndSetQuotes( - { - slippage: maxSlippage, - sourceToken: fromTokenAddress, - destinationToken: toTokenAddress, - value: inputValue, - fromAddress: selectedAccount.address, - destinationTokenAddedForSwap, - balanceError, - sourceDecimals: fromTokenDecimals, - }, - { - sourceTokenInfo, - destinationTokenInfo, - accountBalance: selectedAccount.balance, - }, - )) + const fetchAndSetQuotesPromise = dispatch( + fetchAndSetQuotes( + { + slippage: maxSlippage, + sourceToken: fromTokenAddress, + destinationToken: toTokenAddress, + value: inputValue, + fromAddress: selectedAccount.address, + destinationTokenAddedForSwap, + balanceError, + sourceDecimals: fromTokenDecimals, + }, + { + sourceTokenInfo, + destinationTokenInfo, + accountBalance: selectedAccount.balance, + }, + ), + ) const gasPriceFetchPromise = dispatch(fetchAndSetSwapsGasPriceInfo()) - const [[fetchedQuotes, selectedAggId]] = await Promise.all([fetchAndSetQuotesPromise, gasPriceFetchPromise]) + const [[fetchedQuotes, selectedAggId]] = await Promise.all([ + fetchAndSetQuotesPromise, + gasPriceFetchPromise, + ]) if (Object.values(fetchedQuotes)?.length === 0) { metaMetricsEvent({ @@ -386,7 +452,10 @@ export const fetchQuotesAndSetQuoteState = (history, inputValue, maxSlippage, me token_from: fromTokenSymbol, token_from_amount: String(inputValue), token_to: toTokenSymbol, - token_to_amount: calcTokenAmount(newSelectedQuote.destinationAmount, newSelectedQuote.decimals || 18), + token_to_amount: calcTokenAmount( + newSelectedQuote.destinationAmount, + newSelectedQuote.decimals || 18, + ), request_type: balanceError ? 'Quote' : 'Order', slippage: maxSlippage, custom_slippage: maxSlippage !== 2, @@ -441,21 +510,40 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => { const usedQuote = getUsedQuote(state) const usedTradeTxParams = usedQuote.trade - const estimatedGasLimit = new BigNumber(usedQuote?.gasEstimate || decimalToHex(usedQuote?.averageGas || 0), 16) - const estimatedGasLimitWithMultiplier = estimatedGasLimit.times(1.4, 10).round(0).toString(16) - const maxGasLimit = customSwapsGas || hexMax((`0x${decimalToHex(usedQuote?.maxGas || 0)}`), estimatedGasLimitWithMultiplier) + const estimatedGasLimit = new BigNumber( + usedQuote?.gasEstimate || decimalToHex(usedQuote?.averageGas || 0), + 16, + ) + const estimatedGasLimitWithMultiplier = estimatedGasLimit + .times(1.4, 10) + .round(0) + .toString(16) + const maxGasLimit = + customSwapsGas || + hexMax( + `0x${decimalToHex(usedQuote?.maxGas || 0)}`, + estimatedGasLimitWithMultiplier, + ) usedTradeTxParams.gas = maxGasLimit const customConvertGasPrice = getCustomSwapsGasPrice(state) const tradeTxParams = getSwapsTradeTxParams(state) const fastGasEstimate = getFastPriceEstimateInHexWEI(state) - const usedGasPrice = customConvertGasPrice || tradeTxParams?.gasPrice || fastGasEstimate + const usedGasPrice = + customConvertGasPrice || tradeTxParams?.gasPrice || fastGasEstimate usedTradeTxParams.gasPrice = usedGasPrice const conversionRate = getConversionRate(state) - const destinationValue = calcTokenAmount(usedQuote.destinationAmount, destinationTokenInfo.decimals || 18).toPrecision(8) - const usedGasLimitEstimate = usedQuote?.gasEstimateWithRefund || (`0x${decimalToHex(usedQuote?.averageGas || 0)}`) - const totalGasLimitEstimate = (new BigNumber(usedGasLimitEstimate, 16)).plus(usedQuote.approvalNeeded?.gas || '0x0', 16).toString(16) + const destinationValue = calcTokenAmount( + usedQuote.destinationAmount, + destinationTokenInfo.decimals || 18, + ).toPrecision(8) + const usedGasLimitEstimate = + usedQuote?.gasEstimateWithRefund || + `0x${decimalToHex(usedQuote?.averageGas || 0)}` + const totalGasLimitEstimate = new BigNumber(usedGasLimitEstimate, 16) + .plus(usedQuote.approvalNeeded?.gas || '0x0', 16) + .toString(16) const gasEstimateTotalInEth = getValueFromWeiHex({ value: calcGasTotal(totalGasLimitEstimate, usedGasPrice), toCurrency: 'usd', @@ -472,8 +560,12 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => { custom_slippage: slippage !== 2, best_quote_source: getTopQuote(state)?.aggregator, available_quotes: getQuotes(state)?.length, - other_quote_selected: usedQuote.aggregator !== getTopQuote(state)?.aggregator, - other_quote_selected_source: usedQuote.aggregator === getTopQuote(state)?.aggregator ? '' : usedQuote.aggregator, + other_quote_selected: + usedQuote.aggregator !== getTopQuote(state)?.aggregator, + other_quote_selected_source: + usedQuote.aggregator === getTopQuote(state)?.aggregator + ? '' + : usedQuote.aggregator, gas_fees: formatCurrency(gasEstimateTotalInEth, 'usd')?.slice(1), estimated_gas: estimatedGasLimit.toString(10), suggested_gas_price: hexWEIToDecGWEI(usedGasPrice), @@ -487,18 +579,32 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => { } metaMetricsEvent({ ...metaMetricsConfig }) - metaMetricsEvent({ ...metaMetricsConfig, excludeMetaMetricsId: true, properties: swapMetaData }) + metaMetricsEvent({ + ...metaMetricsConfig, + excludeMetaMetricsId: true, + properties: swapMetaData, + }) let finalApproveTxMeta const approveTxParams = getApproveTxParams(state) if (approveTxParams) { - const approveTxMeta = await dispatch(addUnapprovedTransaction({ ...approveTxParams, amount: '0x0' }, 'metamask')) + const approveTxMeta = await dispatch( + addUnapprovedTransaction( + { ...approveTxParams, amount: '0x0' }, + 'metamask', + ), + ) await dispatch(setApproveTxId(approveTxMeta.id)) - finalApproveTxMeta = await (dispatch(updateTransaction({ - ...approveTxMeta, - transactionCategory: SWAP_APPROVAL, - sourceTokenSymbol: sourceTokenInfo.symbol, - }, true))) + finalApproveTxMeta = await dispatch( + updateTransaction( + { + ...approveTxMeta, + transactionCategory: SWAP_APPROVAL, + sourceTokenSymbol: sourceTokenInfo.symbol, + }, + true, + ), + ) try { await dispatch(updateAndApproveTx(finalApproveTxMeta, true)) } catch (e) { @@ -508,19 +614,26 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => { } } - const tradeTxMeta = await dispatch(addUnapprovedTransaction(usedTradeTxParams, 'metamask')) + const tradeTxMeta = await dispatch( + addUnapprovedTransaction(usedTradeTxParams, 'metamask'), + ) dispatch(setTradeTxId(tradeTxMeta.id)) - const finalTradeTxMeta = await (dispatch(updateTransaction({ - ...tradeTxMeta, - sourceTokenSymbol: sourceTokenInfo.symbol, - destinationTokenSymbol: destinationTokenInfo.symbol, - transactionCategory: SWAP, - destinationTokenDecimals: destinationTokenInfo.decimals, - destinationTokenAddress: destinationTokenInfo.address, - swapMetaData, - swapTokenValue, - approvalTxId: finalApproveTxMeta?.id, - }, true))) + const finalTradeTxMeta = await dispatch( + updateTransaction( + { + ...tradeTxMeta, + sourceTokenSymbol: sourceTokenInfo.symbol, + destinationTokenSymbol: destinationTokenInfo.symbol, + transactionCategory: SWAP, + destinationTokenDecimals: destinationTokenInfo.decimals, + destinationTokenAddress: destinationTokenInfo.address, + swapMetaData, + swapTokenValue, + approvalTxId: finalApproveTxMeta?.id, + }, + true, + ), + ) try { await dispatch(updateAndApproveTx(finalTradeTxMeta, true)) } catch (e) { diff --git a/ui/app/helpers/constants/connected-sites.js b/ui/app/helpers/constants/connected-sites.js index b5d6ad6bd..717460f29 100644 --- a/ui/app/helpers/constants/connected-sites.js +++ b/ui/app/helpers/constants/connected-sites.js @@ -1,3 +1,4 @@ export const STATUS_CONNECTED = 'STATUS_CONNECTED' -export const STATUS_CONNECTED_TO_ANOTHER_ACCOUNT = 'STATUS_CONNECTED_TO_ANOTHER_ACCOUNT' +export const STATUS_CONNECTED_TO_ANOTHER_ACCOUNT = + 'STATUS_CONNECTED_TO_ANOTHER_ACCOUNT' export const STATUS_NOT_CONNECTED = 'STATUS_NOT_CONNECTED' diff --git a/ui/app/helpers/constants/routes.js b/ui/app/helpers/constants/routes.js index d05a6c24c..efd09c151 100644 --- a/ui/app/helpers/constants/routes.js +++ b/ui/app/helpers/constants/routes.js @@ -43,7 +43,8 @@ const INITIALIZE_ROUTE = '/initialize' const INITIALIZE_WELCOME_ROUTE = '/initialize/welcome' const INITIALIZE_UNLOCK_ROUTE = '/initialize/unlock' const INITIALIZE_CREATE_PASSWORD_ROUTE = '/initialize/create-password' -const INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE = '/initialize/create-password/import-with-seed-phrase' +const INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE = + '/initialize/create-password/import-with-seed-phrase' const INITIALIZE_SELECT_ACTION_ROUTE = '/initialize/select-action' const INITIALIZE_SEED_PHRASE_ROUTE = '/initialize/seed-phrase' const INITIALIZE_BACKUP_SEED_PHRASE_ROUTE = '/initialize/backup-seed-phrase' @@ -111,12 +112,16 @@ const PATH_NAME_MAP = { [INITIALIZE_WELCOME_ROUTE]: 'Install Welcome Page', [INITIALIZE_UNLOCK_ROUTE]: 'Initialization Unlock page', [INITIALIZE_CREATE_PASSWORD_ROUTE]: 'Initialization Create Password Page', - [INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE]: 'Initialization Import Account With Seed Phrase Page', - [INITIALIZE_SELECT_ACTION_ROUTE]: 'Initialization Choose Restore or New Account Page', + [INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE]: + 'Initialization Import Account With Seed Phrase Page', + [INITIALIZE_SELECT_ACTION_ROUTE]: + 'Initialization Choose Restore or New Account Page', [INITIALIZE_SEED_PHRASE_ROUTE]: 'Initialization Seed Phrase Page', - [INITIALIZE_BACKUP_SEED_PHRASE_ROUTE]: 'Initialization Backup Seed Phrase Page', + [INITIALIZE_BACKUP_SEED_PHRASE_ROUTE]: + 'Initialization Backup Seed Phrase Page', [INITIALIZE_END_OF_FLOW_ROUTE]: 'End of Initialization Page', - [INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE]: 'Initialization Confirm Seed Phrase Page', + [INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE]: + 'Initialization Confirm Seed Phrase Page', [INITIALIZE_METAMETRICS_OPT_IN_ROUTE]: 'MetaMetrics Opt In Page', [BUILD_QUOTE_ROUTE]: 'Swaps Build Quote Page', [VIEW_QUOTE_ROUTE]: 'Swaps View Quotes Page', diff --git a/ui/app/helpers/constants/swaps.js b/ui/app/helpers/constants/swaps.js index a20000a0c..af22f84ea 100644 --- a/ui/app/helpers/constants/swaps.js +++ b/ui/app/helpers/constants/swaps.js @@ -1,5 +1,6 @@ // An address that the metaswap-api recognizes as ETH, in place of the token address that ERC-20 tokens have -export const ETH_SWAPS_TOKEN_ADDRESS = '0x0000000000000000000000000000000000000000' +export const ETH_SWAPS_TOKEN_ADDRESS = + '0x0000000000000000000000000000000000000000' export const ETH_SWAPS_TOKEN_OBJECT = { symbol: 'ETH', @@ -19,4 +20,5 @@ export const SWAPS_FETCH_ORDER_CONFLICT = 'swaps-fetch-order-conflict' // A gas value for ERC20 approve calls that should be sufficient for all ERC20 approve implementations export const DEFAULT_ERC20_APPROVE_GAS = '0x1d4c0' -export const SWAPS_CONTRACT_ADDRESS = '0x881d40237659c251811cec9c364ef91dc08d300c' +export const SWAPS_CONTRACT_ADDRESS = + '0x881d40237659c251811cec9c364ef91dc08d300c' diff --git a/ui/app/helpers/higher-order-components/authenticated/authenticated.component.js b/ui/app/helpers/higher-order-components/authenticated/authenticated.component.js index c195d0e21..585e34707 100644 --- a/ui/app/helpers/higher-order-components/authenticated/authenticated.component.js +++ b/ui/app/helpers/higher-order-components/authenticated/authenticated.component.js @@ -3,12 +3,12 @@ import PropTypes from 'prop-types' import { Redirect, Route } from 'react-router-dom' import { UNLOCK_ROUTE, INITIALIZE_ROUTE } from '../../constants/routes' -export default function Authenticated (props) { +export default function Authenticated(props) { const { isUnlocked, completedOnboarding } = props switch (true) { case isUnlocked && completedOnboarding: - return + return case !completedOnboarding: return default: diff --git a/ui/app/helpers/higher-order-components/authenticated/authenticated.container.js b/ui/app/helpers/higher-order-components/authenticated/authenticated.container.js index 3b67b2cfe..1f956957b 100644 --- a/ui/app/helpers/higher-order-components/authenticated/authenticated.container.js +++ b/ui/app/helpers/higher-order-components/authenticated/authenticated.container.js @@ -2,7 +2,9 @@ import { connect } from 'react-redux' import Authenticated from './authenticated.component' const mapStateToProps = (state) => { - const { metamask: { isUnlocked, completedOnboarding } } = state + const { + metamask: { isUnlocked, completedOnboarding }, + } = state return { isUnlocked, diff --git a/ui/app/helpers/higher-order-components/feature-toggled-route.js b/ui/app/helpers/higher-order-components/feature-toggled-route.js index ed325f283..bcfca050b 100644 --- a/ui/app/helpers/higher-order-components/feature-toggled-route.js +++ b/ui/app/helpers/higher-order-components/feature-toggled-route.js @@ -2,8 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import { Redirect, Route } from 'react-router-dom' -export default function FeatureToggledRoute ({ flag, redirectRoute, ...props }) { - +export default function FeatureToggledRoute({ flag, redirectRoute, ...props }) { if (flag) { return } diff --git a/ui/app/helpers/higher-order-components/initialized/initialized.component.js b/ui/app/helpers/higher-order-components/initialized/initialized.component.js index 2042c0046..88a4deb1d 100644 --- a/ui/app/helpers/higher-order-components/initialized/initialized.component.js +++ b/ui/app/helpers/higher-order-components/initialized/initialized.component.js @@ -3,10 +3,12 @@ import PropTypes from 'prop-types' import { Redirect, Route } from 'react-router-dom' import { INITIALIZE_ROUTE } from '../../constants/routes' -export default function Initialized (props) { - return props.completedOnboarding - ? - : +export default function Initialized(props) { + return props.completedOnboarding ? ( + + ) : ( + + ) } Initialized.propTypes = { diff --git a/ui/app/helpers/higher-order-components/initialized/initialized.container.js b/ui/app/helpers/higher-order-components/initialized/initialized.container.js index 245655962..d7b5633a4 100644 --- a/ui/app/helpers/higher-order-components/initialized/initialized.container.js +++ b/ui/app/helpers/higher-order-components/initialized/initialized.container.js @@ -2,7 +2,9 @@ import { connect } from 'react-redux' import Initialized from './initialized.component' const mapStateToProps = (state) => { - const { metamask: { completedOnboarding } } = state + const { + metamask: { completedOnboarding }, + } = state return { completedOnboarding, diff --git a/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js b/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js index e14adb2ce..df1b20cb4 100644 --- a/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js +++ b/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js @@ -1,4 +1,3 @@ - import assert from 'assert' import configureMockStore from 'redux-mock-store' import { mount } from 'enzyme' @@ -21,14 +20,10 @@ const mockState = { describe('withModalProps', function () { it('should return a component wrapped with modal state props', function () { - const TestComponent = () => ( -
    Testing
    - ) + const TestComponent = () =>
    Testing
    const WrappedComponent = withModalProps(TestComponent) const store = configureMockStore()(mockState) - const wrapper = mount( - , - ) + const wrapper = mount() assert.ok(wrapper) const testComponent = wrapper.find(TestComponent).at(0) diff --git a/ui/app/helpers/higher-order-components/with-modal-props/with-modal-props.js b/ui/app/helpers/higher-order-components/with-modal-props/with-modal-props.js index b702ff24f..88dbfa925 100644 --- a/ui/app/helpers/higher-order-components/with-modal-props/with-modal-props.js +++ b/ui/app/helpers/higher-order-components/with-modal-props/with-modal-props.js @@ -16,6 +16,6 @@ const mapDispatchToProps = (dispatch) => { } } -export default function withModalProps (Component) { +export default function withModalProps(Component) { return connect(mapStateToProps, mapDispatchToProps)(Component) } diff --git a/ui/app/helpers/utils/common.util.js b/ui/app/helpers/utils/common.util.js index 4df816941..0c0d49c15 100644 --- a/ui/app/helpers/utils/common.util.js +++ b/ui/app/helpers/utils/common.util.js @@ -1,5 +1,3 @@ -export function camelCaseToCapitalize (str = '') { - return str - .replace(/([A-Z])/ug, ' $1') - .replace(/^./u, (s) => s.toUpperCase()) +export function camelCaseToCapitalize(str = '') { + return str.replace(/([A-Z])/gu, ' $1').replace(/^./u, (s) => s.toUpperCase()) } diff --git a/ui/app/helpers/utils/confirm-tx.util.js b/ui/app/helpers/utils/confirm-tx.util.js index 272f56fcc..5232f82a0 100644 --- a/ui/app/helpers/utils/confirm-tx.util.js +++ b/ui/app/helpers/utils/confirm-tx.util.js @@ -11,30 +11,34 @@ import { conversionGreaterThan, } from './conversion-util' -export function increaseLastGasPrice (lastGasPrice) { - return ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice || '0x0', 1.1, { - multiplicandBase: 16, - multiplierBase: 10, - toNumericBase: 'hex', - })) +export function increaseLastGasPrice(lastGasPrice) { + return ethUtil.addHexPrefix( + multiplyCurrencies(lastGasPrice || '0x0', 1.1, { + multiplicandBase: 16, + multiplierBase: 10, + toNumericBase: 'hex', + }), + ) } -export function hexGreaterThan (a, b) { +export function hexGreaterThan(a, b) { return conversionGreaterThan( { value: a, fromNumericBase: 'hex' }, { value: b, fromNumericBase: 'hex' }, ) } -export function getHexGasTotal ({ gasLimit, gasPrice }) { - return ethUtil.addHexPrefix(multiplyCurrencies(gasLimit || '0x0', gasPrice || '0x0', { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, - })) +export function getHexGasTotal({ gasLimit, gasPrice }) { + return ethUtil.addHexPrefix( + multiplyCurrencies(gasLimit || '0x0', gasPrice || '0x0', { + toNumericBase: 'hex', + multiplicandBase: 16, + multiplierBase: 16, + }), + ) } -export function addEth (...args) { +export function addEth(...args) { return args.reduce((acc, base) => { return addCurrencies(acc, base, { toNumericBase: 'dec', @@ -43,7 +47,7 @@ export function addEth (...args) { }) } -export function addFiat (...args) { +export function addFiat(...args) { return args.reduce((acc, base) => { return addCurrencies(acc, base, { toNumericBase: 'dec', @@ -52,7 +56,7 @@ export function addFiat (...args) { }) } -export function getValueFromWeiHex ({ +export function getValueFromWeiHex({ value, fromCurrency = 'ETH', toCurrency, @@ -72,7 +76,7 @@ export function getValueFromWeiHex ({ }) } -export function getTransactionFee ({ +export function getTransactionFee({ value, fromCurrency = 'ETH', toCurrency, @@ -90,15 +94,18 @@ export function getTransactionFee ({ }) } -export function formatCurrency (value, currencyCode) { +export function formatCurrency(value, currencyCode) { const upperCaseCurrencyCode = currencyCode.toUpperCase() return currencies.find((currency) => currency.code === upperCaseCurrencyCode) - ? currencyFormatter.format(Number(value), { code: upperCaseCurrencyCode, style: 'currency' }) + ? currencyFormatter.format(Number(value), { + code: upperCaseCurrencyCode, + style: 'currency', + }) : value } -export function convertTokenToFiat ({ +export function convertTokenToFiat({ value, fromCurrency = 'ETH', toCurrency, @@ -117,7 +124,7 @@ export function convertTokenToFiat ({ }) } -export function hasUnconfirmedTransactions (state) { +export function hasUnconfirmedTransactions(state) { return unconfirmedTransactionsCountSelector(state) > 0 } @@ -128,10 +135,12 @@ export function hasUnconfirmedTransactions (state) { * @returns {string} The rounded number, or the original number if no * rounding was necessary. */ -export function roundExponential (decimalString) { +export function roundExponential(decimalString) { const PRECISION = 4 const bigNumberValue = new BigNumber(decimalString) // In JS, numbers with exponentials greater than 20 get displayed as an exponential. - return bigNumberValue.e > 20 ? bigNumberValue.toPrecision(PRECISION) : decimalString + return bigNumberValue.e > 20 + ? bigNumberValue.toPrecision(PRECISION) + : decimalString } diff --git a/ui/app/helpers/utils/confirm-tx.util.test.js b/ui/app/helpers/utils/confirm-tx.util.test.js index 065631c7d..0db49ef89 100644 --- a/ui/app/helpers/utils/confirm-tx.util.test.js +++ b/ui/app/helpers/utils/confirm-tx.util.test.js @@ -16,31 +16,19 @@ describe('Confirm Transaction utils', function () { describe('hexGreaterThan', function () { it('should return true if the first value is greater than the second value', function () { - assert.equal( - utils.hexGreaterThan('0xb', '0xa'), - true, - ) + assert.equal(utils.hexGreaterThan('0xb', '0xa'), true) }) it('should return false if the first value is less than the second value', function () { - assert.equal( - utils.hexGreaterThan('0xa', '0xb'), - false, - ) + assert.equal(utils.hexGreaterThan('0xa', '0xb'), false) }) it('should return false if the first value is equal to the second value', function () { - assert.equal( - utils.hexGreaterThan('0xa', '0xa'), - false, - ) + assert.equal(utils.hexGreaterThan('0xa', '0xa'), false) }) it('should correctly compare prefixed and non-prefixed hex values', function () { - assert.equal( - utils.hexGreaterThan('0xb', 'a'), - true, - ) + assert.equal(utils.hexGreaterThan('0xb', 'a'), true) }) }) @@ -62,15 +50,20 @@ describe('Confirm Transaction utils', function () { describe('addEth', function () { it('should add two values together rounding to 6 decimal places', function () { - assert.equal( - utils.addEth('0.12345678', '0'), - '0.123457', - ) + assert.equal(utils.addEth('0.12345678', '0'), '0.123457') }) it('should add any number of values together rounding to 6 decimal places', function () { assert.equal( - utils.addEth('0.1', '0.02', '0.003', '0.0004', '0.00005', '0.000006', '0.0000007'), + utils.addEth( + '0.1', + '0.02', + '0.003', + '0.0004', + '0.00005', + '0.000006', + '0.0000007', + ), '0.123457', ) }) @@ -78,15 +71,20 @@ describe('Confirm Transaction utils', function () { describe('addFiat', function () { it('should add two values together rounding to 2 decimal places', function () { - assert.equal( - utils.addFiat('0.12345678', '0'), - '0.12', - ) + assert.equal(utils.addFiat('0.12345678', '0'), '0.12') }) it('should add any number of values together rounding to 2 decimal places', function () { assert.equal( - utils.addFiat('0.1', '0.02', '0.003', '0.0004', '0.00005', '0.000006', '0.0000007'), + utils.addFiat( + '0.1', + '0.02', + '0.003', + '0.0004', + '0.00005', + '0.000006', + '0.0000007', + ), '0.12', ) }) @@ -95,7 +93,10 @@ describe('Confirm Transaction utils', function () { describe('getValueFromWeiHex', function () { it('should get the transaction amount in ETH', function () { const ethTransactionAmount = utils.getValueFromWeiHex({ - value: '0xde0b6b3a7640000', toCurrency: 'ETH', conversionRate: 468.58, numberOfDecimals: 6, + value: '0xde0b6b3a7640000', + toCurrency: 'ETH', + conversionRate: 468.58, + numberOfDecimals: 6, }) assert.equal(ethTransactionAmount, '1') @@ -103,7 +104,10 @@ describe('Confirm Transaction utils', function () { it('should get the transaction amount in fiat', function () { const fiatTransactionAmount = utils.getValueFromWeiHex({ - value: '0xde0b6b3a7640000', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2, + value: '0xde0b6b3a7640000', + toCurrency: 'usd', + conversionRate: 468.58, + numberOfDecimals: 2, }) assert.equal(fiatTransactionAmount, '468.58') @@ -113,7 +117,10 @@ describe('Confirm Transaction utils', function () { describe('getTransactionFee', function () { it('should get the transaction fee in ETH', function () { const ethTransactionFee = utils.getTransactionFee({ - value: '0x1319718a5000', toCurrency: 'ETH', conversionRate: 468.58, numberOfDecimals: 6, + value: '0x1319718a5000', + toCurrency: 'ETH', + conversionRate: 468.58, + numberOfDecimals: 6, }) assert.equal(ethTransactionFee, '0.000021') @@ -121,7 +128,10 @@ describe('Confirm Transaction utils', function () { it('should get the transaction fee in fiat', function () { const fiatTransactionFee = utils.getTransactionFee({ - value: '0x1319718a5000', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2, + value: '0x1319718a5000', + toCurrency: 'usd', + conversionRate: 468.58, + numberOfDecimals: 2, }) assert.equal(fiatTransactionFee, '0.01') diff --git a/ui/app/helpers/utils/conversion-util.js b/ui/app/helpers/utils/conversion-util.js index 152913b50..141f6c5d7 100644 --- a/ui/app/helpers/utils/conversion-util.js +++ b/ui/app/helpers/utils/conversion-util.js @@ -1,25 +1,25 @@ /* Currency Conversion Utility -* This utility function can be used for converting currency related values within metamask. -* The caller should be able to pass it a value, along with information about the value's -* numeric base, denomination and currency, and the desired numeric base, denomination and -* currency. It should return a single value. -* -* @param {(number | string | BN)} value - The value to convert. -* @param {Object} [options] Options to specify details of the conversion -* @param {string} [options.fromCurrency = 'ETH' | 'USD'] The currency of the passed value -* @param {string} [options.toCurrency = 'ETH' | 'USD'] The desired currency of the result -* @param {string} [options.fromNumericBase = 'hex' | 'dec' | 'BN'] The numeric basic of the passed value. -* @param {string} [options.toNumericBase = 'hex' | 'dec' | 'BN'] The desired numeric basic of the result. -* @param {string} [options.fromDenomination = 'WEI'] The denomination of the passed value -* @param {string} [options.numberOfDecimals] The desired number of decimals in the result -* @param {string} [options.roundDown] The desired number of decimals to round down to -* @param {number} [options.conversionRate] The rate to use to make the fromCurrency -> toCurrency conversion -* @returns {(number | string | BN)} -* -* The utility passes value along with the options as a single object to the `converter` function. -* `converter` conditional modifies the supplied `value` property, depending -* on the accompanying options. -*/ + * This utility function can be used for converting currency related values within metamask. + * The caller should be able to pass it a value, along with information about the value's + * numeric base, denomination and currency, and the desired numeric base, denomination and + * currency. It should return a single value. + * + * @param {(number | string | BN)} value - The value to convert. + * @param {Object} [options] Options to specify details of the conversion + * @param {string} [options.fromCurrency = 'ETH' | 'USD'] The currency of the passed value + * @param {string} [options.toCurrency = 'ETH' | 'USD'] The desired currency of the result + * @param {string} [options.fromNumericBase = 'hex' | 'dec' | 'BN'] The numeric basic of the passed value. + * @param {string} [options.toNumericBase = 'hex' | 'dec' | 'BN'] The desired numeric basic of the result. + * @param {string} [options.fromDenomination = 'WEI'] The denomination of the passed value + * @param {string} [options.numberOfDecimals] The desired number of decimals in the result + * @param {string} [options.roundDown] The desired number of decimals to round down to + * @param {number} [options.conversionRate] The rate to use to make the fromCurrency -> toCurrency conversion + * @returns {(number | string | BN)} + * + * The utility passes value along with the options as a single object to the `converter` function. + * `converter` conditional modifies the supplied `value` property, depending + * on the accompanying options. + */ import BigNumber from 'bignumber.js' @@ -50,7 +50,7 @@ const toSpecifiedDenomination = { } const baseChange = { hex: (n) => n.toString(16), - dec: (n) => (new BigNumber(n)).toString(10), + dec: (n) => new BigNumber(n).toString(10), BN: (n) => new BN(n.toString(16)), } @@ -92,7 +92,9 @@ const converter = ({ invertConversionRate, roundDown, }) => { - let convertedValue = fromNumericBase ? toBigNumber[fromNumericBase](value) : value + let convertedValue = fromNumericBase + ? toBigNumber[fromNumericBase](value) + : value if (fromDenomination) { convertedValue = toNormalizedDenomination[fromDenomination](convertedValue) @@ -100,7 +102,9 @@ const converter = ({ if (fromCurrency !== toCurrency) { if (conversionRate === null || conversionRate === undefined) { - throw new Error(`Converting from ${fromCurrency} to ${toCurrency} requires a conversionRate, but one was not provided`) + throw new Error( + `Converting from ${fromCurrency} to ${toCurrency} requires a conversionRate, but one was not provided`, + ) } let rate = toBigNumber.dec(conversionRate) if (invertConversionRate) { @@ -114,7 +118,10 @@ const converter = ({ } if (numberOfDecimals) { - convertedValue = convertedValue.round(numberOfDecimals, BigNumber.ROUND_HALF_DOWN) + convertedValue = convertedValue.round( + numberOfDecimals, + BigNumber.ROUND_HALF_DOWN, + ) } if (roundDown) { @@ -127,36 +134,37 @@ const converter = ({ return convertedValue } -const conversionUtil = (value, { - fromCurrency = null, - toCurrency = fromCurrency, - fromNumericBase, - toNumericBase, - fromDenomination, - toDenomination, - numberOfDecimals, - conversionRate, - invertConversionRate, -}) => converter({ - fromCurrency, - toCurrency, - fromNumericBase, - toNumericBase, - fromDenomination, - toDenomination, - numberOfDecimals, - conversionRate, - invertConversionRate, - value: value || '0', -}) +const conversionUtil = ( + value, + { + fromCurrency = null, + toCurrency = fromCurrency, + fromNumericBase, + toNumericBase, + fromDenomination, + toDenomination, + numberOfDecimals, + conversionRate, + invertConversionRate, + }, +) => + converter({ + fromCurrency, + toCurrency, + fromNumericBase, + toNumericBase, + fromDenomination, + toDenomination, + numberOfDecimals, + conversionRate, + invertConversionRate, + value: value || '0', + }) const getBigNumber = (value, base) => { // We don't include 'number' here, because BigNumber will throw if passed // a number primitive it considers unsafe. - if ( - typeof value === 'string' || - value instanceof BigNumber - ) { + if (typeof value === 'string' || value instanceof BigNumber) { return new BigNumber(value, base) } @@ -164,11 +172,7 @@ const getBigNumber = (value, base) => { } const addCurrencies = (a, b, options = {}) => { - const { - aBase, - bBase, - ...conversionOptions - } = options + const { aBase, bBase, ...conversionOptions } = options const value = getBigNumber(a, aBase).add(getBigNumber(b, bBase)) return converter({ @@ -178,13 +182,8 @@ const addCurrencies = (a, b, options = {}) => { } const subtractCurrencies = (a, b, options = {}) => { - const { - aBase, - bBase, - ...conversionOptions - } = options - const value = getBigNumber(a, aBase) - .minus(getBigNumber(b, bBase)) + const { aBase, bBase, ...conversionOptions } = options + const value = getBigNumber(a, aBase).minus(getBigNumber(b, bBase)) return converter({ value, @@ -193,14 +192,11 @@ const subtractCurrencies = (a, b, options = {}) => { } const multiplyCurrencies = (a, b, options = {}) => { - const { - multiplicandBase, - multiplierBase, - ...conversionOptions - } = options + const { multiplicandBase, multiplierBase, ...conversionOptions } = options - const value = getBigNumber(a, multiplicandBase) - .times(getBigNumber(b, multiplierBase)) + const value = getBigNumber(a, multiplicandBase).times( + getBigNumber(b, multiplierBase), + ) return converter({ value, @@ -208,30 +204,21 @@ const multiplyCurrencies = (a, b, options = {}) => { }) } -const conversionGreaterThan = ( - { ...firstProps }, - { ...secondProps }, -) => { +const conversionGreaterThan = ({ ...firstProps }, { ...secondProps }) => { const firstValue = converter({ ...firstProps }) const secondValue = converter({ ...secondProps }) return firstValue.gt(secondValue) } -const conversionLessThan = ( - { ...firstProps }, - { ...secondProps }, -) => { +const conversionLessThan = ({ ...firstProps }, { ...secondProps }) => { const firstValue = converter({ ...firstProps }) const secondValue = converter({ ...secondProps }) return firstValue.lt(secondValue) } -const conversionMax = ( - { ...firstProps }, - { ...secondProps }, -) => { +const conversionMax = ({ ...firstProps }, { ...secondProps }) => { const firstIsGreater = conversionGreaterThan( { ...firstProps }, { ...secondProps }, @@ -240,19 +227,13 @@ const conversionMax = ( return firstIsGreater ? firstProps.value : secondProps.value } -const conversionGTE = ( - { ...firstProps }, - { ...secondProps }, -) => { +const conversionGTE = ({ ...firstProps }, { ...secondProps }) => { const firstValue = converter({ ...firstProps }) const secondValue = converter({ ...secondProps }) return firstValue.greaterThanOrEqualTo(secondValue) } -const conversionLTE = ( - { ...firstProps }, - { ...secondProps }, -) => { +const conversionLTE = ({ ...firstProps }, { ...secondProps }) => { const firstValue = converter({ ...firstProps }) const secondValue = converter({ ...secondProps }) return firstValue.lessThanOrEqualTo(secondValue) diff --git a/ui/app/helpers/utils/conversion-util.test.js b/ui/app/helpers/utils/conversion-util.test.js index 9c570f95d..22436977a 100644 --- a/ui/app/helpers/utils/conversion-util.test.js +++ b/ui/app/helpers/utils/conversion-util.test.js @@ -22,38 +22,154 @@ describe('conversion utils', function () { describe('conversionUtil', function () { it('Returns expected types', function () { - const conv1 = conversionUtil(1000000000000000000, { fromNumericBase: 'dec', toNumericBase: 'hex' }) - const conv2 = conversionUtil(1, { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'WEI' }) - assert(typeof conv1 === 'string', 'conversion 1 should return type string') + const conv1 = conversionUtil(1000000000000000000, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + }) + const conv2 = conversionUtil(1, { + fromNumericBase: 'dec', + fromDenomination: 'ETH', + toDenomination: 'WEI', + }) + assert( + typeof conv1 === 'string', + 'conversion 1 should return type string', + ) assert(conv2 instanceof BigNumber, 'conversion 2 should be a BigNumber') }) it('Converts from dec to hex', function () { - assert.equal(conversionUtil('1000000000000000000', { fromNumericBase: 'dec', toNumericBase: 'hex' }), 'de0b6b3a7640000') - assert.equal(conversionUtil('1500000000000000000', { fromNumericBase: 'dec', toNumericBase: 'hex' }), '14d1120d7b160000') + assert.equal( + conversionUtil('1000000000000000000', { + fromNumericBase: 'dec', + toNumericBase: 'hex', + }), + 'de0b6b3a7640000', + ) + assert.equal( + conversionUtil('1500000000000000000', { + fromNumericBase: 'dec', + toNumericBase: 'hex', + }), + '14d1120d7b160000', + ) }) it('Converts hex formatted numbers to dec', function () { - assert.equal(conversionUtil('0xde0b6b3a7640000', { fromNumericBase: 'hex', toNumericBase: 'dec' }), 1000000000000000000) - assert.equal(conversionUtil('0x14d1120d7b160000', { fromNumericBase: 'hex', toNumericBase: 'dec' }), 1500000000000000000) + assert.equal( + conversionUtil('0xde0b6b3a7640000', { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }), + 1000000000000000000, + ) + assert.equal( + conversionUtil('0x14d1120d7b160000', { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }), + 1500000000000000000, + ) }) it('Converts WEI to ETH', function () { - assert.equal(conversionUtil('0xde0b6b3a7640000', { fromNumericBase: 'hex', toNumericBase: 'dec', fromDenomination: 'WEI', toDenomination: 'ETH' }), 1) - assert.equal(conversionUtil('0x14d1120d7b160000', { fromNumericBase: 'hex', toNumericBase: 'dec', fromDenomination: 'WEI', toDenomination: 'ETH' }), 1.5) + assert.equal( + conversionUtil('0xde0b6b3a7640000', { + fromNumericBase: 'hex', + toNumericBase: 'dec', + fromDenomination: 'WEI', + toDenomination: 'ETH', + }), + 1, + ) + assert.equal( + conversionUtil('0x14d1120d7b160000', { + fromNumericBase: 'hex', + toNumericBase: 'dec', + fromDenomination: 'WEI', + toDenomination: 'ETH', + }), + 1.5, + ) }) it('Converts ETH to WEI', function () { - assert.equal(conversionUtil('1', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'WEI' }), 1000000000000000000) - assert.equal(conversionUtil('1.5', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'WEI' }), 1500000000000000000) + assert.equal( + conversionUtil('1', { + fromNumericBase: 'dec', + fromDenomination: 'ETH', + toDenomination: 'WEI', + }), + 1000000000000000000, + ) + assert.equal( + conversionUtil('1.5', { + fromNumericBase: 'dec', + fromDenomination: 'ETH', + toDenomination: 'WEI', + }), + 1500000000000000000, + ) }) it('Converts ETH to GWEI', function () { - assert.equal(conversionUtil('1', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'GWEI' }), 1000000000) - assert.equal(conversionUtil('1.5', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'GWEI' }), 1500000000) + assert.equal( + conversionUtil('1', { + fromNumericBase: 'dec', + fromDenomination: 'ETH', + toDenomination: 'GWEI', + }), + 1000000000, + ) + assert.equal( + conversionUtil('1.5', { + fromNumericBase: 'dec', + fromDenomination: 'ETH', + toDenomination: 'GWEI', + }), + 1500000000, + ) }) it('Converts ETH to USD', function () { - assert.equal(conversionUtil('1', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2 }), 468.58) - assert.equal(conversionUtil('1.5', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2 }), 702.87) + assert.equal( + conversionUtil('1', { + fromNumericBase: 'dec', + toNumericBase: 'dec', + toCurrency: 'usd', + conversionRate: 468.58, + numberOfDecimals: 2, + }), + 468.58, + ) + assert.equal( + conversionUtil('1.5', { + fromNumericBase: 'dec', + toNumericBase: 'dec', + toCurrency: 'usd', + conversionRate: 468.58, + numberOfDecimals: 2, + }), + 702.87, + ) }) it('Converts USD to ETH', function () { - assert.equal(conversionUtil('468.58', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2, invertConversionRate: true }), 1) - assert.equal(conversionUtil('702.87', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2, invertConversionRate: true }), 1.5) + assert.equal( + conversionUtil('468.58', { + fromNumericBase: 'dec', + toNumericBase: 'dec', + toCurrency: 'usd', + conversionRate: 468.58, + numberOfDecimals: 2, + invertConversionRate: true, + }), + 1, + ) + assert.equal( + conversionUtil('702.87', { + fromNumericBase: 'dec', + toNumericBase: 'dec', + toCurrency: 'usd', + conversionRate: 468.58, + numberOfDecimals: 2, + invertConversionRate: true, + }), + 1.5, + ) }) }) }) diff --git a/ui/app/helpers/utils/conversions.util.js b/ui/app/helpers/utils/conversions.util.js index dca6b04f6..5587812ac 100644 --- a/ui/app/helpers/utils/conversions.util.js +++ b/ui/app/helpers/utils/conversions.util.js @@ -1,30 +1,37 @@ import ethUtil from 'ethereumjs-util' import BigNumber from 'bignumber.js' import { ETH, GWEI, WEI } from '../constants/common' -import { conversionUtil, addCurrencies, subtractCurrencies } from './conversion-util' import { - formatCurrency, -} from './confirm-tx.util' + conversionUtil, + addCurrencies, + subtractCurrencies, +} from './conversion-util' +import { formatCurrency } from './confirm-tx.util' -export function bnToHex (inputBn) { +export function bnToHex(inputBn) { return ethUtil.addHexPrefix(inputBn.toString(16)) } -export function hexToDecimal (hexValue) { +export function hexToDecimal(hexValue) { return conversionUtil(hexValue, { fromNumericBase: 'hex', toNumericBase: 'dec', }) } -export function decimalToHex (decimal) { +export function decimalToHex(decimal) { return conversionUtil(decimal, { fromNumericBase: 'dec', toNumericBase: 'hex', }) } -export function getEthConversionFromWeiHex ({ value, fromCurrency = ETH, conversionRate, numberOfDecimals = 6 }) { +export function getEthConversionFromWeiHex({ + value, + fromCurrency = ETH, + conversionRate, + numberOfDecimals = 6, +}) { const denominations = [fromCurrency, GWEI, WEI] let nonZeroDenomination @@ -48,7 +55,7 @@ export function getEthConversionFromWeiHex ({ value, fromCurrency = ETH, convers return nonZeroDenomination } -export function getValueFromWeiHex ({ +export function getValueFromWeiHex({ value, fromCurrency = ETH, toCurrency, @@ -68,7 +75,7 @@ export function getValueFromWeiHex ({ }) } -export function getWeiHexFromDecimalValue ({ +export function getWeiHexFromDecimalValue({ value, fromCurrency, conversionRate, @@ -87,7 +94,7 @@ export function getWeiHexFromDecimalValue ({ }) } -export function addHexWEIsToDec (aHexWEI, bHexWEI) { +export function addHexWEIsToDec(aHexWEI, bHexWEI) { return addCurrencies(aHexWEI, bHexWEI, { aBase: 16, bBase: 16, @@ -96,7 +103,7 @@ export function addHexWEIsToDec (aHexWEI, bHexWEI) { }) } -export function subtractHexWEIsToDec (aHexWEI, bHexWEI) { +export function subtractHexWEIsToDec(aHexWEI, bHexWEI) { return subtractCurrencies(aHexWEI, bHexWEI, { aBase: 16, bBase: 16, @@ -105,7 +112,11 @@ export function subtractHexWEIsToDec (aHexWEI, bHexWEI) { }) } -export function decEthToConvertedCurrency (ethTotal, convertedCurrency, conversionRate) { +export function decEthToConvertedCurrency( + ethTotal, + convertedCurrency, + conversionRate, +) { return conversionUtil(ethTotal, { fromNumericBase: 'dec', toNumericBase: 'dec', @@ -116,7 +127,7 @@ export function decEthToConvertedCurrency (ethTotal, convertedCurrency, conversi }) } -export function decGWEIToHexWEI (decGWEI) { +export function decGWEIToHexWEI(decGWEI) { return conversionUtil(decGWEI, { fromNumericBase: 'dec', toNumericBase: 'hex', @@ -125,7 +136,7 @@ export function decGWEIToHexWEI (decGWEI) { }) } -export function hexWEIToDecGWEI (decGWEI) { +export function hexWEIToDecGWEI(decGWEI) { return conversionUtil(decGWEI, { fromNumericBase: 'hex', toNumericBase: 'dec', @@ -134,7 +145,7 @@ export function hexWEIToDecGWEI (decGWEI) { }) } -export function decETHToDecWEI (decEth) { +export function decETHToDecWEI(decEth) { return conversionUtil(decEth, { fromNumericBase: 'dec', toNumericBase: 'dec', @@ -143,7 +154,7 @@ export function decETHToDecWEI (decEth) { }) } -export function hexWEIToDecETH (hexWEI) { +export function hexWEIToDecETH(hexWEI) { return conversionUtil(hexWEI, { fromNumericBase: 'hex', toNumericBase: 'dec', @@ -152,17 +163,17 @@ export function hexWEIToDecETH (hexWEI) { }) } -export function hexMax (...hexNumbers) { +export function hexMax(...hexNumbers) { let max = hexNumbers[0] hexNumbers.slice(1).forEach((hexNumber) => { - if ((new BigNumber(hexNumber, 16)).gt(max, 16)) { + if (new BigNumber(hexNumber, 16).gt(max, 16)) { max = hexNumber } }) return max } -export function addHexes (aHexWEI, bHexWEI) { +export function addHexes(aHexWEI, bHexWEI) { return addCurrencies(aHexWEI, bHexWEI, { aBase: 16, bBase: 16, @@ -171,11 +182,17 @@ export function addHexes (aHexWEI, bHexWEI) { }) } -export function sumHexWEIsToRenderableFiat (hexWEIs, convertedCurrency, conversionRate) { +export function sumHexWEIsToRenderableFiat( + hexWEIs, + convertedCurrency, + conversionRate, +) { const hexWEIsSum = hexWEIs.filter((n) => n).reduce(addHexes) const ethTotal = decEthToConvertedCurrency( getValueFromWeiHex({ - value: hexWEIsSum, toCurrency: 'ETH', numberOfDecimals: 4, + value: hexWEIsSum, + toCurrency: 'ETH', + numberOfDecimals: 4, }), convertedCurrency, conversionRate, diff --git a/ui/app/helpers/utils/fetch-with-cache.js b/ui/app/helpers/utils/fetch-with-cache.js index 470f2a8d6..c04d54086 100644 --- a/ui/app/helpers/utils/fetch-with-cache.js +++ b/ui/app/helpers/utils/fetch-with-cache.js @@ -4,8 +4,15 @@ import { } from '../../../lib/local-storage-helpers' import fetchWithTimeout from '../../../../app/scripts/lib/fetch-with-timeout' -const fetchWithCache = async (url, fetchOptions = {}, { cacheRefreshTime = 360000, timeout = 30000 } = {}) => { - if (fetchOptions.body || (fetchOptions.method && fetchOptions.method !== 'GET')) { +const fetchWithCache = async ( + url, + fetchOptions = {}, + { cacheRefreshTime = 360000, timeout = 30000 } = {}, +) => { + if ( + fetchOptions.body || + (fetchOptions.method && fetchOptions.method !== 'GET') + ) { throw new Error('fetchWithCache only supports GET requests') } if (!(fetchOptions.headers instanceof window.Headers)) { @@ -26,9 +33,7 @@ const fetchWithCache = async (url, fetchOptions = {}, { cacheRefreshTime = 36000 return cachedResponse } fetchOptions.headers.set('Content-Type', 'application/json') - const _fetch = timeout - ? fetchWithTimeout({ timeout }) - : window.fetch + const _fetch = timeout ? fetchWithTimeout({ timeout }) : window.fetch const response = await _fetch(url, { referrerPolicy: 'no-referrer-when-downgrade', body: null, @@ -37,7 +42,9 @@ const fetchWithCache = async (url, fetchOptions = {}, { cacheRefreshTime = 36000 ...fetchOptions, }) if (!response.ok) { - throw new Error(`Fetch failed with status '${response.status}': '${response.statusText}'`) + throw new Error( + `Fetch failed with status '${response.status}': '${response.statusText}'`, + ) } const responseJson = await response.json() const cacheEntry = { diff --git a/ui/app/helpers/utils/fetch-with-cache.test.js b/ui/app/helpers/utils/fetch-with-cache.test.js index 3c57c3794..c5981abd9 100644 --- a/ui/app/helpers/utils/fetch-with-cache.test.js +++ b/ui/app/helpers/utils/fetch-with-cache.test.js @@ -23,7 +23,9 @@ describe('Fetch with cache', function () { .get('/price') .reply(200, '{"average": 1}') - const response = await fetchWithCache('https://fetchwithcache.metamask.io/price') + const response = await fetchWithCache( + 'https://fetchwithcache.metamask.io/price', + ) assert.deepEqual(response, { average: 1, }) @@ -41,7 +43,9 @@ describe('Fetch with cache', function () { }, }) - const response = await fetchWithCache('https://fetchwithcache.metamask.io/price') + const response = await fetchWithCache( + 'https://fetchwithcache.metamask.io/price', + ) assert.deepEqual(response, { average: 1, }) @@ -59,7 +63,11 @@ describe('Fetch with cache', function () { }, }) - const response = await fetchWithCache('https://fetchwithcache.metamask.io/price', {}, { cacheRefreshTime: 123 }) + const response = await fetchWithCache( + 'https://fetchwithcache.metamask.io/price', + {}, + { cacheRefreshTime: 123 }, + ) assert.deepEqual(response, { average: 3, }) @@ -72,7 +80,12 @@ describe('Fetch with cache', function () { .reply(200, '{"average": 4}') await assert.rejects( - () => fetchWithCache('https://fetchwithcache.metamask.io/price', {}, { timeout: 20 }), + () => + fetchWithCache( + 'https://fetchwithcache.metamask.io/price', + {}, + { timeout: 20 }, + ), { name: 'AbortError', message: 'Aborted' }, ) }) @@ -82,8 +95,8 @@ describe('Fetch with cache', function () { .get('/price') .reply(500, '{"average": 6}') - await assert.rejects( - () => fetchWithCache('https://fetchwithcache.metamask.io/price'), + await assert.rejects(() => + fetchWithCache('https://fetchwithcache.metamask.io/price'), ) }) @@ -92,8 +105,10 @@ describe('Fetch with cache', function () { .post('/price') .reply(200, '{"average": 7}') - await assert.rejects( - () => fetchWithCache('https://fetchwithcache.metamask.io/price', { method: 'POST' }), + await assert.rejects(() => + fetchWithCache('https://fetchwithcache.metamask.io/price', { + method: 'POST', + }), ) }) @@ -102,8 +117,8 @@ describe('Fetch with cache', function () { .get('/price') .reply(200, '{"average": 8}') - await assert.rejects( - () => fetchWithCache('https://fetchwithcache.metamask.io/price', { body: 1 }), + await assert.rejects(() => + fetchWithCache('https://fetchwithcache.metamask.io/price', { body: 1 }), ) }) @@ -113,7 +128,10 @@ describe('Fetch with cache', function () { .reply(200, '{"average": 9}') await assert.rejects( - () => fetchWithCache('https://fetchwithcache.metamask.io/price', { headers: { 'Content-Type': 'text/plain' } }), + () => + fetchWithCache('https://fetchwithcache.metamask.io/price', { + headers: { 'Content-Type': 'text/plain' }, + }), { message: 'fetchWithCache only supports JSON responses' }, ) }) diff --git a/ui/app/helpers/utils/formatters.js b/ui/app/helpers/utils/formatters.js index d722ef09b..f4a120044 100644 --- a/ui/app/helpers/utils/formatters.js +++ b/ui/app/helpers/utils/formatters.js @@ -1,3 +1,3 @@ -export function formatETHFee (ethFee) { +export function formatETHFee(ethFee) { return `${ethFee} ETH` } diff --git a/ui/app/helpers/utils/gas-time-estimates.util.js b/ui/app/helpers/utils/gas-time-estimates.util.js index 5aadacf3a..7757f69ff 100644 --- a/ui/app/helpers/utils/gas-time-estimates.util.js +++ b/ui/app/helpers/utils/gas-time-estimates.util.js @@ -1,29 +1,42 @@ import BigNumber from 'bignumber.js' -export function newBigSigDig (n) { - return new BigNumber((new BigNumber(String(n))).toPrecision(15)) +export function newBigSigDig(n) { + return new BigNumber(new BigNumber(String(n)).toPrecision(15)) } -const createOp = (a, b, op) => (newBigSigDig(a))[op](newBigSigDig(b)) +const createOp = (a, b, op) => newBigSigDig(a)[op](newBigSigDig(b)) -export function bigNumMinus (a = 0, b = 0) { +export function bigNumMinus(a = 0, b = 0) { return createOp(a, b, 'minus') } -export function bigNumDiv (a = 0, b = 1) { +export function bigNumDiv(a = 0, b = 1) { return createOp(a, b, 'div') } -export function extrapolateY ({ higherY = 0, lowerY = 0, higherX = 0, lowerX = 0, xForExtrapolation = 0 }) { +export function extrapolateY({ + higherY = 0, + lowerY = 0, + higherX = 0, + lowerX = 0, + xForExtrapolation = 0, +}) { const slope = bigNumMinus(higherY, lowerY).div(bigNumMinus(higherX, lowerX)) - const newTimeEstimate = slope.times(bigNumMinus(higherX, xForExtrapolation)).minus(newBigSigDig(higherY)).negated() + const newTimeEstimate = slope + .times(bigNumMinus(higherX, xForExtrapolation)) + .minus(newBigSigDig(higherY)) + .negated() return newTimeEstimate.toNumber() } -export function getAdjacentGasPrices ({ gasPrices, priceToPosition }) { - const closestLowerValueIndex = gasPrices.findIndex((e, i, a) => e <= priceToPosition && a[i + 1] >= priceToPosition) - const closestHigherValueIndex = gasPrices.findIndex((e) => e > priceToPosition) +export function getAdjacentGasPrices({ gasPrices, priceToPosition }) { + const closestLowerValueIndex = gasPrices.findIndex( + (e, i, a) => e <= priceToPosition && a[i + 1] >= priceToPosition, + ) + const closestHigherValueIndex = gasPrices.findIndex( + (e) => e > priceToPosition, + ) return { closestLowerValueIndex, closestHigherValueIndex, @@ -32,7 +45,7 @@ export function getAdjacentGasPrices ({ gasPrices, priceToPosition }) { } } -export function formatTimeEstimate (totalSeconds, greaterThanMax, lessThanMin) { +export function formatTimeEstimate(totalSeconds, greaterThanMax, lessThanMin) { const minutes = Math.floor(totalSeconds / 60) const seconds = Math.floor(totalSeconds % 60) @@ -49,14 +62,19 @@ export function formatTimeEstimate (totalSeconds, greaterThanMax, lessThanMin) { const formattedMin = `${minutes ? `${minutes} min` : ''}` const formattedSec = `${seconds ? `${seconds} sec` : ''}` - const formattedCombined = formattedMin && formattedSec - ? `${symbol}${formattedMin} ${formattedSec}` - : symbol + (formattedMin || formattedSec) + const formattedCombined = + formattedMin && formattedSec + ? `${symbol}${formattedMin} ${formattedSec}` + : symbol + (formattedMin || formattedSec) return formattedCombined } -export function getRawTimeEstimateData (currentGasPrice, gasPrices, estimatedTimes) { +export function getRawTimeEstimateData( + currentGasPrice, + gasPrices, + estimatedTimes, +) { const minGasPrice = gasPrices[0] const maxGasPrice = gasPrices[gasPrices.length - 1] let priceForEstimation = currentGasPrice @@ -88,12 +106,20 @@ export function getRawTimeEstimateData (currentGasPrice, gasPrices, estimatedTim } } -export function getRenderableTimeEstimate (currentGasPrice, gasPrices, estimatedTimes) { - const { - newTimeEstimate, - minGasPrice, - maxGasPrice, - } = getRawTimeEstimateData(currentGasPrice, gasPrices, estimatedTimes) +export function getRenderableTimeEstimate( + currentGasPrice, + gasPrices, + estimatedTimes, +) { + const { newTimeEstimate, minGasPrice, maxGasPrice } = getRawTimeEstimateData( + currentGasPrice, + gasPrices, + estimatedTimes, + ) - return formatTimeEstimate(newTimeEstimate, currentGasPrice > maxGasPrice, currentGasPrice < minGasPrice) + return formatTimeEstimate( + newTimeEstimate, + currentGasPrice > maxGasPrice, + currentGasPrice < minGasPrice, + ) } diff --git a/ui/app/helpers/utils/i18n-helper.js b/ui/app/helpers/utils/i18n-helper.js index fab317705..776b420b1 100644 --- a/ui/app/helpers/utils/i18n-helper.js +++ b/ui/app/helpers/utils/i18n-helper.js @@ -23,7 +23,9 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => { if (!localeMessages[key]) { if (localeCode === 'en') { if (!missingMessageErrors[key]) { - missingMessageErrors[key] = new Error(`Unable to find value of key "${key}" for locale "${localeCode}"`) + missingMessageErrors[key] = new Error( + `Unable to find value of key "${key}" for locale "${localeCode}"`, + ) Sentry.captureException(missingMessageErrors[key]) log.error(missingMessageErrors[key]) if (process.env.IN_TEST === 'true') { @@ -35,7 +37,9 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => { warned[localeCode] = {} } warned[localeCode][key] = true - log.warn(`Translator - Unable to find value of key "${key}" for locale "${localeCode}"`) + log.warn( + `Translator - Unable to find value of key "${key}" for locale "${localeCode}"`, + ) } return null } @@ -43,12 +47,17 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => { let phrase = entry.message const hasSubstitutions = Boolean(substitutions && substitutions.length) - const hasReactSubstitutions = hasSubstitutions && - substitutions.some((element) => element !== null && (typeof element === 'function' || typeof element === 'object')) + const hasReactSubstitutions = + hasSubstitutions && + substitutions.some( + (element) => + element !== null && + (typeof element === 'function' || typeof element === 'object'), + ) // perform substitutions if (hasSubstitutions) { - const parts = phrase.split(/(\$\d)/ug) + const parts = phrase.split(/(\$\d)/gu) const substitutedParts = parts.map((part) => { const subMatch = part.match(/\$(\d)/u) @@ -57,31 +66,38 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => { } const substituteIndex = Number(subMatch[1]) - 1 if ( - (substitutions[substituteIndex] === null || substitutions[substituteIndex] === undefined) && + (substitutions[substituteIndex] === null || + substitutions[substituteIndex] === undefined) && !missingSubstitutionErrors[localeCode]?.[key] ) { if (!missingSubstitutionErrors[localeCode]) { missingSubstitutionErrors[localeCode] = {} } missingSubstitutionErrors[localeCode][key] = true - const error = new Error(`Insufficient number of substitutions for key "${key}" with locale "${localeCode}"`) + const error = new Error( + `Insufficient number of substitutions for key "${key}" with locale "${localeCode}"`, + ) log.error(error) Sentry.captureException(error) } return substitutions[substituteIndex] }) - phrase = hasReactSubstitutions - ? { substitutedParts } - : substitutedParts.join('') + phrase = hasReactSubstitutions ? ( + {substitutedParts} + ) : ( + substitutedParts.join('') + ) } return phrase } -export async function fetchLocale (localeCode) { +export async function fetchLocale(localeCode) { try { - const response = await window.fetch(`./_locales/${localeCode}/messages.json`) + const response = await window.fetch( + `./_locales/${localeCode}/messages.json`, + ) return await response.json() } catch (error) { log.error(`failed to fetch ${localeCode} locale because of ${error}`) @@ -91,7 +107,7 @@ export async function fetchLocale (localeCode) { const relativeTimeFormatLocaleData = new Set() -export async function loadRelativeTimeFormatLocaleData (localeCode) { +export async function loadRelativeTimeFormatLocaleData(localeCode) { const languageTag = localeCode.split('_')[0] if ( Intl.RelativeTimeFormat && @@ -103,7 +119,9 @@ export async function loadRelativeTimeFormatLocaleData (localeCode) { } } -async function fetchRelativeTimeFormatData (languageTag) { - const response = await window.fetch(`./intl/${languageTag}/relative-time-format-data.json`) +async function fetchRelativeTimeFormatData(languageTag) { + const response = await window.fetch( + `./intl/${languageTag}/relative-time-format-data.json`, + ) return await response.json() } diff --git a/ui/app/helpers/utils/i18n-helper.test.js b/ui/app/helpers/utils/i18n-helper.test.js index 4e41f8c20..3c0cca220 100644 --- a/ui/app/helpers/utils/i18n-helper.test.js +++ b/ui/app/helpers/utils/i18n-helper.test.js @@ -44,70 +44,56 @@ describe('i18n helper', function () { message: '$1 - $2 - $3', }, [TEST_KEY_6]: { - 'message': 'Testing a react substitution $1.', + message: 'Testing a react substitution $1.', }, [TEST_KEY_6_HELPER]: { - 'message': TEST_SUBSTITUTION_1, + message: TEST_SUBSTITUTION_1, }, [TEST_KEY_7]: { - 'message': 'Testing a react substitution $1 and another $2.', + message: 'Testing a react substitution $1 and another $2.', }, [TEST_KEY_7_HELPER_1]: { - 'message': TEST_SUBSTITUTION_1, + message: TEST_SUBSTITUTION_1, }, [TEST_KEY_7_HELPER_2]: { - 'message': TEST_SUBSTITUTION_2, + message: TEST_SUBSTITUTION_2, }, [TEST_KEY_8]: { - 'message': 'Testing a mix $1 of react substitutions $2 and string substitutions $3 + $4.', + message: + 'Testing a mix $1 of react substitutions $2 and string substitutions $3 + $4.', }, [TEST_KEY_8_HELPER_1]: { - 'message': TEST_SUBSTITUTION_3, + message: TEST_SUBSTITUTION_3, }, [TEST_KEY_8_HELPER_2]: { - 'message': TEST_SUBSTITUTION_4, + message: TEST_SUBSTITUTION_4, }, } const t = getMessage.bind(null, TEST_LOCALE_CODE, testLocaleMessages) const TEST_SUBSTITUTION_6 = ( -
    - { t(TEST_KEY_6_HELPER) } +
    + {t(TEST_KEY_6_HELPER)}
    ) const TEST_SUBSTITUTION_7_1 = ( -
    - { t(TEST_KEY_7_HELPER_1) } +
    + {t(TEST_KEY_7_HELPER_1)}
    ) const TEST_SUBSTITUTION_7_2 = ( -
    - { t(TEST_KEY_7_HELPER_2) } +
    + {t(TEST_KEY_7_HELPER_2)}
    ) const TEST_SUBSTITUTION_8_1 = ( -
    - { t(TEST_KEY_8_HELPER_1) } +
    + {t(TEST_KEY_8_HELPER_1)}
    ) const TEST_SUBSTITUTION_8_2 = ( -
    - { t(TEST_KEY_8_HELPER_2) } +
    + {t(TEST_KEY_8_HELPER_2)}
    ) @@ -119,17 +105,32 @@ describe('i18n helper', function () { it('should return the correct message when a single non-react substitution is made', function () { const result = t(TEST_KEY_2, [TEST_SUBSTITUTION_1]) - assert.equal(result, `This is a message with a single non-react substitution ${TEST_SUBSTITUTION_1}.`) + assert.equal( + result, + `This is a message with a single non-react substitution ${TEST_SUBSTITUTION_1}.`, + ) }) it('should return the correct message when two non-react substitutions are made', function () { const result = t(TEST_KEY_3, [TEST_SUBSTITUTION_1, TEST_SUBSTITUTION_2]) - assert.equal(result, `This is a message with two non-react substitutions ${TEST_SUBSTITUTION_1} and ${TEST_SUBSTITUTION_2}.`) + assert.equal( + result, + `This is a message with two non-react substitutions ${TEST_SUBSTITUTION_1} and ${TEST_SUBSTITUTION_2}.`, + ) }) it('should return the correct message when multiple non-react substitutions are made', function () { - const result = t(TEST_KEY_4, [TEST_SUBSTITUTION_1, TEST_SUBSTITUTION_2, TEST_SUBSTITUTION_3, TEST_SUBSTITUTION_4, TEST_SUBSTITUTION_5]) - assert.equal(result, `${TEST_SUBSTITUTION_1} - ${TEST_SUBSTITUTION_2} - ${TEST_SUBSTITUTION_3} - ${TEST_SUBSTITUTION_4} - ${TEST_SUBSTITUTION_5}`) + const result = t(TEST_KEY_4, [ + TEST_SUBSTITUTION_1, + TEST_SUBSTITUTION_2, + TEST_SUBSTITUTION_3, + TEST_SUBSTITUTION_4, + TEST_SUBSTITUTION_5, + ]) + assert.equal( + result, + `${TEST_SUBSTITUTION_1} - ${TEST_SUBSTITUTION_2} - ${TEST_SUBSTITUTION_3} - ${TEST_SUBSTITUTION_4} - ${TEST_SUBSTITUTION_5}`, + ) }) it('should correctly render falsey substitutions', function () { @@ -144,17 +145,34 @@ describe('i18n helper', function () { it('should return the correct message when a single react substitution is made', function () { const result = t(TEST_KEY_6, [TEST_SUBSTITUTION_6]) - assert.equal(shallow(result).html(), ' Testing a react substitution
    TEST_SUBSTITUTION_1
    .
    ') + assert.equal( + shallow(result).html(), + ' Testing a react substitution
    TEST_SUBSTITUTION_1
    .
    ', + ) }) it('should return the correct message when two react substitutions are made', function () { - const result = t(TEST_KEY_7, [TEST_SUBSTITUTION_7_1, TEST_SUBSTITUTION_7_2]) - assert.equal(shallow(result).html(), ' Testing a react substitution
    TEST_SUBSTITUTION_1
    and another
    TEST_SUBSTITUTION_2
    .
    ') + const result = t(TEST_KEY_7, [ + TEST_SUBSTITUTION_7_1, + TEST_SUBSTITUTION_7_2, + ]) + assert.equal( + shallow(result).html(), + ' Testing a react substitution
    TEST_SUBSTITUTION_1
    and another
    TEST_SUBSTITUTION_2
    .
    ', + ) }) it('should return the correct message when substituting a mix of react elements and strings', function () { - const result = t(TEST_KEY_8, [TEST_SUBSTITUTION_1, TEST_SUBSTITUTION_8_1, TEST_SUBSTITUTION_2, TEST_SUBSTITUTION_8_2]) - assert.equal(shallow(result).html(), ' Testing a mix TEST_SUBSTITUTION_1 of react substitutions
    TEST_SUBSTITUTION_3
    and string substitutions TEST_SUBSTITUTION_2 +
    TEST_SUBSTITUTION_4
    .
    ') + const result = t(TEST_KEY_8, [ + TEST_SUBSTITUTION_1, + TEST_SUBSTITUTION_8_1, + TEST_SUBSTITUTION_2, + TEST_SUBSTITUTION_8_2, + ]) + assert.equal( + shallow(result).html(), + ' Testing a mix TEST_SUBSTITUTION_1 of react substitutions
    TEST_SUBSTITUTION_3
    and string substitutions TEST_SUBSTITUTION_2 +
    TEST_SUBSTITUTION_4
    .
    ', + ) }) }) }) diff --git a/ui/app/helpers/utils/switch-direction.js b/ui/app/helpers/utils/switch-direction.js index 81170f43c..5d4075896 100644 --- a/ui/app/helpers/utils/switch-direction.js +++ b/ui/app/helpers/utils/switch-direction.js @@ -24,7 +24,8 @@ const switchDirection = async (direction) => { updatedLink.onload = () => { resolve() } - updatedLink.onerror = () => reject(new Error(`Failed to load '${direction}' stylesheet`)) + updatedLink.onerror = () => + reject(new Error(`Failed to load '${direction}' stylesheet`)) }) } diff --git a/ui/app/helpers/utils/token-util.js b/ui/app/helpers/utils/token-util.js index 700f5f9c8..477238cdf 100644 --- a/ui/app/helpers/utils/token-util.js +++ b/ui/app/helpers/utils/token-util.js @@ -15,19 +15,22 @@ const casedContractMap = Object.keys(contractMap).reduce((acc, base) => { const DEFAULT_SYMBOL = '' const DEFAULT_DECIMALS = '0' -async function getSymbolFromContract (tokenAddress) { +async function getSymbolFromContract(tokenAddress) { const token = util.getContractAtAddress(tokenAddress) try { const result = await token.symbol() return result[0] } catch (error) { - log.warn(`symbol() call for token at address ${tokenAddress} resulted in error:`, error) + log.warn( + `symbol() call for token at address ${tokenAddress} resulted in error:`, + error, + ) return undefined } } -async function getDecimalsFromContract (tokenAddress) { +async function getDecimalsFromContract(tokenAddress) { const token = util.getContractAtAddress(tokenAddress) try { @@ -35,16 +38,19 @@ async function getDecimalsFromContract (tokenAddress) { const decimalsBN = result[0] return decimalsBN && decimalsBN.toString() } catch (error) { - log.warn(`decimals() call for token at address ${tokenAddress} resulted in error:`, error) + log.warn( + `decimals() call for token at address ${tokenAddress} resulted in error:`, + error, + ) return undefined } } -function getContractMetadata (tokenAddress) { +function getContractMetadata(tokenAddress) { return tokenAddress && casedContractMap[tokenAddress.toLowerCase()] } -async function getSymbol (tokenAddress) { +async function getSymbol(tokenAddress) { let symbol = await getSymbolFromContract(tokenAddress) if (!symbol) { @@ -58,7 +64,7 @@ async function getSymbol (tokenAddress) { return symbol } -async function getDecimals (tokenAddress) { +async function getDecimals(tokenAddress) { let decimals = await getDecimalsFromContract(tokenAddress) if (!decimals || decimals === '0') { @@ -72,14 +78,17 @@ async function getDecimals (tokenAddress) { return decimals } -export async function fetchSymbolAndDecimals (tokenAddress) { +export async function fetchSymbolAndDecimals(tokenAddress) { let symbol, decimals try { symbol = await getSymbol(tokenAddress) decimals = await getDecimals(tokenAddress) } catch (error) { - log.warn(`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, error) + log.warn( + `symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, + error, + ) } return { @@ -88,8 +97,10 @@ export async function fetchSymbolAndDecimals (tokenAddress) { } } -export async function getSymbolAndDecimals (tokenAddress, existingTokens = []) { - const existingToken = existingTokens.find(({ address }) => tokenAddress === address) +export async function getSymbolAndDecimals(tokenAddress, existingTokens = []) { + const existingToken = existingTokens.find( + ({ address }) => tokenAddress === address, + ) if (existingToken) { return { @@ -104,7 +115,10 @@ export async function getSymbolAndDecimals (tokenAddress, existingTokens = []) { symbol = await getSymbol(tokenAddress) decimals = await getDecimals(tokenAddress) } catch (error) { - log.warn(`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, error) + log.warn( + `symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, + error, + ) } return { @@ -113,7 +127,7 @@ export async function getSymbolAndDecimals (tokenAddress, existingTokens = []) { } } -export function tokenInfoGetter () { +export function tokenInfoGetter() { const tokens = {} return async (address) => { @@ -127,12 +141,12 @@ export function tokenInfoGetter () { } } -export function calcTokenAmount (value, decimals) { +export function calcTokenAmount(value, decimals) { const multiplier = Math.pow(10, Number(decimals || 0)) return new BigNumber(String(value)).div(multiplier) } -export function calcTokenValue (value, decimals) { +export function calcTokenValue(value, decimals) { const multiplier = Math.pow(10, Number(decimals || 0)) return new BigNumber(String(value)).times(multiplier) } @@ -147,7 +161,7 @@ export function calcTokenValue (value, decimals) { * @param {Object} tokenData - ethers Interface token data. * @returns {string | undefined} A lowercase address string. */ -export function getTokenAddressParam (tokenData = {}) { +export function getTokenAddressParam(tokenData = {}) { const value = tokenData?.args?._to || tokenData?.args?.[0] return value?.toString().toLowerCase() } @@ -159,11 +173,11 @@ export function getTokenAddressParam (tokenData = {}) { * @param {Object} tokenData - ethers Interface token data. * @returns {string | undefined} A decimal string value. */ -export function getTokenValueParam (tokenData = {}) { +export function getTokenValueParam(tokenData = {}) { return tokenData?.args?._value?.toString() } -export function getTokenValue (tokenParams = []) { +export function getTokenValue(tokenParams = []) { const valueData = tokenParams.find((param) => param.name === '_value') return valueData && valueData.value } @@ -180,7 +194,7 @@ export function getTokenValue (tokenParams = []) { * @param {boolean} [hideCurrencySymbol] - excludes the currency symbol in the result if true * @returns {string|undefined} The token amount in the user's chosen fiat currency, optionally formatted and localize */ -export function getTokenFiatAmount ( +export function getTokenFiatAmount( contractExchangeRate, conversionRate, currentCurrency, @@ -192,7 +206,11 @@ export function getTokenFiatAmount ( // If the conversionRate is 0 (i.e. unknown) or the contract exchange rate // is currently unknown, the fiat amount cannot be calculated so it is not // shown to the user - if (conversionRate <= 0 || !contractExchangeRate || tokenAmount === undefined) { + if ( + conversionRate <= 0 || + !contractExchangeRate || + tokenAmount === undefined + ) { return undefined } @@ -211,7 +229,10 @@ export function getTokenFiatAmount ( if (hideCurrencySymbol) { result = formatCurrency(currentTokenInFiat, currentCurrency) } else if (formatted) { - result = `${formatCurrency(currentTokenInFiat, currentCurrency)} ${currentCurrency.toUpperCase()}` + result = `${formatCurrency( + currentTokenInFiat, + currentCurrency, + )} ${currentCurrency.toUpperCase()}` } else { result = currentTokenInFiat } diff --git a/ui/app/helpers/utils/transactions.util.js b/ui/app/helpers/utils/transactions.util.js index fbbbf214b..8cb84396f 100644 --- a/ui/app/helpers/utils/transactions.util.js +++ b/ui/app/helpers/utils/transactions.util.js @@ -35,7 +35,7 @@ const hstInterface = new ethers.utils.Interface(abi) /** * @returns {EthersContractCall | undefined} */ -export function getTokenData (data) { +export function getTokenData(data) { try { return hstInterface.parseTransaction({ data }) } catch (error) { @@ -44,13 +44,16 @@ export function getTokenData (data) { } } -async function getMethodFrom4Byte (fourBytePrefix) { - const fourByteResponse = (await fetchWithCache(`https://www.4byte.directory/api/v1/signatures/?hex_signature=${fourBytePrefix}`, { - referrerPolicy: 'no-referrer-when-downgrade', - body: null, - method: 'GET', - mode: 'cors', - })) +async function getMethodFrom4Byte(fourBytePrefix) { + const fourByteResponse = await fetchWithCache( + `https://www.4byte.directory/api/v1/signatures/?hex_signature=${fourBytePrefix}`, + { + referrerPolicy: 'no-referrer-when-downgrade', + body: null, + method: 'GET', + mode: 'cors', + }, + ) if (fourByteResponse.count === 1) { return fourByteResponse.results[0].text_signature @@ -64,7 +67,7 @@ let registry * @param {string} fourBytePrefix - The prefix from the method code associated with the data * @returns {Object} */ -export async function getMethodDataAsync (fourBytePrefix) { +export async function getMethodDataAsync(fourBytePrefix) { try { const fourByteSig = getMethodFrom4Byte(fourBytePrefix).catch((e) => { log.error(e) @@ -103,19 +106,19 @@ export async function getMethodDataAsync (fourBytePrefix) { * @param {string} data - The hex data (@code txParams.data) of a transaction * @returns {string} - The four-byte method signature */ -export function getFourBytePrefix (data = '') { +export function getFourBytePrefix(data = '') { const prefixedData = ethUtil.addHexPrefix(data) const fourBytePrefix = prefixedData.slice(0, 10) return fourBytePrefix } /** - * Given an transaction category, returns a boolean which indicates whether the transaction is calling an erc20 token method - * - * @param {string} transactionCategory - The category of transaction being evaluated - * @returns {boolean} - whether the transaction is calling an erc20 token method - */ -export function isTokenMethodAction (transactionCategory) { + * Given an transaction category, returns a boolean which indicates whether the transaction is calling an erc20 token method + * + * @param {string} transactionCategory - The category of transaction being evaluated + * @returns {boolean} - whether the transaction is calling an erc20 token method + */ +export function isTokenMethodAction(transactionCategory) { return [ TOKEN_METHOD_TRANSFER, TOKEN_METHOD_APPROVE, @@ -123,7 +126,10 @@ export function isTokenMethodAction (transactionCategory) { ].includes(transactionCategory) } -export function getLatestSubmittedTxWithNonce (transactions = [], nonce = '0x0') { +export function getLatestSubmittedTxWithNonce( + transactions = [], + nonce = '0x0', +) { if (!transactions.length) { return {} } @@ -141,14 +147,14 @@ export function getLatestSubmittedTxWithNonce (transactions = [], nonce = '0x0') }, {}) } -export async function isSmartContractAddress (address) { +export async function isSmartContractAddress(address) { const code = await global.eth.getCode(address) // Geth will return '0x', and ganache-core v2.2.1 will return '0x0' const codeIsEmpty = !code || code === '0x' || code === '0x0' return !codeIsEmpty } -export function sumHexes (...args) { +export function sumHexes(...args) { const total = args.reduce((acc, base) => { return addCurrencies(acc, base, { toNumericBase: 'hex', @@ -165,15 +171,22 @@ export function sumHexes (...args) { * @param {Object} transaction.txReceipt - The transaction receipt. * @returns {string} */ -export function getStatusKey (transaction) { - const { txReceipt: { status: receiptStatus } = {}, type, status } = transaction +export function getStatusKey(transaction) { + const { + txReceipt: { status: receiptStatus } = {}, + type, + status, + } = transaction // There was an on-chain failure if (receiptStatus === '0x0') { return 'failed' } - if (status === TRANSACTION_STATUS_CONFIRMED && type === TRANSACTION_TYPE_CANCEL) { + if ( + status === TRANSACTION_STATUS_CONFIRMED && + type === TRANSACTION_TYPE_CANCEL + ) { return 'cancelled' } @@ -186,7 +199,7 @@ export function getStatusKey (transaction) { * @param {string} hash * @param {Object} rpcPrefs */ -export function getBlockExplorerUrlForTx (networkId, hash, rpcPrefs = {}) { +export function getBlockExplorerUrlForTx(networkId, hash, rpcPrefs = {}) { if (rpcPrefs.blockExplorerUrl) { return `${rpcPrefs.blockExplorerUrl.replace(/\/+$/u, '')}/tx/${hash}` } diff --git a/ui/app/helpers/utils/transactions.util.test.js b/ui/app/helpers/utils/transactions.util.test.js index 503d6a641..a4b47d2d1 100644 --- a/ui/app/helpers/utils/transactions.util.test.js +++ b/ui/app/helpers/utils/transactions.util.test.js @@ -4,7 +4,9 @@ import * as utils from './transactions.util' describe('Transactions utils', function () { describe('getTokenData', function () { it('should return token data', function () { - const tokenData = utils.getTokenData('0xa9059cbb00000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000004e20') + const tokenData = utils.getTokenData( + '0xa9059cbb00000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000004e20', + ) assert.ok(tokenData) const { name, args } = tokenData assert.equal(name, 'transfer') @@ -89,7 +91,10 @@ describe('Transactions utils', function () { ] tests.forEach(({ expected, networkId, hash, rpcPrefs }) => { - assert.equal(utils.getBlockExplorerUrlForTx(networkId, hash, rpcPrefs), expected) + assert.equal( + utils.getBlockExplorerUrlForTx(networkId, hash, rpcPrefs), + expected, + ) }) }) }) diff --git a/ui/app/helpers/utils/util.js b/ui/app/helpers/utils/util.js index 8cf64947d..229aac826 100644 --- a/ui/app/helpers/utils/util.js +++ b/ui/app/helpers/utils/util.js @@ -5,14 +5,20 @@ import ethUtil from 'ethereumjs-util' import { DateTime } from 'luxon' // formatData :: ( date: ) -> String -export function formatDate (date, format = 'M/d/y \'at\' T') { +export function formatDate(date, format = "M/d/y 'at' T") { return DateTime.fromMillis(date).toFormat(format) } -export function formatDateWithYearContext (date, formatThisYear = 'MMM d', fallback = 'MMM d, y') { +export function formatDateWithYearContext( + date, + formatThisYear = 'MMM d', + fallback = 'MMM d, y', +) { const dateTime = DateTime.fromMillis(date) const now = DateTime.local() - return dateTime.toFormat(now.year === dateTime.year ? formatThisYear : fallback) + return dateTime.toFormat( + now.year === dateTime.year ? formatThisYear : fallback, + ) } const valueTable = { @@ -33,25 +39,36 @@ Object.keys(valueTable).forEach((currency) => { bnTable[currency] = new ethUtil.BN(valueTable[currency], 10) }) -export function isEthNetwork (netId) { - if (!netId || netId === '1' || netId === '3' || netId === '4' || netId === '42' || netId === '1337') { +export function isEthNetwork(netId) { + if ( + !netId || + netId === '1' || + netId === '3' || + netId === '4' || + netId === '42' || + netId === '1337' + ) { return true } return false } -export function valuesFor (obj) { +export function valuesFor(obj) { if (!obj) { return [] } - return Object.keys(obj) - .map(function (key) { - return obj[key] - }) + return Object.keys(obj).map(function (key) { + return obj[key] + }) } -export function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includeHex = true) { +export function addressSummary( + address, + firstSegLength = 10, + lastSegLength = 4, + includeHex = true, +) { if (!address) { return '' } @@ -59,28 +76,40 @@ export function addressSummary (address, firstSegLength = 10, lastSegLength = 4, if (!includeHex) { checked = ethUtil.stripHexPrefix(checked) } - return checked ? `${checked.slice(0, firstSegLength)}...${checked.slice(checked.length - lastSegLength)}` : '...' + return checked + ? `${checked.slice(0, firstSegLength)}...${checked.slice( + checked.length - lastSegLength, + )}` + : '...' } -export function isValidAddress (address) { +export function isValidAddress(address) { if (!address || address === '0x0000000000000000000000000000000000000000') { return false } - const prefixed = address.startsWith('0X') ? address : ethUtil.addHexPrefix(address) - return (isAllOneCase(prefixed.slice(2)) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed) + const prefixed = address.startsWith('0X') + ? address + : ethUtil.addHexPrefix(address) + return ( + (isAllOneCase(prefixed.slice(2)) && ethUtil.isValidAddress(prefixed)) || + ethUtil.isValidChecksumAddress(prefixed) + ) } -export function isValidDomainName (address) { - const match = punycode.toASCII(address) +export function isValidDomainName(address) { + const match = punycode + .toASCII(address) .toLowerCase() // Checks that the domain consists of at least one valid domain pieces separated by periods, followed by a tld // Each piece of domain name has only the characters a-z, 0-9, and a hyphen (but not at the start or end of chunk) // A chunk has minimum length of 1, but minimum tld is set to 2 for now (no 1-character tlds exist yet) - .match(/^(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+[a-z0-9][-a-z0-9]*[a-z0-9]$/u) + .match( + /^(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+[a-z0-9][-a-z0-9]*[a-z0-9]$/u, + ) return match !== null } -export function isAllOneCase (address) { +export function isAllOneCase(address) { if (!address) { return true } @@ -90,7 +119,7 @@ export function isAllOneCase (address) { } // Takes wei Hex, returns wei BN, even if input is null -export function numericBalance (balance) { +export function numericBalance(balance) { if (!balance) { return new ethUtil.BN(0, 16) } @@ -99,14 +128,17 @@ export function numericBalance (balance) { } // Takes hex, returns [beforeDecimal, afterDecimal] -export function parseBalance (balance) { +export function parseBalance(balance) { let afterDecimal const wei = numericBalance(balance) const weiString = wei.toString() const trailingZeros = /0+$/u - const beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0' - afterDecimal = (`000000000000000000${wei}`).slice(-18).replace(trailingZeros, '') + const beforeDecimal = + weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0' + afterDecimal = `000000000000000000${wei}` + .slice(-18) + .replace(trailingZeros, '') if (afterDecimal === '') { afterDecimal = '0' } @@ -115,7 +147,12 @@ export function parseBalance (balance) { // Takes wei hex, returns an object with three properties. // Its "formatted" property is what we generally use to render values. -export function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') { +export function formatBalance( + balance, + decimalsToKeep, + needsParse = true, + ticker = 'ETH', +) { const parsed = needsParse ? parseBalance(balance) : balance.split('.') const beforeDecimal = parsed[0] let afterDecimal = parsed[1] @@ -134,12 +171,15 @@ export function formatBalance (balance, decimalsToKeep, needsParse = true, ticke } } else { afterDecimal += Array(decimalsToKeep).join('0') - formatted = `${beforeDecimal}.${afterDecimal.slice(0, decimalsToKeep)} ${ticker}` + formatted = `${beforeDecimal}.${afterDecimal.slice( + 0, + decimalsToKeep, + )} ${ticker}` } return formatted } -export function generateBalanceObject (formattedBalance, decimalsToKeep = 1) { +export function generateBalanceObject(formattedBalance, decimalsToKeep = 1) { let balance = formattedBalance.split(' ')[0] const label = formattedBalance.split(' ')[1] const beforeDecimal = balance.split('.')[0] @@ -160,7 +200,7 @@ export function generateBalanceObject (formattedBalance, decimalsToKeep = 1) { return { balance, label, shortBalance } } -export function shortenBalance (balance, decimalsToKeep = 1) { +export function shortenBalance(balance, decimalsToKeep = 1) { let truncatedValue const convertedBalance = parseFloat(balance) if (convertedBalance > 1000000) { @@ -185,7 +225,7 @@ export function shortenBalance (balance, decimalsToKeep = 1) { // Takes a BN and an ethereum currency name, // returns a BN in wei -export function normalizeToWei (amount, currency) { +export function normalizeToWei(amount, currency) { try { return amount.mul(bnTable.wei).div(bnTable[currency]) } catch (e) { @@ -193,7 +233,7 @@ export function normalizeToWei (amount, currency) { } } -export function normalizeEthStringToWei (str) { +export function normalizeEthStringToWei(str) { const parts = str.split('.') let eth = new ethUtil.BN(parts[0], 10).mul(bnTable.wei) if (parts[1]) { @@ -211,26 +251,26 @@ export function normalizeEthStringToWei (str) { } const multiple = new ethUtil.BN('10000', 10) -export function normalizeNumberToWei (n, currency) { +export function normalizeNumberToWei(n, currency) { const enlarged = n * 10000 const amount = new ethUtil.BN(String(enlarged), 10) return normalizeToWei(amount, currency).div(multiple) } -export function isHex (str) { +export function isHex(str) { return Boolean(str.match(/^(0x)?[0-9a-fA-F]+$/u)) } -export function getContractAtAddress (tokenAddress) { +export function getContractAtAddress(tokenAddress) { return global.eth.contract(abi).at(tokenAddress) } -export function getRandomFileName () { +export function getRandomFileName() { let fileName = '' const charBank = [ ...'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ] - const fileNameLength = Math.floor((Math.random() * 7) + 6) + const fileNameLength = Math.floor(Math.random() * 7 + 6) for (let i = 0; i < fileNameLength; i++) { fileName += charBank[Math.floor(Math.random() * charBank.length)] @@ -239,7 +279,7 @@ export function getRandomFileName () { return fileName } -export function exportAsFile (filename, data, type = 'text/csv') { +export function exportAsFile(filename, data, type = 'text/csv') { // eslint-disable-next-line no-param-reassign filename = filename || getRandomFileName() // source: https://stackoverflow.com/a/33542499 by Ludovic Feltz @@ -264,7 +304,7 @@ export function exportAsFile (filename, data, type = 'text/csv') { * @returns {string} - checksummed address * */ -export function checksumAddress (address) { +export function checksumAddress(address) { const checksummed = address ? ethUtil.toChecksumAddress(address) : '' return checksummed } @@ -280,7 +320,7 @@ export function checksumAddress (address) { * @returns {string} The shortened address, or the original if it was no longer * than 10 characters. */ -export function shortenAddress (address = '') { +export function shortenAddress(address = '') { if (address.length < 11) { return address } @@ -288,14 +328,14 @@ export function shortenAddress (address = '') { return `${address.slice(0, 6)}...${address.slice(-4)}` } -export function isValidAddressHead (address) { +export function isValidAddressHead(address) { const addressLengthIsLessThanFull = address.length < 42 const addressIsHex = isHex(address) return addressLengthIsLessThanFull && addressIsHex } -export function getAccountByAddress (accounts = [], targetAddress) { +export function getAccountByAddress(accounts = [], targetAddress) { return accounts.find(({ address }) => address === targetAddress) } @@ -307,7 +347,7 @@ export function getAccountByAddress (accounts = [], targetAddress) { * @param {string} urlString - The URL string to strip the scheme from. * @returns {string} The URL string, without the scheme, if it was stripped. */ -export function stripHttpSchemes (urlString) { +export function stripHttpSchemes(urlString) { return urlString.replace(/^https?:\/\//u, '') } @@ -317,8 +357,7 @@ export function stripHttpSchemes (urlString) { * @param {string | URL | object} urlLike - The URL-like value to test. * @returns {boolean} Whether the URL-like value is an extension URL. */ -export function isExtensionUrl (urlLike) { - +export function isExtensionUrl(urlLike) { const EXT_PROTOCOLS = ['chrome-extension:', 'moz-extension:'] if (typeof urlLike === 'string') { @@ -343,7 +382,7 @@ export function isExtensionUrl (urlLike) { * @param {array} list - The array of objects to check * @returns {boolean} Whether or not the address is in the list */ -export function checkExistingAddresses (address, list = []) { +export function checkExistingAddresses(address, list = []) { if (!address) { return false } @@ -364,17 +403,17 @@ export function checkExistingAddresses (address, list = []) { * @param {number} precision - The maximum number of significant digits in the return value * @returns {string} The number in decimal form, with <= precision significant digits and no decimal trailing zeros */ -export function toPrecisionWithoutTrailingZeros (n, precision) { - return (new BigNumber(n)) +export function toPrecisionWithoutTrailingZeros(n, precision) { + return new BigNumber(n) .toPrecision(precision) .replace(/(\.[0-9]*[1-9])0*|(\.0*)/u, '$1') } /** - * Given and object where all values are strings, returns the same object with all values - * now prefixed with '0x' - */ -export function addHexPrefixToObjectValues (obj) { + * Given and object where all values are strings, returns the same object with all values + * now prefixed with '0x' + */ +export function addHexPrefixToObjectValues(obj) { return Object.keys(obj).reduce((newObj, key) => { return { ...newObj, [key]: ethUtil.addHexPrefix(obj[key]) } }, {}) @@ -392,7 +431,15 @@ export function addHexPrefixToObjectValues (obj) { * @param {string} gasPrice - A hex representation of the gas price for the transaction * @returns {object} An object ready for submission to the blockchain, with all values appropriately hex prefixed */ -export function constructTxParams ({ sendToken, data, to, amount, from, gas, gasPrice }) { +export function constructTxParams({ + sendToken, + data, + to, + amount, + from, + gas, + gasPrice, +}) { const txParams = { data, from, @@ -417,20 +464,21 @@ export function constructTxParams ({ sendToken, data, to, amount, from, gas, gas * @returns {Promise} Returns the result of the RPC method call, * or throws an error in case of failure. */ -export async function jsonRpcRequest (rpcUrl, rpcMethod, rpcParams = []) { - const jsonRpcResponse = await window.fetch(rpcUrl, { - method: 'POST', - body: JSON.stringify({ - id: Date.now().toString(), - jsonrpc: '2.0', - method: rpcMethod, - params: rpcParams, - }), - headers: { - 'Content-Type': 'application/json', - }, - cache: 'default', - }) +export async function jsonRpcRequest(rpcUrl, rpcMethod, rpcParams = []) { + const jsonRpcResponse = await window + .fetch(rpcUrl, { + method: 'POST', + body: JSON.stringify({ + id: Date.now().toString(), + jsonrpc: '2.0', + method: rpcMethod, + params: rpcParams, + }), + headers: { + 'Content-Type': 'application/json', + }, + cache: 'default', + }) .then((httpResponse) => httpResponse.json()) if ( diff --git a/ui/app/helpers/utils/util.test.js b/ui/app/helpers/utils/util.test.js index 21b3aa9ed..15c8e722f 100644 --- a/ui/app/helpers/utils/util.test.js +++ b/ui/app/helpers/utils/util.test.js @@ -182,7 +182,9 @@ describe('util', function () { }) it('should return 0.500 ETH', function () { - const input = new ethUtil.BN(ethInWei, 10).div(new ethUtil.BN('2', 10)).toJSON() + const input = new ethUtil.BN(ethInWei, 10) + .div(new ethUtil.BN('2', 10)) + .toJSON() const result = util.formatBalance(input, 3) assert.equal(result, '0.500 ETH') }) @@ -233,7 +235,13 @@ describe('util', function () { Object.keys(valueTable).forEach((currency) => { const value = new ethUtil.BN(valueTable[currency], 10) const output = util.normalizeToWei(value, currency) - assert.equal(output.toString(10), valueTable.wei, `value of ${output.toString(10)} ${currency} should convert to ${oneEthBn}`) + assert.equal( + output.toString(10), + valueTable.wei, + `value of ${output.toString( + 10, + )} ${currency} should convert to ${oneEthBn}`, + ) }) }) }) @@ -279,27 +287,39 @@ describe('util', function () { it('should convert a ether number to the appropriate equivalent wei', function () { const result = util.normalizeNumberToWei(1.111, 'ether') - assert.equal(result.toString(10), '1111000000000000000', 'accepts decimals') + assert.equal( + result.toString(10), + '1111000000000000000', + 'accepts decimals', + ) }) }) describe('#isHex', function () { it('should return true when given a hex string', function () { - const result = util.isHex('c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2') + const result = util.isHex( + 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2', + ) assert(result) }) it('should return false when given a non-hex string', function () { - const result = util.isHex('c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714imnotreal') + const result = util.isHex( + 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714imnotreal', + ) assert(!result) }) it('should return false when given a string containing a non letter/number character', function () { - const result = util.isHex('c3ab8ff13720!8ad9047dd39466b3c%8974e592c2fa383d4a396071imnotreal') + const result = util.isHex( + 'c3ab8ff13720!8ad9047dd39466b3c%8974e592c2fa383d4a396071imnotreal', + ) assert(!result) }) it('should return true when given a hex string with hex-prefix', function () { - const result = util.isHex('0xc3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2') + const result = util.isHex( + '0xc3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2', + ) assert(result) }) }) @@ -307,7 +327,7 @@ describe('util', function () { describe('#getRandomFileName', function () { it('should only return a string containing alphanumeric characters', function () { const result = util.getRandomFileName() - assert(result.match(/^[a-zA-Z0-9]*$/ug)) + assert(result.match(/^[a-zA-Z0-9]*$/gu)) }) // 50 samples diff --git a/ui/app/hooks/tests/useCancelTransaction.test.js b/ui/app/hooks/tests/useCancelTransaction.test.js index a355ee5e5..903e861d0 100644 --- a/ui/app/hooks/tests/useCancelTransaction.test.js +++ b/ui/app/hooks/tests/useCancelTransaction.test.js @@ -35,17 +35,26 @@ describe('useCancelTransaction', function () { }) }) transactions.forEach((transactionGroup) => { - const originalGasPrice = transactionGroup.primaryTransaction.txParams?.gasPrice - const gasPrice = originalGasPrice && increaseLastGasPrice(originalGasPrice) + const originalGasPrice = + transactionGroup.primaryTransaction.txParams?.gasPrice + const gasPrice = + originalGasPrice && increaseLastGasPrice(originalGasPrice) const transactionId = transactionGroup.initialTransaction.id it(`should indicate account has insufficient funds to cover ${gasPrice} gas price`, function () { - const { result } = renderHook(() => useCancelTransaction(transactionGroup)) + const { result } = renderHook(() => + useCancelTransaction(transactionGroup), + ) assert.equal(result.current[0], false) }) it(`should return a function that kicks off cancellation for id ${transactionId}`, function () { - const { result } = renderHook(() => useCancelTransaction(transactionGroup)) + const { result } = renderHook(() => + useCancelTransaction(transactionGroup), + ) assert.equal(typeof result.current[1], 'function') - result.current[1]({ preventDefault: () => undefined, stopPropagation: () => undefined }) + result.current[1]({ + preventDefault: () => undefined, + stopPropagation: () => undefined, + }) assert.equal( dispatch.calledWith( showModal({ @@ -78,17 +87,26 @@ describe('useCancelTransaction', function () { }) }) transactions.forEach((transactionGroup) => { - const originalGasPrice = transactionGroup.primaryTransaction.txParams?.gasPrice - const gasPrice = originalGasPrice && increaseLastGasPrice(originalGasPrice) + const originalGasPrice = + transactionGroup.primaryTransaction.txParams?.gasPrice + const gasPrice = + originalGasPrice && increaseLastGasPrice(originalGasPrice) const transactionId = transactionGroup.initialTransaction.id it(`should indicate account has funds to cover ${gasPrice} gas price`, function () { - const { result } = renderHook(() => useCancelTransaction(transactionGroup)) + const { result } = renderHook(() => + useCancelTransaction(transactionGroup), + ) assert.equal(result.current[0], true) }) it(`should return a function that kicks off cancellation for id ${transactionId}`, function () { - const { result } = renderHook(() => useCancelTransaction(transactionGroup)) + const { result } = renderHook(() => + useCancelTransaction(transactionGroup), + ) assert.equal(typeof result.current[1], 'function') - result.current[1]({ preventDefault: () => undefined, stopPropagation: () => undefined }) + result.current[1]({ + preventDefault: () => undefined, + stopPropagation: () => undefined, + }) assert.equal( dispatch.calledWith( showModal({ diff --git a/ui/app/hooks/tests/useCurrencyDisplay.test.js b/ui/app/hooks/tests/useCurrencyDisplay.test.js index 8b3f6910a..bacaa6ff0 100644 --- a/ui/app/hooks/tests/useCurrencyDisplay.test.js +++ b/ui/app/hooks/tests/useCurrencyDisplay.test.js @@ -3,7 +3,11 @@ import { renderHook } from '@testing-library/react-hooks' import * as reactRedux from 'react-redux' import sinon from 'sinon' import { useCurrencyDisplay } from '../useCurrencyDisplay' -import { getCurrentCurrency, getNativeCurrency, getConversionRate } from '../../selectors' +import { + getCurrentCurrency, + getNativeCurrency, + getConversionRate, +} from '../../selectors' const tests = [ { diff --git a/ui/app/hooks/tests/useRetryTransaction.test.js b/ui/app/hooks/tests/useRetryTransaction.test.js index b922bd92c..d1e1fb541 100644 --- a/ui/app/hooks/tests/useRetryTransaction.test.js +++ b/ui/app/hooks/tests/useRetryTransaction.test.js @@ -12,7 +12,10 @@ describe('useRetryTransaction', function () { describe('when transaction meets retry enabled criteria', function () { const dispatch = sinon.spy(() => Promise.resolve({ blockTime: 0 })) const trackEvent = sinon.spy() - const event = { preventDefault: () => undefined, stopPropagation: () => undefined } + const event = { + preventDefault: () => undefined, + stopPropagation: () => undefined, + } before(function () { sinon.stub(reactRedux, 'useDispatch').returns(dispatch) @@ -35,14 +38,18 @@ describe('useRetryTransaction', function () { } it('retryTransaction function should track metrics', function () { - const { result } = renderHook(() => useRetryTransaction(retryEnabledTransaction, true)) + const { result } = renderHook(() => + useRetryTransaction(retryEnabledTransaction, true), + ) const retry = result.current retry(event) assert.equal(trackEvent.calledOnce, true) }) it('retryTransaction function should show retry sidebar', async function () { - const { result } = renderHook(() => useRetryTransaction(retryEnabledTransaction, true)) + const { result } = renderHook(() => + useRetryTransaction(retryEnabledTransaction, true), + ) const retry = result.current await retry(event) const calls = dispatch.getCalls() diff --git a/ui/app/hooks/tests/useTokenData.test.js b/ui/app/hooks/tests/useTokenData.test.js index f745ba23b..8a5d1cdc6 100644 --- a/ui/app/hooks/tests/useTokenData.test.js +++ b/ui/app/hooks/tests/useTokenData.test.js @@ -5,30 +5,33 @@ import { useTokenData } from '../useTokenData' const tests = [ { - data: '0xa9059cbb000000000000000000000000ffe5bc4e8f1f969934d773fa67da095d2e491a970000000000000000000000000000000000000000000000000000000000003a98', + data: + '0xa9059cbb000000000000000000000000ffe5bc4e8f1f969934d773fa67da095d2e491a970000000000000000000000000000000000000000000000000000000000003a98', tokenData: { - 'name': 'transfer', - 'args': [ + name: 'transfer', + args: [ '0xffe5bc4e8f1f969934d773fa67da095d2e491a97', ethers.BigNumber.from(15000), ], }, }, { - data: '0xa9059cbb000000000000000000000000ffe5bc4e8f1f969934d773fa67da095d2e491a9700000000000000000000000000000000000000000000000000000000000061a8', + data: + '0xa9059cbb000000000000000000000000ffe5bc4e8f1f969934d773fa67da095d2e491a9700000000000000000000000000000000000000000000000000000000000061a8', tokenData: { - 'name': 'transfer', - 'args': [ + name: 'transfer', + args: [ '0xffe5bc4e8f1f969934d773fa67da095d2e491a97', ethers.BigNumber.from(25000), ], }, }, { - data: '0xa9059cbb000000000000000000000000ffe5bc4e8f1f969934d773fa67da095d2e491a970000000000000000000000000000000000000000000000000000000000002710', + data: + '0xa9059cbb000000000000000000000000ffe5bc4e8f1f969934d773fa67da095d2e491a970000000000000000000000000000000000000000000000000000000000002710', tokenData: { - 'name': 'transfer', - 'args': [ + name: 'transfer', + args: [ '0xffe5bc4e8f1f969934d773fa67da095d2e491a97', ethers.BigNumber.from(10000), ], @@ -42,14 +45,18 @@ const tests = [ describe('useTokenData', function () { tests.forEach((test) => { - const testTitle = test.tokenData === null - ? `should return null when no data provided` - : `should return properly decoded data with _value ${test.tokenData.args[1].value}` + const testTitle = + test.tokenData === null + ? `should return null when no data provided` + : `should return properly decoded data with _value ${test.tokenData.args[1].value}` it(testTitle, function () { const { result } = renderHook(() => useTokenData(test.data)) if (test.tokenData) { assert.equal(result.current.name, test.tokenData.name) - assert.equal(result.current.args[0].toLowerCase(), test.tokenData.args[0]) + assert.equal( + result.current.args[0].toLowerCase(), + test.tokenData.args[0], + ) assert.ok(test.tokenData.args[1].eq(result.current.args[1])) } else { assert.equal(result.current, test.tokenData) diff --git a/ui/app/hooks/tests/useTokenDisplayValue.test.js b/ui/app/hooks/tests/useTokenDisplayValue.test.js index bcb028957..e9ba328bd 100644 --- a/ui/app/hooks/tests/useTokenDisplayValue.test.js +++ b/ui/app/hooks/tests/useTokenDisplayValue.test.js @@ -126,7 +126,9 @@ describe('useTokenDisplayValue', function () { const getTokenDataStub = sinon.stub(txUtil, 'getTokenData') getTokenDataStub.callsFake(() => test.tokenData) getTokenValueStub.callsFake(() => test.tokenValue) - const { result } = renderHook(() => useTokenDisplayValue(`${idx}-fakestring`, test.token)) + const { result } = renderHook(() => + useTokenDisplayValue(`${idx}-fakestring`, test.token), + ) sinon.restore() assert.equal(result.current, test.displayValue) }) diff --git a/ui/app/hooks/tests/useTransactionDisplayData.test.js b/ui/app/hooks/tests/useTransactionDisplayData.test.js index d44eb77ae..cfecc544b 100644 --- a/ui/app/hooks/tests/useTransactionDisplayData.test.js +++ b/ui/app/hooks/tests/useTransactionDisplayData.test.js @@ -7,7 +7,12 @@ import { MemoryRouter } from 'react-router-dom' import transactions from '../../../../test/data/transaction-data.json' import { useTransactionDisplayData } from '../useTransactionDisplayData' import * as useTokenFiatAmountHooks from '../useTokenFiatAmount' -import { getPreferences, getShouldShowFiat, getNativeCurrency, getCurrentCurrency } from '../../selectors' +import { + getPreferences, + getShouldShowFiat, + getNativeCurrency, + getCurrentCurrency, +} from '../../selectors' import { getTokens } from '../../ducks/metamask/metamask' import * as i18nhooks from '../useI18nContext' import { getMessage } from '../../helpers/utils/i18n-helper' @@ -112,7 +117,9 @@ const expectedResults = [ let useSelector, useI18nContext, useTokenFiatAmount const renderHookWithRouter = (cb, tokenAddress) => { - const initialEntries = [tokenAddress ? `${ASSET_ROUTE}/${tokenAddress}` : DEFAULT_ROUTE] + const initialEntries = [ + tokenAddress ? `${ASSET_ROUTE}/${tokenAddress}` : DEFAULT_ROUTE, + ] // eslint-disable-next-line const wrapper = ({ children }) => {children} return renderHook(cb, { wrapper }) @@ -121,15 +128,26 @@ const renderHookWithRouter = (cb, tokenAddress) => { describe('useTransactionDisplayData', function () { before(function () { useSelector = sinon.stub(reactRedux, 'useSelector') - useTokenFiatAmount = sinon.stub(useTokenFiatAmountHooks, 'useTokenFiatAmount') + useTokenFiatAmount = sinon.stub( + useTokenFiatAmountHooks, + 'useTokenFiatAmount', + ) useTokenFiatAmount.returns((tokenAddress) => { return tokenAddress ? '1 TST' : undefined }) useI18nContext = sinon.stub(i18nhooks, 'useI18nContext') - useI18nContext.returns((key, variables) => getMessage('en', messages, key, variables)) + useI18nContext.returns((key, variables) => + getMessage('en', messages, key, variables), + ) useSelector.callsFake((selector) => { if (selector === getTokens) { - return [{ address: '0xabca64466f257793eaa52fcfff5066894b76a149', symbol: 'ABC', decimals: 18 }] + return [ + { + address: '0xabca64466f257793eaa52fcfff5066894b76a149', + symbol: 'ABC', + decimals: 18, + }, + ] } else if (selector === getPreferences) { return { useNativeCurrencyAsPrimaryCurrency: true, @@ -147,43 +165,76 @@ describe('useTransactionDisplayData', function () { transactions.forEach((transactionGroup, idx) => { describe(`when called with group containing primaryTransaction id ${transactionGroup.primaryTransaction.id}`, function () { const expected = expectedResults[idx] - const tokenAddress = transactionGroup.primaryTransaction?.destinationTokenAddress + const tokenAddress = + transactionGroup.primaryTransaction?.destinationTokenAddress it(`should return a title of ${expected.title}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) assert.equal(result.current.title, expected.title) }) it(`should return a subtitle of ${expected.subtitle}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) assert.equal(result.current.subtitle, expected.subtitle) }) it(`should return a category of ${expected.category}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) assert.equal(result.current.category, expected.category) }) it(`should return a primaryCurrency of ${expected.primaryCurrency}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) assert.equal(result.current.primaryCurrency, expected.primaryCurrency) }) it(`should return a secondaryCurrency of ${expected.secondaryCurrency}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) - assert.equal(result.current.secondaryCurrency, expected.secondaryCurrency) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) + assert.equal( + result.current.secondaryCurrency, + expected.secondaryCurrency, + ) }) it(`should return a displayedStatusKey of ${expected.displayedStatusKey}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) - assert.equal(result.current.displayedStatusKey, expected.displayedStatusKey) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) + assert.equal( + result.current.displayedStatusKey, + expected.displayedStatusKey, + ) }) it(`should return a recipientAddress of ${expected.recipientAddress}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) assert.equal(result.current.recipientAddress, expected.recipientAddress) }) it(`should return a senderAddress of ${expected.senderAddress}`, function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactionGroup), tokenAddress) + const { result } = renderHookWithRouter( + () => useTransactionDisplayData(transactionGroup), + tokenAddress, + ) assert.equal(result.current.senderAddress, expected.senderAddress) }) }) }) it('should return an appropriate object', function () { - const { result } = renderHookWithRouter(() => useTransactionDisplayData(transactions[0])) + const { result } = renderHookWithRouter(() => + useTransactionDisplayData(transactions[0]), + ) assert.deepEqual(result.current, expectedResults[0]) }) after(function () { diff --git a/ui/app/hooks/tests/useUserPreferencedCurrency.test.js b/ui/app/hooks/tests/useUserPreferencedCurrency.test.js index b5d7b47e9..0b5534fdb 100644 --- a/ui/app/hooks/tests/useUserPreferencedCurrency.test.js +++ b/ui/app/hooks/tests/useUserPreferencedCurrency.test.js @@ -111,7 +111,7 @@ const tests = [ }, ] -function getFakeUseSelector (state) { +function getFakeUseSelector(state) { return (selector) => { if (selector === getPreferences) { return state @@ -128,13 +128,22 @@ describe('useUserPreferencedCurrency', function () { const stub = sinon.stub(reactRedux, 'useSelector') stub.callsFake(getFakeUseSelector(state)) - const { result: hookResult } = renderHook(() => useUserPreferencedCurrency(type, otherParams)) + const { result: hookResult } = renderHook(() => + useUserPreferencedCurrency(type, otherParams), + ) stub.restore() - it(`should return currency as ${result.currency || 'not modified by user preferences'}`, function () { + it(`should return currency as ${ + result.currency || 'not modified by user preferences' + }`, function () { assert.equal(hookResult.current.currency, result.currency) }) - it(`should return decimals as ${result.numberOfDecimals || 'not modified by user preferences'}`, function () { - assert.equal(hookResult.current.numberOfDecimals, result.numberOfDecimals) + it(`should return decimals as ${ + result.numberOfDecimals || 'not modified by user preferences' + }`, function () { + assert.equal( + hookResult.current.numberOfDecimals, + result.numberOfDecimals, + ) }) }) }) diff --git a/ui/app/hooks/useCancelTransaction.js b/ui/app/hooks/useCancelTransaction.js index 547697360..ad3fcfa0c 100644 --- a/ui/app/hooks/useCancelTransaction.js +++ b/ui/app/hooks/useCancelTransaction.js @@ -2,7 +2,10 @@ import { useDispatch, useSelector } from 'react-redux' import { useCallback } from 'react' import { showModal } from '../store/actions' import { isBalanceSufficient } from '../pages/send/send.utils' -import { getHexGasTotal, increaseLastGasPrice } from '../helpers/utils/confirm-tx.util' +import { + getHexGasTotal, + increaseLastGasPrice, +} from '../helpers/utils/confirm-tx.util' import { getConversionRate, getSelectedAccount } from '../selectors' /** @@ -15,28 +18,39 @@ import { getConversionRate, getSelectedAccount } from '../selectors' * @param {Object} transactionGroup * @return {[boolean, Function]} */ -export function useCancelTransaction (transactionGroup) { +export function useCancelTransaction(transactionGroup) { const { primaryTransaction, initialTransaction } = transactionGroup const gasPrice = primaryTransaction.txParams?.gasPrice const { id } = initialTransaction const dispatch = useDispatch() const selectedAccount = useSelector(getSelectedAccount) const conversionRate = useSelector(getConversionRate) - const cancelTransaction = useCallback((event) => { - event.stopPropagation() + const cancelTransaction = useCallback( + (event) => { + event.stopPropagation() - return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId: id, originalGasPrice: gasPrice })) - }, [dispatch, id, gasPrice]) + return dispatch( + showModal({ + name: 'CANCEL_TRANSACTION', + transactionId: id, + originalGasPrice: gasPrice, + }), + ) + }, + [dispatch, id, gasPrice], + ) - const hasEnoughCancelGas = primaryTransaction.txParams && isBalanceSufficient({ - amount: '0x0', - gasTotal: getHexGasTotal({ - gasPrice: increaseLastGasPrice(gasPrice), - gasLimit: primaryTransaction.txParams.gas, - }), - balance: selectedAccount.balance, - conversionRate, - }) + const hasEnoughCancelGas = + primaryTransaction.txParams && + isBalanceSufficient({ + amount: '0x0', + gasTotal: getHexGasTotal({ + gasPrice: increaseLastGasPrice(gasPrice), + gasLimit: primaryTransaction.txParams.gas, + }), + balance: selectedAccount.balance, + conversionRate, + }) return [hasEnoughCancelGas, cancelTransaction] } diff --git a/ui/app/hooks/useCopyToClipboard.js b/ui/app/hooks/useCopyToClipboard.js index 8d870d1b8..e1971c544 100644 --- a/ui/app/hooks/useCopyToClipboard.js +++ b/ui/app/hooks/useCopyToClipboard.js @@ -11,7 +11,7 @@ import { useTimeout } from './useTimeout' */ const DEFAULT_DELAY = 3000 -export function useCopyToClipboard (delay = DEFAULT_DELAY) { +export function useCopyToClipboard(delay = DEFAULT_DELAY) { const [copied, setCopied] = useState(false) const startTimeout = useTimeout(() => setCopied(false), delay, false) diff --git a/ui/app/hooks/useCurrencyDisplay.js b/ui/app/hooks/useCurrencyDisplay.js index 4e2c99e3f..14e274d2f 100644 --- a/ui/app/hooks/useCurrencyDisplay.js +++ b/ui/app/hooks/useCurrencyDisplay.js @@ -1,7 +1,14 @@ import { useMemo } from 'react' import { useSelector } from 'react-redux' -import { formatCurrency, getValueFromWeiHex } from '../helpers/utils/confirm-tx.util' -import { getCurrentCurrency, getConversionRate, getNativeCurrency } from '../selectors' +import { + formatCurrency, + getValueFromWeiHex, +} from '../helpers/utils/confirm-tx.util' +import { + getCurrentCurrency, + getConversionRate, + getNativeCurrency, +} from '../selectors' /** * Defines the shape of the options parameter for useCurrencyDisplay @@ -31,7 +38,10 @@ import { getCurrentCurrency, getConversionRate, getNativeCurrency } from '../sel * @param {UseCurrencyOptions} opts - An object for options to format the inputValue * @return {[string, CurrencyDisplayParts]} */ -export function useCurrencyDisplay (inputValue, { displayValue, prefix, numberOfDecimals, denomination, currency, ...opts }) { +export function useCurrencyDisplay( + inputValue, + { displayValue, prefix, numberOfDecimals, denomination, currency, ...opts }, +) { const currentCurrency = useSelector(getCurrentCurrency) const nativeCurrency = useSelector(getNativeCurrency) const conversionRate = useSelector(getConversionRate) @@ -53,7 +63,15 @@ export function useCurrencyDisplay (inputValue, { displayValue, prefix, numberOf }), toCurrency, ) - }, [inputValue, nativeCurrency, conversionRate, displayValue, numberOfDecimals, denomination, toCurrency]) + }, [ + inputValue, + nativeCurrency, + conversionRate, + displayValue, + numberOfDecimals, + denomination, + toCurrency, + ]) let suffix @@ -61,5 +79,8 @@ export function useCurrencyDisplay (inputValue, { displayValue, prefix, numberOf suffix = opts.suffix || toCurrency.toUpperCase() } - return [`${prefix || ''}${value}${suffix ? ` ${suffix}` : ''}`, { prefix, value, suffix }] + return [ + `${prefix || ''}${value}${suffix ? ` ${suffix}` : ''}`, + { prefix, value, suffix }, + ] } diff --git a/ui/app/hooks/useCurrentAsset.js b/ui/app/hooks/useCurrentAsset.js index 7a5b14ec4..80e905a94 100644 --- a/ui/app/hooks/useCurrentAsset.js +++ b/ui/app/hooks/useCurrentAsset.js @@ -10,15 +10,18 @@ import { ETH_SWAPS_TOKEN_OBJECT } from '../helpers/constants/swaps' * the primary, unfiltered, activity list or the ETH asset page. * @returns {import('./useTokenDisplayValue').Token} */ -export function useCurrentAsset () { +export function useCurrentAsset() { // To determine which primary currency to display for swaps transactions we need to be aware // of which asset, if any, we are viewing at present - const match = useRouteMatch({ path: `${ASSET_ROUTE}/:asset`, exact: true, strict: true }) + const match = useRouteMatch({ + path: `${ASSET_ROUTE}/:asset`, + exact: true, + strict: true, + }) const tokenAddress = match?.params?.asset const knownTokens = useSelector(getTokens) - const token = tokenAddress && knownTokens.find( - ({ address }) => address === tokenAddress, - ) + const token = + tokenAddress && knownTokens.find(({ address }) => address === tokenAddress) return token ?? ETH_SWAPS_TOKEN_OBJECT } diff --git a/ui/app/hooks/useEqualityCheck.js b/ui/app/hooks/useEqualityCheck.js index ee4ca1e0a..abb635c99 100644 --- a/ui/app/hooks/useEqualityCheck.js +++ b/ui/app/hooks/useEqualityCheck.js @@ -14,7 +14,7 @@ import { isEqual } from 'lodash' * @param {(T, T) => boolean} equalityFn - A function to determine equality * @returns {T} */ -export function useEqualityCheck (value, equalityFn = isEqual) { +export function useEqualityCheck(value, equalityFn = isEqual) { const [computedValue, setComputedValue] = useState(value) useLayoutEffect(() => { diff --git a/ui/app/hooks/useEthFiatAmount.js b/ui/app/hooks/useEthFiatAmount.js index 2e12a272d..62d43b5c3 100644 --- a/ui/app/hooks/useEthFiatAmount.js +++ b/ui/app/hooks/useEthFiatAmount.js @@ -1,6 +1,10 @@ import { useMemo } from 'react' import { useSelector } from 'react-redux' -import { getConversionRate, getCurrentCurrency, getShouldShowFiat } from '../selectors' +import { + getConversionRate, + getCurrentCurrency, + getShouldShowFiat, +} from '../selectors' import { decEthToConvertedCurrency } from '../helpers/utils/conversions.util' import { formatCurrency } from '../helpers/utils/confirm-tx.util' @@ -14,7 +18,11 @@ import { formatCurrency } from '../helpers/utils/confirm-tx.util' * @param {boolean} hideCurrencySymbol Indicates whether the returned formatted amount should include the trailing currency symbol * @return {string} - The formatted token amount in the user's chosen fiat currency */ -export function useEthFiatAmount (ethAmount, overrides = {}, hideCurrencySymbol) { +export function useEthFiatAmount( + ethAmount, + overrides = {}, + hideCurrencySymbol, +) { const conversionRate = useSelector(getConversionRate) const currentCurrency = useSelector(getCurrentCurrency) const userPrefersShownFiat = useSelector(getShouldShowFiat) @@ -24,11 +32,19 @@ export function useEthFiatAmount (ethAmount, overrides = {}, hideCurrencySymbol) [conversionRate, currentCurrency, ethAmount], ) - if (!showFiat || currentCurrency.toUpperCase() === 'ETH' || conversionRate <= 0 || ethAmount === undefined) { + if ( + !showFiat || + currentCurrency.toUpperCase() === 'ETH' || + conversionRate <= 0 || + ethAmount === undefined + ) { return undefined } return hideCurrencySymbol ? formatCurrency(formattedFiat, currentCurrency) - : `${formatCurrency(formattedFiat, currentCurrency)} ${currentCurrency.toUpperCase()}` + : `${formatCurrency( + formattedFiat, + currentCurrency, + )} ${currentCurrency.toUpperCase()}` } diff --git a/ui/app/hooks/useI18nContext.js b/ui/app/hooks/useI18nContext.js index 819a85c7c..d2fb087c3 100644 --- a/ui/app/hooks/useI18nContext.js +++ b/ui/app/hooks/useI18nContext.js @@ -8,6 +8,6 @@ import { I18nContext } from '../contexts/i18n' * different places. * @return {Function} I18n function from contexts/I18n.js */ -export function useI18nContext () { +export function useI18nContext() { return useContext(I18nContext) } diff --git a/ui/app/hooks/useMethodData.js b/ui/app/hooks/useMethodData.js index c98060f6b..7df5d7604 100644 --- a/ui/app/hooks/useMethodData.js +++ b/ui/app/hooks/useMethodData.js @@ -16,10 +16,15 @@ import { getKnownMethodData } from '../selectors/selectors' * @param {string} data the transaction data to find method data for * @return {Object} contract method data */ -export function useMethodData (data) { +export function useMethodData(data) { const dispatch = useDispatch() - const knownMethodData = useSelector((state) => getKnownMethodData(state, data)) - const getContractMethodData = useCallback((methodData) => dispatch(getContractMethodDataAction(methodData)), [dispatch]) + const knownMethodData = useSelector((state) => + getKnownMethodData(state, data), + ) + const getContractMethodData = useCallback( + (methodData) => dispatch(getContractMethodDataAction(methodData)), + [dispatch], + ) useEffect(() => { if (data) { diff --git a/ui/app/hooks/useMetricEvent.js b/ui/app/hooks/useMetricEvent.js index 790bc5e28..d32c3b35a 100644 --- a/ui/app/hooks/useMetricEvent.js +++ b/ui/app/hooks/useMetricEvent.js @@ -3,28 +3,35 @@ import { MetaMetricsContext } from '../contexts/metametrics' import { MetaMetricsContext as NewMetaMetricsContext } from '../contexts/metametrics.new' import { useEqualityCheck } from './useEqualityCheck' -export function useMetricEvent (config = {}, overrides = {}) { +export function useMetricEvent(config = {}, overrides = {}) { const metricsEvent = useContext(MetaMetricsContext) - const trackEvent = useCallback(() => metricsEvent(config, overrides), [config, metricsEvent, overrides]) + const trackEvent = useCallback(() => metricsEvent(config, overrides), [ + config, + metricsEvent, + overrides, + ]) return trackEvent } /** - * track a metametrics event using segment - * e.g metricsEvent({ event: 'Unlocked MetaMask', category: 'Navigation' }) - * - * @param {object} config - configuration object for the event to track - * @param {string} config.event - event name to track - * @param {string} config.category - category to associate event to - * @param {boolean} [config.isOptIn] - happened during opt in/out workflow - * @param {object} [config.properties] - object of custom values to track, snake_case - * @param {number} [config.revenue] - amount of currency that event creates in revenue for MetaMask - * @param {string} [config.currency] - ISO 4127 format currency for events with revenue, defaults to US dollars - * @param {number} [config.value] - Abstract "value" that this event has for MetaMask. - * @return {() => undefined} function to execute the tracking event - */ -export function useNewMetricEvent (config) { + * track a metametrics event using segment + * e.g metricsEvent({ event: 'Unlocked MetaMask', category: 'Navigation' }) + * + * @param {object} config - configuration object for the event to track + * @param {string} config.event - event name to track + * @param {string} config.category - category to associate event to + * @param {boolean} [config.isOptIn] - happened during opt in/out workflow + * @param {object} [config.properties] - object of custom values to track, snake_case + * @param {number} [config.revenue] - amount of currency that event creates in revenue for MetaMask + * @param {string} [config.currency] - ISO 4127 format currency for events with revenue, defaults to US dollars + * @param {number} [config.value] - Abstract "value" that this event has for MetaMask. + * @return {() => undefined} function to execute the tracking event + */ +export function useNewMetricEvent(config) { const memoizedConfig = useEqualityCheck(config) const metricsEvent = useContext(NewMetaMetricsContext) - return useCallback(() => metricsEvent(memoizedConfig), [metricsEvent, memoizedConfig]) + return useCallback(() => metricsEvent(memoizedConfig), [ + metricsEvent, + memoizedConfig, + ]) } diff --git a/ui/app/hooks/usePrevious.js b/ui/app/hooks/usePrevious.js index 8a3721fe6..64ff105f1 100644 --- a/ui/app/hooks/usePrevious.js +++ b/ui/app/hooks/usePrevious.js @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react' -export function usePrevious (value) { +export function usePrevious(value) { const ref = useRef() useEffect(() => { ref.current = value diff --git a/ui/app/hooks/useRetryTransaction.js b/ui/app/hooks/useRetryTransaction.js index 1f3ffe701..c12000266 100644 --- a/ui/app/hooks/useRetryTransaction.js +++ b/ui/app/hooks/useRetryTransaction.js @@ -16,35 +16,44 @@ import { useMetricEvent } from './useMetricEvent' * @param {Object} transactionGroup - the transaction group * @return {Function} */ -export function useRetryTransaction (transactionGroup) { +export function useRetryTransaction(transactionGroup) { const { primaryTransaction, initialTransaction } = transactionGroup // Signature requests do not have a txParams, but this hook is called indiscriminately const gasPrice = primaryTransaction.txParams?.gasPrice - const trackMetricsEvent = useMetricEvent(({ + const trackMetricsEvent = useMetricEvent({ eventOpts: { category: 'Navigation', action: 'Activity Log', name: 'Clicked "Speed Up"', }, - })) + }) const dispatch = useDispatch() - const retryTransaction = useCallback(async (event) => { - event.stopPropagation() + const retryTransaction = useCallback( + async (event) => { + event.stopPropagation() - trackMetricsEvent() - const basicEstimates = await dispatch(fetchBasicGasAndTimeEstimates) - await dispatch(fetchGasEstimates(basicEstimates.blockTime)) - const transaction = initialTransaction - const increasedGasPrice = increaseLastGasPrice(gasPrice) - dispatch(setCustomGasPriceForRetry(increasedGasPrice || transaction.txParams.gasPrice)) - dispatch(setCustomGasLimit(transaction.txParams.gas)) - dispatch(showSidebar({ - transitionName: 'sidebar-left', - type: 'customize-gas', - props: { transaction }, - })) - }, [dispatch, trackMetricsEvent, initialTransaction, gasPrice]) + trackMetricsEvent() + const basicEstimates = await dispatch(fetchBasicGasAndTimeEstimates) + await dispatch(fetchGasEstimates(basicEstimates.blockTime)) + const transaction = initialTransaction + const increasedGasPrice = increaseLastGasPrice(gasPrice) + dispatch( + setCustomGasPriceForRetry( + increasedGasPrice || transaction.txParams.gasPrice, + ), + ) + dispatch(setCustomGasLimit(transaction.txParams.gas)) + dispatch( + showSidebar({ + transitionName: 'sidebar-left', + type: 'customize-gas', + props: { transaction }, + }), + ) + }, + [dispatch, trackMetricsEvent, initialTransaction, gasPrice], + ) return retryTransaction } diff --git a/ui/app/hooks/useShouldShowSpeedUp.js b/ui/app/hooks/useShouldShowSpeedUp.js index 437c6cba2..97c79044f 100644 --- a/ui/app/hooks/useShouldShowSpeedUp.js +++ b/ui/app/hooks/useShouldShowSpeedUp.js @@ -7,7 +7,7 @@ import { useEffect, useState } from 'react' * @param {Object} transactionGroup - the transaction group to check against * @param {boolean} isEarliestNonce - Whether this group is currently the earliest nonce */ -export function useShouldShowSpeedUp (transactionGroup, isEarliestNonce) { +export function useShouldShowSpeedUp(transactionGroup, isEarliestNonce) { const { transactions, hasRetried } = transactionGroup const [earliestTransaction = {}] = transactions const { submittedTime } = earliestTransaction diff --git a/ui/app/hooks/useSwappedTokenValue.js b/ui/app/hooks/useSwappedTokenValue.js index 8357d8749..f0fe9fd00 100644 --- a/ui/app/hooks/useSwappedTokenValue.js +++ b/ui/app/hooks/useSwappedTokenValue.js @@ -22,40 +22,44 @@ import { useTokenFiatAmount } from './useTokenFiatAmount' * @param {import('./useTokenDisplayValue').Token} currentAsset - The current asset the user is looking at * @returns {SwappedTokenValue} */ -export function useSwappedTokenValue (transactionGroup, currentAsset) { +export function useSwappedTokenValue(transactionGroup, currentAsset) { const { symbol, decimals, address } = currentAsset const { primaryTransaction, initialTransaction } = transactionGroup const { transactionCategory } = initialTransaction const { from: senderAddress } = initialTransaction.txParams || {} - const isViewingReceivedTokenFromSwap = ( - (currentAsset?.symbol === primaryTransaction.destinationTokenSymbol) || ( - currentAsset.address === ETH_SWAPS_TOKEN_ADDRESS && - primaryTransaction.destinationTokenSymbol === 'ETH' - ) - ) + const isViewingReceivedTokenFromSwap = + currentAsset?.symbol === primaryTransaction.destinationTokenSymbol || + (currentAsset.address === ETH_SWAPS_TOKEN_ADDRESS && + primaryTransaction.destinationTokenSymbol === 'ETH') - const swapTokenValue = transactionCategory === SWAP && isViewingReceivedTokenFromSwap - ? getSwapsTokensReceivedFromTxMeta( - primaryTransaction.destinationTokenSymbol, - initialTransaction, - address, - senderAddress, - decimals, - ) - : transactionCategory === SWAP && primaryTransaction.swapTokenValue + const swapTokenValue = + transactionCategory === SWAP && isViewingReceivedTokenFromSwap + ? getSwapsTokensReceivedFromTxMeta( + primaryTransaction.destinationTokenSymbol, + initialTransaction, + address, + senderAddress, + decimals, + ) + : transactionCategory === SWAP && primaryTransaction.swapTokenValue - const isNegative = typeof swapTokenValue === 'string' - ? Math.sign(swapTokenValue) === -1 - : false + const isNegative = + typeof swapTokenValue === 'string' + ? Math.sign(swapTokenValue) === -1 + : false const _swapTokenFiatAmount = useTokenFiatAmount( address, swapTokenValue || '', symbol, ) - const swapTokenFiatAmount = ( + const swapTokenFiatAmount = swapTokenValue && isViewingReceivedTokenFromSwap && _swapTokenFiatAmount - ) - return { swapTokenValue, swapTokenFiatAmount, isViewingReceivedTokenFromSwap, isNegative } + return { + swapTokenValue, + swapTokenFiatAmount, + isViewingReceivedTokenFromSwap, + isNegative, + } } diff --git a/ui/app/hooks/useSwapsEthToken.js b/ui/app/hooks/useSwapsEthToken.js index 398668cf5..cd531f6e3 100644 --- a/ui/app/hooks/useSwapsEthToken.js +++ b/ui/app/hooks/useSwapsEthToken.js @@ -1,7 +1,10 @@ import { useSelector } from 'react-redux' import { getSelectedAccount } from '../selectors' import { ETH_SWAPS_TOKEN_OBJECT } from '../helpers/constants/swaps' -import { getValueFromWeiHex, hexToDecimal } from '../helpers/utils/conversions.util' +import { + getValueFromWeiHex, + hexToDecimal, +} from '../helpers/utils/conversions.util' /** * @typedef {Object} SwapsEthToken @@ -34,7 +37,7 @@ import { getValueFromWeiHex, hexToDecimal } from '../helpers/utils/conversions.u * @returns {SwapsEthToken} The token object representation of the currently * selected account's ETH balance, as expected by the Swaps API. */ -export function useSwapsEthToken () { +export function useSwapsEthToken() { const selectedAccount = useSelector(getSelectedAccount) const { balance } = selectedAccount diff --git a/ui/app/hooks/useTimeout.js b/ui/app/hooks/useTimeout.js index 244e9a34c..6ac46e7a3 100644 --- a/ui/app/hooks/useTimeout.js +++ b/ui/app/hooks/useTimeout.js @@ -9,7 +9,7 @@ import { useState, useEffect, useRef, useCallback } from 'react' * * @return {Function|undefined} */ -export function useTimeout (cb, delay, immediate = true) { +export function useTimeout(cb, delay, immediate = true) { const saveCb = useRef() const [timeoutId, setTimeoutId] = useState(null) diff --git a/ui/app/hooks/useTokenData.js b/ui/app/hooks/useTokenData.js index 932a8752f..685efa057 100644 --- a/ui/app/hooks/useTokenData.js +++ b/ui/app/hooks/useTokenData.js @@ -13,7 +13,7 @@ import { getTokenData } from '../helpers/utils/transactions.util' * with a token. * @return {Object} - Decoded token data */ -export function useTokenData (transactionData, isTokenTransaction = true) { +export function useTokenData(transactionData, isTokenTransaction = true) { return useMemo(() => { if (!isTokenTransaction || !transactionData) { return null diff --git a/ui/app/hooks/useTokenDisplayValue.js b/ui/app/hooks/useTokenDisplayValue.js index 347c0819c..331b53dfb 100644 --- a/ui/app/hooks/useTokenDisplayValue.js +++ b/ui/app/hooks/useTokenDisplayValue.js @@ -1,5 +1,8 @@ import { useMemo } from 'react' -import { getTokenValueParam, calcTokenAmount } from '../helpers/utils/token-util' +import { + getTokenValueParam, + calcTokenAmount, +} from '../helpers/utils/token-util' import { useTokenData } from './useTokenData' /** @@ -24,17 +27,21 @@ import { useTokenData } from './useTokenData' * with a token. * @return {string} - The computed displayValue of the provided transactionData and token */ -export function useTokenDisplayValue (transactionData, token, isTokenTransaction = true) { +export function useTokenDisplayValue( + transactionData, + token, + isTokenTransaction = true, +) { const tokenData = useTokenData(transactionData, isTokenTransaction) const shouldCalculateTokenValue = Boolean( // If we are currently processing a token transaction isTokenTransaction && - // and raw transaction data string is provided - transactionData && - // and a token object has been provided - token && - // and we are able to parse the token details from the raw data - tokenData?.args?.length, + // and raw transaction data string is provided + transactionData && + // and a token object has been provided + token && + // and we are able to parse the token details from the raw data + tokenData?.args?.length, ) const displayValue = useMemo(() => { diff --git a/ui/app/hooks/useTokenFiatAmount.js b/ui/app/hooks/useTokenFiatAmount.js index 65e423805..8f1ae11db 100644 --- a/ui/app/hooks/useTokenFiatAmount.js +++ b/ui/app/hooks/useTokenFiatAmount.js @@ -1,6 +1,11 @@ import { useMemo } from 'react' import { useSelector } from 'react-redux' -import { getTokenExchangeRates, getConversionRate, getCurrentCurrency, getShouldShowFiat } from '../selectors' +import { + getTokenExchangeRates, + getConversionRate, + getCurrentCurrency, + getShouldShowFiat, +} from '../selectors' import { getTokenFiatAmount } from '../helpers/utils/token-util' /** @@ -16,24 +21,39 @@ import { getTokenFiatAmount } from '../helpers/utils/token-util' * @param {boolean} hideCurrencySymbol Indicates whether the returned formatted amount should include the trailing currency symbol * @return {string} - The formatted token amount in the user's chosen fiat currency */ -export function useTokenFiatAmount (tokenAddress, tokenAmount, tokenSymbol, overrides = {}, hideCurrencySymbol) { +export function useTokenFiatAmount( + tokenAddress, + tokenAmount, + tokenSymbol, + overrides = {}, + hideCurrencySymbol, +) { const contractExchangeRates = useSelector(getTokenExchangeRates) const conversionRate = useSelector(getConversionRate) const currentCurrency = useSelector(getCurrentCurrency) const userPrefersShownFiat = useSelector(getShouldShowFiat) const showFiat = overrides.showFiat ?? userPrefersShownFiat - const tokenExchangeRate = overrides.exchangeRate ?? contractExchangeRates[tokenAddress] + const tokenExchangeRate = + overrides.exchangeRate ?? contractExchangeRates[tokenAddress] const formattedFiat = useMemo( - () => getTokenFiatAmount( + () => + getTokenFiatAmount( + tokenExchangeRate, + conversionRate, + currentCurrency, + tokenAmount, + tokenSymbol, + true, + hideCurrencySymbol, + ), + [ tokenExchangeRate, conversionRate, currentCurrency, tokenAmount, tokenSymbol, - true, hideCurrencySymbol, - ), - [tokenExchangeRate, conversionRate, currentCurrency, tokenAmount, tokenSymbol, hideCurrencySymbol], + ], ) if (!showFiat || currentCurrency.toUpperCase() === tokenSymbol) { diff --git a/ui/app/hooks/useTokenTracker.js b/ui/app/hooks/useTokenTracker.js index 65671cd00..5e15af03d 100644 --- a/ui/app/hooks/useTokenTracker.js +++ b/ui/app/hooks/useTokenTracker.js @@ -4,7 +4,7 @@ import { useSelector } from 'react-redux' import { getCurrentNetwork, getSelectedAddress } from '../selectors' import { useEqualityCheck } from './useEqualityCheck' -export function useTokenTracker (tokens) { +export function useTokenTracker(tokens) { const network = useSelector(getCurrentNetwork) const userAddress = useSelector(getSelectedAddress) @@ -34,20 +34,23 @@ export function useTokenTracker (tokens) { } }, []) - const buildTracker = useCallback((address, tokenList) => { - // clear out previous tracker, if it exists. - teardownTracker() - tokenTracker.current = new TokenTracker({ - userAddress: address, - provider: global.ethereumProvider, - tokens: tokenList, - pollingInterval: 8000, - }) + const buildTracker = useCallback( + (address, tokenList) => { + // clear out previous tracker, if it exists. + teardownTracker() + tokenTracker.current = new TokenTracker({ + userAddress: address, + provider: global.ethereumProvider, + tokens: tokenList, + pollingInterval: 8000, + }) - tokenTracker.current.on('update', updateBalances) - tokenTracker.current.on('error', showError) - tokenTracker.current.updateBalances() - }, [updateBalances, showError, teardownTracker]) + tokenTracker.current.on('update', updateBalances) + tokenTracker.current.on('error', showError) + tokenTracker.current.updateBalances() + }, + [updateBalances, showError, teardownTracker], + ) // Effect to remove the tracker when the component is removed from DOM // Do not overload this effect with additional dependencies. teardownTracker @@ -82,7 +85,14 @@ export function useTokenTracker (tokens) { } buildTracker(userAddress, memoizedTokens) - }, [userAddress, teardownTracker, network, memoizedTokens, updateBalances, buildTracker]) + }, [ + userAddress, + teardownTracker, + network, + memoizedTokens, + updateBalances, + buildTracker, + ]) return { loading, tokensWithBalances, error } } diff --git a/ui/app/hooks/useTokensToSearch.js b/ui/app/hooks/useTokensToSearch.js index 5b0b05521..0d9485e1b 100644 --- a/ui/app/hooks/useTokensToSearch.js +++ b/ui/app/hooks/useTokensToSearch.js @@ -5,40 +5,60 @@ import BigNumber from 'bignumber.js' import { isEqual, shuffle } from 'lodash' import { checksumAddress } from '../helpers/utils/util' import { getTokenFiatAmount } from '../helpers/utils/token-util' -import { getTokenExchangeRates, getConversionRate, getCurrentCurrency } from '../selectors' +import { + getTokenExchangeRates, + getConversionRate, + getCurrentCurrency, +} from '../selectors' import { getSwapsTokens } from '../ducks/swaps/swaps' import { useSwapsEthToken } from './useSwapsEthToken' import { useEqualityCheck } from './useEqualityCheck' -const tokenList = shuffle(Object.entries(contractMap) - .map(([address, tokenData]) => ({ ...tokenData, address: address.toLowerCase() })) - .filter((tokenData) => Boolean(tokenData.erc20))) +const tokenList = shuffle( + Object.entries(contractMap) + .map(([address, tokenData]) => ({ + ...tokenData, + address: address.toLowerCase(), + })) + .filter((tokenData) => Boolean(tokenData.erc20)), +) -export function getRenderableTokenData (token, contractExchangeRates, conversionRate, currentCurrency) { +export function getRenderableTokenData( + token, + contractExchangeRates, + conversionRate, + currentCurrency, +) { const { symbol, name, address, iconUrl, string, balance, decimals } = token - const formattedFiat = getTokenFiatAmount( - symbol === 'ETH' ? 1 : contractExchangeRates[address], - conversionRate, - currentCurrency, - string, - symbol, - true, - ) || '' - const rawFiat = getTokenFiatAmount( - symbol === 'ETH' ? 1 : contractExchangeRates[address], - conversionRate, - currentCurrency, - string, - symbol, - false, - ) || '' - const usedIconUrl = iconUrl || (contractMap[checksumAddress(address)] && `images/contract/${contractMap[checksumAddress(address)].logo}`) + const formattedFiat = + getTokenFiatAmount( + symbol === 'ETH' ? 1 : contractExchangeRates[address], + conversionRate, + currentCurrency, + string, + symbol, + true, + ) || '' + const rawFiat = + getTokenFiatAmount( + symbol === 'ETH' ? 1 : contractExchangeRates[address], + conversionRate, + currentCurrency, + string, + symbol, + false, + ) || '' + const usedIconUrl = + iconUrl || + (contractMap[checksumAddress(address)] && + `images/contract/${contractMap[checksumAddress(address)].logo}`) return { ...token, primaryLabel: symbol, secondaryLabel: name || contractMap[checksumAddress(address)]?.name, - rightPrimaryLabel: string && `${(new BigNumber(string)).round(6).toString()} ${symbol}`, + rightPrimaryLabel: + string && `${new BigNumber(string).round(6).toString()} ${symbol}`, rightSecondaryLabel: formattedFiat, iconUrl: usedIconUrl, identiconAddress: usedIconUrl ? null : address, @@ -49,7 +69,7 @@ export function getRenderableTokenData (token, contractExchangeRates, conversion } } -export function useTokensToSearch ({ +export function useTokensToSearch({ providedTokens, usersTokens = [], topTokens = {}, @@ -87,8 +107,10 @@ export function useTokensToSearch ({ } const memoizedTokensToSearch = useEqualityCheck(tokensToSearch) return useMemo(() => { - - const usersTokensAddressMap = memoizedUsersToken.reduce((acc, token) => ({ ...acc, [token.address]: token }), {}) + const usersTokensAddressMap = memoizedUsersToken.reduce( + (acc, token) => ({ ...acc, [token.address]: token }), + {}, + ) const tokensToSearchBuckets = { owned: singleToken ? [] : [memoizedEthToken], @@ -97,24 +119,48 @@ export function useTokensToSearch ({ } memoizedTokensToSearch.forEach((token) => { - const renderableDataToken = getRenderableTokenData({ ...usersTokensAddressMap[token.address], ...token }, tokenConversionRates, conversionRate, currentCurrency) - if (usersTokensAddressMap[token.address] && ((renderableDataToken.symbol === 'ETH') || Number(renderableDataToken.balance ?? 0) !== 0)) { + const renderableDataToken = getRenderableTokenData( + { ...usersTokensAddressMap[token.address], ...token }, + tokenConversionRates, + conversionRate, + currentCurrency, + ) + if ( + usersTokensAddressMap[token.address] && + (renderableDataToken.symbol === 'ETH' || + Number(renderableDataToken.balance ?? 0) !== 0) + ) { tokensToSearchBuckets.owned.push(renderableDataToken) } else if (memoizedTopTokens[token.address]) { - tokensToSearchBuckets.top[memoizedTopTokens[token.address].index] = renderableDataToken + tokensToSearchBuckets.top[ + memoizedTopTokens[token.address].index + ] = renderableDataToken } else { tokensToSearchBuckets.others.push(renderableDataToken) } }) - tokensToSearchBuckets.owned = tokensToSearchBuckets.owned.sort(({ rawFiat }, { rawFiat: secondRawFiat }) => { - return ((new BigNumber(rawFiat || 0)).gt(secondRawFiat || 0) ? -1 : 1) - }) - tokensToSearchBuckets.top = tokensToSearchBuckets.top.filter((token) => token) + tokensToSearchBuckets.owned = tokensToSearchBuckets.owned.sort( + ({ rawFiat }, { rawFiat: secondRawFiat }) => { + return new BigNumber(rawFiat || 0).gt(secondRawFiat || 0) ? -1 : 1 + }, + ) + tokensToSearchBuckets.top = tokensToSearchBuckets.top.filter( + (token) => token, + ) return [ ...tokensToSearchBuckets.owned, ...tokensToSearchBuckets.top, ...tokensToSearchBuckets.others, ] - }, [memoizedTokensToSearch, memoizedUsersToken, tokenConversionRates, conversionRate, currentCurrency, memoizedTopTokens, memoizedEthToken, singleToken]) + }, [ + memoizedTokensToSearch, + memoizedUsersToken, + tokenConversionRates, + conversionRate, + currentCurrency, + memoizedTopTokens, + memoizedEthToken, + singleToken, + ]) } diff --git a/ui/app/hooks/useTransactionDisplayData.js b/ui/app/hooks/useTransactionDisplayData.js index c41fcaf99..13f68b40e 100644 --- a/ui/app/hooks/useTransactionDisplayData.js +++ b/ui/app/hooks/useTransactionDisplayData.js @@ -4,7 +4,11 @@ import { getStatusKey } from '../helpers/utils/transactions.util' import { camelCaseToCapitalize } from '../helpers/utils/common.util' import { PRIMARY, SECONDARY } from '../helpers/constants/common' import { getTokenAddressParam } from '../helpers/utils/token-util' -import { formatDateWithYearContext, shortenAddress, stripHttpSchemes } from '../helpers/utils/util' +import { + formatDateWithYearContext, + shortenAddress, + stripHttpSchemes, +} from '../helpers/utils/util' import { CONTRACT_INTERACTION_KEY, DEPLOY_CONTRACT_ACTION_KEY, @@ -58,7 +62,7 @@ import { useCurrentAsset } from './useCurrentAsset' * @param {Object} transactionGroup group of transactions * @return {TransactionDisplayData} */ -export function useTransactionDisplayData (transactionGroup) { +export function useTransactionDisplayData(transactionGroup) { // To determine which primary currency to display for swaps transactions we need to be aware // of which asset, if any, we are viewing at present const currentAsset = useCurrentAsset() @@ -71,7 +75,10 @@ export function useTransactionDisplayData (transactionGroup) { const { from: senderAddress, to } = initialTransaction.txParams || {} // for smart contract interactions, methodData can be used to derive the name of the action being taken - const methodData = useSelector((state) => getKnownMethodData(state, initialTransaction?.txParams?.data)) || {} + const methodData = + useSelector((state) => + getKnownMethodData(state, initialTransaction?.txParams?.data), + ) || {} const displayedStatusKey = getStatusKey(primaryTransaction) const isPending = displayedStatusKey in PENDING_STATUS_HASH @@ -94,12 +101,27 @@ export function useTransactionDisplayData (transactionGroup) { // transfers, we pass an additional argument to these hooks that will be // false for non-token transactions. This additional argument forces the // hook to return null - const token = isTokenCategory && knownTokens.find(({ address }) => address === recipientAddress) - const tokenData = useTokenData(initialTransaction?.txParams?.data, isTokenCategory) - const tokenDisplayValue = useTokenDisplayValue(initialTransaction?.txParams?.data, token, isTokenCategory) - const tokenFiatAmount = useTokenFiatAmount(token?.address, tokenDisplayValue, token?.symbol) + const token = + isTokenCategory && + knownTokens.find(({ address }) => address === recipientAddress) + const tokenData = useTokenData( + initialTransaction?.txParams?.data, + isTokenCategory, + ) + const tokenDisplayValue = useTokenDisplayValue( + initialTransaction?.txParams?.data, + token, + isTokenCategory, + ) + const tokenFiatAmount = useTokenFiatAmount( + token?.address, + tokenDisplayValue, + token?.symbol, + ) - const origin = stripHttpSchemes(initialTransaction.origin || initialTransaction.msgParams?.origin || '') + const origin = stripHttpSchemes( + initialTransaction.origin || initialTransaction.msgParams?.origin || '', + ) // used to append to the primary display value. initialized to either token.symbol or undefined // but can later be modified if dealing with a swap @@ -115,7 +137,12 @@ export function useTransactionDisplayData (transactionGroup) { // The primary title of the Tx that will be displayed in the activity list let title - const { swapTokenValue, isNegative, swapTokenFiatAmount, isViewingReceivedTokenFromSwap } = useSwappedTokenValue(transactionGroup, currentAsset) + const { + swapTokenValue, + isNegative, + swapTokenFiatAmount, + isViewingReceivedTokenFromSwap, + } = useSwappedTokenValue(transactionGroup, currentAsset) // There are seven types of transaction entries that are currently differentiated in the design // 1. Signature request @@ -131,7 +158,6 @@ export function useTransactionDisplayData (transactionGroup) { title = t('signatureRequest') subtitle = origin subtitleContainsOrigin = true - } else if (transactionCategory === SWAP) { category = TRANSACTION_CATEGORY_SWAP title = t('swapTokenToToken', [ @@ -164,24 +190,29 @@ export function useTransactionDisplayData (transactionGroup) { title = t('approveSpendLimit', [token?.symbol || t('token')]) subtitle = origin subtitleContainsOrigin = true - } else if (transactionCategory === DEPLOY_CONTRACT_ACTION_KEY || transactionCategory === CONTRACT_INTERACTION_KEY) { + } else if ( + transactionCategory === DEPLOY_CONTRACT_ACTION_KEY || + transactionCategory === CONTRACT_INTERACTION_KEY + ) { category = TRANSACTION_CATEGORY_INTERACTION - title = (methodData?.name && camelCaseToCapitalize(methodData.name)) || t(transactionCategory) + title = + (methodData?.name && camelCaseToCapitalize(methodData.name)) || + t(transactionCategory) subtitle = origin subtitleContainsOrigin = true - } else if (transactionCategory === INCOMING_TRANSACTION) { category = TRANSACTION_CATEGORY_RECEIVE title = t('receive') prefix = '' subtitle = t('fromAddress', [shortenAddress(senderAddress)]) - - } else if (transactionCategory === TOKEN_METHOD_TRANSFER_FROM || transactionCategory === TOKEN_METHOD_TRANSFER) { + } else if ( + transactionCategory === TOKEN_METHOD_TRANSFER_FROM || + transactionCategory === TOKEN_METHOD_TRANSFER + ) { category = TRANSACTION_CATEGORY_SEND title = t('sendSpecifiedTokens', [token?.symbol || t('token')]) recipientAddress = getTokenAddressParam(tokenData) subtitle = t('toAddress', [shortenAddress(recipientAddress)]) - } else if (transactionCategory === SEND_ETHER_ACTION_KEY) { category = TRANSACTION_CATEGORY_SEND title = t('sendETH') @@ -211,13 +242,15 @@ export function useTransactionDisplayData (transactionGroup) { date, subtitle, subtitleContainsOrigin, - primaryCurrency: transactionCategory === SWAP && isPending ? '' : primaryCurrency, + primaryCurrency: + transactionCategory === SWAP && isPending ? '' : primaryCurrency, senderAddress, recipientAddress, - secondaryCurrency: ( + secondaryCurrency: (isTokenCategory && !tokenFiatAmount) || (transactionCategory === SWAP && !swapTokenFiatAmount) - ) ? undefined : secondaryCurrency, + ? undefined + : secondaryCurrency, displayedStatusKey, isPending, isSubmitted, diff --git a/ui/app/hooks/useTransactionTimeRemaining.js b/ui/app/hooks/useTransactionTimeRemaining.js index 50f413d05..96deadf07 100644 --- a/ui/app/hooks/useTransactionTimeRemaining.js +++ b/ui/app/hooks/useTransactionTimeRemaining.js @@ -3,7 +3,12 @@ import { useRef, useEffect, useState, useMemo } from 'react' import { isEqual } from 'lodash' import { captureException } from '@sentry/browser' import { hexWEIToDecGWEI } from '../helpers/utils/conversions.util' -import { getEstimatedGasPrices, getEstimatedGasTimes, getFeatureFlags, getIsMainnet } from '../selectors' +import { + getEstimatedGasPrices, + getEstimatedGasTimes, + getFeatureFlags, + getIsMainnet, +} from '../selectors' import { getRawTimeEstimateData } from '../helpers/utils/gas-time-estimates.util' import { getCurrentLocale } from '../ducks/metamask/metamask' @@ -13,12 +18,15 @@ import { getCurrentLocale } from '../ducks/metamask/metamask' * @param {number} submittedTime - timestamp of when the tx was submitted * @return {number} minutes remaining */ -function calcTransactionTimeRemaining (initialTimeEstimate, submittedTime) { - const currentTime = (new Date()).getTime() +function calcTransactionTimeRemaining(initialTimeEstimate, submittedTime) { + const currentTime = new Date().getTime() const timeElapsedSinceSubmission = (currentTime - submittedTime) / 1000 - const timeRemainingOnEstimate = initialTimeEstimate - timeElapsedSinceSubmission + const timeRemainingOnEstimate = + initialTimeEstimate - timeElapsedSinceSubmission - const renderingTimeRemainingEstimate = Math.round(timeRemainingOnEstimate / 60) + const renderingTimeRemainingEstimate = Math.round( + timeRemainingOnEstimate / 60, + ) return renderingTimeRemainingEstimate } @@ -33,7 +41,7 @@ function calcTransactionTimeRemaining (initialTimeEstimate, submittedTime) { * @param {boolean} dontFormat - Whether the result should be be formatted, or just a number of minutes * @returns {string | undefined} i18n formatted string if applicable */ -export function useTransactionTimeRemaining ( +export function useTransactionTimeRemaining( isSubmitted, isEarliestNonce, submittedTime, @@ -53,15 +61,20 @@ export function useTransactionTimeRemaining ( const featureFlags = useSelector(getFeatureFlags) const transactionTimeFeatureActive = featureFlags?.transactionTime - const rtf = new Intl.RelativeTimeFormat(locale.replace('_', '-'), { numeric: 'auto', style: 'narrow' }) + const rtf = new Intl.RelativeTimeFormat(locale.replace('_', '-'), { + numeric: 'auto', + style: 'narrow', + }) // Memoize this value so it can be used as a dependency in the effect below const initialTimeEstimate = useMemo(() => { const customGasPrice = Number(hexWEIToDecGWEI(currentGasPrice)) try { - const { - newTimeEstimate, - } = getRawTimeEstimateData(customGasPrice, gasPrices, estimatedTimes) + const { newTimeEstimate } = getRawTimeEstimateData( + customGasPrice, + gasPrices, + estimatedTimes, + ) return newTimeEstimate } catch (error) { captureException(error) @@ -71,8 +84,8 @@ export function useTransactionTimeRemaining ( useEffect(() => { if ( - (isMainNet && - (transactionTimeFeatureActive || forceAllow)) && + isMainNet && + (transactionTimeFeatureActive || forceAllow) && isSubmitted && isEarliestNonce && !isNaN(initialTimeEstimate) diff --git a/ui/app/hooks/useUserPreferencedCurrency.js b/ui/app/hooks/useUserPreferencedCurrency.js index 986ef6dd7..1764fa24e 100644 --- a/ui/app/hooks/useUserPreferencedCurrency.js +++ b/ui/app/hooks/useUserPreferencedCurrency.js @@ -1,5 +1,9 @@ import { useSelector } from 'react-redux' -import { getPreferences, getShouldShowFiat, getNativeCurrency } from '../selectors' +import { + getPreferences, + getShouldShowFiat, + getNativeCurrency, +} from '../selectors' import { PRIMARY, SECONDARY, ETH } from '../helpers/constants/common' /** @@ -29,21 +33,24 @@ import { PRIMARY, SECONDARY, ETH } from '../helpers/constants/common' * @param {UseUserPreferencedCurrencyOptions} opts - options to override default values * @return {UserPreferredCurrency} */ -export function useUserPreferencedCurrency (type, opts = {}) { +export function useUserPreferencedCurrency(type, opts = {}) { const nativeCurrency = useSelector(getNativeCurrency) - const { - useNativeCurrencyAsPrimaryCurrency, - } = useSelector(getPreferences) + const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences) const showFiat = useSelector(getShouldShowFiat) let currency, numberOfDecimals - if (!showFiat || (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency) || - (type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency)) { + if ( + !showFiat || + (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency) || + (type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency) + ) { // Display ETH currency = nativeCurrency || ETH numberOfDecimals = opts.numberOfDecimals || opts.ethNumberOfDecimals || 6 - } else if ((type === SECONDARY && useNativeCurrencyAsPrimaryCurrency) || - (type === PRIMARY && !useNativeCurrencyAsPrimaryCurrency)) { + } else if ( + (type === SECONDARY && useNativeCurrencyAsPrimaryCurrency) || + (type === PRIMARY && !useNativeCurrencyAsPrimaryCurrency) + ) { // Display Fiat numberOfDecimals = opts.numberOfDecimals || opts.fiatNumberOfDecimals || 2 } diff --git a/ui/app/pages/add-token/add-token.component.js b/ui/app/pages/add-token/add-token.component.js index 00f17d271..dfbc388ab 100644 --- a/ui/app/pages/add-token/add-token.component.js +++ b/ui/app/pages/add-token/add-token.component.js @@ -41,7 +41,7 @@ class AddToken extends Component { forceEditSymbol: false, } - componentDidMount () { + componentDidMount() { this.tokenInfoGetter = tokenInfoGetter() const { pendingTokens = {} } = this.props const pendingTokenKeys = Object.keys(pendingTokens) @@ -67,11 +67,16 @@ class AddToken extends Component { decimals: customDecimals = 0, } = customToken - this.setState({ selectedTokens, customAddress, customSymbol, customDecimals }) + this.setState({ + selectedTokens, + customAddress, + customSymbol, + customDecimals, + }) } } - handleToggleToken (token) { + handleToggleToken(token) { const { address } = token const { selectedTokens = {} } = this.state const selectedTokensCopy = { ...selectedTokens } @@ -88,7 +93,7 @@ class AddToken extends Component { }) } - hasError () { + hasError() { const { tokenSelectorError, customAddressError, @@ -96,15 +101,20 @@ class AddToken extends Component { customDecimalsError, } = this.state - return tokenSelectorError || customAddressError || customSymbolError || customDecimalsError + return ( + tokenSelectorError || + customAddressError || + customSymbolError || + customDecimalsError + ) } - hasSelected () { + hasSelected() { const { customAddress = '', selectedTokens = {} } = this.state return customAddress || Object.keys(selectedTokens).length > 0 } - handleNext () { + handleNext() { if (this.hasError()) { return } @@ -132,7 +142,7 @@ class AddToken extends Component { history.push(CONFIRM_ADD_TOKEN_ROUTE) } - async attemptToAutoFillTokenParams (address) { + async attemptToAutoFillTokenParams(address) { const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(address) const autoFilled = Boolean(symbol && decimals) @@ -141,7 +151,7 @@ class AddToken extends Component { this.handleCustomDecimalsChange(decimals) } - handleCustomAddressChange (value) { + handleCustomAddressChange(value) { const customAddress = value.trim() this.setState({ customAddress, @@ -183,7 +193,7 @@ class AddToken extends Component { } } - handleCustomSymbolChange (value) { + handleCustomSymbolChange(value) { const customSymbol = value.trim() const symbolLength = customSymbol.length let customSymbolError = null @@ -195,9 +205,10 @@ class AddToken extends Component { this.setState({ customSymbol, customSymbolError }) } - handleCustomDecimalsChange (value) { + handleCustomDecimalsChange(value) { const customDecimals = value.trim() - const validDecimals = customDecimals !== null && + const validDecimals = + customDecimals !== null && customDecimals !== '' && customDecimals >= 0 && customDecimals <= 36 @@ -210,7 +221,7 @@ class AddToken extends Component { this.setState({ customDecimals, customDecimalsError }) } - renderCustomTokenForm () { + renderCustomTokenForm() { const { customAddress, customSymbol, @@ -237,12 +248,12 @@ class AddToken extends Component { /> {this.context.t('tokenSymbol')} - {(autoFilled && !forceEditSymbol) && ( + {autoFilled && !forceEditSymbol && (
    this.setState({ forceEditSymbol: true })} @@ -251,7 +262,7 @@ class AddToken extends Component {
    )}
    - )} + } type="text" value={customSymbol} onChange={(e) => this.handleCustomSymbolChange(e.target.value)} @@ -275,13 +286,15 @@ class AddToken extends Component { ) } - renderSearchToken () { + renderSearchToken() { const { tokenSelectorError, selectedTokens, searchResults } = this.state return (
    this.setState({ searchResults: results })} + onSearch={({ results = [] }) => + this.setState({ searchResults: results }) + } error={tokenSelectorError} />
    @@ -295,20 +308,18 @@ class AddToken extends Component { ) } - renderTabs () { + renderTabs() { return ( - - { this.renderSearchToken() } - + {this.renderSearchToken()} - { this.renderCustomTokenForm() } + {this.renderCustomTokenForm()} ) } - render () { + render() { const { history, clearPendingTokens, mostRecentOverviewPage } = this.props return ( diff --git a/ui/app/pages/add-token/add-token.container.js b/ui/app/pages/add-token/add-token.container.js index 9f3f6d21e..80059a689 100644 --- a/ui/app/pages/add-token/add-token.container.js +++ b/ui/app/pages/add-token/add-token.container.js @@ -5,7 +5,9 @@ import { getMostRecentOverviewPage } from '../../ducks/history/history' import AddToken from './add-token.component' const mapStateToProps = (state) => { - const { metamask: { identities, tokens, pendingTokens } } = state + const { + metamask: { identities, tokens, pendingTokens }, + } = state return { identities, mostRecentOverviewPage: getMostRecentOverviewPage(state), diff --git a/ui/app/pages/add-token/tests/add-token.test.js b/ui/app/pages/add-token/tests/add-token.test.js index 8138845e7..300a6b019 100644 --- a/ui/app/pages/add-token/tests/add-token.test.js +++ b/ui/app/pages/add-token/tests/add-token.test.js @@ -33,7 +33,8 @@ describe('Add Token', function () { wrapper = mountWithRouter( - , store, + , + store, ) wrapper.find({ name: 'customToken' }).simulate('click') @@ -44,7 +45,9 @@ describe('Add Token', function () { }) it('next button is disabled when no fields are populated', function () { - const nextButton = wrapper.find('.button.btn-secondary.page-container__footer-button') + const nextButton = wrapper.find( + '.button.btn-secondary.page-container__footer-button', + ) assert.equal(nextButton.props().disabled, true) }) @@ -55,7 +58,10 @@ describe('Add Token', function () { const customAddress = wrapper.find('input#custom-address') customAddress.simulate('change', event) - assert.equal(wrapper.find('AddToken').instance().state.customAddress, tokenAddress) + assert.equal( + wrapper.find('AddToken').instance().state.customAddress, + tokenAddress, + ) }) it('edits token symbol', function () { @@ -64,7 +70,10 @@ describe('Add Token', function () { const customAddress = wrapper.find('#custom-symbol') customAddress.last().simulate('change', event) - assert.equal(wrapper.find('AddToken').instance().state.customSymbol, tokenSymbol) + assert.equal( + wrapper.find('AddToken').instance().state.customSymbol, + tokenSymbol, + ) }) it('edits token decimal precision', function () { @@ -73,11 +82,16 @@ describe('Add Token', function () { const customAddress = wrapper.find('#custom-decimals') customAddress.last().simulate('change', event) - assert.equal(wrapper.find('AddToken').instance().state.customDecimals, tokenPrecision) + assert.equal( + wrapper.find('AddToken').instance().state.customDecimals, + tokenPrecision, + ) }) it('next', function () { - const nextButton = wrapper.find('.button.btn-secondary.page-container__footer-button') + const nextButton = wrapper.find( + '.button.btn-secondary.page-container__footer-button', + ) nextButton.simulate('click') assert(props.setPendingTokens.calledOnce) @@ -86,7 +100,9 @@ describe('Add Token', function () { }) it('cancels', function () { - const cancelButton = wrapper.find('button.btn-default.page-container__footer-button') + const cancelButton = wrapper.find( + 'button.btn-default.page-container__footer-button', + ) cancelButton.simulate('click') assert(props.clearPendingTokens.calledOnce) diff --git a/ui/app/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js b/ui/app/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js index ae14581e8..bc47745cc 100644 --- a/ui/app/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js +++ b/ui/app/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js @@ -7,12 +7,12 @@ export default class TokenListPlaceholder extends Component { t: PropTypes.func, } - render () { + render() { return (
    - { this.context.t('addAcquiredTokens') } + {this.context.t('addAcquiredTokens')}
    ) diff --git a/ui/app/pages/add-token/token-list/token-list.component.js b/ui/app/pages/add-token/token-list/token-list.component.js index 633ffea9c..e8c71ad07 100644 --- a/ui/app/pages/add-token/token-list/token-list.component.js +++ b/ui/app/pages/add-token/token-list/token-list.component.js @@ -16,46 +16,55 @@ export default class InfoBox extends Component { onToggleToken: PropTypes.func, } - render () { - const { results = [], selectedTokens = {}, onToggleToken, tokens = [] } = this.props + render() { + const { + results = [], + selectedTokens = {}, + onToggleToken, + tokens = [], + } = this.props - return results.length === 0 - ? - : ( -
    -
    - { this.context.t('searchResults') } -
    -
    - { - Array(6).fill(undefined) - .map((_, i) => { - const { logo, symbol, name, address } = results[i] || {} - const tokenAlreadyAdded = checkExistingAddresses(address, tokens) - - return Boolean(logo || symbol || name) && ( -
    !tokenAlreadyAdded && onToggleToken(results[i])} - key={i} - > -
    -
    -
    - { `${name} (${symbol})` } -
    -
    - ) - }) - } -
    + return results.length === 0 ? ( + + ) : ( +
    +
    + {this.context.t('searchResults')}
    - ) +
    + {Array(6) + .fill(undefined) + .map((_, i) => { + const { logo, symbol, name, address } = results[i] || {} + const tokenAlreadyAdded = checkExistingAddresses(address, tokens) + + return ( + Boolean(logo || symbol || name) && ( +
    + !tokenAlreadyAdded && onToggleToken(results[i]) + } + key={i} + > +
    +
    + {`${name} (${symbol})`} +
    +
    + ) + ) + })} +
    +
    + ) } } diff --git a/ui/app/pages/add-token/token-search/token-search.component.js b/ui/app/pages/add-token/token-search/token-search.component.js index 2cca26e84..904fdcefb 100644 --- a/ui/app/pages/add-token/token-search/token-search.component.js +++ b/ui/app/pages/add-token/token-search/token-search.component.js @@ -40,7 +40,7 @@ export default class TokenSearch extends Component { searchQuery: '', } - handleSearch (searchQuery) { + handleSearch(searchQuery) { this.setState({ searchQuery }) const fuseSearchResult = fuse.search(searchQuery) const addressSearchResult = contractList.filter((token) => { @@ -50,18 +50,15 @@ export default class TokenSearch extends Component { this.props.onSearch({ searchQuery, results }) } - renderAdornment () { + renderAdornment() { return ( - + ) } - render () { + render() { const { error } = this.props const { searchQuery } = this.state diff --git a/ui/app/pages/asset/asset.js b/ui/app/pages/asset/asset.js index fa9479eb0..22baaf68a 100644 --- a/ui/app/pages/asset/asset.js +++ b/ui/app/pages/asset/asset.js @@ -22,11 +22,7 @@ const Asset = () => { } else { content = } - return ( -
    - { content } -
    - ) + return
    {content}
    } export default Asset diff --git a/ui/app/pages/asset/components/asset-breadcrumb.js b/ui/app/pages/asset/components/asset-breadcrumb.js index 136fec6b0..a081e5b36 100644 --- a/ui/app/pages/asset/components/asset-breadcrumb.js +++ b/ui/app/pages/asset/components/asset-breadcrumb.js @@ -3,15 +3,14 @@ import PropTypes from 'prop-types' const AssetBreadcrumb = ({ accountName, assetName, onBack }) => { return ( - ) } diff --git a/ui/app/pages/asset/components/asset-navigation.js b/ui/app/pages/asset/components/asset-navigation.js index 5423b1094..2af0fac82 100644 --- a/ui/app/pages/asset/components/asset-navigation.js +++ b/ui/app/pages/asset/components/asset-navigation.js @@ -6,8 +6,12 @@ import AssetBreadcrumb from './asset-breadcrumb' const AssetNavigation = ({ accountName, assetName, onBack, optionsButton }) => { return (
    - - { optionsButton } + + {optionsButton}
    ) } diff --git a/ui/app/pages/asset/components/native-asset.js b/ui/app/pages/asset/components/native-asset.js index 3bda491b8..cb7f85750 100644 --- a/ui/app/pages/asset/components/native-asset.js +++ b/ui/app/pages/asset/components/native-asset.js @@ -10,8 +10,10 @@ import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' import AssetNavigation from './asset-navigation' -export default function NativeAsset ({ nativeCurrency }) { - const selectedAccountName = useSelector((state) => getSelectedIdentity(state).name) +export default function NativeAsset({ nativeCurrency }) { + const selectedAccountName = useSelector( + (state) => getSelectedIdentity(state).name, + ) const history = useHistory() return ( diff --git a/ui/app/pages/asset/components/token-asset.js b/ui/app/pages/asset/components/token-asset.js index 84c7eee37..81198ee5d 100644 --- a/ui/app/pages/asset/components/token-asset.js +++ b/ui/app/pages/asset/components/token-asset.js @@ -6,17 +6,22 @@ import { createAccountLink } from '@metamask/etherscan-link' import TransactionList from '../../../components/app/transaction-list' import { TokenOverview } from '../../../components/app/wallet-overview' -import { getCurrentNetworkId, getSelectedIdentity } from '../../../selectors/selectors' +import { + getCurrentNetworkId, + getSelectedIdentity, +} from '../../../selectors/selectors' import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' import { showModal } from '../../../store/actions' import AssetNavigation from './asset-navigation' import TokenOptions from './token-options' -export default function TokenAsset ({ token }) { +export default function TokenAsset({ token }) { const dispatch = useDispatch() const network = useSelector(getCurrentNetworkId) - const selectedAccountName = useSelector((state) => getSelectedIdentity(state).name) + const selectedAccountName = useSelector( + (state) => getSelectedIdentity(state).name, + ) const history = useHistory() return ( @@ -25,16 +30,18 @@ export default function TokenAsset ({ token }) { accountName={selectedAccountName} assetName={token.symbol} onBack={() => history.push(DEFAULT_ROUTE)} - optionsButton={( + optionsButton={ dispatch(showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token }))} + onRemove={() => + dispatch(showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token })) + } onViewEtherscan={() => { const url = createAccountLink(token.address, network) global.platform.openTab({ url }) }} tokenSymbol={token.symbol} /> - )} + } /> diff --git a/ui/app/pages/asset/components/token-options.js b/ui/app/pages/asset/components/token-options.js index eaf142d34..613455f57 100644 --- a/ui/app/pages/asset/components/token-options.js +++ b/ui/app/pages/asset/components/token-options.js @@ -6,7 +6,9 @@ import { Menu, MenuItem } from '../../../components/ui/menu' const TokenOptions = ({ onRemove, onViewEtherscan, tokenSymbol }) => { const t = useContext(I18nContext) - const [tokenOptionsButtonElement, setTokenOptionsButtonElement] = useState(null) + const [tokenOptionsButtonElement, setTokenOptionsButtonElement] = useState( + null, + ) const [tokenOptionsOpen, setTokenOptionsOpen] = useState(false) return ( @@ -18,34 +20,33 @@ const TokenOptions = ({ onRemove, onViewEtherscan, tokenSymbol }) => { ref={setTokenOptionsButtonElement} title={t('tokenOptions')} /> - { - tokenOptionsOpen - ? ( - setTokenOptionsOpen(false)} > - { - setTokenOptionsOpen(false) - onViewEtherscan() - }} - > - { t('viewOnEtherscan') } - - { - setTokenOptionsOpen(false) - onRemove() - }} - > - { t('hideTokenSymbol', [tokenSymbol]) } - - - ) - : null - } + {tokenOptionsOpen ? ( + setTokenOptionsOpen(false)} + > + { + setTokenOptionsOpen(false) + onViewEtherscan() + }} + > + {t('viewOnEtherscan')} + + { + setTokenOptionsOpen(false) + onRemove() + }} + > + {t('hideTokenSymbol', [tokenSymbol])} + + + ) : null} ) } diff --git a/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js b/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js index 28b04ba40..8243a10bb 100644 --- a/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js +++ b/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js @@ -20,15 +20,15 @@ export default class ConfirmAddSuggestedToken extends Component { tokens: PropTypes.array, } - componentDidMount () { + componentDidMount() { this._checkPendingTokens() } - componentDidUpdate () { + componentDidUpdate() { this._checkPendingTokens() } - _checkPendingTokens () { + _checkPendingTokens() { const { mostRecentOverviewPage, pendingTokens = {}, history } = this.props if (Object.keys(pendingTokens).length > 0) { @@ -42,14 +42,19 @@ export default class ConfirmAddSuggestedToken extends Component { } } - getTokenName (name, symbol) { - return typeof name === 'undefined' - ? symbol - : `${name} (${symbol})` + getTokenName(name, symbol) { + return typeof name === 'undefined' ? symbol : `${name} (${symbol})` } - render () { - const { addToken, pendingTokens, tokens, removeSuggestedTokens, history, mostRecentOverviewPage } = this.props + render() { + const { + addToken, + pendingTokens, + tokens, + removeSuggestedTokens, + history, + mostRecentOverviewPage, + } = this.props const pendingTokenKey = Object.keys(pendingTokens)[0] const pendingToken = pendingTokens[pendingTokenKey] const hasTokenDuplicates = this.checkTokenDuplicates(pendingTokens, tokens) @@ -59,65 +64,56 @@ export default class ConfirmAddSuggestedToken extends Component {
    - { this.context.t('addSuggestedTokens') } + {this.context.t('addSuggestedTokens')}
    - { this.context.t('likeToAddTokens') } + {this.context.t('likeToAddTokens')}
    - { hasTokenDuplicates ? - ( -
    - { this.context.t('knownTokenWarning') } -
    - ) : null - } - { reusesName ? - ( -
    - { this.context.t('reusedTokenNameWarning') } -
    - ) : null - } + {hasTokenDuplicates ? ( +
    {this.context.t('knownTokenWarning')}
    + ) : null} + {reusesName ? ( +
    + {this.context.t('reusedTokenNameWarning')} +
    + ) : null}
    - { this.context.t('token') } + {this.context.t('token')}
    - { this.context.t('balance') } + {this.context.t('balance')}
    - { - Object.entries(pendingTokens) - .map(([address, token]) => { - const { name, symbol, image } = token + {Object.entries(pendingTokens).map(([address, token]) => { + const { name, symbol, image } = token - return ( -
    -
    - -
    - { this.getTokenName(name, symbol) } -
    -
    -
    - -
    + return ( +
    +
    + +
    + {this.getTokenName(name, symbol)}
    - ) - }) - } +
    +
    + +
    +
    + ) + })}
    @@ -128,11 +124,12 @@ export default class ConfirmAddSuggestedToken extends Component { large className="page-container__footer-button" onClick={() => { - removeSuggestedTokens() - .then(() => history.push(mostRecentOverviewPage)) + removeSuggestedTokens().then(() => + history.push(mostRecentOverviewPage), + ) }} > - { this.context.t('cancel') } + {this.context.t('cancel')}
    @@ -153,7 +150,7 @@ export default class ConfirmAddSuggestedToken extends Component { ) } - checkTokenDuplicates (pendingTokens, tokens) { + checkTokenDuplicates(pendingTokens, tokens) { const pending = Object.keys(pendingTokens) const existing = tokens.map((token) => token.address) const dupes = pending.filter((proposed) => { @@ -169,15 +166,15 @@ export default class ConfirmAddSuggestedToken extends Component { * - Does not share an address with that same `tokens` member. * This should be flagged as possibly deceptive or confusing. */ - checkNameReuse (pendingTokens, tokens) { + checkNameReuse(pendingTokens, tokens) { const duplicates = Object.keys(pendingTokens) .map((addr) => pendingTokens[addr]) .filter((token) => { - const dupes = tokens.filter((old) => old.symbol === token.symbol) + const dupes = tokens + .filter((old) => old.symbol === token.symbol) .filter((old) => old.address !== token.address) return dupes.length > 0 }) return duplicates.length > 0 } - } diff --git a/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js b/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js index 319d1ed82..51a29a555 100644 --- a/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js +++ b/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js @@ -6,7 +6,9 @@ import { getMostRecentOverviewPage } from '../../ducks/history/history' import ConfirmAddSuggestedToken from './confirm-add-suggested-token.component' const mapStateToProps = (state) => { - const { metamask: { pendingTokens, suggestedTokens, tokens } } = state + const { + metamask: { pendingTokens, suggestedTokens, tokens }, + } = state const params = { ...pendingTokens, ...suggestedTokens } return { @@ -18,7 +20,8 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - addToken: ({ address, symbol, decimals, image }) => dispatch(addToken(address, symbol, Number(decimals), image)), + addToken: ({ address, symbol, decimals, image }) => + dispatch(addToken(address, symbol, Number(decimals), image)), removeSuggestedTokens: () => dispatch(removeSuggestedTokens()), } } diff --git a/ui/app/pages/confirm-add-token/confirm-add-token.component.js b/ui/app/pages/confirm-add-token/confirm-add-token.component.js index f79d962eb..3a0b0b3d0 100644 --- a/ui/app/pages/confirm-add-token/confirm-add-token.component.js +++ b/ui/app/pages/confirm-add-token/confirm-add-token.component.js @@ -18,7 +18,7 @@ export default class ConfirmAddToken extends Component { pendingTokens: PropTypes.object, } - componentDidMount () { + componentDidMount() { const { mostRecentOverviewPage, pendingTokens = {}, history } = this.props if (Object.keys(pendingTokens).length === 0) { @@ -26,63 +26,64 @@ export default class ConfirmAddToken extends Component { } } - getTokenName (name, symbol) { - return typeof name === 'undefined' - ? symbol - : `${name} (${symbol})` + getTokenName(name, symbol) { + return typeof name === 'undefined' ? symbol : `${name} (${symbol})` } - render () { - const { history, addTokens, clearPendingTokens, mostRecentOverviewPage, pendingTokens } = this.props + render() { + const { + history, + addTokens, + clearPendingTokens, + mostRecentOverviewPage, + pendingTokens, + } = this.props return (
    - { this.context.t('addTokens') } + {this.context.t('addTokens')}
    - { this.context.t('likeToAddTokens') } + {this.context.t('likeToAddTokens')}
    - { this.context.t('token') } + {this.context.t('token')}
    - { this.context.t('balance') } + {this.context.t('balance')}
    - { - Object.entries(pendingTokens) - .map(([address, token]) => { - const { name, symbol } = token + {Object.entries(pendingTokens).map(([address, token]) => { + const { name, symbol } = token - return ( -
    -
    - -
    - { this.getTokenName(name, symbol) } -
    -
    -
    - -
    + return ( +
    +
    + +
    + {this.getTokenName(name, symbol)}
    - ) - }) - } +
    +
    + +
    +
    + ) + })}
    @@ -94,26 +95,27 @@ export default class ConfirmAddToken extends Component { className="page-container__footer-button" onClick={() => history.push(ADD_TOKEN_ROUTE)} > - { this.context.t('back') } + {this.context.t('back')}
    diff --git a/ui/app/pages/confirm-add-token/confirm-add-token.container.js b/ui/app/pages/confirm-add-token/confirm-add-token.container.js index 8c09ad837..08a01163c 100644 --- a/ui/app/pages/confirm-add-token/confirm-add-token.container.js +++ b/ui/app/pages/confirm-add-token/confirm-add-token.container.js @@ -5,7 +5,9 @@ import { getMostRecentOverviewPage } from '../../ducks/history/history' import ConfirmAddToken from './confirm-add-token.component' const mapStateToProps = (state) => { - const { metamask: { pendingTokens } } = state + const { + metamask: { pendingTokens }, + } = state return { mostRecentOverviewPage: getMostRecentOverviewPage(state), pendingTokens, diff --git a/ui/app/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/app/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index 8c7394e6f..6cea504e0 100644 --- a/ui/app/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/app/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -2,9 +2,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import Identicon from '../../../components/ui/identicon' -import { - addressSummary, -} from '../../../helpers/utils/util' +import { addressSummary } from '../../../helpers/utils/util' import { formatCurrency } from '../../../helpers/utils/confirm-tx.util' export default class ConfirmApproveContent extends Component { @@ -34,7 +32,7 @@ export default class ConfirmApproveContent extends Component { showFullTxDetails: false, } - renderApproveContentCard ({ + renderApproveContentCard({ symbol, title, showEdit, @@ -51,8 +49,12 @@ export default class ConfirmApproveContent extends Component { })} >
    -
    { symbol }
    -
    { title }
    +
    + {symbol} +
    +
    + {title} +
    {showEdit && (
    )}
    -
    - { content } -
    - { footer } +
    {content}
    + {footer}
    ) } // TODO: Add "Learn Why" with link to the feeAssociatedRequest text - renderTransactionDetailsContent () { + renderTransactionDetailsContent() { const { t } = this.context const { currentCurrency, @@ -81,51 +81,71 @@ export default class ConfirmApproveContent extends Component { return (
    - { t('feeAssociatedRequest') } + {t('feeAssociatedRequest')}
    - { formatCurrency(fiatTransactionTotal, currentCurrency) } + {formatCurrency(fiatTransactionTotal, currentCurrency)}
    - { `${ethTransactionTotal} ETH` } + {`${ethTransactionTotal} ETH`}
    ) } - renderPermissionContent () { + renderPermissionContent() { const { t } = this.context - const { customTokenAmount, tokenAmount, tokenSymbol, origin, toAddress } = this.props + const { + customTokenAmount, + tokenAmount, + tokenSymbol, + origin, + toAddress, + } = this.props return (
    -
    { t('accessAndSpendNotice', [origin]) }
    -
    -
    { t('amountWithColon') }
    -
    { `${Number(customTokenAmount || tokenAmount)} ${tokenSymbol}` }
    +
    + {t('accessAndSpendNotice', [origin])}
    -
    { t('toWithColon') }
    -
    { addressSummary(toAddress) }
    +
    + {t('amountWithColon')} +
    +
    + {`${Number(customTokenAmount || tokenAmount)} ${tokenSymbol}`} +
    +
    +
    +
    + {t('toWithColon')} +
    +
    + {addressSummary(toAddress)} +
    ) } - renderDataContent () { + renderDataContent() { const { t } = this.context const { data } = this.props return (
    -
    { t('functionApprove') }
    -
    { data }
    +
    + {t('functionApprove')} +
    +
    + {data} +
    ) } - render () { + render() { const { t } = this.context const { decimals, @@ -156,27 +176,27 @@ export default class ConfirmApproveContent extends Component { />
    - { t('allowOriginSpendToken', [origin, tokenSymbol]) } + {t('allowOriginSpendToken', [origin, tokenSymbol])}
    - { t('trustSiteApprovePermission', [origin, tokenSymbol]) } + {t('trustSiteApprovePermission', [origin, tokenSymbol])}
    -
    +
    showEditApprovalPermissionModal({ - customTokenAmount, - decimals, - origin, - setCustomAmount, - tokenAmount, - tokenSymbol, - tokenBalance, - })} + onClick={() => + showEditApprovalPermissionModal({ + customTokenAmount, + decimals, + origin, + setCustomAmount, + tokenAmount, + tokenSymbol, + tokenBalance, + }) + } > - { t('editPermission') } + {t('editPermission')}
    @@ -190,7 +210,11 @@ export default class ConfirmApproveContent extends Component { footer: (
    this.setState({ showFullTxDetails: !this.state.showFullTxDetails })} + onClick={() => + this.setState({ + showFullTxDetails: !this.state.showFullTxDetails, + }) + } >
    @@ -208,39 +232,36 @@ export default class ConfirmApproveContent extends Component { })}
    - { - showFullTxDetails - ? ( -
    -
    - {this.renderApproveContentCard({ - symbol: , - title: 'Permission', - content: this.renderPermissionContent(), - showEdit: true, - onEditClick: () => showEditApprovalPermissionModal({ - customTokenAmount, - decimals, - origin, - setCustomAmount, - tokenAmount, - tokenSymbol, - tokenBalance, - }), - })} -
    -
    - {this.renderApproveContentCard({ - symbol: , - title: 'Data', - content: this.renderDataContent(), - noBorder: true, - })} -
    -
    - ) - : null - } + {showFullTxDetails ? ( +
    +
    + {this.renderApproveContentCard({ + symbol: , + title: 'Permission', + content: this.renderPermissionContent(), + showEdit: true, + onEditClick: () => + showEditApprovalPermissionModal({ + customTokenAmount, + decimals, + origin, + setCustomAmount, + tokenAmount, + tokenSymbol, + tokenBalance, + }), + })} +
    +
    + {this.renderApproveContentCard({ + symbol: , + title: 'Data', + content: this.renderDataContent(), + noBorder: true, + })} +
    +
    + ) : null}
    ) } diff --git a/ui/app/pages/confirm-approve/confirm-approve.js b/ui/app/pages/confirm-approve/confirm-approve.js index 0c036a06b..e1109c473 100644 --- a/ui/app/pages/confirm-approve/confirm-approve.js +++ b/ui/app/pages/confirm-approve/confirm-approve.js @@ -3,9 +3,7 @@ import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import ConfirmTransactionBase from '../confirm-transaction-base' import { showModal } from '../../store/actions' -import { - getTokenData, -} from '../../helpers/utils/transactions.util' +import { getTokenData } from '../../helpers/utils/transactions.util' import { calcTokenAmount, getTokenAddressParam, @@ -17,20 +15,20 @@ import { transactionFeeSelector, txDataSelector, } from '../../selectors/confirm-transaction' -import { getCurrentCurrency, getDomainMetadata } from '../../selectors/selectors' +import { + getCurrentCurrency, + getDomainMetadata, +} from '../../selectors/selectors' import { currentNetworkTxListSelector } from '../../selectors/transactions' import { getCustomTxParamsData } from './confirm-approve.util' import ConfirmApproveContent from './confirm-approve-content' -export default function ConfirmApprove () { +export default function ConfirmApprove() { const dispatch = useDispatch() const { id: paramsTransactionId } = useParams() const { id: transactionId, - txParams: { - to: tokenAddress, - data, - } = {}, + txParams: { to: tokenAddress, data } = {}, } = useSelector(txDataSelector) const currentCurrency = useSelector(getCurrentCurrency) @@ -38,15 +36,18 @@ export default function ConfirmApprove () { const domainMetadata = useSelector(getDomainMetadata) const tokens = useSelector(getTokens) - const transaction = ( - currentNetworkTxList.find(({ id }) => id === (Number(paramsTransactionId) || transactionId)) || {} + const transaction = + currentNetworkTxList.find( + ({ id }) => id === (Number(paramsTransactionId) || transactionId), + ) || {} + const { ethTransactionTotal, fiatTransactionTotal } = useSelector((state) => + transactionFeeSelector(state, transaction), ) - const { - ethTransactionTotal, - fiatTransactionTotal, - } = useSelector((state) => transactionFeeSelector(state, transaction)) - const currentToken = (tokens && tokens.find(({ address }) => tokenAddress === address)) || { address: tokenAddress } + const currentToken = (tokens && + tokens.find(({ address }) => tokenAddress === address)) || { + address: tokenAddress, + } const { tokensWithBalances } = useTokenTracker([currentToken]) const tokenTrackerBalance = tokensWithBalances[0]?.balance || '' @@ -56,21 +57,19 @@ export default function ConfirmApprove () { const tokenData = getTokenData(data) const tokenValue = getTokenValueParam(tokenData) const toAddress = getTokenAddressParam(tokenData) - const tokenAmount = tokenData && calcTokenAmount(tokenValue, decimals).toString(10) + const tokenAmount = + tokenData && calcTokenAmount(tokenValue, decimals).toString(10) const [customPermissionAmount, setCustomPermissionAmount] = useState('') const previousTokenAmount = useRef(tokenAmount) - useEffect( - () => { - if (customPermissionAmount && previousTokenAmount.current !== tokenAmount) { - setCustomPermissionAmount(tokenAmount) - } - previousTokenAmount.current = tokenAmount - }, - [customPermissionAmount, tokenAmount], - ) + useEffect(() => { + if (customPermissionAmount && previousTokenAmount.current !== tokenAmount) { + setCustomPermissionAmount(tokenAmount) + } + previousTokenAmount.current = tokenAmount + }, [customPermissionAmount, tokenAmount]) const { origin } = transaction const formattedOrigin = origin @@ -94,7 +93,7 @@ export default function ConfirmApprove () { identiconAddress={tokenAddress} showAccountInHeader title={tokensText} - contentComponent={( + contentComponent={ dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData }))} - showEditApprovalPermissionModal={ - ({ - /* eslint-disable no-shadow */ - customTokenAmount, - decimals, - origin, - setCustomAmount, - tokenAmount, - tokenBalance, - tokenSymbol, - /* eslint-enable no-shadow */ - }) => dispatch( + showCustomizeGasModal={() => + dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData })) + } + showEditApprovalPermissionModal={({ + /* eslint-disable no-shadow */ + customTokenAmount, + decimals, + origin, + setCustomAmount, + tokenAmount, + tokenBalance, + tokenSymbol, + /* eslint-enable no-shadow */ + }) => + dispatch( showModal({ name: 'EDIT_APPROVAL_PERMISSION', customTokenAmount, @@ -135,7 +136,7 @@ export default function ConfirmApprove () { ethTransactionTotal={ethTransactionTotal} fiatTransactionTotal={fiatTransactionTotal} /> - )} + } hideSenderToRecipient customTxParamsData={customData} /> diff --git a/ui/app/pages/confirm-approve/confirm-approve.util.js b/ui/app/pages/confirm-approve/confirm-approve.util.js index afa53352a..921d8c92c 100644 --- a/ui/app/pages/confirm-approve/confirm-approve.util.js +++ b/ui/app/pages/confirm-approve/confirm-approve.util.js @@ -1,14 +1,22 @@ import { decimalToHex } from '../../helpers/utils/conversions.util' -import { calcTokenValue, getTokenAddressParam } from '../../helpers/utils/token-util' +import { + calcTokenValue, + getTokenAddressParam, +} from '../../helpers/utils/token-util' import { getTokenData } from '../../helpers/utils/transactions.util' -export function getCustomTxParamsData (data, { customPermissionAmount, decimals }) { +export function getCustomTxParamsData( + data, + { customPermissionAmount, decimals }, +) { const tokenData = getTokenData(data) if (!tokenData) { throw new Error('Invalid data') } else if (tokenData.name !== 'approve') { - throw new Error(`Invalid data; should be 'approve' method, but instead is '${tokenData.name}'`) + throw new Error( + `Invalid data; should be 'approve' method, but instead is '${tokenData.name}'`, + ) } let spender = getTokenAddressParam(tokenData) if (spender.startsWith('0x')) { @@ -19,10 +27,14 @@ export function getCustomTxParamsData (data, { customPermissionAmount, decimals if (!signature || !tokenValue) { throw new Error('Invalid data') } else if (tokenValue.length !== 64) { - throw new Error('Invalid token value; should be exactly 64 hex digits long (u256)') + throw new Error( + 'Invalid token value; should be exactly 64 hex digits long (u256)', + ) } - let customPermissionValue = decimalToHex(calcTokenValue(customPermissionAmount, decimals)) + let customPermissionValue = decimalToHex( + calcTokenValue(customPermissionAmount, decimals), + ) if (customPermissionValue.length > 64) { throw new Error('Custom value is larger than u256') } diff --git a/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.component.js b/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.component.js index 57310d7b2..9f036cb80 100644 --- a/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.component.js +++ b/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.component.js @@ -44,7 +44,9 @@ export default class ConfirmDecryptMessage extends Component { } componentDidMount = () => { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { + if ( + getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION + ) { window.addEventListener('beforeunload', this._beforeUnload) } } @@ -54,11 +56,7 @@ export default class ConfirmDecryptMessage extends Component { } _beforeUnload = async (event) => { - const { - clearConfirmTransaction, - cancelDecryptMessage, - txData, - } = this.props + const { clearConfirmTransaction, cancelDecryptMessage, txData } = this.props const { metricsEvent } = this.context await cancelDecryptMessage(txData, event) metricsEvent({ @@ -72,7 +70,9 @@ export default class ConfirmDecryptMessage extends Component { } _removeBeforeUnload = () => { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { + if ( + getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION + ) { window.removeEventListener('beforeunload', this._beforeUnload) } } @@ -96,7 +96,7 @@ export default class ConfirmDecryptMessage extends Component {
    - { this.context.t('decryptRequest') } + {this.context.t('decryptRequest')}
    @@ -113,13 +113,11 @@ export default class ConfirmDecryptMessage extends Component { return (
    - { `${t('account')}:` } + {`${t('account')}:`}
    - +
    ) @@ -127,7 +125,9 @@ export default class ConfirmDecryptMessage extends Component { renderBalance = () => { const { conversionRate } = this.props - const { fromAccount: { balance } } = this.state + const { + fromAccount: { balance }, + } = this.state const { t } = this.context const balanceInEther = conversionUtil(balance, { @@ -141,10 +141,10 @@ export default class ConfirmDecryptMessage extends Component { return (
    - { `${t('balance')}:` } + {`${t('balance')}:`}
    - { `${balanceInEther} ETH` } + {`${balanceInEther} ETH`}
    ) @@ -155,10 +155,7 @@ export default class ConfirmDecryptMessage extends Component { return (
    - +
    ) } @@ -166,9 +163,9 @@ export default class ConfirmDecryptMessage extends Component { renderAccountInfo = () => { return (
    - { this.renderAccount() } - { this.renderRequestIcon() } - { this.renderBalance() } + {this.renderAccount()} + {this.renderRequestIcon()} + {this.renderBalance()}
    ) } @@ -191,10 +188,8 @@ export default class ConfirmDecryptMessage extends Component { return (
    - { this.renderAccountInfo() } -
    + {this.renderAccountInfo()} +
    {origin.icon ? ( )} -
    - { notice } -
    +
    {notice}
    -
    -
    - { !hasDecrypted && !hasError ? txData.msgParams.data : rawMessage } - { hasError ? errorMessage : '' } +
    +
    + {!hasDecrypted && !hasError ? txData.msgParams.data : rawMessage} + {hasError ? errorMessage : ''}
    -
    + />
    { decryptMessageInline(txData, event).then((result) => { if (result.error) { - this.setState({ hasError: true, errorMessage: this.context.t('decryptInlineError', [result.error]) }) + this.setState({ + hasError: true, + errorMessage: this.context.t('decryptInlineError', [ + result.error, + ]), + }) } else { - this.setState({ hasDecrypted: true, rawMessage: result.rawData }) + this.setState({ + hasDecrypted: true, + rawMessage: result.rawData, + }) } }) }} > -
    +
    {t('decryptMetamask')}
    - { hasDecrypted ? - ( -
    this.copyMessage()} - onMouseDown={() => this.setState({ copyToClipboardPressed: true })} - onMouseUp={() => this.setState({ copyToClipboardPressed: false })} + {hasDecrypted ? ( +
    this.copyMessage()} + onMouseDown={() => this.setState({ copyToClipboardPressed: true })} + onMouseUp={() => this.setState({ copyToClipboardPressed: false })} + > + - -
    - {t('decryptCopy')} -
    - -
    -
    - ) - : +
    + {t('decryptCopy')} +
    + + +
    + ) : (
    - } + )}
    ) } @@ -316,7 +306,7 @@ export default class ConfirmDecryptMessage extends Component { history.push(mostRecentOverviewPage) }} > - { t('cancel') } + {t('cancel')}
    ) @@ -345,9 +335,9 @@ export default class ConfirmDecryptMessage extends Component { render = () => { return (
    - { this.renderHeader() } - { this.renderBody() } - { this.renderFooter() } + {this.renderHeader()} + {this.renderBody()} + {this.renderFooter()}
    ) } diff --git a/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.container.js b/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.container.js index 57d00021a..6be21e2ea 100644 --- a/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.container.js +++ b/ui/app/pages/confirm-decrypt-message/confirm-decrypt-message.container.js @@ -16,17 +16,17 @@ import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm import { getMostRecentOverviewPage } from '../../ducks/history/history' import ConfirmDecryptMessage from './confirm-decrypt-message.component' -function mapStateToProps (state) { +function mapStateToProps(state) { const { confirmTransaction, metamask: { domainMetadata = {} }, } = state - const { - txData = {}, - } = confirmTransaction + const { txData = {} } = confirmTransaction - const { msgParams: { from } } = txData + const { + msgParams: { from }, + } = txData const fromAccount = getTargetAccountWithSendEtherInfo(state, from) @@ -41,7 +41,7 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { goHome: () => dispatch(goHome()), clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), diff --git a/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js b/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js index 2bb2b8156..d799aa28d 100644 --- a/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js +++ b/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js @@ -12,48 +12,35 @@ export default class ConfirmDeployContract extends Component { txData: PropTypes.object, } - renderData () { + renderData() { const { t } = this.context - const { - txData: { - origin, - txParams: { - data, - } = {}, - } = {}, - } = this.props + const { txData: { origin, txParams: { data } = {} } = {} } = this.props return (
    - { `${t('origin')}:` } -
    -
    - { origin } + {`${t('origin')}:`}
    +
    {origin}
    - { `${t('bytes')}:` } -
    -
    - { ethUtil.toBuffer(data).length } + {`${t('bytes')}:`}
    +
    {ethUtil.toBuffer(data).length}
    - { `${t('hexData')}:` } -
    -
    - { data } + {`${t('hexData')}:`}
    +
    {data}
    ) } - render () { + render() { return ( { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { + if ( + getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION + ) { window.addEventListener('beforeunload', this._beforeUnload) } } @@ -65,7 +67,9 @@ export default class ConfirmEncryptionPublicKey extends Component { } _removeBeforeUnload = () => { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { + if ( + getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION + ) { window.removeEventListener('beforeunload', this._beforeUnload) } } @@ -76,7 +80,7 @@ export default class ConfirmEncryptionPublicKey extends Component {
    - { this.context.t('encryptionPublicKeyRequest') } + {this.context.t('encryptionPublicKeyRequest')}
    @@ -93,13 +97,11 @@ export default class ConfirmEncryptionPublicKey extends Component { return (
    - { `${t('account')}:` } + {`${t('account')}:`}
    - +
    ) @@ -108,7 +110,9 @@ export default class ConfirmEncryptionPublicKey extends Component { renderBalance = () => { const { conversionRate } = this.props const { t } = this.context - const { fromAccount: { balance } } = this.state + const { + fromAccount: { balance }, + } = this.state const balanceInEther = conversionUtil(balance, { fromNumericBase: 'hex', @@ -121,10 +125,10 @@ export default class ConfirmEncryptionPublicKey extends Component { return (
    - { `${t('balance')}:` } + {`${t('balance')}:`}
    - { `${balanceInEther} ETH` } + {`${balanceInEther} ETH`}
    ) @@ -135,10 +139,7 @@ export default class ConfirmEncryptionPublicKey extends Component { return (
    - +
    ) } @@ -146,9 +147,9 @@ export default class ConfirmEncryptionPublicKey extends Component { renderAccountInfo = () => { return (
    - { this.renderAccount() } - { this.renderRequestIcon() } - { this.renderBalance() } + {this.renderAccount()} + {this.renderRequestIcon()} + {this.renderBalance()}
    ) } @@ -162,10 +163,8 @@ export default class ConfirmEncryptionPublicKey extends Component { return (
    - { this.renderAccountInfo() } -
    + {this.renderAccountInfo()} +
    {origin.icon ? ( )} -
    - { notice } +
    + {notice}
    @@ -219,7 +216,7 @@ export default class ConfirmEncryptionPublicKey extends Component { history.push(mostRecentOverviewPage) }} > - { this.context.t('cancel') } + {this.context.t('cancel')}
    ) @@ -248,9 +245,9 @@ export default class ConfirmEncryptionPublicKey extends Component { render = () => { return (
    - { this.renderHeader() } - { this.renderBody() } - { this.renderFooter() } + {this.renderHeader()} + {this.renderBody()} + {this.renderFooter()}
    ) } diff --git a/ui/app/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js b/ui/app/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js index 7a0b2c37f..ea4c156e7 100644 --- a/ui/app/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js +++ b/ui/app/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js @@ -17,15 +17,13 @@ import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm import { getMostRecentOverviewPage } from '../../ducks/history/history' import ConfirmEncryptionPublicKey from './confirm-encryption-public-key.component' -function mapStateToProps (state) { +function mapStateToProps(state) { const { confirmTransaction, metamask: { domainMetadata = {} }, } = state - const { - txData = {}, - } = confirmTransaction + const { txData = {} } = confirmTransaction const { msgParams: from } = txData @@ -42,7 +40,7 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { goHome: () => dispatch(goHome()), clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), diff --git a/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js b/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js index 2fd23f45f..6cff21550 100644 --- a/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js +++ b/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js @@ -14,25 +14,27 @@ export default class ConfirmSendEther extends Component { txParams: PropTypes.object, } - handleEdit ({ txData }) { + handleEdit({ txData }) { const { editTransaction, history } = this.props editTransaction(txData) history.push(SEND_ROUTE) } - shouldHideData () { + shouldHideData() { const { txParams = {} } = this.props return !txParams.data } - render () { + render() { const hideData = this.shouldHideData() return ( this.handleEdit(confirmTransactionData)} + onEdit={(confirmTransactionData) => + this.handleEdit(confirmTransactionData) + } /> ) } diff --git a/ui/app/pages/confirm-send-ether/confirm-send-ether.container.js b/ui/app/pages/confirm-send-ether/confirm-send-ether.container.js index 03268571e..336cf4a4a 100644 --- a/ui/app/pages/confirm-send-ether/confirm-send-ether.container.js +++ b/ui/app/pages/confirm-send-ether/confirm-send-ether.container.js @@ -6,7 +6,9 @@ import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm import ConfirmSendEther from './confirm-send-ether.component' const mapStateToProps = (state) => { - const { confirmTransaction: { txData: { txParams } = {} } } = state + const { + confirmTransaction: { txData: { txParams } = {} }, + } = state return { txParams, @@ -17,24 +19,20 @@ const mapDispatchToProps = (dispatch) => { return { editTransaction: (txData) => { const { id, txParams } = txData - const { - from, - gas: gasLimit, - gasPrice, - to, - value: amount, - } = txParams + const { from, gas: gasLimit, gasPrice, to, value: amount } = txParams - dispatch(updateSend({ - from, - gasLimit, - gasPrice, - gasTotal: null, - to, - amount, - errors: { to: null, amount: null }, - editingTransactionId: id && id.toString(), - })) + dispatch( + updateSend({ + from, + gasLimit, + gasPrice, + gasTotal: null, + to, + amount, + errors: { to: null, amount: null }, + editingTransactionId: id && id.toString(), + }), + ) dispatch(clearConfirmTransaction()) }, diff --git a/ui/app/pages/confirm-send-token/confirm-send-token.component.js b/ui/app/pages/confirm-send-token/confirm-send-token.component.js index ae87808dc..3c68e564b 100644 --- a/ui/app/pages/confirm-send-token/confirm-send-token.component.js +++ b/ui/app/pages/confirm-send-token/confirm-send-token.component.js @@ -10,18 +10,20 @@ export default class ConfirmSendToken extends Component { tokenAmount: PropTypes.string, } - handleEdit (confirmTransactionData) { + handleEdit(confirmTransactionData) { const { editTransaction, history } = this.props editTransaction(confirmTransactionData) history.push(SEND_ROUTE) } - render () { + render() { const { tokenAmount } = this.props return ( this.handleEdit(confirmTransactionData)} + onEdit={(confirmTransactionData) => + this.handleEdit(confirmTransactionData) + } tokenAmount={tokenAmount} /> ) diff --git a/ui/app/pages/confirm-send-token/confirm-send-token.container.js b/ui/app/pages/confirm-send-token/confirm-send-token.container.js index 266bb03c9..c02f43adb 100644 --- a/ui/app/pages/confirm-send-token/confirm-send-token.container.js +++ b/ui/app/pages/confirm-send-token/confirm-send-token.container.js @@ -4,7 +4,10 @@ import { withRouter } from 'react-router-dom' import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck' import { updateSend, showSendTokenPage } from '../../store/actions' import { conversionUtil } from '../../helpers/utils/conversion-util' -import { getTokenValueParam, getTokenAddressParam } from '../../helpers/utils/token-util' +import { + getTokenValueParam, + getTokenAddressParam, +} from '../../helpers/utils/token-util' import { sendTokenTokenAmountAndToAddressSelector } from '../../selectors' import ConfirmSendToken from './confirm-send-token.component' @@ -19,15 +22,9 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { editTransaction: ({ txData, tokenData, tokenProps }) => { - const { id, - txParams: { - from, - to: tokenAddress, - gas: gasLimit, - gasPrice, - } = {}, + txParams: { from, to: tokenAddress, gas: gasLimit, gasPrice } = {}, } = txData const to = getTokenValueParam(tokenData) @@ -38,20 +35,22 @@ const mapDispatchToProps = (dispatch) => { toNumericBase: 'hex', }) - dispatch(updateSend({ - from, - gasLimit, - gasPrice, - gasTotal: null, - to, - amount: tokenAmountInHex, - errors: { to: null, amount: null }, - editingTransactionId: id && id.toString(), - token: { - ...tokenProps, - address: tokenAddress, - }, - })) + dispatch( + updateSend({ + from, + gasLimit, + gasPrice, + gasTotal: null, + to, + amount: tokenAmountInHex, + errors: { to: null, amount: null }, + editingTransactionId: id && id.toString(), + token: { + ...tokenProps, + address: tokenAddress, + }, + }), + ) dispatch(clearConfirmTransaction()) dispatch(showSendTokenPage()) }, diff --git a/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js b/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js index 1bbdde3b1..e60ec0ec2 100644 --- a/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js +++ b/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js @@ -13,7 +13,7 @@ import { import { getWeiHexFromDecimalValue } from '../../helpers/utils/conversions.util' import { ETH, PRIMARY } from '../../helpers/constants/common' -export default function ConfirmTokenTransactionBase ({ +export default function ConfirmTokenTransactionBase({ toAddress, tokenAddress, tokenAmount = '0', @@ -31,9 +31,9 @@ export default function ConfirmTokenTransactionBase ({ return '0' } - const decimalEthValue = ( - (new BigNumber(tokenAmount)).times(new BigNumber(contractExchangeRate)) - ).toFixed() + const decimalEthValue = new BigNumber(tokenAmount) + .times(new BigNumber(contractExchangeRate)) + .toFixed() return getWeiHexFromDecimalValue({ value: decimalEthValue, @@ -56,8 +56,7 @@ export default function ConfirmTokenTransactionBase ({ const fiatTotal = addFiat(fiatTransactionAmount, fiatTransactionTotal) const roundedFiatTotal = roundExponential(fiatTotal) return formatCurrency(roundedFiatTotal, currentCurrency) - }, - [ + }, [ currentCurrency, conversionRate, contractExchangeRate, @@ -73,30 +72,24 @@ export default function ConfirmTokenTransactionBase ({ identiconAddress={tokenAddress} title={tokensText} subtitleComponent={ - contractExchangeRate === undefined - ? ( - - { t('noConversionRateAvailable') } - - ) : ( - - ) - } - primaryTotalTextOverride={( -
    - { `${tokensText} + ` } - {t('noConversionRateAvailable')} + ) : ( + - { ethTransactionTotal } + ) + } + primaryTotalTextOverride={ +
    + {`${tokensText} + `} + + {ethTransactionTotal}
    - )} + } secondaryTotalTextOverride={secondaryTotalTextOverride} /> ) diff --git a/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js b/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js index d835a884e..8be624aa2 100644 --- a/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js +++ b/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js @@ -6,9 +6,7 @@ import { transactionFeeSelector, } from '../../selectors' import { getTokens } from '../../ducks/metamask/metamask' -import { - getTokenData, -} from '../../helpers/utils/transactions.util' +import { getTokenData } from '../../helpers/utils/transactions.util' import { calcTokenAmount, getTokenAddressParam, @@ -17,7 +15,9 @@ import { import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component' const mapStateToProps = (state, ownProps) => { - const { match: { params = {} } } = ownProps + const { + match: { params = {} }, + } = ownProps const { id: paramsTransactionId } = params const { confirmTransaction, @@ -25,26 +25,31 @@ const mapStateToProps = (state, ownProps) => { } = state const { - txData: { id: transactionId, txParams: { to: tokenAddress, data } = {} } = {}, + txData: { + id: transactionId, + txParams: { to: tokenAddress, data } = {}, + } = {}, } = confirmTransaction - const transaction = ( - currentNetworkTxList.find(({ id }) => id === (Number(paramsTransactionId) || - transactionId)) || {} - ) + const transaction = + currentNetworkTxList.find( + ({ id }) => id === (Number(paramsTransactionId) || transactionId), + ) || {} - const { - ethTransactionTotal, - fiatTransactionTotal, - } = transactionFeeSelector(state, transaction) + const { ethTransactionTotal, fiatTransactionTotal } = transactionFeeSelector( + state, + transaction, + ) const tokens = getTokens(state) - const currentToken = tokens && tokens.find(({ address }) => tokenAddress === address) + const currentToken = + tokens && tokens.find(({ address }) => tokenAddress === address) const { decimals, symbol: tokenSymbol } = currentToken || {} const tokenData = getTokenData(data) const tokenValue = getTokenValueParam(tokenData) const toAddress = getTokenAddressParam(tokenData) - const tokenAmount = tokenData && calcTokenAmount(tokenValue, decimals).toFixed() + const tokenAmount = + tokenData && calcTokenAmount(tokenValue, decimals).toFixed() const contractExchangeRate = contractExchangeRateSelector(state) return { diff --git a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js index 4c9ab94e1..614b5d254 100644 --- a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -3,7 +3,9 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums' import { getEnvironmentType } from '../../../../app/scripts/lib/util' -import ConfirmPageContainer, { ConfirmDetailRow } from '../../components/app/confirm-page-container' +import ConfirmPageContainer, { + ConfirmDetailRow, +} from '../../components/app/confirm-page-container' import { isBalanceSufficient } from '../send/send.utils' import { CONFIRM_TRANSACTION_ROUTE } from '../../helpers/constants/routes' import { @@ -11,7 +13,10 @@ import { TRANSACTION_ERROR_KEY, GAS_LIMIT_TOO_LOW_ERROR_KEY, } from '../../helpers/constants/error-keys' -import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../helpers/constants/transactions' +import { + CONFIRMED_STATUS, + DROPPED_STATUS, +} from '../../helpers/constants/transactions' import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display' import { PRIMARY, SECONDARY } from '../../helpers/constants/common' import { hexToDecimal } from '../../helpers/utils/conversions.util' @@ -68,7 +73,10 @@ export default class ConfirmTransactionBase extends Component { detailsComponent: PropTypes.node, errorKey: PropTypes.string, errorMessage: PropTypes.string, - primaryTotalTextOverride: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + primaryTotalTextOverride: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.node, + ]), secondaryTotalTextOverride: PropTypes.string, hideData: PropTypes.bool, hideDetails: PropTypes.bool, @@ -106,7 +114,7 @@ export default class ConfirmTransactionBase extends Component { submitWarning: '', } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { transactionStatus, showTransactionConfirmedModal, @@ -125,11 +133,18 @@ export default class ConfirmTransactionBase extends Component { transactionStatus: prevTxStatus, } = prevProps const statusUpdated = transactionStatus !== prevTxStatus - const txDroppedOrConfirmed = transactionStatus === DROPPED_STATUS || transactionStatus === CONFIRMED_STATUS + const txDroppedOrConfirmed = + transactionStatus === DROPPED_STATUS || + transactionStatus === CONFIRMED_STATUS - if (nextNonce !== prevNextNonce || customNonceValue !== prevCustomNonceValue) { + if ( + nextNonce !== prevNextNonce || + customNonceValue !== prevCustomNonceValue + ) { if (customNonceValue > nextNonce) { - this.setState({ submitWarning: this.context.t('nextNonceWarning', [nextNonce]) }) + this.setState({ + submitWarning: this.context.t('nextNonceWarning', [nextNonce]), + }) } else { this.setState({ submitWarning: '' }) } @@ -149,26 +164,23 @@ export default class ConfirmTransactionBase extends Component { } } - getErrorKey () { + getErrorKey() { const { balance, conversionRate, hexTransactionFee, - txData: { - simulationFails, - txParams: { - value: amount, - } = {}, - } = {}, + txData: { simulationFails, txParams: { value: amount } = {} } = {}, customGas, } = this.props - const insufficientBalance = balance && !isBalanceSufficient({ - amount, - gasTotal: hexTransactionFee || '0x0', - balance, - conversionRate, - }) + const insufficientBalance = + balance && + !isBalanceSufficient({ + amount, + gasTotal: hexTransactionFee || '0x0', + balance, + conversionRate, + }) if (insufficientBalance) { return { @@ -187,7 +199,9 @@ export default class ConfirmTransactionBase extends Component { if (simulationFails) { return { valid: true, - errorKey: simulationFails.errorKey ? simulationFails.errorKey : TRANSACTION_ERROR_KEY, + errorKey: simulationFails.errorKey + ? simulationFails.errorKey + : TRANSACTION_ERROR_KEY, } } @@ -196,8 +210,14 @@ export default class ConfirmTransactionBase extends Component { } } - handleEditGas () { - const { onEditGas, showCustomizeGasModal, actionKey, txData: { origin }, methodData = {} } = this.props + handleEditGas() { + const { + onEditGas, + showCustomizeGasModal, + actionKey, + txData: { origin }, + methodData = {}, + } = this.props this.context.metricsEvent({ eventOpts: { @@ -207,7 +227,8 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', + functionType: + actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -219,7 +240,7 @@ export default class ConfirmTransactionBase extends Component { } } - renderDetails () { + renderDetails() { const { detailsComponent, primaryTotalTextOverride, @@ -254,31 +275,48 @@ export default class ConfirmTransactionBase extends Component { label="Gas Fee" value={hexTransactionFee} headerText={notMainnetOrTest ? '' : 'Edit'} - headerTextClassName={notMainnetOrTest ? '' : 'confirm-detail-row__header-text--edit'} - onHeaderClick={notMainnetOrTest ? null : () => this.handleEditGas()} - secondaryText={hideFiatConversion ? this.context.t('noConversionRateAvailable') : ''} + headerTextClassName={ + notMainnetOrTest ? '' : 'confirm-detail-row__header-text--edit' + } + onHeaderClick={ + notMainnetOrTest ? null : () => this.handleEditGas() + } + secondaryText={ + hideFiatConversion + ? this.context.t('noConversionRateAvailable') + : '' + } /> - {advancedInlineGasShown || notMainnetOrTest - ? ( - updateGasAndCalculate({ ...customGas, gasPrice: newGasPrice })} - updateCustomGasLimit={(newGasLimit) => updateGasAndCalculate({ ...customGas, gasLimit: newGasLimit })} - customGasPrice={customGas.gasPrice} - customGasLimit={customGas.gasLimit} - insufficientBalance={insufficientBalance} - customPriceIsSafe - isSpeedUp={false} - /> - ) - : null - } + {advancedInlineGasShown || notMainnetOrTest ? ( + + updateGasAndCalculate({ ...customGas, gasPrice: newGasPrice }) + } + updateCustomGasLimit={(newGasLimit) => + updateGasAndCalculate({ ...customGas, gasLimit: newGasLimit }) + } + customGasPrice={customGas.gasPrice} + customGasLimit={customGas.gasLimit} + insufficientBalance={insufficientBalance} + customPriceIsSafe + isSpeedUp={false} + /> + ) : null}
    -
    +
    - { this.context.t('nonceFieldHeading') } + {this.context.t('nonceFieldHeading')}
    { if (!value.length || Number(value) < 0) { updateCustomNonce('') @@ -305,7 +347,7 @@ export default class ConfirmTransactionBase extends Component { }} fullWidth margin="dense" - value={ customNonceValue || '' } + value={customNonceValue || ''} />
    @@ -316,17 +358,11 @@ export default class ConfirmTransactionBase extends Component { ) } - renderData (functionType) { + renderData(functionType) { const { t } = this.context const { - txData: { - txParams: { - data, - } = {}, - } = {}, - methodData: { - params, - } = {}, + txData: { txParams: { data } = {} } = {}, + methodData: { params } = {}, hideData, dataComponent, } = this.props @@ -335,38 +371,44 @@ export default class ConfirmTransactionBase extends Component { return null } - return dataComponent || ( -
    -
    - {`${t('functionType')}:`} - - { functionType } - -
    - { - params && ( + return ( + dataComponent || ( +
    +
    + {`${t('functionType')}:`} + + {functionType} + +
    + {params && (
    - { `${t('parameters')}:` } + {`${t('parameters')}:`}
    -
    { JSON.stringify(params, null, 2) }
    +
    {JSON.stringify(params, null, 2)}
    - ) - } -
    - {`${t('hexData')}: ${ethUtil.toBuffer(data).length} bytes`} + )} +
    + {`${t('hexData')}: ${ethUtil.toBuffer(data).length} bytes`} +
    +
    {data}
    -
    - { data } -
    -
    + ) ) } - handleEdit () { - const { txData, tokenData, tokenProps, onEdit, actionKey, txData: { origin }, methodData = {} } = this.props + handleEdit() { + const { + txData, + tokenData, + tokenProps, + onEdit, + actionKey, + txData: { origin }, + methodData = {}, + } = this.props this.context.metricsEvent({ eventOpts: { @@ -376,7 +418,8 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', + functionType: + actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -384,7 +427,7 @@ export default class ConfirmTransactionBase extends Component { onEdit({ txData, tokenData, tokenProps }) } - handleCancelAll () { + handleCancelAll() { const { cancelAllTransactions, clearConfirmTransaction, @@ -405,7 +448,7 @@ export default class ConfirmTransactionBase extends Component { }) } - handleCancel () { + handleCancel() { const { metricsEvent } = this.context const { onCancel, @@ -429,7 +472,8 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', + functionType: + actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -437,15 +481,14 @@ export default class ConfirmTransactionBase extends Component { if (onCancel) { onCancel(txData) } else { - cancelTransaction(txData) - .then(() => { - clearConfirmTransaction() - history.push(mostRecentOverviewPage) - }) + cancelTransaction(txData).then(() => { + clearConfirmTransaction() + history.push(mostRecentOverviewPage) + }) } } - handleSubmit () { + handleSubmit() { const { metricsEvent } = this.context const { txData: { origin }, @@ -467,44 +510,50 @@ export default class ConfirmTransactionBase extends Component { return } - this.setState({ - submitting: true, - submitError: null, - }, () => { - this._removeBeforeUnload() - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Confirm Screen', - name: 'Transaction Completed', - }, - customVariables: { - recipientKnown: null, - functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', - origin, - }, - }) + this.setState( + { + submitting: true, + submitError: null, + }, + () => { + this._removeBeforeUnload() + metricsEvent({ + eventOpts: { + category: 'Transactions', + action: 'Confirm Screen', + name: 'Transaction Completed', + }, + customVariables: { + recipientKnown: null, + functionType: + actionKey || + getMethodName(methodData.name) || + 'contractInteraction', + origin, + }, + }) - setMetaMetricsSendCount(metaMetricsSendCount + 1) - .then(() => { + setMetaMetricsSendCount(metaMetricsSendCount + 1).then(() => { if (onSubmit) { - Promise.resolve(onSubmit(txData)) - .then(() => { - this.setState({ - submitting: false, - }) - updateCustomNonce('') + Promise.resolve(onSubmit(txData)).then(() => { + this.setState({ + submitting: false, }) + updateCustomNonce('') + }) } else { sendTransaction(txData) .then(() => { clearConfirmTransaction() - this.setState({ - submitting: false, - }, () => { - history.push(mostRecentOverviewPage) - updateCustomNonce('') - }) + this.setState( + { + submitting: false, + }, + () => { + history.push(mostRecentOverviewPage) + updateCustomNonce('') + }, + ) }) .catch((error) => { this.setState({ @@ -515,10 +564,11 @@ export default class ConfirmTransactionBase extends Component { }) } }) - }) + }, + ) } - renderTitleComponent () { + renderTitleComponent() { const { title, titleComponent, hexTransactionAmount } = this.props // Title string passed in by props takes priority @@ -526,18 +576,20 @@ export default class ConfirmTransactionBase extends Component { return null } - return titleComponent || ( - + return ( + titleComponent || ( + + ) ) } - renderSubtitleComponent () { + renderSubtitleComponent() { const { subtitle, subtitleComponent, hexTransactionAmount } = this.props // Subtitle string passed in by props takes priority @@ -545,17 +597,19 @@ export default class ConfirmTransactionBase extends Component { return null } - return subtitleComponent || ( - + return ( + subtitleComponent || ( + + ) ) } - handleNextTx (txId) { + handleNextTx(txId) { const { history, clearConfirmTransaction } = this.props if (txId) { @@ -564,7 +618,7 @@ export default class ConfirmTransactionBase extends Component { } } - getNavigateTxData () { + getNavigateTxData() { const { currentNetworkUnapprovedTxs, txData: { id } = {} } = this.props const enumUnapprovedTxs = Object.keys(currentNetworkUnapprovedTxs) const currentPosition = enumUnapprovedTxs.indexOf(id ? id.toString() : '') @@ -604,8 +658,13 @@ export default class ConfirmTransactionBase extends Component { } } - componentDidMount () { - const { toAddress, txData: { origin } = {}, getNextNonce, tryReverseResolveAddress } = this.props + componentDidMount() { + const { + toAddress, + txData: { origin } = {}, + getNextNonce, + tryReverseResolveAddress, + } = this.props const { metricsEvent } = this.context metricsEvent({ eventOpts: { @@ -628,11 +687,11 @@ export default class ConfirmTransactionBase extends Component { } } - componentWillUnmount () { + componentWillUnmount() { this._removeBeforeUnload() } - render () { + render() { const { t } = this.context const { isTxReprice, @@ -666,7 +725,17 @@ export default class ConfirmTransactionBase extends Component { const { name } = methodData const { valid, errorKey } = this.getErrorKey() - const { totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation, firstTx, lastTx, ofText, requestsWaitingText } = this.getNavigateTxData() + const { + totalTx, + positionOfCurrentTx, + nextTxId, + prevTxId, + showNavigation, + firstTx, + lastTx, + ofText, + requestsWaitingText, + } = this.getNavigateTxData() let functionType = getMethodName(name) if (!functionType) { @@ -725,13 +794,13 @@ export default class ConfirmTransactionBase extends Component { } } -export function getMethodName (camelCase) { +export function getMethodName(camelCase) { if (!camelCase || typeof camelCase !== 'string') { return '' } return camelCase - .replace(/([a-z])([A-Z])/ug, '$1 $2') - .replace(/([A-Z])([a-z])/ug, ' $1$2') - .replace(/ +/ug, ' ') + .replace(/([a-z])([A-Z])/gu, '$1 $2') + .replace(/([A-Z])([a-z])/gu, ' $1$2') + .replace(/ +/gu, ' ') } diff --git a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js index 08b0f4581..245df89ec 100644 --- a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -2,9 +2,7 @@ import { connect } from 'react-redux' import { compose } from 'redux' import { withRouter } from 'react-router-dom' import contractMap from 'eth-contract-metadata' -import { - clearConfirmTransaction, -} from '../../ducks/confirm-transaction/confirm-transaction.duck' +import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck' import { updateCustomNonce, @@ -25,7 +23,11 @@ import { getHexGasTotal } from '../../helpers/utils/confirm-tx.util' import { isBalanceSufficient, calcGasTotal } from '../send/send.utils' import { conversionGreaterThan } from '../../helpers/utils/conversion-util' import { MIN_GAS_LIMIT_DEC } from '../send/send.constants' -import { checksumAddress, shortenAddress, valuesFor } from '../../helpers/utils/util' +import { + checksumAddress, + shortenAddress, + valuesFor, +} from '../../helpers/utils/util' import { getAdvancedInlineGasShown, getCustomNonceValue, @@ -47,13 +49,20 @@ const casedContractMap = Object.keys(contractMap).reduce((acc, base) => { }, {}) let customNonceValue = '' -const customNonceMerge = (txData) => (customNonceValue ? ({ - ...txData, - customNonceValue, -}) : txData) +const customNonceMerge = (txData) => + customNonceValue + ? { + ...txData, + customNonceValue, + } + : txData const mapStateToProps = (state, ownProps) => { - const { toAddress: propsToAddress, customTxParamsData, match: { params = {} } } = ownProps + const { + toAddress: propsToAddress, + customTxParamsData, + match: { params = {} }, + } = ownProps const { id: paramsTransactionId } = params const { showFiatInTestnets } = getPreferences(state) const isMainnet = getIsMainnet(state) @@ -69,16 +78,17 @@ const mapStateToProps = (state, ownProps) => { metaMetricsSendCount, nextNonce, } = metamask + const { tokenData, txData, tokenProps, nonce } = confirmTransaction const { - tokenData, - txData, - tokenProps, - nonce, - } = confirmTransaction - const { txParams = {}, lastGasPrice, id: transactionId, transactionCategory } = txData - const transaction = Object.values(unapprovedTxs).find( - ({ id }) => id === (transactionId || Number(paramsTransactionId)), - ) || {} + txParams = {}, + lastGasPrice, + id: transactionId, + transactionCategory, + } = txData + const transaction = + Object.values(unapprovedTxs).find( + ({ id }) => id === (transactionId || Number(paramsTransactionId)), + ) || {} const { from: fromAddress, to: txParamsToAddress, @@ -94,7 +104,8 @@ const mapStateToProps = (state, ownProps) => { const { name: fromName } = identities[fromAddress] const toAddress = propsToAddress || txParamsToAddress - const toName = identities[toAddress]?.name || + const toName = + identities[toAddress]?.name || casedContractMap[toAddress]?.name || shortenAddress(checksumAddress(toAddress)) @@ -171,8 +182,8 @@ const mapStateToProps = (state, ownProps) => { useNonceField: getUseNonceField(state), customNonceValue: getCustomNonceValue(state), insufficientBalance, - hideSubtitle: (!isMainnet && !showFiatInTestnets), - hideFiatConversion: (!isMainnet && !showFiatInTestnets), + hideSubtitle: !isMainnet && !showFiatInTestnets, + hideFiatConversion: !isMainnet && !showFiatInTestnets, metaMetricsSendCount, transactionCategory, nextNonce, @@ -195,17 +206,25 @@ export const mapDispatchToProps = (dispatch) => { return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit })) }, showCustomizeGasModal: ({ txData, onSubmit, validate }) => { - return dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData, onSubmit, validate })) + return dispatch( + showModal({ name: 'CUSTOMIZE_GAS', txData, onSubmit, validate }), + ) }, updateGasAndCalculate: (updatedTx) => { return dispatch(updateTransaction(updatedTx)) }, - showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => { - return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount })) + showRejectTransactionsConfirmationModal: ({ + onSubmit, + unapprovedTxCount, + }) => { + return dispatch( + showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount }), + ) }, cancelTransaction: ({ id }) => dispatch(cancelTx({ id })), cancelAllTransactions: (txList) => dispatch(cancelTxs(txList)), - sendTransaction: (txData) => dispatch(updateAndApproveTx(customNonceMerge(txData))), + sendTransaction: (txData) => + dispatch(updateAndApproveTx(customNonceMerge(txData))), setMetaMetricsSendCount: (val) => dispatch(setMetaMetricsSendCount(val)), getNextNonce: () => dispatch(getNextNonce()), } @@ -230,17 +249,19 @@ const getValidateEditGas = ({ balance, conversionRate, txData }) => { } } - const gasLimitTooLow = gasLimit && conversionGreaterThan( - { - value: MIN_GAS_LIMIT_DEC, - fromNumericBase: 'dec', - conversionRate, - }, - { - value: gasLimit, - fromNumericBase: 'hex', - }, - ) + const gasLimitTooLow = + gasLimit && + conversionGreaterThan( + { + value: MIN_GAS_LIMIT_DEC, + fromNumericBase: 'dec', + conversionRate, + }, + { + value: gasLimit, + fromNumericBase: 'hex', + }, + ) if (gasLimitTooLow) { return { @@ -264,18 +285,24 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { ...otherDispatchProps } = dispatchProps - const validateEditGas = getValidateEditGas({ balance, conversionRate, txData }) + const validateEditGas = getValidateEditGas({ + balance, + conversionRate, + txData, + }) return { ...stateProps, ...otherDispatchProps, ...ownProps, - showCustomizeGasModal: () => dispatchShowCustomizeGasModal({ - txData, - onSubmit: (customGas) => dispatchUpdateGasAndCalculate(customGas), - validate: validateEditGas, - }), - cancelAllTransactions: () => dispatchCancelAllTransactions(valuesFor(unapprovedTxs)), + showCustomizeGasModal: () => + dispatchShowCustomizeGasModal({ + txData, + onSubmit: (customGas) => dispatchUpdateGasAndCalculate(customGas), + validate: validateEditGas, + }), + cancelAllTransactions: () => + dispatchCancelAllTransactions(valuesFor(unapprovedTxs)), updateGasAndCalculate: ({ gasLimit, gasPrice }) => { const updatedTx = { ...txData, diff --git a/ui/app/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js b/ui/app/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js index 92ac0c66b..3add429b6 100644 --- a/ui/app/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js +++ b/ui/app/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js @@ -8,7 +8,10 @@ describe('ConfirmTransactionBase Component', function () { assert.equal(getMethodName({}), '') assert.equal(getMethodName('confirm'), 'confirm') assert.equal(getMethodName('balanceOf'), 'balance Of') - assert.equal(getMethodName('ethToTokenSwapInput'), 'eth To Token Swap Input') + assert.equal( + getMethodName('ethToTokenSwapInput'), + 'eth To Token Swap Input', + ) }) }) }) diff --git a/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.component.js b/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.component.js index 02014ee37..7c35c463e 100644 --- a/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.component.js +++ b/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.component.js @@ -28,10 +28,8 @@ export default class ConfirmTransactionSwitch extends Component { txData: PropTypes.object, } - redirectToTransaction () { - const { - txData, - } = this.props + redirectToTransaction() { + const { txData } = this.props const { id, txParams: { data } = {}, transactionCategory } = txData if (transactionCategory === DEPLOY_CONTRACT_ACTION_KEY) { @@ -69,7 +67,7 @@ export default class ConfirmTransactionSwitch extends Component { return } - render () { + render() { const { txData } = this.props if (txData.txParams) { return this.redirectToTransaction() diff --git a/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.container.js b/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.container.js index dd6970d87..a8266c417 100644 --- a/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.container.js +++ b/ui/app/pages/confirm-transaction-switch/confirm-transaction-switch.container.js @@ -3,8 +3,12 @@ import { unconfirmedTransactionsListSelector } from '../../selectors' import ConfirmTransactionSwitch from './confirm-transaction-switch.component' const mapStateToProps = (state, ownProps) => { - const { metamask: { unapprovedTxs } } = state - const { match: { params = {}, url } } = ownProps + const { + metamask: { unapprovedTxs }, + } = state + const { + match: { params = {}, url }, + } = ownProps const urlId = url && url.match(/\d+/u) && url.match(/\d+/u)[0] const { id: paramsId } = params const transactionId = paramsId || urlId diff --git a/ui/app/pages/confirm-transaction/conf-tx.js b/ui/app/pages/confirm-transaction/conf-tx.js index 3e21a8eb0..5bcb7f815 100644 --- a/ui/app/pages/confirm-transaction/conf-tx.js +++ b/ui/app/pages/confirm-transaction/conf-tx.js @@ -12,16 +12,14 @@ import Loading from '../../components/ui/loading-screen' import { getMostRecentOverviewPage } from '../../ducks/history/history' import { MESSAGE_TYPE } from '../../../../app/scripts/lib/enums' -function mapStateToProps (state) { +function mapStateToProps(state) { const { metamask, appState } = state const { unapprovedMsgCount, unapprovedPersonalMsgCount, unapprovedTypedMessagesCount, } = metamask - const { - txId, - } = appState + const { txId } = appState return { identities: state.metamask.identities, @@ -72,17 +70,21 @@ class ConfirmTxScreen extends Component { }).isRequired, } - getUnapprovedMessagesTotal () { + getUnapprovedMessagesTotal() { const { unapprovedMsgCount = 0, unapprovedPersonalMsgCount = 0, unapprovedTypedMessagesCount = 0, } = this.props - return unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount + return ( + unapprovedTypedMessagesCount + + unapprovedMsgCount + + unapprovedPersonalMsgCount + ) } - getTxData () { + getTxData() { const { network, index, @@ -108,16 +110,19 @@ class ConfirmTxScreen extends Component { : unconfTxList[index] } - signatureSelect (type, version) { + signatureSelect(type, version) { // Temporarily direct only v3 and v4 requests to new code. - if (type === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA && (version === 'V3' || version === 'V4')) { + if ( + type === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA && + (version === 'V3' || version === 'V4') + ) { return SignatureRequest } return SignatureRequestOriginal } - signMessage (msgData, event) { + signMessage(msgData, event) { log.info('conf-tx.js: signing message') const params = msgData.msgParams params.metamaskId = msgData.id @@ -125,13 +130,13 @@ class ConfirmTxScreen extends Component { return this.props.dispatch(actions.signMsg(params)) } - stopPropagation (event) { + stopPropagation(event) { if (event.stopPropagation) { event.stopPropagation() } } - signPersonalMessage (msgData, event) { + signPersonalMessage(msgData, event) { log.info('conf-tx.js: signing personal message') const params = msgData.msgParams params.metamaskId = msgData.id @@ -139,7 +144,7 @@ class ConfirmTxScreen extends Component { return this.props.dispatch(actions.signPersonalMsg(params)) } - signTypedMessage (msgData, event) { + signTypedMessage(msgData, event) { log.info('conf-tx.js: signing typed message') const params = msgData.msgParams params.metamaskId = msgData.id @@ -147,25 +152,25 @@ class ConfirmTxScreen extends Component { return this.props.dispatch(actions.signTypedMsg(params)) } - cancelMessage (msgData, event) { + cancelMessage(msgData, event) { log.info('canceling message') this.stopPropagation(event) return this.props.dispatch(actions.cancelMsg(msgData)) } - cancelPersonalMessage (msgData, event) { + cancelPersonalMessage(msgData, event) { log.info('canceling personal message') this.stopPropagation(event) return this.props.dispatch(actions.cancelPersonalMsg(msgData)) } - cancelTypedMessage (msgData, event) { + cancelTypedMessage(msgData, event) { log.info('canceling typed message') this.stopPropagation(event) return this.props.dispatch(actions.cancelTypedMsg(msgData)) } - componentDidMount () { + componentDidMount() { const { unapprovedTxs = {}, history, @@ -175,12 +180,16 @@ class ConfirmTxScreen extends Component { } = this.props const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network) - if (unconfTxList.length === 0 && !send.to && this.getUnapprovedMessagesTotal() === 0) { + if ( + unconfTxList.length === 0 && + !send.to && + this.getUnapprovedMessagesTotal() === 0 + ) { history.push(mostRecentOverviewPage) } } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { unapprovedTxs = {}, network, @@ -205,33 +214,38 @@ class ConfirmTxScreen extends Component { const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network) if (prevTx && prevTx.status === 'dropped') { - this.props.dispatch(actions.showModal({ - name: 'TRANSACTION_CONFIRMED', - onSubmit: () => history.push(mostRecentOverviewPage), - })) + this.props.dispatch( + actions.showModal({ + name: 'TRANSACTION_CONFIRMED', + onSubmit: () => history.push(mostRecentOverviewPage), + }), + ) return } - if (unconfTxList.length === 0 && !send.to && this.getUnapprovedMessagesTotal() === 0) { + if ( + unconfTxList.length === 0 && + !send.to && + this.getUnapprovedMessagesTotal() === 0 + ) { this.props.history.push(mostRecentOverviewPage) } } - render () { - const { - currentCurrency, - blockGasLimit, - } = this.props + render() { + const { currentCurrency, blockGasLimit } = this.props const txData = this.getTxData() || {} - const { msgParams, type, msgParams: { version } } = txData + const { + msgParams, + type, + msgParams: { version }, + } = txData log.debug('msgParams detected, rendering pending msg') if (!msgParams) { - return ( - - ) + return } const SigComponent = this.signatureSelect(type, version) @@ -253,7 +267,4 @@ class ConfirmTxScreen extends Component { } } -export default compose( - withRouter, - connect(mapStateToProps), -)(ConfirmTxScreen) +export default compose(withRouter, connect(mapStateToProps))(ConfirmTxScreen) diff --git a/ui/app/pages/confirm-transaction/confirm-transaction.component.js b/ui/app/pages/confirm-transaction/confirm-transaction.component.js index 087b8e8b4..92f073d9d 100644 --- a/ui/app/pages/confirm-transaction/confirm-transaction.component.js +++ b/ui/app/pages/confirm-transaction/confirm-transaction.component.js @@ -47,7 +47,7 @@ export default class ConfirmTransaction extends Component { isTokenMethodAction: PropTypes.bool, } - componentDidMount () { + componentDidMount() { const { totalUnapprovedCount = 0, send = {}, @@ -78,7 +78,7 @@ export default class ConfirmTransaction extends Component { } } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { setTransactionToConfirm, transaction: { txData: { txParams: { data } = {} } = {} }, @@ -91,73 +91,86 @@ export default class ConfirmTransaction extends Component { totalUnapprovedCount, } = this.props - if (paramsTransactionId && transactionId && prevProps.paramsTransactionId !== paramsTransactionId) { + if ( + paramsTransactionId && + transactionId && + prevProps.paramsTransactionId !== paramsTransactionId + ) { clearConfirmTransaction() getContractMethodData(data) setTransactionToConfirm(paramsTransactionId) - } else if (prevProps.transactionId && !transactionId && !totalUnapprovedCount) { + } else if ( + prevProps.transactionId && + !transactionId && + !totalUnapprovedCount + ) { history.replace(mostRecentOverviewPage) - } else if (prevProps.transactionId && transactionId && prevProps.transactionId !== transactionId) { + } else if ( + prevProps.transactionId && + transactionId && + prevProps.transactionId !== transactionId + ) { history.replace(mostRecentOverviewPage) } } - render () { + render() { const { transactionId, paramsTransactionId } = this.props // Show routes when state.confirmTransaction has been set and when either the ID in the params // isn't specified or is specified and matches the ID in state.confirmTransaction in order to // support URLs of /confirm-transaction or /confirm-transaction/ - return transactionId && (!paramsTransactionId || paramsTransactionId === transactionId) - ? ( - - - - - - - - - - - - - ) - : + return transactionId && + (!paramsTransactionId || paramsTransactionId === transactionId) ? ( + + + + + + + + + + + + + ) : ( + + ) } } diff --git a/ui/app/pages/confirm-transaction/confirm-transaction.container.js b/ui/app/pages/confirm-transaction/confirm-transaction.container.js index 6ee2579ff..61c4bc445 100644 --- a/ui/app/pages/confirm-transaction/confirm-transaction.container.js +++ b/ui/app/pages/confirm-transaction/confirm-transaction.container.js @@ -5,29 +5,21 @@ import { setTransactionToConfirm, clearConfirmTransaction, } from '../../ducks/confirm-transaction/confirm-transaction.duck' -import { - isTokenMethodAction, -} from '../../helpers/utils/transactions.util' -import { - fetchBasicGasAndTimeEstimates, -} from '../../ducks/gas/gas.duck' +import { isTokenMethodAction } from '../../helpers/utils/transactions.util' +import { fetchBasicGasAndTimeEstimates } from '../../ducks/gas/gas.duck' -import { - getContractMethodData, - getTokenParams, -} from '../../store/actions' +import { getContractMethodData, getTokenParams } from '../../store/actions' import { unconfirmedTransactionsListSelector } from '../../selectors' import { getMostRecentOverviewPage } from '../../ducks/history/history' import ConfirmTransaction from './confirm-transaction.component' const mapStateToProps = (state, ownProps) => { const { - metamask: { - send, - unapprovedTxs, - }, + metamask: { send, unapprovedTxs }, } = state - const { match: { params = {} } } = ownProps + const { + match: { params = {} }, + } = ownProps const { id } = params const unconfirmedTransactions = unconfirmedTransactionsListSelector(state) @@ -56,7 +48,8 @@ const mapDispatchToProps = (dispatch) => { dispatch(setTransactionToConfirm(transactionId)) }, clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()), + fetchBasicGasAndTimeEstimates: () => + dispatch(fetchBasicGasAndTimeEstimates()), getContractMethodData: (data) => dispatch(getContractMethodData(data)), getTokenParams: (tokenAddress) => dispatch(getTokenParams(tokenAddress)), } diff --git a/ui/app/pages/connected-accounts/connected-accounts.component.js b/ui/app/pages/connected-accounts/connected-accounts.component.js index 3fea60ed3..5a0a30109 100644 --- a/ui/app/pages/connected-accounts/connected-accounts.component.js +++ b/ui/app/pages/connected-accounts/connected-accounts.component.js @@ -28,7 +28,7 @@ export default class ConnectedAccounts extends PureComponent { history: PropTypes.object.isRequired, } - render () { + render() { const { accountToConnect, activeTabOrigin, @@ -44,14 +44,23 @@ export default class ConnectedAccounts extends PureComponent { } = this.props const { t } = this.context - const connectedAccountsDescription = connectedAccounts.length > 1 - ? t('connectedAccountsDescriptionPlural', [connectedAccounts.length]) - : t('connectedAccountsDescriptionSingular') + const connectedAccountsDescription = + connectedAccounts.length > 1 + ? t('connectedAccountsDescriptionPlural', [connectedAccounts.length]) + : t('connectedAccountsDescriptionSingular') return ( history.push(mostRecentOverviewPage)} footerClassName="connected-accounts__footer" footer={} diff --git a/ui/app/pages/connected-accounts/connected-accounts.container.js b/ui/app/pages/connected-accounts/connected-accounts.container.js index 0fe24583a..b1a1a2433 100644 --- a/ui/app/pages/connected-accounts/connected-accounts.container.js +++ b/ui/app/pages/connected-accounts/connected-accounts.container.js @@ -6,7 +6,11 @@ import { getSelectedAddress, } from '../../selectors' import { isExtensionUrl } from '../../helpers/utils/util' -import { addPermittedAccount, removePermittedAccount, setSelectedAddress } from '../../store/actions' +import { + addPermittedAccount, + removePermittedAccount, + setSelectedAddress, +} from '../../store/actions' import { getMostRecentOverviewPage } from '../../ducks/history/history' import ConnectedAccounts from './connected-accounts.component' @@ -31,8 +35,10 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - addPermittedAccount: (origin, address) => dispatch(addPermittedAccount(origin, address)), - removePermittedAccount: (origin, address) => dispatch(removePermittedAccount(origin, address)), + addPermittedAccount: (origin, address) => + dispatch(addPermittedAccount(origin, address)), + removePermittedAccount: (origin, address) => + dispatch(removePermittedAccount(origin, address)), setSelectedAddress: (address) => dispatch(setSelectedAddress(address)), } } @@ -44,9 +50,15 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { ...ownProps, ...stateProps, ...dispatchProps, - connectAccount: (address) => dispatchProps.addPermittedAccount(activeTabOrigin, address), - removePermittedAccount: (address) => dispatchProps.removePermittedAccount(activeTabOrigin, address), + connectAccount: (address) => + dispatchProps.addPermittedAccount(activeTabOrigin, address), + removePermittedAccount: (address) => + dispatchProps.removePermittedAccount(activeTabOrigin, address), } } -export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(ConnectedAccounts) +export default connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(ConnectedAccounts) diff --git a/ui/app/pages/connected-sites/connected-sites.component.js b/ui/app/pages/connected-sites/connected-sites.component.js index 93a8d4e26..5c8f84e5f 100644 --- a/ui/app/pages/connected-sites/connected-sites.component.js +++ b/ui/app/pages/connected-sites/connected-sites.component.js @@ -32,7 +32,7 @@ export default class ConnectedSites extends Component { sitePendingDisconnect: null, } - componentDidMount () { + componentDidMount() { const { getOpenMetamaskTabsIds } = this.props getOpenMetamaskTabsIds() } @@ -67,7 +67,7 @@ export default class ConnectedSites extends Component { this.clearPendingDisconnect() } - renderConnectedSitesList () { + renderConnectedSitesList() { return ( - {t('connectManually')} - - ) - : null + tabToConnect ? ( + + {t('connectManually')} + + ) : null } footerClassName="connected-sites__add-site-manually" > @@ -115,11 +114,12 @@ export default class ConnectedSites extends Component { ) } - renderDisconnectPopover () { - + renderDisconnectPopover() { const { closePopover, permittedAccountsByOrigin } = this.props const { t } = this.context - const { sitePendingDisconnect: { domainKey } } = this.state + const { + sitePendingDisconnect: { domainKey }, + } = this.state const numPermittedAccounts = permittedAccountsByOrigin[domainKey].length @@ -129,46 +129,37 @@ export default class ConnectedSites extends Component { title={t('disconnectPrompt', [domainKey])} subtitle={t('disconnectAllAccountsConfirmationDescription')} onClose={closePopover} - footer={( + footer={ <>
    -
    - { - numPermittedAccounts > 1 - ? ( - - ) - : null - } + {numPermittedAccounts > 1 ? ( + + ) : null} - )} + } footerClassName="connected-sites__confirmation" /> ) } - render () { + render() { const { sitePendingDisconnect } = this.state - return ( - sitePendingDisconnect - ? this.renderDisconnectPopover() - : this.renderConnectedSitesPopover() - ) + return sitePendingDisconnect + ? this.renderDisconnectPopover() + : this.renderConnectedSitesPopover() } } diff --git a/ui/app/pages/connected-sites/connected-sites.container.js b/ui/app/pages/connected-sites/connected-sites.container.js index f34558741..ef5edd85b 100644 --- a/ui/app/pages/connected-sites/connected-sites.container.js +++ b/ui/app/pages/connected-sites/connected-sites.container.js @@ -26,9 +26,8 @@ const mapStateToProps = (state) => { const permittedAccountsByOrigin = getPermittedAccountsByOrigin(state) const selectedAddress = getSelectedAddress(state) - const currentTabHasNoAccounts = !permittedAccountsByOrigin[ - originOfCurrentTab - ]?.length + const currentTabHasNoAccounts = !permittedAccountsByOrigin[originOfCurrentTab] + ?.length let tabToConnect if (originOfCurrentTab && currentTabHasNoAccounts && !openMetaMaskTabs[id]) { @@ -56,12 +55,17 @@ const mapDispatchToProps = (dispatch) => { dispatch(removePermittedAccount(domainKey, address)) }, disconnectAllAccounts: (domainKey, domain) => { - const permissionMethodNames = domain.permissions.map(({ parentCapability }) => parentCapability) - dispatch(removePermissionsFor({ - [domainKey]: permissionMethodNames, - })) + const permissionMethodNames = domain.permissions.map( + ({ parentCapability }) => parentCapability, + ) + dispatch( + removePermissionsFor({ + [domainKey]: permissionMethodNames, + }), + ) }, - requestAccountsPermissionWithId: (origin) => dispatch(requestAccountsPermissionWithId(origin)), + requestAccountsPermissionWithId: (origin) => + dispatch(requestAccountsPermissionWithId(origin)), } } @@ -107,4 +111,8 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { } } -export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(ConnectedSites) +export default connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(ConnectedSites) diff --git a/ui/app/pages/create-account/connect-hardware/account-list.js b/ui/app/pages/create-account/connect-hardware/account-list.js index f1f54ddbc..b819c81be 100644 --- a/ui/app/pages/create-account/connect-hardware/account-list.js +++ b/ui/app/pages/create-account/connect-hardware/account-list.js @@ -5,7 +5,7 @@ import getAccountLink from '../../../../lib/account-link' import Button from '../../../components/ui/button' class AccountList extends Component { - getHdPaths () { + getHdPaths() { return [ { label: `Ledger Live`, @@ -18,167 +18,181 @@ class AccountList extends Component { ] } - goToNextPage = () => { - // If we have < 5 accounts, it's restricted by BIP-44 - if (this.props.accounts.length === 5) { - this.props.getPage(this.props.device, 1, this.props.selectedPath) - } else { - this.props.onAccountRestriction() - } + goToNextPage = () => { + // If we have < 5 accounts, it's restricted by BIP-44 + if (this.props.accounts.length === 5) { + this.props.getPage(this.props.device, 1, this.props.selectedPath) + } else { + this.props.onAccountRestriction() } + } - goToPreviousPage = () => { - this.props.getPage(this.props.device, -1, this.props.selectedPath) - } + goToPreviousPage = () => { + this.props.getPage(this.props.device, -1, this.props.selectedPath) + } - renderHdPathSelector () { - const { onPathChange, selectedPath } = this.props + renderHdPathSelector() { + const { onPathChange, selectedPath } = this.props - const options = this.getHdPaths() - return ( -
    -

    - {this.context.t('selectHdPath')} -

    -

    - {this.context.t('selectPathHelp')} -

    -
    - { + onPathChange(opt.value) + }} + />
    - ) - } +
    + ) + } - capitalizeDevice (device) { - return device.slice(0, 1).toUpperCase() + device.slice(1) - } + capitalizeDevice(device) { + return device.slice(0, 1).toUpperCase() + device.slice(1) + } - renderHeader () { - const { device } = this.props - return ( -
    -

    - {`${this.context.t('unlock')} ${this.capitalizeDevice(device)}`} -

    - {device.toLowerCase() === 'ledger' ? this.renderHdPathSelector() : null} -

    - {this.context.t('selectAnAccount')} -

    -

    {this.context.t('selectAnAccountHelp')}

    -
    - ) - } + renderHeader() { + const { device } = this.props + return ( +
    +

    + {`${this.context.t('unlock')} ${this.capitalizeDevice(device)}`} +

    + {device.toLowerCase() === 'ledger' ? this.renderHdPathSelector() : null} +

    + {this.context.t('selectAnAccount')} +

    +

    + {this.context.t('selectAnAccountHelp')} +

    +
    + ) + } - renderAccounts () { - return ( -
    - {this.props.accounts.map((account, idx) => ( -
    -
    - this.props.onAccountChange(e.target.value)} - checked={this.props.selectedAccount === account.index.toString()} - /> - -
    - + {this.props.accounts.map((account, idx) => ( +
    +
    + this.props.onAccountChange(e.target.value)} + checked={ + this.props.selectedAccount === account.index.toString() + } + /> + + + {account.index + 1} + + {`${account.address.slice(0, 4)}...${account.address.slice( + -4, + )}`} + {`${account.balance}`} +
    - ))} -
    - ) + + + +
    + ))} +
    + ) + } + + renderPagination() { + return ( +
    + + +
    + ) + } + + renderButtons() { + const disabled = this.props.selectedAccount === null + const buttonProps = {} + if (disabled) { + buttonProps.disabled = true } - renderPagination () { - return ( -
    - - -
    - ) - } + return ( +
    + + +
    + ) + } - renderButtons () { - const disabled = this.props.selectedAccount === null - const buttonProps = {} - if (disabled) { - buttonProps.disabled = true - } - - return ( -
    - - -
    - ) - } - - renderForgetDevice () { - return ( - - ) - } - - render () { - return ( -
    - {this.renderHeader()} - {this.renderAccounts()} - {this.renderPagination()} - {this.renderButtons()} - {this.renderForgetDevice()} -
    - ) - } + renderForgetDevice() { + return ( + + ) + } + render() { + return ( +
    + {this.renderHeader()} + {this.renderAccounts()} + {this.renderPagination()} + {this.renderButtons()} + {this.renderForgetDevice()} +
    + ) + } } AccountList.propTypes = { diff --git a/ui/app/pages/create-account/connect-hardware/index.js b/ui/app/pages/create-account/connect-hardware/index.js index 30bbfd44c..ef7ef9c38 100644 --- a/ui/app/pages/create-account/connect-hardware/index.js +++ b/ui/app/pages/create-account/connect-hardware/index.js @@ -18,24 +18,29 @@ class ConnectHardwareForm extends Component { device: null, } - UNSAFE_componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps(nextProps) { const { accounts } = nextProps const newAccounts = this.state.accounts.map((a) => { const normalizedAddress = a.address.toLowerCase() - const balanceValue = (accounts[normalizedAddress] && accounts[normalizedAddress].balance) || null + const balanceValue = + (accounts[normalizedAddress] && accounts[normalizedAddress].balance) || + null a.balance = balanceValue ? formatBalance(balanceValue, 6) : '...' return a }) this.setState({ accounts: newAccounts }) } - componentDidMount () { + componentDidMount() { this.checkIfUnlocked() } - async checkIfUnlocked () { + async checkIfUnlocked() { for (const device of ['trezor', 'ledger']) { - const unlocked = await this.props.checkHardwareStatus(device, this.props.defaultHdPaths[device]) + const unlocked = await this.props.checkHardwareStatus( + device, + this.props.defaultHdPaths[device], + ) if (unlocked) { this.setState({ unlocked: true }) this.getPage(device, 0, this.props.defaultHdPaths[device]) @@ -54,7 +59,10 @@ class ConnectHardwareForm extends Component { } onPathChange = (path) => { - this.props.setHardwareWalletDefaultHdPath({ device: this.state.device, path }) + this.props.setHardwareWalletDefaultHdPath({ + device: this.state.device, + path, + }) this.getPage(this.state.device, 0, path) } @@ -66,7 +74,7 @@ class ConnectHardwareForm extends Component { this.setState({ error: this.context.t('ledgerAccountRestriction') }) } - showTemporaryAlert () { + showTemporaryAlert() { this.props.showAlert(this.context.t('hardwareWalletConnected')) // Autohide the alert after 5 seconds setTimeout((_) => { @@ -79,7 +87,6 @@ class ConnectHardwareForm extends Component { .connectHardware(device, page, hdPath) .then((accounts) => { if (accounts.length) { - // If we just loaded the accounts for the first time // (device previously locked) show the global alert if (this.state.accounts.length === 0 && !this.state.unlocked) { @@ -94,16 +101,25 @@ class ConnectHardwareForm extends Component { newState.selectedAccount = a.index.toString() } }) - // If the page doesn't contain the selected account, let's deselect it - } else if (!accounts.filter((a) => a.index.toString() === this.state.selectedAccount).length) { + // If the page doesn't contain the selected account, let's deselect it + } else if ( + !accounts.filter( + (a) => a.index.toString() === this.state.selectedAccount, + ).length + ) { newState.selectedAccount = null } // Map accounts with balances newState.accounts = accounts.map((account) => { const normalizedAddress = account.address.toLowerCase() - const balanceValue = (this.props.accounts[normalizedAddress] && this.props.accounts[normalizedAddress].balance) || null - account.balance = balanceValue ? formatBalance(balanceValue, 6) : '...' + const balanceValue = + (this.props.accounts[normalizedAddress] && + this.props.accounts[normalizedAddress].balance) || + null + account.balance = balanceValue + ? formatBalance(balanceValue, 6) + : '...' return account }) @@ -116,14 +132,18 @@ class ConnectHardwareForm extends Component { this.setState({ browserSupported: false, error: null }) } else if (e.indexOf('U2F') > -1) { this.setState({ error: 'U2F' }) - } else if (errorMessage !== 'Window closed' && errorMessage !== 'Popup closed') { + } else if ( + errorMessage !== 'Window closed' && + errorMessage !== 'Popup closed' + ) { this.setState({ error: errorMessage }) } }) } onForgetDevice = (device) => { - this.props.forgetDevice(device) + this.props + .forgetDevice(device) .then((_) => { this.setState({ error: null, @@ -131,13 +151,18 @@ class ConnectHardwareForm extends Component { accounts: [], unlocked: false, }) - }).catch((e) => { + }) + .catch((e) => { this.setState({ error: e.message }) }) } onUnlockAccount = (device) => { - const { history, mostRecentOverviewPage, unlockHardwareWalletAccount } = this.props + const { + history, + mostRecentOverviewPage, + unlockHardwareWalletAccount, + } = this.props if (this.state.selectedAccount === null) { this.setState({ error: this.context.t('accountSelectionRequired') }) @@ -153,7 +178,8 @@ class ConnectHardwareForm extends Component { }, }) history.push(mostRecentOverviewPage) - }).catch((e) => { + }) + .catch((e) => { this.context.metricsEvent({ eventOpts: { category: 'Accounts', @@ -173,13 +199,12 @@ class ConnectHardwareForm extends Component { history.push(mostRecentOverviewPage) } - renderError () { + renderError() { if (this.state.error === 'U2F') { return ( -

    - {this.context.t('troubleConnectingToWallet', [this.state.device, ( +

    + {this.context.t('troubleConnectingToWallet', [ + this.state.device, // eslint-disable-next-line react/jsx-key {this.context.t('walletConnectionGuide')} - - )])} + , + ])}

    ) } - return this.state.error - ? ( - - {this.state.error} - - ) - : null + return this.state.error ? ( + {this.state.error} + ) : null } - renderContent () { + renderContent() { if (!this.state.accounts.length) { return ( {this.renderError()} @@ -290,7 +311,9 @@ const mapDispatchToProps = (dispatch) => { return dispatch(actions.forgetDevice(deviceName)) }, unlockHardwareWalletAccount: (index, deviceName, hdPath) => { - return dispatch(actions.unlockHardwareWalletAccount(index, deviceName, hdPath)) + return dispatch( + actions.unlockHardwareWalletAccount(index, deviceName, hdPath), + ) }, showAlert: (msg) => dispatch(actions.showAlert(msg)), hideAlert: () => dispatch(actions.hideAlert()), @@ -302,6 +325,4 @@ ConnectHardwareForm.contextTypes = { metricsEvent: PropTypes.func, } -export default connect(mapStateToProps, mapDispatchToProps)( - ConnectHardwareForm, -) +export default connect(mapStateToProps, mapDispatchToProps)(ConnectHardwareForm) diff --git a/ui/app/pages/create-account/connect-hardware/select-hardware.js b/ui/app/pages/create-account/connect-hardware/select-hardware.js index 02c26c95e..f8dd18211 100644 --- a/ui/app/pages/create-account/connect-hardware/select-hardware.js +++ b/ui/app/pages/create-account/connect-hardware/select-hardware.js @@ -24,11 +24,11 @@ export default class SelectHardware extends Component { return null } - renderConnectToTrezorButton () { + renderConnectToTrezorButton() { return ( @@ -98,23 +104,29 @@ export default class SelectHardware extends Component { ) } - renderHeader () { + renderHeader() { return (
    -

    {this.context.t('hardwareWallets')}

    -

    {this.context.t('hardwareWalletsMsg')}

    +

    + {this.context.t('hardwareWallets')} +

    +

    + {this.context.t('hardwareWalletsMsg')} +

    ) } - getAffiliateLinks () { + getAffiliateLinks() { const links = { trezor: `Trezor`, ledger: `Ledger`, } const text = this.context.t('orderOneHere') - const response = text.replace('Trezor', links.trezor).replace('Ledger', links.ledger) + const response = text + .replace('Trezor', links.trezor) + .replace('Ledger', links.ledger) return (
    -

    {this.context.t('dontHaveAHardwareWallet')}

    +

    + {this.context.t('dontHaveAHardwareWallet')} +

    {this.getAffiliateLinks()}
    ) @@ -139,16 +153,20 @@ export default class SelectHardware extends Component { } } - renderLearnMore () { + renderLearnMore() { return (

    {this.context.t('learnMore')} - +

    ) } - renderTutorialSteps () { + renderTutorialSteps() { const steps = [ { asset: 'hardware-wallet-step-1', @@ -181,21 +199,33 @@ export default class SelectHardware extends Component {

    {step.title}

    {step.message}

    - +
    ))}
    ) } - renderFooter () { + renderFooter() { return (
    -

    {this.context.t('readyToConnect')}

    +

    + {this.context.t('readyToConnect')} +

    {this.renderButtons()}

    {this.context.t('havingTroubleConnecting')} - + {this.context.t('getHelp')}

    @@ -203,7 +233,7 @@ export default class SelectHardware extends Component { ) } - renderConnectScreen () { + renderConnectScreen() { return (
    {this.renderHeader()} @@ -216,7 +246,7 @@ export default class SelectHardware extends Component { ) } - render () { + render() { if (this.props.browserSupported) { return this.renderConnectScreen() } diff --git a/ui/app/pages/create-account/create-account.component.js b/ui/app/pages/create-account/create-account.component.js index 2ff859144..1ec2e5258 100644 --- a/ui/app/pages/create-account/create-account.component.js +++ b/ui/app/pages/create-account/create-account.component.js @@ -12,35 +12,50 @@ import NewAccountImportForm from './import-account' import ConnectHardwareForm from './connect-hardware' export default class CreateAccountPage extends Component { - renderTabs () { - const { history, location: { pathname } } = this.props - const getClassNames = (path) => classnames('new-account__tabs__tab', { - 'new-account__tabs__selected': matchPath(pathname, { - path, - exact: true, - }), - }) + renderTabs() { + const { + history, + location: { pathname }, + } = this.props + const getClassNames = (path) => + classnames('new-account__tabs__tab', { + 'new-account__tabs__selected': matchPath(pathname, { + path, + exact: true, + }), + }) return (
    -
    history.push(NEW_ACCOUNT_ROUTE)}> +
    history.push(NEW_ACCOUNT_ROUTE)} + > {this.context.t('create')}
    -
    history.push(IMPORT_ACCOUNT_ROUTE)}> +
    history.push(IMPORT_ACCOUNT_ROUTE)} + > {this.context.t('import')}
    -
    history.push(CONNECT_HARDWARE_ROUTE)}> +
    history.push(CONNECT_HARDWARE_ROUTE)} + > {this.context.t('hardware')}
    ) } - render () { + render() { return (
    -
    +
    {this.renderTabs()}
    diff --git a/ui/app/pages/create-account/import-account/index.js b/ui/app/pages/create-account/import-account/index.js index dee390024..0b7e45cf9 100644 --- a/ui/app/pages/create-account/import-account/index.js +++ b/ui/app/pages/create-account/import-account/index.js @@ -13,14 +13,11 @@ export default class AccountImportSubview extends Component { state = {} - getMenuItemTexts () { - return [ - this.context.t('privateKey'), - this.context.t('jsonFile'), - ] + getMenuItemTexts() { + return [this.context.t('privateKey'), this.context.t('jsonFile')] } - renderImportView () { + renderImportView() { const { type } = this.state const menuItems = this.getMenuItemTexts() const current = type || menuItems[0] @@ -35,7 +32,7 @@ export default class AccountImportSubview extends Component { } } - render () { + render() { const menuItems = this.getMenuItemTexts() const { type } = this.state @@ -50,7 +47,8 @@ export default class AccountImportSubview extends Component { }} onClick={() => { global.platform.openTab({ - url: 'https://metamask.zendesk.com/hc/en-us/articles/360015289932', + url: + 'https://metamask.zendesk.com/hc/en-us/articles/360015289932', }) }} > diff --git a/ui/app/pages/create-account/import-account/json.js b/ui/app/pages/create-account/import-account/json.js index 1edaed355..34eadaf84 100644 --- a/ui/app/pages/create-account/import-account/json.js +++ b/ui/app/pages/create-account/import-account/json.js @@ -9,7 +9,8 @@ import { getMetaMaskAccounts } from '../../../selectors' import Button from '../../../components/ui/button' import { getMostRecentOverviewPage } from '../../../ducks/history/history' -const HELP_LINK = 'https://metamask.zendesk.com/hc/en-us/articles/360015489331-Importing-an-Account' +const HELP_LINK = + 'https://metamask.zendesk.com/hc/en-us/articles/360015489331-Importing-an-Account' class JsonImportSubview extends Component { state = { @@ -19,14 +20,21 @@ class JsonImportSubview extends Component { inputRef = React.createRef() - render () { + render() { const { error, history, mostRecentOverviewPage } = this.props const enabled = !this.state.isEmpty && this.state.fileContents !== '' return ( - { - error - ? {error} - : null - } + {error ? {error} : null}
    ) } - onLoad (event) { + onLoad(event) { this.setState({ fileContents: event.target.result, }) } - createKeyringOnEnter (event) { + createKeyringOnEnter(event) { if (event.key === 'Enter') { event.preventDefault() this.createNewKeychain() } } - createNewKeychain () { + createNewKeychain() { const { firstAddress, displayWarning, @@ -134,7 +138,7 @@ class JsonImportSubview extends Component { .catch((err) => err && displayWarning(err.message || err)) } - checkInputEmpty () { + checkInputEmpty() { const password = this.inputRef.current.value let isEmpty = true if (password !== '') { @@ -165,8 +169,10 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { displayWarning: (warning) => dispatch(actions.displayWarning(warning)), - importNewJsonAccount: (options) => dispatch(actions.importNewAccount('JSON File', options)), - setSelectedAddress: (address) => dispatch(actions.setSelectedAddress(address)), + importNewJsonAccount: (options) => + dispatch(actions.importNewAccount('JSON File', options)), + setSelectedAddress: (address) => + dispatch(actions.setSelectedAddress(address)), } } diff --git a/ui/app/pages/create-account/import-account/private-key.js b/ui/app/pages/create-account/import-account/private-key.js index d3c4240f8..e2f78ada4 100644 --- a/ui/app/pages/create-account/import-account/private-key.js +++ b/ui/app/pages/create-account/import-account/private-key.js @@ -28,9 +28,16 @@ class PrivateKeyImportView extends Component { state = { isEmpty: true } - createNewKeychain () { + createNewKeychain() { const privateKey = this.inputRef.current.value - const { importNewAccount, history, displayWarning, mostRecentOverviewPage, setSelectedAddress, firstAddress } = this.props + const { + importNewAccount, + history, + displayWarning, + mostRecentOverviewPage, + setSelectedAddress, + firstAddress, + } = this.props importNewAccount('Private Key', [privateKey]) .then(({ selectedAddress }) => { @@ -66,7 +73,7 @@ class PrivateKeyImportView extends Component { } } - checkInputEmpty () { + checkInputEmpty() { const privateKey = this.inputRef.current.value let isEmpty = true if (privateKey !== '') { @@ -75,7 +82,7 @@ class PrivateKeyImportView extends Component { this.setState({ isEmpty }) } - render () { + render() { const { error, displayWarning } = this.props return ( @@ -117,11 +124,7 @@ class PrivateKeyImportView extends Component { {this.context.t('import')}
    - { - error - ? {error} - : null - } + {error ? {error} : null}
    ) } @@ -132,7 +135,7 @@ export default compose( connect(mapStateToProps, mapDispatchToProps), )(PrivateKeyImportView) -function mapStateToProps (state) { +function mapStateToProps(state) { return { error: state.appState.warning, firstAddress: Object.keys(getMetaMaskAccounts(state))[0], @@ -140,12 +143,14 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps(dispatch) { return { importNewAccount: (strategy, [privateKey]) => { return dispatch(actions.importNewAccount(strategy, [privateKey])) }, - displayWarning: (message) => dispatch(actions.displayWarning(message || null)), - setSelectedAddress: (address) => dispatch(actions.setSelectedAddress(address)), + displayWarning: (message) => + dispatch(actions.displayWarning(message || null)), + setSelectedAddress: (address) => + dispatch(actions.setSelectedAddress(address)), } } diff --git a/ui/app/pages/create-account/new-account.component.js b/ui/app/pages/create-account/new-account.component.js index 9995b28ab..92f832a23 100644 --- a/ui/app/pages/create-account/new-account.component.js +++ b/ui/app/pages/create-account/new-account.component.js @@ -14,7 +14,7 @@ export default class NewAccountCreateForm extends Component { ]), } - render () { + render() { const { newAccountName, defaultAccountName } = this.state const { history, createAccount, mostRecentOverviewPage } = this.props const createClick = (_) => { @@ -53,7 +53,9 @@ export default class NewAccountCreateForm extends Component { className="new-account-create-form__input" value={newAccountName} placeholder={defaultAccountName} - onChange={(event) => this.setState({ newAccountName: event.target.value })} + onChange={(event) => + this.setState({ newAccountName: event.target.value }) + } autoFocus />
    diff --git a/ui/app/pages/create-account/new-account.container.js b/ui/app/pages/create-account/new-account.container.js index 16fffe959..833d7143c 100644 --- a/ui/app/pages/create-account/new-account.container.js +++ b/ui/app/pages/create-account/new-account.container.js @@ -4,7 +4,9 @@ import { getMostRecentOverviewPage } from '../../ducks/history/history' import NewAccountCreateForm from './new-account.component' const mapStateToProps = (state) => { - const { metamask: { identities = {} } } = state + const { + metamask: { identities = {} }, + } = state const numberOfExistingAccounts = Object.keys(identities).length const newAccountNumber = numberOfExistingAccounts + 1 @@ -17,14 +19,16 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { createAccount: (newAccountName) => { - return dispatch(actions.addNewAccount()) - .then((newAccountAddress) => { - if (newAccountName) { - dispatch(actions.setAccountLabel(newAccountAddress, newAccountName)) - } - }) + return dispatch(actions.addNewAccount()).then((newAccountAddress) => { + if (newAccountName) { + dispatch(actions.setAccountLabel(newAccountAddress, newAccountName)) + } + }) }, } } -export default connect(mapStateToProps, mapDispatchToProps)(NewAccountCreateForm) +export default connect( + mapStateToProps, + mapDispatchToProps, +)(NewAccountCreateForm) diff --git a/ui/app/pages/create-account/tests/create-account.test.js b/ui/app/pages/create-account/tests/create-account.test.js index f41aa2796..a99ffa47f 100644 --- a/ui/app/pages/create-account/tests/create-account.test.js +++ b/ui/app/pages/create-account/tests/create-account.test.js @@ -17,9 +17,7 @@ describe('Create Account Page', function () { } before(function () { - wrapper = mountWithRouter( - , - ) + wrapper = mountWithRouter() }) afterEach(function () { diff --git a/ui/app/pages/error/error.component.js b/ui/app/pages/error/error.component.js index 1da1ac609..d3fe6f756 100644 --- a/ui/app/pages/error/error.component.js +++ b/ui/app/pages/error/error.component.js @@ -12,30 +12,24 @@ class ErrorPage extends PureComponent { error: PropTypes.object.isRequired, } - renderErrorDetail (content) { + renderErrorDetail(content) { return (
  • -

    - {content} -

    +

    {content}

  • ) } - renderErrorStack (title, stack) { + renderErrorStack(title, stack) { return (
  • - - {title} - -
    -          {stack}
    -        
    + {title} +
    {stack}
  • ) } - render () { + render() { const { error } = this.props const { t } = this.context @@ -43,26 +37,26 @@ class ErrorPage extends PureComponent { return (
    -

    - {t('errorPageTitle')} -

    +

    {t('errorPageTitle')}

    - { - isPopup - ? t('errorPagePopupMessage') - : t('errorPageMessage') - } + {isPopup ? t('errorPagePopupMessage') : t('errorPageMessage')}

    - - {t('errorDetails')} - + {t('errorDetails')}
      - { error.message ? this.renderErrorDetail(t('errorMessage', [error.message])) : null } - { error.code ? this.renderErrorDetail(t('errorCode', [error.code])) : null } - { error.name ? this.renderErrorDetail(t('errorName', [error.name])) : null } - { error.stack ? this.renderErrorStack(t('errorStack'), error.stack) : null } + {error.message + ? this.renderErrorDetail(t('errorMessage', [error.message])) + : null} + {error.code + ? this.renderErrorDetail(t('errorCode', [error.code])) + : null} + {error.name + ? this.renderErrorDetail(t('errorName', [error.name])) + : null} + {error.stack + ? this.renderErrorStack(t('errorStack'), error.stack) + : null}
    diff --git a/ui/app/pages/first-time-flow/create-password/create-password.component.js b/ui/app/pages/first-time-flow/create-password/create-password.component.js index a159601da..b249c3aba 100644 --- a/ui/app/pages/first-time-flow/create-password/create-password.component.js +++ b/ui/app/pages/first-time-flow/create-password/create-password.component.js @@ -18,7 +18,7 @@ export default class CreatePassword extends PureComponent { onCreateNewAccountFromSeed: PropTypes.func, } - componentDidMount () { + componentDidMount() { const { isInitialized, history } = this.props if (isInitialized) { @@ -26,7 +26,7 @@ export default class CreatePassword extends PureComponent { } } - render () { + render() { const { onCreateNewAccount, onCreateNewAccountFromSeed } = this.props return ( @@ -38,7 +38,7 @@ export default class CreatePassword extends PureComponent { path={INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE} render={(routeProps) => ( )} @@ -47,10 +47,7 @@ export default class CreatePassword extends PureComponent { exact path={INITIALIZE_CREATE_PASSWORD_ROUTE} render={(routeProps) => ( - + )} /> diff --git a/ui/app/pages/first-time-flow/create-password/create-password.container.js b/ui/app/pages/first-time-flow/create-password/create-password.container.js index 728764d6c..9e8d12870 100644 --- a/ui/app/pages/first-time-flow/create-password/create-password.container.js +++ b/ui/app/pages/first-time-flow/create-password/create-password.container.js @@ -2,7 +2,9 @@ import { connect } from 'react-redux' import CreatePassword from './create-password.component' const mapStateToProps = (state) => { - const { metamask: { isInitialized } } = state + const { + metamask: { isInitialized }, + } = state return { isInitialized, diff --git a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js index bc12fe782..1e17e8f08 100644 --- a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js +++ b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js @@ -35,28 +35,30 @@ export default class ImportWithSeedPhrase extends PureComponent { termsChecked: false, } - parseSeedPhrase = (seedPhrase) => (seedPhrase || '').trim().toLowerCase().match(/\w+/gu)?.join(' ') || '' + parseSeedPhrase = (seedPhrase) => + (seedPhrase || '').trim().toLowerCase().match(/\w+/gu)?.join(' ') || '' - UNSAFE_componentWillMount () { - this._onBeforeUnload = () => this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Import Seed Phrase', - name: 'Close window on import screen', - }, - customVariables: { - errorLabel: 'Seed Phrase Error', - errorMessage: this.state.seedPhraseError, - }, - }) + UNSAFE_componentWillMount() { + this._onBeforeUnload = () => + this.context.metricsEvent({ + eventOpts: { + category: 'Onboarding', + action: 'Import Seed Phrase', + name: 'Close window on import screen', + }, + customVariables: { + errorLabel: 'Seed Phrase Error', + errorMessage: this.state.seedPhraseError, + }, + }) window.addEventListener('beforeunload', this._onBeforeUnload) } - componentWillUnmount () { + componentWillUnmount() { window.removeEventListener('beforeunload', this._onBeforeUnload) } - handleSeedPhraseChange (seedPhrase) { + handleSeedPhraseChange(seedPhrase) { let seedPhraseError = '' if (seedPhrase) { @@ -72,7 +74,7 @@ export default class ImportWithSeedPhrase extends PureComponent { this.setState({ seedPhrase, seedPhraseError }) } - handlePasswordChange (password) { + handlePasswordChange(password) { const { t } = this.context this.setState((state) => { @@ -96,7 +98,7 @@ export default class ImportWithSeedPhrase extends PureComponent { }) } - handleConfirmPasswordChange (confirmPassword) { + handleConfirmPasswordChange(confirmPassword) { const { t } = this.context this.setState((state) => { @@ -122,7 +124,13 @@ export default class ImportWithSeedPhrase extends PureComponent { } const { password, seedPhrase } = this.state - const { history, onSubmit, setSeedPhraseBackedUp, initializeThreeBox, completeOnboarding } = this.props + const { + history, + onSubmit, + setSeedPhraseBackedUp, + initializeThreeBox, + completeOnboarding, + } = this.props try { await onSubmit(password, this.parseSeedPhrase(seedPhrase)) @@ -144,7 +152,7 @@ export default class ImportWithSeedPhrase extends PureComponent { } } - isValid () { + isValid() { const { seedPhrase, password, @@ -154,7 +162,12 @@ export default class ImportWithSeedPhrase extends PureComponent { seedPhraseError, } = this.state - if (!password || !confirmPassword || !seedPhrase || password !== confirmPassword) { + if ( + !password || + !confirmPassword || + !seedPhrase || + password !== confirmPassword + ) { return false } @@ -190,15 +203,18 @@ export default class ImportWithSeedPhrase extends PureComponent { })) } - render () { + render() { const { t } = this.context - const { seedPhraseError, showSeedPhrase, passwordError, confirmPasswordError, termsChecked } = this.state + const { + seedPhraseError, + showSeedPhrase, + passwordError, + confirmPasswordError, + termsChecked, + } = this.state return ( -
    +
    - { t('importAccountSeedPhrase') } -
    -
    - { t('secretPhrase') } + {t('importAccountSeedPhrase')}
    +
    {t('secretPhrase')}
    - + {showSeedPhrase ? (