From 476274474f5fc709b176f481d66865f190e14a52 Mon Sep 17 00:00:00 2001 From: ricky Date: Tue, 19 Nov 2019 10:46:10 -0500 Subject: [PATCH 01/88] Add shellcheck lint (#7392) * Add shellcheck lint script * Add to build * Add shellcheck lint to main lint task * Put shellcheck in the right place, hopefully? * Fix declared multiple executor types * Add sudo * Address shellcheck warnings * Add test-lint-shellcheck * Add test-lint-shellcheck to workflow * Use correct lint task * output version which could be helpful for debugging * Address PR feedback * consistency++ --- .circleci/config.yml | 12 ++++++++++++ development/auto-changelog.sh | 2 +- development/rollback.sh | 14 +++++++------- package.json | 1 + 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index af3b70ebbeb6..5270da98f100 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,6 +22,7 @@ workflows: - test-lint: requires: - prep-deps + - test-lint-shellcheck - test-e2e-chrome: requires: - prep-deps @@ -49,6 +50,7 @@ workflows: - all-tests-pass: requires: - test-lint + - test-lint-shellcheck - test-unit - test-unit-global - test-mozilla-lint @@ -173,6 +175,16 @@ jobs: name: Verify locales command: yarn verify-locales --quiet + test-lint-shellcheck: + docker: + - image: circleci/node:10.17-browsers + steps: + - checkout + - run: sudo apt-get install shellcheck + - run: + name: Shellcheck Lint + command: yarn lint:shellcheck + test-deps: docker: - image: circleci/node:10.17-browsers diff --git a/development/auto-changelog.sh b/development/auto-changelog.sh index 3ed059b3d783..26ab8e93f72a 100755 --- a/development/auto-changelog.sh +++ b/development/auto-changelog.sh @@ -10,7 +10,7 @@ git fetch --tags most_recent_tag="$(git describe --tags "$(git rev-list --tags --max-count=1)")" -git rev-list "${most_recent_tag}"..HEAD | while read commit +git rev-list "${most_recent_tag}"..HEAD | while read -r commit do subject="$(git show -s --format="%s" "$commit")" diff --git a/development/rollback.sh b/development/rollback.sh index 639d72a6751c..a3040e6f1192 100755 --- a/development/rollback.sh +++ b/development/rollback.sh @@ -4,20 +4,20 @@ echo "Rolling back to version $1" # Checkout branch to increment version -git checkout -b version-increment-$1 +git checkout -b "version-increment-$1" yarn version:bump patch # Store the new version name -NEW_VERSION=$(cat app/manifest.json | jq -r .version) +NEW_VERSION=$(jq -r .version < app/manifest.json) # Make sure origin tags are loaded git fetch origin # check out the rollback branch -git checkout origin/v$1 +git checkout "origin/v$1" # Create the rollback branch. -git checkout -b Version-$NEW_VERSION-Rollback-to-$1 +git checkout -b "Version-$NEW_VERSION-Rollback-to-$1" # Set the version files to the next one. git checkout master CHANGELOG.md @@ -28,8 +28,8 @@ git commit -m "Version $NEW_VERSION (Rollback to $1)" git push -u origin HEAD # Create tag and push that up too -git tag v${NEW_VERSION} -git push origin v${NEW_VERSION} +git tag "v${NEW_VERSION}" +git push origin "v${NEW_VERSION}" # Cleanup version branch -git branch -D version-increment-$1 +git branch -D "version-increment-$1" diff --git a/package.json b/package.json index 73659d90970c..49b38bc0d90e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "lint:fix": "eslint . --ext js,json --fix", "lint:changed": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' --regexp='[.]json$' | tr '\\n' '\\0' | xargs -0 eslint", "lint:changed:fix": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' --regexp='[.]json$' | tr '\\n' '\\0' | xargs -0 eslint --fix", + "lint:shellcheck": "shellcheck --version && find . -type f -name '*.sh' ! -path './node_modules/*' -print0 | xargs -0 shellcheck", "verify-locales": "node ./development/verify-locale-strings.js", "mozilla-lint": "addons-linter dist/firefox", "watch": "cross-env METAMASK_ENV=test mocha --watch --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/app/**/*.test.js\"", From aa41057628a812cfa3d330fd36684ca17ab2852d Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 19 Nov 2019 20:33:20 -0330 Subject: [PATCH 02/88] Update ESLint rules for curly braces style (#7477) * eslint: Enable curly and brace-style * yarn lint --fix --- .eslintrc | 4 +- app/scripts/background.js | 4 +- app/scripts/contentscript.js | 12 +++-- app/scripts/controllers/detect-tokens.js | 42 ++++++++++++---- .../controllers/incoming-transactions.js | 4 +- .../controllers/network/middleware/pending.js | 16 +++++-- app/scripts/controllers/network/network.js | 4 +- app/scripts/controllers/preferences.js | 48 ++++++++++++++----- app/scripts/controllers/provider-approval.js | 4 +- app/scripts/controllers/recent-blocks.js | 8 +++- app/scripts/controllers/threebox.js | 4 +- app/scripts/controllers/token-rates.js | 20 ++++++-- app/scripts/controllers/transactions/index.js | 16 +++++-- .../lib/tx-state-history-helper.js | 8 +++- .../controllers/transactions/lib/util.js | 12 +++-- .../transactions/pending-tx-tracker.js | 20 ++++++-- .../controllers/transactions/tx-gas-utils.js | 8 +++- .../transactions/tx-state-manager.js | 24 +++++++--- app/scripts/lib/account-tracker.js | 12 +++-- app/scripts/lib/auto-reload.js | 16 +++++-- app/scripts/lib/buy-eth-url.js | 4 +- app/scripts/lib/createDnodeRemoteGetter.js | 4 +- app/scripts/lib/createLoggerMiddleware.js | 4 +- app/scripts/lib/ens-ipfs/setup.js | 12 +++-- app/scripts/lib/local-store.js | 12 +++-- app/scripts/lib/message-manager.js | 12 +++-- app/scripts/lib/migrator/index.js | 8 +++- app/scripts/lib/nodeify.js | 6 ++- app/scripts/lib/notification-manager.js | 20 ++++++-- app/scripts/lib/pending-balance-calculator.js | 4 +- app/scripts/lib/personal-message-manager.js | 12 +++-- app/scripts/lib/setupFetchDebugging.js | 4 +- app/scripts/lib/setupMetamaskMeshMetrics.js | 4 +- app/scripts/lib/setupSentry.js | 12 +++-- app/scripts/lib/stream-utils.js | 4 +- app/scripts/lib/typed-message-manager.js | 16 +++++-- app/scripts/metamask-controller.js | 28 ++++++++--- app/scripts/migrations/004.js | 4 +- app/scripts/migrations/015.js | 7 ++- app/scripts/migrations/016.js | 4 +- app/scripts/migrations/017.js | 4 +- app/scripts/migrations/019.js | 4 +- app/scripts/migrations/022.js | 4 +- app/scripts/migrations/023.js | 11 +++-- app/scripts/migrations/024.js | 4 +- app/scripts/migrations/025.js | 8 +++- development/mock-3box.js | 4 +- development/show-deps-install-scripts.js | 20 ++++++-- development/sourcemap-validator.js | 8 +++- gulpfile.js | 4 +- test/helper.js | 12 +++-- test/integration/index.js | 4 +- test/lib/mock-simple-keychain.js | 4 +- test/lib/util.js | 8 +++- test/setup.js | 8 +++- test/unit/actions/tx_test.js | 12 +++-- .../controllers/metamask-controller-test.js | 24 +++++++--- .../network/pending-middleware-test.js | 8 +++- .../preferences-controller-test.js | 32 +++++++++---- .../transactions/pending-tx-test.js | 36 ++++++++++---- .../transactions/tx-controller-test.js | 41 +++++++++++----- .../tx-state-history-helper-test.js | 4 +- .../controllers/transactions/tx-utils-test.js | 20 ++++++-- test/unit/app/nodeify-test.js | 16 +++++-- test/unit/migrations/023-test.js | 4 +- test/unit/migrations/024-test.js | 7 ++- test/unit/migrations/025-test.js | 8 +++- test/unit/migrations/027-test.js | 4 +- test/unit/migrations/029-test.js | 4 +- test/unit/migrations/migrator-test.js | 4 +- test/unit/test-utils.js | 4 +- test/unit/util_test.js | 4 +- .../app/dropdowns/components/menu.js | 16 +++++-- .../app/dropdowns/network-dropdown.js | 4 +- .../gas-price-chart/gas-price-chart.utils.js | 4 +- ui/app/components/app/input-number.js | 4 +- ui/app/components/app/token-list.js | 12 +++-- ui/app/components/ui/eth-balance.js | 8 +++- ui/app/components/ui/fiat-value.js | 4 +- ui/app/components/ui/mascot.js | 4 +- .../ui/unit-input/unit-input.component.js | 4 +- ui/app/ducks/index.js | 4 +- ui/app/helpers/utils/util.js | 40 ++++++++++++---- .../confirm-transaction.component.js | 4 +- .../connect-hardware/connect-screen.js | 8 +++- ui/app/pages/mobile-sync/index.js | 4 +- ui/app/pages/routes/index.js | 4 +- .../add-recipient/ens-input.component.js | 12 +++-- ui/app/pages/send/send.component.js | 4 +- ui/app/pages/send/send.utils.js | 12 +++-- ui/app/pages/send/tests/send-utils.test.js | 8 +++- .../add-contact/add-contact.component.js | 4 +- ui/app/store/actions.js | 20 ++++++-- ui/index.js | 8 +++- 94 files changed, 747 insertions(+), 251 deletions(-) diff --git a/.eslintrc b/.eslintrc index 08d8aeb9da0a..159fee387d18 100644 --- a/.eslintrc +++ b/.eslintrc @@ -49,13 +49,13 @@ "accessor-pairs": 2, "arrow-spacing": [2, { "before": true, "after": true }], "block-spacing": [2, "always"], - "brace-style": [2, "1tbs", { "allowSingleLine": true }], + "brace-style": 2, "camelcase": [2, { "properties": "never" }], "comma-dangle": [2, "always-multiline"], "comma-spacing": [2, { "before": false, "after": true }], "comma-style": [2, "last"], "constructor-super": 2, - "curly": [2, "multi-line"], + "curly": 2, "dot-location": [2, "property"], "eol-last": 2, "eqeqeq": [2, "allow-null"], diff --git a/app/scripts/background.js b/app/scripts/background.js index 2639d770387f..b26a87ba2779 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -260,7 +260,9 @@ function setupController (initState, initLangCode) { // report failed transactions to Sentry controller.txController.on(`tx:status-update`, (txId, status) => { - if (status !== 'failed') return + if (status !== 'failed') { + return + } const txMeta = controller.txController.txStateManager.getTx(txId) try { reportFailedTxToSentry({ sentry, txMeta }) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index db4d5fd63ab7..4a84cb64b40b 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -123,7 +123,9 @@ async function setupPublicApi (outStream) { outStream, (err) => { // report any error - if (err) log.error(err) + if (err) { + log.error(err) + } } ) const background = await new Promise(resolve => dnode.once('remote', resolve)) @@ -151,7 +153,9 @@ function getSiteMetadata () { */ function logStreamDisconnectWarning (remoteLabel, err) { let warningMsg = `MetamaskContentscript - lost connection to ${remoteLabel}` - if (err) warningMsg += '\n' + err.stack + if (err) { + warningMsg += '\n' + err.stack + } console.warn(warningMsg) } @@ -302,7 +306,9 @@ function getSiteIcon (window) { */ async function domIsReady () { // already loaded - if (['interactive', 'complete'].includes(document.readyState)) return + if (['interactive', 'complete'].includes(document.readyState)) { + return + } // wait for load await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve, { once: true })) } diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index e6e99307357d..923aa2d15f8a 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -29,8 +29,12 @@ class DetectTokensController { * */ async detectNewTokens () { - if (!this.isActive) { return } - if (this._network.store.getState().provider.type !== MAINNET) { return } + if (!this.isActive) { + return + } + if (this._network.store.getState().provider.type !== MAINNET) { + return + } const tokensToDetect = [] this.web3.setProvider(this._network._provider) for (const contractAddress in contracts) { @@ -80,7 +84,9 @@ class DetectTokensController { * */ restartTokenDetection () { - if (!(this.isActive && this.selectedAddress)) { return } + if (!(this.isActive && this.selectedAddress)) { + return + } this.detectNewTokens() this.interval = DEFAULT_INTERVAL } @@ -90,8 +96,12 @@ class DetectTokensController { */ set interval (interval) { this._handle && clearInterval(this._handle) - if (!interval) { return } - this._handle = setInterval(() => { this.detectNewTokens() }, interval) + if (!interval) { + return + } + this._handle = setInterval(() => { + this.detectNewTokens() + }, interval) } /** @@ -99,9 +109,15 @@ class DetectTokensController { * @type {Object} */ set preferences (preferences) { - if (!preferences) { return } + if (!preferences) { + return + } this._preferences = preferences - preferences.store.subscribe(({ tokens = [] }) => { this.tokenAddresses = tokens.map((obj) => { return obj.address }) }) + preferences.store.subscribe(({ tokens = [] }) => { + this.tokenAddresses = tokens.map((obj) => { + return obj.address + }) + }) preferences.store.subscribe(({ selectedAddress }) => { if (this.selectedAddress !== selectedAddress) { this.selectedAddress = selectedAddress @@ -114,7 +130,9 @@ class DetectTokensController { * @type {Object} */ set network (network) { - if (!network) { return } + if (!network) { + return + } this._network = network this.web3 = new Web3(network._provider) } @@ -124,12 +142,16 @@ class DetectTokensController { * @type {Object} */ set keyringMemStore (keyringMemStore) { - if (!keyringMemStore) { return } + if (!keyringMemStore) { + return + } this._keyringMemStore = keyringMemStore this._keyringMemStore.subscribe(({ isUnlocked }) => { if (this.isUnlocked !== isUnlocked) { this.isUnlocked = isUnlocked - if (isUnlocked) { this.restartTokenDetection() } + if (isUnlocked) { + this.restartTokenDetection() + } } }) } diff --git a/app/scripts/controllers/incoming-transactions.js b/app/scripts/controllers/incoming-transactions.js index 029bf47aa5ab..10735b3f9248 100644 --- a/app/scripts/controllers/incoming-transactions.js +++ b/app/scripts/controllers/incoming-transactions.js @@ -163,7 +163,9 @@ class IncomingTransactionsController { const newIncomingTransactions = { ...currentIncomingTxs, } - newTxs.forEach(tx => { newIncomingTransactions[tx.hash] = tx }) + newTxs.forEach(tx => { + newIncomingTransactions[tx.hash] = tx + }) this.store.updateState({ incomingTxLastFetchedBlocksByNetwork: { diff --git a/app/scripts/controllers/network/middleware/pending.js b/app/scripts/controllers/network/middleware/pending.js index 542d8bde6f72..96a5d40be81e 100644 --- a/app/scripts/controllers/network/middleware/pending.js +++ b/app/scripts/controllers/network/middleware/pending.js @@ -4,9 +4,13 @@ const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware function createPendingNonceMiddleware ({ getPendingNonce }) { return createAsyncMiddleware(async (req, res, next) => { const {method, params} = req - if (method !== 'eth_getTransactionCount') return next() + if (method !== 'eth_getTransactionCount') { + return next() + } const [param, blockRef] = params - if (blockRef !== 'pending') return next() + if (blockRef !== 'pending') { + return next() + } res.result = await getPendingNonce(param) }) } @@ -14,10 +18,14 @@ function createPendingNonceMiddleware ({ getPendingNonce }) { function createPendingTxMiddleware ({ getPendingTransactionByHash }) { return createAsyncMiddleware(async (req, res, next) => { const {method, params} = req - if (method !== 'eth_getTransactionByHash') return next() + if (method !== 'eth_getTransactionByHash') { + return next() + } const [hash] = params const txMeta = getPendingTransactionByHash(hash) - if (!txMeta) return next() + if (!txMeta) { + return next() + } res.result = formatTxMetaForRpcResult(txMeta) }) } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 7b5d8ef383fe..f1be914bb545 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -81,7 +81,9 @@ module.exports = class NetworkController extends EventEmitter { verifyNetwork () { // Check network when restoring connectivity: - if (this.isNetworkLoading()) this.lookupNetwork() + if (this.isNetworkLoading()) { + this.lookupNetwork() + } } getNetworkState () { diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 1cfbb4d4c289..22c6e999db19 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -303,7 +303,9 @@ class PreferencesController { const accountTokens = this.store.getState().accountTokens addresses.forEach((address) => { // skip if already exists - if (identities[address]) return + if (identities[address]) { + return + } // add missing identity const identityCount = Object.keys(identities).length @@ -335,7 +337,9 @@ class PreferencesController { if (Object.keys(newlyLost).length > 0) { // Notify our servers: - if (this.diagnostics) this.diagnostics.reportOrphans(newlyLost) + if (this.diagnostics) { + this.diagnostics.reportOrphans(newlyLost) + } // store lost accounts for (const key in newlyLost) { @@ -463,7 +467,9 @@ class PreferencesController { * @return {Promise} */ setAccountLabel (account, label) { - if (!account) throw new Error('setAccountLabel requires a valid address, got ' + String(account)) + if (!account) { + throw new Error('setAccountLabel requires a valid address, got ' + String(account)) + } const address = normalizeAddress(account) const {identities} = this.store.getState() identities[address] = identities[address] || {} @@ -500,7 +506,9 @@ class PreferencesController { updateRpc (newRpcDetails) { const rpcList = this.getFrequentRpcListDetail() - const index = rpcList.findIndex((element) => { return element.rpcUrl === newRpcDetails.rpcUrl }) + const index = rpcList.findIndex((element) => { + return element.rpcUrl === newRpcDetails.rpcUrl + }) if (index > -1) { const rpcDetail = rpcList[index] const updatedRpc = extend(rpcDetail, newRpcDetails) @@ -524,7 +532,9 @@ class PreferencesController { */ addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) { const rpcList = this.getFrequentRpcListDetail() - const index = rpcList.findIndex((element) => { return element.rpcUrl === url }) + const index = rpcList.findIndex((element) => { + return element.rpcUrl === url + }) if (index !== -1) { rpcList.splice(index, 1) } @@ -548,7 +558,9 @@ class PreferencesController { */ removeFromFrequentRpcList (url) { const rpcList = this.getFrequentRpcListDetail() - const index = rpcList.findIndex((element) => { return element.rpcUrl === url }) + const index = rpcList.findIndex((element) => { + return element.rpcUrl === url + }) if (index !== -1) { rpcList.splice(index, 1) } @@ -687,10 +699,16 @@ class PreferencesController { */ _getTokenRelatedStates (selectedAddress) { const accountTokens = this.store.getState().accountTokens - if (!selectedAddress) selectedAddress = this.store.getState().selectedAddress + if (!selectedAddress) { + selectedAddress = this.store.getState().selectedAddress + } const providerType = this.network.providerStore.getState().type - if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} - if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = [] + if (!(selectedAddress in accountTokens)) { + accountTokens[selectedAddress] = {} + } + if (!(providerType in accountTokens[selectedAddress])) { + accountTokens[selectedAddress][providerType] = [] + } const tokens = accountTokens[selectedAddress][providerType] return { tokens, accountTokens, providerType, selectedAddress } } @@ -727,13 +745,19 @@ class PreferencesController { */ _validateERC20AssetParams (opts) { const { rawAddress, symbol, decimals } = opts - if (!rawAddress || !symbol || typeof decimals === 'undefined') 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`) + if (!rawAddress || !symbol || typeof decimals === 'undefined') { + 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`) } - if (!isValidAddress(rawAddress)) throw new Error(`Invalid address ${rawAddress}`) + if (!isValidAddress(rawAddress)) { + throw new Error(`Invalid address ${rawAddress}`) + } } } diff --git a/app/scripts/controllers/provider-approval.js b/app/scripts/controllers/provider-approval.js index 00ff626f71a1..e54c7196f34a 100644 --- a/app/scripts/controllers/provider-approval.js +++ b/app/scripts/controllers/provider-approval.js @@ -34,7 +34,9 @@ class ProviderApprovalController extends SafeEventEmitter { createMiddleware ({ senderUrl, extensionId, getSiteMetadata }) { return createAsyncMiddleware(async (req, res, next) => { // only handle requestAccounts - if (req.method !== 'eth_requestAccounts') return next() + if (req.method !== 'eth_requestAccounts') { + return next() + } // if already approved or privacy mode disabled, return early const isUnlocked = this.keyringController.memStore.getState().isUnlocked const origin = senderUrl.hostname diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index a2b5d1bae6cf..9e5a384a9f3e 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -90,7 +90,9 @@ class RecentBlocksController { async processBlock (newBlockNumberHex) { const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) const newBlock = await this.getBlockByNumber(newBlockNumber, true) - if (!newBlock) return + if (!newBlock) { + return + } const block = this.mapTransactionsToPrices(newBlock) @@ -162,7 +164,9 @@ class RecentBlocksController { await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => { try { const newBlock = await this.getBlockByNumber(targetBlockNumber, true) - if (!newBlock) return + if (!newBlock) { + return + } this.backfillBlock(newBlock) } catch (e) { diff --git a/app/scripts/controllers/threebox.js b/app/scripts/controllers/threebox.js index 5bcab29ed453..8226fb6b1f84 100644 --- a/app/scripts/controllers/threebox.js +++ b/app/scripts/controllers/threebox.js @@ -28,7 +28,9 @@ class ThreeBoxController { this.provider = this._createProvider({ version, getAccounts: async ({ origin }) => { - if (origin !== '3Box') { return [] } + if (origin !== '3Box') { + return [] + } const isUnlocked = getKeyringControllerState().isUnlocked const accounts = await this.keyringController.getAccounts() diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js index 9b86a9ebf08c..7c8526c343b0 100644 --- a/app/scripts/controllers/token-rates.js +++ b/app/scripts/controllers/token-rates.js @@ -28,7 +28,9 @@ class TokenRatesController { * Updates exchange rates for all tokens */ async updateExchangeRates () { - if (!this.isActive) { return } + if (!this.isActive) { + return + } const contractExchangeRates = {} const nativeCurrency = this.currency ? this.currency.state.nativeCurrency.toLowerCase() : 'eth' const pairs = this._tokens.map(token => token.address).join(',') @@ -53,8 +55,12 @@ class TokenRatesController { */ set interval (interval) { this._handle && clearInterval(this._handle) - if (!interval) { return } - this._handle = setInterval(() => { this.updateExchangeRates() }, interval) + if (!interval) { + return + } + this._handle = setInterval(() => { + this.updateExchangeRates() + }, interval) } /** @@ -62,10 +68,14 @@ class TokenRatesController { */ set preferences (preferences) { this._preferences && this._preferences.unsubscribe() - if (!preferences) { return } + if (!preferences) { + return + } this._preferences = preferences this.tokens = preferences.getState().tokens - preferences.subscribe(({ tokens = [] }) => { this.tokens = tokens }) + preferences.subscribe(({ tokens = [] }) => { + this.tokens = tokens + }) } /** diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index df9fb6502392..f19dd53f7985 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -402,7 +402,9 @@ class TransactionController extends EventEmitter { log.error(err) } // must set transaction to submitted/failed before releasing lock - if (nonceLock) nonceLock.releaseLock() + if (nonceLock) { + nonceLock.releaseLock() + } // continue with error chain throw err } finally { @@ -603,7 +605,9 @@ class TransactionController extends EventEmitter { } }) this.pendingTxTracker.on('tx:retry', (txMeta) => { - if (!('retryCount' in txMeta)) txMeta.retryCount = 0 + if (!('retryCount' in txMeta)) { + txMeta.retryCount = 0 + } txMeta.retryCount++ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') }) @@ -657,10 +661,14 @@ class TransactionController extends EventEmitter { const txMeta = this.txStateManager.getTx(txId) const { nonce, from } = txMeta.txParams const sameNonceTxs = this.txStateManager.getFilteredTxList({nonce, from}) - if (!sameNonceTxs.length) return + if (!sameNonceTxs.length) { + return + } // mark all same nonce transactions as dropped and give i a replacedBy hash sameNonceTxs.forEach((otherTxMeta) => { - if (otherTxMeta.id === txId) return + if (otherTxMeta.id === txId) { + 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.setTxStatusDropped(otherTxMeta.id) diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js index 76fc5c35b394..3cc76e617951 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js @@ -18,7 +18,9 @@ function migrateFromSnapshotsToDiffs (longHistory) { longHistory // convert non-initial history entries into diffs .map((entry, index) => { - if (index === 0) return entry + if (index === 0) { + return entry + } return generateHistoryEntry(longHistory[index - 1], entry) }) ) @@ -40,7 +42,9 @@ 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]) { - if (note) entry[0].note = note + if (note) { + entry[0].note = note + } entry[0].timestamp = Date.now() } diff --git a/app/scripts/controllers/transactions/lib/util.js b/app/scripts/controllers/transactions/lib/util.js index 0d2ddddef923..86924e7fafa8 100644 --- a/app/scripts/controllers/transactions/lib/util.js +++ b/app/scripts/controllers/transactions/lib/util.js @@ -35,7 +35,9 @@ function normalizeTxParams (txParams, LowerCase) { // apply only keys in the normalizers const normalizedTxParams = {} for (const key in normalizers) { - if (txParams[key]) normalizedTxParams[key] = normalizers[key](txParams[key], LowerCase) + if (txParams[key]) { + normalizedTxParams[key] = normalizers[key](txParams[key], LowerCase) + } } return normalizedTxParams } @@ -64,8 +66,12 @@ function validateTxParams (txParams) { @param txParams {object} */ function validateFrom (txParams) { - if (!(typeof txParams.from === 'string')) throw new Error(`Invalid from address ${txParams.from} not a string`) - if (!isValidAddress(txParams.from)) throw new Error('Invalid from address') + if (!(typeof txParams.from === 'string')) { + throw new Error(`Invalid from address ${txParams.from} not a string`) + } + if (!isValidAddress(txParams.from)) { + throw new Error('Invalid from address') + } } /** diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 8f4076f45c96..4e2db5ead754 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -56,7 +56,9 @@ class PendingTransactionTracker extends EventEmitter { resubmitPendingTxs (blockNumber) { const pending = this.getPendingTransactions() // only try resubmitting if their are transactions to resubmit - if (!pending.length) return + if (!pending.length) { + return + } pending.forEach((txMeta) => this._resubmitTx(txMeta, blockNumber).catch((err) => { /* Dont marked as failed if the error is a "known" transaction warning @@ -79,7 +81,9 @@ class PendingTransactionTracker extends EventEmitter { errorMessage.includes('nonce too low') ) // ignore resubmit warnings, return early - if (isKnownTx) return + if (isKnownTx) { + return + } // encountered real error - transition to error state txMeta.warning = { error: errorMessage, @@ -107,10 +111,14 @@ class PendingTransactionTracker extends EventEmitter { const retryCount = txMeta.retryCount || 0 // Exponential backoff to limit retries at publishing - if (txBlockDistance <= Math.pow(2, retryCount) - 1) return + if (txBlockDistance <= Math.pow(2, retryCount) - 1) { + return + } // Only auto-submit already-signed txs: - if (!('rawTx' in txMeta)) return this.approveTransaction(txMeta.id) + if (!('rawTx' in txMeta)) { + return this.approveTransaction(txMeta.id) + } const rawTx = txMeta.rawTx const txHash = await this.publishTransaction(rawTx) @@ -132,7 +140,9 @@ class PendingTransactionTracker extends EventEmitter { const txId = txMeta.id // Only check submitted txs - if (txMeta.status !== 'submitted') return + if (txMeta.status !== 'submitted') { + return + } // extra check in case there was an uncaught error during the // signature and submission process diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 287fb6f44c42..517137f86511 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -142,9 +142,13 @@ class TxGasUtil { const bufferedGasLimitBn = initialGasLimitBn.muln(1.5) // if initialGasLimit is above blockGasLimit, dont modify it - if (initialGasLimitBn.gt(upperGasLimitBn)) return bnToHex(initialGasLimitBn) + if (initialGasLimitBn.gt(upperGasLimitBn)) { + return bnToHex(initialGasLimitBn) + } // if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit - if (bufferedGasLimitBn.lt(upperGasLimitBn)) return bnToHex(bufferedGasLimitBn) + if (bufferedGasLimitBn.lt(upperGasLimitBn)) { + return bnToHex(bufferedGasLimitBn) + } // otherwise use blockGasLimit return bnToHex(upperGasLimitBn) } diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 6a92c06011a4..fb9359c79174 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -45,7 +45,9 @@ class TransactionStateManager extends EventEmitter { */ generateTxMeta (opts) { const netId = this.getNetwork() - if (netId === 'loading') throw new Error('MetaMask is having trouble connecting to the network') + if (netId === 'loading') { + throw new Error('MetaMask is having trouble connecting to the network') + } return extend({ id: createId(), time: (new Date()).getTime(), @@ -89,7 +91,9 @@ class TransactionStateManager extends EventEmitter { */ getApprovedTransactions (address) { const opts = { status: 'approved' } - if (address) opts.from = address + if (address) { + opts.from = address + } return this.getFilteredTxList(opts) } @@ -100,7 +104,9 @@ class TransactionStateManager extends EventEmitter { */ getPendingTransactions (address) { const opts = { status: 'submitted' } - if (address) opts.from = address + if (address) { + opts.from = address + } return this.getFilteredTxList(opts) } @@ -111,7 +117,9 @@ class TransactionStateManager extends EventEmitter { */ getConfirmedTransactions (address) { const opts = { status: 'confirmed' } - if (address) opts.from = address + if (address) { + opts.from = address + } return this.getFilteredTxList(opts) } @@ -236,10 +244,14 @@ class TransactionStateManager extends EventEmitter { // 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})`) + if (typeof value !== 'number' && typeof value !== 'string') { + 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})`) + if (typeof value !== 'string') { + throw new Error(`${key} in txParams is not a string. got: (${value})`) + } break } }) diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index 3137ea8a363f..8fef712fe67c 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -124,7 +124,9 @@ class AccountTracker { // save accounts state this.store.updateState({ accounts }) // fetch balances for the accounts if there is block number ready - if (!this._currentBlockNumber) return + if (!this._currentBlockNumber) { + return + } this._updateAccounts() } @@ -158,7 +160,9 @@ class AccountTracker { // block gasLimit polling shouldn't be in account-tracker shouldn't be here... const currentBlock = await this._query.getBlockByNumber(blockNumber, false) - if (!currentBlock) return + if (!currentBlock) { + return + } const currentBlockGasLimit = currentBlock.gasLimit this.store.updateState({ currentBlockGasLimit }) @@ -218,7 +222,9 @@ class AccountTracker { // update accounts state const { accounts } = this.store.getState() // only populate if the entry is still present - if (!accounts[address]) return + if (!accounts[address]) { + return + } accounts[address] = result this.store.updateState({ accounts }) } diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js index fd209c230ae8..343191f4c126 100644 --- a/app/scripts/lib/auto-reload.js +++ b/app/scripts/lib/auto-reload.js @@ -28,10 +28,14 @@ function setupDappAutoReload (web3, observable) { observable.subscribe(function (state) { // if the auto refresh on network change is false do not // do anything - if (!window.ethereum.autoRefreshOnNetworkChange) return + if (!window.ethereum.autoRefreshOnNetworkChange) { + return + } // if reload in progress, no need to check reload logic - if (reloadInProgress) return + if (reloadInProgress) { + return + } const currentNetwork = state.networkVersion @@ -42,10 +46,14 @@ function setupDappAutoReload (web3, observable) { } // skip reload logic if web3 not used - if (!lastTimeUsed) return + if (!lastTimeUsed) { + return + } // if network did not change, exit - if (currentNetwork === lastSeenNetwork) return + if (currentNetwork === lastSeenNetwork) { + return + } // initiate page reload reloadInProgress = true diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index 5cae83a9f4be..6728fde7c170 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -13,7 +13,9 @@ module.exports = getBuyEthUrl */ function getBuyEthUrl ({ network, amount, address, service }) { // default service by network if not specified - if (!service) service = getDefaultServiceForNetwork(network) + if (!service) { + service = getDefaultServiceForNetwork(network) + } switch (service) { case 'wyre': diff --git a/app/scripts/lib/createDnodeRemoteGetter.js b/app/scripts/lib/createDnodeRemoteGetter.js index b70d218f3228..60a7753831d4 100644 --- a/app/scripts/lib/createDnodeRemoteGetter.js +++ b/app/scripts/lib/createDnodeRemoteGetter.js @@ -8,7 +8,9 @@ function createDnodeRemoteGetter (dnode) { }) async function getRemote () { - if (remote) return remote + if (remote) { + return remote + } return await new Promise(resolve => dnode.once('remote', resolve)) } diff --git a/app/scripts/lib/createLoggerMiddleware.js b/app/scripts/lib/createLoggerMiddleware.js index 996c3477c6ac..d95cdb465f03 100644 --- a/app/scripts/lib/createLoggerMiddleware.js +++ b/app/scripts/lib/createLoggerMiddleware.js @@ -13,7 +13,9 @@ function createLoggerMiddleware (opts) { if (res.error) { log.error('Error in RPC response:\n', res) } - if (req.isMetamaskInternal) return + if (req.isMetamaskInternal) { + return + } log.info(`RPC (${opts.origin}):`, req, '->', res) cb() }) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index a3711c5f94b8..f12a22238b3d 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -23,14 +23,18 @@ function setupEnsIpfsResolver ({ provider }) { async function webRequestDidFail (details) { const { tabId, url } = details // ignore requests that are not associated with tabs - if (tabId === -1) return + if (tabId === -1) { + return + } // parse ens name const urlData = urlUtil.parse(url) const { hostname: name, path, search } = urlData const domainParts = name.split('.') const topLevelDomain = domainParts[domainParts.length - 1] // if unsupported TLD, abort - if (!supportedTopLevelDomains.includes(topLevelDomain)) return + if (!supportedTopLevelDomains.includes(topLevelDomain)) { + return + } // otherwise attempt resolve attemptResolve({ tabId, name, path, search }) } @@ -45,7 +49,9 @@ function setupEnsIpfsResolver ({ provider }) { try { // check if ipfs gateway has result const response = await fetch(resolvedUrl, { method: 'HEAD' }) - if (response.status === 200) url = resolvedUrl + if (response.status === 200) { + url = resolvedUrl + } } catch (err) { console.warn(err) } diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 8fde2e9111d7..49294c84dd64 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -20,7 +20,9 @@ module.exports = class ExtensionStore { * @return {Promise<*>} */ async get () { - if (!this.isSupported) return undefined + if (!this.isSupported) { + return undefined + } const result = await this._get() // extension.storage.local always returns an obj // if the object is empty, treat it as undefined @@ -96,9 +98,13 @@ function isEmpty (obj) { */ function checkForError () { const lastError = extension.runtime.lastError - if (!lastError) return + if (!lastError) { + return + } // if it quacks like an Error, its an Error - if (lastError.stack && lastError.message) return lastError + if (lastError.stack && lastError.message) { + return lastError + } // repair incomplete error object (eg chromium v77) return new Error(lastError.message) } diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index 8e1ff34b755f..9f087abad968 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -62,7 +62,9 @@ module.exports = class MessageManager extends EventEmitter { */ getUnapprovedMsgs () { return this.messages.filter(msg => msg.status === 'unapproved') - .reduce((result, msg) => { result[msg.id] = msg; return result }, {}) + .reduce((result, msg) => { + result[msg.id] = msg; return result + }, {}) } /** @@ -102,7 +104,9 @@ module.exports = class MessageManager extends EventEmitter { */ addUnapprovedMessage (msgParams, req) { // add origin from request - if (req) msgParams.origin = req.origin + if (req) { + msgParams.origin = req.origin + } msgParams.data = normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data var time = (new Date()).getTime() @@ -219,7 +223,9 @@ module.exports = class MessageManager extends EventEmitter { */ _setMsgStatus (msgId, status) { const msg = this.getMsg(msgId) - if (!msg) throw new Error('MessageManager - Message not found for id: "${msgId}".') + if (!msg) { + throw new Error('MessageManager - Message not found for id: "${msgId}".') + } msg.status = status this._updateMsg(msg) this.emit(`${msgId}:${status}`, msg) diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index 345ca800162b..c1c225fb39c2 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -40,8 +40,12 @@ class Migrator extends EventEmitter { try { // attempt migration and validate const migratedData = await migration.migrate(versionedData) - 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.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') + } // accept the migration as good versionedData = migratedData } catch (err) { diff --git a/app/scripts/lib/nodeify.js b/app/scripts/lib/nodeify.js index a813ae679c36..99b96b3566ce 100644 --- a/app/scripts/lib/nodeify.js +++ b/app/scripts/lib/nodeify.js @@ -1,5 +1,9 @@ const promiseToCallback = require('promise-to-callback') -const callbackNoop = function (err) { if (err) throw err } +const callbackNoop = function (err) { + if (err) { + throw err + } +} /** * A generator that returns a function which, when passed a promise, can treat that promise as a node style callback. diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index 721d109a1a95..85177cceb9eb 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -18,7 +18,9 @@ class NotificationManager { */ showPopup () { this._getPopup((err, popup) => { - if (err) throw err + if (err) { + throw err + } // Bring focus to chrome popup if (popup) { @@ -28,7 +30,9 @@ class NotificationManager { const {screenX, screenY, outerWidth, outerHeight} = window const notificationTop = Math.round(screenY + (outerHeight / 2) - (NOTIFICATION_HEIGHT / 2)) const notificationLeft = Math.round(screenX + (outerWidth / 2) - (NOTIFICATION_WIDTH / 2)) - const cb = (currentPopup) => { this._popupId = currentPopup.id } + const cb = (currentPopup) => { + this._popupId = currentPopup.id + } // create new notification popup const creation = extension.windows.create({ url: 'notification.html', @@ -50,8 +54,12 @@ class NotificationManager { closePopup () { // closes notification popup this._getPopup((err, popup) => { - if (err) throw err - if (!popup) return + if (err) { + throw err + } + if (!popup) { + return + } extension.windows.remove(popup.id, console.error) }) } @@ -66,7 +74,9 @@ class NotificationManager { */ _getPopup (cb) { this._getWindows((err, windows) => { - if (err) throw err + if (err) { + throw err + } cb(null, this._getPopupIn(windows)) }) } diff --git a/app/scripts/lib/pending-balance-calculator.js b/app/scripts/lib/pending-balance-calculator.js index 0f1dc19a907d..dd7fa6de4683 100644 --- a/app/scripts/lib/pending-balance-calculator.js +++ b/app/scripts/lib/pending-balance-calculator.js @@ -32,7 +32,9 @@ class PendingBalanceCalculator { ]) const [ balance, pending ] = results - if (!balance) return undefined + if (!balance) { + return undefined + } const pendingValue = pending.reduce((total, tx) => { return total.add(this.calculateMaxCost(tx)) diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index 2a2ab481ab87..eea8e286d107 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -65,7 +65,9 @@ module.exports = class PersonalMessageManager extends EventEmitter { */ getUnapprovedMsgs () { return this.messages.filter(msg => msg.status === 'unapproved') - .reduce((result, msg) => { result[msg.id] = msg; return result }, {}) + .reduce((result, msg) => { + result[msg.id] = msg; return result + }, {}) } /** @@ -110,7 +112,9 @@ module.exports = class PersonalMessageManager extends EventEmitter { addUnapprovedMessage (msgParams, req) { log.debug(`PersonalMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) // add origin from request - if (req) msgParams.origin = req.origin + if (req) { + msgParams.origin = req.origin + } msgParams.data = this.normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data var time = (new Date()).getTime() @@ -229,7 +233,9 @@ module.exports = class PersonalMessageManager extends EventEmitter { */ _setMsgStatus (msgId, status) { const msg = this.getMsg(msgId) - if (!msg) throw new Error(`PersonalMessageManager - Message not found for id: "${msgId}".`) + if (!msg) { + throw new Error(`PersonalMessageManager - Message not found for id: "${msgId}".`) + } msg.status = status this._updateMsg(msg) this.emit(`${msgId}:${status}`, msg) diff --git a/app/scripts/lib/setupFetchDebugging.js b/app/scripts/lib/setupFetchDebugging.js index 431340e2beaf..d5c01b1f2306 100644 --- a/app/scripts/lib/setupFetchDebugging.js +++ b/app/scripts/lib/setupFetchDebugging.js @@ -7,7 +7,9 @@ module.exports = setupFetchDebugging // function setupFetchDebugging () { - if (!global.fetch) return + if (!global.fetch) { + return + } const originalFetch = global.fetch global.fetch = wrappedFetch diff --git a/app/scripts/lib/setupMetamaskMeshMetrics.js b/app/scripts/lib/setupMetamaskMeshMetrics.js index 6f0d86b2841d..b520ceaa7f03 100644 --- a/app/scripts/lib/setupMetamaskMeshMetrics.js +++ b/app/scripts/lib/setupMetamaskMeshMetrics.js @@ -22,7 +22,9 @@ function setupMetamaskMeshMetrics () { function submitMeshMetricsEntry (message) { // ignore if we haven't loaded yet - if (!didLoad) return + if (!didLoad) { + return + } // submit the message testingContainer.contentWindow.postMessage(message, targetOrigin) } diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index ba0e17df0ddc..096bd34541b8 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -67,11 +67,15 @@ function simplifyErrorMessages (report) { function rewriteErrorMessages (report, rewriteFn) { // rewrite top level message - if (typeof report.message === 'string') report.message = rewriteFn(report.message) + if (typeof report.message === 'string') { + report.message = rewriteFn(report.message) + } // rewrite each exception message if (report.exception && report.exception.values) { report.exception.values.forEach(item => { - if (typeof item.value === 'string') item.value = rewriteFn(item.value) + if (typeof item.value === 'string') { + item.value = rewriteFn(item.value) + } }) } } @@ -91,7 +95,9 @@ function rewriteReportUrls (report) { function toMetamaskUrl (origUrl) { const filePath = origUrl.split(location.origin)[1] - if (!filePath) return origUrl + if (!filePath) { + return origUrl + } const metamaskUrl = `metamask${filePath}` return metamaskUrl } diff --git a/app/scripts/lib/stream-utils.js b/app/scripts/lib/stream-utils.js index 3dbc064b5e7f..66b3107f4e3f 100644 --- a/app/scripts/lib/stream-utils.js +++ b/app/scripts/lib/stream-utils.js @@ -43,7 +43,9 @@ function setupMultiplex (connectionStream) { mux, connectionStream, (err) => { - if (err) console.error(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 e4d3e842bb99..3f5934299615 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -58,7 +58,9 @@ module.exports = class TypedMessageManager extends EventEmitter { */ getUnapprovedMsgs () { return this.messages.filter(msg => msg.status === 'unapproved') - .reduce((result, msg) => { result[msg.id] = msg; return result }, {}) + .reduce((result, msg) => { + result[msg.id] = msg; return result + }, {}) } /** @@ -103,7 +105,9 @@ module.exports = class TypedMessageManager extends EventEmitter { msgParams.version = version this.validateParams(msgParams) // add origin from request - if (req) msgParams.origin = req.origin + if (req) { + msgParams.origin = req.origin + } log.debug(`TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) // create txData obj with parameters and meta data @@ -149,7 +153,9 @@ module.exports = class TypedMessageManager extends EventEmitter { assert.ok('from' in params, 'Params must include a from field.') assert.equal(typeof params.from, 'string', 'From field must be a string.') assert.equal(typeof params.data, 'string', 'Data must be passed as a valid JSON string.') - assert.doesNotThrow(() => { data = JSON.parse(params.data) }, 'Data must be passed as a valid JSON string.') + assert.doesNotThrow(() => { + data = JSON.parse(params.data) + }, 'Data must be passed as 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, 'Data must conform to EIP-712 schema. See https://git.io/fNtcx.') @@ -278,7 +284,9 @@ module.exports = class TypedMessageManager extends EventEmitter { */ _setMsgStatus (msgId, status) { const msg = this.getMsg(msgId) - if (!msg) throw new Error('TypedMessageManager - Message not found for id: "${msgId}".') + if (!msg) { + throw new Error('TypedMessageManager - Message not found for id: "${msgId}".') + } msg.status = status this._updateMsg(msg) this.emit(`${msgId}:${status}`, msg) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 1c607a4c65eb..c8182b6bdbb9 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -342,7 +342,9 @@ module.exports = class MetamaskController extends EventEmitter { // Expose no accounts if this origin has not been approved, preventing // account-requring RPC methods from completing successfully const exposeAccounts = this.providerApprovalController.shouldExposeAccounts(origin) - if (origin !== 'metamask' && !exposeAccounts) { return [] } + if (origin !== 'metamask' && !exposeAccounts) { + return [] + } const isUnlocked = this.keyringController.memStore.getState().isUnlocked const selectedAddress = this.preferencesController.getSelectedAddress() // only show address if account is unlocked @@ -1404,7 +1406,9 @@ module.exports = class MetamaskController extends EventEmitter { this.activeControllerConnections-- this.emit('controllerConnectionChanged', this.activeControllerConnections) // report any error - if (err) log.error(err) + if (err) { + log.error(err) + } } ) dnode.on('remote', (remote) => { @@ -1442,7 +1446,9 @@ module.exports = class MetamaskController extends EventEmitter { mid.destroy() } }) - if (err) log.error(err) + if (err) { + log.error(err) + } } ) } @@ -1507,7 +1513,9 @@ module.exports = class MetamaskController extends EventEmitter { (err) => { configStore.destroy() configStream.destroy() - if (err) log.error(err) + if (err) { + log.error(err) + } } ) } @@ -1527,7 +1535,9 @@ module.exports = class MetamaskController extends EventEmitter { outStream, (err) => { // report any error - if (err) log.error(err) + if (err) { + log.error(err) + } } ) @@ -1676,10 +1686,14 @@ module.exports = class MetamaskController extends EventEmitter { * @param {string} amount - The amount of ether desired, as a base 10 string. */ buyEth (address, amount) { - if (!amount) amount = '5' + if (!amount) { + amount = '5' + } const network = this.networkController.getNetworkState() const url = getBuyEthUrl({ network, address, amount }) - if (url) this.platform.openWindow({ url }) + if (url) { + this.platform.openWindow({ url }) + } } /** diff --git a/app/scripts/migrations/004.js b/app/scripts/migrations/004.js index cd558300c33f..c0cf600c9139 100644 --- a/app/scripts/migrations/004.js +++ b/app/scripts/migrations/004.js @@ -9,7 +9,9 @@ module.exports = { const safeVersionedData = clone(versionedData) safeVersionedData.meta.version = version try { - if (safeVersionedData.data.config.provider.type !== 'rpc') return Promise.resolve(safeVersionedData) + if (safeVersionedData.data.config.provider.type !== 'rpc') { + return Promise.resolve(safeVersionedData) + } switch (safeVersionedData.data.config.provider.rpcTarget) { case 'https://testrpc.metamask.io/': safeVersionedData.data.config.provider = { diff --git a/app/scripts/migrations/015.js b/app/scripts/migrations/015.js index 5e2f9e63bd87..3d20b58db5b2 100644 --- a/app/scripts/migrations/015.js +++ b/app/scripts/migrations/015.js @@ -32,8 +32,11 @@ function transformState (state) { if (TransactionController && TransactionController.transactions) { const transactions = TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta) => { - if (!txMeta.err) return txMeta - else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed' + if (!txMeta.err) { + return txMeta + } else if (txMeta.err.message === 'Gave up submitting tx.') { + txMeta.status = 'failed' + } return txMeta }) } diff --git a/app/scripts/migrations/016.js b/app/scripts/migrations/016.js index 048c7a40ec26..76a106ca7e38 100644 --- a/app/scripts/migrations/016.js +++ b/app/scripts/migrations/016.js @@ -33,7 +33,9 @@ function transformState (state) { const transactions = newState.TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta) => { - if (!txMeta.err) return txMeta + if (!txMeta.err) { + return txMeta + } 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 5f6d906d6724..918df4ade10e 100644 --- a/app/scripts/migrations/017.js +++ b/app/scripts/migrations/017.js @@ -31,7 +31,9 @@ function transformState (state) { if (TransactionController && TransactionController.transactions) { const transactions = newState.TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta) => { - if (!txMeta.status === 'failed') return txMeta + if (!txMeta.status === 'failed') { + return txMeta + } if (txMeta.retryCount > 0 && txMeta.retryCount < 2) { txMeta.status = 'submitted' delete txMeta.err diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js index 7b726c3e8575..f560f5579d9a 100644 --- a/app/scripts/migrations/019.js +++ b/app/scripts/migrations/019.js @@ -35,7 +35,9 @@ function transformState (state) { const transactions = newState.TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { - if (txMeta.status !== 'submitted') return txMeta + if (txMeta.status !== 'submitted') { + return txMeta + } const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed') .filter((tx) => tx.txParams.from === txMeta.txParams.from) diff --git a/app/scripts/migrations/022.js b/app/scripts/migrations/022.js index 1fbe241e6ed4..eeb142b7a939 100644 --- a/app/scripts/migrations/022.js +++ b/app/scripts/migrations/022.js @@ -33,7 +33,9 @@ function transformState (state) { const transactions = newState.TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta) => { - if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta + if (txMeta.status !== 'submitted' || txMeta.submittedTime) { + return txMeta + } txMeta.submittedTime = (new Date()).getTime() return txMeta }) diff --git a/app/scripts/migrations/023.js b/app/scripts/migrations/023.js index 18493a7893c5..84532537ea94 100644 --- a/app/scripts/migrations/023.js +++ b/app/scripts/migrations/023.js @@ -33,7 +33,9 @@ function transformState (state) { if (TransactionController && TransactionController.transactions) { const transactions = newState.TransactionController.transactions - if (transactions.length <= 40) return newState + if (transactions.length <= 40) { + return newState + } const reverseTxList = transactions.reverse() let stripping = true @@ -44,8 +46,11 @@ function transformState (state) { txMeta.status === 'confirmed' || txMeta.status === 'dropped') }) - if (txIndex < 0) stripping = false - else reverseTxList.splice(txIndex, 1) + if (txIndex < 0) { + stripping = false + } else { + reverseTxList.splice(txIndex, 1) + } } newState.TransactionController.transactions = reverseTxList.reverse() diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js index 5ffaea377ece..fda463e1a1b0 100644 --- a/app/scripts/migrations/024.js +++ b/app/scripts/migrations/024.js @@ -25,7 +25,9 @@ module.exports = { function transformState (state) { const newState = state - if (!newState.TransactionController) return newState + if (!newState.TransactionController) { + return newState + } const transactions = newState.TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta, _) => { if ( diff --git a/app/scripts/migrations/025.js b/app/scripts/migrations/025.js index fd4faa782cf9..48bff962dedb 100644 --- a/app/scripts/migrations/025.js +++ b/app/scripts/migrations/025.js @@ -29,7 +29,9 @@ function transformState (state) { if (newState.TransactionController.transactions) { const transactions = newState.TransactionController.transactions newState.TransactionController.transactions = transactions.map((txMeta) => { - if (txMeta.status !== 'unapproved') return txMeta + if (txMeta.status !== 'unapproved') { + return txMeta + } txMeta.txParams = normalizeTxParams(txMeta.txParams) return txMeta }) @@ -54,7 +56,9 @@ function normalizeTxParams (txParams) { // apply only keys in the whiteList const normalizedTxParams = {} Object.keys(whiteList).forEach((key) => { - if (txParams[key]) normalizedTxParams[key] = whiteList[key](txParams[key]) + if (txParams[key]) { + normalizedTxParams[key] = whiteList[key](txParams[key]) + } }) return normalizedTxParams diff --git a/development/mock-3box.js b/development/mock-3box.js index 53f228f2168b..a26e02a82079 100644 --- a/development/mock-3box.js +++ b/development/mock-3box.js @@ -28,7 +28,9 @@ class Mock3Box { static openBox (address) { this.address = address return Promise.resolve({ - onSyncDone: cb => { setTimeout(cb, 200) }, + onSyncDone: cb => { + setTimeout(cb, 200) + }, openSpace: async (spaceName, config) => { const { onSyncDone } = config this.spaceName = spaceName diff --git a/development/show-deps-install-scripts.js b/development/show-deps-install-scripts.js index 03a9bb859b73..419c9d25f2cf 100644 --- a/development/show-deps-install-scripts.js +++ b/development/show-deps-install-scripts.js @@ -5,7 +5,9 @@ const readInstalled = require('read-installed') const installScripts = ['preinstall', 'install', 'postinstall'] readInstalled('./', { dev: true }, function (err, data) { - if (err) throw err + if (err) { + throw err + } const deps = data.dependencies Object.entries(deps).forEach(([packageName, packageData]) => { @@ -13,12 +15,20 @@ readInstalled('./', { dev: true }, function (err, data) { const scriptKeys = Reflect.ownKeys(packageScripts) const hasInstallScript = installScripts.some(installKey => scriptKeys.includes(installKey)) - if (!hasInstallScript) return + if (!hasInstallScript) { + return + } const matchingScripts = {} - if (packageScripts.preinstall) matchingScripts.preinstall = packageScripts.preinstall - if (packageScripts.install) matchingScripts.install = packageScripts.install - if (packageScripts.postinstall) matchingScripts.postinstall = packageScripts.postinstall + if (packageScripts.preinstall) { + matchingScripts.preinstall = packageScripts.preinstall + } + if (packageScripts.install) { + matchingScripts.install = packageScripts.install + } + if (packageScripts.postinstall) { + matchingScripts.postinstall = packageScripts.postinstall + } const scriptNames = Reflect.ownKeys(matchingScripts) const relativePath = path.relative(process.cwd(), packageData.path) diff --git a/development/sourcemap-validator.js b/development/sourcemap-validator.js index 546745f1665d..44336df9ec42 100644 --- a/development/sourcemap-validator.js +++ b/development/sourcemap-validator.js @@ -52,7 +52,9 @@ async function validateSourcemapForFile ({ buildName }) { const consumer = await new SourceMapConsumer(rawSourceMap) const hasContentsOfAllSources = consumer.hasContentsOfAllSources() - if (!hasContentsOfAllSources) console.warn('SourcemapValidator - missing content of some sources...') + if (!hasContentsOfAllSources) { + console.warn('SourcemapValidator - missing content of some sources...') + } console.log(` sampling from ${consumer.sources.length} files`) let sampleCount = 0 @@ -96,6 +98,8 @@ async function validateSourcemapForFile ({ buildName }) { function indicesOf (substring, string) { var a = [] var i = -1 - while ((i = string.indexOf(substring, i + 1)) >= 0) a.push(i) + while ((i = string.indexOf(substring, i + 1)) >= 0) { + a.push(i) + } return a } diff --git a/gulpfile.js b/gulpfile.js index 3e4a3b7ff2f8..d5d74333afc9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -428,7 +428,9 @@ function createTasksForBuildJs ({ rootDir, taskPrefix, bundleTaskOpts, destinati // compose into larger task const subtasks = [] subtasks.push(gulp.parallel(buildPhase1.map(file => `${taskPrefix}:${file}`))) - if (buildPhase2.length) subtasks.push(gulp.parallel(buildPhase2.map(file => `${taskPrefix}:${file}`))) + if (buildPhase2.length) { + subtasks.push(gulp.parallel(buildPhase2.map(file => `${taskPrefix}:${file}`))) + } gulp.task(taskPrefix, gulp.series(subtasks)) } diff --git a/test/helper.js b/test/helper.js index ddc2aba408ef..a49249062c12 100644 --- a/test/helper.js +++ b/test/helper.js @@ -36,8 +36,12 @@ require('jsdom-global')() window.localStorage = {} // crypto.getRandomValues -if (!window.crypto) window.crypto = {} -if (!window.crypto.getRandomValues) window.crypto.getRandomValues = require('polyfill-crypto.getrandomvalues') +if (!window.crypto) { + window.crypto = {} +} +if (!window.crypto.getRandomValues) { + window.crypto.getRandomValues = require('polyfill-crypto.getrandomvalues') +} function enableFailureOnUnhandledPromiseRejection () { // overwrite node's promise with the stricter Bluebird promise @@ -60,7 +64,9 @@ function enableFailureOnUnhandledPromiseRejection () { } else { var oldOHR = window.onunhandledrejection window.onunhandledrejection = function (evt) { - if (typeof oldOHR === 'function') oldOHR.apply(this, arguments) + if (typeof oldOHR === 'function') { + oldOHR.apply(this, arguments) + } throw evt.detail.reason } } diff --git a/test/integration/index.js b/test/integration/index.js index b266ddf37cf5..1c4523e1e343 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -19,7 +19,9 @@ pump( b.bundle(), writeStream, (err) => { - if (err) throw err + if (err) { + throw err + } console.log(`Integration test build completed: "${bundlePath}"`) process.exit(0) } diff --git a/test/lib/mock-simple-keychain.js b/test/lib/mock-simple-keychain.js index d3addc3e8a3d..daf6001c4ab9 100644 --- a/test/lib/mock-simple-keychain.js +++ b/test/lib/mock-simple-keychain.js @@ -6,7 +6,9 @@ const type = 'Simple Key Pair' module.exports = class MockSimpleKeychain { - static type () { return type } + static type () { + return type + } constructor (opts) { this.type = type diff --git a/test/lib/util.js b/test/lib/util.js index 4c5d789d1602..be7e240a4c21 100644 --- a/test/lib/util.js +++ b/test/lib/util.js @@ -15,7 +15,9 @@ async function findAsync (container, selector, opts) { try { return await pollUntilTruthy(() => { const result = container.find(selector) - if (result.length > 0) return result + if (result.length > 0) { + return result + } }, opts) } catch (err) { throw new Error(`Failed to find element within interval: "${selector}"`) @@ -26,7 +28,9 @@ async function queryAsync (jQuery, selector, opts) { try { return await pollUntilTruthy(() => { const result = jQuery(selector) - if (result.length > 0) return result + if (result.length > 0) { + return result + } }, opts) } catch (err) { throw new Error(`Failed to find element within interval: "${selector}"`) diff --git a/test/setup.js b/test/setup.js index bccb4d58e57a..5aa6e59dd9fe 100644 --- a/test/setup.js +++ b/test/setup.js @@ -5,6 +5,10 @@ require('@babel/register')({ require('./helper') window.SVGPathElement = window.SVGPathElement || { prototype: {} } -window.fetch = window.fetch || function fetch () { return Promise.resolve() } +window.fetch = window.fetch || function fetch () { + return Promise.resolve() +} global.indexedDB = {} -global.fetch = global.fetch || function fetch () { return Promise.resolve() } +global.fetch = global.fetch || function fetch () { + return Promise.resolve() +} diff --git a/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js index 66378b594435..ca1225113723 100644 --- a/test/unit/actions/tx_test.js +++ b/test/unit/actions/tx_test.js @@ -33,9 +33,15 @@ describe('tx confirmation screen', function () { describe('cancelTx', function () { before(function (done) { actions._setBackgroundConnection({ - approveTransaction (_, cb) { cb('An error!') }, - cancelTransaction (_, cb) { cb() }, - getState (cb) { cb() }, + approveTransaction (_, cb) { + cb('An error!') + }, + cancelTransaction (_, cb) { + cb() + }, + getState (cb) { + cb() + }, }) done() }) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 7eac91a9b399..a904dec089ea 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -227,7 +227,9 @@ describe('MetaMaskController', function () { it('should be able to call newVaultAndRestore despite a mistake.', async function () { const password = 'what-what-what' sandbox.stub(metamaskController, 'getBalance') - metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0') }) + metamaskController.getBalance.callsFake(() => { + return Promise.resolve('0x0') + }) await metamaskController.createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)).catch(() => null) await metamaskController.createNewVaultAndRestore(password, TEST_SEED) @@ -237,7 +239,9 @@ describe('MetaMaskController', function () { it('should clear previous identities after vault restoration', async () => { sandbox.stub(metamaskController, 'getBalance') - metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0') }) + metamaskController.getBalance.callsFake(() => { + return Promise.resolve('0x0') + }) await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED) assert.deepEqual(metamaskController.getState().identities, { @@ -676,7 +680,9 @@ describe('MetaMaskController', function () { beforeEach(async () => { sandbox.stub(metamaskController, 'getBalance') - metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0') }) + metamaskController.getBalance.callsFake(() => { + return Promise.resolve('0x0') + }) await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT) @@ -734,7 +740,9 @@ describe('MetaMaskController', function () { beforeEach(async function () { sandbox.stub(metamaskController, 'getBalance') - metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0') }) + metamaskController.getBalance.callsFake(() => { + return Promise.resolve('0x0') + }) await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT) @@ -809,7 +817,9 @@ describe('MetaMaskController', function () { const { promise, resolve } = deferredPromise() streamTest = createThoughStream((chunk, _, cb) => { - if (chunk.name !== 'phishing') return cb() + if (chunk.name !== 'phishing') { + return cb() + } assert.equal(chunk.data.hostname, phishingUrl.hostname) resolve() cb() @@ -929,6 +939,8 @@ describe('MetaMaskController', function () { function deferredPromise () { let resolve - const promise = new Promise(_resolve => { resolve = _resolve }) + const promise = new Promise(_resolve => { + resolve = _resolve + }) return { promise, resolve } } diff --git a/test/unit/app/controllers/network/pending-middleware-test.js b/test/unit/app/controllers/network/pending-middleware-test.js index 838395b0bfa5..ac6f8ad9a6c3 100644 --- a/test/unit/app/controllers/network/pending-middleware-test.js +++ b/test/unit/app/controllers/network/pending-middleware-test.js @@ -19,7 +19,9 @@ describe('#createPendingNonceMiddleware', function () { it('should fill the result with a the "pending" nonce', (done) => { const req = { method: 'eth_getTransactionCount', params: [address, 'pending'] } const res = {} - pendingNonceMiddleware(req, res, () => { done(new Error('should not have called next')) }, () => { + pendingNonceMiddleware(req, res, () => { + done(new Error('should not have called next')) + }, () => { assert(res.result === '0x2') done() }) @@ -63,7 +65,9 @@ describe('#createPendingTxMiddleware', function () { returnUndefined = false const req = { method: 'eth_getTransactionByHash', params: [address, 'pending'] } const res = {} - pendingTxMiddleware(req, res, () => { done(new Error('should not have called next')) }, () => { + pendingTxMiddleware(req, res, () => { + done(new Error('should not have called next')) + }, () => { /* // uncomment this section for debugging help with non matching keys const coppy = {...res.result} diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index 7e047a2a8172..f9dc9c09995b 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -455,28 +455,44 @@ describe('preferences controller', function () { }) it('should validate ERC20 asset correctly', async function () { const validateSpy = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpy({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 0}) } catch (e) {} + try { + validateSpy({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 0}) + } catch (e) {} assert.equal(validateSpy.threw(), false, 'correct options object') const validateSpyAddress = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpyAddress({symbol: 'ABC', decimals: 0}) } catch (e) {} + try { + validateSpyAddress({symbol: 'ABC', decimals: 0}) + } catch (e) {} assert.equal(validateSpyAddress.threw(), true, 'options object with no address') const validateSpySymbol = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpySymbol({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', decimals: 0}) } catch (e) {} + try { + validateSpySymbol({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', decimals: 0}) + } catch (e) {} assert.equal(validateSpySymbol.threw(), true, 'options object with no symbol') const validateSpyDecimals = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpyDecimals({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC'}) } catch (e) {} + try { + validateSpyDecimals({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC'}) + } catch (e) {} assert.equal(validateSpyDecimals.threw(), true, 'options object with no decimals') const validateSpyInvalidSymbol = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpyInvalidSymbol({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 0}) } catch (e) {} + try { + validateSpyInvalidSymbol({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 0}) + } catch (e) {} assert.equal(validateSpyInvalidSymbol.threw(), true, 'options object with invalid symbol') const validateSpyInvalidDecimals1 = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpyInvalidDecimals1({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: -1}) } catch (e) {} + try { + validateSpyInvalidDecimals1({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: -1}) + } catch (e) {} assert.equal(validateSpyInvalidDecimals1.threw(), true, 'options object with decimals less than zero') const validateSpyInvalidDecimals2 = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpyInvalidDecimals2({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 38}) } catch (e) {} + try { + validateSpyInvalidDecimals2({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 38}) + } catch (e) {} assert.equal(validateSpyInvalidDecimals2.threw(), true, 'options object with decimals more than 36') const validateSpyInvalidAddress = sandbox.spy(preferencesController._validateERC20AssetParams) - try { validateSpyInvalidAddress({rawAddress: '0x123', symbol: 'ABC', decimals: 0}) } catch (e) {} + try { + validateSpyInvalidAddress({rawAddress: '0x123', symbol: 'ABC', decimals: 0}) + } catch (e) {} assert.equal(validateSpyInvalidAddress.threw(), true, 'options object with address invalid') }) }) diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index e1de5731b4af..622a53b184fe 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -40,13 +40,19 @@ describe('PendingTransactionTracker', function () { return { releaseLock: () => {} } }, }, - getPendingTransactions: () => { return [] }, - getCompletedTransactions: () => { return [] }, + getPendingTransactions: () => { + return [] + }, + getCompletedTransactions: () => { + return [] + }, publishTransaction: () => {}, confirmTransaction: () => {}, }) - pendingTxTracker._getBlock = (blockNumber) => { return {number: blockNumber, transactions: []} } + pendingTxTracker._getBlock = (blockNumber) => { + return {number: blockNumber, transactions: []} + } }) describe('_checkPendingTx state management', function () { @@ -150,14 +156,18 @@ describe('PendingTransactionTracker', function () { txMeta2.id = 2 txMeta3.id = 3 txList = [txMeta, txMeta2, txMeta3].map((tx) => { - tx.processed = new Promise((resolve) => { tx.resolve = resolve }) + tx.processed = new Promise((resolve) => { + tx.resolve = resolve + }) return tx }) }) it('should warp all txMeta\'s in #updatePendingTxs', function (done) { pendingTxTracker.getPendingTransactions = () => txList - pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) } + pendingTxTracker._checkPendingTx = (tx) => { + tx.resolve(tx) + } Promise.all(txList.map((tx) => tx.processed)) .then(() => done()) .catch(done) @@ -171,7 +181,9 @@ describe('PendingTransactionTracker', function () { beforeEach(function () { const txMeta2 = txMeta3 = txMeta txList = [txMeta, txMeta2, txMeta3].map((tx) => { - tx.processed = new Promise((resolve) => { tx.resolve = resolve }) + tx.processed = new Promise((resolve) => { + tx.resolve = resolve + }) return tx }) }) @@ -181,7 +193,9 @@ describe('PendingTransactionTracker', function () { }) it('should call #_resubmitTx for all pending tx\'s', function (done) { pendingTxTracker.getPendingTransactions = () => txList - pendingTxTracker._resubmitTx = async (tx) => { tx.resolve(tx) } + pendingTxTracker._resubmitTx = async (tx) => { + tx.resolve(tx) + } Promise.all(txList.map((tx) => tx.processed)) .then(() => done()) .catch(done) @@ -225,7 +239,9 @@ describe('PendingTransactionTracker', function () { }) pendingTxTracker.getPendingTransactions = () => txList - pendingTxTracker._resubmitTx = async () => { throw new TypeError('im some real error') } + pendingTxTracker._resubmitTx = async () => { + throw new TypeError('im some real error') + } Promise.all(txList.map((tx) => tx.processed)) .then(() => done()) .catch(done) @@ -369,7 +385,9 @@ describe('PendingTransactionTracker', function () { rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', }] pendingTxTracker.getCompletedTransactions = (address) => { - if (!address) throw new Error('unless behavior has changed #_checkIfNonceIsTaken needs a filtered list of transactions to see if the nonce is taken') + if (!address) { + throw new Error('unless behavior has changed #_checkIfNonceIsTaken needs a filtered list of transactions to see if the nonce is taken') + } return confirmedTxList } }) diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index 76b8e50254ee..d0a989e71e16 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -38,7 +38,9 @@ describe('Transaction Controller', function () { blockTrackerStub.getLatestBlock = noop txController = new TransactionController({ provider, - getGasPrice: function () { return '0xee6b2800' }, + getGasPrice: function () { + return '0xee6b2800' + }, networkStore: netStore, txHistoryLimit: 10, blockTracker: blockTrackerStub, @@ -162,8 +164,11 @@ describe('Transaction Controller', function () { txController.newUnapprovedTransaction(txParams) .catch((err) => { - if (err.message === 'MetaMask Tx Signature: User denied transaction signature.') done() - else done(err) + if (err.message === 'MetaMask Tx Signature: User denied transaction signature.') { + done() + } else { + done(err) + } }) }) }) @@ -209,8 +214,11 @@ describe('Transaction Controller', function () { txController.networkStore = new ObservableStore(1) txController.addUnapprovedTransaction({ from: selectedAddress, to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' }) .catch((err) => { - if (err.message === 'Recipient is a public account') done() - else done(err) + if (err.message === 'Recipient is a public account') { + done() + } else { + done(err) + } }) }) @@ -239,8 +247,11 @@ describe('Transaction Controller', function () { txController.networkStore = new ObservableStore('loading') txController.addUnapprovedTransaction({ from: selectedAddress, to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' }) .catch((err) => { - if (err.message === 'MetaMask is having trouble connecting to the network') done() - else done(err) + if (err.message === 'MetaMask is having trouble connecting to the network') { + done() + } else { + done(err) + } }) }) }) @@ -403,7 +414,9 @@ describe('Transaction Controller', function () { assert.equal(status, 'rejected', 'status should e rejected') assert.equal(txId, 0, 'id should e 0') done() - } catch (e) { done(e) } + } catch (e) { + done(e) + } }) txController.cancelTransaction(0) @@ -498,7 +511,9 @@ describe('Transaction Controller', function () { }) it('should ignore the error "Transaction Failed: known transaction" and be as usual', async function () { - providerResultStub['eth_sendRawTransaction'] = async (_, __, ___, end) => { end('Transaction Failed: known transaction') } + providerResultStub['eth_sendRawTransaction'] = async (_, __, ___, end) => { + end('Transaction Failed: known transaction') + } const rawTx = '0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a' txController.txStateManager.addTx(txMeta) await txController.publishTransaction(txMeta.id, rawTx) @@ -617,7 +632,9 @@ describe('Transaction Controller', function () { _blockTrackerStub.getLatestBlock = noop const _txController = new TransactionController({ provider: _provider, - getGasPrice: function () { return '0xee6b2800' }, + getGasPrice: function () { + return '0xee6b2800' + }, networkStore: new ObservableStore(currentNetworkId), txHistoryLimit: 10, blockTracker: _blockTrackerStub, @@ -647,7 +664,9 @@ describe('Transaction Controller', function () { _blockTrackerStub.getLatestBlock = noop const _txController = new TransactionController({ provider: _provider, - getGasPrice: function () { return '0xee6b2800' }, + getGasPrice: function () { + return '0xee6b2800' + }, networkStore: new ObservableStore(currentNetworkId), txHistoryLimit: 10, blockTracker: _blockTrackerStub, diff --git a/test/unit/app/controllers/transactions/tx-state-history-helper-test.js b/test/unit/app/controllers/transactions/tx-state-history-helper-test.js index 328c2ac6f664..6136de66e5e8 100644 --- a/test/unit/app/controllers/transactions/tx-state-history-helper-test.js +++ b/test/unit/app/controllers/transactions/tx-state-history-helper-test.js @@ -106,7 +106,9 @@ describe('Transaction state history helper', function () { assert.equal(result[0].path, expectedEntry1.path) assert.equal(result[0].value, expectedEntry1.value) assert.equal(result[0].value, expectedEntry1.value) - if (note) { assert.equal(result[0].note, note) } + if (note) { + assert.equal(result[0].note, note) + } assert.ok(result[0].timestamp >= before && result[0].timestamp <= after) diff --git a/test/unit/app/controllers/transactions/tx-utils-test.js b/test/unit/app/controllers/transactions/tx-utils-test.js index 65c8d35b05fd..1c5d20b0963f 100644 --- a/test/unit/app/controllers/transactions/tx-utils-test.js +++ b/test/unit/app/controllers/transactions/tx-utils-test.js @@ -66,7 +66,9 @@ 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') }) }) @@ -76,19 +78,27 @@ describe('txUtils', 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/nodeify-test.js b/test/unit/app/nodeify-test.js index fa5e49fb22a5..fc06803dbc8f 100644 --- a/test/unit/app/nodeify-test.js +++ b/test/unit/app/nodeify-test.js @@ -33,7 +33,9 @@ describe('nodeify', function () { }) it('no callback - should asyncly throw an error if underlying function does', function (done) { - const nodified = nodeify(async () => { throw new Error('boom!') }, obj) + const nodified = nodeify(async () => { + throw new Error('boom!') + }, obj) process.prependOnceListener('uncaughtException', function (err) { assert.ok(err, 'got expected error') assert.ok(err.message.includes('boom!'), 'got expected error message') @@ -50,7 +52,9 @@ describe('nodeify', function () { const nodified = nodeify(() => 42) try { nodified((err, result) => { - if (err) return done(new Error(`should not have thrown any error: ${err.message}`)) + if (err) { + return done(new Error(`should not have thrown any error: ${err.message}`)) + } assert.equal(42, result, 'got expected result') }) done() @@ -60,10 +64,14 @@ describe('nodeify', function () { }) it('sync functions - handles errors', function (done) { - const nodified = nodeify(() => { throw new Error('boom!') }) + const nodified = nodeify(() => { + throw new Error('boom!') + }) try { nodified((err, result) => { - if (result) return done(new Error('should not have returned any result')) + if (result) { + return done(new Error('should not have returned any result')) + } assert.ok(err, 'got expected error') assert.ok(err.message.includes('boom!'), 'got expected error message') }) diff --git a/test/unit/migrations/023-test.js b/test/unit/migrations/023-test.js index 1b47dea92e38..7c93feefec53 100644 --- a/test/unit/migrations/023-test.js +++ b/test/unit/migrations/023-test.js @@ -37,7 +37,9 @@ let nonDeletableCount = 0 let status while (transactions.length <= 100) { status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] - if (!deletableTxStates.find((s) => s === status)) nonDeletableCount++ + if (!deletableTxStates.find((s) => s === status)) { + nonDeletableCount++ + } transactions.push({status}) } diff --git a/test/unit/migrations/024-test.js b/test/unit/migrations/024-test.js index 671c7f83286f..9a6a6661ac18 100644 --- a/test/unit/migrations/024-test.js +++ b/test/unit/migrations/024-test.js @@ -31,8 +31,11 @@ describe('storage is migrated successfully and the txParams.from are lowercase', .then((migratedData) => { const migratedTransactions = migratedData.data.TransactionController.transactions migratedTransactions.forEach((tx) => { - if (tx.status === 'unapproved') assert.equal(tx.txParams.from, '0x8acce2391c0d510a6c5e5d8f819a678f79b7e675') - else assert.equal(tx.txParams.from, '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675') + if (tx.status === 'unapproved') { + assert.equal(tx.txParams.from, '0x8acce2391c0d510a6c5e5d8f819a678f79b7e675') + } else { + assert.equal(tx.txParams.from, '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675') + } }) done() }).catch(done) diff --git a/test/unit/migrations/025-test.js b/test/unit/migrations/025-test.js index fa89bc54fdb1..cabaecd41005 100644 --- a/test/unit/migrations/025-test.js +++ b/test/unit/migrations/025-test.js @@ -32,8 +32,12 @@ describe('storage is migrated successfully and the txParams.from are lowercase', .then((migratedData) => { const migratedTransactions = migratedData.data.TransactionController.transactions migratedTransactions.forEach((tx) => { - if (tx.status === 'unapproved') assert(!tx.txParams.random) - if (tx.status === 'unapproved') assert(!tx.txParams.chainId) + if (tx.status === 'unapproved') { + assert(!tx.txParams.random) + } + if (tx.status === 'unapproved') { + assert(!tx.txParams.chainId) + } }) done() }).catch(done) diff --git a/test/unit/migrations/027-test.js b/test/unit/migrations/027-test.js index 3ec9f0c0e506..767243a25e2a 100644 --- a/test/unit/migrations/027-test.js +++ b/test/unit/migrations/027-test.js @@ -30,7 +30,9 @@ describe('migration #27', () => { 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')) + if (txMeta.status === 'rejected') { + done(new Error('transaction was found with a status of rejected')) + } }) done() }) diff --git a/test/unit/migrations/029-test.js b/test/unit/migrations/029-test.js index 7f9b8a005f74..ca0996389b5f 100644 --- a/test/unit/migrations/029-test.js +++ b/test/unit/migrations/029-test.js @@ -28,7 +28,9 @@ describe('storage is migrated successfully where transactions that are submitted assert(txMeta1.err.message.includes('too long'), 'error message assigned') txs.forEach((tx) => { - if (tx.id === 1) return + if (tx.id === 1) { + return + } assert.notEqual(tx.status, 'failed', 'other tx is not auto failed') }) diff --git a/test/unit/migrations/migrator-test.js b/test/unit/migrations/migrator-test.js index 3dcc5aff7971..9a949def4594 100644 --- a/test/unit/migrations/migrator-test.js +++ b/test/unit/migrations/migrator-test.js @@ -58,7 +58,9 @@ describe('Migrator', () => { it('should emit an error', function (done) { this.timeout(15000) - const migrator = new Migrator({ migrations: [{ version: 1, migrate: async () => { throw new Error('test') } } ] }) + const migrator = new Migrator({ migrations: [{ version: 1, migrate: async () => { + throw new Error('test') + } } ] }) migrator.on('error', () => done()) migrator.migrateData({ meta: {version: 0} }) .then(() => { diff --git a/test/unit/test-utils.js b/test/unit/test-utils.js index 7d0ae4d91a2c..de508c5046ca 100644 --- a/test/unit/test-utils.js +++ b/test/unit/test-utils.js @@ -10,7 +10,9 @@ async function assertRejects (asyncFn, regExp) { try { await asyncFn() } catch (error) { - f = () => { throw error } + f = () => { + throw error + } } finally { assert.throws(f, regExp) } diff --git a/test/unit/util_test.js b/test/unit/util_test.js index 87f57b218ef7..768288ce7d08 100644 --- a/test/unit/util_test.js +++ b/test/unit/util_test.js @@ -7,7 +7,9 @@ var util = require(path.join(__dirname, '..', '..', 'ui', 'app', 'helpers', 'uti describe('util', function () { var ethInWei = '1' - for (var i = 0; i < 18; i++) { ethInWei += '0' } + for (var i = 0; i < 18; i++) { + ethInWei += '0' + } beforeEach(function () { this.sinon = sinon.createSandbox() diff --git a/ui/app/components/app/dropdowns/components/menu.js b/ui/app/components/app/dropdowns/components/menu.js index 63501eaa964d..950ccccb7721 100644 --- a/ui/app/components/app/dropdowns/components/menu.js +++ b/ui/app/components/app/dropdowns/components/menu.js @@ -3,7 +3,9 @@ const Component = require('react').Component const h = require('react-hyperscript') inherits(Menu, Component) -function Menu () { Component.call(this) } +function Menu () { + Component.call(this) +} Menu.prototype.render = function () { const { className = '', children, isShowing } = this.props @@ -13,7 +15,9 @@ Menu.prototype.render = function () { } inherits(Item, Component) -function Item () { Component.call(this) } +function Item () { + Component.call(this) +} Item.prototype.render = function () { const { @@ -37,14 +41,18 @@ Item.prototype.render = function () { } inherits(Divider, Component) -function Divider () { Component.call(this) } +function Divider () { + Component.call(this) +} Divider.prototype.render = function () { return h('div.menu__divider') } inherits(CloseArea, Component) -function CloseArea () { Component.call(this) } +function CloseArea () { + Component.call(this) +} CloseArea.prototype.render = function () { return h('div.menu__close-area', { onClick: this.props.onClick }) diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index e6a24ef11648..d36f10d4069b 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -370,7 +370,9 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { const props = this.props const network = props.network - if (type !== 'rpc') return null + if (type !== 'rpc') { + return null + } switch (rpcTarget) { 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 419cae0cdb52..452544abe820 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 @@ -214,7 +214,9 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate tick: { values: [Math.floor(gasPrices[0]), Math.ceil(gasPricesMax)], outer: false, - format: function (val) { return val + ' GWEI' }, + format: function (val) { + return val + ' GWEI' + }, }, padding: {left: gasPricesMax / 50, right: gasPricesMax / 50}, label: { diff --git a/ui/app/components/app/input-number.js b/ui/app/components/app/input-number.js index 8a6ec725c386..ed678755f5f8 100644 --- a/ui/app/components/app/input-number.js +++ b/ui/app/components/app/input-number.js @@ -28,7 +28,9 @@ function removeLeadingZeroes (str) { InputNumber.prototype.setValue = function (newValue) { newValue = removeLeadingZeroes(newValue) - if (newValue && !isValidInput(newValue)) return + if (newValue && !isValidInput(newValue)) { + return + } const { fixed, min = -1, max = Infinity, onChange } = this.props newValue = fixed ? newValue.toFixed(4) : newValue diff --git a/ui/app/components/app/token-list.js b/ui/app/components/app/token-list.js index 000ca6b3f918..c15e86e1dc3a 100644 --- a/ui/app/components/app/token-list.js +++ b/ui/app/components/app/token-list.js @@ -105,7 +105,9 @@ TokenList.prototype.createFreshTokenTracker = function () { this.tracker.removeListener('error', this.showError) } - if (!global.ethereumProvider) return + if (!global.ethereumProvider) { + return + } const { userAddress } = this.props this.tracker = new TokenTracker({ @@ -154,7 +156,9 @@ TokenList.prototype.componentDidUpdate = function (prevProps) { const oldTokensLength = tokens ? tokens.length : 0 const tokensLengthUnchanged = oldTokensLength === newTokens.length - if (tokensLengthUnchanged && shouldUpdateTokens) return + if (tokensLengthUnchanged && shouldUpdateTokens) { + return + } this.setState({ isLoading: true }) this.createFreshTokenTracker() @@ -168,7 +172,9 @@ TokenList.prototype.updateBalances = function (tokens) { } TokenList.prototype.componentWillUnmount = function () { - if (!this.tracker) return + if (!this.tracker) { + return + } this.tracker.stop() this.tracker.removeListener('update', this.balanceUpdater) this.tracker.removeListener('error', this.showError) diff --git a/ui/app/components/ui/eth-balance.js b/ui/app/components/ui/eth-balance.js index 7d577b7162a3..63d0057c5410 100644 --- a/ui/app/components/ui/eth-balance.js +++ b/ui/app/components/ui/eth-balance.js @@ -43,8 +43,12 @@ EthBalanceComponent.prototype.render = function () { ) } EthBalanceComponent.prototype.renderBalance = function (value) { - if (value === 'None') return value - if (value === '...') return value + if (value === 'None') { + return value + } + if (value === '...') { + return value + } const { conversionRate, diff --git a/ui/app/components/ui/fiat-value.js b/ui/app/components/ui/fiat-value.js index 02111ba49dd4..cabdd479d972 100644 --- a/ui/app/components/ui/fiat-value.js +++ b/ui/app/components/ui/fiat-value.js @@ -17,7 +17,9 @@ FiatValue.prototype.render = function () { const value = formatBalance(props.value, 6) - if (value === 'None') return value + if (value === 'None') { + return value + } var fiatDisplayNumber, fiatTooltipNumber var splitBalance = value.split(' ') diff --git a/ui/app/components/ui/mascot.js b/ui/app/components/ui/mascot.js index 3b0d3e31b416..e54a464db501 100644 --- a/ui/app/components/ui/mascot.js +++ b/ui/app/components/ui/mascot.js @@ -46,7 +46,9 @@ Mascot.prototype.componentWillUnmount = function () { Mascot.prototype.handleAnimationEvents = function () { // only setup listeners once - if (this.animations) return + 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)) 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 01a2e7cf11cd..55797440fe87 100644 --- a/ui/app/components/ui/unit-input/unit-input.component.js +++ b/ui/app/components/ui/unit-input/unit-input.component.js @@ -91,7 +91,9 @@ export default class UnitInput extends PureComponent { onChange={this.handleChange} onBlur={this.handleBlur} style={{ width: this.getInputWidth(value) }} - ref={ref => { this.unitInput = ref }} + ref={ref => { + this.unitInput = ref + }} disabled={maxModeOn} /> { diff --git a/ui/app/ducks/index.js b/ui/app/ducks/index.js index 6808252ef554..f9c8821b0932 100644 --- a/ui/app/ducks/index.js +++ b/ui/app/ducks/index.js @@ -67,7 +67,9 @@ window.getCleanAppState = function () { window.logStateString = function (cb) { const state = window.getCleanAppState() global.platform.getPlatformInfo((err, platform) => { - if (err) return cb(err) + if (err) { + return cb(err) + } state.platform = platform const stateString = JSON.stringify(state, null, 2) cb(null, stateString) diff --git a/ui/app/helpers/utils/util.js b/ui/app/helpers/utils/util.js index 19aabb77084c..96557c62e8f3 100644 --- a/ui/app/helpers/utils/util.js +++ b/ui/app/helpers/utils/util.js @@ -73,13 +73,19 @@ function isEthNetwork (netId) { } function valuesFor (obj) { - if (!obj) return [] + if (!obj) { + return [] + } return Object.keys(obj) - .map(function (key) { return obj[key] }) + .map(function (key) { + return obj[key] + }) } function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includeHex = true) { - if (!address) return '' + if (!address) { + return '' + } let checked = checksumAddress(address) if (!includeHex) { checked = ethUtil.stripHexPrefix(checked) @@ -88,14 +94,18 @@ function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includ } function miniAddressSummary (address) { - if (!address) return '' + if (!address) { + return '' + } var checked = checksumAddress(address) return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...' } function isValidAddress (address) { var prefixed = ethUtil.addHexPrefix(address) - if (address === '0x0000000000000000000000000000000000000000') return false + if (address === '0x0000000000000000000000000000000000000000') { + return false + } return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed) } @@ -105,12 +115,16 @@ function isValidENSAddress (address) { function isInvalidChecksumAddress (address) { var prefixed = ethUtil.addHexPrefix(address) - if (address === '0x0000000000000000000000000000000000000000') return false + if (address === '0x0000000000000000000000000000000000000000') { + return false + } return !isAllOneCase(prefixed) && !ethUtil.isValidChecksumAddress(prefixed) && ethUtil.isValidAddress(prefixed) } function isAllOneCase (address) { - if (!address) return true + if (!address) { + return true + } var lower = address.toLowerCase() var upper = address.toUpperCase() return address === lower || address === upper @@ -118,7 +132,9 @@ function isAllOneCase (address) { // Takes wei Hex, returns wei BN, even if input is null function numericBalance (balance) { - if (!balance) return new ethUtil.BN(0, 16) + if (!balance) { + return new ethUtil.BN(0, 16) + } var stripped = ethUtil.stripHexPrefix(balance) return new ethUtil.BN(stripped, 16) } @@ -132,7 +148,9 @@ function parseBalance (balance) { beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0' afterDecimal = ('000000000000000000' + wei).slice(-18).replace(trailingZeros, '') - if (afterDecimal === '') { afterDecimal = '0' } + if (afterDecimal === '') { + afterDecimal = '0' + } return [beforeDecimal, afterDecimal] } @@ -147,7 +165,9 @@ function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ET if (beforeDecimal === '0') { if (afterDecimal !== '0') { var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits - if (sigFigs) { afterDecimal = sigFigs[0] } + if (sigFigs) { + afterDecimal = sigFigs[0] + } formatted = '0.' + afterDecimal + ` ${ticker}` } } else { diff --git a/ui/app/pages/confirm-transaction/confirm-transaction.component.js b/ui/app/pages/confirm-transaction/confirm-transaction.component.js index 9cb69e0da30e..eb87c57ba7b1 100644 --- a/ui/app/pages/confirm-transaction/confirm-transaction.component.js +++ b/ui/app/pages/confirm-transaction/confirm-transaction.component.js @@ -75,7 +75,9 @@ export default class ConfirmTransaction extends Component { getTokenParams(to) } const txId = transactionId || paramsTransactionId - if (txId) this.props.setTransactionToConfirm(txId) + if (txId) { + this.props.setTransactionToConfirm(txId) + } if (trackABTest) { this.context.metricsEvent({ diff --git a/ui/app/pages/create-account/connect-hardware/connect-screen.js b/ui/app/pages/create-account/connect-hardware/connect-screen.js index 3b45e729363e..b1323b46762d 100644 --- a/ui/app/pages/create-account/connect-hardware/connect-screen.js +++ b/ui/app/pages/create-account/connect-hardware/connect-screen.js @@ -104,7 +104,9 @@ class ConnectScreen extends Component { scrollToTutorial = () => { - if (this.referenceNode) this.referenceNode.scrollIntoView({behavior: 'smooth'}) + if (this.referenceNode) { + this.referenceNode.scrollIntoView({behavior: 'smooth'}) + } } renderLearnMore () { @@ -141,7 +143,9 @@ class ConnectScreen extends Component { ] return h('.hw-tutorial', { - ref: node => { this.referenceNode = node }, + ref: node => { + this.referenceNode = node + }, }, steps.map((step) => ( h('div.hw-connect', {}, [ diff --git a/ui/app/pages/mobile-sync/index.js b/ui/app/pages/mobile-sync/index.js index bd2385808820..078d2a5f641a 100644 --- a/ui/app/pages/mobile-sync/index.js +++ b/ui/app/pages/mobile-sync/index.js @@ -170,7 +170,9 @@ class MobileSyncPage extends Component { } async startSyncing () { - if (this.syncing) return false + if (this.syncing) { + return false + } this.syncing = true this.setState({syncing: true}) diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index 01e61b1b4bbe..45da4d0970ba 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -261,7 +261,9 @@ class Routes extends Component { if (!this.props.isUnlocked) { // currently inactive: redirect to password box var passwordBox = document.querySelector('input[type=password]') - if (!passwordBox) return + if (!passwordBox) { + return + } passwordBox.focus() } else { // currently active: deactivate diff --git a/ui/app/pages/send/send-content/add-recipient/ens-input.component.js b/ui/app/pages/send/send-content/add-recipient/ens-input.component.js index 8f8023fd05dd..5294388ac615 100644 --- a/ui/app/pages/send/send-content/add-recipient/ens-input.component.js +++ b/ui/app/pages/send/send-content/add-recipient/ens-input.component.js @@ -86,8 +86,12 @@ export default class EnsInput extends Component { log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient) .then((address) => { - if (address === ZERO_ADDRESS) throw new Error(this.context.t('noAddressForName')) - if (address === ZERO_X_ERROR_ADDRESS) throw new Error(this.context.t('ensRegistrationError')) + if (address === ZERO_ADDRESS) { + throw new Error(this.context.t('noAddressForName')) + } + if (address === ZERO_X_ERROR_ADDRESS) { + throw new Error(this.context.t('ensRegistrationError')) + } this.props.updateEnsResolution(address) }) .catch((reason) => { @@ -232,7 +236,9 @@ export default class EnsInput extends Component { ensIconContents () { const { loadingEns, ensFailure, ensResolution, toError } = this.state || { ensResolution: ZERO_ADDRESS } - if (toError) return + if (toError) { + return + } if (loadingEns) { return ( diff --git a/ui/app/pages/send/send.component.js b/ui/app/pages/send/send.component.js index d699e27a7104..e348e283bea1 100644 --- a/ui/app/pages/send/send.component.js +++ b/ui/app/pages/send/send.component.js @@ -304,7 +304,9 @@ export default class SendTransactionScreen extends PersistentForm { }} onChange={this.onRecipientInputChange} onValidAddressTyped={(address) => this.props.updateSendTo(address, '')} - onPaste={text => { this.props.updateSendTo(text) && this.updateGas() }} + onPaste={text => { + this.props.updateSendTo(text) && this.updateGas() + }} onReset={() => this.props.updateSendTo('', '')} updateEnsResolution={this.props.updateSendEnsResolution} updateEnsResolutionError={this.props.updateSendEnsResolutionError} diff --git a/ui/app/pages/send/send.utils.js b/ui/app/pages/send/send.utils.js index 89513bfc11ef..aef9c7e78115 100644 --- a/ui/app/pages/send/send.utils.js +++ b/ui/app/pages/send/send.utils.js @@ -293,18 +293,24 @@ function addGasBuffer (initialGasLimitHex, blockGasLimitHex, bufferMultiplier = if (conversionGreaterThan( { value: initialGasLimitHex, fromNumericBase: 'hex' }, { value: upperGasLimit, fromNumericBase: 'hex' }, - )) return initialGasLimitHex + )) { + return initialGasLimitHex + } // if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit if (conversionLessThan( { value: bufferedGasLimit, fromNumericBase: 'hex' }, { value: upperGasLimit, fromNumericBase: 'hex' }, - )) return bufferedGasLimit + )) { + return bufferedGasLimit + } // otherwise use blockGasLimit return upperGasLimit } function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', selectedToken }) { - if (!selectedToken) return + if (!selectedToken) { + return + } return TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call( abi.rawEncode(['address', 'uint256'], [toAddress, ethUtil.addHexPrefix(amount)]), x => ('00' + x.toString(16)).slice(-2) diff --git a/ui/app/pages/send/tests/send-utils.test.js b/ui/app/pages/send/tests/send-utils.test.js index 4930b7ee1934..9f6a01ad571b 100644 --- a/ui/app/pages/send/tests/send-utils.test.js +++ b/ui/app/pages/send/tests/send-utils.test.js @@ -18,8 +18,12 @@ const { const stubs = { addCurrencies: sinon.stub().callsFake((a, b) => { - if (String(a).match(/^0x.+/)) a = Number(String(a).slice(2)) - if (String(b).match(/^0x.+/)) b = Number(String(b).slice(2)) + if (String(a).match(/^0x.+/)) { + a = Number(String(a).slice(2)) + } + if (String(b).match(/^0x.+/)) { + b = Number(String(b).slice(2)) + } return a + b }), conversionUtil: sinon.stub().callsFake((val) => parseInt(val, 16)), diff --git a/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js b/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js index 56d4415cf5fb..9e3bc791bb0a 100644 --- a/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js +++ b/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js @@ -63,7 +63,9 @@ export default class AddContact extends PureComponent { return ( { this.props.scanQrCode() }} + scanQrCode={_ => { + this.props.scanQrCode() + }} onChange={this.dValidate} onPaste={text => this.setState({ ethAddress: text })} onReset={() => this.setState({ ethAddress: '', ensAddress: '' })} diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index f760245901cf..e694cfeffd11 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -675,7 +675,9 @@ function addNewKeyring (type, opts) { log.debug(`background.addNewKeyring`) background.addNewKeyring(type, opts, (err) => { dispatch(actions.hideLoadingIndication()) - if (err) return dispatch(actions.displayWarning(err.message)) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } dispatch(actions.showAccountsPage()) }) } @@ -2288,7 +2290,9 @@ function pairUpdate (coin) { dispatch(actions.hideWarning()) shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => { dispatch(actions.hideSubLoadingIndication()) - if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error)) + if (mktResponse.error) { + return dispatch(actions.displayWarning(mktResponse.error)) + } dispatch({ type: actions.PAIR_UPDATE, value: { @@ -2306,7 +2310,9 @@ function shapeShiftSubview () { shapeShiftRequest('marketinfo', {pair}, (mktResponse) => { shapeShiftRequest('getcoins', {}, (response) => { dispatch(actions.hideSubLoadingIndication()) - if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error)) + if (mktResponse.error) { + return dispatch(actions.displayWarning(mktResponse.error)) + } dispatch({ type: actions.SHAPESHIFT_SUBVIEW, value: { @@ -2324,7 +2330,9 @@ function coinShiftRquest (data, marketData) { dispatch(actions.showLoadingIndication()) shapeShiftRequest('shift', { method: 'POST', data}, (response) => { dispatch(actions.hideLoadingIndication()) - if (response.error) return dispatch(actions.displayWarning(response.error)) + if (response.error) { + return dispatch(actions.displayWarning(response.error)) + } var message = ` Deposit your ${response.depositType} to the address below:` log.debug(`background.createShapeShiftTx`) @@ -2359,7 +2367,9 @@ function reshowQrCode (data, coin) { return (dispatch) => { dispatch(actions.showLoadingIndication()) shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => { - if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error)) + if (mktResponse.error) { + return dispatch(actions.displayWarning(mktResponse.error)) + } var message = [ `Deposit your ${coin} to the address below:`, diff --git a/ui/index.js b/ui/index.js index 058c09be0b6b..5b268b7b0551 100644 --- a/ui/index.js +++ b/ui/index.js @@ -17,7 +17,9 @@ function launchMetamaskUi (opts, cb) { actions._setBackgroundConnection(backgroundConnection) // check if we are unlocked first backgroundConnection.getState(function (err, metamaskState) { - if (err) return cb(err) + if (err) { + return cb(err) + } startApp(metamaskState, backgroundConnection, opts) .then((store) => { cb(null, store) @@ -27,7 +29,9 @@ function launchMetamaskUi (opts, cb) { async function startApp (metamaskState, backgroundConnection, opts) { // parse opts - if (!metamaskState.featureFlags) metamaskState.featureFlags = {} + if (!metamaskState.featureFlags) { + metamaskState.featureFlags = {} + } const currentLocaleMessages = metamaskState.currentLocale ? await fetchLocale(metamaskState.currentLocale) From a8be9ae42be3e0421114f7393dbf4863808f262a Mon Sep 17 00:00:00 2001 From: Antonio Savage Date: Wed, 20 Nov 2019 08:42:36 -0600 Subject: [PATCH 03/88] Fix link on root README.md (#7480) --- CHANGELOG.md | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02d6a0b6477b..a37d5c989bac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Current Develop Branch +- [#7480](https://github.com/MetaMask/metamask-extension/pull/7480): Fixed link on root README.md ## 7.6.1 Tue Nov 19 2019 - [#7475](https://github.com/MetaMask/metamask-extension/pull/7475): Add 'Remind Me Later' to the Maker notification diff --git a/README.md b/README.md index 08d7e3a74f51..c1db416e3065 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,6 @@ To write tests that will be run in the browser using QUnit, add your test files - [How to add new networks to the Provider Menu](./docs/adding-new-networks.md) - [How to port MetaMask to a new platform](./docs/porting_to_new_environment.md) - [How to use the TREZOR emulator](./docs/trezor-emulator.md) -- [How to generate a visualization of this repository's development](./docs/development-visualization.md) +- [How to generate a visualization of this repository's development](./development/gource-viz.sh) [1]: http://www.nomnoml.com/#view/%5B%3Cactor%3Euser%5D%0A%0A%5Bmetamask-ui%7C%0A%20%20%20%5Btools%7C%0A%20%20%20%20%20react%0A%20%20%20%20%20redux%0A%20%20%20%20%20thunk%0A%20%20%20%20%20ethUtils%0A%20%20%20%20%20jazzicon%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20account-detail%0A%20%20%20%20%20accounts%0A%20%20%20%20%20locked-screen%0A%20%20%20%20%20restore-vault%0A%20%20%20%20%20identicon%0A%20%20%20%20%20config%0A%20%20%20%20%20info%0A%20%20%20%5D%0A%20%20%20%5Breducers%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20metamask%0A%20%20%20%20%20identities%0A%20%20%20%5D%0A%20%20%20%5Bactions%7C%0A%20%20%20%20%20%5BbackgroundConnection%5D%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%5D%3A-%3E%5Bactions%5D%0A%20%20%20%5Bactions%5D%3A-%3E%5Breducers%5D%0A%20%20%20%5Breducers%5D%3A-%3E%5Bcomponents%5D%0A%5D%0A%0A%5Bweb%20dapp%7C%0A%20%20%5Bui%20code%5D%0A%20%20%5Bweb3%5D%0A%20%20%5Bmetamask-inpage%5D%0A%20%20%0A%20%20%5B%3Cactor%3Eui%20developer%5D%0A%20%20%5Bui%20developer%5D-%3E%5Bui%20code%5D%0A%20%20%5Bui%20code%5D%3C-%3E%5Bweb3%5D%0A%20%20%5Bweb3%5D%3C-%3E%5Bmetamask-inpage%5D%0A%5D%0A%0A%5Bmetamask-background%7C%0A%20%20%5Bprovider-engine%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bid%20store%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%3E%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%3C-%3E%5Bid%20store%5D%0A%20%20%5Bconfig%20manager%7C%0A%20%20%20%20%5Brpc%20configuration%5D%0A%20%20%20%20%5Bencrypted%20keys%5D%0A%20%20%20%20%5Bwallet%20nicknames%5D%0A%20%20%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%5Bconfig%20manager%5D%0A%20%20%5Bid%20store%5D%3C-%3E%5Bconfig%20manager%5D%0A%5D%0A%0A%5Buser%5D%3C-%3E%5Bmetamask-ui%5D%0A%0A%5Buser%5D%3C%3A--%3A%3E%5Bweb%20dapp%5D%0A%0A%5Bmetamask-contentscript%7C%0A%20%20%5Bplugin%20restart%20detector%5D%0A%20%20%5Brpc%20passthrough%5D%0A%5D%0A%0A%5Brpc%20%7C%0A%20%20%5Bethereum%20blockchain%20%7C%0A%20%20%20%20%5Bcontracts%5D%0A%20%20%20%20%5Baccounts%5D%0A%20%20%5D%0A%5D%0A%0A%5Bweb%20dapp%5D%3C%3A--%3A%3E%5Bmetamask-contentscript%5D%0A%5Bmetamask-contentscript%5D%3C-%3E%5Bmetamask-background%5D%0A%5Bmetamask-background%5D%3C-%3E%5Bmetamask-ui%5D%0A%5Bmetamask-background%5D%3C-%3E%5Brpc%5D%0A From 71a0bc8b3ff94478e61294c815770e6bc12a72f5 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Wed, 20 Nov 2019 18:03:49 -0400 Subject: [PATCH 04/88] Refactor signature-request-original (#7415) The component has been updated to split the container from the base component, and all hyperscript has been replaced with JSX. ES6 imports are used throughout as well. --- .../app/signature-request-original.js | 357 ------------------ .../app/signature-request-original/index.js | 1 + .../signature-request-original.component.js | 318 ++++++++++++++++ .../signature-request-original.container.js | 72 ++++ ui/app/pages/confirm-transaction/conf-tx.js | 2 +- 5 files changed, 392 insertions(+), 358 deletions(-) delete mode 100644 ui/app/components/app/signature-request-original.js create mode 100644 ui/app/components/app/signature-request-original/index.js create mode 100644 ui/app/components/app/signature-request-original/signature-request-original.component.js create mode 100644 ui/app/components/app/signature-request-original/signature-request-original.container.js diff --git a/ui/app/components/app/signature-request-original.js b/ui/app/components/app/signature-request-original.js deleted file mode 100644 index e23d724cb7fa..000000000000 --- a/ui/app/components/app/signature-request-original.js +++ /dev/null @@ -1,357 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums' -import { getEnvironmentType } from '../../../../app/scripts/lib/util' -import Identicon from '../ui/identicon' -const connect = require('react-redux').connect -const ethUtil = require('ethereumjs-util') -const classnames = require('classnames') -const { compose } = require('recompose') -const { withRouter } = require('react-router-dom') -const { ObjectInspector } = require('react-inspector') - -import AccountListItem from '../../pages/send/account-list-item/account-list-item.component' - -const actions = require('../../store/actions') -const { conversionUtil } = require('../../helpers/utils/conversion-util') - -const { - getSelectedAccount, - getCurrentAccountWithSendEtherInfo, - getSelectedAddress, - conversionRateSelector, -} = require('../../selectors/selectors.js') - -import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck' -import Button from '../ui/button' - -const { DEFAULT_ROUTE } = require('../../helpers/constants/routes') - -function mapStateToProps (state) { - return { - balance: getSelectedAccount(state).balance, - selectedAccount: getCurrentAccountWithSendEtherInfo(state), - selectedAddress: getSelectedAddress(state), - requester: null, - requesterAddress: null, - conversionRate: conversionRateSelector(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - goHome: () => dispatch(actions.goHome()), - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - } -} - -function mergeProps (stateProps, dispatchProps, ownProps) { - const { - signPersonalMessage, - signTypedMessage, - cancelPersonalMessage, - cancelTypedMessage, - signMessage, - cancelMessage, - txData, - } = ownProps - - const { type } = txData - - let cancel - let sign - if (type === 'personal_sign') { - cancel = cancelPersonalMessage - sign = signPersonalMessage - } else if (type === 'eth_signTypedData') { - cancel = cancelTypedMessage - sign = signTypedMessage - } else if (type === 'eth_sign') { - cancel = cancelMessage - sign = signMessage - } - - return { - ...ownProps, - ...stateProps, - ...dispatchProps, - txData, - cancel, - sign, - } -} - -SignatureRequest.contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, -} - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps, mergeProps) -)(SignatureRequest) - - -inherits(SignatureRequest, Component) -function SignatureRequest (props) { - Component.call(this) - - this.state = { - selectedAccount: props.selectedAccount, - } - this._beforeUnload = this._beforeUnload.bind(this) -} - -SignatureRequest.prototype._beforeUnload = function (event) { - const { clearConfirmTransaction, cancel } = this.props - const { metricsEvent } = this.context - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Sign Request', - name: 'Cancel Sig Request Via Notification Close', - }, - }) - clearConfirmTransaction() - cancel(event) -} - -SignatureRequest.prototype._removeBeforeUnload = function () { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { - window.removeEventListener('beforeunload', this._beforeUnload) - } -} - -SignatureRequest.prototype.componentDidMount = function () { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { - window.addEventListener('beforeunload', this._beforeUnload) - } -} - -SignatureRequest.prototype.componentWillUnmount = function () { - this._removeBeforeUnload() -} - -SignatureRequest.prototype.renderHeader = function () { - return h('div.request-signature__header', [ - - h('div.request-signature__header-background'), - - h('div.request-signature__header__text', this.context.t('sigRequest')), - - h('div.request-signature__header__tip-container', [ - h('div.request-signature__header__tip'), - ]), - - ]) -} - -SignatureRequest.prototype.renderAccount = function () { - const { selectedAccount } = this.state - - return h('div.request-signature__account', [ - - h('div.request-signature__account-text', [this.context.t('account') + ':']), - - h('div.request-signature__account-item', [ - h(AccountListItem, { - account: selectedAccount, - displayBalance: false, - }), - ]), - ]) -} - -SignatureRequest.prototype.renderBalance = function () { - const { balance, conversionRate } = this.props - - const balanceInEther = conversionUtil(balance, { - fromNumericBase: 'hex', - toNumericBase: 'dec', - fromDenomination: 'WEI', - numberOfDecimals: 6, - conversionRate, - }) - - return h('div.request-signature__balance', [ - - h('div.request-signature__balance-text', `${this.context.t('balance')}:`), - - h('div.request-signature__balance-value', `${balanceInEther} ETH`), - - ]) -} - -SignatureRequest.prototype.renderAccountInfo = function () { - return h('div.request-signature__account-info', [ - - this.renderAccount(), - - this.renderRequestIcon(), - - this.renderBalance(), - - ]) -} - -SignatureRequest.prototype.renderRequestIcon = function () { - const { requesterAddress } = this.props - - return h('div.request-signature__request-icon', [ - h(Identicon, { - diameter: 40, - address: requesterAddress, - }), - ]) -} - -SignatureRequest.prototype.renderRequestInfo = function () { - return h('div.request-signature__request-info', [ - - h('div.request-signature__headline', [ - this.context.t('yourSigRequested'), - ]), - - ]) -} - -SignatureRequest.prototype.msgHexToText = function (hex) { - try { - const stripped = ethUtil.stripHexPrefix(hex) - const buff = Buffer.from(stripped, 'hex') - return buff.length === 32 ? hex : buff.toString('utf8') - } catch (e) { - return hex - } -} - -// eslint-disable-next-line react/display-name -SignatureRequest.prototype.renderTypedData = function (data) { - const { domain, message } = JSON.parse(data) - return [ - h('div.request-signature__typed-container', [ - domain ? h('div', [ - h('h1', 'Domain'), - h(ObjectInspector, { data: domain, expandLevel: 1, name: 'domain' }), - ]) : '', - message ? h('div', [ - h('h1', 'Message'), - h(ObjectInspector, { data: message, expandLevel: 1, name: 'message' }), - ]) : '', - ]), - ] -} - -SignatureRequest.prototype.renderBody = function () { - let rows - let notice = this.context.t('youSign') + ':' - - const { txData } = this.props - const { type, msgParams: { data } } = txData - - if (type === 'personal_sign') { - rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }] - } else if (type === 'eth_signTypedData') { - rows = data - } else if (type === 'eth_sign') { - rows = [{ name: this.context.t('message'), value: data }] - notice = [this.context.t('signNotice'), - h('span.request-signature__help-link', { - onClick: () => { - global.platform.openWindow({ - url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751', - }) - }, - }, this.context.t('learnMore'))] - } - - return h('div.request-signature__body', {}, [ - - this.renderAccountInfo(), - - this.renderRequestInfo(), - - h('div.request-signature__notice', { - className: classnames({ - 'request-signature__notice': type === 'personal_sign' || type === 'eth_signTypedData', - 'request-signature__warning': type === 'eth_sign', - }), - }, [notice]), - - h('div.request-signature__rows', - rows.map(({ name, value }, index) => { - if (typeof value === 'boolean') { - value = value.toString() - } - return h('div.request-signature__row', { key: `request-signature-row-${index}` }, [ - h('div.request-signature__row-title', [`${name}:`]), - h('div.request-signature__row-value', value), - ]) - }) - ), - ]) -} - -SignatureRequest.prototype.renderFooter = function () { - const { cancel, sign } = this.props - - return h('div.request-signature__footer', [ - h(Button, { - type: 'default', - large: true, - className: 'request-signature__footer__cancel-button', - onClick: event => { - this._removeBeforeUnload() - cancel(event).then(() => { - this.context.metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Sign Request', - name: 'Cancel', - }, - }) - this.props.clearConfirmTransaction() - this.props.history.push(DEFAULT_ROUTE) - }) - }, - }, this.context.t('cancel')), - h(Button, { - type: 'secondary', - large: true, - className: 'request-signature__footer__sign-button', - onClick: event => { - this._removeBeforeUnload() - sign(event).then(() => { - this.context.metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Sign Request', - name: 'Confirm', - }, - }) - this.props.clearConfirmTransaction() - this.props.history.push(DEFAULT_ROUTE) - }) - }, - }, this.context.t('sign')), - ]) -} - -SignatureRequest.prototype.render = function () { - return ( - - h('div.request-signature__container', [ - - this.renderHeader(), - - this.renderBody(), - - this.renderFooter(), - - ]) - - ) - -} diff --git a/ui/app/components/app/signature-request-original/index.js b/ui/app/components/app/signature-request-original/index.js new file mode 100644 index 000000000000..00a90678574e --- /dev/null +++ b/ui/app/components/app/signature-request-original/index.js @@ -0,0 +1 @@ +export { default } from './signature-request-original.container' 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 new file mode 100644 index 000000000000..2485ae5068f4 --- /dev/null +++ b/ui/app/components/app/signature-request-original/signature-request-original.component.js @@ -0,0 +1,318 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ethUtil from 'ethereumjs-util' +import classnames from 'classnames' +import { ObjectInspector } from 'react-inspector' + +import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../../app/scripts/lib/enums' +import { getEnvironmentType } from '../../../../../app/scripts/lib/util' +import Identicon from '../../ui/identicon' +import AccountListItem from '../../../pages/send/account-list-item/account-list-item.component' +import { conversionUtil } from '../../../helpers/utils/conversion-util' +import Button from '../../ui/button' +import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' + +export default class SignatureRequestOriginal extends Component { + static contextTypes = { + t: PropTypes.func.isRequired, + metricsEvent: PropTypes.func.isRequired, + } + + static propTypes = { + balance: PropTypes.string, + cancel: PropTypes.func.isRequired, + clearConfirmTransaction: PropTypes.func.isRequired, + conversionRate: PropTypes.number, + history: PropTypes.object.isRequired, + requesterAddress: PropTypes.string, + selectedAccount: PropTypes.string, + sign: PropTypes.func.isRequired, + txData: PropTypes.object.isRequired, + } + + state = { + selectedAccount: this.props.selectedAccount, + } + + componentDidMount = () => { + if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { + window.addEventListener('beforeunload', this._beforeUnload) + } + } + + componentWillUnmount = () => { + this._removeBeforeUnload() + } + + _beforeUnload = (event) => { + const { clearConfirmTransaction, cancel } = this.props + const { metricsEvent } = this.context + metricsEvent({ + eventOpts: { + category: 'Transactions', + action: 'Sign Request', + name: 'Cancel Sig Request Via Notification Close', + }, + }) + clearConfirmTransaction() + cancel(event) + } + + _removeBeforeUnload = () => { + if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { + window.removeEventListener('beforeunload', this._beforeUnload) + } + } + + renderHeader = () => { + return ( +
+
+ +
+ { this.context.t('sigRequest') } +
+ +
+
+
+
+ ) + } + + renderAccount = () => { + const { selectedAccount } = this.state + + return ( +
+
+ { `${this.context.t('account')}:` } +
+ +
+ +
+
+ ) + } + + renderBalance = () => { + const { balance, conversionRate } = this.props + + const balanceInEther = conversionUtil(balance, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + fromDenomination: 'WEI', + numberOfDecimals: 6, + conversionRate, + }) + + return ( +
+
+ { `${this.context.t('balance')}:` } +
+
+ { `${balanceInEther} ETH` } +
+
+ ) + } + + renderRequestIcon = () => { + const { requesterAddress } = this.props + + return ( +
+ +
+ ) + } + + renderAccountInfo = () => { + return ( +
+ { this.renderAccount() } + { this.renderRequestIcon() } + { this.renderBalance() } +
+ ) + } + + renderRequestInfo = () => { + return ( +
+
+ { this.context.t('yourSigRequested') } +
+
+ ) + } + + msgHexToText = (hex) => { + try { + const stripped = ethUtil.stripHexPrefix(hex) + const buff = Buffer.from(stripped, 'hex') + return buff.length === 32 ? hex : buff.toString('utf8') + } catch (e) { + return hex + } + } + + renderTypedData = (data) => { + const { domain, message } = JSON.parse(data) + return ( +
+ { + domain + ?
+

+ Domain +

+ +
+ : '' + } + { + message + ?
+

+ Message +

+ +
+ : '' + } +
+ ) + } + + renderBody = () => { + let rows + let notice = `${this.context.t('youSign')}:` + + const { txData } = this.props + const { type, msgParams: { data } } = txData + + if (type === 'personal_sign') { + rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }] + } else if (type === 'eth_signTypedData') { + rows = data + } else if (type === 'eth_sign') { + rows = [{ name: this.context.t('message'), value: data }] + notice = this.context.t('signNotice') + } + + return ( +
+ { this.renderAccountInfo() } + { this.renderRequestInfo() } +
+ { notice } + { + type === 'eth_sign' + ? { + global.platform.openWindow({ + url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751', + }) + }} + > + { this.context.t('learnMore') } + + : null + } +
+
+ { + rows.map(({ name, value }, index) => { + if (typeof value === 'boolean') { + value = value.toString() + } + return ( +
+
+ { `${name}:` } +
+
+ { value } +
+
+ ) + }) + } +
+
+ ) + } + + renderFooter = () => { + const { cancel, sign } = this.props + + return ( +
+ , + +
+ ) + } + + render = () => { + return ( +
+ { 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 new file mode 100644 index 000000000000..be891b4dbe7f --- /dev/null +++ b/ui/app/components/app/signature-request-original/signature-request-original.container.js @@ -0,0 +1,72 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' + +import actions from '../../../store/actions' +import { + getSelectedAccount, + getCurrentAccountWithSendEtherInfo, + getSelectedAddress, + conversionRateSelector, +} from '../../../selectors/selectors.js' +import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck' +import SignatureRequestOriginal from './signature-request-original.component' + +function mapStateToProps (state) { + return { + balance: getSelectedAccount(state).balance, + selectedAccount: getCurrentAccountWithSendEtherInfo(state), + selectedAddress: getSelectedAddress(state), + requester: null, + requesterAddress: null, + conversionRate: conversionRateSelector(state), + } +} + +function mapDispatchToProps (dispatch) { + return { + goHome: () => dispatch(actions.goHome()), + clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), + } +} + +function mergeProps (stateProps, dispatchProps, ownProps) { + const { + signPersonalMessage, + signTypedMessage, + cancelPersonalMessage, + cancelTypedMessage, + signMessage, + cancelMessage, + txData, + } = ownProps + + const { type } = txData + + let cancel + let sign + if (type === 'personal_sign') { + cancel = cancelPersonalMessage + sign = signPersonalMessage + } else if (type === 'eth_signTypedData') { + cancel = cancelTypedMessage + sign = signTypedMessage + } else if (type === 'eth_sign') { + cancel = cancelMessage + sign = signMessage + } + + return { + ...ownProps, + ...stateProps, + ...dispatchProps, + txData, + cancel, + sign, + } +} + +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps, mergeProps) +)(SignatureRequestOriginal) diff --git a/ui/app/pages/confirm-transaction/conf-tx.js b/ui/app/pages/confirm-transaction/conf-tx.js index ce1edde5ceee..79d7f5e4f30d 100644 --- a/ui/app/pages/confirm-transaction/conf-tx.js +++ b/ui/app/pages/confirm-transaction/conf-tx.js @@ -10,7 +10,7 @@ const log = require('loglevel') const R = require('ramda') const SignatureRequest = require('../../components/app/signature-request').default -const SignatureRequestOriginal = require('../../components/app/signature-request-original') +const SignatureRequestOriginal = require('../../components/app/signature-request-original').default const Loading = require('../../components/ui/loading-screen') const { DEFAULT_ROUTE } = require('../../helpers/constants/routes') From ff12d0572739d80faadac690e10b46ef8331ed2b Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Thu, 21 Nov 2019 18:09:29 -0330 Subject: [PATCH 05/88] Remove stray periods from settings tabs descriptions (#7489) --- app/_locales/bg/messages.json | 4 ++-- app/_locales/ca/messages.json | 4 ++-- app/_locales/da/messages.json | 4 ++-- app/_locales/de/messages.json | 4 ++-- app/_locales/el/messages.json | 4 ++-- app/_locales/en/messages.json | 4 ++-- app/_locales/es_419/messages.json | 4 ++-- app/_locales/et/messages.json | 4 ++-- app/_locales/fi/messages.json | 4 ++-- app/_locales/fil/messages.json | 4 ++-- app/_locales/fr/messages.json | 4 ++-- app/_locales/hr/messages.json | 4 ++-- app/_locales/hu/messages.json | 4 ++-- app/_locales/id/messages.json | 4 ++-- app/_locales/it/messages.json | 4 ++-- app/_locales/kn/messages.json | 4 ++-- app/_locales/ko/messages.json | 4 ++-- app/_locales/lt/messages.json | 4 ++-- app/_locales/lv/messages.json | 2 +- app/_locales/ms/messages.json | 4 ++-- app/_locales/no/messages.json | 4 ++-- app/_locales/pl/messages.json | 4 ++-- app/_locales/pt_BR/messages.json | 4 ++-- app/_locales/ro/messages.json | 4 ++-- app/_locales/sk/messages.json | 4 ++-- app/_locales/sl/messages.json | 4 ++-- app/_locales/sr/messages.json | 4 ++-- app/_locales/sv/messages.json | 4 ++-- app/_locales/sw/messages.json | 4 ++-- app/_locales/uk/messages.json | 4 ++-- 30 files changed, 59 insertions(+), 59 deletions(-) diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 799214110c38..f5fdc0f0e807 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -27,7 +27,7 @@ "message": "Информация" }, "aboutSettingsDescription": { - "message": "Версия, център за поддръжка и информация за контакт." + "message": "Версия, център за поддръжка и информация за контакт" }, "acceleratingATransaction": { "message": "* Ускоряването на транзакция чрез използване на по-висока цена на газа увеличава шансовете й да се обработва по-бързо от мрежата, но това не винаги е гарантирано." @@ -63,7 +63,7 @@ "message": "Разширени" }, "advancedSettingsDescription": { - "message": "Достъп до функции за разработчици, изтегляйте дневници, нулиране на акаунта, тестови мрежи за настройка и персонализиран RPC." + "message": "Достъп до функции за разработчици, изтегляйте дневници, нулиране на акаунта, тестови мрежи за настройка и персонализиран RPC" }, "advancedOptions": { "message": "Разширени опции" diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 599cb84ad967..3524181e3968 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -27,7 +27,7 @@ "message": "Informació" }, "aboutSettingsDescription": { - "message": "Versió, centre de suport, i informació de contacte." + "message": "Versió, centre de suport, i informació de contacte" }, "acceleratingATransaction": { "message": "* Accelerar una transacció utilitzant un preu de gas més alt augmenta les possibilitats de ser processat més ràpidament per la xarxa, però no sempre es pot garantir." @@ -63,7 +63,7 @@ "message": "Configuració avançada" }, "advancedSettingsDescription": { - "message": "Accedeix a característiques de desenvolupador, descarrega Registres d'Estat, Reinicia el Compte, instal·la testnets i personalitza RPC." + "message": "Accedeix a característiques de desenvolupador, descarrega Registres d'Estat, Reinicia el Compte, instal·la testnets i personalitza RPC" }, "advancedOptions": { "message": "Opcions Avançades" diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 5a2c3c100cdb..75081340e4d5 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -27,7 +27,7 @@ "message": "Om" }, "aboutSettingsDescription": { - "message": "Version, supportcenter og kontaktinformation." + "message": "Version, supportcenter og kontaktinformation" }, "acceleratingATransaction": { "message": "* At gøre din transaktion hurtigere ved at bruge en højere Gas-priser, øger dennes chancer for at blive behandlet af netværket hurtigere, men det er ikke altid garanteret." @@ -63,7 +63,7 @@ "message": "Avanceret" }, "advancedSettingsDescription": { - "message": "Få adgang til udviklerfunktioner, hent tilstandslogs, nulstil konto, opsæt testnetværk og brugerdefineret RPC." + "message": "Få adgang til udviklerfunktioner, hent tilstandslogs, nulstil konto, opsæt testnetværk og brugerdefineret RPC" }, "advancedOptions": { "message": "Avancerede Valgmuligheder" diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 5f241ab05079..b0dc2967d25e 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -27,7 +27,7 @@ "message": "Über" }, "aboutSettingsDescription": { - "message": "Version, Supportcenter und Kontaktinformationen." + "message": "Version, Supportcenter und Kontaktinformationen" }, "acceleratingATransaction": { "message": "* Die Beschleunigung einer Transaktion durch die Verwendung eines höheren Gaspreises erhöht die Chancen einer schnelleren Verarbeitung durch das Netz, wofür es allerdings keine Garantie gibt." @@ -60,7 +60,7 @@ "message": "Erweitert" }, "advancedSettingsDescription": { - "message": "Zugriff auf Entwicklerfunktionen, Download von Statusprotokollen, Zurücksetzen des Kontos, Einrichten von Testnetzen und benutzerdefinierten RPCs." + "message": "Zugriff auf Entwicklerfunktionen, Download von Statusprotokollen, Zurücksetzen des Kontos, Einrichten von Testnetzen und benutzerdefinierten RPCs" }, "advancedOptions": { "message": "Erweiterte Optionen" diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 126b9133fea9..a8dd4eb0e437 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -27,7 +27,7 @@ "message": "Σχετικά με" }, "aboutSettingsDescription": { - "message": "Έκδοση, κέντρο υποστήριξης και πληροφορίες επικοινωνίας." + "message": "Έκδοση, κέντρο υποστήριξης και πληροφορίες επικοινωνίας" }, "acceleratingATransaction": { "message": "* Η επιτάχυνση μιας συναλλαγής με τη χρήση υψηλότερης τιμής καυσίμου αυξάνει τις πιθανότητές της για ταχύτερη επεξεργασία από το δίκτυο, αλλά δεν είναι πάντοτε εγγυημένη." @@ -63,7 +63,7 @@ "message": "Σύνθετες" }, "advancedSettingsDescription": { - "message": "Αποκτήστε πρόσβαση στις λειτουργίες του προγραμματιστή, κατεβάστε Αρχεία Καταγραφών Καταστάσεων, Επαναφέρετε τον Λογαριασμό, εγκαταστήστε δοκιμαστικά δίκτυα και προσαρμοσμένα RPC." + "message": "Αποκτήστε πρόσβαση στις λειτουργίες του προγραμματιστή, κατεβάστε Αρχεία Καταγραφών Καταστάσεων, Επαναφέρετε τον Λογαριασμό, εγκαταστήστε δοκιμαστικά δίκτυα και προσαρμοσμένα RPC" }, "advancedOptions": { "message": "Σύνθετες Επιλογές" diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f947c9e5c5b0..2a060b1e44de 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -60,7 +60,7 @@ "message": "About" }, "aboutSettingsDescription": { - "message": "Version, support center, and contact info." + "message": "Version, support center, and contact info" }, "acceleratingATransaction": { "message": "* Accelerating a transaction by using a higher gas price increases its chances of getting processed by the network faster, but it is not always guaranteed." @@ -100,7 +100,7 @@ "message": "Advanced" }, "advancedSettingsDescription": { - "message": "Access developer features, download State Logs, Reset Account, setup testnets and custom RPC." + "message": "Access developer features, download State Logs, Reset Account, setup testnets and custom RPC" }, "advancedOptions": { "message": "Advanced Options" diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index c861be81b51d..ed8259e2beb1 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -27,7 +27,7 @@ "message": "Acerca de" }, "aboutSettingsDescription": { - "message": "Versión, centro de soporte técnico e información de contacto." + "message": "Versión, centro de soporte técnico e información de contacto" }, "acceleratingATransaction": { "message": "* Aumentar una transacción utilizando un precio de gas más alto aumenta sus posibilidades de ser procesada más rápido por la red, pero esto no siempre está garantizado." @@ -63,7 +63,7 @@ "message": "Avanzada" }, "advancedSettingsDescription": { - "message": "Accede a las funciones de desarrollador, descarga los registros de estado, restablece la cuenta, y configura las redes Testnet y el RPC personalizado." + "message": "Accede a las funciones de desarrollador, descarga los registros de estado, restablece la cuenta, y configura las redes Testnet y el RPC personalizado" }, "advancedOptions": { "message": "Opciones avanzadas" diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index c779dff85ea1..315b72fa79c6 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -27,7 +27,7 @@ "message": "Teave" }, "aboutSettingsDescription": { - "message": "Versioon, tugikeskus ja kontaktteave." + "message": "Versioon, tugikeskus ja kontaktteave" }, "acceleratingATransaction": { "message": "* Tehingu kiirendamine kõrgemate gaasihindadega suurendab võimalust kiiremaks võrgus töötlemiseks, kuid see ei ole alati tagatud." @@ -63,7 +63,7 @@ "message": "Täpsemad" }, "advancedSettingsDescription": { - "message": "Juurdepääs arendaja funktsioonidele, olekulogide allalaadimine, konto lähtestamine, testvõrkude ja kohandatud RPC-de seadistamine." + "message": "Juurdepääs arendaja funktsioonidele, olekulogide allalaadimine, konto lähtestamine, testvõrkude ja kohandatud RPC-de seadistamine" }, "advancedOptions": { "message": "Täpsemad suvandid" diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index df4f62a1912c..2123065f3623 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -27,7 +27,7 @@ "message": "Tietoja asetuksista" }, "aboutSettingsDescription": { - "message": "Versio, tukikeskus ja yhteystiedot." + "message": "Versio, tukikeskus ja yhteystiedot" }, "acceleratingATransaction": { "message": "* Tapahtuman nopeuttaminen käyttämällä korkeampaa gas-hintaa parantaa mahdollisuutta, että verkko käsittelee sen nopeammin, mutta tämä ei ole aina taattua." @@ -63,7 +63,7 @@ "message": "Lisäasetukset" }, "advancedSettingsDescription": { - "message": "Käytä kehittäjän ominaisuuksia, lataa tilalokeja, palauta tilit, asenna testiverkostoja ja muokattavia RPC:itä." + "message": "Käytä kehittäjän ominaisuuksia, lataa tilalokeja, palauta tilit, asenna testiverkostoja ja muokattavia RPC:itä" }, "advancedOptions": { "message": "Tarkemmat vaihtoehdot" diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index d0072681144a..b1183a7c4912 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -27,7 +27,7 @@ "message": "Tungkol sa" }, "aboutSettingsDescription": { - "message": "Bersyon, support center, at impormasyon sa pakikipag-ugnayan." + "message": "Bersyon, support center, at impormasyon sa pakikipag-ugnayan" }, "acceleratingATransaction": { "message": "* Ang pagpapabilis sa isang transaksyon sa pamamagitan ng paggamit ng mas mataas na presyo ng gas ay makakadagdag sa tsansa nitong maproseso ng network nang mas mabilis, pero hindi ito palaging garantisado." @@ -57,7 +57,7 @@ "message": "Magdagdag ng Recipient" }, "advancedSettingsDescription": { - "message": "I-access ang mga feature para sa mga developer, mag-download ng mga State Log, I-reset ang Account, mag-set up ng mga testnet at custom RPC." + "message": "I-access ang mga feature para sa mga developer, mag-download ng mga State Log, I-reset ang Account, mag-set up ng mga testnet at custom RPC" }, "advancedOptions": { "message": "Mga Advanced na Opsyon" diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 98ae1576bd09..1ec676542240 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -27,7 +27,7 @@ "message": "À propos" }, "aboutSettingsDescription": { - "message": "Version, centre d'assistance et coordonnées." + "message": "Version, centre d'assistance et coordonnées" }, "acceleratingATransaction": { "message": "* Accélérer une transaction en utilisant un prix de l'essence plus élevé augmente ses chances d'être traitée plus rapidement par le réseau, mais ce n'est pas toujours garanti." @@ -63,7 +63,7 @@ "message": "Paramètres avancés" }, "advancedSettingsDescription": { - "message": "Accédez aux fonctionnalités pour les développeurs, téléchargez State Logs, réinitialisez votre compte, configurez testnets et personnalisez RPC." + "message": "Accédez aux fonctionnalités pour les développeurs, téléchargez State Logs, réinitialisez votre compte, configurez testnets et personnalisez RPC" }, "advancedOptions": { "message": "Options avancées" diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index ba64748c20c2..9d873cbbf48b 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -31,7 +31,7 @@ "message": "O opcijama" }, "aboutSettingsDescription": { - "message": "Inačica, centar za podršku i informacije za kontakt." + "message": "Inačica, centar za podršku i informacije za kontakt" }, "acceleratingATransaction": { "message": "* Ubrzavanjem se transakcije pomoću veće cijene goriva povećava šansa za bržu obradu mrežom, ali se uvijek ne jamči." @@ -67,7 +67,7 @@ "message": "Napredno" }, "advancedSettingsDescription": { - "message": "Pristup značajkama razvojnog inženjera, preuzimanje zapisnika stanja, poništavanje računa, postavljanje testnih mreža i prilagođeni RPC." + "message": "Pristup značajkama razvojnog inženjera, preuzimanje zapisnika stanja, poništavanje računa, postavljanje testnih mreža i prilagođeni RPC" }, "advancedOptions": { "message": "Napredne mogućnosti" diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 542534f32360..b4cbd1104086 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -31,7 +31,7 @@ "message": "Névjegy" }, "aboutSettingsDescription": { - "message": "Verzió, ügyfélszolgálat és elérhetőségek." + "message": "Verzió, ügyfélszolgálat és elérhetőségek" }, "acceleratingATransaction": { "message": "* Ha szeretné felgyorsítani a tranzakciót azzal, hogy magasabb gázárat használ, az növeli a gyorsabb feldolgozás esélyét, de ez nem mindig garantált." @@ -67,7 +67,7 @@ "message": "Speciális" }, "advancedSettingsDescription": { - "message": "Hozzáférés fejlesztői funkciókhoz, állapotnaplók letöltése, fiók újraállítása, testnetek és egyéni RPC-k beállítása." + "message": "Hozzáférés fejlesztői funkciókhoz, állapotnaplók letöltése, fiók újraállítása, testnetek és egyéni RPC-k beállítása" }, "advancedOptions": { "message": "Haladó beállítások" diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 252b7ec9f2c2..e02bc3296452 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -31,7 +31,7 @@ "message": "Tentang" }, "aboutSettingsDescription": { - "message": "Versi, pusat dukungan, dan informasi kontak." + "message": "Versi, pusat dukungan, dan informasi kontak" }, "acceleratingATransaction": { "message": "* Mempercepat transaksi dengan menggunakan harga gas yang lebih tinggi meningkatkan peluangnya untuk lebih cepat diproses oleh jaringan, tetapi tak selalu terjamin pasti cepat." @@ -67,7 +67,7 @@ "message": "Lanjutan" }, "advancedSettingsDescription": { - "message": "Akses fitur pengembang, unduh Log Status, Atur Ulang Akun, tata testnets dan RPC kustom." + "message": "Akses fitur pengembang, unduh Log Status, Atur Ulang Akun, tata testnets dan RPC kustom" }, "advancedOptions": { "message": "Opsi Lanjutan" diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 1d0725183913..ce745c9f42af 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -27,7 +27,7 @@ "message": "Informazioni" }, "aboutSettingsDescription": { - "message": "Version, centro di supporto e contatti." + "message": "Version, centro di supporto e contatti" }, "acceleratingATransaction": { "message": "* Accelerare una transazione usando un prezzo del gas maggiore aumenta la probabilità che la rete la elabori più velocemente, ma non è garantito." @@ -60,7 +60,7 @@ "message": "Avanzate" }, "advancedSettingsDescription": { - "message": "Accedi alle funzionalità sviluppatore, download dei log di Stato, Reset Account, imposta reti di test e RPC personalizzata." + "message": "Accedi alle funzionalità sviluppatore, download dei log di Stato, Reset Account, imposta reti di test e RPC personalizzata" }, "advancedOptions": { "message": "Opzioni Avanzate" diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 7fc11498804a..ebe05f6851bd 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -31,7 +31,7 @@ "message": "ಕುರಿತು" }, "aboutSettingsDescription": { - "message": "ಆವೃತ್ತಿ, ಬೆಂಬಲ ಕೇಂದ್ರ ಮತ್ತು ಸಂಪರ್ಕ ಮಾಹಿತಿ." + "message": "ಆವೃತ್ತಿ, ಬೆಂಬಲ ಕೇಂದ್ರ ಮತ್ತು ಸಂಪರ್ಕ ಮಾಹಿತಿ" }, "acceleratingATransaction": { "message": "* ಹೆಚ್ಚಿನ ಗ್ಯಾಸ್ ಬೆಲೆಯನ್ನು ಬಳಸಿಕೊಂಡು ವಹಿವಾಟನ್ನು ವೇಗಗೊಳಿಸುವುದರಿಂದ ನೆಟ್‌ವರ್ಕ್ ವೇಗವಾಗಿ ಪ್ರಕ್ರಿಯೆಗೊಳ್ಳುವ ಸಾಧ್ಯತೆಗಳನ್ನು ಅದು ಹೆಚ್ಚಿಸುತ್ತದೆ, ಆದರೆ ಇದು ಯಾವಾಗಲೂ ಖಚಿತವಾಗಿರುವುದಿಲ್ಲ." @@ -67,7 +67,7 @@ "message": "ಸುಧಾರಿತ" }, "advancedSettingsDescription": { - "message": "ಡೆವಲಪರ್ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಪ್ರವೇಶಿಸಿ, ರಾಜ್ಯದ ಲಾಗ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ, ಖಾತೆಯನ್ನು ಮರುಹೊಂದಿಸಿ, ಟೆಸ್ಟ್‌ನೆಟ್ಸ್‌ ಹೊಂದಿಸಿ ಮತ್ತು ಕಸ್ಟಮ್ RPC." + "message": "ಡೆವಲಪರ್ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಪ್ರವೇಶಿಸಿ, ರಾಜ್ಯದ ಲಾಗ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ, ಖಾತೆಯನ್ನು ಮರುಹೊಂದಿಸಿ, ಟೆಸ್ಟ್‌ನೆಟ್ಸ್‌ ಹೊಂದಿಸಿ ಮತ್ತು ಕಸ್ಟಮ್ RPC" }, "advancedOptions": { "message": "ಸುಧಾರಿತ ಆಯ್ಕೆಗಳು" diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index c71e3c2676d1..f9a1e7ffe6c7 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -27,7 +27,7 @@ "message": "정보" }, "aboutSettingsDescription": { - "message": "버전, 지원 센터, 그리고 연락처 정보." + "message": "버전, 지원 센터, 그리고 연락처 정보" }, "acceleratingATransaction": { "message": "* 더 높은 가스 요금을 사용하여 트랜잭션을 가속화하면 네트워크에 의해 더 빨리 처리될 가능성이 증가하지만 항상 빠른 처리가 보장되는 것은 아닙니다." @@ -63,7 +63,7 @@ "message": "고급" }, "advancedSettingsDescription": { - "message": "개발자 기능 사용, 상태 로그 다운로드, 계정 재설정, 테스트넷 및 사용자 정의 RPC 설정." + "message": "개발자 기능 사용, 상태 로그 다운로드, 계정 재설정, 테스트넷 및 사용자 정의 RPC 설정" }, "advancedOptions": { "message": "고급 옵션" diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 7e029494fa2b..db386046387c 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -27,7 +27,7 @@ "message": "Apie" }, "aboutSettingsDescription": { - "message": "Versija, palaikymo centras ir kontaktinė informacija." + "message": "Versija, palaikymo centras ir kontaktinė informacija" }, "acceleratingATransaction": { "message": "Operacijos paspartinimas naudojantis didesne dujų kaina padidina galimybes, kad ji bus greičiau apdorota tinkle, tačiau tai ne visada garantuojama. " @@ -63,7 +63,7 @@ "message": "Išplėstiniai" }, "advancedSettingsDescription": { - "message": "Prieigos kūrėjo funkcijos, būsenos žurnalų atsiuntimas, paskyros atstatymas, „testnet“ nustatymas ir pritaikytas RPC." + "message": "Prieigos kūrėjo funkcijos, būsenos žurnalų atsiuntimas, paskyros atstatymas, „testnet“ nustatymas ir pritaikytas RPC" }, "advancedOptions": { "message": "Išplėstinės parinktys" diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index ace47600fb23..454dedcc599f 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -67,7 +67,7 @@ "message": "Papildu" }, "advancedSettingsDescription": { - "message": "Piekļūstiet izstrādātāju funkcijām, lejupielādējiet stāvokļu žurnālus, atiestatiet kontu, iestatiet testa tīklus un pielāgotos RPC izsaukumus." + "message": "Piekļūstiet izstrādātāju funkcijām, lejupielādējiet stāvokļu žurnālus, atiestatiet kontu, iestatiet testa tīklus un pielāgotos RPC izsaukumus" }, "advancedOptions": { "message": "Papildu opcijas" diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index 03f9ac0b2cf6..cbe103493931 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -27,7 +27,7 @@ "message": "Mengenai" }, "aboutSettingsDescription": { - "message": "Versi, pusat sokongan, dan maklumat perhubungan." + "message": "Versi, pusat sokongan, dan maklumat perhubungan" }, "acceleratingATransaction": { "message": "* Mempercepatkan transaksi menggunakan harga gas lebih tinggi akan meningkatkan peluang diproses oleh rangkaian lebih cepat, tetapi ini pun tidak sentiasa dijamin." @@ -63,7 +63,7 @@ "message": "Lanjutan" }, "advancedSettingsDescription": { - "message": "Akses ciri-ciri pembangun, muat turun Log Keadaan, Set Semula Akaun, sediakan jaringan ujian dan RPC tersuai." + "message": "Akses ciri-ciri pembangun, muat turun Log Keadaan, Set Semula Akaun, sediakan jaringan ujian dan RPC tersuai" }, "advancedOptions": { "message": "Pilihan Lanjutan" diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 83a6f09d3920..b64fab7c8680 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -27,7 +27,7 @@ "message": "Info" }, "aboutSettingsDescription": { - "message": "Versjon, brukerstøtte og kontaktinformasjon." + "message": "Versjon, brukerstøtte og kontaktinformasjon" }, "acceleratingATransaction": { "message": "* Akselerering av en transaksjon ved å bruke en høyere datakraftspris øker sjansene for å bli behandlet av nettverket raskere, men det er ikke alltid garantert." @@ -63,7 +63,7 @@ "message": "Avansert" }, "advancedSettingsDescription": { - "message": "Få tilgang til utviklerfunksjoner, last ned tilstandslogger, tilbakestill konto, installer testnett og tilpasset RPC." + "message": "Få tilgang til utviklerfunksjoner, last ned tilstandslogger, tilbakestill konto, installer testnett og tilpasset RPC" }, "advancedOptions": { "message": "Avanserte valg" diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 5ffd5585a760..0f7b00fbb185 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -27,7 +27,7 @@ "message": "Informacje" }, "aboutSettingsDescription": { - "message": "Wersja, centrum wsparcia i dane kontaktowe." + "message": "Wersja, centrum wsparcia i dane kontaktowe" }, "acceleratingATransaction": { "message": "* Przyspieszenie transakcji poprzez zastosowanie wyższej ceny gazu zwiększa szanse na jej szybsze przetworzenie przez sieć, jednak skuteczność tej operacji nie jest gwarantowana." @@ -63,7 +63,7 @@ "message": "Zaawansowane" }, "advancedSettingsDescription": { - "message": "Dostęp do funkcji programisty, pobieranie dzienników stanu, resetowanie konta, konfigurowanie sieci testowych i niestandardowe RPC." + "message": "Dostęp do funkcji programisty, pobieranie dzienników stanu, resetowanie konta, konfigurowanie sieci testowych i niestandardowe RPC" }, "advancedOptions": { "message": "Opcje zaawansowane" diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index ecb223dcbeef..295849511079 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -31,7 +31,7 @@ "message": "Sobre" }, "aboutSettingsDescription": { - "message": "Versão, centro de apoio e informações de contato." + "message": "Versão, centro de apoio e informações de contato" }, "acceleratingATransaction": { "message": "* Acelerar uma transação usando um preço de gás mais alto aumenta suas chances de a rede processá-la de forma mais rápida, mas isso nem sempre é garantido." @@ -67,7 +67,7 @@ "message": "Avançado" }, "advancedSettingsDescription": { - "message": "Acesse recursos do desenvolvedor, baixe registros de estado, redefina a conta, configure testnets e personalize RPC." + "message": "Acesse recursos do desenvolvedor, baixe registros de estado, redefina a conta, configure testnets e personalize RPC" }, "advancedOptions": { "message": "Opções avançadas" diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 5fed700da0e3..074683601bcd 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -27,7 +27,7 @@ "message": "Despre" }, "aboutSettingsDescription": { - "message": "Versiune, centru de asistență și date de contact." + "message": "Versiune, centru de asistență și date de contact" }, "acceleratingATransaction": { "message": "* Accelerarea unei tranzacții folosind un preț în gas mai mare îi crește șansele de a fi procesată mai rapid de rețea, însă acest lucru nu este garantat întotdeauna." @@ -63,7 +63,7 @@ "message": "Avansate" }, "advancedSettingsDescription": { - "message": "Accesați funcții pentru dezvoltatori, descărcați Jurnale de stare, resetați contul, configurați rețele de test și RPC personalizat." + "message": "Accesați funcții pentru dezvoltatori, descărcați Jurnale de stare, resetați contul, configurați rețele de test și RPC personalizat" }, "advancedOptions": { "message": "Opțiuni avansate" diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 697c589367e1..8e40c04f0881 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -27,7 +27,7 @@ "message": "Informácie" }, "aboutSettingsDescription": { - "message": "Verzia, centrum podpory a kontaktné informácie." + "message": "Verzia, centrum podpory a kontaktné informácie" }, "acceleratingATransaction": { "message": "*Urýchlenie transakcie pomocou vyššej ceny za GAS zvyšuje šance na rýchlejšie spracovanie v sieti, nie je to však vždy zaručené." @@ -63,7 +63,7 @@ "message": "Rozšírené" }, "advancedSettingsDescription": { - "message": "Získajte prístup k vývojárskym funkciám, sťahujte si Stavové denníky, resetujte účet, nastavujte testovacie siete a vlastné RPC." + "message": "Získajte prístup k vývojárskym funkciám, sťahujte si Stavové denníky, resetujte účet, nastavujte testovacie siete a vlastné RPC" }, "advancedOptions": { "message": "Rozšírené nastavenia" diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 643e62c23405..a7d37c3a42a0 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -27,7 +27,7 @@ "message": "O možnostih" }, "aboutSettingsDescription": { - "message": "Različica, center za podporo in podatki za stik." + "message": "Različica, center za podporo in podatki za stik" }, "acceleratingATransaction": { "message": "* Pospešitev transakcije z višjo gas ceno poveča njene možnosti za hitrejšo obdelavo v omrežju, vendar ni vedno zagotovljena." @@ -63,7 +63,7 @@ "message": "Napredno" }, "advancedSettingsDescription": { - "message": "Dostopite do funkcij razvijalca, prenesite dnevnike držav, ponastavite račun, nastavite testne mreže in RPC po meri." + "message": "Dostopite do funkcij razvijalca, prenesite dnevnike držav, ponastavite račun, nastavite testne mreže in RPC po meri" }, "advancedOptions": { "message": "Napredne možnosti" diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 1cd653ed7165..f333380ccb13 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -27,7 +27,7 @@ "message": "Основни подаци" }, "aboutSettingsDescription": { - "message": "Verzija, centar za podršku i podaci za kontakt." + "message": "Verzija, centar za podršku i podaci za kontakt" }, "acceleratingATransaction": { "message": "* Time što se ubrzava transakcija koristeći veću gas cenu, povećavaju se šanse da se procesuira brže od strane mreže, ali to nije uvek zagarantovano." @@ -63,7 +63,7 @@ "message": "Напредне опције" }, "advancedSettingsDescription": { - "message": "Pristupite funkcijama za programere, preuzmite državne evidencije, resetujte nalog, postavite testne mreže i prilagođeni RPC." + "message": "Pristupite funkcijama za programere, preuzmite državne evidencije, resetujte nalog, postavite testne mreže i prilagođeni RPC" }, "advancedOptions": { "message": "Dodatne opcije" diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 6d89b6e5ce81..d17b310ad5b2 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -31,7 +31,7 @@ "message": "Om" }, "aboutSettingsDescription": { - "message": "Version, supportcenter och kontaktinformation." + "message": "Version, supportcenter och kontaktinformation" }, "acceleratingATransaction": { "message": "* Att snabba upp en överföring genom att använda ett högre gaspris ökar chanserna för att överföringen ska hanteras snabbare av nätverket, men det är inte en garanti." @@ -67,7 +67,7 @@ "message": "Avancerat" }, "advancedSettingsDescription": { - "message": "Åtkomst till verktyg för utvecklare, ladda ner loggar, återställ konto, upprätta testnätverk och skräddarsy RPC." + "message": "Åtkomst till verktyg för utvecklare, ladda ner loggar, återställ konto, upprätta testnätverk och skräddarsy RPC" }, "advancedOptions": { "message": "Avancerade alternativ" diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 76d1897accda..3f5fa2ce1113 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -31,7 +31,7 @@ "message": "Kuhusu" }, "aboutSettingsDescription": { - "message": "Toleo, kituo cha msaada, na taarifa za mawasiliano." + "message": "Toleo, kituo cha msaada, na taarifa za mawasiliano" }, "acceleratingATransaction": { "message": "*Kuwezesha muamala kwa kutumia bei ya juu ya gesi huongeza uwezekano wake wa kushughulikiwa na mtandao haraka, lakini hauhakikishiwi siku zote." @@ -67,7 +67,7 @@ "message": "Mipangilio ya kina" }, "advancedSettingsDescription": { - "message": "Vipengele vya idhini ya msanidi, Kumbukumbu za Hali ya kupakua, Kufuta Akaunti, mitando ya majaribio ya kuweka mipangilio na RPC maalumu." + "message": "Vipengele vya idhini ya msanidi, Kumbukumbu za Hali ya kupakua, Kufuta Akaunti, mitando ya majaribio ya kuweka mipangilio na RPC maalumu" }, "advancedOptions": { "message": "Machaguo ya Juu" diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index d269044b3d33..f04390e41d65 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -27,7 +27,7 @@ "message": "Про Google Chrome" }, "aboutSettingsDescription": { - "message": "Версія, центр підтримки та контактна інформація." + "message": "Версія, центр підтримки та контактна інформація" }, "acceleratingATransaction": { "message": "* Прискорення транзакції за допомогою вищих цін на газ підвищує її шанси бути обробленою мережею швидше, але це не завжди гарантовано." @@ -63,7 +63,7 @@ "message": "Розширені" }, "advancedSettingsDescription": { - "message": "Отримайте доступ до функцій розробника, завантажте Логи станів, перезапустіть обліковий запис, налаштуйте тестові сітки та персоніфіковані RPC." + "message": "Отримайте доступ до функцій розробника, завантажте Логи станів, перезапустіть обліковий запис, налаштуйте тестові сітки та персоніфіковані RPC" }, "advancedOptions": { "message": "Додаткові параметри" From bf57dd5ad918210c5f7e6680ed09d94f5f4b9acf Mon Sep 17 00:00:00 2001 From: ricky Date: Thu, 21 Nov 2019 16:59:50 -0500 Subject: [PATCH 06/88] Add overflow hidden (#7488) --- ui/app/components/app/transaction-list-item/index.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/components/app/transaction-list-item/index.scss b/ui/app/components/app/transaction-list-item/index.scss index e0c62199e3c7..9804ecd97676 100644 --- a/ui/app/components/app/transaction-list-item/index.scss +++ b/ui/app/components/app/transaction-list-item/index.scss @@ -139,6 +139,7 @@ &__expander { max-height: 0px; width: 100%; + overflow: hidden; &--show { max-height: 1000px; From 359fbf3ace4849ff7181a4e2842f58576501ab56 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 21 Nov 2019 17:17:08 -0800 Subject: [PATCH 07/88] Change component props from string to object and associated tests to mimic actual in-use component Add test to updateGas when asset is changed --- .../pages/send/tests/send-component.test.js | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/ui/app/pages/send/tests/send-component.test.js b/ui/app/pages/send/tests/send-component.test.js index d5b43bbe4a86..19ea88626a2a 100644 --- a/ui/app/pages/send/tests/send-component.test.js +++ b/ui/app/pages/send/tests/send-component.test.js @@ -57,10 +57,10 @@ describe('Send Component', function () { primaryCurrency="mockPrimaryCurrency" recentBlocks={['mockBlock']} selectedAddress="mockSelectedAddress" - selectedToken="mockSelectedToken" + selectedToken={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }} showHexData tokenBalance="mockTokenBalance" - tokenContract="mockTokenContract" + tokenContract={{ method: 'mockTokenMethod' }} updateAndSetGasLimit={propsMethodSpies.updateAndSetGasLimit} updateSendErrors={propsMethodSpies.updateSendErrors} updateSendTokenBalance={propsMethodSpies.updateSendTokenBalance} @@ -79,6 +79,7 @@ describe('Send Component', function () { propsMethodSpies.updateAndSetGasLimit.resetHistory() propsMethodSpies.updateSendErrors.resetHistory() propsMethodSpies.updateSendTokenBalance.resetHistory() + propsMethodSpies.updateToNicknameIfNecessary.resetHistory() }) it('should call componentDidMount', () => { @@ -129,7 +130,7 @@ describe('Send Component', function () { prevBalance: '', prevGasTotal: undefined, prevTokenBalance: undefined, - selectedToken: 'mockSelectedToken', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, tokenBalance: 'mockTokenBalance', } ) @@ -162,7 +163,7 @@ describe('Send Component', function () { conversionRate: 10, gasTotal: 'mockGasTotal', primaryCurrency: 'mockPrimaryCurrency', - selectedToken: 'mockSelectedToken', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, tokenBalance: 'mockTokenBalance', } ) @@ -184,7 +185,7 @@ describe('Send Component', function () { conversionRate: 10, gasTotal: 'mockGasTotal', primaryCurrency: 'mockPrimaryCurrency', - selectedToken: 'mockSelectedToken', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, } ) }) @@ -225,7 +226,7 @@ describe('Send Component', function () { it('should call updateSendErrors with the expected params if selectedToken is truthy', () => { propsMethodSpies.updateSendErrors.resetHistory() - wrapper.setProps({ selectedToken: 'someToken' }) + wrapper.setProps({ selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }}) wrapper.instance().componentDidUpdate({ from: { balance: 'balanceChanged', @@ -246,6 +247,7 @@ describe('Send Component', function () { balance: 'balanceChanged', }, network: '3', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset }) assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0) assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0) @@ -260,6 +262,7 @@ describe('Send Component', function () { balance: 'balanceChanged', }, network: '3', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset }) assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0) assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0) @@ -273,13 +276,14 @@ describe('Send Component', function () { balance: 'balanceChanged', }, network: '2', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset }) assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 1) assert.deepEqual( propsMethodSpies.updateSendTokenBalance.getCall(0).args[0], { - selectedToken: 'mockSelectedToken', - tokenContract: 'mockTokenContract', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset + tokenContract: { method: 'mockTokenMethod' }, address: 'mockAddress', } ) @@ -289,6 +293,20 @@ describe('Send Component', function () { [] ) }) + + it('should call updateGas when ', () => { + SendTransactionScreen.prototype.updateGas.resetHistory() + propsMethodSpies.updateAndSetGasLimit.resetHistory() + wrapper.instance().componentDidUpdate({ + from: { + balance: 'balancedChanged', + }, + network: '3', // Make sure not to hit updateGas when changing network + selectedToken: { address: 'newSelectedToken' }, + }) + assert.equal(propsMethodSpies.updateToNicknameIfNecessary.callCount, 0) // Network did not change + assert.equal(propsMethodSpies.updateAndSetGasLimit.callCount, 1) + }) }) describe('updateGas', () => { @@ -305,7 +323,7 @@ describe('Send Component', function () { gasPrice: 'mockGasPrice', recentBlocks: ['mockBlock'], selectedAddress: 'mockSelectedAddress', - selectedToken: 'mockSelectedToken', + selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, to: '', value: 'mockAmount', data: undefined, @@ -431,9 +449,7 @@ describe('Send Component', function () { }) it('should warn when send to a known token contract address', () => { - wrapper.setProps({ - selectedToken: '0x888', - }) + wrapper.setProps({ address: '0x888', decimals: 18, symbol: '888' }) const instance = wrapper.instance() instance.onRecipientInputChange('0x13cb85823f78Cff38f0B0E90D3e975b8CB3AAd64') From d84b16a78422890a4f8ffd873d9c1993d7bf8422 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 21 Nov 2019 17:19:33 -0800 Subject: [PATCH 08/88] Update Gas when asset is changed --- ui/app/pages/send/send.component.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/pages/send/send.component.js b/ui/app/pages/send/send.component.js index e348e283bea1..e6f5ca71d5ff 100644 --- a/ui/app/pages/send/send.component.js +++ b/ui/app/pages/send/send.component.js @@ -165,6 +165,7 @@ export default class SendTransactionScreen extends PersistentForm { if (selectedTokenAddress && prevTokenAddress !== selectedTokenAddress) { this.updateSendToken() + this.updateGas() } } From 4736e3ed87cf74f1e08f035133a8eb1ea2c15ab9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 21 Nov 2019 17:21:24 -0800 Subject: [PATCH 09/88] Finish test description --- ui/app/pages/send/tests/send-component.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/pages/send/tests/send-component.test.js b/ui/app/pages/send/tests/send-component.test.js index 19ea88626a2a..98ac55f91cf3 100644 --- a/ui/app/pages/send/tests/send-component.test.js +++ b/ui/app/pages/send/tests/send-component.test.js @@ -294,7 +294,7 @@ describe('Send Component', function () { ) }) - it('should call updateGas when ', () => { + it('should call updateGas when selectedToken.address is changed', () => { SendTransactionScreen.prototype.updateGas.resetHistory() propsMethodSpies.updateAndSetGasLimit.resetHistory() wrapper.instance().componentDidUpdate({ From 015ba83c6e69dcca676d626f70ef887a38ce01b9 Mon Sep 17 00:00:00 2001 From: Tyson Malchow Date: Fri, 22 Nov 2019 09:13:23 -0600 Subject: [PATCH 10/88] Update Wyre buy ETH URL (#7482) --- app/scripts/lib/buy-eth-url.js | 2 +- test/unit/app/buy-eth-url.spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index 6728fde7c170..d4b74fa19398 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -19,7 +19,7 @@ function getBuyEthUrl ({ network, amount, address, service }) { switch (service) { case 'wyre': - return `https://dash.sendwyre.com/sign-up` + return `https://pay.sendwyre.com/?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2` case 'coinswitch': return `https://metamask.coinswitch.co/?address=${address}&to=eth` case 'coinbase': diff --git a/test/unit/app/buy-eth-url.spec.js b/test/unit/app/buy-eth-url.spec.js index 7db9922440c8..96814c59d75c 100644 --- a/test/unit/app/buy-eth-url.spec.js +++ b/test/unit/app/buy-eth-url.spec.js @@ -17,10 +17,10 @@ describe('buy-eth-url', function () { network: '42', } - it('returns coinbase url with amount and address for network 1', function () { + it('returns wyre url with address for network 1', function () { const wyreUrl = getBuyEthUrl(mainnet) - assert.equal(wyreUrl, 'https://dash.sendwyre.com/sign-up') + assert.equal(wyreUrl, 'https://pay.sendwyre.com/?dest=ethereum:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc&destCurrency=ETH&accountId=AC-7AG3W4XH4N2') }) From f763979beded94a8bfe7717a96e36c9c65f87368 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Fri, 22 Nov 2019 13:03:51 -0400 Subject: [PATCH 11/88] Add support for one-click onboarding (#7017) * Add support for one-click onboarding MetaMask now allows sites to register as onboarding the user, so that the user is redirected back to the initiating site after onboarding. This is accomplished through the use of the `metamask-onboarding` library and the MetaMask forwarder. At the end of onboarding, a 'snackbar'-stype component will explain to the user they are about to be moved back to the originating dapp, and it will show the origin of that dapp. This is intended to help prevent phishing attempts, as it highlights that a redirect is taking place to an untrusted third party. If the onboarding initiator tab is closed when onboarding is finished, the user is redirected to the onboarding originator as a fallback. Closes #6161 * Add onboarding button to contract test dapp The `contract-test` dapp (run with `yarn dapp`, used in e2e tests) now uses a `Connect` button instead of connecting automatically. This button also serves as an onboarding button when a MetaMask installation is not detected. * Add new static server for test dapp The `static-server` library we were using for the `contract-test` dapp didn't allow referencing files outside the server root. This should have been possible to work around using symlinks, but there was a bug that resulted in symlinks crashing the server. Instead it has been replaced with a simple static file server that will serve paths starting with `node_modules` from the project root. This will be useful in testing the onboarding library without vendoring it. * Add `@metamask/onboarding` and `@metamask/forwarder` Both libraries used to test onboarding are now included as dev dependencies, to help with testing. A few convenience scripts were added to help with this (`yarn forwarder` and `yarn dapp-forwarder`) --- app/_locales/en/messages.json | 4 + app/scripts/background.js | 1 + app/scripts/contentscript.js | 39 ++ app/scripts/controllers/onboarding.js | 46 +- app/scripts/inpage.js | 26 +- app/scripts/metamask-controller.js | 43 +- app/scripts/migrations/031.js | 2 +- development/static-server.js | 92 ++++ package.json | 13 +- test/e2e/contract-test/contract.js | 409 +++++++++++------- test/e2e/contract-test/index.html | 99 +++-- test/e2e/ethereum-on.spec.js | 9 +- test/e2e/metamask-ui.spec.js | 5 + test/e2e/run-web3.sh | 2 +- test/e2e/signature-request.spec.js | 5 + test/e2e/web3.spec.js | 5 + ui/app/components/ui/snackbar/index.js | 1 + ui/app/components/ui/snackbar/index.scss | 11 + .../ui/snackbar/snackbar.component.js | 18 + ui/app/css/itcss/components/index.scss | 1 + .../end-of-flow/end-of-flow.component.js | 45 +- .../end-of-flow/end-of-flow.container.js | 7 +- .../first-time-flow/end-of-flow/index.scss | 2 +- .../first-time-flow.selectors.js | 28 +- .../onboarding-initiator-util.js | 48 ++ .../seed-phrase/reveal-seed-phrase/index.scss | 2 +- .../reveal-seed-phrase.component.js | 32 +- .../reveal-seed-phrase.container.js | 9 +- yarn.lock | 143 +++--- 29 files changed, 827 insertions(+), 320 deletions(-) create mode 100644 development/static-server.js create mode 100644 ui/app/components/ui/snackbar/index.js create mode 100644 ui/app/components/ui/snackbar/index.scss create mode 100644 ui/app/components/ui/snackbar/snackbar.component.js create mode 100644 ui/app/pages/first-time-flow/onboarding-initiator-util.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 2a060b1e44de..db150930b155 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -507,6 +507,10 @@ "endOfFlowMessage10": { "message": "All Done" }, + "onboardingReturnNotice": { + "message": "\"$1\" will close this tab and direct back to $2", + "description": "Return the user to the site that initiated onboarding" + }, "ensRegistrationError": { "message": "Error in ENS name registration" }, diff --git a/app/scripts/background.js b/app/scripts/background.js index b26a87ba2779..18bdfdfb95ac 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -314,6 +314,7 @@ function setupController (initState, initLangCode) { // extension.runtime.onConnect.addListener(connectRemote) extension.runtime.onConnectExternal.addListener(connectExternal) + extension.runtime.onMessage.addListener(controller.onMessage.bind(controller)) const metamaskInternalProcessHash = { [ENVIRONMENT_TYPE_POPUP]: true, diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 4a84cb64b40b..6ea2db740dd9 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -4,6 +4,7 @@ const pump = require('pump') const log = require('loglevel') const Dnode = require('dnode') const querystring = require('querystring') +const { Writable } = require('readable-stream') const LocalMessageDuplexStream = require('post-message-stream') const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') @@ -86,6 +87,44 @@ async function setupStreams () { (err) => logStreamDisconnectWarning('MetaMask Background Multiplex', err) ) + const onboardingStream = pageMux.createStream('onboarding') + const addCurrentTab = new Writable({ + objectMode: true, + write: (chunk, _, callback) => { + if (!chunk) { + return callback(new Error('Malformed onboarding message')) + } + + const handleSendMessageResponse = (error, success) => { + if (!error && !success) { + error = extension.runtime.lastError + } + if (error) { + log.error(`Failed to send ${chunk.type} message`, error) + return callback(error) + } + callback(null) + } + + try { + if (chunk.type === 'registerOnboarding') { + extension.runtime.sendMessage({ type: 'metamask:registerOnboarding', location: window.location.href }, handleSendMessageResponse) + } else { + throw new Error(`Unrecognized onboarding message type: '${chunk.type}'`) + } + } catch (error) { + log.error(error) + return callback(error) + } + }, + }) + + pump( + onboardingStream, + addCurrentTab, + error => console.error('MetaMask onboarding channel traffic failed', error), + ) + // forward communication across inpage-background for these channels only forwardTrafficBetweenMuxers('provider', pageMux, extensionMux) forwardTrafficBetweenMuxers('publicConfig', pageMux, extensionMux) diff --git a/app/scripts/controllers/onboarding.js b/app/scripts/controllers/onboarding.js index a29c8407a486..5d00fb77553e 100644 --- a/app/scripts/controllers/onboarding.js +++ b/app/scripts/controllers/onboarding.js @@ -1,5 +1,6 @@ const ObservableStore = require('obs-store') const extend = require('xtend') +const log = require('loglevel') /** * @typedef {Object} InitState @@ -9,11 +10,12 @@ const extend = require('xtend') /** * @typedef {Object} OnboardingOptions * @property {InitState} initState The initial controller state + * @property {PreferencesController} preferencesController Controller for managing user perferences */ /** * Controller responsible for maintaining - * a cache of account balances in local storage + * state related to onboarding */ class OnboardingController { /** @@ -22,10 +24,28 @@ class OnboardingController { * @param {OnboardingOptions} [opts] Controller configuration parameters */ constructor (opts = {}) { - const initState = extend({ - seedPhraseBackedUp: true, - }, opts.initState) + const initialTransientState = { + onboardingTabs: {}, + } + const initState = extend( + { + seedPhraseBackedUp: true, + }, + opts.initState, + initialTransientState, + ) this.store = new ObservableStore(initState) + this.preferencesController = opts.preferencesController + this.completedOnboarding = this.preferencesController.store.getState().completedOnboarding + + this.preferencesController.store.subscribe(({ completedOnboarding }) => { + if (completedOnboarding !== this.completedOnboarding) { + this.completedOnboarding = completedOnboarding + if (completedOnboarding) { + this.store.updateState(initialTransientState) + } + } + }) } setSeedPhraseBackedUp (newSeedPhraseBackUpState) { @@ -38,6 +58,24 @@ class OnboardingController { return this.store.getState().seedPhraseBackedUp } + /** + * Registering a site as having initiated onboarding + * + * @param {string} location - The location of the site registering + * @param {string} tabId - The id of the tab registering + */ + async registerOnboarding (location, tabId) { + if (this.completedOnboarding) { + log.debug('Ignoring registerOnboarding; user already onboarded') + return + } + const onboardingTabs = Object.assign({}, this.store.getState().onboardingTabs) + if (!onboardingTabs[location] || onboardingTabs[location] !== tabId) { + log.debug(`Registering onboarding tab at location '${location}' with tabId '${tabId}'`) + onboardingTabs[location] = tabId + this.store.updateState({ onboardingTabs }) + } + } } module.exports = OnboardingController diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index ec88243a4e34..0f752f1afb75 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -37,6 +37,9 @@ const log = require('loglevel') const LocalMessageDuplexStream = require('post-message-stream') const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('metamask-inpage-provider') +const ObjectMultiplex = require('obj-multiplex') +const pump = require('pump') +const promisify = require('pify') const createStandardProvider = require('./createStandardProvider').default let warned = false @@ -61,6 +64,14 @@ const inpageProvider = new MetamaskInpageProvider(metamaskStream) // set a high max listener count to avoid unnecesary warnings inpageProvider.setMaxListeners(100) +const pageMux = new ObjectMultiplex() +const onboardingStream = pageMux.createStream('onboarding') +pump( + pageMux, + metamaskStream, + error => log.error('MetaMask muxed in-page traffic failed', error) +) + let warnedOfAutoRefreshDeprecation = false // augment the provider with its enable method inpageProvider.enable = function ({ force } = {}) { @@ -134,6 +145,15 @@ inpageProvider._metamask = new Proxy({ const { isUnlocked } = await getPublicConfigWhenReady() return Boolean(isUnlocked) }, + + /** + * Registers a page as having initated onboarding. This facilitates MetaMask focusing the initiating tab after onboarding. + * + * @returns {Promise} - Promise resolving to undefined + */ + registerOnboarding: async () => { + await promisify(onboardingStream.write({ type: 'registerOnboarding' })) + }, }, { get: function (obj, prop) { !warned && console.warn('Heads up! ethereum._metamask exposes methods that have ' + @@ -178,9 +198,3 @@ setupDappAutoReload(web3, inpageProvider.publicConfigStore) inpageProvider.publicConfigStore.subscribe(function (state) { web3.eth.defaultAccount = state.selectedAddress }) - -inpageProvider.publicConfigStore.subscribe(function (state) { - if (state.onboardingcomplete) { - window.postMessage('onboardingcomplete', '*') - } -}) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6e2f0d08e497..be8424d426cb 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -4,10 +4,12 @@ * @license MIT */ +const assert = require('assert').strict const EventEmitter = require('events') const pump = require('pump') const Dnode = require('dnode') const pify = require('pify') +const extension = require('extensionizer') const ObservableStore = require('obs-store') const ComposableObservableStore = require('./lib/ComposableObservableStore') const createDnodeRemoteGetter = require('./lib/createDnodeRemoteGetter') @@ -177,6 +179,7 @@ module.exports = class MetamaskController extends EventEmitter { this.onboardingController = new OnboardingController({ initState: initState.OnboardingController, + preferencesController: this.preferencesController, }) // ensure accountTracker updates balances after network change @@ -390,7 +393,7 @@ module.exports = class MetamaskController extends EventEmitter { publicConfigStore.putState(publicState) } - function selectPublicState ({ isUnlocked, selectedAddress, network, completedOnboarding, provider }) { + function selectPublicState ({ isUnlocked, selectedAddress, network, provider }) { const isEnabled = checkIsEnabled() const isReady = isUnlocked && isEnabled const result = { @@ -398,7 +401,6 @@ module.exports = class MetamaskController extends EventEmitter { isEnabled, selectedAddress: isReady ? selectedAddress : null, networkVersion: network, - onboardingcomplete: completedOnboarding, chainId: selectChainId({ network, provider }), } return result @@ -1521,6 +1523,43 @@ module.exports = class MetamaskController extends EventEmitter { ) } + onMessage (message, sender, sendResponse) { + if (!message || !message.type) { + log.debug(`Ignoring invalid message: '${JSON.stringify(message)}'`) + return + } + + let handleMessage + + try { + if (message.type === 'metamask:registerOnboarding') { + assert(sender.tab, 'Missing tab from sender') + assert(sender.tab.id && sender.tab.id !== extension.tabs.TAB_ID_NONE, 'Missing tab ID from sender') + assert(message.location, 'Missing location from message') + + handleMessage = this.onboardingController.registerOnboarding(message.location, sender.tab.id) + } else { + throw new Error(`Unrecognized message type: '${message.type}'`) + } + } catch (error) { + console.error(error) + sendResponse(error) + return true + } + + if (handleMessage) { + handleMessage + .then(() => { + sendResponse(null, true) + }) + .catch((error) => { + console.error(error) + sendResponse(error) + }) + return true + } + } + /** * A method for providing our public api over a stream. * This includes a method for setting site metadata like title and image diff --git a/app/scripts/migrations/031.js b/app/scripts/migrations/031.js index 9c8cbeb09b1f..927de98c4314 100644 --- a/app/scripts/migrations/031.js +++ b/app/scripts/migrations/031.js @@ -3,7 +3,7 @@ const version = 31 const clone = require('clone') /* - * The purpose of this migration is to properly set the completedOnboarding flag baesd on the state + * The purpose of this migration is to properly set the completedOnboarding flag based on the state * of the KeyringController. */ module.exports = { diff --git a/development/static-server.js b/development/static-server.js new file mode 100644 index 000000000000..d8f22cabead9 --- /dev/null +++ b/development/static-server.js @@ -0,0 +1,92 @@ +const fs = require('fs') +const http = require('http') +const path = require('path') + +const chalk = require('chalk') +const pify = require('pify') +const serveHandler = require('serve-handler') + +const fsStat = pify(fs.stat) +const DEFAULT_PORT = 9080 + +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}`) + } else { + console.log(chalk`{gray '-->'} {green.dim ${response.statusCode}} ${request.url}`) + } +} +const onRequest = (request, response) => { + console.log(chalk`{gray '<--'} {blue [${request.method}]} ${request.url}`) + response.on('finish', () => onResponse(request, response)) +} + +const startServer = ({ port, rootDirectory }) => { + const server = http.createServer((request, response) => { + if (request.url.startsWith('/node_modules/')) { + request.url = request.url.substr(14) + return serveHandler(request, response, { + directoryListing: false, + public: path.resolve('./node_modules'), + }) + } + return serveHandler(request, response, { + directoryListing: false, + public: rootDirectory, + }) + }) + + server.on('request', onRequest) + + server.listen(port, () => { + console.log(`Running at http://localhost:${port}`) + }) +} + +const parsePort = (portString) => { + const port = Number(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`) + } + return port +} + +const parseDirectoryArgument = async (pathString) => { + const resolvedPath = path.resolve(pathString) + const directoryStats = await fsStat(resolvedPath) + if (!directoryStats.isDirectory()) { + throw new Error(`Invalid path '${pathString}'; must be a directory`) + } + return resolvedPath +} + +const main = async () => { + const args = process.argv.slice(2) + + const options = { + port: process.env.port || DEFAULT_PORT, + rootDirectory: path.resolve('.'), + } + + while (args.length) { + if (/^(--port|-p)$/i.test(args[0])) { + if (args[1] === undefined) { + throw new Error('Missing port argument') + } + options.port = parsePort(args[1]) + args.splice(0, 2) + } else { + options.rootDirectory = await parseDirectoryArgument(args[0]) + args.splice(0, 1) + } + } + + startServer(options) +} + +main() + .catch(console.error) diff --git a/package.json b/package.json index 7c0723ad4562..7b51c827f7ab 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,12 @@ "start:test": "gulp dev:test", "build:test": "gulp build:test", "test": "yarn test:unit && yarn lint", - "dapp": "static-server test/e2e/contract-test --port 8080", - "dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && static-server test/e2e/contract-test --port 8080'", + "dapp": "node development/static-server.js test/e2e/contract-test --port 8080", + "dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && node development/static-server.js test/e2e/contract-test --port 8080'", + "forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010", + "dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'", "watch:test:unit": "nodemon --exec \"yarn test:unit\" ./test ./app ./ui", - "sendwithprivatedapp": "static-server test/e2e/send-eth-with-private-key-test --port 8080", + "sendwithprivatedapp": "node development/static-server.js test/e2e/send-eth-with-private-key-test --port 8080", "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\" \"ui/app/**/*.test.js\"", "test:unit:global": "mocha test/unit-global/*", "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", @@ -189,6 +191,8 @@ "@babel/preset-env": "^7.5.5", "@babel/preset-react": "^7.0.0", "@babel/register": "^7.5.5", + "@metamask/forwarder": "^1.0.0", + "@metamask/onboarding": "^0.1.2", "@sentry/cli": "^1.30.3", "@storybook/addon-actions": "^5.2.6", "@storybook/addon-info": "^5.1.1", @@ -201,6 +205,7 @@ "browserify": "^16.2.3", "browserify-transform-tools": "^1.7.0", "chai": "^4.1.0", + "chalk": "^2.4.2", "chromedriver": "^2.41.0", "concurrently": "^4.1.1", "coveralls": "^3.0.0", @@ -279,12 +284,12 @@ "rimraf": "^2.6.2", "sass-loader": "^7.0.1", "selenium-webdriver": "^3.5.0", + "serve-handler": "^6.1.2", "sesify": "^4.2.1", "sesify-viz": "^3.0.5", "sinon": "^5.0.0", "source-map": "^0.7.2", "source-map-explorer": "^2.0.1", - "static-server": "^2.2.1", "style-loader": "^0.21.0", "stylelint": "^9.10.1", "stylelint-config-standard": "^18.2.0", diff --git a/test/e2e/contract-test/contract.js b/test/e2e/contract-test/contract.js index ebfea34ecd08..a6b5f110bf01 100644 --- a/test/e2e/contract-test/contract.js +++ b/test/e2e/contract-test/contract.js @@ -1,4 +1,4 @@ -/*global ethereum*/ +/*global ethereum, MetamaskOnboarding */ /* The `piggybankContract` is compiled from: @@ -30,8 +30,14 @@ The `piggybankContract` is compiled from: } */ -web3.currentProvider.enable().then(() => { - var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}]) +const forwarderOrigin = 'http://localhost:9010' + +const isMetaMaskInstalled = () => { + return Boolean(window.ethereum && window.ethereum.isMetaMask) +} + +const initialize = () => { + const onboardButton = document.getElementById('connectButton') const deployButton = document.getElementById('deployButton') const depositButton = document.getElementById('depositButton') const withdrawButton = document.getElementById('withdrawButton') @@ -42,200 +48,295 @@ web3.currentProvider.enable().then(() => { const transferTokensWithoutGas = document.getElementById('transferTokensWithoutGas') const approveTokensWithoutGas = document.getElementById('approveTokensWithoutGas') const signTypedData = document.getElementById('signTypedData') + const signTypedDataResults = document.getElementById('signTypedDataResult') - deployButton.addEventListener('click', async function () { - document.getElementById('contractStatus').innerHTML = 'Deploying' - - var piggybank = await piggybankContract.new( - { - from: web3.eth.accounts[0], - data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', - gas: '4700000', - }, function (e, contract) { - if (e) { - throw e - } - if (typeof contract.address !== 'undefined') { - console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + const contractStatus = document.getElementById('contractStatus') + const tokenAddress = document.getElementById('tokenAddress') + const networkDiv = document.getElementById('network') + const chainIdDiv = document.getElementById('chainId') + const accountsDiv = document.getElementById('accounts') - document.getElementById('contractStatus').innerHTML = 'Deployed' + let onboarding + try { + onboarding = new MetamaskOnboarding({ forwarderOrigin }) + } catch (error) { + console.error(error) + } + let accounts + let piggybankContract - depositButton.addEventListener('click', function () { - document.getElementById('contractStatus').innerHTML = 'Deposit initiated' - contract.deposit({ from: web3.eth.accounts[0], value: '0x3782dace9d900000' }, function (result) { - console.log(result) - document.getElementById('contractStatus').innerHTML = 'Deposit completed' - }) - }) + const accountButtons = [ + deployButton, + depositButton, + withdrawButton, + sendButton, + createToken, + transferTokens, + approveTokens, + transferTokensWithoutGas, + approveTokensWithoutGas, + ] - withdrawButton.addEventListener('click', function () { - contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) { - console.log(result) - document.getElementById('contractStatus').innerHTML = 'Withdrawn' - }) - }) + for (const button of accountButtons) { + button.disabled = true + } + + const isMetaMaskConnected = () => accounts && accounts.length > 0 + + const onClickInstall = () => { + onboardButton.innerText = 'Onboarding in progress' + onboardButton.disabled = true + onboarding.startOnboarding() + } + + const onClickConnect = async () => { + await window.ethereum.enable() + } + + const updateButtons = () => { + const accountButtonsDisabled = !isMetaMaskInstalled() || !isMetaMaskConnected() + if (accountButtonsDisabled) { + for (const button of accountButtons) { + button.disabled = true + } + } else { + deployButton.disabled = false + sendButton.disabled = false + createToken.disabled = false + } + + if (!isMetaMaskInstalled()) { + onboardButton.innerText = 'Click here to install MetaMask!' + onboardButton.onclick = onClickInstall + } else if (isMetaMaskConnected()) { + onboardButton.innerText = 'Connected' + onboardButton.disabled = true + if (onboarding) { + onboarding.stopOnboarding() + } + } else { + onboardButton.innerText = 'Connect' + onboardButton.onclick = onClickConnect + } + } + + const initializeAccountButtons = () => { + piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}]) + deployButton.onclick = async () => { + contractStatus.innerHTML = 'Deploying' + + const piggybank = await piggybankContract.new( + { + from: accounts[0], + data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', + gas: '4700000', + }, (error, contract) => { + if (error) { + contractStatus.innerHTML = 'Deployment Failed' + throw error + } else if (contract.address === undefined) { + return + } + + console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + contractStatus.innerHTML = 'Deployed' + depositButton.disabled = false + withdrawButton.disabled = false + + depositButton.onclick = () => { + contractStatus.innerHTML = 'Deposit initiated' + contract.deposit( + { + from: accounts[0], + value: '0x3782dace9d900000', + }, + (result) => { + console.log(result) + contractStatus.innerHTML = 'Deposit completed' + } + ) + } + withdrawButton.onclick = () => { + contract.withdraw( + '0xde0b6b3a7640000', + { from: accounts[0] }, + (result) => { + console.log(result) + contractStatus.innerHTML = 'Withdrawn' + } + ) + } } + ) + console.log(piggybank) + } + + sendButton.onclick = () => { + web3.eth.sendTransaction({ + from: accounts[0], + to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + value: '0x29a2241af62c0000', + gas: 21000, + gasPrice: 20000000000, + }, (result) => { + console.log(result) }) + } - console.log(piggybank) - }) - - sendButton.addEventListener('click', function () { - web3.eth.sendTransaction({ - from: web3.eth.accounts[0], - to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - value: '0x29a2241af62c0000', - gas: 21000, - gasPrice: 20000000000, - }, (result) => { - console.log(result) - }) - }) - - - createToken.addEventListener('click', async function () { - var _initialAmount = 100 - var _tokenName = 'TST' - var _decimalUnits = 0 - var _tokenSymbol = 'TST' - var humanstandardtokenContract = web3.eth.contract([{'constant': true, 'inputs': [], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'totalSupply', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_from', 'type': 'address'}, {'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'decimals', 'outputs': [{'name': '', 'type': 'uint8'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': 'balance', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'symbol', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}, {'name': '_extraData', 'type': 'bytes'}], 'name': 'approveAndCall', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}, {'name': '_spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'name': 'remaining', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'name': '_initialAmount', 'type': 'uint256'}, {'name': '_tokenName', 'type': 'string'}, {'name': '_decimalUnits', 'type': 'uint8'}, {'name': '_tokenSymbol', 'type': 'string'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': false, 'stateMutability': 'nonpayable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_from', 'type': 'address'}, {'indexed': true, 'name': '_to', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_owner', 'type': 'address'}, {'indexed': true, 'name': '_spender', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}]) - return humanstandardtokenContract.new( - _initialAmount, - _tokenName, - _decimalUnits, - _tokenSymbol, - { - from: web3.eth.accounts[0], - data: '0x60806040523480156200001157600080fd5b506040516200156638038062001566833981018060405260808110156200003757600080fd5b8101908080516401000000008111156200005057600080fd5b828101905060208101848111156200006757600080fd5b81518560018202830111640100000000821117156200008557600080fd5b50509291906020018051640100000000811115620000a257600080fd5b82810190506020810184811115620000b957600080fd5b8151856001820283011164010000000082111715620000d757600080fd5b5050929190602001805190602001909291908051906020019092919050505083838382600390805190602001906200011192919062000305565b5081600490805190602001906200012a92919062000305565b5080600560006101000a81548160ff021916908360ff1602179055505050506200016433826200016e640100000000026401000000009004565b50505050620003b4565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515620001ab57600080fd5b620001d081600254620002e36401000000000262001155179091906401000000009004565b60028190555062000237816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054620002e36401000000000262001155179091906401000000009004565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6000808284019050838110151515620002fb57600080fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200034857805160ff191683800117855562000379565b8280016001018555821562000379579182015b82811115620003785782518255916020019190600101906200035b565b5b5090506200038891906200038c565b5090565b620003b191905b80821115620003ad57600081600090555060010162000393565b5090565b90565b6111a280620003c46000396000f3fe6080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014457806318160ddd146101b757806323b872dd146101e2578063313ce5671461027557806339509351146102a657806370a082311461031957806395d89b411461037e578063a457c2d71461040e578063a9059cbb14610481578063dd62ed3e146104f4575b600080fd5b3480156100c057600080fd5b506100c9610579565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101095780820151818401526020810190506100ee565b50505050905090810190601f1680156101365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015057600080fd5b5061019d6004803603604081101561016757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061061b565b604051808215151515815260200191505060405180910390f35b3480156101c357600080fd5b506101cc610748565b6040518082815260200191505060405180910390f35b3480156101ee57600080fd5b5061025b6004803603606081101561020557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610752565b604051808215151515815260200191505060405180910390f35b34801561028157600080fd5b5061028a61095a565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102b257600080fd5b506102ff600480360360408110156102c957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610971565b604051808215151515815260200191505060405180910390f35b34801561032557600080fd5b506103686004803603602081101561033c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ba8565b6040518082815260200191505060405180910390f35b34801561038a57600080fd5b50610393610bf0565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d35780820151818401526020810190506103b8565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b506104676004803603604081101561043157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c92565b604051808215151515815260200191505060405180910390f35b34801561048d57600080fd5b506104da600480360360408110156104a457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610ec9565b604051808215151515815260200191505060405180910390f35b34801561050057600080fd5b506105636004803603604081101561051757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ee0565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106115780601f106105e657610100808354040283529160200191610611565b820191906000526020600020905b8154815290600101906020018083116105f457829003601f168201915b5050505050905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561065857600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000600254905090565b60006107e382600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6790919063ffffffff16565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061086e848484610f89565b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a3600190509392505050565b6000600560009054906101000a900460ff16905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156109ae57600080fd5b610a3d82600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461115590919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a36001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c885780601f10610c5d57610100808354040283529160200191610c88565b820191906000526020600020905b815481529060010190602001808311610c6b57829003601f168201915b5050505050905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515610ccf57600080fd5b610d5e82600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6790919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a36001905092915050565b6000610ed6338484610f89565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000828211151515610f7857600080fd5b600082840390508091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515610fc557600080fd5b611016816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6790919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506110a9816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461115590919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b600080828401905083811015151561116c57600080fd5b809150509291505056fea165627a7a723058205fcdfea06f4d97b442bc9f444b1e92524bc66398eb4f37ed5a99f2093a8842640029000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000000000003545354000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035453540000000000000000000000000000000000000000000000000000000000', - gas: '4700000', - gasPrice: '20000000000', - }, function (e, contract) { - console.log(e, contract) - if (typeof contract.address !== 'undefined') { - console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + createToken.onclick = async () => { + const _initialAmount = 100 + const _tokenName = 'TST' + const _decimalUnits = 0 + const _tokenSymbol = 'TST' + const humanstandardtokenContract = web3.eth.contract([{'constant': true, 'inputs': [], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'totalSupply', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_from', 'type': 'address'}, {'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'decimals', 'outputs': [{'name': '', 'type': 'uint8'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': 'balance', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'symbol', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}, {'name': '_extraData', 'type': 'bytes'}], 'name': 'approveAndCall', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}, {'name': '_spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'name': 'remaining', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'name': '_initialAmount', 'type': 'uint256'}, {'name': '_tokenName', 'type': 'string'}, {'name': '_decimalUnits', 'type': 'uint8'}, {'name': '_tokenSymbol', 'type': 'string'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': false, 'stateMutability': 'nonpayable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_from', 'type': 'address'}, {'indexed': true, 'name': '_to', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_owner', 'type': 'address'}, {'indexed': true, 'name': '_spender', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}]) + + return humanstandardtokenContract.new( + _initialAmount, + _tokenName, + _decimalUnits, + _tokenSymbol, + { + from: accounts[0], + data: '0x60806040523480156200001157600080fd5b506040516200156638038062001566833981018060405260808110156200003757600080fd5b8101908080516401000000008111156200005057600080fd5b828101905060208101848111156200006757600080fd5b81518560018202830111640100000000821117156200008557600080fd5b50509291906020018051640100000000811115620000a257600080fd5b82810190506020810184811115620000b957600080fd5b8151856001820283011164010000000082111715620000d757600080fd5b5050929190602001805190602001909291908051906020019092919050505083838382600390805190602001906200011192919062000305565b5081600490805190602001906200012a92919062000305565b5080600560006101000a81548160ff021916908360ff1602179055505050506200016433826200016e640100000000026401000000009004565b50505050620003b4565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515620001ab57600080fd5b620001d081600254620002e36401000000000262001155179091906401000000009004565b60028190555062000237816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054620002e36401000000000262001155179091906401000000009004565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6000808284019050838110151515620002fb57600080fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200034857805160ff191683800117855562000379565b8280016001018555821562000379579182015b82811115620003785782518255916020019190600101906200035b565b5b5090506200038891906200038c565b5090565b620003b191905b80821115620003ad57600081600090555060010162000393565b5090565b90565b6111a280620003c46000396000f3fe6080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014457806318160ddd146101b757806323b872dd146101e2578063313ce5671461027557806339509351146102a657806370a082311461031957806395d89b411461037e578063a457c2d71461040e578063a9059cbb14610481578063dd62ed3e146104f4575b600080fd5b3480156100c057600080fd5b506100c9610579565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101095780820151818401526020810190506100ee565b50505050905090810190601f1680156101365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015057600080fd5b5061019d6004803603604081101561016757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061061b565b604051808215151515815260200191505060405180910390f35b3480156101c357600080fd5b506101cc610748565b6040518082815260200191505060405180910390f35b3480156101ee57600080fd5b5061025b6004803603606081101561020557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610752565b604051808215151515815260200191505060405180910390f35b34801561028157600080fd5b5061028a61095a565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102b257600080fd5b506102ff600480360360408110156102c957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610971565b604051808215151515815260200191505060405180910390f35b34801561032557600080fd5b506103686004803603602081101561033c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ba8565b6040518082815260200191505060405180910390f35b34801561038a57600080fd5b50610393610bf0565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d35780820151818401526020810190506103b8565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b506104676004803603604081101561043157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c92565b604051808215151515815260200191505060405180910390f35b34801561048d57600080fd5b506104da600480360360408110156104a457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610ec9565b604051808215151515815260200191505060405180910390f35b34801561050057600080fd5b506105636004803603604081101561051757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ee0565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106115780601f106105e657610100808354040283529160200191610611565b820191906000526020600020905b8154815290600101906020018083116105f457829003601f168201915b5050505050905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561065857600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000600254905090565b60006107e382600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6790919063ffffffff16565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061086e848484610f89565b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a3600190509392505050565b6000600560009054906101000a900460ff16905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156109ae57600080fd5b610a3d82600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461115590919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a36001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c885780601f10610c5d57610100808354040283529160200191610c88565b820191906000526020600020905b815481529060010190602001808311610c6b57829003601f168201915b5050505050905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515610ccf57600080fd5b610d5e82600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6790919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a36001905092915050565b6000610ed6338484610f89565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000828211151515610f7857600080fd5b600082840390508091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515610fc557600080fd5b611016816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6790919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506110a9816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461115590919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b600080828401905083811015151561116c57600080fd5b809150509291505056fea165627a7a723058205fcdfea06f4d97b442bc9f444b1e92524bc66398eb4f37ed5a99f2093a8842640029000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000000000003545354000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035453540000000000000000000000000000000000000000000000000000000000', + gas: '4700000', + gasPrice: '20000000000', + }, (error, contract) => { + if (error) { + tokenAddress.innerHTML = 'Creation Failed' + throw error + } else if (contract.address === undefined) { + return + } - document.getElementById('tokenAddress').innerHTML = contract.address + console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + tokenAddress.innerHTML = contract.address + transferTokens.disabled = false + approveTokens.disabled = false + transferTokensWithoutGas.disabled = false + approveTokensWithoutGas.disabled = false - transferTokens.addEventListener('click', function (event) { + transferTokens.onclick = (event) => { console.log(`event`, event) contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '15000', { - from: web3.eth.accounts[0], + from: accounts[0], to: contract.address, data: '0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c9700000000000000000000000000000000000000000000000000000000000003a98', gas: 60000, gasPrice: '20000000000', - }, function (result) { + }, (result) => { console.log('result', result) }) - }) + } - approveTokens.addEventListener('click', function () { + approveTokens.onclick = () => { contract.approve('0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4', '70000', { - from: web3.eth.accounts[0], + from: accounts[0], to: contract.address, data: '0x095ea7b30000000000000000000000009bc5baF874d2DA8D216aE9f137804184EE5AfEF40000000000000000000000000000000000000000000000000000000000000005', gas: 60000, gasPrice: '20000000000', - }, function (result) { + }, (result) => { console.log(result) }) - }) + } - transferTokensWithoutGas.addEventListener('click', function (event) { + transferTokensWithoutGas.onclick = (event) => { console.log(`event`, event) contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '15000', { - from: web3.eth.accounts[0], + from: accounts[0], to: contract.address, data: '0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c9700000000000000000000000000000000000000000000000000000000000003a98', gasPrice: '20000000000', - }, function (result) { + }, (result) => { console.log('result', result) }) - }) + } - approveTokensWithoutGas.addEventListener('click', function () { + approveTokensWithoutGas.onclick = () => { contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '70000', { - from: web3.eth.accounts[0], + from: accounts[0], to: contract.address, data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', gasPrice: '20000000000', - }, function (result) { + }, (result) => { console.log(result) }) - }) + } } - }) - - }) - - ethereum.autoRefreshOnNetworkChange = false - - const networkDiv = document.getElementById('network') - const chainIdDiv = document.getElementById('chainId') - const accountsDiv = document.getElementById('accounts') + ) + } - ethereum.on('networkChanged', (networkId) => { - networkDiv.innerHTML = networkId - }) - - ethereum.on('chainIdChanged', (chainId) => { - chainIdDiv.innerHTML = chainId - }) - - ethereum.on('accountsChanged', (accounts) => { - accountsDiv.innerHTML = accounts - }) - - const signTypedDataResultsDiv = document.getElementById('signTypedDataResult') - signTypedData.addEventListener('click', function () { - - const typedData = { - 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: 3, - verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', - }, - message: { - sender: { - name: 'Cow', - wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + signTypedData.addEventListener('click', () => { + const typedData = { + 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' }, + ], }, - recipient: { - name: 'Bob', - wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 3, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', }, - contents: 'Hello, Bob!', - }, - } - web3.currentProvider.sendAsync({ - method: 'eth_signTypedData_v3', - params: [ethereum.selectedAddress, JSON.stringify(typedData)], - from: ethereum.selectedAddress, - }, function (err, result) { - if (err) { - console.log(err) - } else { - signTypedDataResultsDiv.innerHTML = result + message: { + sender: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + recipient: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + } + web3.currentProvider.sendAsync({ + method: 'eth_signTypedData_v3', + params: [ethereum.selectedAddress, JSON.stringify(typedData)], + from: ethereum.selectedAddress, + }, (err, result) => { + if (err) { + console.log(err) + } else { + signTypedDataResults.innerHTML = result + } + }) + }) + + } + + updateButtons() + if (isMetaMaskInstalled()) { + ethereum.autoRefreshOnNetworkChange = false + ethereum.on('networkChanged', (networkId) => { + networkDiv.innerHTML = networkId + }) + ethereum.on('chainIdChanged', (chainId) => { + chainIdDiv.innerHTML = chainId + }) + ethereum.on('accountsChanged', (newAccounts) => { + const connecting = Boolean((!accounts || !accounts.length) && newAccounts && newAccounts.length) + accounts = newAccounts + accountsDiv.innerHTML = accounts + if (connecting) { + initializeAccountButtons() } + updateButtons() }) - }) -}) + } +} +window.addEventListener('DOMContentLoaded', initialize) diff --git a/test/e2e/contract-test/index.html b/test/e2e/contract-test/index.html index 9689654ee083..9454a67dd28d 100644 --- a/test/e2e/contract-test/index.html +++ b/test/e2e/contract-test/index.html @@ -1,51 +1,64 @@ + E2E Test Dapp + + -
-
Contract
-
- - - -
-
- Not clicked -
-
-
-
Send eth
-
+
+

E2E Test Dapp

+
+
+
+

Connect

+ +
+
+

Contract

+
+ + + +
+
+ Contract Status: Not clicked +
+
+
+

Send Eth

-
-
-
-
Send tokens
-
-
- - - - - -
-
-
-
Network:
-
ChainId:
-
Accounts:
-
-
-
-
Sign Typed Data
-
+ +
+

Send Tokens

+
+ Token: +
+
+ + + + + +
+
+
+

Status

+
+ Network: +
+
+ ChainId: +
+
+ Accounts: +
+
+
+

Sign Typed Data

-
Sign Typed Data Result:
-
-
- - +
Sign Typed Data Result:
+ + - - \ No newline at end of file + diff --git a/test/e2e/ethereum-on.spec.js b/test/e2e/ethereum-on.spec.js index 9c6cd4ceb68c..ca062ca26a8b 100644 --- a/test/e2e/ethereum-on.spec.js +++ b/test/e2e/ethereum-on.spec.js @@ -117,6 +117,11 @@ describe('MetaMask', function () { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) + const connectButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await connectButton.click() + + await delay(regularDelayMs) + await waitUntilXWindowHandles(driver, 3) const windowHandles = await driver.getAllWindowHandles() @@ -132,9 +137,9 @@ describe('MetaMask', function () { await delay(regularDelayMs) }) - it('has not set the network within the dapp', async () => { + it('has the ganache network id within the dapp', async () => { const networkDiv = await findElement(driver, By.css('#network')) - assert.equal(await networkDiv.getText(), '') + assert.equal(await networkDiv.getText(), '5777') }) it('changes the network', async () => { diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index a0efe56f9668..b5a8220b0a29 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -436,6 +436,11 @@ describe('MetaMask', function () { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) + const connectButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await connectButton.click() + + await delay(regularDelayMs) + await waitUntilXWindowHandles(driver, 3) windowHandles = await driver.getAllWindowHandles() diff --git a/test/e2e/run-web3.sh b/test/e2e/run-web3.sh index 174370683a24..729333b840a6 100755 --- a/test/e2e/run-web3.sh +++ b/test/e2e/run-web3.sh @@ -9,5 +9,5 @@ export PATH="$PATH:./node_modules/.bin" concurrently --kill-others \ --names 'dapp,e2e' \ --prefix '[{time}][{name}]' \ - 'static-server test/web3 --port 8080' \ + 'node development/static-server.js test/web3 --port 8080' \ 'sleep 5 && mocha test/e2e/web3.spec' diff --git a/test/e2e/signature-request.spec.js b/test/e2e/signature-request.spec.js index e9490e08dc4d..a5be61baf077 100644 --- a/test/e2e/signature-request.spec.js +++ b/test/e2e/signature-request.spec.js @@ -128,6 +128,11 @@ describe('MetaMask', function () { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) + const connectButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await connectButton.click() + + await delay(regularDelayMs) + await waitUntilXWindowHandles(driver, 3) windowHandles = await driver.getAllWindowHandles() diff --git a/test/e2e/web3.spec.js b/test/e2e/web3.spec.js index 6dd0813223b1..f576b397fb90 100644 --- a/test/e2e/web3.spec.js +++ b/test/e2e/web3.spec.js @@ -126,6 +126,11 @@ describe('Using MetaMask with an existing account', function () { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) + const connectButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await connectButton.click() + + await delay(regularDelayMs) + await waitUntilXWindowHandles(driver, 3) const windowHandles = await driver.getAllWindowHandles() diff --git a/ui/app/components/ui/snackbar/index.js b/ui/app/components/ui/snackbar/index.js new file mode 100644 index 000000000000..3d3e0394dd97 --- /dev/null +++ b/ui/app/components/ui/snackbar/index.js @@ -0,0 +1 @@ +export { default } from './snackbar.component' diff --git a/ui/app/components/ui/snackbar/index.scss b/ui/app/components/ui/snackbar/index.scss new file mode 100644 index 000000000000..5cfab7a9b19a --- /dev/null +++ b/ui/app/components/ui/snackbar/index.scss @@ -0,0 +1,11 @@ +.snackbar { + padding: .75rem 1rem; + font-size: 0.75rem; + color: $Blue-600; + min-width: 360px; + width: fit-content; + + background: $Blue-000; + border: 1px solid $Blue-200; + border-radius: 6px; +} diff --git a/ui/app/components/ui/snackbar/snackbar.component.js b/ui/app/components/ui/snackbar/snackbar.component.js new file mode 100644 index 000000000000..8945341fef4d --- /dev/null +++ b/ui/app/components/ui/snackbar/snackbar.component.js @@ -0,0 +1,18 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' + +const Snackbar = ({ className = '', content }) => { + return ( +
+ { content } +
+ ) +} + +Snackbar.propTypes = { + className: PropTypes.string, + content: PropTypes.string.isRequired, +} + +module.exports = Snackbar diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss index 0e2034670dd1..01c913a1a1f0 100644 --- a/ui/app/css/itcss/components/index.scss +++ b/ui/app/css/itcss/components/index.scss @@ -1,5 +1,6 @@ @import '../../../components/ui/button/buttons'; @import '../../../components/ui/dialog/dialog'; +@import '../../../components/ui/snackbar/index'; @import './footer.scss'; diff --git a/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js b/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js index 8cbf4d69f930..f603c827b14e 100644 --- a/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js +++ b/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js @@ -1,8 +1,10 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import Button from '../../../components/ui/button' +import Snackbar from '../../../components/ui/snackbar' import MetaFoxLogo from '../../../components/ui/metafox-logo' import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' +import { returnToOnboardingInitiator } from '../onboarding-initiator-util' export default class EndOfFlowScreen extends PureComponent { static contextTypes = { @@ -14,11 +16,33 @@ export default class EndOfFlowScreen extends PureComponent { history: PropTypes.object, completeOnboarding: PropTypes.func, completionMetaMetricsName: PropTypes.string, + onboardingInitiator: PropTypes.exact({ + location: PropTypes.string, + tabId: PropTypes.number, + }), + } + + onComplete = async () => { + const { history, completeOnboarding, completionMetaMetricsName, onboardingInitiator } = this.props + + await completeOnboarding() + this.context.metricsEvent({ + eventOpts: { + category: 'Onboarding', + action: 'Onboarding Complete', + name: completionMetaMetricsName, + }, + }) + + if (onboardingInitiator) { + await returnToOnboardingInitiator(onboardingInitiator) + } + history.push(DEFAULT_ROUTE) } render () { const { t } = this.context - const { history, completeOnboarding, completionMetaMetricsName } = this.props + const { onboardingInitiator } = this.props return (
@@ -62,20 +86,17 @@ export default class EndOfFlowScreen extends PureComponent { + { + onboardingInitiator ? + : + null + }
) } diff --git a/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.container.js b/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.container.js index 38313806c48d..2bb9ef15ab72 100644 --- a/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.container.js +++ b/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.container.js @@ -1,21 +1,22 @@ import { connect } from 'react-redux' import EndOfFlow from './end-of-flow.component' import { setCompletedOnboarding } from '../../../store/actions' +import { getOnboardingInitiator } from '../first-time-flow.selectors' const firstTimeFlowTypeNameMap = { create: 'New Wallet Created', 'import': 'New Wallet Imported', } -const mapStateToProps = ({ metamask }) => { - const { firstTimeFlowType } = metamask +const mapStateToProps = (state) => { + const { metamask: { firstTimeFlowType } } = state return { completionMetaMetricsName: firstTimeFlowTypeNameMap[firstTimeFlowType], + onboardingInitiator: getOnboardingInitiator(state), } } - const mapDispatchToProps = dispatch => { return { completeOnboarding: () => dispatch(setCompletedOnboarding()), diff --git a/ui/app/pages/first-time-flow/end-of-flow/index.scss b/ui/app/pages/first-time-flow/end-of-flow/index.scss index d7eb4513b176..de603fce4dec 100644 --- a/ui/app/pages/first-time-flow/end-of-flow/index.scss +++ b/ui/app/pages/first-time-flow/end-of-flow/index.scss @@ -50,4 +50,4 @@ font-size: 80px; margin-top: 70px; } -} \ No newline at end of file +} diff --git a/ui/app/pages/first-time-flow/first-time-flow.selectors.js b/ui/app/pages/first-time-flow/first-time-flow.selectors.js index e6cd5a84ac3b..74cad5e12b51 100644 --- a/ui/app/pages/first-time-flow/first-time-flow.selectors.js +++ b/ui/app/pages/first-time-flow/first-time-flow.selectors.js @@ -4,12 +4,6 @@ import { DEFAULT_ROUTE, } from '../../helpers/constants/routes' -const selectors = { - getFirstTimeFlowTypeRoute, -} - -module.exports = selectors - function getFirstTimeFlowTypeRoute (state) { const { firstTimeFlowType } = state.metamask @@ -24,3 +18,25 @@ function getFirstTimeFlowTypeRoute (state) { return nextRoute } + +const getOnboardingInitiator = (state) => { + const { onboardingTabs } = state.metamask + + if (!onboardingTabs || Object.keys(onboardingTabs).length !== 1) { + return null + } + + const location = Object.keys(onboardingTabs)[0] + const tabId = onboardingTabs[location] + return { + location, + tabId, + } +} + +const selectors = { + getFirstTimeFlowTypeRoute, + getOnboardingInitiator, +} + +module.exports = selectors diff --git a/ui/app/pages/first-time-flow/onboarding-initiator-util.js b/ui/app/pages/first-time-flow/onboarding-initiator-util.js new file mode 100644 index 000000000000..dd70085f6aa3 --- /dev/null +++ b/ui/app/pages/first-time-flow/onboarding-initiator-util.js @@ -0,0 +1,48 @@ +import extension from 'extensionizer' +import log from 'loglevel' + +const returnToOnboardingInitiatorTab = async (onboardingInitiator) => { + const tab = await (new Promise((resolve) => { + extension.tabs.update(onboardingInitiator.tabId, { active: true }, (tab) => { + if (tab) { + resolve(tab) + } else { + // silence console message about unchecked error + if (extension.runtime.lastError) { + log.debug(extension.runtime.lastError) + } + resolve() + } + }) + })) + + if (!tab) { + // this case can happen if the tab was closed since being checked with `extension.tabs.get` + log.warn(`Setting current tab to onboarding initator has failed; falling back to redirect`) + window.location.assign(onboardingInitiator.location) + } else { + window.close() + } +} + +export const returnToOnboardingInitiator = async (onboardingInitiator) => { + const tab = await (new Promise((resolve) => { + extension.tabs.get(onboardingInitiator.tabId, (tab) => { + if (tab) { + resolve(tab) + } else { + // silence console message about unchecked error + if (extension.runtime.lastError) { + log.debug(extension.runtime.lastError) + } + resolve() + } + }) + })) + + if (tab) { + await returnToOnboardingInitiatorTab(onboardingInitiator) + } else { + window.location.assign(onboardingInitiator.location) + } +} diff --git a/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss b/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss index dfe9868cfa63..583d92a0bb9f 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss +++ b/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss @@ -60,7 +60,7 @@ } button { - margin-top: 0xp; + margin-top: 0px; } &__buttons { diff --git a/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js b/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js index 4144fb8789cd..bd45a61e8ce2 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js +++ b/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js @@ -3,8 +3,10 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import LockIcon from '../../../../components/ui/lock-icon' import Button from '../../../../components/ui/button' +import Snackbar from '../../../../components/ui/snackbar' import { INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE, DEFAULT_ROUTE } from '../../../../helpers/constants/routes' import { exportAsFile } from '../../../../helpers/utils/util' +import { returnToOnboardingInitiator } from '../../onboarding-initiator-util' export default class RevealSeedPhrase extends PureComponent { static contextTypes = { @@ -17,6 +19,10 @@ export default class RevealSeedPhrase extends PureComponent { seedPhrase: PropTypes.string, setSeedPhraseBackedUp: PropTypes.func, setCompletedOnboarding: PropTypes.func, + onboardingInitiator: PropTypes.exact({ + location: PropTypes.string, + tabId: PropTypes.number, + }), } state = { @@ -27,8 +33,7 @@ export default class RevealSeedPhrase extends PureComponent { exportAsFile('MetaMask Secret Backup Phrase', this.props.seedPhrase, 'text/plain') } - handleNext = event => { - event.preventDefault() + handleNext = () => { const { isShowingSeedPhrase } = this.state const { history } = this.props @@ -47,9 +52,8 @@ export default class RevealSeedPhrase extends PureComponent { history.push(INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE) } - handleSkip = event => { - event.preventDefault() - const { history, setSeedPhraseBackedUp, setCompletedOnboarding } = this.props + handleSkip = async () => { + const { history, setSeedPhraseBackedUp, setCompletedOnboarding, onboardingInitiator } = this.props this.context.metricsEvent({ eventOpts: { @@ -59,10 +63,12 @@ export default class RevealSeedPhrase extends PureComponent { }, }) - Promise.all([setCompletedOnboarding(), setSeedPhraseBackedUp(false)]) - .then(() => { - history.push(DEFAULT_ROUTE) - }) + await Promise.all([setCompletedOnboarding(), setSeedPhraseBackedUp(false)]) + + if (onboardingInitiator) { + await returnToOnboardingInitiator(onboardingInitiator) + } + history.push(DEFAULT_ROUTE) } renderSecretWordsContainer () { @@ -111,6 +117,7 @@ export default class RevealSeedPhrase extends PureComponent { render () { const { t } = this.context const { isShowingSeedPhrase } = this.state + const { onboardingInitiator } = this.props return (
@@ -166,6 +173,13 @@ export default class RevealSeedPhrase extends PureComponent { { t('next') }
+ { + onboardingInitiator ? + : + null + }
) } diff --git a/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.container.js b/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.container.js index 7ada36afc940..11a26fb6d2ab 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.container.js +++ b/ui/app/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.container.js @@ -4,6 +4,13 @@ import { setCompletedOnboarding, setSeedPhraseBackedUp, } from '../../../../store/actions' +import { getOnboardingInitiator } from '../../first-time-flow.selectors' + +const mapStateToProps = (state) => { + return { + onboardingInitiator: getOnboardingInitiator(state), + } +} const mapDispatchToProps = dispatch => { return { @@ -12,4 +19,4 @@ const mapDispatchToProps = dispatch => { } } -export default connect(null, mapDispatchToProps)(RevealSeedPhrase) +export default connect(mapStateToProps, mapDispatchToProps)(RevealSeedPhrase) diff --git a/yarn.lock b/yarn.lock index 5e9578a16af7..edd2a97fb86d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1985,6 +1985,18 @@ scroll "^2.0.3" warning "^3.0.0" +"@metamask/forwarder@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@metamask/forwarder/-/forwarder-1.0.0.tgz#3e321022a36561cc6e7b7c84df25f600925f4d95" + integrity sha512-ufgPndhZz0oNhRrixiR6cXH/HwtFwurWvbrU8zAZsFnf1hB4L2VB2Wey/P1wStIx+BJJQjyROvCDyPDoz4ny1A== + +"@metamask/onboarding@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@metamask/onboarding/-/onboarding-0.1.2.tgz#d5126cbb5e593d782645d6236c497e27bd38d3c4" + integrity sha512-+85Z5OxckGuYr5cCoMlpxASu9geJBMYvwkNWqa5qDDEYKZ8eNXHsADcVYFsvBhxFcf87dC7ty1kWljYVEfTIIA== + dependencies: + bowser "^2.5.4" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -3560,11 +3572,6 @@ ansi-red@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-regex@^0.2.0, ansi-regex@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" - integrity sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk= - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -3580,11 +3587,6 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-styles@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" - integrity sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94= - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -4025,10 +4027,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0: integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assert@^1.1.1, assert@^1.3.0, assert@^1.4.0, assert@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== dependencies: + object-assign "^4.1.1" util "0.10.3" assertion-error@^1.0.1: @@ -5640,6 +5643,11 @@ bowser@^1.7.3: resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.3.tgz#6643ae4d783f31683f6d23156976b74183862162" integrity sha512-/gp96UlcFw5DbV2KQPCqTqi0Mb9gZRyDAHiDsGEH+4B/KOQjeoE5lM1PxlVX8DQDvfEfitmC1rW2Oy8fk/XBDg== +bowser@^2.5.4: + version "2.7.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.7.0.tgz#96eab1fa07fab08c1ec4c75977a7c8ddf8e0fe1f" + integrity sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w== + boxen@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -6435,17 +6443,6 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4. escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" - integrity sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ= - dependencies: - ansi-styles "^1.1.0" - escape-string-regexp "^1.0.0" - has-ansi "^0.1.0" - strip-ansi "^0.3.0" - supports-color "^0.2.0" - chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -7023,7 +7020,7 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.7.tgz#419cd7fb3258b1ed838dc0953167a25e152f5b59" integrity sha512-Jrx3xsP4pPv4AwJUDWY9wOXGtwPXARej6Xd99h4TUGotmf8APuquKMpK+dnD3UgyxK7OEWaisjZz+3b5jtL6xQ== -commander@2, commander@2.11.0, commander@^2.3.0, commander@^2.5.0, commander@^2.6.0: +commander@2, commander@2.11.0, commander@^2.5.0, commander@^2.6.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== @@ -7237,6 +7234,11 @@ contains-path@^0.1.0: resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + content-disposition@0.5.3, content-disposition@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -9598,7 +9600,7 @@ escape-html@^1.0.3, escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -11308,6 +11310,13 @@ fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.0.7: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + fast-write-atomic@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/fast-write-atomic/-/fast-write-atomic-0.2.1.tgz#7ee8ef0ce3c1f531043c09ae8e5143361ab17ede" @@ -11442,11 +11451,6 @@ file-loader@^3.0.1: loader-utils "^1.0.2" schema-utils "^1.0.0" -file-size@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/file-size/-/file-size-0.0.5.tgz#057d43c3a3ed735da3f90d6052ab380f1e6d5e3b" - integrity sha1-BX1Dw6Ptc12j+Q1gUqs4Dx5tXjs= - file-system-cache@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-1.0.5.tgz#84259b36a2bbb8d3d6eb1021d3132ffe64cfff4f" @@ -13288,13 +13292,6 @@ har-validator@~5.1.0: ajv "^6.5.5" har-schema "^2.0.0" -has-ansi@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" - integrity sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4= - dependencies: - ansi-regex "^0.2.0" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -18311,11 +18308,23 @@ mime-db@^1.28.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.41.0.tgz#9110408e1f6aa1b34aef51f2c9df3caddf46b6a0" integrity sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw== +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + mime-db@~1.38.0: version "1.38.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + mime-types@^2.1.12, mime-types@^2.1.21, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.24" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" @@ -18335,7 +18344,7 @@ mime@1.6.0, mime@^1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^1.2.11, mime@^1.4.1: +mime@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== @@ -19766,13 +19775,6 @@ opn@5.4.0: dependencies: is-wsl "^1.1.0" -opn@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" - integrity sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ== - dependencies: - is-wsl "^1.1.0" - optimist@0.6.x, optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -20443,7 +20445,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-is-inside@^1.0.1, path-is-inside@^1.0.2: +path-is-inside@1.0.2, path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= @@ -20480,6 +20482,11 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + path-to-regexp@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" @@ -21928,6 +21935,11 @@ randomhex@0.1.5: resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" integrity sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU= +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + range-parser@^1.2.0, range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -24148,6 +24160,20 @@ serve-favicon@^2.5.0: parseurl "~1.3.2" safe-buffer "5.1.1" +serve-handler@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.2.tgz#f05b0421a313fff2d257838cba00cbcc512cd2b6" + integrity sha512-RFh49wX7zJmmOVDcIjiDSJnMH+ItQEvyuYLYuDBVoA/xmQSCuj+uRmk1cmBB5QQlI3qOiWKp6p4DUGY+Z5AB2A== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -25048,17 +25074,6 @@ static-module@^2.2.0: static-eval "^2.0.0" through2 "~2.0.3" -static-server@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/static-server/-/static-server-2.2.1.tgz#49e3cae2a001736b0ee9e95d21d3d843fc95efaa" - integrity sha512-j5eeW6higxYNmXMIT8iHjsdiViTpQDthg7o+SHsRtqdbxscdHqBHXwrXjHC8hL3F0Tsu34ApUpDkwzMBPBsrLw== - dependencies: - chalk "^0.5.1" - commander "^2.3.0" - file-size "0.0.5" - mime "^1.2.11" - opn "^5.2.0" - "statuses@>= 1.3.1 < 2": version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -25363,13 +25378,6 @@ strip-ansi@5.2.0, strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" - integrity sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA= - dependencies: - ansi-regex "^0.2.1" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -25639,11 +25647,6 @@ supports-color@4.4.0: dependencies: has-flag "^2.0.0" -supports-color@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" - integrity sha1-2S3iaU6z9nMjlz1649i1W0wiGQo= - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" From 7dd0b13408a278da6ad2de9ae4d217e9ecf4c45a Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 16:53:38 -0330 Subject: [PATCH 12/88] Add EOL conversion to gitattributes (#7494) --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 590ac71c00ef..561741e377ba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ +* text=auto CHANGELOG.md merge=union # Reviewing the lockfile contents is an important step in verifying that From 5235d8db965bd90fb1c8dfc9b253aa07247f568f Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 17:23:27 -0330 Subject: [PATCH 13/88] Remove unused onClick prop from Dropdown component (#7500) --- ui/app/components/app/dropdowns/components/dropdown.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/app/components/app/dropdowns/components/dropdown.js b/ui/app/components/app/dropdowns/components/dropdown.js index cc966ffa5bb1..fd705580331c 100644 --- a/ui/app/components/app/dropdowns/components/dropdown.js +++ b/ui/app/components/app/dropdowns/components/dropdown.js @@ -58,7 +58,6 @@ Dropdown.defaultProps = { Dropdown.propTypes = { isOpen: PropTypes.bool.isRequired, - onClick: PropTypes.func.isRequired, children: PropTypes.node, style: PropTypes.object.isRequired, onClickOutside: PropTypes.func, From f7c9903d953f17b1f63b7a2e89628088a5278512 Mon Sep 17 00:00:00 2001 From: Bruno Barbieri Date: Fri, 22 Nov 2019 17:25:44 -0500 Subject: [PATCH 14/88] Fix chainId for non standard networks (#7502) --- app/scripts/lib/select-chain-id.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/select-chain-id.js b/app/scripts/lib/select-chain-id.js index 3171c98402e5..d94b35898f7d 100644 --- a/app/scripts/lib/select-chain-id.js +++ b/app/scripts/lib/select-chain-id.js @@ -15,8 +15,8 @@ const standardNetworkId = { } function selectChainId (metamaskState) { - const { network, provider: { chaindId } } = metamaskState - return standardNetworkId[network] || `0x${parseInt(chaindId, 10).toString(16)}` + const { network, provider: { chainId } } = metamaskState + return standardNetworkId[network] || `0x${parseInt(chainId, 10).toString(16)}` } module.exports = selectChainId From 6820a245b5d6f27c35494ec03037e80e5b640ea8 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 20:13:58 -0330 Subject: [PATCH 15/88] Convert InputNumber component to use JSX (#7503) --- ui/app/components/app/input-number.js | 57 ++++++++++++++------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/ui/app/components/app/input-number.js b/ui/app/components/app/input-number.js index ed678755f5f8..d511dd0d68a0 100644 --- a/ui/app/components/app/input-number.js +++ b/ui/app/components/app/input-number.js @@ -1,5 +1,5 @@ +import React from 'react' const Component = require('react').Component -const h = require('react-hyperscript') const inherits = require('util').inherits const { addCurrencies, @@ -52,32 +52,35 @@ InputNumber.prototype.setValue = function (newValue) { } } -InputNumber.prototype.render = function () { +InputNumber.prototype.render = function InputNumber () { const { unitLabel, step = 1, placeholder, value } = this.props - return h('div.customize-gas-input-wrapper', {}, [ - h('input', { - className: 'customize-gas-input', - value, - placeholder, - type: 'number', - onChange: e => { - this.setValue(e.target.value) - }, - min: 0, - }), - h('span.gas-tooltip-input-detail', {}, [unitLabel]), - h('div.gas-tooltip-input-arrows', {}, [ - h('div.gas-tooltip-input-arrow-wrapper', { - onClick: () => this.setValue(addCurrencies(value, step, { toNumericBase: 'dec' })), - }, [ - h('i.fa.fa-angle-up'), - ]), - h('div.gas-tooltip-input-arrow-wrapper', { - onClick: () => this.setValue(subtractCurrencies(value, step, { toNumericBase: 'dec' })), - }, [ - h('i.fa.fa-angle-down'), - ]), - ]), - ]) + return ( +
+ { + this.setValue(e.target.value) + }} + min={0} + /> + {unitLabel} +
+
this.setValue(addCurrencies(value, step, { toNumericBase: 'dec' }))} + > + +
+
this.setValue(subtractCurrencies(value, step, { toNumericBase: 'dec' }))} + > + +
+
+
+ ) } From 878e0e3164fd0a2c60febc4a2c1a2e9d62fb9f24 Mon Sep 17 00:00:00 2001 From: ryanml Date: Fri, 22 Nov 2019 18:54:59 -0700 Subject: [PATCH 16/88] Fixing hardware connect error display (#7519) --- .../pages/create-account/connect-hardware/index.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ui/app/pages/create-account/connect-hardware/index.js b/ui/app/pages/create-account/connect-hardware/index.js index 66851c780616..ff8506142a0a 100644 --- a/ui/app/pages/create-account/connect-hardware/index.js +++ b/ui/app/pages/create-account/connect-hardware/index.js @@ -116,10 +116,11 @@ class ConnectHardwareForm extends Component { } }) .catch(e => { - if (e === 'Window blocked') { + const errorMessage = e.message + if (errorMessage === 'Window blocked') { this.setState({ browserSupported: false, error: null}) - } else if (e !== 'Window closed' && e !== 'Popup closed') { - this.setState({ error: e.toString() }) + } else if (errorMessage !== 'Window closed' && errorMessage !== 'Popup closed') { + this.setState({ error: errorMessage }) } }) } @@ -134,7 +135,7 @@ class ConnectHardwareForm extends Component { unlocked: false, }) }).catch(e => { - this.setState({ error: e.toString() }) + this.setState({ error: e.message }) }) } @@ -162,10 +163,10 @@ class ConnectHardwareForm extends Component { name: 'Error connecting hardware wallet', }, customVariables: { - error: e.toString(), + error: e.message, }, }) - this.setState({ error: e.toString() }) + this.setState({ error: e.message }) }) } From 3d598473a0925bda1f3a9fb6fcd2fa4560e4d05a Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 22:48:46 -0330 Subject: [PATCH 17/88] Convert AccountPanel component to use JSX (#7505) --- ui/app/components/app/account-panel.js | 54 +++++++++----------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/ui/app/components/app/account-panel.js b/ui/app/components/app/account-panel.js index e61cb8ad67fe..2bae0a296615 100644 --- a/ui/app/components/app/account-panel.js +++ b/ui/app/components/app/account-panel.js @@ -1,6 +1,5 @@ +import React, { Component } from 'react' const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') import Identicon from '../ui/identicon' const formatBalance = require('../../helpers/utils/util').formatBalance const addressSummary = require('../../helpers/utils/util').addressSummary @@ -33,39 +32,24 @@ AccountPanel.prototype.render = function () { } return ( - - h('.identity-panel.flex-row.flex-space-between', { - style: { - flex: '1 0 auto', - cursor: panelState.onClick ? 'pointer' : undefined, - }, - onClick: panelState.onClick, - }, [ - - // account identicon - h('.identicon-wrapper.flex-column.select-none', [ - h(Identicon, { - address: panelState.identiconKey, - imageify: state.imageifyIdenticons, - }), - h('span.font-small', panelState.identiconLabel.substring(0, 7) + '...'), - ]), - - // account address, balance - h('.identity-data.flex-column.flex-justify-center.flex-grow.select-none', [ - - panelState.attributes.map((attr) => { - return h('.flex-row.flex-space-between', { - key: '' + Math.round(Math.random() * 1000000), - }, [ - h('label.font-small.no-select', attr.key), - h('span.font-small', attr.value), - ]) - }), - ]), - - ]) - +
+
+ + {panelState.identiconLabel.substring(0, 7) + '...'} +
+
+ {panelState.attributes.map((attr) => ( +
+ + {attr.value} +
+ ))} +
+
) } From df88e7656d0ecda75079d62f94961a70a2f39272 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 23:26:02 -0330 Subject: [PATCH 18/88] Delete unused GasSlider component (#7508) --- .../app/customize-gas-modal/gas-slider.js | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100644 ui/app/components/app/customize-gas-modal/gas-slider.js diff --git a/ui/app/components/app/customize-gas-modal/gas-slider.js b/ui/app/components/app/customize-gas-modal/gas-slider.js deleted file mode 100644 index 69fd6f985610..000000000000 --- a/ui/app/components/app/customize-gas-modal/gas-slider.js +++ /dev/null @@ -1,50 +0,0 @@ -// const Component = require('react').Component -// const h = require('react-hyperscript') -// const inherits = require('util').inherits - -// module.exports = GasSlider - -// inherits(GasSlider, Component) -// function GasSlider () { -// Component.call(this) -// } - -// GasSlider.prototype.render = function () { -// const { -// memo, -// identities, -// onChange, -// unitLabel, -// value, -// id, -// step, -// max, -// min, -// } = this.props - -// return h('div.gas-slider', [ - -// h('input.gas-slider__input', { -// type: 'range', -// step, -// max, -// min, -// value, -// id: 'gasSlider', -// onChange: event => onChange(event.target.value), -// }, []), - -// h('div.gas-slider__bar', [ - -// h('div.gas-slider__low'), - -// h('div.gas-slider__mid'), - -// h('div.gas-slider__high'), - -// ]), - -// ]) - -// } - From 1d9787c0d8803a3e54aa8f04d5ed51e4b04e188c Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 23:28:33 -0330 Subject: [PATCH 19/88] Convert GasModalCard component to use JSX (#7507) --- .../app/customize-gas-modal/gas-modal-card.js | 48 +++++++------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/ui/app/components/app/customize-gas-modal/gas-modal-card.js b/ui/app/components/app/customize-gas-modal/gas-modal-card.js index 23754d819bd3..5ba96dd82428 100644 --- a/ui/app/components/app/customize-gas-modal/gas-modal-card.js +++ b/ui/app/components/app/customize-gas-modal/gas-modal-card.js @@ -1,8 +1,6 @@ -const Component = require('react').Component -const h = require('react-hyperscript') +import React, {Component} from 'react' const inherits = require('util').inherits const InputNumber = require('../input-number.js') -// const GasSlider = require('./gas-slider.js') module.exports = GasModalCard @@ -11,44 +9,30 @@ function GasModalCard () { Component.call(this) } -GasModalCard.prototype.render = function () { +GasModalCard.prototype.render = function GasModalCard () { const { - // memo, onChange, unitLabel, value, min, - // max, step, title, copy, } = this.props - return h('div.send-v2__gas-modal-card', [ - - h('div.send-v2__gas-modal-card__title', {}, title), - - h('div.send-v2__gas-modal-card__copy', {}, copy), - - h(InputNumber, { - unitLabel, - step, - // max, - min, - placeholder: '0', - value, - onChange, - }), - - // h(GasSlider, { - // value, - // step, - // max, - // min, - // onChange, - // }), - - ]) - + return ( +
+
{title}
+
{copy}
+ +
+ ) } From 7a0e40829ab7bb2fe0b697904e87ec76f2b3a4c5 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 23:52:41 -0330 Subject: [PATCH 20/88] Convert AccountDetailsDropdown component to use JSX (#7509) --- .../app/dropdowns/account-details-dropdown.js | 155 ++++++++++-------- 1 file changed, 85 insertions(+), 70 deletions(-) diff --git a/ui/app/components/app/dropdowns/account-details-dropdown.js b/ui/app/components/app/dropdowns/account-details-dropdown.js index cf2aa8ae8299..89e7f91ef60c 100644 --- a/ui/app/components/app/dropdowns/account-details-dropdown.js +++ b/ui/app/components/app/dropdowns/account-details-dropdown.js @@ -1,6 +1,5 @@ -const Component = require('react').Component +import React, { Component } from 'react' const PropTypes = require('prop-types') -const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../../store/actions') @@ -50,7 +49,7 @@ AccountDetailsDropdown.prototype.onClose = function (e) { this.props.onClose() } -AccountDetailsDropdown.prototype.render = function () { +AccountDetailsDropdown.prototype.render = function AccountDetailsDropdown () { const { selectedIdentity, network, @@ -69,71 +68,87 @@ AccountDetailsDropdown.prototype.render = function () { const isRemovable = keyring.type !== 'HD Key Tree' - return h(Menu, { className: 'account-details-dropdown', isShowing: true }, [ - h(CloseArea, { - onClick: this.onClose, - }), - h(Item, { - onClick: (e) => { - e.stopPropagation() - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Account Options', - name: 'Clicked Expand View', - }, - }) - global.platform.openExtensionInBrowser() - this.props.onClose() - }, - text: this.context.t('expandView'), - icon: h(`img`, { src: 'images/expand.svg', style: { height: '15px' } }), - }), - h(Item, { - onClick: (e) => { - e.stopPropagation() - showAccountDetailModal() - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Account Options', - name: 'Viewed Account Details', - }, - }) - this.props.onClose() - }, - text: this.context.t('accountDetails'), - icon: h(`img`, { src: 'images/info.svg', style: { height: '15px' } }), - }), - h(Item, { - onClick: (e) => { - e.stopPropagation() - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Account Options', - name: 'Clicked View on Etherscan', - }, - }) - viewOnEtherscan(address, network, rpcPrefs) - this.props.onClose() - }, - text: (rpcPrefs.blockExplorerUrl - ? this.context.t('viewinExplorer') - : this.context.t('viewOnEtherscan')), - subText: (rpcPrefs.blockExplorerUrl - ? rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/)[1] - : null), - icon: h(`img`, { src: 'images/open-etherscan.svg', style: { height: '15px' } }), - }), - isRemovable ? h(Item, { - onClick: (e) => { - e.stopPropagation() - showRemoveAccountConfirmationModal(selectedIdentity) - this.props.onClose() - }, - text: this.context.t('removeAccount'), - icon: h(`img`, { src: 'images/hide.svg', style: { height: '15px' } }), - }) : null, - ]) + return ( + + + { + e.stopPropagation() + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Account Options', + name: 'Clicked Expand View', + }, + }) + global.platform.openExtensionInBrowser() + this.props.onClose() + }} + text={this.context.t('expandView')} + icon={( + + )} + /> + { + e.stopPropagation() + showAccountDetailModal() + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Account Options', + name: 'Viewed Account Details', + }, + }) + this.props.onClose() + }} + text={this.context.t('accountDetails')} + icon={( + + )} + /> + { + e.stopPropagation() + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Account Options', + name: 'Clicked View on Etherscan', + }, + }) + viewOnEtherscan(address, network, rpcPrefs) + this.props.onClose() + }} + text={ + rpcPrefs.blockExplorerUrl + ? this.context.t('viewinExplorer') + : this.context.t('viewOnEtherscan') + } + subText={ + rpcPrefs.blockExplorerUrl + ? rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/)[1] + : null + } + icon={( + + )} + /> + { + isRemovable + ? ( + { + e.stopPropagation() + showRemoveAccountConfirmationModal(selectedIdentity) + this.props.onClose() + }} + text={this.context.t('removeAccount')} + icon={} + /> + ) + : null + } + + ) } From 7d097dedaf92bfcbbfe9cb9619cd29038ba9287f Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 22 Nov 2019 23:53:16 -0330 Subject: [PATCH 21/88] Convert Dropdown and DropdownMenuItem components to JSX (#7510) --- .../app/dropdowns/components/dropdown.js | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/ui/app/components/app/dropdowns/components/dropdown.js b/ui/app/components/app/dropdowns/components/dropdown.js index fd705580331c..ad6c1c5140b1 100644 --- a/ui/app/components/app/dropdowns/components/dropdown.js +++ b/ui/app/components/app/dropdowns/components/dropdown.js @@ -1,6 +1,5 @@ -const Component = require('react').Component +import React, { Component } from 'react' const PropTypes = require('prop-types') -const h = require('react-hyperscript') const MenuDroppo = require('../../menu-droppo') const extend = require('xtend') @@ -23,31 +22,28 @@ class Dropdown extends Component { boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', }, innerStyle) - return h( - MenuDroppo, - { - containerClassName, - useCssTransition, - isOpen, - zIndex: 55, - onClickOutside, - style, - innerStyle: innerStyleDefaults, - }, - [ - h( - 'style', - ` - li.dropdown-menu-item:hover { - color:rgb(225, 225, 225); - background-color: rgba(255, 255, 255, 0.05); - border-radius: 4px; - } - li.dropdown-menu-item { color: rgb(185, 185, 185); } - ` - ), - ...children, - ] + return ( + + + { children } + ) } } @@ -70,14 +66,14 @@ class DropdownMenuItem extends Component { render () { const { onClick, closeMenu, children, style } = this.props - return h( - 'li.dropdown-menu-item', - { - onClick: () => { + return ( +
  • { onClick() closeMenu() - }, - style: Object.assign({ + }} + style={Object.assign({ listStyle: 'none', padding: '8px 0px', fontSize: '18px', @@ -87,9 +83,10 @@ class DropdownMenuItem extends Component { justifyContent: 'flex-start', alignItems: 'center', color: 'white', - }, style), - }, - children + }, style)} + > + {children} +
  • ) } } From c775a842d10b5d0cd9f9db9b7cdda282f3fccd21 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 00:10:35 -0330 Subject: [PATCH 22/88] Convert QrCodeView to use JSX (#7504) --- ui/app/components/ui/qr-code.js | 92 +++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/ui/app/components/ui/qr-code.js b/ui/app/components/ui/qr-code.js index 351e072e2c84..e0b7f3ff2222 100644 --- a/ui/app/components/ui/qr-code.js +++ b/ui/app/components/ui/qr-code.js @@ -1,7 +1,6 @@ -const Component = require('react').Component -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React from 'react' const qrCode = require('qrcode-generator') -const inherits = require('util').inherits const connect = require('react-redux').connect const { isHexPrefixed } = require('ethereumjs-util') const ReadOnlyInput = require('./readonly-input') @@ -17,47 +16,60 @@ function mapStateToProps (state) { } } -inherits(QrCodeView, Component) - -function QrCodeView () { - Component.call(this) -} - -QrCodeView.prototype.render = function () { - const props = this.props - const { message, data, network } = props.Qr - const address = `${isHexPrefixed(data) ? 'ethereum:' : ''}${checksumAddress(data, network)}` +function QrCodeView (props) { + const { message, data } = props.Qr + const address = `${isHexPrefixed(data) ? 'ethereum:' : ''}${checksumAddress(data)}` const qrImage = qrCode(4, 'M') qrImage.addData(address) qrImage.make() - return h('.div.flex-column.flex-center', [ - Array.isArray(message) - ? h('.message-container', this.renderMultiMessage()) - : message && h('.qr-header', message), - - this.props.warning ? this.props.warning && h('span.error.flex-center', { - style: { - }, - }, - this.props.warning) : null, - - h('.div.qr-wrapper', { - style: {}, - dangerouslySetInnerHTML: { - __html: qrImage.createTableTag(4), - }, - }), - h(ReadOnlyInput, { - wrapperClass: 'ellip-address-wrapper', - inputClass: 'qr-ellip-address', - value: checksumAddress(data, network), - }), - ]) + return ( +
    + { + Array.isArray(message) + ? ( +
    + {props.Qr.message.map((message, index) => ( +
    + {message} +
    + ))} +
    + ) + : message && ( +
    + {message} +
    + ) + } + { + props.warning + ? (props.warning && ( + + {props.warning} + + )) + : null + } +
    + +
    + ) } -QrCodeView.prototype.renderMultiMessage = function () { - var Qr = this.props.Qr - var multiMessage = Qr.message.map((message) => h('.qr-message', message)) - return multiMessage +QrCodeView.propTypes = { + warning: PropTypes.node, + Qr: PropTypes.shape({ + message: PropTypes.array, + data: PropTypes.string.isRequired, + }).isRequired, } From d7fabae847ca9b4ee30921e5d1a7bc2478187587 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 00:43:48 -0330 Subject: [PATCH 23/88] Convert JsonImportSubview component to use JSX (#7521) --- .../create-account/import-account/json.js | 85 +++++++++---------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/ui/app/pages/create-account/import-account/json.js b/ui/app/pages/create-account/import-account/json.js index 2482e49d173a..c9ff8d926f52 100644 --- a/ui/app/pages/create-account/import-account/json.js +++ b/ui/app/pages/create-account/import-account/json.js @@ -1,6 +1,5 @@ -const Component = require('react').Component +import React, { Component } from 'react' const PropTypes = require('prop-types') -const h = require('react-hyperscript') const { withRouter } = require('react-router-dom') const { compose } = require('recompose') const connect = require('react-redux').connect @@ -26,53 +25,51 @@ class JsonImportSubview extends Component { const { error } = this.props return ( - h('div.new-account-import-form__json', [ - - h('p', this.context.t('usedByClients')), - h('a.warning', { - href: HELP_LINK, - target: '_blank', - }, this.context.t('fileImportFail')), - - h(FileInput, { - readAs: 'text', - onLoad: this.onLoad.bind(this), - style: { +
    +

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

    + {this.context.t('fileImportFail')} + this.props.history.push(DEFAULT_ROUTE), - }, [this.context.t('cancel')]), - - h(Button, { - type: 'secondary', - large: true, - className: 'new-account-create-form__button', - onClick: () => this.createNewKeychain(), - }, [this.context.t('import')]), - - ]), - - error ? h('span.error', error) : null, - ]) + }} + /> + +
    + + +
    + { + error + ? {error} + : null + } +
    ) } From 1454426e3e23277939e8d8841a6010907c27ff65 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 00:44:12 -0330 Subject: [PATCH 24/88] Convert AccountImportSubview to use JSX (#7520) --- .../create-account/import-account/index.js | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/ui/app/pages/create-account/import-account/index.js b/ui/app/pages/create-account/import-account/index.js index 48d8f8838bf5..d89aa6df82e8 100644 --- a/ui/app/pages/create-account/import-account/index.js +++ b/ui/app/pages/create-account/import-account/index.js @@ -1,6 +1,5 @@ +import React, { Component } from 'react' const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') const PropTypes = require('prop-types') const connect = require('react-redux').connect import Select from 'react-select' @@ -35,47 +34,44 @@ AccountImportSubview.prototype.render = function () { const { type } = state return ( - h('div.new-account-import-form', [ - - h('.new-account-import-disclaimer', [ - h('span', this.context.t('importAccountMsg')), - h('span', { - style: { +
    +
    + {this.context.t('importAccountMsg')} + { + }} + onClick={() => { global.platform.openWindow({ url: 'https://metamask.zendesk.com/hc/en-us/articles/360015289932', }) - }, - }, this.context.t('here')), - ]), - - h('div.new-account-import-form__select-section', [ - - h('div.new-account-import-form__select-label', this.context.t('selectType')), - - h(Select, { - className: 'new-account-import-form__select', - name: 'import-type-select', - clearable: false, - value: type || menuItems[0], - options: menuItems.map((type) => { + }}> + {this.context.t('here')} + +
    +
    +
    + {this.context.t('selectType')} +
    + this.createKeyringOnEnter(e)} + /> +
    +
    + + +
    + { + error + ? {error} + : null + } +
    ) } From 3086c0db7102f7f50f93b790cd180d7b9774eb8d Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 12:52:52 -0330 Subject: [PATCH 36/88] Convert AccountList component to use JSX (#7524) --- .../connect-hardware/account-list.js | 223 +++++++++--------- 1 file changed, 113 insertions(+), 110 deletions(-) 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 71684783f47d..af9f58210344 100644 --- a/ui/app/pages/create-account/connect-hardware/account-list.js +++ b/ui/app/pages/create-account/connect-hardware/account-list.js @@ -1,8 +1,7 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import Select from 'react-select' const genAccountLink = require('../../../../lib/account-link.js') -const Select = require('react-select').default import Button from '../../../components/ui/button' class AccountList extends Component { @@ -36,22 +35,28 @@ class AccountList extends Component { const { onPathChange, selectedPath } = this.props const options = this.getHdPaths() - return h('div', [ - h('h3.hw-connect__hdPath__title', {}, this.context.t('selectHdPath')), - h('p.hw-connect__msg', {}, this.context.t('selectPathHelp')), - h('div.hw-connect__hdPath', [ - h(Select, { - className: 'hw-connect__hdPath__select', - name: 'hd-path-select', - clearable: false, - value: selectedPath, - options, - onChange: (opt) => { - onPathChange(opt.value) - }, - }), - ]), - ]) + return ( +
    +

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

    +

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

    +
    + this.props.onAccountChange(e.target.value)} + checked={this.props.selectedAccount === account.index.toString()} + /> + +
    + + + +
    + ))} +
    + ) } renderPagination () { - return h('div.hw-list-pagination', [ - h( - 'button.hw-list-pagination__button', - { - onClick: this.goToPreviousPage, - }, - `< ${this.context.t('prev')}` - ), - - h( - 'button.hw-list-pagination__button', - { - onClick: this.goToNextPage, - }, - `${this.context.t('next')} >` - ), - ]) + return ( +
    + + +
    + ) } renderButtons () { @@ -139,40 +133,49 @@ class AccountList extends Component { buttonProps.disabled = true } - return h('div.new-account-connect-form__buttons', {}, [ - h(Button, { - type: 'default', - large: true, - className: 'new-account-connect-form__button', - onClick: this.props.onCancel.bind(this), - }, [this.context.t('cancel')]), - - h(Button, { - type: 'primary', - large: true, - className: 'new-account-connect-form__button unlock', - disabled, - onClick: this.props.onUnlockAccount.bind(this, this.props.device), - }, [this.context.t('unlock')]), - ]) + return ( +
    + + +
    + ) } renderForgetDevice () { - return h('div.hw-forget-device-container', {}, [ - h('a', { - onClick: this.props.onForgetDevice.bind(this, this.props.device), - }, this.context.t('forgetDevice')), - ]) + return ( + + ) } render () { - return h('div.new-account-connect-form.account-list', {}, [ - this.renderHeader(), - this.renderAccounts(), - this.renderPagination(), - this.renderButtons(), - this.renderForgetDevice(), - ]) + return ( +
    + {this.renderHeader()} + {this.renderAccounts()} + {this.renderPagination()} + {this.renderButtons()} + {this.renderForgetDevice()} +
    + ) } } From 80badb10c13d75c0e4ffc72e9673f4e5e9ab646e Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 12:53:09 -0330 Subject: [PATCH 37/88] Convert ConnectScreen to use JSX (#7525) --- .../connect-hardware/connect-screen.js | 375 +++++++++--------- 1 file changed, 198 insertions(+), 177 deletions(-) diff --git a/ui/app/pages/create-account/connect-hardware/connect-screen.js b/ui/app/pages/create-account/connect-hardware/connect-screen.js index b1323b46762d..3a7d3a3af8bb 100644 --- a/ui/app/pages/create-account/connect-hardware/connect-screen.js +++ b/ui/app/pages/create-account/connect-hardware/connect-screen.js @@ -1,206 +1,227 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import classnames from 'classnames' +import PropTypes from 'prop-types' +import React, { Component } from 'react' import Button from '../../../components/ui/button' class ConnectScreen extends Component { - constructor (props) { - super(props) - this.state = { - selectedDevice: null, - } + static contextTypes = { + t: PropTypes.func, } - connect = () => { - if (this.state.selectedDevice) { - this.props.connectToHardwareWallet(this.state.selectedDevice) - } - return null - } + static propTypes = { + connectToHardwareWallet: PropTypes.func.isRequired, + browserSupported: PropTypes.bool.isRequired, + } - renderConnectToTrezorButton () { - return h( - `button.hw-connect__btn${this.state.selectedDevice === 'trezor' ? '.selected' : ''}`, - { onClick: _ => this.setState({selectedDevice: 'trezor'}) }, - h('img.hw-connect__btn__img', { - src: 'images/trezor-logo.svg', - }) - ) - } + state = { + selectedDevice: null, + } - renderConnectToLedgerButton () { - return h( - `button.hw-connect__btn${this.state.selectedDevice === 'ledger' ? '.selected' : ''}`, - { onClick: _ => this.setState({selectedDevice: 'ledger'}) }, - h('img.hw-connect__btn__img', { - src: 'images/ledger-logo.svg', - }) - ) + connect = () => { + if (this.state.selectedDevice) { + this.props.connectToHardwareWallet(this.state.selectedDevice) } + return null + } - renderButtons () { - return ( - h('div', {}, [ - h('div.hw-connect__btn-wrapper', {}, [ - this.renderConnectToLedgerButton(), - this.renderConnectToTrezorButton(), - ]), - h(Button, { - type: 'primary', - large: true, - className: 'hw-connect__connect-btn', - onClick: this.connect, - disabled: !this.state.selectedDevice, - }, this.context.t('connect')), - ]) - ) - } + renderConnectToTrezorButton () { + return ( + + ) + } - renderUnsupportedBrowser () { - return ( - h('div.new-account-connect-form.unsupported-browser', {}, [ - h('div.hw-connect', [ - h('h3.hw-connect__title', {}, this.context.t('browserNotSupported')), - h('p.hw-connect__msg', {}, this.context.t('chromeRequiredForHardwareWallets')), - ]), - h(Button, { - type: 'primary', - large: true, - onClick: () => global.platform.openWindow({ - url: 'https://google.com/chrome', - }), - }, this.context.t('downloadGoogleChrome')), - ]) - ) - } + renderConnectToLedgerButton () { + return ( + + ) + } - renderHeader () { - return ( - h('div.hw-connect__header', {}, [ - h('h3.hw-connect__header__title', {}, this.context.t('hardwareWallets')), - h('p.hw-connect__header__msg', {}, this.context.t('hardwareWalletsMsg')), - ]) - ) - } + renderButtons () { + return ( +
    +
    + {this.renderConnectToLedgerButton()} + {this.renderConnectToTrezorButton()} +
    + +
    + ) + } - getAffiliateLinks () { - const links = { - trezor: `Trezor`, - ledger: `Ledger`, - } + renderUnsupportedBrowser () { + return ( +
    +
    +

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

    +

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

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

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

    +

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

    +
    + ) + } - return h('div.hw-connect__get-hw__msg', { dangerouslySetInnerHTML: {__html: response }}) + getAffiliateLinks () { + const links = { + trezor: `Trezor`, + ledger: `Ledger`, } - renderTrezorAffiliateLink () { - return h('div.hw-connect__get-hw', {}, [ - h('p.hw-connect__get-hw__msg', {}, this.context.t('dontHaveAHardwareWallet')), - this.getAffiliateLinks(), - ]) - } + const text = this.context.t('orderOneHere') + const response = text.replace('Trezor', links.trezor).replace('Ledger', links.ledger) + return ( +
    + ) + } - scrollToTutorial = () => { - if (this.referenceNode) { - this.referenceNode.scrollIntoView({behavior: 'smooth'}) - } - } + renderTrezorAffiliateLink () { + return ( +
    +

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

    + {this.getAffiliateLinks()} +
    + ) + } - renderLearnMore () { - return ( - h('p.hw-connect__learn-more', { - onClick: this.scrollToTutorial, - }, [ - this.context.t('learnMore'), - h('img.hw-connect__learn-more__arrow', { src: 'images/caret-right.svg'}), - ]) - ) - } - renderTutorialSteps () { - const steps = [ - { - asset: 'hardware-wallet-step-1', - dimensions: {width: '225px', height: '75px'}, - title: this.context.t('step1HardwareWallet'), - message: this.context.t('step1HardwareWalletMsg'), - }, - { - asset: 'hardware-wallet-step-2', - dimensions: {width: '300px', height: '100px'}, - title: this.context.t('step2HardwareWallet'), - message: this.context.t('step2HardwareWalletMsg'), - }, - { - asset: 'hardware-wallet-step-3', - dimensions: {width: '120px', height: '90px'}, - title: this.context.t('step3HardwareWallet'), - message: this.context.t('step3HardwareWalletMsg'), - }, - ] - - return h('.hw-tutorial', { - ref: node => { - this.referenceNode = node - }, - }, - steps.map((step) => ( - h('div.hw-connect', {}, [ - h('h3.hw-connect__title', {}, step.title), - h('p.hw-connect__msg', {}, step.message), - h('img.hw-connect__step-asset', { src: `images/${step.asset}.svg`, ...step.dimensions }), - ]) - )) - ) + scrollToTutorial = () => { + if (this.referenceNode) { + this.referenceNode.scrollIntoView({behavior: 'smooth'}) } + } - renderFooter () { - return ( - h('div.hw-connect__footer', {}, [ - h('h3.hw-connect__footer__title', {}, this.context.t('readyToConnect')), - this.renderButtons(), - h('p.hw-connect__footer__msg', {}, [ - this.context.t('havingTroubleConnecting'), - h('a.hw-connect__footer__link', { - href: 'https://support.metamask.io/', - target: '_blank', - }, this.context.t('getHelp')), - ]), - ]) - ) - } + renderLearnMore () { + return ( +

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

    + ) + } - renderConnectScreen () { - return ( - h('div.new-account-connect-form', {}, [ - this.renderHeader(), - this.renderButtons(), - this.renderTrezorAffiliateLink(), - this.renderLearnMore(), - this.renderTutorialSteps(), - this.renderFooter(), - ]) - ) - } + renderTutorialSteps () { + const steps = [ + { + asset: 'hardware-wallet-step-1', + dimensions: {width: '225px', height: '75px'}, + title: this.context.t('step1HardwareWallet'), + message: this.context.t('step1HardwareWalletMsg'), + }, + { + asset: 'hardware-wallet-step-2', + dimensions: {width: '300px', height: '100px'}, + title: this.context.t('step2HardwareWallet'), + message: this.context.t('step2HardwareWalletMsg'), + }, + { + asset: 'hardware-wallet-step-3', + dimensions: {width: '120px', height: '90px'}, + title: this.context.t('step3HardwareWallet'), + message: this.context.t('step3HardwareWalletMsg'), + }, + ] - render () { - if (this.props.browserSupported) { - return this.renderConnectScreen() - } - return this.renderUnsupportedBrowser() - } -} + return ( +
    { + this.referenceNode = node + }}> + {steps.map((step, index) => ( +
    +

    {step.title}

    +

    {step.message}

    + +
    + ))} +
    + ) + } -ConnectScreen.propTypes = { - connectToHardwareWallet: PropTypes.func.isRequired, - browserSupported: PropTypes.bool.isRequired, -} + renderFooter () { + return ( +
    +

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

    + {this.renderButtons()} +

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

    +
    + ) + } -ConnectScreen.contextTypes = { - t: PropTypes.func, + renderConnectScreen () { + return ( +
    + {this.renderHeader()} + {this.renderButtons()} + {this.renderTrezorAffiliateLink()} + {this.renderLearnMore()} + {this.renderTutorialSteps()} + {this.renderFooter()} +
    + ) + } + + render () { + if (this.props.browserSupported) { + return this.renderConnectScreen() + } + return this.renderUnsupportedBrowser() + } } module.exports = ConnectScreen From 49dfb5ec2c800f6ab2e24fdb406a70c1652f9460 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 14:44:09 -0330 Subject: [PATCH 38/88] Convert ConnectHardwareForm component to JSX (#7517) --- .../create-account/connect-hardware/index.js | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/ui/app/pages/create-account/connect-hardware/index.js b/ui/app/pages/create-account/connect-hardware/index.js index ff8506142a0a..351699e8a1a3 100644 --- a/ui/app/pages/create-account/connect-hardware/index.js +++ b/ui/app/pages/create-account/connect-hardware/index.js @@ -1,6 +1,5 @@ -const { Component } = require('react') +import React, { Component } from 'react' const PropTypes = require('prop-types') -const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('../../../store/actions') const { getMetaMaskAccounts } = require('../../../selectors/selectors') @@ -176,40 +175,53 @@ class ConnectHardwareForm extends Component { renderError () { return this.state.error - ? h('span.error', { style: { margin: '20px 20px 10px', display: 'block', textAlign: 'center' } }, this.state.error) + ? ( + + {this.state.error} + + ) : null } renderContent () { if (!this.state.accounts.length) { - return h(ConnectScreen, { - connectToHardwareWallet: this.connectToHardwareWallet, - browserSupported: this.state.browserSupported, - }) + return ( + + ) } - return h(AccountList, { - onPathChange: this.onPathChange, - selectedPath: this.props.defaultHdPaths[this.state.device], - device: this.state.device, - accounts: this.state.accounts, - selectedAccount: this.state.selectedAccount, - onAccountChange: this.onAccountChange, - network: this.props.network, - getPage: this.getPage, - history: this.props.history, - onUnlockAccount: this.onUnlockAccount, - onForgetDevice: this.onForgetDevice, - onCancel: this.onCancel, - onAccountRestriction: this.onAccountRestriction, - }) + return ( + + ) } render () { - return h('div', [ - this.renderError(), - this.renderContent(), - ]) + return ( +
    + {this.renderError()} + {this.renderContent()} +
    + ) } } From 714935d36ef5d8d4d7e3771f5b8c14f248091214 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sat, 23 Nov 2019 14:44:18 -0330 Subject: [PATCH 39/88] Update Dropdown components tests to use JSX (#7527) --- .../responsive/components/dropdown-test.js | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/test/unit/responsive/components/dropdown-test.js b/test/unit/responsive/components/dropdown-test.js index 1fadbfb6012f..2b9a5457baeb 100644 --- a/test/unit/responsive/components/dropdown-test.js +++ b/test/unit/responsive/components/dropdown-test.js @@ -1,6 +1,6 @@ +const React = require('react') const assert = require('assert') -const h = require('react-hyperscript') const sinon = require('sinon') const path = require('path') const Dropdown = require(path.join(__dirname, '..', '..', '..', '..', 'ui', 'app', 'components', 'app', 'dropdowns', 'index.js')).Dropdown @@ -39,23 +39,19 @@ describe('Dropdown components', function () { onClick = sinon.spy() store = createMockStore(mockState) - component = mountWithStore(h( - Dropdown, - dropdownComponentProps, - [ - h('style', ` - .drop-menu-item:hover { background:rgb(235, 235, 235); } - .drop-menu-item i { margin: 11px; } - `), - h('li', { - closeMenu, - onClick, - }, 'Item 1'), - h('li', { - closeMenu, - onClick, - }, 'Item 2'), - ] + component = mountWithStore(( + + +
  • Item 1
  • +
  • Item 2
  • +
    ), store) dropdownComponent = component }) From 340559b8052b1f34c2bee83b551db6c27b837b6a Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:19:51 -0330 Subject: [PATCH 40/88] Convert TokenList component to use JSX (#7541) --- ui/app/components/app/token-list.js | 97 +++++++++++++---------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/ui/app/components/app/token-list.js b/ui/app/components/app/token-list.js index c15e86e1dc3a..5bab96a454af 100644 --- a/ui/app/components/app/token-list.js +++ b/ui/app/components/app/token-list.js @@ -1,6 +1,5 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React, { Component } from 'react' const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') const TokenCell = require('./token-cell.js') @@ -44,53 +43,60 @@ function TokenList () { Component.call(this) } -TokenList.prototype.render = function () { +TokenList.prototype.render = function TokenList () { const { userAddress, assetImages } = this.props const state = this.state const { tokens, isLoading, error } = state if (isLoading) { - return this.message(this.context.t('loadingTokens')) + return ( +
    + {this.context.t('loadingTokens')} +
    + ) } if (error) { log.error(error) - return h('.hotFix', { - style: { + return ( +
    { - global.platform.openWindow({ - url: `https://ethplorer.io/address/${userAddress}`, - }) - }, - }, this.context.t('here')), - ]) + }}> + {this.context.t('troubleTokenBalances')} + { + global.platform.openWindow({ + url: `https://ethplorer.io/address/${userAddress}`, + }) + }} + > + {this.context.t('here')} + +
    + ) } - return h('div', tokens.map((tokenData) => { - tokenData.image = assetImages[tokenData.address] - return h(TokenCell, tokenData) - })) - -} - -TokenList.prototype.message = function (body) { - return h('div', { - style: { - display: 'flex', - height: '250px', - alignItems: 'center', - justifyContent: 'center', - padding: '30px', - }, - }, body) + return ( +
    + {tokens.map((tokenData, index) => { + tokenData.image = assetImages[tokenData.address] + return ( + + ) + })} +
    + ) } TokenList.prototype.componentDidMount = function () { @@ -179,16 +185,3 @@ TokenList.prototype.componentWillUnmount = function () { this.tracker.removeListener('update', this.balanceUpdater) this.tracker.removeListener('error', this.showError) } - -// function uniqueMergeTokens (tokensA, tokensB = []) { -// const uniqueAddresses = [] -// const result = [] -// tokensA.concat(tokensB).forEach((token) => { -// const normal = normalizeAddress(token.address) -// if (!uniqueAddresses.includes(normal)) { -// uniqueAddresses.push(normal) -// result.push(token) -// } -// }) -// return result -// } From 6849595326df0db4557a534fee3d0a83ec13f1d7 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:20:48 -0330 Subject: [PATCH 41/88] Delete unused to-autocomplete (#7533) --- ui/app/css/itcss/components/send.scss | 60 -------- .../pages/send/to-autocomplete.component.js | 141 ------------------ ui/app/pages/send/to-autocomplete/index.js | 1 - .../send/to-autocomplete/to-autocomplete.js | 121 --------------- 4 files changed, 323 deletions(-) delete mode 100644 ui/app/pages/send/to-autocomplete.component.js delete mode 100644 ui/app/pages/send/to-autocomplete/index.js delete mode 100644 ui/app/pages/send/to-autocomplete/to-autocomplete.js diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index 47e00fb415d8..7bbfe7a09a0f 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -749,66 +749,6 @@ } } - &__to-autocomplete { - position: relative; - - &__qr-code { - z-index: 1026; - top: 13px; - right: 33px; - cursor: pointer; - padding: 8px 5px 5px; - border-radius: 4px; - } - - &__qr-code:hover { - background: #f1f1f1; - } - } - - &__to-autocomplete { - display: flex; - flex-direction: row; - z-index: 1025; - position: relative; - height: 54px; - width: 100%; - border: 1px solid $Grey-100; - border-radius: 8px; - background-color: $white; - color: $tundora; - padding: 0 10px; - font-family: Roboto; - line-height: 21px; - align-items: center; - - &__input { - font-size: 16px; - height: 100%; - border: none; - flex: 1 1 auto; - width: 0; - - &::placeholder { - color: #A1A5B3; - } - } - - &__resolved { - font-size: 12px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - height: 30px; - cursor: pointer; - - + .send-v2__to-autocomplete__qr-code { - top: 2px; - right: 0; - } - } - } - &__memo-text-area, &__hex-data { &__input { z-index: 1025; diff --git a/ui/app/pages/send/to-autocomplete.component.js b/ui/app/pages/send/to-autocomplete.component.js deleted file mode 100644 index bb27537db3f9..000000000000 --- a/ui/app/pages/send/to-autocomplete.component.js +++ /dev/null @@ -1,141 +0,0 @@ -import React, {Component} from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import AccountListItem from './account-list-item/account-list-item.component' - - -export default class ToAutoComplete extends Component { - - static propTypes = { - dropdownOpen: PropTypes.bool, - openDropdown: PropTypes.func, - closeDropdown: PropTypes.func, - onChange: PropTypes.func, - to: PropTypes.string, - accounts: PropTypes.array, - inError: PropTypes.bool, - } - - static contextTypes = { - t: PropTypes.func, - } - - state = { - accountsToRender: [], - } - - getListItemIcon (listItemAddress, toAddress) { - return toAddress && listItemAddress === toAddress - ? - : null - } - - renderDropdown () { - const { - closeDropdown, - onChange, - to, - } = this.props - const {accountsToRender} = this.state - - if (!accountsToRender.length) { - return null - } - - return ( -
    -
    -
    - {accountsToRender.map((account, i) => ( - { - onChange(account.address) - closeDropdown() - }} - icon={this.getListItemIcon(account.address, to)} - displayBalance={false} - displayAddress - /> - ))} -
    -
    - ) - } - - handleInputEvent (event = {}, cb) { - const { - to, - accounts, - closeDropdown, - openDropdown, - } = this.props - - const matchingAccounts = accounts.filter(({address}) => address.match(to || '')) - const matches = matchingAccounts.length - - if (!matches || matchingAccounts[0].address === to) { - this.setState({accountsToRender: []}) - event.target && event.target.select() - closeDropdown() - } else { - this.setState({accountsToRender: matchingAccounts}) - openDropdown() - } - cb && cb(event.target.value) - } - - componentDidUpdate (nextProps) { - if (this.props.to !== nextProps.to) { - this.handleInputEvent() - } - } - - render () { - const { - to, - dropdownOpen, - onChange, - inError, - } = this.props - - return ( -
    - onChange(event.target.value)} - onFocus={event => this.handleInputEvent(event)} - style={{ - borderColor: inError ? 'red' : null, - }} - /> - { - to - ? null - : this.handleInputEvent()} - style={{ - style: {color: '#dedede'}, - }} - /> - } - { - dropdownOpen - ? this.renderDropdown() - : null - } -
    - ) - } - -} diff --git a/ui/app/pages/send/to-autocomplete/index.js b/ui/app/pages/send/to-autocomplete/index.js deleted file mode 100644 index 244d301d1651..000000000000 --- a/ui/app/pages/send/to-autocomplete/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './to-autocomplete.js' diff --git a/ui/app/pages/send/to-autocomplete/to-autocomplete.js b/ui/app/pages/send/to-autocomplete/to-autocomplete.js deleted file mode 100644 index 71c69b5fbae1..000000000000 --- a/ui/app/pages/send/to-autocomplete/to-autocomplete.js +++ /dev/null @@ -1,121 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const AccountListItem = require('../account-list-item/account-list-item.component').default -const connect = require('react-redux').connect -const Tooltip = require('../../../components/ui/tooltip') -const checksumAddress = require('../../../helpers/utils/util').checksumAddress - -ToAutoComplete.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect()(ToAutoComplete) - - -inherits(ToAutoComplete, Component) -function ToAutoComplete () { - Component.call(this) - - this.state = { accountsToRender: [] } -} - -ToAutoComplete.prototype.getListItemIcon = function (listItemAddress, toAddress) { - const listItemIcon = h(`i.fa.fa-check.fa-lg`, { style: { color: '#02c9b1' } }) - - return toAddress && listItemAddress === toAddress - ? listItemIcon - : null -} - -ToAutoComplete.prototype.renderDropdown = function () { - const { - closeDropdown, - onChange, - to, - } = this.props - const { accountsToRender } = this.state - - return !!accountsToRender.length && h('div', {}, [ - - h('div.send-v2__from-dropdown__list', {}, [ - - ...accountsToRender.map(account => h(AccountListItem, { - account, - className: 'account-list-item__dropdown', - handleClick: () => { - onChange(checksumAddress(account.address)) - closeDropdown() - }, - icon: this.getListItemIcon(account.address, to), - displayBalance: false, - displayAddress: true, - })), - - ]), - - ]) -} - -ToAutoComplete.prototype.handleInputEvent = function (event = {}, cb) { - const { - to, - accounts, - closeDropdown, - openDropdown, - } = this.props - - const matchingAccounts = accounts.filter(({ address }) => address.match(to || '')) - const matches = matchingAccounts.length - - if (!matches || matchingAccounts[0].address === to) { - this.setState({ accountsToRender: [] }) - event.target && event.target.select() - closeDropdown() - } else { - this.setState({ accountsToRender: matchingAccounts }) - openDropdown() - } - cb && cb(event.target.value) -} - -ToAutoComplete.prototype.componentDidUpdate = function (nextProps) { - if (this.props.to !== nextProps.to) { - this.handleInputEvent() - } -} - -ToAutoComplete.prototype.render = function () { - const { - to, - onChange, - inError, - qrScanner, - } = this.props - - return h('div.send-v2__to-autocomplete', {}, [ - - h(`input.send-v2__to-autocomplete__input${qrScanner ? '.with-qr' : ''}`, { - placeholder: this.context.t('recipientAddress'), - className: inError ? `send-v2__error-border` : '', - dir: 'auto', - value: to, - onChange: event => onChange(event.target.value), - onFocus: event => this.handleInputEvent(event), - style: { - borderColor: inError ? 'red' : null, - }, - }), - qrScanner && h(Tooltip, { - title: this.context.t('scanQrCode'), - position: 'bottom', - }, h(`i.fa.fa-qrcode.fa-lg.send-v2__to-autocomplete__qr-code`, { - style: { color: '#33333' }, - onClick: () => this.props.scanQrCode(), - })), - - this.renderDropdown(), - - ]) -} From f15237b1a51dc279455c792a855db2bb6eeb982c Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:24:22 -0330 Subject: [PATCH 42/88] Convert ExportTextContainer component to use JSX (#7538) --- .../export-text-container.component.js | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) 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 21fd5ecec24e..23ae0b047284 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 @@ -1,6 +1,5 @@ -const { Component } = require('react') +import React, { Component } from 'react' const PropTypes = require('prop-types') -const h = require('react-hyperscript') const copyToClipboard = require('copy-to-clipboard') const { exportAsFile } = require('../../../helpers/utils/util') @@ -10,25 +9,33 @@ class ExportTextContainer extends Component { const { t } = this.context return ( - h('.export-text-container', [ - h('.export-text-container__text-container', [ - h('.export-text-container__text.notranslate', text), - ]), - h('.export-text-container__buttons-container', [ - h('.export-text-container__button.export-text-container__button--copy', { - onClick: () => copyToClipboard(text), - }, [ - h('img', { src: 'images/copy-to-clipboard.svg' }), - h('.export-text-container__button-text', t('copyToClipboard')), - ]), - h('.export-text-container__button', { - onClick: () => exportAsFile(filename, text), - }, [ - h('img', { src: 'images/download.svg' }), - h('.export-text-container__button-text', t('saveAsCsvFile')), - ]), - ]), - ]) +
    +
    +
    + {text} +
    +
    +
    +
    copyToClipboard(text)} + > + +
    + {t('copyToClipboard')} +
    +
    +
    exportAsFile(filename, text)} + > + +
    + {t('saveAsCsvFile')} +
    +
    +
    +
    ) } } From c51914c1a5262a7e5844bcf72f6d137f0a097559 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:28:32 -0330 Subject: [PATCH 43/88] Convert the RevealSeedPage component to use JSX (#7536) --- ui/app/pages/keychains/reveal-seed.js | 171 +++++++++++++------------- 1 file changed, 88 insertions(+), 83 deletions(-) diff --git a/ui/app/pages/keychains/reveal-seed.js b/ui/app/pages/keychains/reveal-seed.js index e83e3fd98d68..0e842594f4f6 100644 --- a/ui/app/pages/keychains/reveal-seed.js +++ b/ui/app/pages/keychains/reveal-seed.js @@ -1,7 +1,6 @@ -const { Component } = require('react') +import React, { Component } from 'react' const { connect } = require('react-redux') const PropTypes = require('prop-types') -const h = require('react-hyperscript') const classnames = require('classnames') const { requestRevealSeedWords } = require('../../store/actions') @@ -14,15 +13,11 @@ const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN' const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN' class RevealSeedPage extends Component { - constructor (props) { - super(props) - - this.state = { - screen: PASSWORD_PROMPT_SCREEN, - password: '', - seedWords: null, - error: null, - } + state = { + screen: PASSWORD_PROMPT_SCREEN, + password: '', + seedWords: null, + error: null, } componentDidMount () { @@ -42,15 +37,17 @@ class RevealSeedPage extends Component { renderWarning () { return ( - h('.page-container__warning-container', [ - h('img.page-container__warning-icon', { - src: 'images/warning.svg', - }), - h('.page-container__warning-message', [ - h('.page-container__warning-title', [this.context.t('revealSeedWordsWarningTitle')]), - h('div', [this.context.t('revealSeedWordsWarning')]), - ]), - ]) +
    + +
    +
    + {this.context.t('revealSeedWordsWarningTitle')} +
    +
    + {this.context.t('revealSeedWordsWarning')} +
    +
    +
    ) } @@ -64,24 +61,25 @@ class RevealSeedPage extends Component { const { t } = this.context return ( - h('form', { - onSubmit: event => this.handleSubmit(event), - }, [ - h('label.input-label', { - htmlFor: 'password-box', - }, t('enterPasswordContinue')), - h('.input-group', [ - h('input.form-control', { - type: 'password', - placeholder: t('password'), - id: 'password-box', - value: this.state.password, - onChange: event => this.setState({ password: event.target.value }), - className: classnames({ 'form-control--error': this.state.error }), - }), - ]), - this.state.error && h('.reveal-seed__error', this.state.error), - ]) +
    this.handleSubmit(event)}> + +
    + this.setState({ password: event.target.value })} + className={classnames('form-control', { 'form-control--error': this.state.error })} + /> +
    + { + this.state.error && ( +
    + {this.state.error} +
    + )} +
    ) } @@ -89,13 +87,10 @@ class RevealSeedPage extends Component { const { t } = this.context return ( - h('div', [ - h('label.reveal-seed__label', t('yourPrivateSeedPhrase')), - h(ExportTextContainer, { - text: this.state.seedWords, - filename: t('metamaskSeedWords'), - }), - ]) +
    + + +
    ) } @@ -107,54 +102,64 @@ class RevealSeedPage extends Component { renderPasswordPromptFooter () { return ( - h('.page-container__footer', [ - h('header', [ - h(Button, { - type: 'default', - large: true, - className: 'page-container__footer-button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('cancel')), - h(Button, { - type: 'secondary', - large: true, - className: 'page-container__footer-button', - onClick: event => this.handleSubmit(event), - disabled: this.state.password === '', - }, this.context.t('next')), - ]), - ]) +
    +
    + + +
    +
    ) } renderRevealSeedFooter () { return ( - h('.page-container__footer', [ - h(Button, { - type: 'default', - large: true, - className: 'page-container__footer-button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('close')), - ]) +
    + +
    ) } render () { return ( - h('.page-container', [ - h('.page-container__header', [ - h('.page-container__title', this.context.t('revealSeedWordsTitle')), - h('.page-container__subtitle', this.context.t('revealSeedWordsDescription')), - ]), - h('.page-container__content', [ - this.renderWarning(), - h('.reveal-seed__content', [ - this.renderContent(), - ]), - ]), - this.renderFooter(), - ]) +
    +
    +
    + {this.context.t('revealSeedWordsTitle')} +
    +
    + {this.context.t('revealSeedWordsDescription')} +
    +
    +
    + {this.renderWarning()} +
    + {this.renderContent()} +
    +
    + {this.renderFooter()} +
    ) } } From 439fce89012c5c69b80f67a8578a57cb4c0d48a2 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:29:18 -0330 Subject: [PATCH 44/88] Convert Mascot component to use JSX (#7535) --- ui/app/components/ui/mascot.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/app/components/ui/mascot.js b/ui/app/components/ui/mascot.js index e54a464db501..9606fb9aa9ed 100644 --- a/ui/app/components/ui/mascot.js +++ b/ui/app/components/ui/mascot.js @@ -1,6 +1,5 @@ +import React, { Component } from 'react' const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') const metamaskLogo = require('metamask-logo') const debounce = require('debounce') @@ -20,15 +19,17 @@ function Mascot ({width = '200', height = '200'}) { this.unfollowMouse = this.logo.setFollowMouse.bind(this.logo, false) } -Mascot.prototype.render = function () { +Mascot.prototype.render = function Mascot () { // this is a bit hacky // the event emitter is on `this.props` // and we dont get that until render this.handleAnimationEvents() - - return h('#metamask-mascot-container', { - style: { zIndex: 0 }, - }) + return ( +
    + ) } Mascot.prototype.componentDidMount = function () { From c3e834d17bc2a9d98671c86e67b5858b8664677b Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:32:14 -0330 Subject: [PATCH 45/88] Convert CustomizeGasModal component to use JSX (#7537) --- .../app/customize-gas-modal/index.js | 136 +++++++++--------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/ui/app/components/app/customize-gas-modal/index.js b/ui/app/components/app/customize-gas-modal/index.js index 1f9436810742..7bbe725b2247 100644 --- a/ui/app/components/app/customize-gas-modal/index.js +++ b/ui/app/components/app/customize-gas-modal/index.js @@ -1,6 +1,5 @@ -const Component = require('react').Component +import React, { Component } from 'react' const PropTypes = require('prop-types') -const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const BigNumber = require('bignumber.js') @@ -328,69 +327,72 @@ CustomizeGasModal.prototype.render = function () { toNumericBase: 'dec', }) - return !gasIsLoading && h('div.send-v2__customize-gas', {}, [ - h('div.send-v2__customize-gas__content', { - }, [ - h('div.send-v2__customize-gas__header', {}, [ - - h('div.send-v2__customize-gas__title', this.context.t('customGas')), - - h('div.send-v2__customize-gas__close', { - onClick: hideModal, - }), - - ]), - - h('div.send-v2__customize-gas__body', {}, [ - - h(GasModalCard, { - value: convertedGasPrice, - min: forceGasMin || MIN_GAS_PRICE_GWEI, - step: 1, - onChange: value => this.convertAndSetGasPrice(value), - title: this.context.t('gasPrice'), - copy: this.context.t('gasPriceCalculation'), - gasIsLoading, - }), - - h(GasModalCard, { - value: convertedGasLimit, - min: 1, - step: 1, - onChange: value => this.convertAndSetGasLimit(value), - title: this.context.t('gasLimit'), - copy: this.context.t('gasLimitCalculation'), - gasIsLoading, - }), - - ]), - - h('div.send-v2__customize-gas__footer', {}, [ - - error && h('div.send-v2__customize-gas__error-message', [ - error, - ]), - - h('div.send-v2__customize-gas__revert', { - onClick: () => this.revert(), - }, [this.context.t('revert')]), - - h('div.send-v2__customize-gas__buttons', [ - h(Button, { - type: 'default', - className: 'send-v2__customize-gas__cancel', - onClick: this.props.hideModal, - }, [this.context.t('cancel')]), - h(Button, { - type: 'secondary', - className: 'send-v2__customize-gas__save', - onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal), - disabled: error, - }, [this.context.t('save')]), - ]), - - ]), - - ]), - ]) + if (gasIsLoading) { + return null + } + + const { t } = this.context + + return ( +
    +
    +
    +
    + {this.context.t('customGas')} +
    +
    +
    +
    + this.convertAndSetGasPrice(value)} + title={t('gasPrice')} + copy={t('gasPriceCalculation')} + gasIsLoading={gasIsLoading} + /> + this.convertAndSetGasLimit(value)} + title={t('gasLimit')} + copy={t('gasLimitCalculation')} + gasIsLoading={gasIsLoading} + /> +
    +
    + {error && ( +
    + {error} +
    + )} +
    this.revert()}> + {t('revert')} +
    +
    + + +
    +
    +
    +
    + ) } From 3377228b74217d522a05f0aa9aa1e4b134978c6a Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 01:41:30 -0330 Subject: [PATCH 46/88] Split ShiftListItem into container and component files with JSX (#7539) --- ui/app/components/app/shift-list-item.js | 204 --------------- .../components/app/shift-list-item/index.js | 1 + .../shift-list-item.component.js | 240 ++++++++++++++++++ .../shift-list-item.container.js | 12 + 4 files changed, 253 insertions(+), 204 deletions(-) delete mode 100644 ui/app/components/app/shift-list-item.js create mode 100644 ui/app/components/app/shift-list-item/index.js create mode 100644 ui/app/components/app/shift-list-item/shift-list-item.component.js create mode 100644 ui/app/components/app/shift-list-item/shift-list-item.container.js diff --git a/ui/app/components/app/shift-list-item.js b/ui/app/components/app/shift-list-item.js deleted file mode 100644 index f5fa00047bce..000000000000 --- a/ui/app/components/app/shift-list-item.js +++ /dev/null @@ -1,204 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const explorerLink = require('etherscan-link').createExplorerLink -const actions = require('../../store/actions') -const { formatDate, addressSummary } = require('../../helpers/utils/util') - -const CopyButton = require('../ui/copyButton') -const EthBalance = require('../ui/eth-balance') -const Tooltip = require('../ui/tooltip') - - -ShiftListItem.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(ShiftListItem) - - -function mapStateToProps (state) { - return { - selectedAddress: state.metamask.selectedAddress, - conversionRate: state.metamask.conversionRate, - currentCurrency: state.metamask.currentCurrency, - } -} - -inherits(ShiftListItem, Component) - -function ShiftListItem () { - Component.call(this) -} - -ShiftListItem.prototype.render = function () { - return h('div.transaction-list-item.tx-list-clickable', { - style: { - paddingTop: '20px', - paddingBottom: '20px', - justifyContent: 'space-around', - alignItems: 'center', - flexDirection: 'row', - }, - }, [ - h('div', { - style: { - width: '0px', - position: 'relative', - bottom: '19px', - }, - }, [ - h('img', { - src: 'https://shapeshift.io/logo.png', - style: { - height: '35px', - width: '132px', - position: 'absolute', - clip: 'rect(0px,30px,34px,0px)', - }, - }), - ]), - - this.renderInfo(), - this.renderUtilComponents(), - ]) -} - -ShiftListItem.prototype.renderUtilComponents = function () { - var props = this.props - const { conversionRate, currentCurrency } = props - - switch (props.response.status) { - case 'no_deposits': - return h('.flex-row', [ - h(CopyButton, { - value: this.props.depositAddress, - }), - h(Tooltip, { - title: this.context.t('qrCode'), - }, [ - h('i.fa.fa-qrcode.pointer.pop-hover', { - onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), - style: { - margin: '5px', - marginLeft: '23px', - marginRight: '12px', - fontSize: '20px', - color: '#F7861C', - }, - }), - ]), - ]) - case 'received': - return h('.flex-row') - - case 'complete': - return h('.flex-row', [ - h(CopyButton, { - value: this.props.response.transaction, - }), - h(EthBalance, { - value: `${props.response.outgoingCoin}`, - conversionRate, - currentCurrency, - width: '55px', - shorten: true, - needsParse: false, - incoming: true, - style: { - fontSize: '15px', - color: '#01888C', - }, - }), - ]) - - case 'failed': - return '' - default: - return '' - } -} - -ShiftListItem.prototype.renderInfo = function () { - var props = this.props - switch (props.response.status) { - case 'no_deposits': - return h('.flex-column', { - style: { - overflow: 'hidden', - }, - }, [ - h('div', { - style: { - fontSize: 'x-small', - color: '#ABA9AA', - width: '100%', - }, - }, this.context.t('toETHviaShapeShift', [props.depositType])), - h('div', this.context.t('noDeposits')), - h('div', { - style: { - fontSize: 'x-small', - color: '#ABA9AA', - width: '100%', - }, - }, formatDate(props.time)), - ]) - case 'received': - return h('.flex-column', { - style: { - width: '200px', - overflow: 'hidden', - }, - }, [ - h('div', { - style: { - fontSize: 'x-small', - color: '#ABA9AA', - width: '100%', - }, - }, this.context.t('toETHviaShapeShift', [props.depositType])), - h('div', this.context.t('conversionProgress')), - h('div', { - style: { - fontSize: 'x-small', - color: '#ABA9AA', - width: '100%', - }, - }, formatDate(props.time)), - ]) - case 'complete': - var url = explorerLink(props.response.transaction, parseInt('1')) - - return h('.flex-column.pointer', { - style: { - width: '200px', - overflow: 'hidden', - }, - onClick: () => global.platform.openWindow({ url }), - }, [ - h('div', { - style: { - fontSize: 'x-small', - color: '#ABA9AA', - width: '100%', - }, - }, this.context.t('fromShapeShift')), - h('div', formatDate(props.time)), - h('div', { - style: { - fontSize: 'x-small', - color: '#ABA9AA', - width: '100%', - }, - }, addressSummary(props.response.transaction)), - ]) - - case 'failed': - return h('span.error', '(' + this.context.t('failed') + ')') - default: - return '' - } -} diff --git a/ui/app/components/app/shift-list-item/index.js b/ui/app/components/app/shift-list-item/index.js new file mode 100644 index 000000000000..fd6796983df1 --- /dev/null +++ b/ui/app/components/app/shift-list-item/index.js @@ -0,0 +1 @@ +export { default } from './shift-list-item.container' diff --git a/ui/app/components/app/shift-list-item/shift-list-item.component.js b/ui/app/components/app/shift-list-item/shift-list-item.component.js new file mode 100644 index 000000000000..0d8e55389837 --- /dev/null +++ b/ui/app/components/app/shift-list-item/shift-list-item.component.js @@ -0,0 +1,240 @@ +import PropTypes from 'prop-types' +import React, { Component } from 'react' +const explorerLink = require('etherscan-link').createExplorerLink +const actions = require('../../../store/actions') +const { formatDate, addressSummary } = require('../../../helpers/utils/util') + +const CopyButton = require('../../ui/copyButton') +const EthBalance = require('../../ui/eth-balance') +const Tooltip = require('../../ui/tooltip') + +export default class ShiftListItem extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static defaultProps = { + conversionRate: undefined, + currentCurrency: undefined, + } + + static propTypes = { + depositType: PropTypes.string.isRequired, + dispatch: PropTypes.func.isRequired, + depositAddress: PropTypes.string.isRequired, + conversionRate: PropTypes.any, + currentCurrency: PropTypes.any, + time: PropTypes.string.isRequired, + response: PropTypes.shape({ + outgoingCoin: PropTypes.number.isRequired, + status: PropTypes.string.isRequired, + transaction: PropTypes.string.isRequired, + }), + } + + renderUtilComponents () { + const { conversionRate, currentCurrency } = this.props + + switch (this.props.response.status) { + case 'no_deposits': + return ( +
    + + + { + this.props.dispatch(actions.reshowQrCode(this.props.depositAddress, this.props.depositType)) + }} + style={{ + margin: '5px', + marginLeft: '23px', + marginRight: '12px', + fontSize: '20px', + color: '#F7861C', + }} + /> + +
    + ) + case 'received': + return
    + + case 'complete': + return ( +
    + + +
    + ) + + case 'failed': + return '' + + default: + return '' + } + } + + renderInfo () { + switch (this.props.response.status) { + case 'no_deposits': + return ( +
    +
    + {this.context.t('toETHviaShapeShift', [this.props.depositType])} +
    +
    + {this.context.t('noDeposits')} +
    +
    + {formatDate(this.props.time)} +
    +
    + ) + + case 'received': + return ( +
    +
    + {this.context.t('toETHviaShapeShift', [this.props.depositType])} +
    +
    + {this.context.t('conversionProgress')} +
    +
    + {formatDate(this.props.time)} +
    +
    + ) + + case 'complete': + const url = explorerLink(this.props.response.transaction, parseInt('1')) + return ( +
    global.platform.openWindow({ url })} + > +
    + {this.context.t('fromShapeShift')} +
    +
    + {formatDate(this.props.time)} +
    +
    + {addressSummary(this.props.response.transaction)} +
    +
    + ) + + case 'failed': + return ( + + {`(${this.context.t('failed')})`} + + ) + + default: + return '' + } + } + + render () { + return ( +
    +
    + +
    + {this.renderInfo()} + {this.renderUtilComponents()} +
    + ) + } +} diff --git a/ui/app/components/app/shift-list-item/shift-list-item.container.js b/ui/app/components/app/shift-list-item/shift-list-item.container.js new file mode 100644 index 000000000000..1d7645dfdf9e --- /dev/null +++ b/ui/app/components/app/shift-list-item/shift-list-item.container.js @@ -0,0 +1,12 @@ +import {connect} from 'react-redux' +import ShiftListItem from './shift-list-item.component' + +function mapStateToProps (state) { + return { + selectedAddress: state.metamask.selectedAddress, + conversionRate: state.metamask.conversionRate, + currentCurrency: state.metamask.currentCurrency, + } +} + +export default connect(mapStateToProps)(ShiftListItem) From a849218f8113f52b189b2a7261a816a489834609 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 13:45:35 -0330 Subject: [PATCH 47/88] Adjust QrCodeView propTypes for its Qr.messages prop (#7529) --- ui/app/components/ui/qr-code.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/app/components/ui/qr-code.js b/ui/app/components/ui/qr-code.js index e0b7f3ff2222..0594273a249c 100644 --- a/ui/app/components/ui/qr-code.js +++ b/ui/app/components/ui/qr-code.js @@ -69,7 +69,10 @@ function QrCodeView (props) { QrCodeView.propTypes = { warning: PropTypes.node, Qr: PropTypes.shape({ - message: PropTypes.array, + message: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node, + ]), data: PropTypes.string.isRequired, }).isRequired, } From ec938686a91d262fc2eaa1988424a207deb84dd3 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 13:46:25 -0330 Subject: [PATCH 48/88] Split MobileSyncPage into container and component, with JSX (#7534) --- ui/app/pages/mobile-sync/index.js | 418 +---------------- .../mobile-sync/mobile-sync.component.js | 436 ++++++++++++++++++ .../mobile-sync/mobile-sync.container.js | 25 + ui/app/pages/routes/index.js | 2 +- 4 files changed, 463 insertions(+), 418 deletions(-) create mode 100644 ui/app/pages/mobile-sync/mobile-sync.component.js create mode 100644 ui/app/pages/mobile-sync/mobile-sync.container.js diff --git a/ui/app/pages/mobile-sync/index.js b/ui/app/pages/mobile-sync/index.js index 078d2a5f641a..c7df5ede559e 100644 --- a/ui/app/pages/mobile-sync/index.js +++ b/ui/app/pages/mobile-sync/index.js @@ -1,417 +1 @@ -const { Component } = require('react') -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const classnames = require('classnames') -const PubNub = require('pubnub') - -const { requestRevealSeedWords, fetchInfoToSync } = require('../../store/actions') -const { DEFAULT_ROUTE } = require('../../helpers/constants/routes') -const actions = require('../../store/actions') - -const qrCode = require('qrcode-generator') - -import Button from '../../components/ui/button' -import LoadingScreen from '../../components/ui/loading-screen' - -const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN' -const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN' -const KEYS_GENERATION_TIME = 30000 - -class MobileSyncPage extends Component { - static propTypes = { - history: PropTypes.object, - selectedAddress: PropTypes.string, - displayWarning: PropTypes.func, - fetchInfoToSync: PropTypes.func, - requestRevealSeedWords: PropTypes.func, - } - - constructor (props) { - super(props) - - this.state = { - screen: PASSWORD_PROMPT_SCREEN, - password: '', - seedWords: null, - error: null, - syncing: false, - completed: false, - channelName: undefined, - cipherKey: undefined, - } - - this.syncing = false - } - - componentDidMount () { - const passwordBox = document.getElementById('password-box') - if (passwordBox) { - passwordBox.focus() - } - } - - handleSubmit (event) { - event.preventDefault() - this.setState({ seedWords: null, error: null }) - this.props.requestRevealSeedWords(this.state.password) - .then(seedWords => { - this.startKeysGeneration() - this.setState({ seedWords, screen: REVEAL_SEED_SCREEN }) - }) - .catch(error => this.setState({ error: error.message })) - } - - startKeysGeneration () { - this.handle && clearTimeout(this.handle) - this.disconnectWebsockets() - this.generateCipherKeyAndChannelName() - this.initWebsockets() - this.handle = setTimeout(() => { - this.startKeysGeneration() - }, KEYS_GENERATION_TIME) - } - - generateCipherKeyAndChannelName () { - this.cipherKey = `${this.props.selectedAddress.substr(-4)}-${PubNub.generateUUID()}` - this.channelName = `mm-${PubNub.generateUUID()}` - this.setState({cipherKey: this.cipherKey, channelName: this.channelName}) - } - - initWithCipherKeyAndChannelName (cipherKey, channelName) { - this.cipherKey = cipherKey - this.channelName = channelName - } - - initWebsockets () { - // Make sure there are no existing listeners - this.disconnectWebsockets() - - this.pubnub = new PubNub({ - subscribeKey: process.env.PUBNUB_SUB_KEY, - publishKey: process.env.PUBNUB_PUB_KEY, - cipherKey: this.cipherKey, - ssl: true, - }) - - this.pubnubListener = { - message: (data) => { - const {channel, message} = data - // handle message - if (channel !== this.channelName || !message) { - return false - } - - if (message.event === 'start-sync') { - this.startSyncing() - } else if (message.event === 'connection-info') { - this.handle && clearTimeout(this.handle) - this.disconnectWebsockets() - this.initWithCipherKeyAndChannelName(message.cipher, message.channel) - this.initWebsockets() - } else if (message.event === 'end-sync') { - this.disconnectWebsockets() - this.setState({syncing: false, completed: true}) - } - }, - } - - this.pubnub.addListener(this.pubnubListener) - - this.pubnub.subscribe({ - channels: [this.channelName], - withPresence: false, - }) - - } - - disconnectWebsockets () { - if (this.pubnub && this.pubnubListener) { - this.pubnub.removeListener(this.pubnubListener) - } - } - - // Calculating a PubNub Message Payload Size. - calculatePayloadSize (channel, message) { - return encodeURIComponent( - channel + JSON.stringify(message) - ).length + 100 - } - - chunkString (str, size) { - const numChunks = Math.ceil(str.length / size) - const chunks = new Array(numChunks) - for (let i = 0, o = 0; i < numChunks; ++i, o += size) { - chunks[i] = str.substr(o, size) - } - return chunks - } - - notifyError (errorMsg) { - return new Promise((resolve, reject) => { - this.pubnub.publish( - { - message: { - event: 'error-sync', - data: errorMsg, - }, - channel: this.channelName, - sendByPost: false, // true to send via post - storeInHistory: false, - }, - (status, response) => { - if (!status.error) { - resolve() - } else { - reject(response) - } - }) - }) - } - - async startSyncing () { - if (this.syncing) { - return false - } - this.syncing = true - this.setState({syncing: true}) - - const { accounts, network, preferences, transactions } = await this.props.fetchInfoToSync() - - const allDataStr = JSON.stringify({ - accounts, - network, - preferences, - transactions, - udata: { - pwd: this.state.password, - seed: this.state.seedWords, - }, - }) - - const chunks = this.chunkString(allDataStr, 17000) - const totalChunks = chunks.length - try { - for (let i = 0; i < totalChunks; i++) { - await this.sendMessage(chunks[i], i + 1, totalChunks) - } - } catch (e) { - this.props.displayWarning('Sync failed :(') - this.setState({syncing: false}) - this.syncing = false - this.notifyError(e.toString()) - } - } - - sendMessage (data, pkg, count) { - return new Promise((resolve, reject) => { - this.pubnub.publish( - { - message: { - event: 'syncing-data', - data, - totalPkg: count, - currentPkg: pkg, - }, - channel: this.channelName, - sendByPost: false, // true to send via post - storeInHistory: false, - }, - (status, response) => { - if (!status.error) { - resolve() - } else { - reject(response) - } - } - ) - }) - } - - - componentWillUnmount () { - this.disconnectWebsockets() - } - - renderWarning (text) { - return ( - h('.page-container__warning-container', [ - h('.page-container__warning-message', [ - h('div', [text]), - ]), - ]) - ) - } - - renderContent () { - const { t } = this.context - - if (this.state.syncing) { - return h(LoadingScreen, {loadingMessage: 'Sync in progress'}) - } - - if (this.state.completed) { - return h('div.reveal-seed__content', {}, - h('label.reveal-seed__label', { - style: { - width: '100%', - textAlign: 'center', - }, - }, t('syncWithMobileComplete')), - ) - } - - return this.state.screen === PASSWORD_PROMPT_SCREEN - ? h('div', {}, [ - this.renderWarning(this.context.t('mobileSyncText')), - h('.reveal-seed__content', [ - this.renderPasswordPromptContent(), - ]), - ]) - : h('div', {}, [ - this.renderWarning(this.context.t('syncWithMobileBeCareful')), - h('.reveal-seed__content', [ this.renderRevealSeedContent() ]), - ]) - } - - renderPasswordPromptContent () { - const { t } = this.context - - return ( - h('form', { - onSubmit: event => this.handleSubmit(event), - }, [ - h('label.input-label', { - htmlFor: 'password-box', - }, t('enterPasswordContinue')), - h('.input-group', [ - h('input.form-control', { - type: 'password', - placeholder: t('password'), - id: 'password-box', - value: this.state.password, - onChange: event => this.setState({ password: event.target.value }), - className: classnames({ 'form-control--error': this.state.error }), - }), - ]), - this.state.error && h('.reveal-seed__error', this.state.error), - ]) - ) - } - - renderRevealSeedContent () { - - const qrImage = qrCode(0, 'M') - qrImage.addData(`metamask-sync:${this.state.channelName}|@|${this.state.cipherKey}`) - qrImage.make() - - const { t } = this.context - return ( - h('div', [ - h('label.reveal-seed__label', { - style: { - width: '100%', - textAlign: 'center', - }, - }, t('syncWithMobileScanThisCode')), - h('.div.qr-wrapper', { - style: { - display: 'flex', - justifyContent: 'center', - }, - dangerouslySetInnerHTML: { - __html: qrImage.createTableTag(4), - }, - }), - ]) - ) - } - - renderFooter () { - return this.state.screen === PASSWORD_PROMPT_SCREEN - ? this.renderPasswordPromptFooter() - : this.renderRevealSeedFooter() - } - - renderPasswordPromptFooter () { - return ( - h('div.new-account-import-form__buttons', {style: {padding: 30}}, [ - - h(Button, { - type: 'default', - large: true, - className: 'new-account-create-form__button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('cancel')), - - h(Button, { - type: 'secondary', - large: true, - className: 'new-account-create-form__button', - onClick: event => this.handleSubmit(event), - disabled: this.state.password === '', - }, this.context.t('next')), - ]) - ) - } - - renderRevealSeedFooter () { - return ( - h('.page-container__footer', {style: {padding: 30}}, [ - h(Button, { - type: 'default', - large: true, - className: 'page-container__footer-button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('close')), - ]) - ) - } - - render () { - return ( - h('.page-container', [ - h('.page-container__header', [ - h('.page-container__title', this.context.t('syncWithMobileTitle')), - this.state.screen === PASSWORD_PROMPT_SCREEN ? h('.page-container__subtitle', this.context.t('syncWithMobileDesc')) : null, - this.state.screen === PASSWORD_PROMPT_SCREEN ? h('.page-container__subtitle', this.context.t('syncWithMobileDescNewUsers')) : null, - ]), - h('.page-container__content', [ - this.renderContent(), - ]), - this.renderFooter(), - ]) - ) - } -} - -MobileSyncPage.propTypes = { - requestRevealSeedWords: PropTypes.func, - fetchInfoToSync: PropTypes.func, - history: PropTypes.object, -} - -MobileSyncPage.contextTypes = { - t: PropTypes.func, -} - -const mapDispatchToProps = dispatch => { - return { - requestRevealSeedWords: password => dispatch(requestRevealSeedWords(password)), - fetchInfoToSync: () => dispatch(fetchInfoToSync()), - displayWarning: (message) => dispatch(actions.displayWarning(message || null)), - } - -} - -const mapStateToProps = state => { - const { - metamask: { selectedAddress }, - } = state - - return { - selectedAddress, - } -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(MobileSyncPage) +export { default } from './mobile-sync.container' diff --git a/ui/app/pages/mobile-sync/mobile-sync.component.js b/ui/app/pages/mobile-sync/mobile-sync.component.js new file mode 100644 index 000000000000..b97bf1232a9b --- /dev/null +++ b/ui/app/pages/mobile-sync/mobile-sync.component.js @@ -0,0 +1,436 @@ +import React, { Component } from 'react' + +const PropTypes = require('prop-types') +const classnames = require('classnames') +const PubNub = require('pubnub') +const qrCode = require('qrcode-generator') + +const { DEFAULT_ROUTE } = require('../../helpers/constants/routes') + +import Button from '../../components/ui/button' +import LoadingScreen from '../../components/ui/loading-screen' + +const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN' +const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN' +const KEYS_GENERATION_TIME = 30000 + +export default class MobileSyncPage extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + history: PropTypes.object, + selectedAddress: PropTypes.string, + displayWarning: PropTypes.func, + fetchInfoToSync: PropTypes.func, + requestRevealSeedWords: PropTypes.func, + } + + + state = { + screen: PASSWORD_PROMPT_SCREEN, + password: '', + seedWords: null, + error: null, + syncing: false, + completed: false, + channelName: undefined, + cipherKey: undefined, + } + + syncing = false + + componentDidMount () { + const passwordBox = document.getElementById('password-box') + if (passwordBox) { + passwordBox.focus() + } + } + + handleSubmit (event) { + event.preventDefault() + this.setState({ seedWords: null, error: null }) + this.props.requestRevealSeedWords(this.state.password) + .then(seedWords => { + this.startKeysGeneration() + this.setState({ seedWords, screen: REVEAL_SEED_SCREEN }) + }) + .catch(error => this.setState({ error: error.message })) + } + + startKeysGeneration () { + this.handle && clearTimeout(this.handle) + this.disconnectWebsockets() + this.generateCipherKeyAndChannelName() + this.initWebsockets() + this.handle = setTimeout(() => { + this.startKeysGeneration() + }, KEYS_GENERATION_TIME) + } + + generateCipherKeyAndChannelName () { + this.cipherKey = `${this.props.selectedAddress.substr(-4)}-${PubNub.generateUUID()}` + this.channelName = `mm-${PubNub.generateUUID()}` + this.setState({cipherKey: this.cipherKey, channelName: this.channelName}) + } + + initWithCipherKeyAndChannelName (cipherKey, channelName) { + this.cipherKey = cipherKey + this.channelName = channelName + } + + initWebsockets () { + // Make sure there are no existing listeners + this.disconnectWebsockets() + + this.pubnub = new PubNub({ + subscribeKey: process.env.PUBNUB_SUB_KEY, + publishKey: process.env.PUBNUB_PUB_KEY, + cipherKey: this.cipherKey, + ssl: true, + }) + + this.pubnubListener = { + message: (data) => { + const {channel, message} = data + // handle message + if (channel !== this.channelName || !message) { + return false + } + + if (message.event === 'start-sync') { + this.startSyncing() + } else if (message.event === 'connection-info') { + this.handle && clearTimeout(this.handle) + this.disconnectWebsockets() + this.initWithCipherKeyAndChannelName(message.cipher, message.channel) + this.initWebsockets() + } else if (message.event === 'end-sync') { + this.disconnectWebsockets() + this.setState({syncing: false, completed: true}) + } + }, + } + + this.pubnub.addListener(this.pubnubListener) + + this.pubnub.subscribe({ + channels: [this.channelName], + withPresence: false, + }) + + } + + disconnectWebsockets () { + if (this.pubnub && this.pubnubListener) { + this.pubnub.removeListener(this.pubnubListener) + } + } + + // Calculating a PubNub Message Payload Size. + calculatePayloadSize (channel, message) { + return encodeURIComponent( + channel + JSON.stringify(message) + ).length + 100 + } + + chunkString (str, size) { + const numChunks = Math.ceil(str.length / size) + const chunks = new Array(numChunks) + for (let i = 0, o = 0; i < numChunks; ++i, o += size) { + chunks[i] = str.substr(o, size) + } + return chunks + } + + notifyError (errorMsg) { + return new Promise((resolve, reject) => { + this.pubnub.publish( + { + message: { + event: 'error-sync', + data: errorMsg, + }, + channel: this.channelName, + sendByPost: false, // true to send via post + storeInHistory: false, + }, + (status, response) => { + if (!status.error) { + resolve() + } else { + reject(response) + } + }) + }) + } + + async startSyncing () { + if (this.syncing) { + return false + } + this.syncing = true + this.setState({syncing: true}) + + const { accounts, network, preferences, transactions } = await this.props.fetchInfoToSync() + + const allDataStr = JSON.stringify({ + accounts, + network, + preferences, + transactions, + udata: { + pwd: this.state.password, + seed: this.state.seedWords, + }, + }) + + const chunks = this.chunkString(allDataStr, 17000) + const totalChunks = chunks.length + try { + for (let i = 0; i < totalChunks; i++) { + await this.sendMessage(chunks[i], i + 1, totalChunks) + } + } catch (e) { + this.props.displayWarning('Sync failed :(') + this.setState({syncing: false}) + this.syncing = false + this.notifyError(e.toString()) + } + } + + sendMessage (data, pkg, count) { + return new Promise((resolve, reject) => { + this.pubnub.publish( + { + message: { + event: 'syncing-data', + data, + totalPkg: count, + currentPkg: pkg, + }, + channel: this.channelName, + sendByPost: false, // true to send via post + storeInHistory: false, + }, + (status, response) => { + if (!status.error) { + resolve() + } else { + reject(response) + } + } + ) + }) + } + + + componentWillUnmount () { + this.disconnectWebsockets() + } + + renderWarning (text) { + return ( +
    +
    +
    {text}
    +
    +
    + ) + } + + renderContent () { + const { syncing, completed, screen } = this.state + const { t } = this.context + + if (syncing) { + return ( + + ) + } + + if (completed) { + return ( +
    + +
    + ) + } + + return screen === PASSWORD_PROMPT_SCREEN + ? ( +
    + {this.renderWarning(this.context.t('mobileSyncText'))} +
    + {this.renderPasswordPromptContent()} +
    +
    + ) + : ( +
    + {this.renderWarning(this.context.t('syncWithMobileBeCareful'))} +
    + {this.renderRevealSeedContent()} +
    +
    + ) + } + + renderPasswordPromptContent () { + const { t } = this.context + + return ( +
    this.handleSubmit(event)}> + +
    + this.setState({ password: event.target.value })} + className={classnames('form-control', { + 'form-control--error': this.state.error, + })} + /> +
    + {this.state.error && ( +
    + {this.state.error} +
    + )} +
    + ) + } + + renderRevealSeedContent () { + const qrImage = qrCode(0, 'M') + qrImage.addData(`metamask-sync:${this.state.channelName}|@|${this.state.cipherKey}`) + qrImage.make() + + const { t } = this.context + return ( +
    + +
    +
    + ) + } + + renderFooter () { + return this.state.screen === PASSWORD_PROMPT_SCREEN + ? this.renderPasswordPromptFooter() + : this.renderRevealSeedFooter() + } + + renderPasswordPromptFooter () { + const { t } = this.context + const { history } = this.props + const { password } = this.state + + return ( +
    + + +
    + ) + } + + renderRevealSeedFooter () { + const { t } = this.context + const { history } = this.props + + return ( +
    + +
    + ) + } + + render () { + const { t } = this.context + const { screen } = this.state + + return ( +
    +
    +
    + {t('syncWithMobileTitle')} +
    + { + screen === PASSWORD_PROMPT_SCREEN + ? ( +
    + {t('syncWithMobileDesc')} +
    + ) + : null + } + { + screen === PASSWORD_PROMPT_SCREEN + ? ( +
    + {t('syncWithMobileDescNewUsers')} +
    + ) + : null + } +
    +
    + {this.renderContent()} +
    + {this.renderFooter()} +
    + ) + } +} diff --git a/ui/app/pages/mobile-sync/mobile-sync.container.js b/ui/app/pages/mobile-sync/mobile-sync.container.js new file mode 100644 index 000000000000..915563841893 --- /dev/null +++ b/ui/app/pages/mobile-sync/mobile-sync.container.js @@ -0,0 +1,25 @@ +import { connect } from 'react-redux' +import { displayWarning, requestRevealSeedWords, fetchInfoToSync } from '../../store/actions' +import MobileSyncPage from './mobile-sync.component' + +const mapDispatchToProps = (dispatch) => { + return { + requestRevealSeedWords: password => dispatch(requestRevealSeedWords(password)), + fetchInfoToSync: () => dispatch(fetchInfoToSync()), + displayWarning: (message) => dispatch(displayWarning(message || null)), + } +} + +const mapStateToProps = state => { + const { + metamask: { + selectedAddress, + }, + } = state + + return { + selectedAddress, + } +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(MobileSyncPage) diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index 45da4d0970ba..64da523d682a 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -27,7 +27,7 @@ import Initialized from '../../helpers/higher-order-components/initialized' import Lock from '../lock' const RestoreVaultPage = require('../keychains/restore-vault').default const RevealSeedConfirmation = require('../keychains/reveal-seed') -const MobileSyncPage = require('../mobile-sync') +const MobileSyncPage = require('../mobile-sync').default const AddTokenPage = require('../add-token') const ConfirmAddTokenPage = require('../confirm-add-token') const ConfirmAddSuggestedTokenPage = require('../confirm-add-suggested-token') From 50c5365933ff6eb9b7bc8c61fd612bb3bcf0f178 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 14:46:57 -0330 Subject: [PATCH 49/88] Add isRequired flag to MobileSyncPage props (#7544) --- ui/app/pages/mobile-sync/mobile-sync.component.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/app/pages/mobile-sync/mobile-sync.component.js b/ui/app/pages/mobile-sync/mobile-sync.component.js index b97bf1232a9b..9510afa80745 100644 --- a/ui/app/pages/mobile-sync/mobile-sync.component.js +++ b/ui/app/pages/mobile-sync/mobile-sync.component.js @@ -20,11 +20,11 @@ export default class MobileSyncPage extends Component { } static propTypes = { - history: PropTypes.object, - selectedAddress: PropTypes.string, - displayWarning: PropTypes.func, - fetchInfoToSync: PropTypes.func, - requestRevealSeedWords: PropTypes.func, + history: PropTypes.object.isRequired, + selectedAddress: PropTypes.string.isRequired, + displayWarning: PropTypes.func.isRequired, + fetchInfoToSync: PropTypes.func.isRequired, + requestRevealSeedWords: PropTypes.func.isRequired, } From 7d2b5b26a57dc0efbcf65d89f6b6831593ddf761 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 17:48:34 -0330 Subject: [PATCH 50/88] Delete unused SeedImportSubview component (#7530) * Delete unused SeedImportSubview component * Remove 2 unused messages --- app/_locales/am/messages.json | 6 ---- app/_locales/ar/messages.json | 6 ---- app/_locales/bg/messages.json | 6 ---- app/_locales/bn/messages.json | 6 ---- app/_locales/ca/messages.json | 6 ---- app/_locales/cs/messages.json | 6 ---- app/_locales/da/messages.json | 6 ---- app/_locales/de/messages.json | 6 ---- app/_locales/el/messages.json | 6 ---- app/_locales/en/messages.json | 6 ---- app/_locales/es/messages.json | 6 ---- app/_locales/es_419/messages.json | 6 ---- app/_locales/et/messages.json | 6 ---- app/_locales/fa/messages.json | 6 ---- app/_locales/fi/messages.json | 6 ---- app/_locales/fil/messages.json | 6 ---- app/_locales/fr/messages.json | 6 ---- app/_locales/gu/messages.json | 3 -- app/_locales/he/messages.json | 6 ---- app/_locales/hi/messages.json | 6 ---- app/_locales/hn/messages.json | 6 ---- app/_locales/hr/messages.json | 6 ---- app/_locales/ht/messages.json | 6 ---- app/_locales/hu/messages.json | 6 ---- app/_locales/id/messages.json | 6 ---- app/_locales/it/messages.json | 6 ---- app/_locales/ja/messages.json | 6 ---- app/_locales/kn/messages.json | 6 ---- app/_locales/ko/messages.json | 6 ---- app/_locales/lt/messages.json | 6 ---- app/_locales/lv/messages.json | 6 ---- app/_locales/ml/messages.json | 3 -- app/_locales/mr/messages.json | 3 -- app/_locales/ms/messages.json | 6 ---- app/_locales/nl/messages.json | 6 ---- app/_locales/no/messages.json | 6 ---- app/_locales/ph/messages.json | 6 ---- app/_locales/pl/messages.json | 6 ---- app/_locales/pt/messages.json | 6 ---- app/_locales/pt_BR/messages.json | 6 ---- app/_locales/pt_PT/messages.json | 3 -- app/_locales/ro/messages.json | 6 ---- app/_locales/ru/messages.json | 6 ---- app/_locales/sk/messages.json | 6 ---- app/_locales/sl/messages.json | 6 ---- app/_locales/sr/messages.json | 6 ---- app/_locales/sv/messages.json | 6 ---- app/_locales/sw/messages.json | 6 ---- app/_locales/ta/messages.json | 6 ---- app/_locales/te/messages.json | 3 -- app/_locales/th/messages.json | 6 ---- app/_locales/tr/messages.json | 6 ---- app/_locales/uk/messages.json | 6 ---- app/_locales/vi/messages.json | 6 ---- app/_locales/zh_CN/messages.json | 6 ---- app/_locales/zh_TW/messages.json | 6 ---- .../create-account/import-account/seed.js | 35 ------------------- 57 files changed, 356 deletions(-) delete mode 100644 ui/app/pages/create-account/import-account/seed.js diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 6b2839b8c581..8b8c70ead233 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -864,9 +864,6 @@ "message": "የግል ቁልፍዎን ሕብረ ቁምፊ እዚህ ለጥፍ፡", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "የዘር ሐረግዎን እዚህ ይለጥፉ!" - }, "pending": { "message": "በእንጥልጥል ላይ ያለ" }, @@ -1180,9 +1177,6 @@ "storePhrase": { "message": "ይህን ሐረግ እንደ 1Password ባለ የይለፍ ቃል አስተዳዳሪ ውስጥ ያስቀምጡ።" }, - "submit": { - "message": "አስገባ" - }, "submitted": { "message": "የቀረበ" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index a69beaafc77e..1bee5df313ee 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -860,9 +860,6 @@ "message": "الصق مقطع مفتاحك الخاص هنا:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "قم بلصق عبارة الأمان الخاصة بك هنا!" - }, "pending": { "message": "قيد الانتظار" }, @@ -1176,9 +1173,6 @@ "storePhrase": { "message": "احتفظ بهذه الجملة في مدير كلمات مرور مثل 1Password." }, - "submit": { - "message": "إرسال" - }, "submitted": { "message": "المقدمة" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 0aebd87573d5..fac03f1c0b2f 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -863,9 +863,6 @@ "message": "Поставете низ от личния си ключ тук:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Поставете тук ключовата си фраза!" - }, "pending": { "message": "в изчакване" }, @@ -1179,9 +1176,6 @@ "storePhrase": { "message": "Съхранявайте тази фраза в мениджър на пароли като 1Password." }, - "submit": { - "message": "Изпращане" - }, "submitted": { "message": "Изпратен" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index b7f4775b270c..79fd24a3ccfc 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -867,9 +867,6 @@ "message": "আপনার গোপনীয় কী স্ট্রিং এখানে পেস্ট করুন:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "আপনার সীড ফ্রেজ এখানে পেস্ট করুন!" - }, "pending": { "message": "বাকি" }, @@ -1183,9 +1180,6 @@ "storePhrase": { "message": "এই বাক্যাংশটি 1Password এর মতো একটি পাসওয়ার্ড পরিচালকে সংরক্ষণ করুন। " }, - "submit": { - "message": "জমা দিন" - }, "submitted": { "message": "জমা করা হয়েছে" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 60473d1a07da..42af089d4810 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -851,9 +851,6 @@ "message": "Enganxa la teva cadena clau privada aquí:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Enganxa la teva frase de seeds aquí!" - }, "pending": { "message": "pendent" }, @@ -1161,9 +1158,6 @@ "storePhrase": { "message": "Guarda aquesta frase a un gestor de contrasenyes com Contrasenya 1" }, - "submit": { - "message": "Envia" - }, "submitted": { "message": "Enviat" }, diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index e99e75c60cf9..95c45c98b0b0 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -364,9 +364,6 @@ "message": "Vložte zde svůj privátní klíč:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Svou klíčovou frázi vložte zde!" - }, "personalAddressDetected": { "message": "Detekována osobní adresa. Zadejte adresu kontraktu tokenu." }, @@ -473,9 +470,6 @@ "stateLogError": { "message": "Chyba během získávání stavových protokolů." }, - "submit": { - "message": "Odeslat" - }, "submitted": { "message": "Odesláno" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 1e11807757d4..627e6222c22a 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -845,9 +845,6 @@ "message": "Indsæt din private nøglestreng her:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Indsæt din seed-sætning her!" - }, "pending": { "message": "afventer" }, @@ -1158,9 +1155,6 @@ "storePhrase": { "message": "Gem denne sætning i en adgangskodeadministrator som 1Password." }, - "submit": { - "message": "Indsend" - }, "submitted": { "message": "Indsendt" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index a9fc00d61e81..6f8a4f6118b6 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -837,9 +837,6 @@ "message": "Füge deine Private Key Zeichenfolge hier ein:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Füge deine Seed-Wörterfolge hier ein!" - }, "pending": { "message": "ausstehend" }, @@ -1149,9 +1146,6 @@ "storePhrase": { "message": "Speichern Sie diesen Schlüssel in einem Passwortmanager wie 1Password." }, - "submit": { - "message": "Einreichen" - }, "submitted": { "message": "Abgeschickt" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index c2e5b9378b32..b2dca5cfae5f 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -864,9 +864,6 @@ "message": "Επικολλήστε τη συμβολοσειρά ιδιωτικού κλειδιού εδώ:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Επικολλήστε τη φράση επαναφοράς σας εδώ!" - }, "pending": { "message": "σε εκκρεμότητα" }, @@ -1180,9 +1177,6 @@ "storePhrase": { "message": "Αποθηκεύστε αυτήν τη φράση σε έναν διαχειριστή κωδικών πρόσβασης όπως το 1Password." }, - "submit": { - "message": "Υποβολή" - }, "submitted": { "message": "Υποβλήθηκε" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 17d8adb09ecb..57be0891c1cd 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -962,9 +962,6 @@ "message": "Paste your private key string here:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Paste your seed phrase here!" - }, "pending": { "message": "pending" }, @@ -1298,9 +1295,6 @@ "storePhrase": { "message": "Store this phrase in a password manager like 1Password." }, - "submit": { - "message": "Submit" - }, "submitted": { "message": "Submitted" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index e651b5b54c5f..f0ac779345aa 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -698,9 +698,6 @@ "message": "Pega tu clave privada aqui", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "¡Pega tu frase semilla aquí!" - }, "pending": { "message": "pendiente" }, @@ -963,9 +960,6 @@ "step3HardwareWalletMsg": { "message": "Usa tu cuenta física igual que harías con cualquier cuenta de Ethereum. Regístrate con dApps, manda Eth, compra y almacena tokens de ERC20 y otros tokens no-fungibles, como CryptoKitties." }, - "submit": { - "message": "Enviar" - }, "submitted": { "message": "Enviado" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 7b3ea8b83236..5e7c1282e591 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -852,9 +852,6 @@ "message": "Copia y pega tu cadena de claves privada aquí:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "¡Copia y pega tu frase de inicialización aquí!" - }, "pending": { "message": "pendiente" }, @@ -1168,9 +1165,6 @@ "storePhrase": { "message": "Almacena esta frase en un administrador de contraseñas como 1Password." }, - "submit": { - "message": "Enviar" - }, "submitted": { "message": "Enviado" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 1c3572190b35..7ca84547ba1f 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -857,9 +857,6 @@ "message": "Kleepige oma privaatne võtmestring siia:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Kleepige oma seemnefraas siia!" - }, "pending": { "message": "ootel" }, @@ -1173,9 +1170,6 @@ "storePhrase": { "message": "Salvestage see fraas paroolihaldurisse, nagu 1Password." }, - "submit": { - "message": "Esita" - }, "submitted": { "message": "Edastatud" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 45e1d3478808..0baf9e39d347 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -867,9 +867,6 @@ "message": "زنجیره کلید شخصی را در اینجا کاپی کنید:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "عبارت بازیاب تان را اینجا بگذارید!" - }, "pending": { "message": "در حال تعلیق" }, @@ -1183,9 +1180,6 @@ "storePhrase": { "message": "این عبارت را در یک نرم افزار مدیریت رمز عبور مانند 1Password ذخیره نمایید." }, - "submit": { - "message": "ارائه" - }, "submitted": { "message": "ارائه شد" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index eeaad61a4875..b794c350e18d 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -864,9 +864,6 @@ "message": "Liitä yksityisen avaimesi merkkijono tähän:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Liitä salaustekstisi tähän!" - }, "pending": { "message": "odottaa" }, @@ -1180,9 +1177,6 @@ "storePhrase": { "message": "Tallenna tämä teksti johonkin salasanojen hallintaohjelmaan (esim. 1Password)." }, - "submit": { - "message": "Lähetä" - }, "submitted": { "message": "Lähetetty" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index b1183a7c4912..d631cf86e011 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -792,9 +792,6 @@ "message": "I-paste ang iyong private key string dito:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "I-paste ang iyong seed phrase dito!" - }, "pending": { "message": "nakabinbin" }, @@ -1083,9 +1080,6 @@ "storePhrase": { "message": "I-store ang pariralang ito sa isang password manager tulad ng 1Password." }, - "submit": { - "message": "Isumite" - }, "submitted": { "message": "Isinumite" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 144d9faa5607..dd8f40ad2e85 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -834,9 +834,6 @@ "message": "Collez votre clé privée ici:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Collez votre seed phrase ici!" - }, "pending": { "message": "En attente" }, @@ -1150,9 +1147,6 @@ "storePhrase": { "message": "Stockez cette phrase dans un gestionnaire de mots de passe comme 1Password." }, - "submit": { - "message": "Soumettre" - }, "submitted": { "message": "Envoyé" }, diff --git a/app/_locales/gu/messages.json b/app/_locales/gu/messages.json index 3d35859d83ce..39f5ab26c809 100644 --- a/app/_locales/gu/messages.json +++ b/app/_locales/gu/messages.json @@ -128,9 +128,6 @@ "settings": { "message": "સેટિંગ્સ" }, - "submit": { - "message": "સબમિટ કરો" - }, "tryAgain": { "message": "ફરી પ્રયાસ કરો" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index e3a0f25cc3de..70c0d116c3ba 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -864,9 +864,6 @@ "message": "הדבק/י את מחרוזת המפתח הפרטי שלך כאן:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "הדבק/י את ה-seed phrase של כאן!" - }, "pending": { "message": "בהמתנה" }, @@ -1177,9 +1174,6 @@ "storePhrase": { "message": "אחסנ/י צירוף זה במנהל ססמאות כמו 1Password." }, - "submit": { - "message": "שלח" - }, "submitted": { "message": "הוגש" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 84552a299fb4..82681dd4af25 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -864,9 +864,6 @@ "message": "अपनी निजी कुंजी स्ट्रिंग यहां पेस्ट करें:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "अपना बीज वाक्यांश यहाँ पेस्ट करें!" - }, "pending": { "message": "विलंबित" }, @@ -1177,9 +1174,6 @@ "storePhrase": { "message": "इस वाक्यांश को 1पासवर्ड जैसे पासवर्ड मैनेजर में संग्रहीत करें।" }, - "submit": { - "message": "सबमिट करें" - }, "submitted": { "message": "प्रस्तुत किया गया" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index f6475312bcd1..e7a954b6a8ff 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -341,9 +341,6 @@ "message": "यहां अपनी निजी कुंजी स्ट्रिंग चिपकाएं:", "description": "किसी निजी कुंजी से किसी खाते को आयात करने के लिए" }, - "pasteSeed": { - "message": "यहां अपने बीज वाक्यांश पेस्ट करें!" - }, "personalAddressDetected": { "message": "व्यक्तिगत पता मिला। टोकन अनुबंध का पता इनपुट।" }, @@ -444,9 +441,6 @@ "stateLogsDescription": { "message": "स्थिति संदेश में आपका सार्वजनिक खाता, पतों और भेजे गए लेनदेन, होते हैं।" }, - "submit": { - "message": "सबमिट करें" - }, "supportCenter": { "message": "हमारे सहायता केंद्र पर जाएं" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 6ea7a3c87298..0c8b878b270d 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -860,9 +860,6 @@ "message": "Ovdje zalijepite svoj privatni niz ključa:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Ovdje zalijepite svoju početnu rečenicu!" - }, "pending": { "message": "na čekanju" }, @@ -1176,9 +1173,6 @@ "storePhrase": { "message": "Spremite ovu rečenicu u upravitelj lozinkama poput aplikacije 1Password." }, - "submit": { - "message": "Pošalji" - }, "submitted": { "message": "Poslano" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 50ee5ee6cfe3..f94a29f7291e 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -521,9 +521,6 @@ "message": "Kole fraz prive ou a la:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Kole seed fraz ou a la!" - }, "pending": { "message": "l ap mache" }, @@ -753,9 +750,6 @@ "step3HardwareWalletMsg": { "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties." }, - "submit": { - "message": "Soumèt" - }, "submitted": { "message": "Te Soumèt" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index ce45b6c72954..ba33a070575e 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -860,9 +860,6 @@ "message": "Illessze be ide a privát kulcs karakterláncát:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Másolja be ide a seed mondatot!" - }, "pending": { "message": "folyamatban" }, @@ -1176,9 +1173,6 @@ "storePhrase": { "message": "Tárolja a mondatot jelszókezelőben, például az 1Passwordben." }, - "submit": { - "message": "Elküldés" - }, "submitted": { "message": "Elküldve" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 89c4cf39ad6e..6c5e2d8da842 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -845,9 +845,6 @@ "message": "Tempelkan string kunci privat di sini:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Tempel frasa benih Anda di sini!" - }, "pending": { "message": "tertunda" }, @@ -1161,9 +1158,6 @@ "storePhrase": { "message": "Simpan frasa ini dalam manajer sandi seperti 1Password." }, - "submit": { - "message": "Kirim" - }, "submitted": { "message": "Terkirim" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 68e7d17391f0..36666d21b01a 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -830,9 +830,6 @@ "message": "Incolla la tua chiave privata qui:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Incolla la tua frase seed qui!" - }, "pending": { "message": "in corso" }, @@ -1146,9 +1143,6 @@ "storePhrase": { "message": "Conserva questa frase in un gestore di password come 1Password." }, - "submit": { - "message": "Invia" - }, "submitted": { "message": "Inviata" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 7a0de9a10060..1205038562a4 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -413,9 +413,6 @@ "message": "秘密鍵をここにペーストして下さい:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "パスフレーズをここにペーストして下さい!" - }, "privacyMsg": { "message": "プライバシーポリシー" }, @@ -507,9 +504,6 @@ "sigRequest": { "message": "署名リクエスト" }, - "submit": { - "message": "送信" - }, "terms": { "message": "利用規約" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index b84dfab71221..86ffad3b3480 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -867,9 +867,6 @@ "message": "ನಿಮ್ಮ ಖಾಸಗಿ ಪ್ರಮುಖ ಸ್ಟ್ರಿಂಗ್ ಅನ್ನು ಇಲ್ಲಿ ನಕಲಿಸಿ:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "ನಿಮ್ಮ ಸೀಡ್ ಫ್ರೇಸ್ ಅನ್ನು ಇಲ್ಲಿ ನಕಲಿಸಿ!" - }, "pending": { "message": "ಬಾಕಿಯಿರುವುದು" }, @@ -1183,9 +1180,6 @@ "storePhrase": { "message": "ಈ ಫ್ರೇಸ್ ಅನ್ನು ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ 1Password ರೂಪದಲ್ಲಿ ಸಂಗ್ರಹಿಸಿ." }, - "submit": { - "message": "ಸಲ್ಲಿಸು" - }, "submitted": { "message": "ಸಲ್ಲಿಸಲಾಗಿದೆ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index bdc554fd68df..4cf4699d1a72 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -858,9 +858,6 @@ "message": "개인키를 입력해주세요:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "시드 구문을 이곳에 붙여넣어 주세요!" - }, "pending": { "message": "펜딩 중" }, @@ -1174,9 +1171,6 @@ "storePhrase": { "message": "이 구문을 1Password같은 암호 관리자에 저장하세요." }, - "submit": { - "message": "제출" - }, "submitted": { "message": "제출됨" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index e0128b2c8512..2862daa98ce1 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -867,9 +867,6 @@ "message": "Čia įklijuokite asmeninio rakto eilutę:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Čia įklijuokite savo atkūrimo frazę!" - }, "pending": { "message": "laukiama patvirtinimo" }, @@ -1183,9 +1180,6 @@ "storePhrase": { "message": "Laikykite šią frazę slaptažodžių tvarkyklėje kaip 1 slaptažodį." }, - "submit": { - "message": "Pateikti" - }, "submitted": { "message": "Pateikta" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 84a7e866b5f1..13b5f56a9a75 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -863,9 +863,6 @@ "message": "Ielīmējiet privātās atslēgas rindu šeit:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Iekopējiet savu atkopšanas frāzi šeit!" - }, "pending": { "message": "gaida" }, @@ -1179,9 +1176,6 @@ "storePhrase": { "message": "Saglabājiet šo frāzi paroļu pārvaldniekā, piemēram, 1Password." }, - "submit": { - "message": "Iesniegt" - }, "submitted": { "message": "Iesniegts" }, diff --git a/app/_locales/ml/messages.json b/app/_locales/ml/messages.json index 7d32da1fb3ed..cd9736e8c5f6 100644 --- a/app/_locales/ml/messages.json +++ b/app/_locales/ml/messages.json @@ -128,9 +128,6 @@ "settings": { "message": "ക്രമീകരണങ്ങള്‍" }, - "submit": { - "message": "സമര്‍പ്പിക്കൂ" - }, "tryAgain": { "message": "വീണ്ടും ശ്രമിക്കുക" }, diff --git a/app/_locales/mr/messages.json b/app/_locales/mr/messages.json index d8af2aa1c5ac..fa8635a39832 100644 --- a/app/_locales/mr/messages.json +++ b/app/_locales/mr/messages.json @@ -128,9 +128,6 @@ "settings": { "message": "सेटिंग्ज" }, - "submit": { - "message": "सबमिट करा" - }, "tryAgain": { "message": "पुन्हा प्रयत्न करा" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index a9c3a8b83385..abcf699e3e15 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -838,9 +838,6 @@ "message": "Tampal rentetan kekunci persendirian anda di sini:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Tampal ungkapan benih anda di sini!" - }, "pending": { "message": "menunggu" }, @@ -1154,9 +1151,6 @@ "storePhrase": { "message": "Simpan ungkapan ini di dalam pengurus kata laluan seperti 1Password." }, - "submit": { - "message": "Serah" - }, "submitted": { "message": "Dihantar" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index ffc41547630b..82cabe99661e 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -328,9 +328,6 @@ "message": "Plak hier uw privésleutelstring:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Plak je back-up woorden hier!" - }, "personalAddressDetected": { "message": "Persoonlijk adres gedetecteerd. Voer het tokencontractadres in." }, @@ -434,9 +431,6 @@ "stateLogsDescription": { "message": "Staatslogboeken bevatten uw openbare accountadressen en verzonden transacties." }, - "submit": { - "message": "voorleggen" - }, "supportCenter": { "message": "Bezoek ons ​​ondersteuningscentrum" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index de59dc5ac683..437e1a4c42e8 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -857,9 +857,6 @@ "message": "Lim inn din private nøkkelstreng her:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Lim inn seed-frasen din her!" - }, "pending": { "message": "i påvente " }, @@ -1161,9 +1158,6 @@ "storePhrase": { "message": "Lagre denne frasen i en passordbehandler slik som 1Password." }, - "submit": { - "message": "Send" - }, "submitted": { "message": "Sendt inn" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index fbe079a76c03..1eaa38ef390e 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -249,9 +249,6 @@ "message": "I-paste dito ang iyong private key string:", "description": "Para sa pag-import ng account mula sa private key" }, - "pasteSeed": { - "message": "I-paste dito ang iyong seed phrase!" - }, "privateKeyWarning": { "message": "Babala: Huwag sabihin sa kahit na sino ang key na ito. Maaring makuha at manakaw ng sinumang nakakaalam ng iyong private key ang mga assets sa iyong account." }, @@ -300,9 +297,6 @@ "sigRequest": { "message": "Hiling na Signature" }, - "submit": { - "message": "I-submit" - }, "toETHviaShapeShift": { "message": "$1 sa ETH sa pamamagitan ng ShapeShift", "description": "Pupunan ng system ang deposit type sa simula ng mensahe" diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 97fc8a24efa6..c49570571a85 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -858,9 +858,6 @@ "message": "Tutaj wklej swój prywatny klucz:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Tutaj wklej swoją frazę seed!" - }, "pending": { "message": "oczekiwanie" }, @@ -1174,9 +1171,6 @@ "storePhrase": { "message": "Przechowuj tę frazę w menedżerze haseł, takim jak 1Password." }, - "submit": { - "message": "Wyślij" - }, "submitted": { "message": "Wysłane" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 1f66d39f5074..40365ad337e5 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -338,9 +338,6 @@ "message": "Cole aqui a sua chave privada:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Cole aqui a sua frase seed!" - }, "personalAddressDetected": { "message": "Endereço pessoal detectado. Introduza o endereço do contrato do token." }, @@ -444,9 +441,6 @@ "stateLogsDescription": { "message": "Registo de estado podem conter o seu endereço e transações enviadas da sua conta pública." }, - "submit": { - "message": "Submeter" - }, "supportCenter": { "message": "Visitar o nosso Centro de Suporte" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 01a280a92bf7..5d43cab5d205 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -852,9 +852,6 @@ "message": "Cole a string de sua chave particular aqui:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Cole sua seed phrase aqui!" - }, "pending": { "message": "pendente" }, @@ -1168,9 +1165,6 @@ "storePhrase": { "message": "Guarde esta frase em um gerenciador de senhas como o 1Password." }, - "submit": { - "message": "Enviar" - }, "submitted": { "message": "Enviado" }, diff --git a/app/_locales/pt_PT/messages.json b/app/_locales/pt_PT/messages.json index 5fd6b291a099..b2f844fdd8c8 100644 --- a/app/_locales/pt_PT/messages.json +++ b/app/_locales/pt_PT/messages.json @@ -153,9 +153,6 @@ "settings": { "message": "Definições" }, - "submit": { - "message": "Submeter" - }, "tips": { "message": "Doações" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 2da7f04bb91e..4cbd0faa8c2d 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -854,9 +854,6 @@ "message": "Lipiți aici șirul de chei private:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Copiați-vă expresia seed aici!" - }, "pending": { "message": "în așteptare" }, @@ -1170,9 +1167,6 @@ "storePhrase": { "message": "Păstrați această expresie într-un program de gestionare a parolelor cum ar fi 1Password." }, - "submit": { - "message": "Trimite" - }, "submitted": { "message": "Trimis" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 0024be030b79..82245dd0eeb0 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -374,9 +374,6 @@ "message": "Вставьте ваш закрытый ключ тут:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Вставьте вашу ключевую фразу!" - }, "personalAddressDetected": { "message": "Обнаружен персональный адрес. Введите адрес контракта токена." }, @@ -489,9 +486,6 @@ "stateLogError": { "message": "Ошибка при получении журнала состояния." }, - "submit": { - "message": "Отправить" - }, "submitted": { "message": "Отправлена" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 0cf1cb5e09a2..903b2d7c7b63 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -833,9 +833,6 @@ "message": "Vložte zde svůj privátní klíč:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Svou klíčovou frázi vložte zde!" - }, "pending": { "message": "prebieha" }, @@ -1143,9 +1140,6 @@ "storePhrase": { "message": "Túto frázu uložte do správcu hesiel ako 1Password." }, - "submit": { - "message": "Odeslat" - }, "submitted": { "message": "Odesláno" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 6a7b1c88893d..84d46bab25c1 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -852,9 +852,6 @@ "message": "Tukaj prilepite vaš zasebni ključ:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Tukaj prilepite seed phase!" - }, "pending": { "message": "v obdelavi" }, @@ -1165,9 +1162,6 @@ "storePhrase": { "message": "To geslo shranite v upravitelja gesel, kot je 1Password." }, - "submit": { - "message": "Potrdi" - }, "submitted": { "message": "Potrjeno" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index f2d5d8f44dfe..67c7980aef32 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -858,9 +858,6 @@ "message": "Ovde nalepite vaš niz privatnog ključa", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Nalepite ovde svoju početnu frazu!" - }, "pending": { "message": "u toku" }, @@ -1174,9 +1171,6 @@ "storePhrase": { "message": "Čuvajte ovaj izraz u menadžeru šifri kao što je 1Password." }, - "submit": { - "message": "Пошаљи" - }, "submitted": { "message": "Prosleđeno" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 33d6a2c63571..b15c3369e69e 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -851,9 +851,6 @@ "message": "Klistra in din privata nyckel här:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Klistra in din nyckelfras här!" - }, "pending": { "message": "väntar" }, @@ -1167,9 +1164,6 @@ "storePhrase": { "message": "Lagra denna fras i en lösenordshanterare såsom 1Password." }, - "submit": { - "message": "Skicka" - }, "submitted": { "message": "Inskickat" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index be0032257203..fda4cb20524b 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -845,9 +845,6 @@ "message": "Bandika uzi wako wa ufunguo binafsi hapa:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Bandika kirai kianzio chako hapa!" - }, "pending": { "message": "inasubiri" }, @@ -1161,9 +1158,6 @@ "storePhrase": { "message": "Hifadhi kirai hiki kwenye kidhibiti nenosiri kama vile 1Password." }, - "submit": { - "message": "Wasilisha" - }, "submitted": { "message": "Imewasilishwa" }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index 60c75d3c597d..8cf8db165b6f 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -371,9 +371,6 @@ "message": "இங்கே உங்கள் தனிப்பட்ட விசை சரத்தை ஒட்டுக:", "description": "ஒரு தனிப்பட்ட விசை ஒரு கணக்கை இறக்குமதி செய்ய" }, - "pasteSeed": { - "message": "இங்கே உங்கள் விதை சொற்றொடரை ஒட்டவும்!" - }, "personalAddressDetected": { "message": "தனிப்பட்ட முகவரி கண்டறியப்பட்டது. டோக்கன் ஒப்பந்த முகவரியை உள்ளிடவும்." }, @@ -498,9 +495,6 @@ "stateLogError": { "message": "மாநில பதிவுகளை மீட்டெடுப்பதில் பிழை." }, - "submit": { - "message": "சமர்ப்பி" - }, "submitted": { "message": "சமர்ப்பிக்கப்பட்டது" }, diff --git a/app/_locales/te/messages.json b/app/_locales/te/messages.json index d0fb123106c5..6de4b0464def 100644 --- a/app/_locales/te/messages.json +++ b/app/_locales/te/messages.json @@ -128,9 +128,6 @@ "settings": { "message": "సెట్టింగ్‌లు" }, - "submit": { - "message": "సమర్పించు" - }, "tryAgain": { "message": "మళ్లీ ప్రయత్నించు" }, diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index 10a23bd9fb16..0cd9456d28e3 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -440,9 +440,6 @@ "message": "วางคีย์ส่วนตัวของคุณที่นี่:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "วางคำชีดของคุณที่นี่!" - }, "personalAddressDetected": { "message": "ตรวจพบแอดแดรสส่วนตัวแล้ว ใส่แอดแดรสสัญญาโทเค็น" }, @@ -585,9 +582,6 @@ "storePhrase": { "message": "เก็บ Phrase นี้ในตัวจัดการรหัสผ่าน เช่น 1Password" }, - "submit": { - "message": "ตกลง" - }, "supportCenter": { "message": "ไปที่ศูนย์สนับสนุนของเรา" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index caeea4fcc048..96351eebdf25 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -376,9 +376,6 @@ "message": "Özel anahtar dizinizi buraya yapıştırın:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Kaynak ifadenizi buraya yapıştırın!" - }, "personalAddressDetected": { "message": "Kişisel adres tespit edilidi. Jeton sözleşme adresini girin." }, @@ -491,9 +488,6 @@ "stateLogError": { "message": "Durum kayıtlarını alma hatası" }, - "submit": { - "message": "Gönder" - }, "submitted": { "message": "Gönderildi" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index c818cce719b9..f2601e8dd46b 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -867,9 +867,6 @@ "message": "Вставте ваш рядок з особистим ключем сюди:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Вставте сюди свою мнемонічну фразу!" - }, "pending": { "message": "очікує" }, @@ -1183,9 +1180,6 @@ "storePhrase": { "message": "Зберігайте цю фразу у менеджері паролів, як 1Password." }, - "submit": { - "message": "Надіслати" - }, "submitted": { "message": "Надіслано" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 32470ecb75b3..7e5f717e58e0 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -281,9 +281,6 @@ "message": "Dán dãy khóa cá nhân của bạn tại đây:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "Dán Mật Khẩu Sinh Khoá (seed phrase) của bạn tại đây!" - }, "privateKey": { "message": "Khóa Bí Mật", "description": "select this type of file to use to import an account" @@ -345,9 +342,6 @@ "sigRequest": { "message": "Yêu cầu chữ ký" }, - "submit": { - "message": "Gửi đi" - }, "testFaucet": { "message": "Vòi nhận tiền ETH ảo để thử nghiệm" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index c7da59af04d9..4c087fd3b4e3 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -849,9 +849,6 @@ "message": "请粘贴你的私钥:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "请粘贴你的助记词!" - }, "pending": { "message": "待处理" }, @@ -1165,9 +1162,6 @@ "storePhrase": { "message": "通过如 1Password 等密码管家保存该密语。" }, - "submit": { - "message": "提交" - }, "submitted": { "message": "已提交" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index b78fbbbce55b..56cc4751dc0d 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -855,9 +855,6 @@ "message": "請貼上您的私鑰字串:", "description": "For importing an account from a private key" }, - "pasteSeed": { - "message": "請貼上您的助憶詞!" - }, "pending": { "message": "等待處理" }, @@ -1159,9 +1156,6 @@ "storePhrase": { "message": "您可以用密碼管理系統例如 1Password 等軟體儲存助憶詞。" }, - "submit": { - "message": "送出" - }, "submitted": { "message": "已送出" }, diff --git a/ui/app/pages/create-account/import-account/seed.js b/ui/app/pages/create-account/import-account/seed.js deleted file mode 100644 index 73332f926123..000000000000 --- a/ui/app/pages/create-account/import-account/seed.js +++ /dev/null @@ -1,35 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') -const PropTypes = require('prop-types') -const connect = require('react-redux').connect - -SeedImportSubview.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(SeedImportSubview) - - -function mapStateToProps () { - return {} -} - -inherits(SeedImportSubview, Component) -function SeedImportSubview () { - Component.call(this) -} - -SeedImportSubview.prototype.render = function () { - return ( - h('div', { - style: { - }, - }, [ - this.context.t('pasteSeed'), - h('textarea'), - h('br'), - h('button', this.context.t('submit')), - ]) - ) -} From 1cac6f27687cbc452b3483287cf556f9dfd0db25 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 17:48:58 -0330 Subject: [PATCH 51/88] Convert SimpleDropdown component to use JSX (#7540) --- .../app/dropdowns/simple-dropdown.js | 98 +++++++++---------- 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/ui/app/components/app/dropdowns/simple-dropdown.js b/ui/app/components/app/dropdowns/simple-dropdown.js index bba088ed1d28..081674397fc0 100644 --- a/ui/app/components/app/dropdowns/simple-dropdown.js +++ b/ui/app/components/app/dropdowns/simple-dropdown.js @@ -1,15 +1,18 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const classnames = require('classnames') -const R = require('ramda') +import classnames from 'classnames' +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import R from 'ramda' class SimpleDropdown extends Component { - constructor (props) { - super(props) - this.state = { - isOpen: false, - } + static propTypes = { + options: PropTypes.array.isRequired, + placeholder: PropTypes.string, + onSelect: PropTypes.func, + selectedOption: PropTypes.string, + } + + state = { + isOpen: false, } getDisplayValue () { @@ -26,67 +29,58 @@ class SimpleDropdown extends Component { } toggleOpen () { - const { isOpen } = this.state - this.setState({ isOpen: !isOpen }) + this.setState((prevState) => ({ + isOpen: !prevState.isOpen, + })) } renderOptions () { const { options, onSelect, selectedOption } = this.props - return h('div', [ - h('div.simple-dropdown__close-area', { - onClick: event => { - event.stopPropagation() - this.handleClose() - }, - }), - h('div.simple-dropdown__options', [ - ...options.map(option => { - return h( - 'div.simple-dropdown__option', - { - className: classnames({ + return ( +
    +
    { + event.stopPropagation() + this.handleClose() + }} + /> +
    + {options.map((option) => ( +
    { + })} + key={option.value} + onClick={() => { if (option.value !== selectedOption) { onSelect(option.value) } this.handleClose() - }, - }, - option.displayValue || option.value, - ) - }), - ]), - ]) + }} + > + {option.displayValue || option.value} +
    + ))} +
    +
    + ) } render () { const { placeholder } = this.props const { isOpen } = this.state - return h( - 'div.simple-dropdown', - { - onClick: () => this.toggleOpen(), - }, - [ - h('div.simple-dropdown__selected', this.getDisplayValue() || placeholder || 'Select'), - h('i.fa.fa-caret-down.fa-lg.simple-dropdown__caret'), - isOpen && this.renderOptions(), - ] + return ( +
    this.toggleOpen()}> +
    {this.getDisplayValue() || placeholder || 'Select'}
    + + {isOpen && this.renderOptions()} +
    ) } } -SimpleDropdown.propTypes = { - options: PropTypes.array.isRequired, - placeholder: PropTypes.string, - onSelect: PropTypes.func, - selectedOption: PropTypes.string, -} - module.exports = SimpleDropdown From 04442318d39d3cfc3ab0657f7a7ac201ea9ce614 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 17:51:21 -0330 Subject: [PATCH 52/88] Convert EditableLabel component to use JSX (#7543) --- ui/app/components/ui/editable-label.js | 96 ++++++++++++-------------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/ui/app/components/ui/editable-label.js b/ui/app/components/ui/editable-label.js index 8eb10e1742a5..43b28881930e 100644 --- a/ui/app/components/ui/editable-label.js +++ b/ui/app/components/ui/editable-label.js @@ -1,16 +1,17 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const classnames = require('classnames') +import classnames from 'classnames' +import PropTypes from 'prop-types' +import React, { Component } from 'react' class EditableLabel extends Component { - constructor (props) { - super(props) + static propTypes = { + onSubmit: PropTypes.func.isRequired, + defaultValue: PropTypes.string, + className: PropTypes.string, + } - this.state = { - isEditing: false, - value: props.defaultValue || '', - } + state = { + isEditing: false, + value: this.props.defaultValue || '', } handleSubmit () { @@ -24,46 +25,41 @@ class EditableLabel extends Component { .then(() => this.setState({ isEditing: false })) } - saveIfEnter (event) { - if (event.key === 'Enter') { - this.handleSubmit() - } - } - renderEditing () { const { value } = this.state - return ([ - h('input.large-input.editable-label__input', { - type: 'text', - required: true, - dir: 'auto', - value: this.state.value, - onKeyPress: (event) => { + return [( + { if (event.key === 'Enter') { this.handleSubmit() } - }, - onChange: event => this.setState({ value: event.target.value }), - className: classnames({ 'editable-label__input--error': value === '' }), - }), - h('div.editable-label__icon-wrapper', [ - h('i.fa.fa-check.editable-label__icon', { - onClick: () => this.handleSubmit(), - }), - ]), - ]) + }} + onChange={event => this.setState({ value: event.target.value })} + className={classnames('large-input', 'editable-label__input', { + 'editable-label__input--error': value === '', + })} + /> + ), ( +
    + this.handleSubmit()} /> +
    + )] } renderReadonly () { - return ([ - h('div.editable-label__value', this.state.value), - h('div.editable-label__icon-wrapper', [ - h('i.fa.fa-pencil.editable-label__icon', { - onClick: () => this.setState({ isEditing: true }), - }), - ]), - ]) + return [( +
    {this.state.value}
    + ), ( +
    + this.setState({ isEditing: true })} /> +
    + )] } render () { @@ -71,19 +67,15 @@ class EditableLabel extends Component { const { className } = this.props return ( - h('div.editable-label', { className: classnames(className) }, - isEditing - ? this.renderEditing() - : this.renderReadonly() - ) +
    + { + isEditing + ? this.renderEditing() + : this.renderReadonly() + } +
    ) } } -EditableLabel.propTypes = { - onSubmit: PropTypes.func.isRequired, - defaultValue: PropTypes.string, - className: PropTypes.string, -} - module.exports = EditableLabel From 8311617b95f43aa1c009018140b8164ae9a404f3 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 17:51:50 -0330 Subject: [PATCH 53/88] Convert LoadingScreen component to use JSX (#7545) --- .../loading-screen.component.js | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) 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 6b843cfee0c4..b3fb3308d566 100644 --- a/ui/app/components/ui/loading-screen/loading-screen.component.js +++ b/ui/app/components/ui/loading-screen/loading-screen.component.js @@ -1,31 +1,33 @@ -const { Component } = require('react') -const h = require('react-hyperscript') +import React, {Component} from 'react' const PropTypes = require('prop-types') const Spinner = require('../spinner') class LoadingScreen extends Component { + static defaultProps = { + loadingMessage: null, + } + + static propTypes = { + loadingMessage: PropTypes.string, + } + renderMessage () { const { loadingMessage } = this.props - return loadingMessage && h('span', loadingMessage) + return loadingMessage + ? {loadingMessage} + : null } render () { return ( - h('.loading-overlay', [ - h('.loading-overlay__container', [ - h(Spinner, { - color: '#F7C06C', - }), - - this.renderMessage(), - ]), - ]) +
    +
    + + {this.renderMessage()} +
    +
    ) } } -LoadingScreen.propTypes = { - loadingMessage: PropTypes.string, -} - module.exports = LoadingScreen From 6e73d2be69dccf6cf4b2bc4ddebdd868ec87f3d5 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 18:31:56 -0330 Subject: [PATCH 54/88] Convert HideTokenConfirmationModal component to use JSX (#7551) --- .../modals/hide-token-confirmation-modal.js | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/ui/app/components/app/modals/hide-token-confirmation-modal.js b/ui/app/components/app/modals/hide-token-confirmation-modal.js index e2b098923c81..c3709e9239c8 100644 --- a/ui/app/components/app/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/app/modals/hide-token-confirmation-modal.js @@ -1,6 +1,5 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React, { Component } from 'react' const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../../store/actions') @@ -40,44 +39,43 @@ HideTokenConfirmationModal.contextTypes = { module.exports = connect(mapStateToProps, mapDispatchToProps)(HideTokenConfirmationModal) -HideTokenConfirmationModal.prototype.render = function () { +HideTokenConfirmationModal.prototype.render = function HideTokenConfirmationModal () { const { token, network, hideToken, hideModal, assetImages } = this.props const { symbol, address } = token const image = assetImages[address] - return h('div.hide-token-confirmation', {}, [ - h('div.hide-token-confirmation__container', { - }, [ - h('div.hide-token-confirmation__title', {}, [ - this.context.t('hideTokenPrompt'), - ]), - - h(Identicon, { - className: 'hide-token-confirmation__identicon', - diameter: 45, - address, - network, - image, - }), - - h('div.hide-token-confirmation__symbol', {}, symbol), - - h('div.hide-token-confirmation__copy', {}, [ - this.context.t('readdToken'), - ]), - - h('div.hide-token-confirmation__buttons', {}, [ - h('button.btn-default.hide-token-confirmation__button.btn--large', { - onClick: () => hideModal(), - }, [ - this.context.t('cancel'), - ]), - h('button.btn-secondary.hide-token-confirmation__button.btn--large', { - onClick: () => hideToken(address), - }, [ - this.context.t('hide'), - ]), - ]), - ]), - ]) + return ( +
    +
    +
    + {this.context.t('hideTokenPrompt')} +
    + +
    {symbol}
    +
    + {this.context.t('readdToken')} +
    +
    + + +
    +
    +
    + ) } From d948a3b195d587c2c460d47af5392c9168662ca3 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 18:32:53 -0330 Subject: [PATCH 55/88] Convert NotificationModal component to use JSX (#7550) --- .../app/modals/notification-modal.js | 84 ++++++++++--------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/ui/app/components/app/modals/notification-modal.js b/ui/app/components/app/modals/notification-modal.js index 84d9004b7bfe..9cec3ed826c1 100644 --- a/ui/app/components/app/modals/notification-modal.js +++ b/ui/app/components/app/modals/notification-modal.js @@ -1,8 +1,7 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('../../../store/actions') +import PropTypes from 'prop-types' +import React, {Component} from 'react' +import {connect} from 'react-redux' +import { hideModal } from '../../../store/actions' class NotificationModal extends Component { render () { @@ -17,41 +16,44 @@ class NotificationModal extends Component { const showButtons = showCancelButton || showConfirmButton - return h('div', [ - h('div.notification-modal__wrapper', { - }, [ - - h('div.notification-modal__header', {}, [ - this.context.t(header), - ]), - - h('div.notification-modal__message-wrapper', {}, [ - h('div.notification-modal__message', {}, [ - this.context.t(message), - ]), - ]), - - h('div.modal-close-x', { - onClick: hideModal, - }), - - showButtons && h('div.notification-modal__buttons', [ - - showCancelButton && h('div.btn-default.notification-modal__buttons__btn', { - onClick: hideModal, - }, 'Cancel'), - - showConfirmButton && h('div.button.btn-secondary.notification-modal__buttons__btn', { - onClick: () => { - onConfirm() - hideModal() - }, - }, 'Confirm'), - - ]), - - ]), - ]) + return ( +
    +
    +
    + {this.context.t(header)} +
    +
    +
    + {this.context.t(message)} +
    +
    +
    + {showButtons && ( +
    + {showCancelButton && ( +
    + Cancel +
    + )} + {showConfirmButton && ( +
    { + onConfirm() + hideModal() + }} + > + Confirm +
    + )} +
    + )} +
    +
    + ) } } @@ -68,7 +70,7 @@ NotificationModal.propTypes = { const mapDispatchToProps = dispatch => { return { hideModal: () => { - dispatch(actions.hideModal()) + dispatch(hideModal()) }, } } From 666277b4fa6518e1d7fba5b44ee35b47a5780a3b Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 19:09:10 -0330 Subject: [PATCH 56/88] Convert TokenMenuDropdown component to use JSX (#7552) --- .../app/dropdowns/token-menu-dropdown.js | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/ui/app/components/app/dropdowns/token-menu-dropdown.js b/ui/app/components/app/dropdowns/token-menu-dropdown.js index e2730aea2111..65c559f7090b 100644 --- a/ui/app/components/app/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/app/dropdowns/token-menu-dropdown.js @@ -1,6 +1,5 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React, { Component } from 'react' const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../../store/actions') @@ -40,29 +39,29 @@ TokenMenuDropdown.prototype.onClose = function (e) { this.props.onClose() } -TokenMenuDropdown.prototype.render = function () { +TokenMenuDropdown.prototype.render = function TokenMenuDropdown () { const { showHideTokenConfirmationModal } = this.props - return h(Menu, { className: 'token-menu-dropdown', isShowing: true }, [ - h(CloseArea, { - onClick: this.onClose, - }), - h(Item, { - onClick: (e) => { - e.stopPropagation() - showHideTokenConfirmationModal(this.props.token) - this.props.onClose() - }, - text: this.context.t('hideToken'), - }), - h(Item, { - onClick: (e) => { - e.stopPropagation() - const url = genAccountLink(this.props.token.address, this.props.network) - global.platform.openWindow({ url }) - this.props.onClose() - }, - text: this.context.t('viewOnEtherscan'), - }), - ]) + return ( + + + { + e.stopPropagation() + showHideTokenConfirmationModal(this.props.token) + this.props.onClose() + }} + text={this.context.t('hideToken')} + /> + { + e.stopPropagation() + const url = genAccountLink(this.props.token.address, this.props.network) + global.platform.openWindow({ url }) + this.props.onClose() + }} + text={this.context.t('viewOnEtherscan')} + /> + + ) } From 22a2d21796e652123dd304c38e3648bef0130ec1 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 19:10:16 -0330 Subject: [PATCH 57/88] Convert Alert component to use JSX (#7542) --- ui/app/components/ui/alert/index.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/ui/app/components/ui/alert/index.js b/ui/app/components/ui/alert/index.js index da2ca4b661c8..7d09de3cbad4 100644 --- a/ui/app/components/ui/alert/index.js +++ b/ui/app/components/ui/alert/index.js @@ -1,17 +1,12 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import classnames from 'classnames' +import PropTypes from 'prop-types' +import React, { Component } from 'react' class Alert extends Component { - - constructor (props) { - super(props) - - this.state = { - visble: false, - msg: false, - className: '', - } + state = { + visible: false, + msg: false, + className: '', } componentWillReceiveProps (nextProps) { @@ -26,14 +21,14 @@ class Alert extends Component { this.setState({ msg: props.msg, visible: true, - className: '.visible', + className: 'visible', }) } animateOut () { this.setState({ msg: null, - className: '.hidden', + className: 'hidden', }) setTimeout(_ => { @@ -45,9 +40,9 @@ class Alert extends Component { render () { if (this.state.visible) { return ( - h(`div.global-alert${this.state.className}`, {}, - h('a.msg', {}, this.state.msg) - ) + ) } return null From 1ffaa330adfaa02b0002fed1c9a0d70e7f5bcd73 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Sun, 24 Nov 2019 19:11:08 -0330 Subject: [PATCH 58/88] Split AccountModalContainer into container and component files (#7549) Co-Authored-By: Mark Stacey --- .../app/modals/account-modal-container.js | 80 ------------------- .../account-modal-container.component.js | 51 ++++++++++++ .../account-modal-container.container.js | 20 +++++ .../modals/account-modal-container/index.js | 1 + .../app/modals/export-private-key-modal.js | 2 +- 5 files changed, 73 insertions(+), 81 deletions(-) delete mode 100644 ui/app/components/app/modals/account-modal-container.js create mode 100644 ui/app/components/app/modals/account-modal-container/account-modal-container.component.js create mode 100644 ui/app/components/app/modals/account-modal-container/account-modal-container.container.js create mode 100644 ui/app/components/app/modals/account-modal-container/index.js diff --git a/ui/app/components/app/modals/account-modal-container.js b/ui/app/components/app/modals/account-modal-container.js deleted file mode 100644 index b7ae0b5b87a3..000000000000 --- a/ui/app/components/app/modals/account-modal-container.js +++ /dev/null @@ -1,80 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const actions = require('../../../store/actions') -const { getSelectedIdentity } = require('../../../selectors/selectors') -import Identicon from '../../ui/identicon' - -function mapStateToProps (state, ownProps) { - return { - selectedIdentity: ownProps.selectedIdentity || getSelectedIdentity(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - hideModal: () => { - dispatch(actions.hideModal()) - }, - } -} - -inherits(AccountModalContainer, Component) -function AccountModalContainer () { - Component.call(this) -} - -AccountModalContainer.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountModalContainer) - - -AccountModalContainer.prototype.render = function () { - const { - selectedIdentity, - showBackButton = false, - backButtonAction, - } = this.props - let { children } = this.props - - if (children.constructor !== Array) { - children = [children] - } - - return h('div', { style: { borderRadius: '4px' }}, [ - h('div.account-modal-container', [ - - h('div', [ - - // Needs a border; requires changes to svg - h(Identicon, { - address: selectedIdentity.address, - diameter: 64, - style: {}, - }), - - ]), - - showBackButton && h('div.account-modal-back', { - onClick: backButtonAction, - }, [ - - h('i.fa.fa-angle-left.fa-lg'), - - h('span.account-modal-back__text', ' ' + this.context.t('back')), - - ]), - - h('div.account-modal-close', { - onClick: this.props.hideModal, - }), - - ...children, - - ]), - ]) -} 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 new file mode 100644 index 000000000000..c59b1a1accb6 --- /dev/null +++ b/ui/app/components/app/modals/account-modal-container/account-modal-container.component.js @@ -0,0 +1,51 @@ +import PropTypes from 'prop-types' +import React from 'react' +import Identicon from '../../../ui/identicon' + +export default function AccountModalContainer (props, context) { + const { + selectedIdentity, + showBackButton, + backButtonAction, + hideModal, + children, + } = props + + return ( +
    +
    +
    + +
    + {showBackButton && ( +
    + + {' ' + context.t('back')} +
    + )} +
    + {children} +
    +
    + ) +} + +AccountModalContainer.contextTypes = { + t: PropTypes.func, +} + +AccountModalContainer.defaultProps = { + showBackButton: false, + children: null, +} + +AccountModalContainer.propTypes = { + selectedIdentity: PropTypes.object.isRequired, + showBackButton: PropTypes.bool, + backButtonAction: PropTypes.func.isRequired, + hideModal: PropTypes.func.isRequired, + children: PropTypes.node, +} diff --git a/ui/app/components/app/modals/account-modal-container/account-modal-container.container.js b/ui/app/components/app/modals/account-modal-container/account-modal-container.container.js new file mode 100644 index 000000000000..ad118f92d56a --- /dev/null +++ b/ui/app/components/app/modals/account-modal-container/account-modal-container.container.js @@ -0,0 +1,20 @@ +import { connect } from 'react-redux' +import { hideModal } from '../../../../store/actions' +import { getSelectedIdentity } from '../../../../selectors/selectors' +import AccountModalContainer from './account-modal-container.component' + +function mapStateToProps (state, ownProps) { + return { + selectedIdentity: ownProps.selectedIdentity || getSelectedIdentity(state), + } +} + +function mapDispatchToProps (dispatch) { + return { + hideModal: () => { + dispatch(hideModal()) + }, + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(AccountModalContainer) diff --git a/ui/app/components/app/modals/account-modal-container/index.js b/ui/app/components/app/modals/account-modal-container/index.js new file mode 100644 index 000000000000..e37684b963b3 --- /dev/null +++ b/ui/app/components/app/modals/account-modal-container/index.js @@ -0,0 +1 @@ +export { default } from './account-modal-container.container' diff --git a/ui/app/components/app/modals/export-private-key-modal.js b/ui/app/components/app/modals/export-private-key-modal.js index 1e1aaeb74123..2150520153fd 100644 --- a/ui/app/components/app/modals/export-private-key-modal.js +++ b/ui/app/components/app/modals/export-private-key-modal.js @@ -6,11 +6,11 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const { stripHexPrefix } = require('ethereumjs-util') const actions = require('../../../store/actions') -const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../../selectors/selectors') const ReadOnlyInput = require('../../ui/readonly-input') const copyToClipboard = require('copy-to-clipboard') const { checksumAddress } = require('../../../helpers/utils/util') +import AccountModalContainer from './account-modal-container' import Button from '../../ui/button' function mapStateToPropsFactory () { From 2b4c99e0316c8d8a68b63fb859d234412f452c66 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 10:00:46 -0330 Subject: [PATCH 59/88] Split WalletView into component and container files (#7546) --- ui/app/components/app/wallet-view.js | 178 ------------------ ui/app/components/app/wallet-view/index.js | 1 + .../app/wallet-view/wallet-view.component.js | 132 +++++++++++++ .../app/wallet-view/wallet-view.container.js | 33 ++++ 4 files changed, 166 insertions(+), 178 deletions(-) delete mode 100644 ui/app/components/app/wallet-view.js create mode 100644 ui/app/components/app/wallet-view/index.js create mode 100644 ui/app/components/app/wallet-view/wallet-view.component.js create mode 100644 ui/app/components/app/wallet-view/wallet-view.container.js diff --git a/ui/app/components/app/wallet-view.js b/ui/app/components/app/wallet-view.js deleted file mode 100644 index 55aeec333025..000000000000 --- a/ui/app/components/app/wallet-view.js +++ /dev/null @@ -1,178 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const connect = require('react-redux').connect -const h = require('react-hyperscript') -const { withRouter } = require('react-router-dom') -const { compose } = require('recompose') -const inherits = require('util').inherits -const { checksumAddress } = require('../../helpers/utils/util') -// const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns -const actions = require('../../store/actions') -import BalanceComponent from '../ui/balance' -const TokenList = require('./token-list') -const selectors = require('../../selectors/selectors') -const { ADD_TOKEN_ROUTE } = require('../../helpers/constants/routes') - -import AddTokenButton from './add-token-button' -import AccountDetails from './account-details' - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(WalletView) - -WalletView.contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, -} - -WalletView.defaultProps = { - responsiveDisplayClassname: '', -} - -function mapStateToProps (state) { - - return { - network: state.metamask.network, - sidebarOpen: state.appState.sidebar.isOpen, - identities: state.metamask.identities, - accounts: selectors.getMetaMaskAccounts(state), - keyrings: state.metamask.keyrings, - selectedAddress: selectors.getSelectedAddress(state), - selectedAccount: selectors.getSelectedAccount(state), - selectedTokenAddress: state.metamask.selectedTokenAddress, - } -} - -function mapDispatchToProps (dispatch) { - return { - showSendPage: () => dispatch(actions.showSendPage()), - hideSidebar: () => dispatch(actions.hideSidebar()), - unsetSelectedToken: () => dispatch(actions.setSelectedToken()), - showAddTokenPage: () => dispatch(actions.showAddTokenPage()), - } -} - -inherits(WalletView, Component) -function WalletView () { - Component.call(this) -} - -WalletView.prototype.renderWalletBalance = function () { - const { - selectedTokenAddress, - selectedAccount, - unsetSelectedToken, - hideSidebar, - sidebarOpen, - } = this.props - - const selectedClass = selectedTokenAddress - ? '' - : 'wallet-balance-wrapper--active' - const className = `flex-column wallet-balance-wrapper ${selectedClass}` - - return h('div', { className }, [ - h('div.wallet-balance', - { - onClick: () => { - unsetSelectedToken() - selectedTokenAddress && sidebarOpen && hideSidebar() - }, - }, - [ - h(BalanceComponent, { - balanceValue: selectedAccount ? selectedAccount.balance : '', - style: {}, - }), - ] - ), - ]) -} - -WalletView.prototype.renderAddToken = function () { - const { - sidebarOpen, - hideSidebar, - history, - } = this.props - const { metricsEvent } = this.context - - return h(AddTokenButton, { - onClick () { - history.push(ADD_TOKEN_ROUTE) - metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Token Menu', - name: 'Clicked "Add Token"', - }, - }) - if (sidebarOpen) { - hideSidebar() - } - }, - }) -} - -WalletView.prototype.render = function () { - const { - responsiveDisplayClassname, - selectedAddress, - keyrings, - identities, - network, - } = this.props - // temporary logs + fake extra wallets - - const checksummedAddress = checksumAddress(selectedAddress, network) - - if (!selectedAddress) { - throw new Error('selectedAddress should not be ' + String(selectedAddress)) - } - - const keyring = keyrings.find((kr) => { - return kr.accounts.includes(selectedAddress) - }) - - let label = '' - let type - if (keyring) { - type = keyring.type - if (type !== 'HD Key Tree') { - if (type.toLowerCase().search('hardware') !== -1) { - label = this.context.t('hardware') - } else { - label = this.context.t('imported') - } - } - } - - return h('div.wallet-view.flex-column', { - style: {}, - className: responsiveDisplayClassname, - }, [ - - h(AccountDetails, { - label, - checksummedAddress, - name: identities[selectedAddress].name, - }), - - this.renderWalletBalance(), - - h(TokenList), - - this.renderAddToken(), - ]) -} - -// TODO: Extra wallets, for dev testing. Remove when PRing to master. -// const extraWallet = h('div.flex-column.wallet-balance-wrapper', {}, [ -// h('div.wallet-balance', {}, [ -// h(BalanceComponent, { -// balanceValue: selectedAccount.balance, -// style: {}, -// }), -// ]), -// ]) diff --git a/ui/app/components/app/wallet-view/index.js b/ui/app/components/app/wallet-view/index.js new file mode 100644 index 000000000000..bc8fd26aba16 --- /dev/null +++ b/ui/app/components/app/wallet-view/index.js @@ -0,0 +1 @@ +export { default } from './wallet-view.container' diff --git a/ui/app/components/app/wallet-view/wallet-view.component.js b/ui/app/components/app/wallet-view/wallet-view.component.js new file mode 100644 index 000000000000..bf3c976500cf --- /dev/null +++ b/ui/app/components/app/wallet-view/wallet-view.component.js @@ -0,0 +1,132 @@ +import classnames from 'classnames' +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import BalanceComponent from '../../ui/balance' +import AddTokenButton from '../add-token-button' +import AccountDetails from '../account-details' + +const { checksumAddress } = require('../../../helpers/utils/util') +const TokenList = require('../token-list') +const { ADD_TOKEN_ROUTE } = require('../../../helpers/constants/routes') + +export default class WalletView extends Component { + static contextTypes = { + t: PropTypes.func, + metricsEvent: PropTypes.func, + } + + static defaultProps = { + responsiveDisplayClassname: '', + selectedAccount: null, + selectedTokenAddress: null, + } + + static propTypes = { + selectedTokenAddress: PropTypes.string, + selectedAccount: PropTypes.object, + selectedAddress: PropTypes.string.isRequired, + keyrings: PropTypes.array.isRequired, + responsiveDisplayClassname: PropTypes.string, + identities: PropTypes.object.isRequired, + history: PropTypes.object.isRequired, + unsetSelectedToken: PropTypes.func.isRequired, + sidebarOpen: PropTypes.bool.isRequired, + hideSidebar: PropTypes.func.isRequired, + } + + renderWalletBalance () { + const { + selectedTokenAddress, + selectedAccount, + unsetSelectedToken, + hideSidebar, + sidebarOpen, + } = this.props + + return ( +
    +
    { + unsetSelectedToken() + selectedTokenAddress && sidebarOpen && hideSidebar() + }} + > + +
    +
    + ) + } + + renderAddToken () { + const { + sidebarOpen, + hideSidebar, + history, + } = this.props + const { metricsEvent } = this.context + + return ( + { + history.push(ADD_TOKEN_ROUTE) + metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Token Menu', + name: 'Clicked "Add Token"', + }, + }) + if (sidebarOpen) { + hideSidebar() + } + }} + /> + ) + } + + render () { + const { + responsiveDisplayClassname, + selectedAddress, + keyrings, + identities, + } = this.props + + const checksummedAddress = checksumAddress(selectedAddress) + + const keyring = keyrings.find((kr) => { + return kr.accounts.includes(selectedAddress) + }) + + let label = '' + let type + if (keyring) { + type = keyring.type + if (type !== 'HD Key Tree') { + if (type.toLowerCase().search('hardware') !== -1) { + label = this.context.t('hardware') + } else { + label = this.context.t('imported') + } + } + } + + return ( +
    + + {this.renderWalletBalance()} + + {this.renderAddToken()} +
    + ) + } +} diff --git a/ui/app/components/app/wallet-view/wallet-view.container.js b/ui/app/components/app/wallet-view/wallet-view.container.js new file mode 100644 index 000000000000..f0329e3c362b --- /dev/null +++ b/ui/app/components/app/wallet-view/wallet-view.container.js @@ -0,0 +1,33 @@ +import { connect } from 'react-redux' +import { withRouter } from 'react-router-dom' +import { compose } from 'recompose' +import WalletView from './wallet-view.component' +import {showSendPage, hideSidebar, setSelectedToken, showAddTokenPage} from '../../../store/actions' +import * as selectors from '../../../selectors/selectors' + +function mapStateToProps (state) { + return { + network: state.metamask.network, + sidebarOpen: state.appState.sidebar.isOpen, + identities: state.metamask.identities, + accounts: selectors.getMetaMaskAccounts(state), + keyrings: state.metamask.keyrings, + selectedAddress: selectors.getSelectedAddress(state), + selectedAccount: selectors.getSelectedAccount(state), + selectedTokenAddress: state.metamask.selectedTokenAddress, + } +} + +function mapDispatchToProps (dispatch) { + return { + showSendPage: () => dispatch(showSendPage()), + hideSidebar: () => dispatch(hideSidebar()), + unsetSelectedToken: () => dispatch(setSelectedToken()), + showAddTokenPage: () => dispatch(showAddTokenPage()), + } +} + +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(WalletView) From f5c496ffcd834549087b71565fa5e9ebbb095674 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 10:01:44 -0330 Subject: [PATCH 60/88] Convert Menu, Item, Divider, and CloseArea components to use JSX (#7547) --- .../app/dropdowns/components/menu.js | 94 ++++++++++++------- .../app/dropdowns/tests/menu.test.js | 4 +- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/ui/app/components/app/dropdowns/components/menu.js b/ui/app/components/app/dropdowns/components/menu.js index 950ccccb7721..9bb919c6d082 100644 --- a/ui/app/components/app/dropdowns/components/menu.js +++ b/ui/app/components/app/dropdowns/components/menu.js @@ -1,61 +1,87 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React from 'react' +import classnames from 'classnames' -inherits(Menu, Component) -function Menu () { - Component.call(this) +/** + * Menu component + * @return {Component|null} + */ +function Menu (props) { + const { className, children, isShowing } = props + return isShowing + ?
    {children}
    + : null } -Menu.prototype.render = function () { - const { className = '', children, isShowing } = this.props - return isShowing - ? h('div', { className: `menu ${className}` }, children) - : h('noscript') +Menu.defaultProps = { + className: '', + isShowing: false, + children: null, } -inherits(Item, Component) -function Item () { - Component.call(this) +Menu.propTypes = { + className: PropTypes.string, + children: PropTypes.node, + isShowing: PropTypes.bool, } -Item.prototype.render = function () { +function Item (props) { const { icon, children, text, subText, - className = '', + className, onClick, - } = this.props - const itemClassName = `menu__item ${className} ${onClick ? 'menu__item--clickable' : ''}` - const iconComponent = icon ? h('div.menu__item__icon', [icon]) : null - const textComponent = text ? h('div.menu__item__text', text) : null - const subTextComponent = subText ? h('div.menu__item__subtext', subText) : null + } = props + + const itemClassName = classnames('menu__item', className, { + 'menu__item--clickable': Boolean(onClick), + }) + const iconComponent = icon ?
    {icon}
    : null + const textComponent = text ?
    {text}
    : null + const subTextComponent = subText ?
    {subText}
    : null return children - ? h('div', { className: itemClassName, onClick }, children) - : h('div.menu__item', { className: itemClassName, onClick }, [ iconComponent, textComponent, subTextComponent ] - .filter(d => Boolean(d)) + ?
    {children}
    + : ( +
    + {[ iconComponent, textComponent, subTextComponent ].filter(d => Boolean(d))} +
    ) } -inherits(Divider, Component) -function Divider () { - Component.call(this) +Item.defaultProps = { + children: null, + icon: null, + text: null, + subText: null, + className: '', + onClick: null, } -Divider.prototype.render = function () { - return h('div.menu__divider') +Item.propTypes = { + icon: PropTypes.node, + children: PropTypes.node, + text: PropTypes.node, + subText: PropTypes.node, + className: PropTypes.string, + onClick: PropTypes.func, +} + +function Divider () { + return
    } -inherits(CloseArea, Component) -function CloseArea () { - Component.call(this) +function CloseArea ({ onClick }) { + return
    } -CloseArea.prototype.render = function () { - return h('div.menu__close-area', { onClick: this.props.onClick }) +CloseArea.propTypes = { + onClick: PropTypes.func.isRequired, } module.exports = { Menu, Item, Divider, CloseArea } diff --git a/ui/app/components/app/dropdowns/tests/menu.test.js b/ui/app/components/app/dropdowns/tests/menu.test.js index 6413c0c2c76e..56cec93a3cf7 100644 --- a/ui/app/components/app/dropdowns/tests/menu.test.js +++ b/ui/app/components/app/dropdowns/tests/menu.test.js @@ -31,14 +31,14 @@ describe('Dropdown Menu Components', () => { ) }) it('add className based on props', () => { - assert.equal(wrapper.find('.menu__item').prop('className'), 'menu__item menu__item test className menu__item--clickable') + assert.equal(wrapper.find('.menu__item').prop('className'), 'menu__item test foo1 menu__item--clickable') }) it('simulates onClick called', () => { From 1501742d68888ae6a1dc3de1a98794f061110716 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 10:02:09 -0330 Subject: [PATCH 61/88] Convert dev scripts to use JSX (#7555) --- development/mock-dev.js | 60 +++++++++++++++--------------- development/selector.js | 81 ++++++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 68 deletions(-) diff --git a/development/mock-dev.js b/development/mock-dev.js index 8da625149382..cbb4368907a8 100644 --- a/development/mock-dev.js +++ b/development/mock-dev.js @@ -10,13 +10,13 @@ * without having to re-open the plugin or even re-build it. */ +import React from 'react' const render = require('react-dom').render -const h = require('react-hyperscript') const Root = require('../ui/app/pages') const configureStore = require('../ui/app/store/store') const actions = require('../ui/app/store/actions') const backGroundConnectionModifiers = require('./backGroundConnectionModifiers') -const Selector = require('./selector') +import Selector from './selector' const MetamaskController = require('../app/scripts/metamask-controller') const firstTimeState = require('../app/scripts/first-time-state') const ExtensionPlatform = require('../app/scripts/platforms/extension') @@ -106,40 +106,38 @@ function startApp () { body.appendChild(container) render( - h('.super-dev-container', [ - - h('button', { - onClick: (ev) => { +
    + + +
    + +
    +
    , + container, + ) } diff --git a/development/selector.js b/development/selector.js index 2673d0fe3c30..01011c710708 100644 --- a/development/selector.js +++ b/development/selector.js @@ -1,42 +1,49 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits +import PropTypes from 'prop-types' +import React, {Component} from 'react' -module.exports = NewComponent +export default class Selector extends Component { + state = {} -inherits(NewComponent, Component) -function NewComponent () { - Component.call(this) -} - -NewComponent.prototype.render = function () { - const props = this.props - const { - states, - selectedKey, - actions, - store, - modifyBackgroundConnection, - backGroundConnectionModifiers, - } = props + render () { + const { + states, + selectedKey, + actions, + store, + modifyBackgroundConnection, + backGroundConnectionModifiers, + } = this.props + const selected = this.state.selected || selectedKey - const state = this.state || {} - const selected = state.selected || selectedKey - - return h('select', { - style: { - margin: '20px 20px 0px', - }, - value: selected, - onChange: (event) => { - const selectedKey = event.target.value - const backgroundConnectionModifier = backGroundConnectionModifiers[selectedKey] - modifyBackgroundConnection(backgroundConnectionModifier || {}) - store.dispatch(actions.update(selectedKey)) - this.setState({ selected: selectedKey }) - }, - }, Object.keys(states).map((stateName) => { - return h('option', { value: stateName }, stateName) - })) + return ( + + ) + } +} +Selector.propTypes = { + states: PropTypes.object.isRequired, + selectedKey: PropTypes.string.isRequired, + actions: PropTypes.object.isRequired, + store: PropTypes.object.isRequired, + modifyBackgroundConnection: PropTypes.func.isRequired, + backGroundConnectionModifiers: PropTypes.object.isRequired, } From 5f899886712660393e5692bba17fb6ca70325ab3 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 10:02:28 -0330 Subject: [PATCH 62/88] Delete unused BnAsDecimalInput (#7556) --- app/_locales/am/messages.json | 12 -- app/_locales/ar/messages.json | 12 -- app/_locales/bg/messages.json | 12 -- app/_locales/bn/messages.json | 12 -- app/_locales/ca/messages.json | 12 -- app/_locales/cs/messages.json | 12 -- app/_locales/da/messages.json | 12 -- app/_locales/de/messages.json | 12 -- app/_locales/el/messages.json | 12 -- app/_locales/en/messages.json | 12 -- app/_locales/es/messages.json | 12 -- app/_locales/es_419/messages.json | 12 -- app/_locales/et/messages.json | 12 -- app/_locales/fa/messages.json | 12 -- app/_locales/fi/messages.json | 12 -- app/_locales/fil/messages.json | 12 -- app/_locales/fr/messages.json | 12 -- app/_locales/he/messages.json | 12 -- app/_locales/hi/messages.json | 12 -- app/_locales/hn/messages.json | 12 -- app/_locales/hr/messages.json | 12 -- app/_locales/ht/messages.json | 12 -- app/_locales/hu/messages.json | 12 -- app/_locales/id/messages.json | 12 -- app/_locales/it/messages.json | 12 -- app/_locales/ja/messages.json | 12 -- app/_locales/kn/messages.json | 12 -- app/_locales/ko/messages.json | 12 -- app/_locales/lt/messages.json | 12 -- app/_locales/lv/messages.json | 12 -- app/_locales/ms/messages.json | 12 -- app/_locales/nl/messages.json | 12 -- app/_locales/no/messages.json | 12 -- app/_locales/ph/messages.json | 12 -- app/_locales/pl/messages.json | 12 -- app/_locales/pt/messages.json | 12 -- app/_locales/pt_BR/messages.json | 12 -- app/_locales/ro/messages.json | 12 -- app/_locales/ru/messages.json | 12 -- app/_locales/sk/messages.json | 12 -- app/_locales/sl/messages.json | 12 -- app/_locales/sr/messages.json | 12 -- app/_locales/sv/messages.json | 12 -- app/_locales/sw/messages.json | 12 -- app/_locales/ta/messages.json | 12 -- app/_locales/th/messages.json | 12 -- app/_locales/tr/messages.json | 8 - app/_locales/uk/messages.json | 12 -- app/_locales/vi/messages.json | 12 -- app/_locales/zh_CN/messages.json | 12 -- app/_locales/zh_TW/messages.json | 12 -- ui/app/components/app/bn-as-decimal-input.js | 188 ------------------- 52 files changed, 796 deletions(-) delete mode 100644 ui/app/components/app/bn-as-decimal-input.js diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 8b8c70ead233..70da475f4dff 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "መሠረታዊ" }, - "betweenMinAndMax": { - "message": "ከ$1መብለጥ ወይም እኩል እና ከ$2በታች ወይም እኩል መሆን አለበት።", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "ኤክስፕሎረር አግድ" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "አስጀማሪ መመሪያ" }, - "greaterThanMin": { - "message": "ከ $1ጋር እኩል መሆን ወይም መብለጥ አለበት።", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "እርስዎን በማየታችን ደስተኛ ነን።" }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "አዲስ መለያ ከማከልዎ በፊት የመጨረሻውን መለያዎን መጠቀም አለብዎት።" }, - "lessThanMax": { - "message": "ከ $1ያነሰ ወይም እኩል መሆን አለበት።", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "አዎ፣ እናደራጅ!" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index 1bee5df313ee..f9bceb60de6b 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "الأساسية" }, - "betweenMinAndMax": { - "message": "يجب أن تكون أكبر من أو تساوي $1 وأقل من أو تساوي $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "متصفح Block Explorer" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "البدء" }, - "greaterThanMin": { - "message": "يجب أن يكون أكبر من أو يساوي $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "نحن سعداء برؤيتك." }, @@ -655,10 +647,6 @@ "ledgerAccountRestriction": { "message": "أنت بحاجة إلى استخدام حسابك الأخير قبل أن تتمكن من إضافة حساب جديد." }, - "lessThanMax": { - "message": "يجب أن يكون أقل من أو يساوي $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "نعم، دعنا نبدأ التثبيت!" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index fac03f1c0b2f..c029ceb4bfda 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Основни" }, - "betweenMinAndMax": { - "message": "трябва да бъде по-голям или равен на $1 и по-малък или равен на $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Блокиране на Explorer" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "Първи стъпки" }, - "greaterThanMin": { - "message": "трябва да бъде по-голяма или равна на $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Радваме се да Ви видим." }, @@ -658,10 +650,6 @@ "ledgerAccountRestriction": { "message": "Трябва да използвате последния си акаунт, преди да можете да добавите нов." }, - "lessThanMax": { - "message": "трябва да бъде по-малко или равно на $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Да, нека да настроим нещата!" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index 79fd24a3ccfc..ee20241156f2 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "প্রাথমিক" }, - "betweenMinAndMax": { - "message": "অবশ্যই $1 এর বড় বা সমান এবং $2 এর ছোটো বা সমান হতে হবে।", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "এক্সপ্লোরার ব্লক করুন" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "শুরু করুন" }, - "greaterThanMin": { - "message": "অবশ্যই $1 এর থেকে বড় বা সমান হতে হবে।", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "আপনাকে দেখে আমরা আনন্দিত।" }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "একটি নতুন অ্যা কাউন্ট যোগ করার আগে আপনাকে আপনার শেষ অ্যাকাউন্ট ব্যবহার করে ফেলতে হবে।" }, - "lessThanMax": { - "message": "অবশ্যই $1 এর থেকে কম বা সমান হতে হবে।", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "হ্যাঁ, তাহলে সেট আপ করে নেওয়া যাক!" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 42af089d4810..7b8bdf8968ef 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Opcions bàsiques" }, - "betweenMinAndMax": { - "message": "ha de ser igual o superior a $1 i menor o igual a $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Bloqueja l'explorador" }, @@ -530,10 +526,6 @@ "getStarted": { "message": "Comença" }, - "greaterThanMin": { - "message": "ha de ser major o igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Ens alegrem de veure't." }, @@ -646,10 +638,6 @@ "ledgerAccountRestriction": { "message": "Has de fer servir el teu últim compte abans de poder afegir-ne un altre." }, - "lessThanMax": { - "message": "ha de ser igual o menor a $1 .", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Sí, posem-nos en marxa!" }, diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index 95c45c98b0b0..72c4a7bce660 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -58,10 +58,6 @@ "balanceIsInsufficientGas": { "message": "Nedostatek prostředků pro aktuální množství paliva" }, - "betweenMinAndMax": { - "message": "musí být větší nebo roven $1 a menší nebo roven $2.", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Použít Blockies Identicon" }, @@ -224,10 +220,6 @@ "message": "Získejte Ether z faucetu za $1.", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": "musí být větší nebo roven $1.", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "zde", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -282,10 +274,6 @@ "learnMore": { "message": "Zjistěte více." }, - "lessThanMax": { - "message": "musí být menší nebo roven $1.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "Chcete přidat tyto tokeny?" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 627e6222c22a..9d68e86cfe33 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Grundlæggende oplysninger" }, - "betweenMinAndMax": { - "message": "skal være større end eller lig med $1 og mindre end eller lig med $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Block-udforsker" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "Kom godt i gang" }, - "greaterThanMin": { - "message": "skal være større end eller lig med $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Vi er glade for at se dig." }, @@ -655,10 +647,6 @@ "ledgerAccountRestriction": { "message": "Du skal benytte din tidligere konto, før du kan tilføje en ny." }, - "lessThanMax": { - "message": "skal være mindre end eller lig med $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ja, lad os komme i gang!" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 6f8a4f6118b6..1f7409ee2dc6 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -154,10 +154,6 @@ "basic": { "message": "Grundlegend" }, - "betweenMinAndMax": { - "message": "Muss größer oder gleich $1 und kleiner oder gleich $2 sein.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Block-Explorer" }, @@ -525,10 +521,6 @@ "getStarted": { "message": "Erste Schritte" }, - "greaterThanMin": { - "message": "Muss größer oder gleich $1 sein.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Wir freuen uns, Sie zu sehen." }, @@ -644,10 +636,6 @@ "ledgerAccountRestriction": { "message": "Sie müssen Ihr letztes Konto verwenden, ehe Sie ein neues hinzufügen können." }, - "lessThanMax": { - "message": "Muss kleiner oder gleich $1 sein.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ja, legen wir los!" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index b2dca5cfae5f..44fa55db0622 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Βασικά" }, - "betweenMinAndMax": { - "message": "πρέπει να είναι μεγαλύτερο ή ίσο με $1 και μικρότερο ή ίσο με $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Εξερευνητής Μπλοκ" }, @@ -537,10 +533,6 @@ "getStarted": { "message": "Έναρξη" }, - "greaterThanMin": { - "message": "πρέπει να είναι μεγαλύτερο ή ίσο με $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Χαιρόμαστε που σας βλέπουμε." }, @@ -659,10 +651,6 @@ "ledgerAccountRestriction": { "message": "Πρέπει να χρησιμοποιήσετε τον τελευταίο σας λογαριασμό πριν προσθέσετε έναν νέο." }, - "lessThanMax": { - "message": "πρέπει να είναι μικρότερο από ή ίσο με $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ναι, ας το εγκαταστήσουμε!" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 57be0891c1cd..f85b64a02f70 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -205,10 +205,6 @@ "basic": { "message": "Basic" }, - "betweenMinAndMax": { - "message": "must be greater than or equal to $1 and less than or equal to $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Block Explorer" }, @@ -625,10 +621,6 @@ "getStarted": { "message": "Get Started" }, - "greaterThanMin": { - "message": "must be greater than or equal to $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "We’re happy to see you." }, @@ -747,10 +739,6 @@ "ledgerAccountRestriction": { "message": "You need to make use your last account before you can add a new one." }, - "lessThanMax": { - "message": "must be less than or equal to $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Yes, let’s get set up!" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index f0ac779345aa..79d508a07b7f 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -145,10 +145,6 @@ "basic": { "message": "Básico" }, - "betweenMinAndMax": { - "message": "Debe ser mayor o igual a $1 y menor o igual a $2", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Usar Blockies Identicon (Iconos)" }, @@ -446,10 +442,6 @@ "getHelp": { "message": "Pedir ayuda." }, - "greaterThanMin": { - "message": "Debe ser mayor o igual a $1", - "description": "helper for inputting hex as decimal input" - }, "hardwareWalletConnected": { "message": "Se ha conectado el monedero físico" }, @@ -550,10 +542,6 @@ "ledgerAccountRestriction": { "message": "Hay que hacer uso de tu última cuenta antes de agregarle una nueva." }, - "lessThanMax": { - "message": "Debe ser menor o igual a $1", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "¿Te gustaría agregar estos tokens?" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 5e7c1282e591..39d45ddaff37 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Básicas" }, - "betweenMinAndMax": { - "message": "debe ser superior o igual a $1 e inferior o igual a $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Bloquear Explorer" }, @@ -534,10 +530,6 @@ "getStarted": { "message": "Comenzar" }, - "greaterThanMin": { - "message": "debe ser superior o igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Estamos encantados de verte." }, @@ -653,10 +645,6 @@ "ledgerAccountRestriction": { "message": "Necesitas utilizar tu cuenta anterior para agregar una nueva." }, - "lessThanMax": { - "message": "debe ser menor o igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "¡Eso, pongámonos en marcha!" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 7ca84547ba1f..63c7ca53e3b5 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Põhiseaded" }, - "betweenMinAndMax": { - "message": "peab olema suurem või võrdne $1 ja väiksem või võrdne $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blokeeri Explorer" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "Alustamine" }, - "greaterThanMin": { - "message": "peab olema $1või suurem.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Meil on hea meel teid näha." }, @@ -655,10 +647,6 @@ "ledgerAccountRestriction": { "message": "Enne uue konto loomist peate kasutama eelmist kontot." }, - "lessThanMax": { - "message": "peab olema $1või väiksem.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Jah, hakkame pihta!" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 0baf9e39d347..1e93ec772d14 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "پایه" }, - "betweenMinAndMax": { - "message": "باید بزرگتر از یا مساوی به 1$1 و کوچکتر یا مساوی به 2$2 باشد.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "بلاک کردن براوزر" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "شروع به کار" }, - "greaterThanMin": { - "message": "باید بزرگتر از یا مساوی به 1$1 باشد.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "از دیدن شما خوشحال هستیم." }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "لازم است تا حساب قبلی تان را قبل از اینکه جدید اضافه کنید، مورد استفاده قرار دهید." }, - "lessThanMax": { - "message": "باید کوچکتر از 1$1 یا مساوی با آن باشد.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "بلی، درست شد!" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index b794c350e18d..e2d8a59c548d 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Perusvaihtoehdot" }, - "betweenMinAndMax": { - "message": "tulee olla vähintään $1 ja korkeintaan $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Lohkonhallinta" }, @@ -537,10 +533,6 @@ "getStarted": { "message": "Aloitusopas" }, - "greaterThanMin": { - "message": "on oltava vähintään $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Meistä on mukava nähdä sinut." }, @@ -659,10 +651,6 @@ "ledgerAccountRestriction": { "message": "Sinun tarvitsee käyttää edellistä tiliäsi ennen kuin voit lisätä uuden." }, - "lessThanMax": { - "message": "tulee olla korkeintaan $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Kyllä, valmistaudutaan!" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index d631cf86e011..2734fecc3262 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -145,10 +145,6 @@ "basic": { "message": "Pangunahin" }, - "betweenMinAndMax": { - "message": "dapat ay mas malaki sa o katumbas ng $1 at mas maliit sa o katumbas ng $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerView": { "message": "Tingnan ang account sa $1", "description": "$1 replaced by URL for custom block explorer" @@ -503,10 +499,6 @@ "getStarted": { "message": "Magsimula" }, - "greaterThanMin": { - "message": "dapat ay mas malaki sa o katumbas ng $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Masaya kaming makita ka." }, @@ -606,10 +598,6 @@ "ledgerAccountRestriction": { "message": "Kailangan mong gamitin ang iyong dating account bago ka makapagdagdag ng bago." }, - "lessThanMax": { - "message": "dapat ay mas mababa sa o katumbas ng $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Oo, i-set up natin ito!" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index dd8f40ad2e85..98925ad696c7 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -154,10 +154,6 @@ "basic": { "message": "Général" }, - "betweenMinAndMax": { - "message": "doit être supérieur ou égal à $1 et inférieur ou égal à $2", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerView": { "message": "Afficher le compte à $1", "description": "$1 replaced by URL for custom block explorer" @@ -528,10 +524,6 @@ "getStarted": { "message": "Démarrer" }, - "greaterThanMin": { - "message": "doit être supérieur ou égal à $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Nous sommes ravis de vous voir." }, @@ -638,10 +630,6 @@ "ledgerAccountRestriction": { "message": "Vous devez d'abord utiliser le dernier compte que vous avez créé avant de pouvoir en créer un autre." }, - "lessThanMax": { - "message": "doit être inférieur ou égal à $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Oui, passons à la configuration !" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 70c0d116c3ba..9c9966edcfe9 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "בסיסי" }, - "betweenMinAndMax": { - "message": "חייב להיות גדול או שווה ל-$1 ופחות או שווה ל-$2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "סייר בלוקים" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "תחילת העבודה" }, - "greaterThanMin": { - "message": "חייב להיות גדול או שווה ל-$1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "אנו שמחים לראותך." }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "עליך להשתמש בחשבון האחרון שלך לפני שתוכל/י להוסיף חשבון חדש." }, - "lessThanMax": { - "message": "חייב להיות פחות או שווה ל- $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "כן, בוא נתקין!" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 82681dd4af25..25e8014ffae9 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "मूलभूत" }, - "betweenMinAndMax": { - "message": "$1 से अधिक या बराबर होना चाहिए और $2 के बराबर या उससे कम होना चाहिए।", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "एक्सप्लोरर को ब्लॉक करें" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "आरंभ करें" }, - "greaterThanMin": { - "message": "$1 से बड़ा या उसके बराबर होना चाहिए।", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "आपको देखकर हमें बहुत ख़ुशी हुई।" }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "नया खाता जोड़ने से पहले आपको अपने पिछले खाते का उपयोग करना होगा।" }, - "lessThanMax": { - "message": "$1 से कम या उसके बराबर होना चाहिए।", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "जी हां, सेट होने दें!" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index e7a954b6a8ff..e15b244ca055 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -55,10 +55,6 @@ "balanceIsInsufficientGas": { "message": "वर्तमान गैस कुल के लिए अपर्याप्त शेष" }, - "betweenMinAndMax": { - "message": "$1 के बराबर या ज्यदा या, $2 के बराबर या कम होना चाहिए।", - "description": "हेक्स इनपुट के लिए दशमलव इनपुट के रूप में सहायक" - }, "blockiesIdenticon": { "message": "ब्लॉकीज पहचान का उपयोग करें" }, @@ -200,10 +196,6 @@ "message": "$1 के लिए एक नल से ईथर प्राप्त करें", "description": "ईथर नल के लिए नेटवर्क नाम प्रदर्शित करता है" }, - "greaterThanMin": { - "message": "$1 के बराबर या बराबर होना चाहिए।", - "description": "हेक्स इनपुट के लिए दशमलव इनपुट के रूप में सहायक" - }, "here": { "message": "यहां", "description": "अधिक जानकारी के लिए यहां क्लिक करें- (परेशानी के साथ जाता है टोकनबैलेंस) (troubleTokenBalances)" @@ -262,10 +254,6 @@ "kovan": { "message": "कोवान टेस्ट नेटवर्क" }, - "lessThanMax": { - "message": "$1 से कम या बराबर होना चाहिए।", - "description": "हेक्स इनपुट के लिए दशमलव इनपुट के रूप में सहायक" - }, "likeToAddTokens": { "message": "क्या आप इन टोकनों को जोड़ना चाहते हैं?" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 0c8b878b270d..318713b7d0f2 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Osnovne" }, - "betweenMinAndMax": { - "message": "mora biti veće od $1 ili jednako te manje od $2 ili jednako.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blokiraj Explorer" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "Početak upotrebe" }, - "greaterThanMin": { - "message": "mora biti veće od $1 ili jednako.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Sretni smo što ste tu." }, @@ -658,10 +650,6 @@ "ledgerAccountRestriction": { "message": "Treba se koristiti zadnjim računom kako biste dodali novi račun." }, - "lessThanMax": { - "message": "mora biti manje od $1 ili jednako.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Da, obavimo postavljanje!" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index f94a29f7291e..d3a9dd4bab73 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -79,10 +79,6 @@ "balanceIsInsufficientGas": { "message": "Ensifizan balans pou total gaz aktyèl la" }, - "betweenMinAndMax": { - "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Itilize Blockies Identicon" }, @@ -302,10 +298,6 @@ "getHelp": { "message": "Jwenn èd." }, - "greaterThanMin": { - "message": "dwe pi gran pase oswa egal a $ 1.", - "description": "helper for inputting hex as decimal input" - }, "hardware": { "message": "materyèl" }, @@ -400,10 +392,6 @@ "ledgerAccountRestriction": { "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo." }, - "lessThanMax": { - "message": "dwe mwens pase oswa egal a $ 1.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "Èske ou ta renmen ajoute sa nan tokens?" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index ba33a070575e..870972e5bcb3 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Alapvető" }, - "betweenMinAndMax": { - "message": "legyen nagyobb vagy egyenlő mint $1 és kisebb vagy egyenlő mint $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Explorer blokkolása" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "Első lépések" }, - "greaterThanMin": { - "message": "legyen nagyobb vagy egyenlő mint $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Örülünk, hogy itt van. " }, @@ -658,10 +650,6 @@ "ledgerAccountRestriction": { "message": "Használnia kell a korábbi fiókját, mielőtt újat adhat hozzá. " }, - "lessThanMax": { - "message": "egyenlő vagy kevesebb kell legyen mint $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Igen, hozzuk létre!" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 6c5e2d8da842..42d8472892c1 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Dasar" }, - "betweenMinAndMax": { - "message": "harus lebih dari atau sama dengan $1 dan kurang dari atau sama dengan $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blokir Penjelajah" }, @@ -527,10 +523,6 @@ "getStarted": { "message": "Mulai" }, - "greaterThanMin": { - "message": "harus lebih besar atau sama dengan $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Kami senang bertemu dengan Anda." }, @@ -649,10 +641,6 @@ "ledgerAccountRestriction": { "message": "Anda perlu menggunakan akun terakhir sebelum dapat menambahkan akun baru." }, - "lessThanMax": { - "message": "harus kurang dari atau setara $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ya, ayo tata!" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 36666d21b01a..83b63785905a 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -151,10 +151,6 @@ "basic": { "message": "Base" }, - "betweenMinAndMax": { - "message": "deve essere maggiore o uguale a $1 e minore o uguale a $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerView": { "message": "Visualizza account su $1", "description": "$1 replaced by URL for custom block explorer" @@ -519,10 +515,6 @@ "getStarted": { "message": "Inizia" }, - "greaterThanMin": { - "message": "deve essere maggiore o uguale a $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Siamo contenti di vederti." }, @@ -638,10 +630,6 @@ "ledgerAccountRestriction": { "message": "E' necessario utilizzare l'ultimo account prima di poterne aggiungere uno nuovo." }, - "lessThanMax": { - "message": "deve essere minore o uguale a $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Si, iniziamo!" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 1205038562a4..4967db8a6604 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -136,10 +136,6 @@ "balanceIsInsufficientGas": { "message": "現在のガス総量に対して残高が不足しています" }, - "betweenMinAndMax": { - "message": " $1以上 $2以下にして下さい。", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Blockies Identicon を使用" }, @@ -275,10 +271,6 @@ "message": "フォーセットで $1のEtherを得ることができます。", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": " $1以上にして下さい。", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "ここ", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -331,10 +323,6 @@ "learnMore": { "message": "詳細" }, - "lessThanMax": { - "message": " $1以下にして下さい。", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "トークンを追加しますか?" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 86ffad3b3480..480abe20d3b1 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "ಮೂಲ" }, - "betweenMinAndMax": { - "message": " $1 ಗಿಂತಲೂ ಹೆಚ್ಚಾಗಿರಬೇಕು ಅಥವಾ ಸಮನಾಗಿರಬೇಕು ಮತ್ತು $2 ಗಿಂತಲೂ ಕಡಿಮೆ ಇರಬೇಕು ಅಥವಾ ಸಮನಾಗಿರಬೇಕು.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "ಅನ್ವೇಷಕವನ್ನು ನಿರ್ಬಂಧಿಸಿ" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "ಪ್ರಾರಂಭಗೊಂಡಿದೆ" }, - "greaterThanMin": { - "message": " $1 ಗಿಂತಲೂ ಹೆಚ್ಚಾಗಿರಬೇಕು ಅಥವಾ ಸಮನಾಗಿರಬೇಕು.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "ನಿಮ್ಮನ್ನು ನೋಡಿ ನಮಗೆ ಸಂತೋಷವಾಗಿದೆ." }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "ನೀವು ಹೊಸದನ್ನು ಸೇರಿಸುವುದರ ಮೊದಲು ನಿಮ್ಮ ಹಿಂದಿನ ಖಾತೆಯನ್ನು ನೀವು ಬಳಸಬೇಕು." }, - "lessThanMax": { - "message": "$1 ಗಿಂತ ಕಡಿಮೆ ಅಥವಾ ಸಮನಾಗಿರಬೇಕು.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "ಹೌದು, ಹೊಂದಿಸೋಣ!" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 4cf4699d1a72..47af1dbffef2 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -154,10 +154,6 @@ "balanceIsInsufficientGas": { "message": "현재 가스 총합에 대해 잔액이 부족합니다" }, - "betweenMinAndMax": { - "message": "$1 이상 $2 이하여야 합니다.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "익스플로러 차단" }, @@ -537,10 +533,6 @@ "getStarted": { "message": "시작하기" }, - "greaterThanMin": { - "message": "$1 이상이어야 합니다.", - "description": "helper for inputting hex as decimal input" - }, "hardware": { "message": "하드웨어" }, @@ -656,10 +648,6 @@ "ledgerAccountRestriction": { "message": "새 계정을 추가하려면 최소 마지막 계정을 사용해야 합니다." }, - "lessThanMax": { - "message": "$1 이하여야합니다.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "네, 설정해볼게요!" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 2862daa98ce1..51113ffe482d 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Bendrieji" }, - "betweenMinAndMax": { - "message": "turi būti ne mažiau kaip $1 ir ne daugiau kaip $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blokuoti naršyklę" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "Darbo pradžia" }, - "greaterThanMin": { - "message": "turi būti daugiau arba lygu $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Džiaugiamės jus matydami." }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "Prieš įtraukdami naują, turite pasinaudoti paskutine paskyra." }, - "lessThanMax": { - "message": "turi būti mažiau arba lygu $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Taip, pradėkime!" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 13b5f56a9a75..db678240b06c 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Pamata" }, - "betweenMinAndMax": { - "message": "jābūt lielākai par vai vienādai ar $1 un mazākai par vai vienādai ar $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Bloķēt Explorer" }, @@ -536,10 +532,6 @@ "getStarted": { "message": "Sākt darbu" }, - "greaterThanMin": { - "message": "jābūt lielākam par vai vienādam ar $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Priecājamies jūs redzēt!" }, @@ -658,10 +650,6 @@ "ledgerAccountRestriction": { "message": "Jums jāizmanto pēdējais konts pirms varat pievienot jaunu." }, - "lessThanMax": { - "message": "jābūt mazākam par vai vienādam ar $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Jā, sāksim iestatīšanu!" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index abcf699e3e15..ed1daeb3d177 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Asas" }, - "betweenMinAndMax": { - "message": "mestilah lebih besar atau sama dengan $1 dan kurang atau sama dengan $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Sekat Explorer" }, @@ -524,10 +520,6 @@ "getStarted": { "message": "Bermula" }, - "greaterThanMin": { - "message": "mestilah melebihi atau bersamaan dengan $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Kami gembira bertemu anda." }, @@ -642,10 +634,6 @@ "ledgerAccountRestriction": { "message": "Anda perlu menggunakan akaun terakhir anda sebelum anda boleh menambah yang baru." }, - "lessThanMax": { - "message": "mestilah kurang atau bersamaan dengan $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ya, mari sediakannya!" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index 82cabe99661e..b026ec93a809 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -52,10 +52,6 @@ "balanceIsInsufficientGas": { "message": "Onvoldoende saldo voor huidig ​​gastotaal" }, - "betweenMinAndMax": { - "message": "moet groter zijn dan of gelijk zijn aan $1 en kleiner dan of gelijk aan $2.", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Gebruik Blockies Identicon" }, @@ -194,10 +190,6 @@ "message": "Haal Ether uit een kraan voor de $1", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": "moet groter zijn dan of gelijk zijn aan $1.", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "hier", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -256,10 +248,6 @@ "kovan": { "message": "Kovan-testnetwerk" }, - "lessThanMax": { - "message": "moet kleiner zijn dan of gelijk zijn aan $1.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "Wil je deze tokens toevoegen?" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 437e1a4c42e8..1f936842168a 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Enkle" }, - "betweenMinAndMax": { - "message": "må være større enn eller det samme som $1 og mindre enn eller det samme som $2. ", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blokkér Explorer" }, @@ -533,10 +529,6 @@ "getStarted": { "message": "Kom i gang" }, - "greaterThanMin": { - "message": "Må være mer enn eller tilsvarende $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Vi er glade for å se deg " }, @@ -652,10 +644,6 @@ "ledgerAccountRestriction": { "message": "Du må bruke den siste kontoen din før du kan legge til en ny." }, - "lessThanMax": { - "message": "Må være mindre eller likt som $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ja, la oss komme i gang!" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 1eaa38ef390e..6b66773f68fd 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -46,10 +46,6 @@ "balanceIsInsufficientGas": { "message": "Kulang ang balanse para sa kasalukuyang gas total" }, - "betweenMinAndMax": { - "message": "dapat mas malaki o katumbas ng $1 at mas mababa o katumbas ng $2.", - "description": "helper para sa pag-input ng hex bilang decimal input" - }, "buyCoinSwitch": { "message": "Bumili sa CoinSwitch" }, @@ -164,10 +160,6 @@ "message": "Kumuha ng Ether mula sa faucet para sa $1", "description": "Ipinapakita ang pangalan ng network para sa Ether faucet" }, - "greaterThanMin": { - "message": "dapat mas malaki o katumbas ng $1.", - "description": "helper para sa pag-input ng hex bilang decimal input" - }, "here": { "message": "i-click ito", "description": "tulad ng -i-click dito- para sa mas maraming impormasyon (kasama ng troubleTokenBalances)" @@ -201,10 +193,6 @@ "invalidInput": { "message": "Invalid ang input." }, - "lessThanMax": { - "message": "dapat mas mababa o katumbas ng $1.", - "description": "helper para sa pag-input ng hex bilang decimal input" - }, "loading": { "message": "Naglo-load..." }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index c49570571a85..ea9bac563d6e 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Podstawy" }, - "betweenMinAndMax": { - "message": "musi być większe lub równe $1 i mniejsze lub równe $2,", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Przeglądaj blok" }, @@ -537,10 +533,6 @@ "getStarted": { "message": "Rozpocznij" }, - "greaterThanMin": { - "message": "musi być większe lub równe $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Cieszymy się, że tu jesteś." }, @@ -659,10 +651,6 @@ "ledgerAccountRestriction": { "message": "Musisz użyć swojego poprzedniego konta zanim dodasz kolejne." }, - "lessThanMax": { - "message": "musi być mniejsze lub równe $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Tak, zacznijmy od początku!" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 40365ad337e5..0c8949603043 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -55,10 +55,6 @@ "balanceIsInsufficientGas": { "message": "Saldo insuficiente para a quantidade de gas total" }, - "betweenMinAndMax": { - "message": "tem de ser maior ou igual a $1 e menor ou igual a $2.", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Usar Blockies Identicon" }, @@ -200,10 +196,6 @@ "message": "Obter Ether de um faucet por $1", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": "tem de ser maior ou igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "aqui", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -262,10 +254,6 @@ "kovan": { "message": "Rede de Teste Kovan" }, - "lessThanMax": { - "message": "tem de ser menor ou igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "Gostaria de adicionar estes tokens?" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 5d43cab5d205..6f496b57c147 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Básicas" }, - "betweenMinAndMax": { - "message": "deve ser maior ou igual a $1 e menor ou igual a $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerView": { "message": "Ver conta em $1", "description": "$1 replaced by URL for custom block explorer" @@ -534,10 +530,6 @@ "getStarted": { "message": "Primeiros passos" }, - "greaterThanMin": { - "message": "deve ser maior ou igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Estamos felizes em vê-lo." }, @@ -656,10 +648,6 @@ "ledgerAccountRestriction": { "message": "Você precisa usar sua última conta antes de adicionar uma nova." }, - "lessThanMax": { - "message": "deve ser inferior ou igual a $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Sim, vamos configurar!" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 4cbd0faa8c2d..a5fe91697ef5 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "De bază" }, - "betweenMinAndMax": { - "message": "trebuie să fie mai mare sau egal cu $1 și mai mic sau egal cu $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Explorator blocuri" }, @@ -533,10 +529,6 @@ "getStarted": { "message": "Începe" }, - "greaterThanMin": { - "message": "trebuie să fie mai mare sau egal cu $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Ne pare bine să vă vedem." }, @@ -652,10 +644,6 @@ "ledgerAccountRestriction": { "message": "Trebuie să folosiți ultimul cont înainte să adăugați altul." }, - "lessThanMax": { - "message": "trebuie să fie mai mic sau egal cu $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Da, hai să configurăm!" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 82245dd0eeb0..ac6aa65e27bf 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -58,10 +58,6 @@ "balanceIsInsufficientGas": { "message": "Недостаточный баланс для текущего объема газа" }, - "betweenMinAndMax": { - "message": "должно быть больше или равно $1 и меньше или равно $2.", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Использовать Blockies Identicon" }, @@ -227,10 +223,6 @@ "message": "Получить Ether из крана для $1", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": "должно быть больше или равно $1.", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "тут", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -295,10 +287,6 @@ "learnMore": { "message": "Узнать больше." }, - "lessThanMax": { - "message": "должно быть меньше или равно $1.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "Вы хотите добавить эти токены?" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 903b2d7c7b63..2de10f9abfad 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -154,10 +154,6 @@ "basic": { "message": "Základné" }, - "betweenMinAndMax": { - "message": "musí být větší nebo roven $1 a menší nebo roven $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerView": { "message": "Zobraziť účet na $1", "description": "$1 replaced by URL for custom block explorer" @@ -531,10 +527,6 @@ "getStarted": { "message": "Začať" }, - "greaterThanMin": { - "message": "musí být větší nebo roven $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Sme radi, že vás vidíme." }, @@ -640,10 +632,6 @@ "ledgerAccountRestriction": { "message": "Skôr ako budete môcť pridať nový účet, musíte použiť svoj posledný účet." }, - "lessThanMax": { - "message": "musí být menší nebo roven $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Áno, poďme to nastaviť!" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 84d46bab25c1..1e1884a26cb7 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Osnovno" }, - "betweenMinAndMax": { - "message": "mora biti večji ali enak $1 in manjši ali enak $1.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blokiraj Explorer" }, @@ -534,10 +530,6 @@ "getStarted": { "message": "Začnite" }, - "greaterThanMin": { - "message": "mora biti večji ali enak $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Veseli nas, da ste nas spet obiskali." }, @@ -650,10 +642,6 @@ "ledgerAccountRestriction": { "message": "Za dodajanje novega računa morate uporabiti zadnji račun." }, - "lessThanMax": { - "message": "mora biti manjši ali enak $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Lotimo se nastavitev!" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 67c7980aef32..58d31c183e76 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Основна" }, - "betweenMinAndMax": { - "message": "mora biti veće od ili jednako $1 i manje od ili jednako $2", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blok istraživač" }, @@ -537,10 +533,6 @@ "getStarted": { "message": "Започнимо" }, - "greaterThanMin": { - "message": "mora biti veći od ili jednak $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Drago nam je da vas vidimo." }, @@ -659,10 +651,6 @@ "ledgerAccountRestriction": { "message": "Treba da koristite svoj poslednji nalog pre nego što budete mogli da dodate novi." }, - "lessThanMax": { - "message": "mora biti manje od ili jednako $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Da, hajde da sve podesimo!" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index b15c3369e69e..e808703f1807 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Grunder" }, - "betweenMinAndMax": { - "message": "måste vara större än/lika med $1, eller mindre än/lika med $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Blockera Utforskaren" }, @@ -530,10 +526,6 @@ "getStarted": { "message": "Komma igång" }, - "greaterThanMin": { - "message": "måste vara större än eller lika med $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Vi är glada att se dig." }, @@ -652,10 +644,6 @@ "ledgerAccountRestriction": { "message": "Du måste använda ditt senaste konto innan du kan lägga till ett nytt." }, - "lessThanMax": { - "message": "måste vara mindre än eller lika med $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ja, kör igång!" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index fda4cb20524b..ad58787339dd 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Msingi" }, - "betweenMinAndMax": { - "message": "inapaswa kuwa kubwa kuliko au sawa na $1 na ndogo kuliko au sawa na $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerView": { "message": "Tazama akaunti kwenye $1", "description": "$1 replaced by URL for custom block explorer" @@ -530,10 +526,6 @@ "getStarted": { "message": "Anza" }, - "greaterThanMin": { - "message": "inapaswa iwe kubwa kuliko au sawa na $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Tuna furaha kukuona" }, @@ -646,10 +638,6 @@ "ledgerAccountRestriction": { "message": "Unapaswa kutumia akaunti yako ya mwisho kabla hujaongeza mpya." }, - "lessThanMax": { - "message": "inapaswa kuwa ndogo kuliko au sawa na $1. ", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Ndiyo, hebu tuweke mipangilio!" }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index 8cf8db165b6f..ba173def5dd0 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -58,10 +58,6 @@ "balanceIsInsufficientGas": { "message": "நடப்பு வாயு மொத்தம் போதுமான சமநிலை" }, - "betweenMinAndMax": { - "message": "$ 1 க்கும் அதிகமாகவும் அல்லது $ 2 க்கு சமமாகவும் இருக்க வேண்டும்.", - "description": "ஹெக்ஸ் உள்ளீடு தசம உள்ளீடு என உதவி" - }, "blockiesIdenticon": { "message": "ப்ளாக்கிஸ் ஐடென்டிகோன் பயன்பாட்டு" }, @@ -221,10 +217,6 @@ "message": "$ 1 க்கு ஒரு குழாய் இருந்து ஈதர் கிடைக்கும்$1", "description": "ஈத்தர் குழாய் ஐந்து பிணைய பெயர் காட்டுகிறது" }, - "greaterThanMin": { - "message": "$ 1 க்கும் அதிகமாகவோ அல்லது சமமாகவோ இருக்க வேண்டும்", - "description": "ஹெக்ஸ் உள்ளீடு தசம உள்ளீடு என உதவி" - }, "here": { "message": "இங்கே", "description": "இங்கே-கிளிக் செய்யவும்- மேலும் தகவலுக்கு (troubleTokenBalances செல்கிறது)" @@ -289,10 +281,6 @@ "learnMore": { "message": "மேலும் அறிக" }, - "lessThanMax": { - "message": "$ 1 க்கும் குறைவாகவோ அல்லது சமமாகவோ இருக்க வேண்டும்.", - "description": "ஹெக்ஸ் உள்ளீடு தசம உள்ளீடு என உதவி" - }, "likeToAddTokens": { "message": "இந்த டோக்கன்களைச் சேர்க்க விரும்புகிறீர்களா?" }, diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index 0cd9456d28e3..c32044bb16ac 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -64,10 +64,6 @@ "balanceIsInsufficientGas": { "message": "ยอดคงเหลือไม่พอสำหรับจ่ายค่าแก๊สทั้งหมด" }, - "betweenMinAndMax": { - "message": "ต้องมากกว่าหรือเท่ากับ $1 และน้อยกว่าหรือเท่ากับ $2", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "ใช้งาน Blockies Identicon" }, @@ -281,10 +277,6 @@ "message": "รับอีเธอร์ที่ปล่อยจาก $1", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": "ต้องมากกว่าหรือเท่ากับ $1.", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "ที่นี่", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -349,10 +341,6 @@ "learnMore": { "message": "เรียนรู้เพิ่มเติม" }, - "lessThanMax": { - "message": "ต้องน้อยกว่าหรือเท่ากับ $1.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "คุณต้องการเพิ่มโทเค็นเหล่านี้หรือไม่?" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 96351eebdf25..dbfe3cf08617 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -58,10 +58,6 @@ "balanceIsInsufficientGas": { "message": "Toplam gas için yetersiz bakiye" }, - "betweenMinAndMax": { - "message": "$1'e eşit veya daha büyük olmalı ve $2'den küçük veya eşit olmalı", - "description": "helper for inputting hex as decimal input" - }, "blockiesIdenticon": { "message": "Blockies Identicon kullan" }, @@ -291,10 +287,6 @@ "learnMore": { "message": "Daha fazla bilgi." }, - "lessThanMax": { - "message": "$1'den az veya eşit olmalıdır.", - "description": "helper for inputting hex as decimal input" - }, "likeToAddTokens": { "message": "Bu jetonlara adres eklemek ister misiniz?" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index f2601e8dd46b..a4252cb3e8a8 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "Основні параметри" }, - "betweenMinAndMax": { - "message": "має бути більшим або дорівнювати $1 і меншим або дорівнювати $2.", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "Блокувати Explorer" }, @@ -540,10 +536,6 @@ "getStarted": { "message": "Почати" }, - "greaterThanMin": { - "message": "має бути більшим або рівним $1.", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "Раді вас бачити." }, @@ -662,10 +654,6 @@ "ledgerAccountRestriction": { "message": "Потрібно скористатися своїм останнім обліковим записом, перш ніж додавати новий." }, - "lessThanMax": { - "message": "має бути більшим або дорівнювати $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "Так, давайте налаштуємо!" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 7e5f717e58e0..bc017c9472cd 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -49,10 +49,6 @@ "balanceIsInsufficientGas": { "message": "Số dư không đủ để thanh toán tổng tiền gas hiện tại" }, - "betweenMinAndMax": { - "message": "phải nhiều hơn hoặc bằng $1 và ít hơn hoặc bằng $2.", - "description": "helper for inputting hex as decimal input" - }, "buyCoinSwitch": { "message": "Mua trên CoinSwitch" }, @@ -176,10 +172,6 @@ "message": "Lấy Ether từ vòi với giá $1", "description": "Displays network name for Ether faucet" }, - "greaterThanMin": { - "message": "phải nhiều hơn hoặc bằng $1", - "description": "helper for inputting hex as decimal input" - }, "here": { "message": "tại đây", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -220,10 +212,6 @@ "kovan": { "message": "Mạng thử nghiệm Kovan" }, - "lessThanMax": { - "message": "phải ít hơn hoặc bằng $1.", - "description": "helper for inputting hex as decimal input" - }, "loading": { "message": "Đang tải..." }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 4c087fd3b4e3..c0b10a9730d7 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "基本" }, - "betweenMinAndMax": { - "message": "必须大于等于 $1 并且小于等于 $2 。", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "屏蔽管理器" }, @@ -534,10 +530,6 @@ "getStarted": { "message": "开始使用" }, - "greaterThanMin": { - "message": "必须要大于等于 $1。", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "我们很高兴与您见面。" }, @@ -653,10 +645,6 @@ "ledgerAccountRestriction": { "message": "请在新增账户前,确认添加上一个账户。" }, - "lessThanMax": { - "message": "必须小于或等于 $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "是的。立即开始设置!" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 56cc4751dc0d..5a0a2e3ea3e1 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -157,10 +157,6 @@ "basic": { "message": "基本" }, - "betweenMinAndMax": { - "message": "必須大於等於 $1 並且小於等於 $2 。", - "description": "helper for inputting hex as decimal input" - }, "blockExplorerUrl": { "message": "區塊鏈瀏覽器" }, @@ -537,10 +533,6 @@ "getStarted": { "message": "開始使用" }, - "greaterThanMin": { - "message": "必須要大於等於 $1。", - "description": "helper for inputting hex as decimal input" - }, "happyToSeeYou": { "message": "我們很高興看到你。" }, @@ -659,10 +651,6 @@ "ledgerAccountRestriction": { "message": "您必須使用最後的帳戶才能產生新帳戶" }, - "lessThanMax": { - "message": "必須小於等於 $1.", - "description": "helper for inputting hex as decimal input" - }, "letsGoSetUp": { "message": "好,我們開始吧!" }, diff --git a/ui/app/components/app/bn-as-decimal-input.js b/ui/app/components/app/bn-as-decimal-input.js deleted file mode 100644 index 834bab0a4d8c..000000000000 --- a/ui/app/components/app/bn-as-decimal-input.js +++ /dev/null @@ -1,188 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const ethUtil = require('ethereumjs-util') -const BN = ethUtil.BN -const extend = require('xtend') -const connect = require('react-redux').connect - -BnAsDecimalInput.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect()(BnAsDecimalInput) - - -inherits(BnAsDecimalInput, Component) -function BnAsDecimalInput () { - this.state = { invalid: null } - Component.call(this) -} - -/* Bn as Decimal Input - * - * A component for allowing easy, decimal editing - * of a passed in bn string value. - * - * On change, calls back its `onChange` function parameter - * and passes it an updated bn string. - */ - -BnAsDecimalInput.prototype.render = function () { - const props = this.props - const state = this.state - - const { value, scale, precision, onChange, min, max } = props - - const suffix = props.suffix - const style = props.style - const valueString = value.toString(10) - const newMin = min && this.downsize(min.toString(10), scale) - const newMax = max && this.downsize(max.toString(10), scale) - const newValue = this.downsize(valueString, scale) - - return ( - h('.flex-column', [ - h('.flex-row', { - style: { - alignItems: 'flex-end', - lineHeight: '13px', - fontFamily: 'Montserrat Light', - textRendering: 'geometricPrecision', - }, - }, [ - h('input.hex-input', { - type: 'number', - step: 'any', - required: true, - min: newMin, - max: newMax, - style: extend({ - display: 'block', - textAlign: 'right', - backgroundColor: 'transparent', - border: '1px solid #bdbdbd', - - }, style), - value: newValue, - onBlur: (event) => { - this.updateValidity(event) - }, - onChange: (event) => { - this.updateValidity(event) - const value = (event.target.value === '') ? '' : event.target.value - - - const scaledNumber = this.upsize(value, scale, precision) - const precisionBN = new BN(scaledNumber, 10) - onChange(precisionBN, event.target.checkValidity()) - }, - onInvalid: (event) => { - const msg = this.constructWarning() - if (msg === state.invalid) { - return - } - this.setState({ invalid: msg }) - event.preventDefault() - return false - }, - }), - h('div', { - style: { - color: ' #AEAEAE', - fontSize: '12px', - marginLeft: '5px', - marginRight: '6px', - width: '20px', - }, - }, suffix), - ]), - - state.invalid ? h('span.error', { - style: { - position: 'absolute', - right: '0px', - textAlign: 'right', - transform: 'translateY(26px)', - padding: '3px', - background: 'rgba(255,255,255,0.85)', - zIndex: '1', - textTransform: 'capitalize', - border: '2px solid #E20202', - }, - }, state.invalid) : null, - ]) - ) -} - -BnAsDecimalInput.prototype.setValid = function () { - this.setState({ invalid: null }) -} - -BnAsDecimalInput.prototype.updateValidity = function (event) { - const target = event.target - const value = this.props.value - const newValue = target.value - - if (value === newValue) { - return - } - - const valid = target.checkValidity() - - if (valid) { - this.setState({ invalid: null }) - } -} - -BnAsDecimalInput.prototype.constructWarning = function () { - const { name, min, max, scale, suffix } = this.props - const newMin = min && this.downsize(min.toString(10), scale) - const newMax = max && this.downsize(max.toString(10), scale) - let message = name ? name + ' ' : '' - - if (min && max) { - message += this.context.t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) - } else if (min) { - message += this.context.t('greaterThanMin', [`${newMin} ${suffix}`]) - } else if (max) { - message += this.context.t('lessThanMax', [`${newMax} ${suffix}`]) - } else { - message += this.context.t('invalidInput') - } - - return message -} - - -BnAsDecimalInput.prototype.downsize = function (number, scale) { - // if there is no scaling, simply return the number - if (scale === 0) { - return Number(number) - } else { - // if the scale is the same as the precision, account for this edge case. - var adjustedNumber = number - while (adjustedNumber.length < scale) { - adjustedNumber = '0' + adjustedNumber - } - return Number(adjustedNumber.slice(0, -scale) + '.' + adjustedNumber.slice(-scale)) - } -} - -BnAsDecimalInput.prototype.upsize = function (number, scale, precision) { - var stringArray = number.toString().split('.') - var decimalLength = stringArray[1] ? stringArray[1].length : 0 - var newString = stringArray[0] - - // If there is scaling and decimal parts exist, integrate them in. - if ((scale !== 0) && (decimalLength !== 0)) { - newString += stringArray[1].slice(0, precision) - } - - // Add 0s to account for the upscaling. - for (var i = decimalLength; i < scale; i++) { - newString += '0' - } - return newString -} From caefda5f47c06f0ec43b9bdde9f1c3bbb66057e8 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 10:02:51 -0330 Subject: [PATCH 63/88] Use localized messages for NotificationModal buttons (#7558) --- ui/app/components/app/modals/notification-modal.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/app/components/app/modals/notification-modal.js b/ui/app/components/app/modals/notification-modal.js index 9cec3ed826c1..800cd4f2f8bb 100644 --- a/ui/app/components/app/modals/notification-modal.js +++ b/ui/app/components/app/modals/notification-modal.js @@ -4,6 +4,10 @@ import {connect} from 'react-redux' import { hideModal } from '../../../store/actions' class NotificationModal extends Component { + static contextProps = { + t: PropTypes.func.isRequired, + } + render () { const { header, @@ -14,6 +18,8 @@ class NotificationModal extends Component { onConfirm, } = this.props + const { t } = this.context + const showButtons = showCancelButton || showConfirmButton return ( @@ -35,7 +41,7 @@ class NotificationModal extends Component { className="btn-default notification-modal__buttons__btn" onClick={hideModal} > - Cancel + {t('cancel')}
    )} {showConfirmButton && ( @@ -46,7 +52,7 @@ class NotificationModal extends Component { hideModal() }} > - Confirm + {t('confirm')}
    )}
    From 921134bad1ddb69f42fa55cc32b0becdbc91fb09 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 10:03:30 -0330 Subject: [PATCH 64/88] Convert ConfirmTxScreen component to use JSX (#7559) --- ui/app/pages/confirm-transaction/conf-tx.js | 49 ++++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/ui/app/pages/confirm-transaction/conf-tx.js b/ui/app/pages/confirm-transaction/conf-tx.js index 79d7f5e4f30d..5d8069d9102b 100644 --- a/ui/app/pages/confirm-transaction/conf-tx.js +++ b/ui/app/pages/confirm-transaction/conf-tx.js @@ -1,6 +1,5 @@ +import React, {Component} from 'react' const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') const connect = require('react-redux').connect const { withRouter } = require('react-router-dom') const { compose } = require('recompose') @@ -148,35 +147,41 @@ ConfirmTxScreen.prototype.signatureSelect = function (type, version) { } ConfirmTxScreen.prototype.render = function () { - const props = this.props const { currentCurrency, blockGasLimit, conversionRate, - } = props + } = this.props var txData = this.getTxData() || {} const { msgParams, type, msgParams: { version } } = txData log.debug('msgParams detected, rendering pending msg') - return msgParams ? h(this.signatureSelect(type, version), { - // Properties - txData: txData, - key: txData.id, - selectedAddress: props.selectedAddress, - accounts: props.accounts, - identities: props.identities, - conversionRate, - currentCurrency, - blockGasLimit, - // Actions - signMessage: this.signMessage.bind(this, txData), - signPersonalMessage: this.signPersonalMessage.bind(this, txData), - signTypedMessage: this.signTypedMessage.bind(this, txData), - cancelMessage: this.cancelMessage.bind(this, txData), - cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData), - cancelTypedMessage: this.cancelTypedMessage.bind(this, txData), - }) : h(Loading) + if (!msgParams) { + return ( + + ) + } + + const SigComponent = this.signatureSelect(type, version) + return ( + + ) } ConfirmTxScreen.prototype.signMessage = function (msgData, event) { From e2d679867305f760e9303acbefb8b802c0d39f28 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 25 Nov 2019 11:58:21 -0330 Subject: [PATCH 65/88] Split EthBalance into container and component files (#7557) Co-Authored-By: Mark Stacey --- .../shift-list-item.component.js | 2 +- ui/app/components/ui/eth-balance.js | 106 -------------- .../ui/eth-balance/eth-balance.component.js | 129 ++++++++++++++++++ .../ui/eth-balance/eth-balance.container.js | 10 ++ ui/app/components/ui/eth-balance/index.js | 1 + 5 files changed, 141 insertions(+), 107 deletions(-) delete mode 100644 ui/app/components/ui/eth-balance.js create mode 100644 ui/app/components/ui/eth-balance/eth-balance.component.js create mode 100644 ui/app/components/ui/eth-balance/eth-balance.container.js create mode 100644 ui/app/components/ui/eth-balance/index.js diff --git a/ui/app/components/app/shift-list-item/shift-list-item.component.js b/ui/app/components/app/shift-list-item/shift-list-item.component.js index 0d8e55389837..5e8797d27b0c 100644 --- a/ui/app/components/app/shift-list-item/shift-list-item.component.js +++ b/ui/app/components/app/shift-list-item/shift-list-item.component.js @@ -5,7 +5,7 @@ const actions = require('../../../store/actions') const { formatDate, addressSummary } = require('../../../helpers/utils/util') const CopyButton = require('../../ui/copyButton') -const EthBalance = require('../../ui/eth-balance') +const EthBalance = require('../../ui/eth-balance').default const Tooltip = require('../../ui/tooltip') export default class ShiftListItem extends Component { diff --git a/ui/app/components/ui/eth-balance.js b/ui/app/components/ui/eth-balance.js deleted file mode 100644 index 63d0057c5410..000000000000 --- a/ui/app/components/ui/eth-balance.js +++ /dev/null @@ -1,106 +0,0 @@ -const { Component } = require('react') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const { inherits } = require('util') -const { - formatBalance, - generateBalanceObject, -} = require('../../helpers/utils/util') -const Tooltip = require('./tooltip.js') -const FiatValue = require('./fiat-value.js') - -module.exports = connect(mapStateToProps)(EthBalanceComponent) -function mapStateToProps (state) { - return { - ticker: state.metamask.ticker, - } -} - -inherits(EthBalanceComponent, Component) -function EthBalanceComponent () { - Component.call(this) -} - -EthBalanceComponent.prototype.render = function () { - const props = this.props - const { ticker, value, style, width, needsParse = true } = props - - const formattedValue = value ? formatBalance(value, 6, needsParse, ticker) : '...' - - return ( - - h('.ether-balance.ether-balance-amount', { - style, - }, [ - h('div', { - style: { - display: 'inline', - width, - }, - }, this.renderBalance(formattedValue)), - ]) - - ) -} -EthBalanceComponent.prototype.renderBalance = function (value) { - if (value === 'None') { - return value - } - if (value === '...') { - return value - } - - const { - conversionRate, - shorten, - incoming, - currentCurrency, - hideTooltip, - styleOveride = {}, - showFiat = true, - } = this.props - const { fontSize, color, fontFamily, lineHeight } = styleOveride - - const { shortBalance, balance, label } = generateBalanceObject(value, shorten ? 1 : 3) - const balanceToRender = shorten ? shortBalance : balance - - const [ethNumber, ethSuffix] = value.split(' ') - const containerProps = hideTooltip ? {} : { - position: 'bottom', - title: `${ethNumber} ${ethSuffix}`, - } - - return ( - h(hideTooltip ? 'div' : Tooltip, - containerProps, - h('div.flex-column', [ - h('.flex-row', { - style: { - alignItems: 'flex-end', - lineHeight: lineHeight || '13px', - fontFamily: fontFamily || 'Montserrat Light', - textRendering: 'geometricPrecision', - }, - }, [ - h('div', { - style: { - width: '100%', - textAlign: 'right', - fontSize: fontSize || 'inherit', - color: color || 'inherit', - }, - }, incoming ? `+${balanceToRender}` : balanceToRender), - h('div', { - style: { - color: color || '#AEAEAE', - fontSize: fontSize || '12px', - marginLeft: '5px', - }, - }, label), - ]), - - showFiat ? h(FiatValue, { value: this.props.value, conversionRate, currentCurrency }) : null, - ]) - ) - ) -} diff --git a/ui/app/components/ui/eth-balance/eth-balance.component.js b/ui/app/components/ui/eth-balance/eth-balance.component.js new file mode 100644 index 000000000000..fedbcc192c9e --- /dev/null +++ b/ui/app/components/ui/eth-balance/eth-balance.component.js @@ -0,0 +1,129 @@ +import PropTypes from 'prop-types' +import React, {Component} from 'react' + +const { + formatBalance, + generateBalanceObject, +} = require('../../../helpers/utils/util') +const Tooltip = require('../tooltip.js') +const FiatValue = require('../fiat-value.js') + +export default class EthBalance extends Component { + static defaultProps = { + style: null, + styleOverride: {}, + showFiat: true, + needsParse: true, + width: undefined, + shorten: false, + incoming: false, + } + + static propTypes = { + conversionRate: PropTypes.any.isRequired, + shorten: PropTypes.bool, + incoming: PropTypes.bool, + currentCurrency: PropTypes.string.isRequired, + hideTooltip: PropTypes.bool, + styleOverride: PropTypes.object, + showFiat: PropTypes.bool, + ticker: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + style: PropTypes.object, + width: PropTypes.string, + needsParse: PropTypes.bool, + } + + renderBalance (value) { + if (value === 'None') { + return value + } + if (value === '...') { + return value + } + + const { + conversionRate, + shorten, + incoming, + currentCurrency, + hideTooltip, + styleOverride = {}, + showFiat = true, + } = this.props + const { fontSize, color, fontFamily, lineHeight } = styleOverride + + const { shortBalance, balance, label } = generateBalanceObject(value, shorten ? 1 : 3) + const balanceToRender = shorten ? shortBalance : balance + + const [ethNumber, ethSuffix] = value.split(' ') + const containerProps = hideTooltip ? {} : { + position: 'bottom', + title: `${ethNumber} ${ethSuffix}`, + } + + const TooltipComponent = hideTooltip ? 'div' : Tooltip + + return ( + +
    +
    +
    + { + incoming + ? `+${balanceToRender}` + : balanceToRender + } +
    +
    + {label} +
    +
    +
    + { + showFiat + ? ( + + ) + : null + } +
    + ) + } + + render () { + const { ticker, value, style, width, needsParse } = this.props + const formattedValue = value + ? formatBalance(value, 6, needsParse, ticker) + : '...' + + return ( +
    +
    + {this.renderBalance(formattedValue)} +
    +
    + ) + } +} diff --git a/ui/app/components/ui/eth-balance/eth-balance.container.js b/ui/app/components/ui/eth-balance/eth-balance.container.js new file mode 100644 index 000000000000..8e36b6f78e38 --- /dev/null +++ b/ui/app/components/ui/eth-balance/eth-balance.container.js @@ -0,0 +1,10 @@ +import { connect } from 'react-redux' +import EthBalance from './eth-balance.component' + +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} + +export default connect(mapStateToProps)(EthBalance) diff --git a/ui/app/components/ui/eth-balance/index.js b/ui/app/components/ui/eth-balance/index.js new file mode 100644 index 000000000000..f40991784319 --- /dev/null +++ b/ui/app/components/ui/eth-balance/index.js @@ -0,0 +1 @@ +export { default } from './eth-balance.container' From e39485cb1c8e65a84d8f7bbf3e7ee0f6c6a9eea0 Mon Sep 17 00:00:00 2001 From: ricky Date: Mon, 25 Nov 2019 13:15:12 -0500 Subject: [PATCH 66/88] Fix loading prop type (#7563) --- .../app/dropdowns/components/network-dropdown-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 de3e8496de42..2e5f71593abd 100644 --- a/ui/app/components/app/dropdowns/components/network-dropdown-icon.js +++ b/ui/app/components/app/dropdowns/components/network-dropdown-icon.js @@ -45,7 +45,7 @@ NetworkDropdownIcon.defaultProps = { NetworkDropdownIcon.propTypes = { backgroundColor: PropTypes.string, - loading: PropTypes.boolean, + loading: PropTypes.bool, innerBorder: PropTypes.string, diameter: PropTypes.string, isSelected: PropTypes.bool, From c044400a7e51e5ae79e82c06dbe893dd411c4fd7 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 26 Nov 2019 17:14:29 -0330 Subject: [PATCH 67/88] Don't overwrite state when setting inactive timeout Using `#putState` here was clearing the other fields in the store. --- app/scripts/controllers/app-state.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 8d67874ad078..c60a1c4f5065 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -45,7 +45,7 @@ class AppStateController { * @private */ _setInactiveTimeout (timeoutMinutes) { - this.store.putState({ + this.store.updateState({ timeoutMinutes, }) From c3a1a35f7d6c6e0cad77df8a2365cbec07d33b3b Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 26 Nov 2019 17:54:53 -0330 Subject: [PATCH 68/88] Construct AppStateController with the persisted initial state --- app/scripts/metamask-controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index be8424d426cb..9b38451a4e4b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -111,6 +111,7 @@ module.exports = class MetamaskController extends EventEmitter { this.appStateController = new AppStateController({ preferencesStore: this.preferencesController.store, onInactiveTimeout: () => this.setLocked(), + initState: initState.AppStateController, }) // currency controller From 4a59fb432fb14e2400773d8b1fd12e1ec725ae49 Mon Sep 17 00:00:00 2001 From: ricky Date: Tue, 26 Nov 2019 17:44:33 -0500 Subject: [PATCH 69/88] Fix backButtonAction proptype (#7578) * Fix backButtonAction proptype * Fix missing trailing comma * Remove no-op --- .../account-modal-container.component.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 c59b1a1accb6..ed28f5fd120f 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 @@ -40,12 +40,13 @@ AccountModalContainer.contextTypes = { AccountModalContainer.defaultProps = { showBackButton: false, children: null, + backButtonAction: undefined, } AccountModalContainer.propTypes = { selectedIdentity: PropTypes.object.isRequired, showBackButton: PropTypes.bool, - backButtonAction: PropTypes.func.isRequired, + backButtonAction: PropTypes.func, hideModal: PropTypes.func.isRequired, children: PropTypes.node, } From 724bd42e2cba55b5ab42c4ee68431eeb65f2bd05 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 27 Nov 2019 09:28:03 -0330 Subject: [PATCH 70/88] Ensures the tx controller + state-manager orders transactions as received (#7484) * Ensures the tx controller + tx-state-manager orders transactions in the order they are received * Handle transaction ordering in cases where tx ids are off by more than 1 in tx-state-manager * Add comment to addUnapprovedTransaction explaining calling _determineTransactionCategory after generateTxMeta * Sort txes by timestamp of creation instead of id --- app/scripts/controllers/transactions/index.js | 11 ++++++++--- .../controllers/transactions/tx-state-manager.js | 7 ++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index f19dd53f7985..31f8cc103972 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -192,13 +192,18 @@ class TransactionController extends EventEmitter { throw new Error(`Transaction from address isn't valid for this account`) } txUtils.validateTxParams(normalizedTxParams) - // construct txMeta - const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams) + /** + `generateTxMeta` adds the default txMeta properties to the passed object. + These include the tx's `id`. As we use the id for determining order of + txes in the tx-state-manager, it is necessary to call the asynchronous + method `this._determineTransactionCategory` after `generateTxMeta`. + */ let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams, type: TRANSACTION_TYPE_STANDARD, - transactionCategory, }) + const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams) + txMeta.transactionCategory = transactionCategory this.addTx(txMeta) this.emit('newUnapprovedTx', txMeta) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index fb9359c79174..ffbe6f0107b0 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -167,7 +167,12 @@ class TransactionStateManager extends EventEmitter { transactions.splice(index, 1) } } - transactions.push(txMeta) + const newTxIndex = transactions + .findIndex((currentTxMeta) => currentTxMeta.time > txMeta.time) + + newTxIndex === -1 + ? transactions.push(txMeta) + : transactions.splice(newTxIndex, 0, txMeta) this._saveTxList(transactions) return txMeta } From 00060d787a7381632b86a6b686c5c43f4ae10d04 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 11:36:12 -0330 Subject: [PATCH 71/88] Split TokenCell into container and component files (#7560) --- ui/app/components/app/token-cell.js | 177 ------------------ ui/app/components/app/token-cell/index.js | 1 + .../app/token-cell/token-cell.component.js | 140 ++++++++++++++ .../app/token-cell/token-cell.container.js | 25 +++ ui/app/components/app/token-list.js | 2 +- 5 files changed, 167 insertions(+), 178 deletions(-) delete mode 100644 ui/app/components/app/token-cell.js create mode 100644 ui/app/components/app/token-cell/index.js create mode 100644 ui/app/components/app/token-cell/token-cell.component.js create mode 100644 ui/app/components/app/token-cell/token-cell.container.js diff --git a/ui/app/components/app/token-cell.js b/ui/app/components/app/token-cell.js deleted file mode 100644 index 495b9502be07..000000000000 --- a/ui/app/components/app/token-cell.js +++ /dev/null @@ -1,177 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -import Identicon from '../ui/identicon' -const prefixForNetwork = require('../../../lib/etherscan-prefix-for-network') -const selectors = require('../../selectors/selectors') -const actions = require('../../store/actions') -const { conversionUtil, multiplyCurrencies } = require('../../helpers/utils/conversion-util') - -const TokenMenuDropdown = require('./dropdowns/token-menu-dropdown.js') - -function mapStateToProps (state) { - return { - network: state.metamask.network, - currentCurrency: state.metamask.currentCurrency, - selectedTokenAddress: state.metamask.selectedTokenAddress, - userAddress: selectors.getSelectedAddress(state), - contractExchangeRates: state.metamask.contractExchangeRates, - conversionRate: state.metamask.conversionRate, - sidebarOpen: state.appState.sidebar.isOpen, - } -} - -function mapDispatchToProps (dispatch) { - return { - setSelectedToken: address => dispatch(actions.setSelectedToken(address)), - hideSidebar: () => dispatch(actions.hideSidebar()), - } -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(TokenCell) - -inherits(TokenCell, Component) -function TokenCell () { - Component.call(this) - - this.state = { - tokenMenuOpen: false, - } -} - -TokenCell.contextTypes = { - metricsEvent: PropTypes.func, -} - -TokenCell.prototype.render = function () { - const { tokenMenuOpen } = this.state - const props = this.props - const { - address, - symbol, - string, - network, - setSelectedToken, - selectedTokenAddress, - contractExchangeRates, - conversionRate, - hideSidebar, - sidebarOpen, - currentCurrency, - // userAddress, - image, - } = props - let currentTokenToFiatRate - let currentTokenInFiat - let formattedFiat = '' - - if (contractExchangeRates[address]) { - currentTokenToFiatRate = multiplyCurrencies( - contractExchangeRates[address], - conversionRate - ) - currentTokenInFiat = conversionUtil(string, { - fromNumericBase: 'dec', - fromCurrency: symbol, - toCurrency: currentCurrency.toUpperCase(), - numberOfDecimals: 2, - conversionRate: currentTokenToFiatRate, - }) - formattedFiat = currentTokenInFiat.toString() === '0' - ? '' - : `${currentTokenInFiat} ${currentCurrency.toUpperCase()}` - } - - const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol - - return ( - h('div.token-list-item', { - className: `token-list-item ${selectedTokenAddress === address ? 'token-list-item--active' : ''}`, - // style: { cursor: network === '1' ? 'pointer' : 'default' }, - // onClick: this.view.bind(this, address, userAddress, network), - onClick: () => { - setSelectedToken(address) - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Token Menu', - name: 'Clicked Token', - }, - }) - selectedTokenAddress !== address && sidebarOpen && hideSidebar() - }, - }, [ - - h(Identicon, { - className: 'token-list-item__identicon', - diameter: 50, - address, - network, - image, - }), - - h('div.token-list-item__balance-ellipsis', null, [ - h('div.token-list-item__balance-wrapper', null, [ - h('div.token-list-item__token-balance', `${string || 0}`), - h('div.token-list-item__token-symbol', symbol), - showFiat && h('div.token-list-item__fiat-amount', { - style: {}, - }, formattedFiat), - ]), - - h('i.fa.fa-ellipsis-h.fa-lg.token-list-item__ellipsis.cursor-pointer', { - onClick: (e) => { - e.stopPropagation() - this.setState({ tokenMenuOpen: true }) - }, - }), - - ]), - - - tokenMenuOpen && h(TokenMenuDropdown, { - onClose: () => this.setState({ tokenMenuOpen: false }), - token: { symbol, address }, - }), - - /* - h('button', { - onClick: this.send.bind(this, address), - }, 'SEND'), - */ - - ]) - ) -} - -TokenCell.prototype.send = function (address, event) { - event.preventDefault() - event.stopPropagation() - const url = tokenFactoryFor(address) - if (url) { - navigateTo(url) - } -} - -TokenCell.prototype.view = function (address, userAddress, network) { - const url = etherscanLinkFor(address, userAddress, network) - if (url) { - navigateTo(url) - } -} - -function navigateTo (url) { - global.platform.openWindow({ url }) -} - -function etherscanLinkFor (tokenAddress, address, network) { - const prefix = prefixForNetwork(network) - return `https://${prefix}etherscan.io/token/${tokenAddress}?a=${address}` -} - -function tokenFactoryFor (tokenAddress) { - return `https://tokenfactory.surge.sh/#/token/${tokenAddress}` -} - diff --git a/ui/app/components/app/token-cell/index.js b/ui/app/components/app/token-cell/index.js new file mode 100644 index 000000000000..f0f3bcb4aaab --- /dev/null +++ b/ui/app/components/app/token-cell/index.js @@ -0,0 +1 @@ +export { default } from './token-cell.container' diff --git a/ui/app/components/app/token-cell/token-cell.component.js b/ui/app/components/app/token-cell/token-cell.component.js new file mode 100644 index 000000000000..10a3447d122b --- /dev/null +++ b/ui/app/components/app/token-cell/token-cell.component.js @@ -0,0 +1,140 @@ +import classnames from 'classnames' +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import Identicon from '../../ui/identicon' +const prefixForNetwork = require('../../../../lib/etherscan-prefix-for-network') +const { conversionUtil, multiplyCurrencies } = require('../../../helpers/utils/conversion-util') + +const TokenMenuDropdown = require('../dropdowns/token-menu-dropdown.js') + +export default class TokenCell extends Component { + static contextTypes = { + metricsEvent: PropTypes.func, + } + + state = { + tokenMenuOpen: false, + } + + send (address, event) { + event.preventDefault() + event.stopPropagation() + const url = tokenFactoryFor(address) + if (url) { + navigateTo(url) + } + } + + view (address, userAddress, network) { + const url = etherscanLinkFor(address, userAddress, network) + if (url) { + navigateTo(url) + } + } + + render () { + const { tokenMenuOpen } = this.state + const props = this.props + const { + address, + symbol, + string, + network, + setSelectedToken, + selectedTokenAddress, + contractExchangeRates, + conversionRate, + hideSidebar, + sidebarOpen, + currentCurrency, + // userAddress, + image, + } = props + let currentTokenToFiatRate + let currentTokenInFiat + let formattedFiat = '' + + if (contractExchangeRates[address]) { + currentTokenToFiatRate = multiplyCurrencies( + contractExchangeRates[address], + conversionRate + ) + currentTokenInFiat = conversionUtil(string, { + fromNumericBase: 'dec', + fromCurrency: symbol, + toCurrency: currentCurrency.toUpperCase(), + numberOfDecimals: 2, + conversionRate: currentTokenToFiatRate, + }) + formattedFiat = currentTokenInFiat.toString() === '0' + ? '' + : `${currentTokenInFiat} ${currentCurrency.toUpperCase()}` + } + + const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol + + return ( +
    { + setSelectedToken(address) + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Token Menu', + name: 'Clicked Token', + }, + }) + selectedTokenAddress !== address && sidebarOpen && hideSidebar() + }} + > + +
    +
    +
    {string || 0}
    +
    {symbol}
    + {showFiat && ( +
    + {formattedFiat} +
    + )} +
    + { + e.stopPropagation() + this.setState({ tokenMenuOpen: true }) + }} + /> +
    + {tokenMenuOpen && ( + this.setState({ tokenMenuOpen: false })} + token={{ symbol, address }} + /> + )} +
    + ) + } +} + +function navigateTo (url) { + global.platform.openWindow({ url }) +} + +function etherscanLinkFor (tokenAddress, address, network) { + const prefix = prefixForNetwork(network) + return `https://${prefix}etherscan.io/token/${tokenAddress}?a=${address}` +} + +function tokenFactoryFor (tokenAddress) { + return `https://tokenfactory.surge.sh/#/token/${tokenAddress}` +} + diff --git a/ui/app/components/app/token-cell/token-cell.container.js b/ui/app/components/app/token-cell/token-cell.container.js new file mode 100644 index 000000000000..176e93008b3f --- /dev/null +++ b/ui/app/components/app/token-cell/token-cell.container.js @@ -0,0 +1,25 @@ +import { connect } from 'react-redux' +import { setSelectedToken, hideSidebar } from '../../../store/actions' +import { getSelectedAddress } from '../../../selectors/selectors' +import TokenCell from './token-cell.component' + +function mapStateToProps (state) { + return { + network: state.metamask.network, + currentCurrency: state.metamask.currentCurrency, + selectedTokenAddress: state.metamask.selectedTokenAddress, + userAddress: getSelectedAddress(state), + contractExchangeRates: state.metamask.contractExchangeRates, + conversionRate: state.metamask.conversionRate, + sidebarOpen: state.appState.sidebar.isOpen, + } +} + +function mapDispatchToProps (dispatch) { + return { + setSelectedToken: address => dispatch(setSelectedToken(address)), + hideSidebar: () => dispatch(hideSidebar()), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TokenCell) diff --git a/ui/app/components/app/token-list.js b/ui/app/components/app/token-list.js index 5bab96a454af..7917cd54ad83 100644 --- a/ui/app/components/app/token-list.js +++ b/ui/app/components/app/token-list.js @@ -1,8 +1,8 @@ import PropTypes from 'prop-types' import React, { Component } from 'react' +import TokenCell from './token-cell' const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') -const TokenCell = require('./token-cell.js') const connect = require('react-redux').connect const selectors = require('../../selectors/selectors') const log = require('loglevel') From f0e5ab6c126e53efb45c1b903baa808ff4e01048 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 11:36:31 -0330 Subject: [PATCH 72/88] Split ExportPrivateKeyModal into container and component files (#7561) --- .../app/modals/export-private-key-modal.js | 178 ------------------ .../export-private-key-modal.component.js | 168 +++++++++++++++++ .../export-private-key-modal.container.js | 38 ++++ .../modals/export-private-key-modal/index.js | 1 + ui/app/components/app/modals/modal.js | 2 +- 5 files changed, 208 insertions(+), 179 deletions(-) delete mode 100644 ui/app/components/app/modals/export-private-key-modal.js create mode 100644 ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js create mode 100644 ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.container.js create mode 100644 ui/app/components/app/modals/export-private-key-modal/index.js diff --git a/ui/app/components/app/modals/export-private-key-modal.js b/ui/app/components/app/modals/export-private-key-modal.js deleted file mode 100644 index 2150520153fd..000000000000 --- a/ui/app/components/app/modals/export-private-key-modal.js +++ /dev/null @@ -1,178 +0,0 @@ -const log = require('loglevel') -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const { stripHexPrefix } = require('ethereumjs-util') -const actions = require('../../../store/actions') -const { getSelectedIdentity } = require('../../../selectors/selectors') -const ReadOnlyInput = require('../../ui/readonly-input') -const copyToClipboard = require('copy-to-clipboard') -const { checksumAddress } = require('../../../helpers/utils/util') -import AccountModalContainer from './account-modal-container' -import Button from '../../ui/button' - -function mapStateToPropsFactory () { - let selectedIdentity = null - 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 - // which is the expected behavior that we are side-stepping. - selectedIdentity = selectedIdentity || getSelectedIdentity(state) - return { - warning: state.appState.warning, - privateKey: state.appState.accountDetail.privateKey, - network: state.metamask.network, - selectedIdentity, - previousModalState: state.appState.modal.previousModalState.name, - } - } -} - -function mapDispatchToProps (dispatch) { - return { - exportAccount: (password, address) => { - return dispatch(actions.exportAccount(password, address)) - .then((res) => { - dispatch(actions.hideWarning()) - return res - }) - }, - showAccountDetailModal: () => dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' })), - hideModal: () => dispatch(actions.hideModal()), - } -} - -inherits(ExportPrivateKeyModal, Component) -function ExportPrivateKeyModal () { - Component.call(this) - - this.state = { - password: '', - privateKey: null, - showWarning: true, - } -} - -ExportPrivateKeyModal.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToPropsFactory, mapDispatchToProps)(ExportPrivateKeyModal) - - -ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (password, address) { - const { exportAccount } = this.props - - exportAccount(password, address) - .then(privateKey => this.setState({ - privateKey, - showWarning: false, - })) - .catch((e) => log.error(e)) -} - -ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { - return h('span.private-key-password-label', privateKey - ? this.context.t('copyPrivateKey') - : this.context.t('typePassword') - ) -} - -ExportPrivateKeyModal.prototype.renderPasswordInput = function (privateKey) { - const plainKey = privateKey && stripHexPrefix(privateKey) - - return privateKey - ? h(ReadOnlyInput, { - wrapperClass: 'private-key-password-display-wrapper', - inputClass: 'private-key-password-display-textarea', - textarea: true, - value: plainKey, - onClick: () => copyToClipboard(plainKey), - }) - : h('input.private-key-password-input', { - type: 'password', - onChange: event => this.setState({ password: event.target.value }), - }) -} - -ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, address, hideModal) { - return h('div.export-private-key-buttons', {}, [ - !privateKey && h(Button, { - type: 'default', - large: true, - className: 'export-private-key__button export-private-key__button--cancel', - onClick: () => hideModal(), - }, this.context.t('cancel')), - - (privateKey - ? ( - h(Button, { - type: 'secondary', - large: true, - className: 'export-private-key__button', - onClick: () => hideModal(), - }, this.context.t('done')) - ) : ( - h(Button, { - type: 'secondary', - large: true, - className: 'export-private-key__button', - disabled: !this.state.password, - onClick: () => this.exportAccountAndGetPrivateKey(this.state.password, address), - }, this.context.t('confirm')) - ) - ), - - ]) -} - -ExportPrivateKeyModal.prototype.render = function () { - const { - selectedIdentity, - warning, - showAccountDetailModal, - hideModal, - previousModalState, - } = this.props - const { name, address } = selectedIdentity - - const { - privateKey, - showWarning, - } = this.state - - return h(AccountModalContainer, { - selectedIdentity, - showBackButton: previousModalState === 'ACCOUNT_DETAILS', - backButtonAction: () => showAccountDetailModal(), - }, [ - - h('span.account-name', name), - - h(ReadOnlyInput, { - wrapperClass: 'ellip-address-wrapper', - inputClass: 'qr-ellip-address ellip-address', - value: checksumAddress(address), - }), - - h('div.account-modal-divider'), - - h('span.modal-body-title', this.context.t('showPrivateKeys')), - - h('div.private-key-password', {}, [ - this.renderPasswordLabel(privateKey), - - this.renderPasswordInput(privateKey), - - showWarning && warning ? h('span.private-key-password-error', warning) : null, - ]), - - h('div.private-key-password-warning', 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.component.js b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js new file mode 100644 index 000000000000..264bcc04175d --- /dev/null +++ b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js @@ -0,0 +1,168 @@ +import log from 'loglevel' +import PropTypes from 'prop-types' +import React, { Component } from 'react' + +const { stripHexPrefix } = require('ethereumjs-util') +const copyToClipboard = require('copy-to-clipboard') +const { checksumAddress } = require('../../../../helpers/utils/util') +const ReadOnlyInput = require('../../../ui/readonly-input') +import Button from '../../../ui/button' +import AccountModalContainer from '../account-modal-container' + +export default class ExportPrivateKeyModal extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static defaultProps = { + warning: null, + previousModalState: null, + } + + static propTypes = { + exportAccount: PropTypes.func.isRequired, + selectedIdentity: PropTypes.object.isRequired, + warning: PropTypes.node, + showAccountDetailModal: PropTypes.func.isRequired, + hideModal: PropTypes.func.isRequired, + previousModalState: PropTypes.string, + } + + state = { + password: '', + privateKey: null, + showWarning: true, + } + + exportAccountAndGetPrivateKey = (password, address) => { + const { exportAccount } = this.props + + exportAccount(password, address) + .then(privateKey => this.setState({ + privateKey, + showWarning: false, + })) + .catch((e) => log.error(e)) + } + + renderPasswordLabel (privateKey) { + return ( + + { + privateKey + ? this.context.t('copyPrivateKey') + : this.context.t('typePassword') + } + + ) + } + + renderPasswordInput (privateKey) { + const plainKey = privateKey && stripHexPrefix(privateKey) + + if (!privateKey) { + return ( + this.setState({ password: event.target.value })} + /> + ) + } + + return ( + copyToClipboard(plainKey)} + /> + ) + } + + renderButtons (privateKey, address, hideModal) { + return ( +
    + {!privateKey && ( + + )} + { + privateKey + ? ( + + ) + : ( + + ) + } +
    + ) + } + + render () { + const { + selectedIdentity, + warning, + showAccountDetailModal, + hideModal, + previousModalState, + } = this.props + const { name, address } = selectedIdentity + + const { + privateKey, + showWarning, + } = this.state + + return ( + showAccountDetailModal()} + > + {name} + +
    + {this.context.t('showPrivateKeys')} +
    + {this.renderPasswordLabel(privateKey)} + {this.renderPasswordInput(privateKey)} + { + (showWarning && warning) + ? {warning} + : null + } +
    +
    {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 new file mode 100644 index 000000000000..1b8f63c947d3 --- /dev/null +++ b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.container.js @@ -0,0 +1,38 @@ +import { connect } from 'react-redux' +import { exportAccount, hideWarning, showModal, hideModal } from '../../../../store/actions' +import { getSelectedIdentity } from '../../../../selectors/selectors' +import ExportPrivateKeyModal from './export-private-key-modal.component' + +function mapStateToPropsFactory () { + let selectedIdentity = null + 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 + // which is the expected behavior that we are side-stepping. + selectedIdentity = selectedIdentity || getSelectedIdentity(state) + return { + warning: state.appState.warning, + privateKey: state.appState.accountDetail.privateKey, + network: state.metamask.network, + selectedIdentity, + previousModalState: state.appState.modal.previousModalState.name, + } + } +} + +function mapDispatchToProps (dispatch) { + return { + exportAccount: (password, address) => { + return dispatch(exportAccount(password, address)) + .then((res) => { + dispatch(hideWarning()) + return res + }) + }, + showAccountDetailModal: () => dispatch(showModal({ name: 'ACCOUNT_DETAILS' })), + hideModal: () => dispatch(hideModal()), + } +} + +export default connect(mapStateToPropsFactory, mapDispatchToProps)(ExportPrivateKeyModal) diff --git a/ui/app/components/app/modals/export-private-key-modal/index.js b/ui/app/components/app/modals/export-private-key-modal/index.js new file mode 100644 index 000000000000..996c995ca717 --- /dev/null +++ b/ui/app/components/app/modals/export-private-key-modal/index.js @@ -0,0 +1 @@ +export { default } from './export-private-key-modal.container' diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js index ada758b9913d..27162bdd506c 100644 --- a/ui/app/components/app/modals/modal.js +++ b/ui/app/components/app/modals/modal.js @@ -12,7 +12,7 @@ const { ENVIRONMENT_TYPE_POPUP } = require('../../../../../app/scripts/lib/enums // Modal Components const DepositEtherModal = require('./deposit-ether-modal') import AccountDetailsModal from './account-details-modal' -const ExportPrivateKeyModal = require('./export-private-key-modal') +const ExportPrivateKeyModal = require('./export-private-key-modal').default const HideTokenConfirmationModal = require('./hide-token-confirmation-modal') const NotifcationModal = require('./notification-modal') const QRScanner = require('./qr-scanner') From baa5313d212c33e1e6b2766f00a5904a64123f01 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 11:36:46 -0330 Subject: [PATCH 73/88] Convert NetworkDropdown component to use JSX (#7562) --- .../app/dropdowns/network-dropdown.js | 503 +++++++++--------- 1 file changed, 258 insertions(+), 245 deletions(-) diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index d36f10d4069b..cf56919c4eb6 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -1,6 +1,5 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') +import PropTypes from 'prop-types' +import React, {Component} from 'react' const inherits = require('util').inherits const connect = require('react-redux').connect const { withRouter } = require('react-router-dom') @@ -67,10 +66,9 @@ module.exports = compose( // TODO: specify default props and proptypes -NetworkDropdown.prototype.render = function () { - const props = this.props - const { provider: { type: providerType, rpcTarget: activeNetwork }, setNetworksTabAddMode } = props - const rpcListDetail = props.frequentRpcListDetail +NetworkDropdown.prototype.render = function NetworkDropdown () { + const { provider: { type: providerType, rpcTarget: activeNetwork }, setNetworksTabAddMode } = this.props + const rpcListDetail = this.props.frequentRpcListDetail const isOpen = this.props.networkDropdownOpen const dropdownMenuItemStyle = { fontSize: '16px', @@ -78,201 +76,206 @@ NetworkDropdown.prototype.render = function () { padding: '12px 0', } - return h(Dropdown, { - isOpen, - onClickOutside: (event) => { - const { classList } = event.target - const isInClassList = className => classList.contains(className) - const notToggleElementIndex = R.findIndex(isInClassList)(notToggleElementClassnames) - - if (notToggleElementIndex === -1) { - this.props.hideNetworkDropdown() - } - }, - containerClassName: 'network-droppo', - zIndex: 55, - style: { - position: 'absolute', - top: '58px', - width: '309px', - zIndex: '55px', - }, - innerStyle: { - padding: '18px 8px', - }, - }, [ - - h('div.network-dropdown-header', {}, [ - h('div.network-dropdown-title', {}, this.context.t('networks')), - - h('div.network-dropdown-divider'), - - h('div.network-dropdown-content', - {}, - this.context.t('defaultNetwork') - ), - ]), - - h( - DropdownMenuItem, - { - key: 'main', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.handleClick('mainnet'), - style: { ...dropdownMenuItemStyle, borderColor: '#038789' }, - }, - [ - providerType === 'mainnet' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - backgroundColor: '#29B6AF', // $java - isSelected: providerType === 'mainnet', - }), - h('span.network-name-item', { - style: { - color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('mainnet')), - ] - ), - - h( - DropdownMenuItem, - { - key: 'ropsten', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.handleClick('ropsten'), - style: dropdownMenuItemStyle, - }, - [ - providerType === 'ropsten' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - backgroundColor: '#ff4a8d', // $wild-strawberry - isSelected: providerType === 'ropsten', - }), - h('span.network-name-item', { - style: { - color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('ropsten')), - ] - ), - - h( - DropdownMenuItem, - { - key: 'kovan', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.handleClick('kovan'), - style: dropdownMenuItemStyle, - }, - [ - providerType === 'kovan' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - backgroundColor: '#7057ff', // $cornflower-blue - isSelected: providerType === 'kovan', - }), - h('span.network-name-item', { - style: { - color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('kovan')), - ] - ), - - h( - DropdownMenuItem, - { - key: 'rinkeby', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.handleClick('rinkeby'), - style: dropdownMenuItemStyle, - }, - [ - providerType === 'rinkeby' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - backgroundColor: '#f6c343', // $saffron - isSelected: providerType === 'rinkeby', - }), - h('span.network-name-item', { - style: { - color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('rinkeby')), - ] - ), - - h( - DropdownMenuItem, - { - key: 'goerli', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.handleClick('goerli'), - style: dropdownMenuItemStyle, - }, - [ - providerType === 'goerli' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - backgroundColor: '#3099f2', // $dodger-blue - isSelected: providerType === 'goerli', - }), - h('span.network-name-item', { - style: { - color: providerType === 'goerli' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('goerli')), - ] - ), - - h( - DropdownMenuItem, - { - key: 'default', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.handleClick('localhost'), - style: dropdownMenuItemStyle, - }, - [ - providerType === 'localhost' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - isSelected: providerType === 'localhost', - innerBorder: '1px solid #9b9b9b', - }), - h('span.network-name-item', { - style: { - color: providerType === 'localhost' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('localhost')), - ] - ), - - this.renderCustomOption(props.provider), - this.renderCommonRpc(rpcListDetail, props.provider), - - h( - DropdownMenuItem, - { - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => { + return ( + { + const { classList } = event.target + const isInClassList = className => classList.contains(className) + const notToggleElementIndex = R.findIndex(isInClassList)(notToggleElementClassnames) + + if (notToggleElementIndex === -1) { + this.props.hideNetworkDropdown() + } + }} + containerClassName="network-droppo" + zIndex={55} + style={{ + position: 'absolute', + top: '58px', + width: '309px', + zIndex: '55px', + }} + innerStyle={{ + padding: '18px 8px', + }} + > +
    +
    + {this.context.t('networks')} +
    +
    +
    + {this.context.t('defaultNetwork')} +
    +
    + this.props.hideNetworkDropdown()} + onClick={() => this.handleClick('mainnet')} + style={{ ...dropdownMenuItemStyle, borderColor: '#038789' }} + > + { + providerType === 'mainnet' + ? + :
    + } + + + {this.context.t('mainnet')} + +
    + this.props.hideNetworkDropdown()} + onClick={() => this.handleClick('ropsten')} + style={dropdownMenuItemStyle} + > + { + providerType === 'ropsten' + ? + :
    + } + + + {this.context.t('ropsten')} + +
    + this.props.hideNetworkDropdown()} + onClick={() => this.handleClick('kovan')} + style={dropdownMenuItemStyle} + > + { + providerType === 'kovan' + ? + :
    + } + + + {this.context.t('kovan')} + +
    + this.props.hideNetworkDropdown()} + onClick={() => this.handleClick('rinkeby')} + style={dropdownMenuItemStyle} + > + { + providerType === 'rinkeby' + ? + :
    + } + + + {this.context.t('rinkeby')} + +
    + this.props.hideNetworkDropdown()} + onClick={() => this.handleClick('goerli')} + style={dropdownMenuItemStyle} + > + { + providerType === 'goerli' + ? + :
    + } + + + {this.context.t('goerli')} + +
    + this.props.hideNetworkDropdown()} + onClick={() => this.handleClick('localhost')} + style={dropdownMenuItemStyle} + > + { + providerType === 'localhost' + ? + :
    + } + + + {this.context.t('localhost')} + +
    + {this.renderCustomOption(this.props.provider)} + {this.renderCommonRpc(rpcListDetail, this.props.provider)} + this.props.hideNetworkDropdown()} + onClick={() => { setNetworksTabAddMode(true) this.props.history.push(NETWORKS_ROUTE) - }, - style: dropdownMenuItemStyle, - }, - [ - activeNetwork === 'custom' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - isSelected: activeNetwork === 'custom', - innerBorder: '1px solid #9b9b9b', - }), - h('span.network-name-item', { - style: { - color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('customRPC')), - ] - ), - - ]) + }} + style={dropdownMenuItemStyle} + > + { + activeNetwork === 'custom' + ? + :
    + } + + + {this.context.t('customRPC')} + +
    + + ) } NetworkDropdown.prototype.handleClick = function (newProviderType) { @@ -332,43 +335,52 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) { return null } else { const chainId = entry.chainId - return h( - DropdownMenuItem, - { - key: `common${rpc}`, - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setRpcTarget(rpc, chainId, ticker, nickname), - style: { + return ( + this.props.hideNetworkDropdown()} + onClick={() => props.setRpcTarget(rpc, chainId, ticker, nickname)} + style={{ fontSize: '16px', lineHeight: '20px', padding: '12px 0', - }, - }, - [ - currentRpcTarget ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h('i.fa.fa-question-circle.fa-med.menu-icon-circle'), - h('span.network-name-item', { - style: { - color: currentRpcTarget ? '#ffffff' : '#9b9b9b', - }, - }, nickname || rpc), - h('i.fa.fa-times.delete', - { - onClick: (e) => { - e.stopPropagation() - props.delRpcTarget(rpc) - }, - }), - ] + }} + > + { + currentRpcTarget + ? + :
    + } + + + {nickname || rpc} + + { + e.stopPropagation() + props.delRpcTarget(rpc) + }} + /> +
    ) } }) } -NetworkDropdown.prototype.renderCustomOption = function (provider) { +/** + * @return {Component|null} + */ +NetworkDropdown.prototype.renderCustomOption = function NetworkDropdown (provider) { const { rpcTarget, type, ticker, nickname } = provider - const props = this.props - const network = props.network + const network = this.props.network if (type !== 'rpc') { return null @@ -380,27 +392,28 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { return null default: - return h( - DropdownMenuItem, - { - key: rpcTarget, - onClick: () => props.setRpcTarget(rpcTarget, network, ticker, nickname), - closeMenu: () => this.props.hideNetworkDropdown(), - style: { + return ( + this.props.setRpcTarget(rpcTarget, network, ticker, nickname)} + closeMenu={() => this.props.hideNetworkDropdown()} + style={{ fontSize: '16px', lineHeight: '20px', padding: '12px 0', - }, - }, - [ - h('i.fa.fa-check'), - h('i.fa.fa-question-circle.fa-med.menu-icon-circle'), - h('span.network-name-item', { - style: { + }} + > + + + + {nickname || rpcTarget} + + ) } } From 9a1c7e386486f50ff0c6f5330b45668b0a1a1a27 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 11:37:06 -0330 Subject: [PATCH 74/88] Convert Network component to use JSX (#7564) --- ui/app/components/app/network.js | 197 +++++++++++++++++-------------- 1 file changed, 111 insertions(+), 86 deletions(-) diff --git a/ui/app/components/app/network.js b/ui/app/components/app/network.js index d46906a6698b..88204aef7c47 100644 --- a/ui/app/components/app/network.js +++ b/ui/app/components/app/network.js @@ -1,7 +1,6 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect +import PropTypes from 'prop-types' +import React, {Component} from 'react' + const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') @@ -10,8 +9,7 @@ Network.contextTypes = { t: PropTypes.func, } -module.exports = connect()(Network) - +module.exports = Network inherits(Network, Component) @@ -19,15 +17,14 @@ function Network () { Component.call(this) } -Network.prototype.render = function () { - const props = this.props +Network.prototype.render = function Network () { const context = this.context - const networkNumber = props.network + const networkNumber = this.props.network let providerName, providerNick, providerUrl try { - providerName = props.provider.type - providerNick = props.provider.nickname || '' - providerUrl = props.provider.rpcTarget + providerName = this.props.provider.type + providerNick = this.props.provider.nickname || '' + providerUrl = this.props.provider.rpcTarget } catch (e) { providerName = null } @@ -56,96 +53,124 @@ Network.prototype.render = function () { } return ( - h('div.network-component.pointer', { - className: classnames({ +
    { + })} + title={hoverText} + onClick={(event) => { if (!this.props.disabled) { this.props.onClick(event) } - }, - }, [ - (function () { + }} + > + {(function () { switch (iconName) { case 'ethereum-network': - return h('.network-indicator', [ - h(NetworkDropdownIcon, { - backgroundColor: '#038789', // $blue-lagoon - nonSelectBackgroundColor: '#15afb2', - loading: networkNumber === 'loading', - }), - h('.network-name', context.t('mainnet')), - h('.network-indicator__down-arrow'), - ]) + return ( +
    + +
    + {context.t('mainnet')} +
    +
    +
    + ) case 'ropsten-test-network': - return h('.network-indicator', [ - h(NetworkDropdownIcon, { - backgroundColor: '#e91550', // $crimson - nonSelectBackgroundColor: '#ec2c50', - loading: networkNumber === 'loading', - }), - h('.network-name', context.t('ropsten')), - h('.network-indicator__down-arrow'), - ]) + return ( +
    + +
    + {context.t('ropsten')} +
    +
    +
    + ) case 'kovan-test-network': - return h('.network-indicator', [ - h(NetworkDropdownIcon, { - backgroundColor: '#690496', // $purple - nonSelectBackgroundColor: '#b039f3', - loading: networkNumber === 'loading', - }), - h('.network-name', context.t('kovan')), - h('.network-indicator__down-arrow'), - ]) + return ( +
    + +
    + {context.t('kovan')} +
    +
    +
    + ) case 'rinkeby-test-network': - return h('.network-indicator', [ - h(NetworkDropdownIcon, { - backgroundColor: '#ebb33f', // $tulip-tree - nonSelectBackgroundColor: '#ecb23e', - loading: networkNumber === 'loading', - }), - h('.network-name', context.t('rinkeby')), - h('.network-indicator__down-arrow'), - ]) + return ( +
    + +
    + {context.t('rinkeby')} +
    +
    +
    + ) case 'goerli-test-network': - return h('.network-indicator', [ - h(NetworkDropdownIcon, { - backgroundColor: '#3099f2', // $dodger-blue - nonSelectBackgroundColor: '#ecb23e', - loading: networkNumber === 'loading', - }), - h('.network-name', context.t('goerli')), - h('.network-indicator__down-arrow'), - ]) + return ( +
    + +
    {context.t('goerli')}
    +
    +
    + ) default: - return h('.network-indicator', [ - networkNumber === 'loading' - ? h('span.pointer.network-loading-spinner', { - onClick: (event) => this.props.onClick(event), - }, [ - h('img', { - title: context.t('attemptingConnect'), - src: 'images/loading.svg', - }), - ]) - : h('i.fa.fa-question-circle.fa-lg', { - style: { - color: 'rgb(125, 128, 130)', - }, - }), - - h('.network-name', providerName === 'localhost' ? context.t('localhost') : providerNick || context.t('privateNetwork')), - h('.network-indicator__down-arrow'), - ]) + return ( +
    + {networkNumber === 'loading' + ? ( + this.props.onClick(event)} + > + + + ) + : ( + + )} +
    + { + providerName === 'localhost' + ? context.t('localhost') + : providerNick || context.t('privateNetwork') + } +
    +
    +
    + ) } - })(), - ]) + })()} +
    ) } From 629e5501a1842801c48089f100335e1f59aaced2 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 12:37:41 -0330 Subject: [PATCH 75/88] Mark onClick prop as not required for DraggableSeed (#7583) --- .../confirm-seed-phrase/draggable-seed.component.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js b/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js index 7e0652f8f73b..e9bef631e7a5 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js +++ b/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js @@ -13,7 +13,7 @@ class DraggableSeed extends Component { isOver: PropTypes.bool, canDrop: PropTypes.bool, // Own Props - onClick: PropTypes.func.isRequired, + onClick: PropTypes.func, setHoveringIndex: PropTypes.func.isRequired, index: PropTypes.number, draggingSeedIndex: PropTypes.number, @@ -25,6 +25,7 @@ class DraggableSeed extends Component { static defaultProps = { className: '', + onClick: undefined, } componentWillReceiveProps (nextProps) { From 926c8848f123e50ccef9a9e68c64f0f10122ee8f Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 12:38:35 -0330 Subject: [PATCH 76/88] Enable default-case rule for ESLint (#7572) * eslint: Enable default-case rule * Fix missing default cases * Fix tests failing due to incorrect assumptions --- .eslintrc | 1 + app/scripts/lib/buy-eth-url.js | 6 ++++-- app/scripts/lib/ens-ipfs/resolver.js | 2 ++ app/scripts/lib/typed-message-manager.js | 2 ++ app/scripts/migrations/004.js | 1 + development/version-bump.js | 2 ++ test/e2e/helpers.js | 2 ++ test/unit/app/typed-message-manager.spec.js | 12 ++++++------ test/unit/ui/app/actions.spec.js | 7 ++----- .../app/account-menu/account-menu.component.js | 4 +++- 10 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.eslintrc b/.eslintrc index 159fee387d18..2269cb98a243 100644 --- a/.eslintrc +++ b/.eslintrc @@ -44,6 +44,7 @@ }, "rules": { + "default-case": 2, "import/no-unresolved": ["error", { "commonjs": true }], "no-restricted-globals": ["error", "event"], "accessor-pairs": 2, diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index d4b74fa19398..6892364ca059 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -32,8 +32,9 @@ function getBuyEthUrl ({ network, amount, address, service }) { return 'https://github.com/kovan-testnet/faucet' case 'goerli-faucet': return 'https://goerli-faucet.slock.it/' + default: + throw new Error(`Unknown cryptocurrency exchange or faucet: "${service}"`) } - throw new Error(`Unknown cryptocurrency exchange or faucet: "${service}"`) } function getDefaultServiceForNetwork (network) { @@ -48,6 +49,7 @@ function getDefaultServiceForNetwork (network) { return 'kovan-faucet' 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/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js index a0af263bc779..34b1304c1784 100644 --- a/app/scripts/lib/ens-ipfs/resolver.js +++ b/app/scripts/lib/ens-ipfs/resolver.js @@ -66,5 +66,7 @@ function getRegistryForChainId (chainId) { // goerli case 5: return '0x112234455c3a32fd11230c42e7bccd4a84e02010' + default: + return null } } diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index 3f5934299615..e87704712eda 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -163,6 +163,8 @@ module.exports = class TypedMessageManager extends EventEmitter { const activeChainId = parseInt(this.networkController.getNetworkState()) chainId && assert.equal(chainId, activeChainId, `Provided chainId (${chainId}) must match the active chainId (${activeChainId})`) break + default: + assert.fail(`Unknown params.version ${params.version}`) } } diff --git a/app/scripts/migrations/004.js b/app/scripts/migrations/004.js index c0cf600c9139..a1ae823cde2e 100644 --- a/app/scripts/migrations/004.js +++ b/app/scripts/migrations/004.js @@ -23,6 +23,7 @@ module.exports = { type: 'mainnet', } break + // No default } } catch (_) {} return Promise.resolve(safeVersionedData) diff --git a/development/version-bump.js b/development/version-bump.js index 66b6baffeed5..6ae21b782adb 100644 --- a/development/version-bump.js +++ b/development/version-bump.js @@ -40,6 +40,8 @@ function newVersionFrom (manifest, bumpType) { case 'patch': segments[2] += 1 break + default: + throw new Error(`invalid bumpType ${bumpType}`) } return segments.map(String).join('.') diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 9e12ba8da00d..27de882eb79d 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -123,6 +123,8 @@ async function loadExtension (driver, extensionId) { await driver.get(`moz-extension://${extensionId}/home.html`) break } + default: + throw new Error('Unrecognized SELENIUM_BROWSER value') } } diff --git a/test/unit/app/typed-message-manager.spec.js b/test/unit/app/typed-message-manager.spec.js index 3db92d4a386b..959662b9161f 100644 --- a/test/unit/app/typed-message-manager.spec.js +++ b/test/unit/app/typed-message-manager.spec.js @@ -30,12 +30,12 @@ describe('Typed Message Manager', () => { 'EIP712Domain': [ {'name': 'name', 'type': 'string' }, {'name': 'version', 'type': 'string' }, - {'name': 'chainId', ' type': 'uint256' }, - {'name': 'verifyingContract', ' type': 'address' }, + {'name': 'chainId', 'type': 'uint256' }, + {'name': 'verifyingContract', 'type': 'address' }, ], 'Person': [ {'name': 'name', 'type': 'string' }, - {'name': 'wallet', ' type': 'address' }, + {'name': 'wallet', 'type': 'address' }, ], 'Mail': [ {'name': 'from', 'type': 'Person' }, @@ -64,7 +64,7 @@ describe('Typed Message Manager', () => { }), } - typedMessageManager.addUnapprovedMessage(msgParamsV3, 'V3') + typedMessageManager.addUnapprovedMessage(msgParamsV3, null, 'V3') typedMsgs = typedMessageManager.getUnapprovedMsgs() messages = typedMessageManager.messages msgId = Object.keys(typedMsgs)[0] @@ -73,7 +73,7 @@ describe('Typed Message Manager', () => { }) it('supports version 1 of signedTypedData', () => { - typedMessageManager.addUnapprovedMessage(msgParamsV1, 'V1') + typedMessageManager.addUnapprovedMessage(msgParamsV1, null, 'V1') assert.equal(messages[messages.length - 1].msgParams.data, msgParamsV1.data) }) @@ -87,7 +87,7 @@ describe('Typed Message Manager', () => { it('validates params', function () { assert.doesNotThrow(() => { - typedMessageManager.validateParams(messages[0]) + typedMessageManager.validateParams(messages[0].msgParams) }, 'Does not throw with valid parameters') }) diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js index 9ed21e729c84..fffc14ab8cf1 100644 --- a/test/unit/ui/app/actions.spec.js +++ b/test/unit/ui/app/actions.spec.js @@ -755,7 +755,6 @@ describe('Actions', () => { 'domain': { 'name': 'Ether Mainl', 'version': '1', - 'chainId': 1, 'verifyingContract': '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', }, 'message': { @@ -773,11 +772,12 @@ describe('Actions', () => { } beforeEach(() => { - metamaskController.newUnsignedTypedMessage(msgParamsV3, 'V3') + metamaskController.newUnsignedTypedMessage(msgParamsV3, null, 'V3') messages = metamaskController.typedMessageManager.getUnapprovedMsgs() typedMessages = metamaskController.typedMessageManager.messages msgId = Object.keys(messages)[0] typedMessages[0].msgParams.metamaskId = parseInt(msgId) + signTypedMsgSpy = sinon.stub(background, 'signTypedMessage') }) afterEach(() => { @@ -786,7 +786,6 @@ describe('Actions', () => { it('calls signTypedMsg in background with no error', () => { const store = mockStore() - signTypedMsgSpy = sinon.stub(background, 'signTypedMessage') store.dispatch(actions.signTypedMsg(msgParamsV3)) assert(signTypedMsgSpy.calledOnce) @@ -801,8 +800,6 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, ] - signTypedMsgSpy = sinon.stub(background, 'signTypedMessage') - signTypedMsgSpy.callsFake((_, callback) => { callback(new Error('error')) }) 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 1b81e33a26b9..7be2bc5ddccc 100644 --- a/ui/app/components/app/account-menu/account-menu.component.js +++ b/ui/app/components/app/account-menu/account-menu.component.js @@ -156,9 +156,11 @@ export default class AccountMenu extends PureComponent { case 'Simple Key Pair': label = t('imported') break + default: + return null } - return label && ( + return (
    { label }
    From 359be03db8fd551549359e8143baa6a52a02dd4b Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 12:44:02 -0330 Subject: [PATCH 77/88] Split DepositEtherModal into container and component files (#7565) --- .../app/modals/deposit-ether-modal.js | 213 ------------------ .../deposit-ether-modal.component.js | 167 ++++++++++++++ .../deposit-ether-modal.container.js | 34 +++ .../app/modals/deposit-ether-modal/index.js | 1 + ui/app/components/app/modals/modal.js | 2 +- 5 files changed, 203 insertions(+), 214 deletions(-) delete mode 100644 ui/app/components/app/modals/deposit-ether-modal.js create mode 100644 ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js create mode 100644 ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.container.js create mode 100644 ui/app/components/app/modals/deposit-ether-modal/index.js diff --git a/ui/app/components/app/modals/deposit-ether-modal.js b/ui/app/components/app/modals/deposit-ether-modal.js deleted file mode 100644 index f71e0619e8fe..000000000000 --- a/ui/app/components/app/modals/deposit-ether-modal.js +++ /dev/null @@ -1,213 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const actions = require('../../../store/actions') -const { getNetworkDisplayName } = require('../../../../../app/scripts/controllers/network/util') - -import Button from '../../ui/button' - -let DIRECT_DEPOSIT_ROW_TITLE -let DIRECT_DEPOSIT_ROW_TEXT -let WYRE_ROW_TITLE -let WYRE_ROW_TEXT -let FAUCET_ROW_TITLE -let COINSWITCH_ROW_TITLE -let COINSWITCH_ROW_TEXT - -function mapStateToProps (state) { - return { - network: state.metamask.network, - address: state.metamask.selectedAddress, - } -} - -function mapDispatchToProps (dispatch) { - return { - toWyre: (address) => { - dispatch(actions.buyEth({ service: 'wyre', address, amount: 0 })) - }, - toCoinSwitch: (address) => { - dispatch(actions.buyEth({ service: 'coinswitch', address })) - }, - hideModal: () => { - dispatch(actions.hideModal()) - }, - hideWarning: () => { - dispatch(actions.hideWarning()) - }, - showAccountDetailModal: () => { - dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' })) - }, - toFaucet: network => dispatch(actions.buyEth({ network })), - } -} - -inherits(DepositEtherModal, Component) -function DepositEtherModal (_, context) { - Component.call(this) - - // need to set after i18n locale has loaded - DIRECT_DEPOSIT_ROW_TITLE = context.t('directDepositEther') - DIRECT_DEPOSIT_ROW_TEXT = context.t('directDepositEtherExplainer') - WYRE_ROW_TITLE = context.t('buyWithWyre') - WYRE_ROW_TEXT = context.t('buyWithWyreDescription') - FAUCET_ROW_TITLE = context.t('testFaucet') - COINSWITCH_ROW_TITLE = context.t('buyCoinSwitch') - COINSWITCH_ROW_TEXT = context.t('buyCoinSwitchExplainer') -} - -DepositEtherModal.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal) - - -DepositEtherModal.prototype.facuetRowText = function (networkName) { - return this.context.t('getEtherFromFaucet', [networkName]) -} - -DepositEtherModal.prototype.renderRow = function ({ - logo, - title, - text, - buttonLabel, - onButtonClick, - hide, - className, - hideButton, - hideTitle, - onBackClick, - showBackButton, -}) { - if (hide) { - return null - } - - return h('div', { - className: className || 'deposit-ether-modal__buy-row', - }, [ - - onBackClick && showBackButton && h('div.deposit-ether-modal__buy-row__back', { - onClick: onBackClick, - }, [ - - h('i.fa.fa-arrow-left.cursor-pointer'), - - ]), - - h('div.deposit-ether-modal__buy-row__logo-container', [logo]), - - h('div.deposit-ether-modal__buy-row__description', [ - - !hideTitle && h('div.deposit-ether-modal__buy-row__description__title', [title]), - - h('div.deposit-ether-modal__buy-row__description__text', [text]), - - ]), - - !hideButton && h('div.deposit-ether-modal__buy-row__button', [ - h(Button, { - type: 'secondary', - className: 'deposit-ether-modal__deposit-button', - large: true, - onClick: onButtonClick, - }, [buttonLabel]), - ]), - - ]) -} - -DepositEtherModal.prototype.render = function () { - const { network, toWyre, toCoinSwitch, address, toFaucet } = this.props - - const isTestNetwork = ['3', '4', '5', '42'].find(n => n === network) - const networkName = getNetworkDisplayName(network) - - return h('div.page-container.page-container--full-width.page-container--full-height', {}, [ - - h('div.page-container__header', [ - - h('div.page-container__title', [this.context.t('depositEther')]), - - h('div.page-container__subtitle', [ - this.context.t('needEtherInWallet'), - ]), - - h('div.page-container__header-close', { - onClick: () => { - this.props.hideWarning() - this.props.hideModal() - }, - }), - - ]), - - h('.page-container__content', {}, [ - - h('div.deposit-ether-modal__buy-rows', [ - - this.renderRow({ - logo: h('img.deposit-ether-modal__logo', { - src: './images/deposit-eth.svg', - style: { - height: '75px', - width: '75px', - }, - }), - title: DIRECT_DEPOSIT_ROW_TITLE, - text: DIRECT_DEPOSIT_ROW_TEXT, - buttonLabel: this.context.t('viewAccount'), - onButtonClick: () => this.goToAccountDetailsModal(), - }), - - this.renderRow({ - logo: h('i.fa.fa-tint.fa-2x'), - title: FAUCET_ROW_TITLE, - text: this.facuetRowText(networkName), - buttonLabel: this.context.t('getEther'), - onButtonClick: () => toFaucet(network), - hide: !isTestNetwork, - }), - - this.renderRow({ - logo: h('div.deposit-ether-modal__logo', { - style: { - backgroundImage: 'url(\'./images/wyre.svg\')', - height: '40px', - }, - }), - title: WYRE_ROW_TITLE, - text: WYRE_ROW_TEXT, - buttonLabel: this.context.t('continueToWyre'), - onButtonClick: () => toWyre(address), - hide: isTestNetwork, - }), - - this.renderRow({ - logo: h('div.deposit-ether-modal__logo', { - style: { - backgroundImage: 'url(\'./images/coinswitch_logo.png\')', - height: '40px', - }, - }), - title: COINSWITCH_ROW_TITLE, - text: COINSWITCH_ROW_TEXT, - buttonLabel: this.context.t('continueToCoinSwitch'), - onButtonClick: () => toCoinSwitch(address), - hide: isTestNetwork, - }), - - ]), - - ]), - ]) -} - -DepositEtherModal.prototype.goToAccountDetailsModal = function () { - this.props.hideWarning() - this.props.hideModal() - this.props.showAccountDetailModal() -} diff --git a/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js b/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js new file mode 100644 index 000000000000..c251aee667c7 --- /dev/null +++ b/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js @@ -0,0 +1,167 @@ +import PropTypes from 'prop-types' +import React, {Component} from 'react' +import {getNetworkDisplayName} from '../../../../../../app/scripts/controllers/network/util' +import Button from '../../../ui/button' + +export default class DepositEtherModal extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + network: PropTypes.string.isRequired, + toWyre: PropTypes.func.isRequired, + toCoinSwitch: PropTypes.func.isRequired, + address: PropTypes.string.isRequired, + toFaucet: PropTypes.func.isRequired, + hideWarning: PropTypes.func.isRequired, + hideModal: PropTypes.func.isRequired, + showAccountDetailModal: PropTypes.func.isRequired, + } + + faucetRowText = (networkName) => { + return this.context.t('getEtherFromFaucet', [networkName]) + } + + goToAccountDetailsModal = () => { + this.props.hideWarning() + this.props.hideModal() + this.props.showAccountDetailModal() + } + + renderRow ({ + logo, + title, + text, + buttonLabel, + onButtonClick, + hide, + className, + hideButton, + hideTitle, + onBackClick, + showBackButton, + }) { + if (hide) { + return null + } + + return ( +
    + {onBackClick && showBackButton && ( +
    + +
    + )} +
    {logo}
    +
    + {!hideTitle && ( +
    {title}
    + )} +
    {text}
    +
    + {!hideButton && ( +
    + +
    + )} +
    + ) + } + + render () { + const { network, toWyre, toCoinSwitch, address, toFaucet } = this.props + + const isTestNetwork = ['3', '4', '5', '42'].find(n => n === network) + const networkName = getNetworkDisplayName(network) + + return ( +
    +
    +
    + {this.context.t('depositEther')} +
    +
    + {this.context.t('needEtherInWallet')} +
    +
    { + this.props.hideWarning() + this.props.hideModal() + }} + /> +
    +
    +
    + {this.renderRow({ + logo: ( + + ), + title: this.context.t('directDepositEther'), + text: this.context.t('directDepositEtherExplainer'), + buttonLabel: this.context.t('viewAccount'), + onButtonClick: () => this.goToAccountDetailsModal(), + })} + {this.renderRow({ + logo: , + title: this.context.t('testFaucet'), + text: this.faucetRowText(networkName), + buttonLabel: this.context.t('getEther'), + onButtonClick: () => toFaucet(network), + hide: !isTestNetwork, + })} + {this.renderRow({ + logo: ( +
    + ), + title: this.context.t('buyWithWyre'), + text: this.context.t('buyWithWyreDescription'), + buttonLabel: this.context.t('continueToWyre'), + onButtonClick: () => toWyre(address), + hide: isTestNetwork, + })} + {this.renderRow({ + logo: ( +
    + ), + title: this.context.t('buyCoinSwitch'), + text: this.context.t('buyCoinSwitchExplainer'), + buttonLabel: this.context.t('continueToCoinSwitch'), + onButtonClick: () => toCoinSwitch(address), + hide: isTestNetwork, + })} +
    +
    +
    + ) + } +} diff --git a/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.container.js b/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.container.js new file mode 100644 index 000000000000..cccbe76671af --- /dev/null +++ b/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.container.js @@ -0,0 +1,34 @@ +import { connect } from 'react-redux' +import { buyEth, hideModal, showModal, hideWarning } from '../../../../store/actions' +import DepositEtherModal from './deposit-ether-modal.component' + +function mapStateToProps (state) { + return { + network: state.metamask.network, + address: state.metamask.selectedAddress, + } +} + +function mapDispatchToProps (dispatch) { + return { + toWyre: (address) => { + dispatch(buyEth({ service: 'wyre', address, amount: 0 })) + }, + toCoinSwitch: (address) => { + dispatch(buyEth({ service: 'coinswitch', address })) + }, + hideModal: () => { + dispatch(hideModal()) + }, + hideWarning: () => { + dispatch(hideWarning()) + }, + showAccountDetailModal: () => { + dispatch(showModal({ name: 'ACCOUNT_DETAILS' })) + }, + toFaucet: network => dispatch(buyEth({ network })), + } +} + + +export default connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal) diff --git a/ui/app/components/app/modals/deposit-ether-modal/index.js b/ui/app/components/app/modals/deposit-ether-modal/index.js new file mode 100644 index 000000000000..01a262a73ea7 --- /dev/null +++ b/ui/app/components/app/modals/deposit-ether-modal/index.js @@ -0,0 +1 @@ +export { default } from './deposit-ether-modal.container' diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js index 27162bdd506c..df6402b346a1 100644 --- a/ui/app/components/app/modals/modal.js +++ b/ui/app/components/app/modals/modal.js @@ -10,7 +10,7 @@ const { getEnvironmentType } = require('../../../../../app/scripts/lib/util') const { ENVIRONMENT_TYPE_POPUP } = require('../../../../../app/scripts/lib/enums') // Modal Components -const DepositEtherModal = require('./deposit-ether-modal') +import DepositEtherModal from './deposit-ether-modal' import AccountDetailsModal from './account-details-modal' const ExportPrivateKeyModal = require('./export-private-key-modal').default const HideTokenConfirmationModal = require('./hide-token-confirmation-modal') From 867dcc48ee09d7b685c44468a2e2d7b65c7d15f9 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 15:49:38 -0330 Subject: [PATCH 78/88] Clean up Item JSX (#7584) --- ui/app/components/app/dropdowns/components/menu.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ui/app/components/app/dropdowns/components/menu.js b/ui/app/components/app/dropdowns/components/menu.js index 9bb919c6d082..669a50c63b11 100644 --- a/ui/app/components/app/dropdowns/components/menu.js +++ b/ui/app/components/app/dropdowns/components/menu.js @@ -38,10 +38,6 @@ function Item (props) { const itemClassName = classnames('menu__item', className, { 'menu__item--clickable': Boolean(onClick), }) - const iconComponent = icon ?
    {icon}
    : null - const textComponent = text ?
    {text}
    : null - const subTextComponent = subText ?
    {subText}
    : null - return children ?
    {children}
    : ( @@ -49,7 +45,9 @@ function Item (props) { className={itemClassName} onClick={onClick} > - {[ iconComponent, textComponent, subTextComponent ].filter(d => Boolean(d))} + {icon ?
    {icon}
    : null} + {text ?
    {text}
    : null} + {subText ?
    {subText}
    : null}
    ) } From cfd041b3648dc1c170d7a69d0976dac8b63a3292 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 18:49:48 -0330 Subject: [PATCH 79/88] Convert modals to use JSX (#7566) --- ui/app/components/app/modals/modal.js | 95 +++++++++++---------------- 1 file changed, 39 insertions(+), 56 deletions(-) diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js index df6402b346a1..28395b21fb84 100644 --- a/ui/app/components/app/modals/modal.js +++ b/ui/app/components/app/modals/modal.js @@ -1,5 +1,5 @@ -const Component = require('react').Component -const h = require('react-hyperscript') +import React, { Component } from 'react' + const inherits = require('util').inherits const connect = require('react-redux').connect const FadeModal = require('boron').FadeModal @@ -80,9 +80,7 @@ const accountModalStyle = { const MODALS = { DEPOSIT_ETHER: { - contents: [ - h(DepositEtherModal, {}, []), - ], + contents: , onHide: (props) => props.hideWarning(), mobileModalStyle: { width: '100%', @@ -115,9 +113,7 @@ const MODALS = { }, ADD_TO_ADDRESSBOOK: { - contents: [ - h(AddToAddressBookModal, {}, []), - ], + contents: , mobileModalStyle: { width: '95%', top: '10%', @@ -144,23 +140,17 @@ const MODALS = { }, ACCOUNT_DETAILS: { - contents: [ - h(AccountDetailsModal, {}, []), - ], + contents: , ...accountModalStyle, }, EXPORT_PRIVATE_KEY: { - contents: [ - h(ExportPrivateKeyModal, {}, []), - ], + contents: , ...accountModalStyle, }, HIDE_TOKEN_CONFIRMATION: { - contents: [ - h(HideTokenConfirmationModal, {}, []), - ], + contents: , mobileModalStyle: { width: '95%', top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', @@ -172,7 +162,7 @@ const MODALS = { }, CLEAR_APPROVED_ORIGINS: { - contents: h(ClearApprovedOrigins), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -185,7 +175,7 @@ const MODALS = { }, METAMETRICS_OPT_IN_MODAL: { - contents: h(MetaMetricsOptInModal), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, width: '100%', @@ -202,12 +192,9 @@ const MODALS = { }, GAS_PRICE_INFO_MODAL: { - contents: [ - h(NotifcationModal, { - header: 'gasPriceNoDenom', - message: 'gasPriceInfoModalContent', - }), - ], + // TODO Remove this once our i18n unused messages script detection is better + // eslint-disable-next-line react/jsx-curly-brace-presence + contents: , mobileModalStyle: { width: '95%', top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', @@ -219,12 +206,9 @@ const MODALS = { }, GAS_LIMIT_INFO_MODAL: { - contents: [ - h(NotifcationModal, { - header: 'gasLimit', - message: 'gasLimitInfoModalContent', - }), - ], + // TODO Remove this once our i18n unused messages script detection is better + // eslint-disable-next-line react/jsx-curly-brace-presence + contents: , mobileModalStyle: { width: '95%', top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', @@ -236,7 +220,7 @@ const MODALS = { }, CONFIRM_RESET_ACCOUNT: { - contents: h(ConfirmResetAccount), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -249,7 +233,7 @@ const MODALS = { }, CONFIRM_REMOVE_ACCOUNT: { - contents: h(ConfirmRemoveAccount), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -262,7 +246,7 @@ const MODALS = { }, CONFIRM_DELETE_NETWORK: { - contents: h(ConfirmDeleteNetwork), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -275,9 +259,7 @@ const MODALS = { }, CUSTOMIZE_GAS: { - contents: [ - h(ConfirmCustomizeGasModal), - ], + contents: , mobileModalStyle: { width: '100vw', height: '100vh', @@ -306,7 +288,7 @@ const MODALS = { }, EDIT_APPROVAL_PERMISSION: { - contents: h(EditApprovalPermission), + contents: , mobileModalStyle: { width: '95vw', height: '100vh', @@ -332,7 +314,7 @@ const MODALS = { TRANSACTION_CONFIRMED: { disableBackdropClick: true, - contents: h(TransactionConfirmed), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -345,7 +327,7 @@ const MODALS = { }, QR_SCANNER: { - contents: h(QRScanner), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -358,7 +340,7 @@ const MODALS = { }, CANCEL_TRANSACTION: { - contents: h(CancelTransaction), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -371,7 +353,7 @@ const MODALS = { }, REJECT_TRANSACTIONS: { - contents: h(RejectTransactions), + contents: , mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -430,25 +412,26 @@ Modal.prototype.render = function () { const modalStyle = modal[isMobileView() ? 'mobileModalStyle' : 'laptopModalStyle'] const contentStyle = modal.contentStyle || {} - return h(FadeModal, - { - className: 'modal', - keyboard: false, - onHide: () => { + return ( + { if (modal.onHide) { modal.onHide(this.props) } this.onHide(modal.customOnHideOpts) - }, - ref: (ref) => { + }} + ref={(ref) => { this.modalRef = ref - }, - modalStyle, - contentStyle, - backdropStyle: BACKDROPSTYLE, - closeOnClick: !disableBackdropClick, - }, - children, + }} + modalStyle={modalStyle} + contentStyle={contentStyle} + backdropStyle={BACKDROPSTYLE} + closeOnClick={!disableBackdropClick} + > + {children} + ) } From 13a1de061dd1e8e72a64676e1d0ef8ce4afc9d62 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Nov 2019 18:50:00 -0330 Subject: [PATCH 80/88] Allow translation keys to be in single- or double-quotes (#7588) --- development/verify-locale-strings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index aa0c4503fd1c..c6875b36c99e 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -161,11 +161,11 @@ async function verifyEnglishLocale (fix = false) { const englishLocale = await getLocale('en') const javascriptFiles = await findJavascriptFiles(path.resolve(__dirname, '..', 'ui')) - const regex = /'(\w+)'/g + const regex = /'(\w+)'|"(\w+)"/g const usedMessages = new Set() for await (const fileContents of getFileContents(javascriptFiles)) { for (const match of matchAll.call(fileContents, regex)) { - usedMessages.add(match[1]) + usedMessages.add(match[1] || match[2]) } } From f61b068bd2d658adf3cf82ba4ae26aa70bc093a8 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Thu, 28 Nov 2019 13:38:31 -0330 Subject: [PATCH 81/88] Drop eslint-disable and TODO comments from Modal component (#7589) --- ui/app/components/app/modals/modal.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js index 28395b21fb84..02690722b676 100644 --- a/ui/app/components/app/modals/modal.js +++ b/ui/app/components/app/modals/modal.js @@ -192,9 +192,7 @@ const MODALS = { }, GAS_PRICE_INFO_MODAL: { - // TODO Remove this once our i18n unused messages script detection is better - // eslint-disable-next-line react/jsx-curly-brace-presence - contents: , + contents: , mobileModalStyle: { width: '95%', top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', @@ -206,9 +204,7 @@ const MODALS = { }, GAS_LIMIT_INFO_MODAL: { - // TODO Remove this once our i18n unused messages script detection is better - // eslint-disable-next-line react/jsx-curly-brace-presence - contents: , + contents: , mobileModalStyle: { width: '95%', top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', From c7f320b087ff912bdef88a083e417a9157eb08df Mon Sep 17 00:00:00 2001 From: Erik Marks <25517051+rekmarks@users.noreply.github.com> Date: Fri, 29 Nov 2019 10:39:45 -0800 Subject: [PATCH 82/88] add locale fix script (#7580) --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 7b51c827f7ab..f7df8b7e57eb 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "lint:changed:fix": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' --regexp='[.]json$' | tr '\\n' '\\0' | xargs -0 eslint --fix", "lint:shellcheck": "shellcheck --version && find . -type f -name '*.sh' ! -path './node_modules/*' -print0 | xargs -0 shellcheck", "verify-locales": "node ./development/verify-locale-strings.js", + "verify-locales:fix": "node ./development/verify-locale-strings.js --fix", "mozilla-lint": "addons-linter dist/firefox", "watch": "cross-env METAMASK_ENV=test mocha --watch --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/app/**/*.test.js\"", "devtools:react": "react-devtools", From 04064d5d198e082fa43d28cee462ddc962c79740 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 3 Dec 2019 11:22:01 -0330 Subject: [PATCH 83/88] Enable no-var rule for ESLint (#7590) * eslint: Enable no-var rule * yarn lint --fix --- .eslintrc | 1 + app/scripts/controllers/network/network.js | 4 +- app/scripts/edge-encryptor.js | 28 ++-- app/scripts/lib/cleanErrorStack.js | 4 +- app/scripts/lib/message-manager.js | 6 +- app/scripts/lib/personal-message-manager.js | 6 +- app/scripts/lib/typed-message-manager.js | 6 +- development/announcer.js | 12 +- development/mock-dev.js | 2 +- development/sourcemap-validator.js | 4 +- test/e2e/web3.spec.js | 32 ++--- test/helper.js | 4 +- test/lib/mock-encryptor.js | 4 +- test/lib/mock-simple-keychain.js | 4 +- test/lib/react-trigger-change.js | 24 ++-- test/unit/actions/config_test.js | 16 +-- .../unit/actions/set_selected_account_test.js | 18 +-- test/unit/actions/tx_test.js | 4 +- test/unit/actions/view_info_test.js | 14 +- test/unit/actions/warning_test.js | 12 +- .../app/controllers/detect-tokens-test.js | 10 +- .../preferences-controller-test.js | 12 +- .../controllers/transactions/tx-utils-test.js | 4 +- test/unit/app/edge-encryptor-test.js | 4 +- test/unit/app/message-manager-test.js | 16 +-- .../unit/app/personal-message-manager-test.js | 28 ++-- test/unit/reducers/unlock_vault_test.js | 10 +- test/unit/util_test.js | 122 +++++++++--------- test/web3/schema.js | 4 +- test/web3/web3.js | 2 +- ui/app/components/app/account-panel.js | 10 +- ui/app/components/app/menu-droppo.js | 4 +- ui/app/components/ui/fiat-value.js | 4 +- ui/app/components/ui/mascot.js | 4 +- ui/app/ducks/app/app.js | 4 +- ui/app/ducks/metamask/metamask.js | 4 +- ui/app/helpers/utils/util.js | 80 ++++++------ ui/app/pages/confirm-transaction/conf-tx.js | 8 +- ui/app/pages/routes/index.js | 2 +- ui/app/store/actions.js | 20 +-- ui/index.js | 2 +- ui/lib/icon-factory.js | 16 +-- ui/lib/persistent-form.js | 4 +- 43 files changed, 290 insertions(+), 289 deletions(-) diff --git a/.eslintrc b/.eslintrc index 2269cb98a243..b8a5c409497e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -143,6 +143,7 @@ "no-useless-computed-key": 2, "no-useless-constructor": 2, "no-useless-escape": 2, + "no-var": 2, "no-whitespace-before-property": 2, "no-with": 2, "one-var": [2, { "initialized": "never" }], diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index f1be914bb545..d78f92f93d6b 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -198,7 +198,7 @@ module.exports = class NetworkController extends EventEmitter { }) this._setNetworkClient(networkClient) // setup networkConfig - var settings = { + const settings = { ticker: 'ETH', } this.networkConfig.putState(settings) @@ -221,7 +221,7 @@ module.exports = class NetworkController extends EventEmitter { nickname, } // setup networkConfig - var settings = { + let settings = { network: chainId, } settings = extend(settings, networks.networkList['rpc']) diff --git a/app/scripts/edge-encryptor.js b/app/scripts/edge-encryptor.js index 012672ed2327..d086a854de19 100644 --- a/app/scripts/edge-encryptor.js +++ b/app/scripts/edge-encryptor.js @@ -14,17 +14,17 @@ class EdgeEncryptor { * @returns {Promise} Promise resolving to an object with ciphertext */ encrypt (password, dataObject) { - var salt = this._generateSalt() + const salt = this._generateSalt() return this._keyFromPassword(password, salt) .then(function (key) { - var data = JSON.stringify(dataObject) - var dataBuffer = Unibabel.utf8ToBuffer(data) - var vector = global.crypto.getRandomValues(new Uint8Array(16)) - var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector) + const data = JSON.stringify(dataObject) + const dataBuffer = Unibabel.utf8ToBuffer(data) + const vector = global.crypto.getRandomValues(new Uint8Array(16)) + const resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector) - var buffer = new Uint8Array(resultbuffer) - var vectorStr = Unibabel.bufferToBase64(vector) - var vaultStr = Unibabel.bufferToBase64(buffer) + const buffer = new Uint8Array(resultbuffer) + const vectorStr = Unibabel.bufferToBase64(vector) + const vaultStr = Unibabel.bufferToBase64(buffer) return JSON.stringify({ data: vaultStr, iv: vectorStr, @@ -48,7 +48,7 @@ class EdgeEncryptor { const encryptedData = Unibabel.base64ToBuffer(payload.data) const vector = Unibabel.base64ToBuffer(payload.iv) return new Promise((resolve, reject) => { - var result + let result try { result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector) } catch (err) { @@ -72,12 +72,12 @@ class EdgeEncryptor { */ _keyFromPassword (password, salt) { - var passBuffer = Unibabel.utf8ToBuffer(password) - var saltBuffer = Unibabel.base64ToBuffer(salt) + const passBuffer = Unibabel.utf8ToBuffer(password) + const saltBuffer = Unibabel.base64ToBuffer(salt) const iterations = 10000 const length = 32 // SHA256 hash size return new Promise((resolve) => { - var key = asmcrypto.Pbkdf2HmacSha256(passBuffer, saltBuffer, iterations, length) + const key = asmcrypto.Pbkdf2HmacSha256(passBuffer, saltBuffer, iterations, length) resolve(key) }) } @@ -89,9 +89,9 @@ class EdgeEncryptor { * @returns {string} Randomized base64 encoded data */ _generateSalt (byteCount = 32) { - var view = new Uint8Array(byteCount) + const view = new Uint8Array(byteCount) global.crypto.getRandomValues(view) - var b64encoded = btoa(String.fromCharCode.apply(null, view)) + const b64encoded = btoa(String.fromCharCode.apply(null, view)) return b64encoded } } diff --git a/app/scripts/lib/cleanErrorStack.js b/app/scripts/lib/cleanErrorStack.js index 8adf55db707b..58f7ccfdf158 100644 --- a/app/scripts/lib/cleanErrorStack.js +++ b/app/scripts/lib/cleanErrorStack.js @@ -4,10 +4,10 @@ * @returns {Error} Error with clean stack trace. */ function cleanErrorStack (err) { - var name = err.name + let name = err.name name = (name === undefined) ? 'Error' : String(name) - var msg = err.message + let msg = err.message msg = (msg === undefined) ? '' : String(msg) if (name === '') { diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index 9f087abad968..c66b3a9e1afe 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -109,9 +109,9 @@ module.exports = class MessageManager extends EventEmitter { } msgParams.data = normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data - var time = (new Date()).getTime() - var msgId = createId() - var msgData = { + const time = (new Date()).getTime() + const msgId = createId() + const msgData = { id: msgId, msgParams: msgParams, time: time, diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index eea8e286d107..c538ef17f023 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -117,9 +117,9 @@ module.exports = class PersonalMessageManager extends EventEmitter { } msgParams.data = this.normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data - var time = (new Date()).getTime() - var msgId = createId() - var msgData = { + const time = (new Date()).getTime() + const msgId = createId() + const msgData = { id: msgId, msgParams: msgParams, time: time, diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index e87704712eda..7a73e7761378 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -111,9 +111,9 @@ module.exports = class TypedMessageManager extends EventEmitter { log.debug(`TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) // create txData obj with parameters and meta data - var time = (new Date()).getTime() - var msgId = createId() - var msgData = { + const time = (new Date()).getTime() + const msgId = createId() + const msgData = { id: msgId, msgParams: msgParams, time: time, diff --git a/development/announcer.js b/development/announcer.js index ea1bfdd3663e..8b0c1de272c4 100644 --- a/development/announcer.js +++ b/development/announcer.js @@ -1,11 +1,11 @@ -var manifest = require('../app/manifest.json') -var version = manifest.version +const manifest = require('../app/manifest.json') +const version = manifest.version -var fs = require('fs') -var path = require('path') -var changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md')).toString() +const fs = require('fs') +const path = require('path') +const changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md')).toString() -var log = changelog.split(version)[1].split('##')[0].trim() +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/mock-dev.js b/development/mock-dev.js index cbb4368907a8..16fdd0273a43 100644 --- a/development/mock-dev.js +++ b/development/mock-dev.js @@ -94,7 +94,7 @@ function modifyBackgroundConnection (backgroundConnectionModifier) { } // parse opts -var store = configureStore(firstState) +const store = configureStore(firstState) // start app startApp() diff --git a/development/sourcemap-validator.js b/development/sourcemap-validator.js index 44336df9ec42..22c448862af9 100644 --- a/development/sourcemap-validator.js +++ b/development/sourcemap-validator.js @@ -96,8 +96,8 @@ async function validateSourcemapForFile ({ buildName }) { } function indicesOf (substring, string) { - var a = [] - var i = -1 + const a = [] + let i = -1 while ((i = string.indexOf(substring, i + 1)) >= 0) { a.push(i) } diff --git a/test/e2e/web3.spec.js b/test/e2e/web3.spec.js index f576b397fb90..8c0853755ed7 100644 --- a/test/e2e/web3.spec.js +++ b/test/e2e/web3.spec.js @@ -30,7 +30,7 @@ describe('Using MetaMask with an existing account', function () { await delay(largeDelayMs) const [results] = await findElements(driver, By.css('#results')) const resulttext = await results.getText() - var parsedData = JSON.parse(resulttext) + const parsedData = JSON.parse(resulttext) return (parsedData) @@ -153,14 +153,14 @@ describe('Using MetaMask with an existing account', function () { it('testing hexa methods', async () => { - var List = await driver.findElements(By.className('hexaNumberMethods')) + const List = await driver.findElements(By.className('hexaNumberMethods')) for (let i = 0; i < List.length; i++) { try { - var parsedData = await button(List[i]) + const parsedData = await button(List[i]) console.log(parsedData) - var result = parseInt(parsedData.result, 16) + const result = parseInt(parsedData.result, 16) assert.equal((typeof result === 'number'), true) await delay(regularDelayMs) @@ -174,14 +174,14 @@ describe('Using MetaMask with an existing account', function () { it('testing booleanMethods', async () => { - var List = await driver.findElements(By.className('booleanMethods')) + const List = await driver.findElements(By.className('booleanMethods')) for (let i = 0; i < List.length; i++) { try { - var parsedData = await button(List[i]) + const parsedData = await button(List[i]) console.log(parsedData) - var result = parsedData.result + const result = parsedData.result assert.equal(result, false) await delay(regularDelayMs) @@ -197,16 +197,16 @@ describe('Using MetaMask with an existing account', function () { it('testing transactionMethods', async () => { - var List = await driver.findElements(By.className('transactionMethods')) + const List = await driver.findElements(By.className('transactionMethods')) for (let i = 0; i < List.length; i++) { try { - var parsedData = await button(List[i]) + const parsedData = await button(List[i]) console.log(parsedData.result.blockHash) - var result = [] + const result = [] result.push(parseInt(parsedData.result.blockHash, 16)) result.push(parseInt(parsedData.result.blockNumber, 16)) result.push(parseInt(parsedData.result.gas, 16)) @@ -239,17 +239,17 @@ describe('Using MetaMask with an existing account', function () { it('testing blockMethods', async () => { - var List = await driver.findElements(By.className('blockMethods')) + const List = await driver.findElements(By.className('blockMethods')) for (let i = 0; i < List.length; i++) { try { - var parsedData = await button(List[i]) + const parsedData = await button(List[i]) console.log(JSON.stringify(parsedData) + i) console.log(parsedData.result.parentHash) - var result = parseInt(parsedData.result.parentHash, 16) + const result = parseInt(parsedData.result.parentHash, 16) assert.equal((typeof result === 'number'), true) await delay(regularDelayMs) @@ -265,9 +265,9 @@ describe('Using MetaMask with an existing account', function () { it('testing methods', async () => { - var List = await driver.findElements(By.className('methods')) - var parsedData - var result + const List = await driver.findElements(By.className('methods')) + let parsedData + let result for (let i = 0; i < List.length; i++) { try { diff --git a/test/helper.js b/test/helper.js index a49249062c12..bea0b326c05c 100644 --- a/test/helper.js +++ b/test/helper.js @@ -17,7 +17,7 @@ server.listen(8545, () => { }) // logging util -var log = require('loglevel') +const log = require('loglevel') log.setDefaultLevel(5) global.log = log @@ -62,7 +62,7 @@ function enableFailureOnUnhandledPromiseRejection () { throw evt.detail.reason }) } else { - var oldOHR = window.onunhandledrejection + const oldOHR = window.onunhandledrejection window.onunhandledrejection = function (evt) { if (typeof oldOHR === 'function') { oldOHR.apply(this, arguments) diff --git a/test/lib/mock-encryptor.js b/test/lib/mock-encryptor.js index 23ab2404fe20..0f70b5b3c2ca 100644 --- a/test/lib/mock-encryptor.js +++ b/test/lib/mock-encryptor.js @@ -1,5 +1,5 @@ -var mockHex = '0xabcdef0123456789' -var mockKey = Buffer.alloc(32) +const mockHex = '0xabcdef0123456789' +const mockKey = Buffer.alloc(32) let cacheVal module.exports = { diff --git a/test/lib/mock-simple-keychain.js b/test/lib/mock-simple-keychain.js index daf6001c4ab9..74e6fd8a26df 100644 --- a/test/lib/mock-simple-keychain.js +++ b/test/lib/mock-simple-keychain.js @@ -1,4 +1,4 @@ -var fakeWallet = { +const fakeWallet = { privKey: '0x123456788890abcdef', address: '0xfedcba0987654321', } @@ -28,7 +28,7 @@ module.exports = class MockSimpleKeychain { } addAccounts (n = 1) { - for (var i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { this.wallets.push(fakeWallet) } } diff --git a/test/lib/react-trigger-change.js b/test/lib/react-trigger-change.js index d169dd614c57..52fe779c1f11 100644 --- a/test/lib/react-trigger-change.js +++ b/test/lib/react-trigger-change.js @@ -18,7 +18,7 @@ // Constants and functions are declared inside the closure. // In this way, reactTriggerChange can be passed directly to executeScript in Selenium. module.exports = function reactTriggerChange (node) { - var supportedInputTypes = { + const supportedInputTypes = { color: true, date: true, datetime: true, @@ -35,27 +35,27 @@ module.exports = function reactTriggerChange (node) { url: true, week: true, } - var nodeName = node.nodeName.toLowerCase() - var type = node.type - var event - var descriptor - var initialValue - var initialChecked - var initialCheckedRadio + const nodeName = node.nodeName.toLowerCase() + const type = node.type + let event + let descriptor + let initialValue + let initialChecked + let initialCheckedRadio // Do not try to delete non-configurable properties. // Value and checked properties on DOM elements are non-configurable in PhantomJS. function deletePropertySafe (elem, prop) { - var desc = Object.getOwnPropertyDescriptor(elem, prop) + const desc = Object.getOwnPropertyDescriptor(elem, prop) if (desc && desc.configurable) { delete elem[prop] } } function getCheckedRadio (radio) { - var name = radio.name - var radios - var i + const name = radio.name + let radios + let i if (name) { radios = document.querySelectorAll('input[type="radio"][name="' + name + '"]') for (i = 0; i < radios.length; i += 1) { diff --git a/test/unit/actions/config_test.js b/test/unit/actions/config_test.js index 9127474a8b1c..39224a9b1720 100644 --- a/test/unit/actions/config_test.js +++ b/test/unit/actions/config_test.js @@ -1,13 +1,13 @@ // var jsdom = require('mocha-jsdom') -var assert = require('assert') -var freeze = require('deep-freeze-strict') -var path = require('path') +const assert = require('assert') +const freeze = require('deep-freeze-strict') +const path = require('path') -var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) -var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) +const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) +const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) describe('config view actions', function () { - var initialState = { + const initialState = { metamask: { rpcTarget: 'foo', frequentRpcList: [], @@ -22,7 +22,7 @@ describe('config view actions', function () { describe('SHOW_CONFIG_PAGE', function () { it('should set appState.currentView.name to config', function () { - var result = reducers(initialState, actions.showConfigPage()) + const result = reducers(initialState, actions.showConfigPage()) assert.equal(result.appState.currentView.name, 'config') }) }) @@ -34,7 +34,7 @@ describe('config view actions', function () { value: 'foo', } - var result = reducers(initialState, action) + const result = reducers(initialState, action) assert.equal(result.metamask.provider.type, 'rpc') assert.equal(result.metamask.provider.rpcTarget, 'foo') }) diff --git a/test/unit/actions/set_selected_account_test.js b/test/unit/actions/set_selected_account_test.js index 36d312d7bbeb..0488c844e934 100644 --- a/test/unit/actions/set_selected_account_test.js +++ b/test/unit/actions/set_selected_account_test.js @@ -1,14 +1,14 @@ // var jsdom = require('mocha-jsdom') -var assert = require('assert') -var freeze = require('deep-freeze-strict') -var path = require('path') +const assert = require('assert') +const freeze = require('deep-freeze-strict') +const path = require('path') -var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) -var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) +const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) +const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) describe('SET_SELECTED_ACCOUNT', function () { it('sets the state.appState.activeAddress property of the state to the action.value', function () { - var initialState = { + const initialState = { appState: { activeAddress: 'foo', }, @@ -21,14 +21,14 @@ describe('SET_SELECTED_ACCOUNT', function () { } freeze(action) - var resultingState = reducers(initialState, action) + const resultingState = reducers(initialState, action) assert.equal(resultingState.appState.activeAddress, action.value) }) }) describe('SHOW_ACCOUNT_DETAIL', function () { it('updates metamask state', function () { - var initialState = { + const initialState = { metamask: { selectedAddress: 'foo', }, @@ -41,7 +41,7 @@ describe('SHOW_ACCOUNT_DETAIL', function () { } freeze(action) - var resultingState = reducers(initialState, action) + const resultingState = reducers(initialState, action) assert.equal(resultingState.metamask.selectedAddress, action.value) }) }) diff --git a/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js index ca1225113723..0b2da16aad54 100644 --- a/test/unit/actions/tx_test.js +++ b/test/unit/actions/tx_test.js @@ -1,5 +1,5 @@ -var assert = require('assert') -var path = require('path') +const assert = require('assert') +const path = require('path') import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' diff --git a/test/unit/actions/view_info_test.js b/test/unit/actions/view_info_test.js index 5785a368c4bb..4792af72781b 100644 --- a/test/unit/actions/view_info_test.js +++ b/test/unit/actions/view_info_test.js @@ -1,14 +1,14 @@ // var jsdom = require('mocha-jsdom') -var assert = require('assert') -var freeze = require('deep-freeze-strict') -var path = require('path') +const assert = require('assert') +const freeze = require('deep-freeze-strict') +const path = require('path') -var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) -var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) +const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) +const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) describe('SHOW_INFO_PAGE', function () { it('sets the state.appState.currentView.name property to info', function () { - var initialState = { + const initialState = { appState: { activeAddress: 'foo', }, @@ -16,7 +16,7 @@ describe('SHOW_INFO_PAGE', function () { freeze(initialState) const action = actions.showInfoPage() - var resultingState = reducers(initialState, action) + const resultingState = reducers(initialState, action) assert.equal(resultingState.appState.currentView.name, 'info') }) }) diff --git a/test/unit/actions/warning_test.js b/test/unit/actions/warning_test.js index e57374cda5d3..ac639f600147 100644 --- a/test/unit/actions/warning_test.js +++ b/test/unit/actions/warning_test.js @@ -1,14 +1,14 @@ // var jsdom = require('mocha-jsdom') -var assert = require('assert') -var freeze = require('deep-freeze-strict') -var path = require('path') +const assert = require('assert') +const freeze = require('deep-freeze-strict') +const path = require('path') -var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) -var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) +const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) +const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) describe('action DISPLAY_WARNING', function () { it('sets appState.warning to provided value', function () { - var initialState = { + const initialState = { appState: {}, } freeze(initialState) diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index 8f18406f4b1a..c65ee97abacd 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -54,7 +54,7 @@ describe('DetectTokensController', () => { controller.isOpen = true controller.isUnlocked = true - var stub = sandbox.stub(controller, 'detectNewTokens') + const stub = sandbox.stub(controller, 'detectNewTokens') clock.tick(1) sandbox.assert.notCalled(stub) @@ -70,7 +70,7 @@ describe('DetectTokensController', () => { controller.isOpen = true controller.isUnlocked = true - var stub = sandbox.stub(controller, 'detectTokenBalance') + const stub = sandbox.stub(controller, 'detectTokenBalance') .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) @@ -114,7 +114,7 @@ describe('DetectTokensController', () => { it('should trigger detect new tokens when change address', async () => { controller.isOpen = true controller.isUnlocked = true - var stub = sandbox.stub(controller, 'detectNewTokens') + const stub = sandbox.stub(controller, 'detectNewTokens') await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388') sandbox.assert.called(stub) }) @@ -122,7 +122,7 @@ describe('DetectTokensController', () => { it('should trigger detect new tokens when submit password', async () => { controller.isOpen = true controller.selectedAddress = '0x0' - var stub = sandbox.stub(controller, 'detectNewTokens') + const stub = sandbox.stub(controller, 'detectNewTokens') await controller._keyringMemStore.updateState({ isUnlocked: true }) sandbox.assert.called(stub) }) @@ -130,7 +130,7 @@ describe('DetectTokensController', () => { it('should not trigger detect new tokens when not open or not unlocked', async () => { controller.isOpen = true controller.isUnlocked = false - var stub = sandbox.stub(controller, 'detectTokenBalance') + const stub = sandbox.stub(controller, 'detectTokenBalance') clock.tick(180000) sandbox.assert.notCalled(stub) controller.isOpen = false diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index f9dc9c09995b..f49e518c3f98 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -342,7 +342,7 @@ describe('preferences controller', function () { }) describe('on watchAsset', function () { - var stubNext, stubEnd, stubHandleWatchAssetERC20, asy, req, res + let stubNext, stubEnd, stubHandleWatchAssetERC20, asy, req, res const sandbox = sinon.createSandbox() beforeEach(() => { @@ -359,8 +359,8 @@ describe('preferences controller', function () { it('shouldn not do anything if method not corresponds', async function () { const asy = {next: () => {}, end: () => {}} - var stubNext = sandbox.stub(asy, 'next') - var stubEnd = sandbox.stub(asy, 'end').returns(0) + const stubNext = sandbox.stub(asy, 'next') + const stubEnd = sandbox.stub(asy, 'end').returns(0) req.method = 'metamask' await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) sandbox.assert.notCalled(stubEnd) @@ -368,8 +368,8 @@ describe('preferences controller', function () { }) it('should do something if method is supported', async function () { const asy = {next: () => {}, end: () => {}} - var stubNext = sandbox.stub(asy, 'next') - var stubEnd = sandbox.stub(asy, 'end').returns(0) + const stubNext = sandbox.stub(asy, 'next') + const stubEnd = sandbox.stub(asy, 'end').returns(0) req.method = 'metamask_watchAsset' req.params.type = 'someasset' await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) @@ -400,7 +400,7 @@ describe('preferences controller', function () { }) describe('on watchAsset of type ERC20', function () { - var req + let req const sandbox = sinon.createSandbox() beforeEach(() => { diff --git a/test/unit/app/controllers/transactions/tx-utils-test.js b/test/unit/app/controllers/transactions/tx-utils-test.js index 1c5d20b0963f..e8bc8a5b780d 100644 --- a/test/unit/app/controllers/transactions/tx-utils-test.js +++ b/test/unit/app/controllers/transactions/tx-utils-test.js @@ -5,7 +5,7 @@ const txUtils = require('../../../../../app/scripts/controllers/transactions/lib describe('txUtils', function () { describe('#validateTxParams', function () { it('does not throw for positive values', function () { - var sample = { + const sample = { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '0x01', } @@ -13,7 +13,7 @@ describe('txUtils', function () { }) it('returns error for negative values', function () { - var sample = { + const sample = { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '-0x01', } diff --git a/test/unit/app/edge-encryptor-test.js b/test/unit/app/edge-encryptor-test.js index ad873e351166..3f2e8830a376 100644 --- a/test/unit/app/edge-encryptor-test.js +++ b/test/unit/app/edge-encryptor-test.js @@ -2,8 +2,8 @@ const assert = require('assert') const EdgeEncryptor = require('../../../app/scripts/edge-encryptor') -var password = 'passw0rd1' -var data = 'some random data' +const password = 'passw0rd1' +const data = 'some random data' global.crypto = global.crypto || { getRandomValues: function (array) { diff --git a/test/unit/app/message-manager-test.js b/test/unit/app/message-manager-test.js index 36ef6c29f254..b824acfe7a16 100644 --- a/test/unit/app/message-manager-test.js +++ b/test/unit/app/message-manager-test.js @@ -10,7 +10,7 @@ describe('Message Manager', function () { describe('#getMsgList', function () { it('when new should return empty array', function () { - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 0) }) @@ -21,9 +21,9 @@ describe('Message Manager', function () { describe('#addMsg', function () { it('adds a Msg returned in getMsgList', function () { - var Msg = { id: 1, status: 'approved', metamaskNetworkId: 'unit test' } + const Msg = { id: 1, status: 'approved', metamaskNetworkId: 'unit test' } messageManager.addMsg(Msg) - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 1) assert.equal(result[0].id, 1) @@ -32,10 +32,10 @@ describe('Message Manager', function () { describe('#setMsgStatusApproved', function () { it('sets the Msg status to approved', function () { - var Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } messageManager.addMsg(Msg) messageManager.setMsgStatusApproved(1) - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 1) assert.equal(result[0].status, 'approved') @@ -44,10 +44,10 @@ describe('Message Manager', function () { describe('#rejectMsg', function () { it('sets the Msg status to rejected', function () { - var Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } messageManager.addMsg(Msg) messageManager.rejectMsg(1) - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 1) assert.equal(result[0].status, 'rejected') @@ -59,7 +59,7 @@ describe('Message Manager', 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' }) - var result = messageManager.getMsg('1') + const result = messageManager.getMsg('1') assert.equal(result.hash, 'foo') }) }) diff --git a/test/unit/app/personal-message-manager-test.js b/test/unit/app/personal-message-manager-test.js index b07167bff914..52cbdb75cbce 100644 --- a/test/unit/app/personal-message-manager-test.js +++ b/test/unit/app/personal-message-manager-test.js @@ -11,7 +11,7 @@ describe('Personal Message Manager', function () { describe('#getMsgList', function () { it('when new should return empty array', function () { - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 0) }) @@ -22,9 +22,9 @@ describe('Personal Message Manager', function () { describe('#addMsg', function () { it('adds a Msg returned in getMsgList', function () { - var Msg = { id: 1, status: 'approved', metamaskNetworkId: 'unit test' } + const Msg = { id: 1, status: 'approved', metamaskNetworkId: 'unit test' } messageManager.addMsg(Msg) - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 1) assert.equal(result[0].id, 1) @@ -33,10 +33,10 @@ describe('Personal Message Manager', function () { describe('#setMsgStatusApproved', function () { it('sets the Msg status to approved', function () { - var Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } messageManager.addMsg(Msg) messageManager.setMsgStatusApproved(1) - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 1) assert.equal(result[0].status, 'approved') @@ -45,10 +45,10 @@ describe('Personal Message Manager', function () { describe('#rejectMsg', function () { it('sets the Msg status to rejected', function () { - var Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } + const Msg = { id: 1, status: 'unapproved', metamaskNetworkId: 'unit test' } messageManager.addMsg(Msg) messageManager.rejectMsg(1) - var result = messageManager.messages + const result = messageManager.messages assert.ok(Array.isArray(result)) assert.equal(result.length, 1) assert.equal(result[0].status, 'rejected') @@ -60,7 +60,7 @@ describe('Personal Message Manager', 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' }) - var result = messageManager.getMsg('1') + const result = messageManager.getMsg('1') assert.equal(result.hash, 'foo') }) }) @@ -87,20 +87,20 @@ describe('Personal Message Manager', function () { describe('#normalizeMsgData', function () { it('converts text to a utf8 hex string', function () { - var input = 'hello' - var output = messageManager.normalizeMsgData(input) + const input = 'hello' + const output = messageManager.normalizeMsgData(input) assert.equal(output, '0x68656c6c6f', 'predictably hex encoded') }) it('tolerates a hex prefix', function () { - var input = '0x12' - var output = messageManager.normalizeMsgData(input) + const input = '0x12' + const output = messageManager.normalizeMsgData(input) assert.equal(output, '0x12', 'un modified') }) it('tolerates normal hex', function () { - var input = '12' - var output = messageManager.normalizeMsgData(input) + const input = '12' + const output = messageManager.normalizeMsgData(input) assert.equal(output, '0x12', 'adds prefix') }) }) diff --git a/test/unit/reducers/unlock_vault_test.js b/test/unit/reducers/unlock_vault_test.js index d66891a63695..bb992ab40c74 100644 --- a/test/unit/reducers/unlock_vault_test.js +++ b/test/unit/reducers/unlock_vault_test.js @@ -1,11 +1,11 @@ // var jsdom = require('mocha-jsdom') -var assert = require('assert') +const assert = require('assert') // var freeze = require('deep-freeze-strict') -var path = require('path') -var sinon = require('sinon') +const path = require('path') +const sinon = require('sinon') -var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) -var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) +const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'store', 'actions.js')) +const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'ducks', 'index.js')) describe('#unlockMetamask(selectedAccount)', function () { beforeEach(function () { diff --git a/test/unit/util_test.js b/test/unit/util_test.js index 768288ce7d08..ffb2202765e6 100644 --- a/test/unit/util_test.js +++ b/test/unit/util_test.js @@ -1,13 +1,13 @@ -var assert = require('assert') -var sinon = require('sinon') +const assert = require('assert') +const sinon = require('sinon') const ethUtil = require('ethereumjs-util') -var path = require('path') -var util = require(path.join(__dirname, '..', '..', 'ui', 'app', 'helpers', 'utils', 'util.js')) +const path = require('path') +const util = require(path.join(__dirname, '..', '..', 'ui', 'app', 'helpers', 'utils', 'util.js')) describe('util', function () { - var ethInWei = '1' - for (var i = 0; i < 18; i++) { + let ethInWei = '1' + for (let i = 0; i < 18; i++) { ethInWei += '0' } @@ -47,52 +47,52 @@ describe('util', function () { describe('#addressSummary', function () { it('should add case-sensitive checksum', function () { - var address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' - var result = util.addressSummary(address) + const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' + const result = util.addressSummary(address) assert.equal(result, '0xFDEa65C8...b825') }) it('should accept arguments for firstseg, lastseg, and keepPrefix', function () { - var address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' - var result = util.addressSummary(address, 4, 4, false) + const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' + const result = util.addressSummary(address, 4, 4, false) assert.equal(result, 'FDEa...b825') }) }) describe('#isValidAddress', function () { it('should allow 40-char non-prefixed hex', function () { - var address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b825' - var result = util.isValidAddress(address) + const address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b825' + const result = util.isValidAddress(address) assert.ok(result) }) it('should allow 42-char non-prefixed hex', function () { - var address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' - var result = util.isValidAddress(address) + const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' + const result = util.isValidAddress(address) assert.ok(result) }) it('should not allow less non hex-prefixed', function () { - var address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b85' - var result = util.isValidAddress(address) + const address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b85' + const result = util.isValidAddress(address) assert.ok(!result) }) it('should not allow less hex-prefixed', function () { - var address = '0xfdea65ce26263f6d9a1b5de9555d2931a33b85' - var result = util.isValidAddress(address) + const address = '0xfdea65ce26263f6d9a1b5de9555d2931a33b85' + const result = util.isValidAddress(address) assert.ok(!result) }) it('should recognize correct capitalized checksum', function () { - var address = '0xFDEa65C8e26263F6d9A1B5de9555D2931A33b825' - var result = util.isValidAddress(address) + const address = '0xFDEa65C8e26263F6d9A1B5de9555D2931A33b825' + const result = util.isValidAddress(address) assert.ok(result) }) it('should recognize incorrect capitalized checksum', function () { - var address = '0xFDea65C8e26263F6d9A1B5de9555D2931A33b825' - var result = util.isValidAddress(address) + const address = '0xFDea65C8e26263F6d9A1B5de9555D2931A33b825' + const result = util.isValidAddress(address) assert.ok(!result) }) @@ -107,58 +107,58 @@ describe('util', function () { describe('#numericBalance', function () { it('should return a BN 0 if given nothing', function () { - var result = util.numericBalance() + const result = util.numericBalance() assert.equal(result.toString(10), 0) }) it('should work with hex prefix', function () { - var result = util.numericBalance('0x012') + const result = util.numericBalance('0x012') assert.equal(result.toString(10), '18') }) it('should work with no hex prefix', function () { - var result = util.numericBalance('012') + const result = util.numericBalance('012') assert.equal(result.toString(10), '18') }) }) describe('#formatBalance', function () { it('when given nothing', function () { - var result = util.formatBalance() + const result = util.formatBalance() assert.equal(result, 'None', 'should return "None"') }) it('should return eth as string followed by ETH', function () { - var input = new ethUtil.BN(ethInWei, 10).toJSON() - var result = util.formatBalance(input, 4) + const input = new ethUtil.BN(ethInWei, 10).toJSON() + const result = util.formatBalance(input, 4) assert.equal(result, '1.0000 ETH') }) it('should return eth as string followed by ETH', function () { - var input = new ethUtil.BN(ethInWei, 10).div(new ethUtil.BN('2', 10)).toJSON() - var result = util.formatBalance(input, 3) + 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') }) it('should display specified decimal points', function () { - var input = '0x128dfa6a90b28000' - var result = util.formatBalance(input, 2) + const input = '0x128dfa6a90b28000' + const result = util.formatBalance(input, 2) assert.equal(result, '1.33 ETH') }) it('should default to 3 decimal points', function () { - var input = '0x128dfa6a90b28000' - var result = util.formatBalance(input) + const input = '0x128dfa6a90b28000' + const result = util.formatBalance(input) assert.equal(result, '1.337 ETH') }) it('should show 2 significant digits for tiny balances', function () { - var input = '0x1230fa6a90b28' - var result = util.formatBalance(input) + const input = '0x1230fa6a90b28' + const result = util.formatBalance(input) assert.equal(result, '0.00032 ETH') }) it('should not parse the balance and return value with 2 decimal points with ETH at the end', function () { - var value = '1.2456789' - var needsParse = false - var result = util.formatBalance(value, 2, needsParse) + const value = '1.2456789' + const needsParse = false + const result = util.formatBalance(value, 2, needsParse) assert.equal(result, '1.24 ETH') }) }) @@ -166,7 +166,7 @@ describe('util', function () { describe('normalizing values', function () { describe('#normalizeToWei', function () { it('should convert an eth to the appropriate equivalent values', function () { - var valueTable = { + const valueTable = { wei: '1000000000000000000', kwei: '1000000000000000', mwei: '1000000000000', @@ -181,11 +181,11 @@ describe('util', function () { // gether:'0.000000001', // tether:'0.000000000001', } - var oneEthBn = new ethUtil.BN(ethInWei, 10) + const oneEthBn = new ethUtil.BN(ethInWei, 10) - for (var currency in valueTable) { - var value = new ethUtil.BN(valueTable[currency], 10) - var output = util.normalizeToWei(value, currency) + for (const currency in valueTable) { + 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}`) } }) @@ -193,66 +193,66 @@ describe('util', function () { describe('#normalizeEthStringToWei', function () { it('should convert decimal eth to pure wei BN', function () { - var input = '1.23456789' - var output = util.normalizeEthStringToWei(input) + const input = '1.23456789' + const output = util.normalizeEthStringToWei(input) assert.equal(output.toString(10), '1234567890000000000') }) it('should convert 1 to expected wei', function () { - var input = '1' - var output = util.normalizeEthStringToWei(input) + const input = '1' + const output = util.normalizeEthStringToWei(input) assert.equal(output.toString(10), ethInWei) }) it('should account for overflow numbers gracefully by dropping extra precision.', function () { - var input = '1.11111111111111111111' - var output = util.normalizeEthStringToWei(input) + const input = '1.11111111111111111111' + const output = util.normalizeEthStringToWei(input) assert.equal(output.toString(10), '1111111111111111111') }) it('should not truncate very exact wei values that do not have extra precision.', function () { - var input = '1.100000000000000001' - var output = util.normalizeEthStringToWei(input) + const input = '1.100000000000000001' + const output = util.normalizeEthStringToWei(input) assert.equal(output.toString(10), '1100000000000000001') }) }) describe('#normalizeNumberToWei', function () { it('should handle a simple use case', function () { - var input = 0.0002 - var output = util.normalizeNumberToWei(input, 'ether') - var str = output.toString(10) + const input = 0.0002 + const output = util.normalizeNumberToWei(input, 'ether') + const str = output.toString(10) assert.equal(str, '200000000000000') }) it('should convert a kwei number to the appropriate equivalent wei', function () { - var result = util.normalizeNumberToWei(1.111, 'kwei') + const result = util.normalizeNumberToWei(1.111, 'kwei') assert.equal(result.toString(10), '1111', 'accepts decimals') }) it('should convert a ether number to the appropriate equivalent wei', function () { - var result = util.normalizeNumberToWei(1.111, 'ether') + const result = util.normalizeNumberToWei(1.111, 'ether') assert.equal(result.toString(10), '1111000000000000000', 'accepts decimals') }) }) describe('#isHex', function () { it('should return true when given a hex string', function () { - var result = util.isHex('c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2') + const result = util.isHex('c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2') assert(result) }) it('should return false when given a non-hex string', function () { - var 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 () { - var 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 () { - var result = util.isHex('0xc3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2') + const result = util.isHex('0xc3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2') assert(result) }) }) diff --git a/test/web3/schema.js b/test/web3/schema.js index 336060431502..9dc528a5747e 100644 --- a/test/web3/schema.js +++ b/test/web3/schema.js @@ -1,6 +1,6 @@ /* eslint no-unused-vars: 0 */ -var params = { +const params = { // diffrent params used in the methods param: [], blockHashParams: '0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35', @@ -93,7 +93,7 @@ var params = { }, } -var methods = { +const methods = { hexaNumberMethods: { // these are the methods which have output in the form of hexa decimal numbers eth_blockNumber: ['eth_blockNumber', params.param, 'Q'], diff --git a/test/web3/web3.js b/test/web3/web3.js index 8f319f38ecf2..3431ee8ba7f0 100644 --- a/test/web3/web3.js +++ b/test/web3/web3.js @@ -1,6 +1,6 @@ /* eslint no-undef: 0 */ -var json = methods +const json = methods web3.currentProvider.enable().then(() => { diff --git a/ui/app/components/app/account-panel.js b/ui/app/components/app/account-panel.js index 2bae0a296615..3ffd978877c0 100644 --- a/ui/app/components/app/account-panel.js +++ b/ui/app/components/app/account-panel.js @@ -13,12 +13,12 @@ function AccountPanel () { } AccountPanel.prototype.render = function () { - var state = this.props - var identity = state.identity || {} - var account = state.account || {} - var isFauceting = state.isFauceting + const state = this.props + const identity = state.identity || {} + const account = state.account || {} + const isFauceting = state.isFauceting - var panelState = { + const panelState = { key: `accountPanel${identity.address}`, identiconKey: identity.address, identiconLabel: identity.name || '', diff --git a/ui/app/components/app/menu-droppo.js b/ui/app/components/app/menu-droppo.js index 62c5ddb3be19..57a0df2fec60 100644 --- a/ui/app/components/app/menu-droppo.js +++ b/ui/app/components/app/menu-droppo.js @@ -98,7 +98,7 @@ MenuDroppoComponent.prototype.componentDidMount = function () { this.globalClickHandler = this.globalClickOccurred.bind(this) document.body.addEventListener('click', this.globalClickHandler) // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) + const container = findDOMNode(this) this.container = container } } @@ -122,7 +122,7 @@ MenuDroppoComponent.prototype.globalClickOccurred = function (event) { } function isDescendant (parent, child) { - var node = child.parentNode + let node = child.parentNode while (node !== null) { if (node === parent) { return true diff --git a/ui/app/components/ui/fiat-value.js b/ui/app/components/ui/fiat-value.js index e3e2fd6be9d6..a02264b01c54 100644 --- a/ui/app/components/ui/fiat-value.js +++ b/ui/app/components/ui/fiat-value.js @@ -19,8 +19,8 @@ FiatValue.prototype.render = function () { if (value === 'None') { return value } - var fiatDisplayNumber, fiatTooltipNumber - var splitBalance = value.split(' ') + let fiatDisplayNumber, fiatTooltipNumber + const splitBalance = value.split(' ') if (conversionRate !== 0) { fiatTooltipNumber = Number(splitBalance[0]) * conversionRate diff --git a/ui/app/components/ui/mascot.js b/ui/app/components/ui/mascot.js index 9606fb9aa9ed..f849617450d3 100644 --- a/ui/app/components/ui/mascot.js +++ b/ui/app/components/ui/mascot.js @@ -33,8 +33,8 @@ Mascot.prototype.render = function Mascot () { } Mascot.prototype.componentDidMount = function () { - var targetDivId = 'metamask-mascot-container' - var container = document.getElementById(targetDivId) + const targetDivId = 'metamask-mascot-container' + const container = document.getElementById(targetDivId) container.appendChild(this.logo.container) } diff --git a/ui/app/ducks/app/app.js b/ui/app/ducks/app/app.js index fbdaf7b8dd14..34291df05a7e 100644 --- a/ui/app/ducks/app/app.js +++ b/ui/app/ducks/app/app.js @@ -21,14 +21,14 @@ export default function reduceApp (state, action) { name = 'confTx' } - var defaultView = { + const defaultView = { name, detailView: null, context: selectedAddress, } // default state - var appState = extend({ + const appState = extend({ shouldClose: false, menuOpen: false, modal: { diff --git a/ui/app/ducks/metamask/metamask.js b/ui/app/ducks/metamask/metamask.js index 23437610fff4..97574bc9cfa9 100644 --- a/ui/app/ducks/metamask/metamask.js +++ b/ui/app/ducks/metamask/metamask.js @@ -10,7 +10,7 @@ function reduceMetamask (state, action) { let newState // clone + defaults - var metamaskState = extend({ + const metamaskState = extend({ isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, @@ -99,7 +99,7 @@ function reduceMetamask (state, action) { }) case actions.COMPLETED_TX: - var stringId = String(action.id) + const stringId = String(action.id) newState = extend(metamaskState, { unapprovedTxs: {}, unapprovedMsgs: {}, diff --git a/ui/app/helpers/utils/util.js b/ui/app/helpers/utils/util.js index 96557c62e8f3..05be6d4064f4 100644 --- a/ui/app/helpers/utils/util.js +++ b/ui/app/helpers/utils/util.js @@ -12,7 +12,7 @@ function formatDate (date, format = 'M/d/y \'at\' T') { return DateTime.fromMillis(date).toFormat(format) } -var valueTable = { +const valueTable = { wei: '1000000000000000000', kwei: '1000000000000000', mwei: '1000000000000', @@ -25,8 +25,8 @@ var valueTable = { gether: '0.000000001', tether: '0.000000000001', } -var bnTable = {} -for (var currency in valueTable) { +const bnTable = {} +for (const currency in valueTable) { bnTable[currency] = new ethUtil.BN(valueTable[currency], 10) } @@ -97,12 +97,12 @@ function miniAddressSummary (address) { if (!address) { return '' } - var checked = checksumAddress(address) + const checked = checksumAddress(address) return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...' } function isValidAddress (address) { - var prefixed = ethUtil.addHexPrefix(address) + const prefixed = ethUtil.addHexPrefix(address) if (address === '0x0000000000000000000000000000000000000000') { return false } @@ -114,7 +114,7 @@ function isValidENSAddress (address) { } function isInvalidChecksumAddress (address) { - var prefixed = ethUtil.addHexPrefix(address) + const prefixed = ethUtil.addHexPrefix(address) if (address === '0x0000000000000000000000000000000000000000') { return false } @@ -125,8 +125,8 @@ function isAllOneCase (address) { if (!address) { return true } - var lower = address.toLowerCase() - var upper = address.toUpperCase() + const lower = address.toLowerCase() + const upper = address.toUpperCase() return address === lower || address === upper } @@ -135,18 +135,18 @@ function numericBalance (balance) { if (!balance) { return new ethUtil.BN(0, 16) } - var stripped = ethUtil.stripHexPrefix(balance) + const stripped = ethUtil.stripHexPrefix(balance) return new ethUtil.BN(stripped, 16) } // Takes hex, returns [beforeDecimal, afterDecimal] function parseBalance (balance) { - var beforeDecimal, afterDecimal + let afterDecimal const wei = numericBalance(balance) - var weiString = wei.toString() + const weiString = wei.toString() const trailingZeros = /0+$/ - beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0' + const beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0' afterDecimal = ('000000000000000000' + wei).slice(-18).replace(trailingZeros, '') if (afterDecimal === '') { afterDecimal = '0' @@ -157,14 +157,14 @@ function parseBalance (balance) { // Takes wei hex, returns an object with three properties. // Its "formatted" property is what we generally use to render values. function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') { - var parsed = needsParse ? parseBalance(balance) : balance.split('.') - var beforeDecimal = parsed[0] - var afterDecimal = parsed[1] - var formatted = 'None' + const parsed = needsParse ? parseBalance(balance) : balance.split('.') + const beforeDecimal = parsed[0] + let afterDecimal = parsed[1] + let formatted = 'None' if (decimalsToKeep === undefined) { if (beforeDecimal === '0') { if (afterDecimal !== '0') { - var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits + const sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits if (sigFigs) { afterDecimal = sigFigs[0] } @@ -182,11 +182,11 @@ function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ET function generateBalanceObject (formattedBalance, decimalsToKeep = 1) { - var balance = formattedBalance.split(' ')[0] - var label = formattedBalance.split(' ')[1] - var beforeDecimal = balance.split('.')[0] - var afterDecimal = balance.split('.')[1] - var shortBalance = shortenBalance(balance, decimalsToKeep) + let balance = formattedBalance.split(' ')[0] + const label = formattedBalance.split(' ')[1] + const beforeDecimal = balance.split('.')[0] + const afterDecimal = balance.split('.')[1] + const shortBalance = shortenBalance(balance, decimalsToKeep) if (beforeDecimal === '0' && afterDecimal.substr(0, 5) === '00000') { // eslint-disable-next-line eqeqeq @@ -203,8 +203,8 @@ function generateBalanceObject (formattedBalance, decimalsToKeep = 1) { } function shortenBalance (balance, decimalsToKeep = 1) { - var truncatedValue - var convertedBalance = parseFloat(balance) + let truncatedValue + const convertedBalance = parseFloat(balance) if (convertedBalance > 1000000) { truncatedValue = (balance / 1000000).toFixed(decimalsToKeep) return `${truncatedValue}m` @@ -216,7 +216,7 @@ function shortenBalance (balance, decimalsToKeep = 1) { } else if (convertedBalance < 0.001) { return '<0.001' } else if (convertedBalance < 1) { - var stringBalance = convertedBalance.toString() + const stringBalance = convertedBalance.toString() if (stringBalance.split('.')[1].length > 3) { return convertedBalance.toFixed(3) } else { @@ -228,7 +228,7 @@ function shortenBalance (balance, decimalsToKeep = 1) { } function dataSize (data) { - var size = data ? ethUtil.stripHexPrefix(data).length : 0 + const size = data ? ethUtil.stripHexPrefix(data).length : 0 return size + ' bytes' } @@ -245,7 +245,7 @@ function normalizeEthStringToWei (str) { const parts = str.split('.') let eth = new ethUtil.BN(parts[0], 10).mul(bnTable.wei) if (parts[1]) { - var decimal = parts[1] + let decimal = parts[1] while (decimal.length < 18) { decimal += '0' } @@ -258,24 +258,24 @@ function normalizeEthStringToWei (str) { return eth } -var multiple = new ethUtil.BN('10000', 10) +const multiple = new ethUtil.BN('10000', 10) function normalizeNumberToWei (n, currency) { - var enlarged = n * 10000 - var amount = new ethUtil.BN(String(enlarged), 10) + const enlarged = n * 10000 + const amount = new ethUtil.BN(String(enlarged), 10) return normalizeToWei(amount, currency).div(multiple) } function readableDate (ms) { - var date = new Date(ms) - var month = date.getMonth() - var day = date.getDate() - var year = date.getFullYear() - var hours = date.getHours() - var minutes = '0' + date.getMinutes() - var seconds = '0' + date.getSeconds() - - var dateStr = `${month}/${day}/${year}` - var time = `${hours}:${minutes.substr(-2)}:${seconds.substr(-2)}` + const date = new Date(ms) + const month = date.getMonth() + const day = date.getDate() + const year = date.getFullYear() + const hours = date.getHours() + const minutes = '0' + date.getMinutes() + const seconds = '0' + date.getSeconds() + + const dateStr = `${month}/${day}/${year}` + const time = `${hours}:${minutes.substr(-2)}:${seconds.substr(-2)}` return `${dateStr} ${time}` } diff --git a/ui/app/pages/confirm-transaction/conf-tx.js b/ui/app/pages/confirm-transaction/conf-tx.js index 5d8069d9102b..91ff4b9e48b8 100644 --- a/ui/app/pages/confirm-transaction/conf-tx.js +++ b/ui/app/pages/confirm-transaction/conf-tx.js @@ -153,7 +153,7 @@ ConfirmTxScreen.prototype.render = function () { conversionRate, } = this.props - var txData = this.getTxData() || {} + const txData = this.getTxData() || {} const { msgParams, type, msgParams: { version } } = txData log.debug('msgParams detected, rendering pending msg') @@ -186,7 +186,7 @@ ConfirmTxScreen.prototype.render = function () { ConfirmTxScreen.prototype.signMessage = function (msgData, event) { log.info('conf-tx.js: signing message') - var params = msgData.msgParams + const params = msgData.msgParams params.metamaskId = msgData.id this.stopPropagation(event) return this.props.dispatch(actions.signMsg(params)) @@ -200,7 +200,7 @@ ConfirmTxScreen.prototype.stopPropagation = function (event) { ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) { log.info('conf-tx.js: signing personal message') - var params = msgData.msgParams + const params = msgData.msgParams params.metamaskId = msgData.id this.stopPropagation(event) return this.props.dispatch(actions.signPersonalMsg(params)) @@ -208,7 +208,7 @@ ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) { ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) { log.info('conf-tx.js: signing typed message') - var params = msgData.msgParams + const params = msgData.msgParams params.metamaskId = msgData.id this.stopPropagation(event) return this.props.dispatch(actions.signTypedMsg(params)) diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index 64da523d682a..93965a9fdc42 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -260,7 +260,7 @@ class Routes extends Component { toggleMetamaskActive () { if (!this.props.isUnlocked) { // currently inactive: redirect to password box - var passwordBox = document.querySelector('input[type=password]') + const passwordBox = document.querySelector('input[type=password]') if (!passwordBox) { return } diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index c78a8ab15a2a..d6c29fcd6759 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -17,7 +17,7 @@ const { hasUnconfirmedTransactions } = require('../helpers/utils/confirm-tx.util const gasDuck = require('../ducks/gas/gas.duck') const WebcamUtils = require('../../lib/webcam-utils') -var actions = { +const actions = { _setBackgroundConnection: _setBackgroundConnection, GO_HOME: 'GO_HOME', @@ -399,7 +399,7 @@ var actions = { module.exports = actions -var background = null +let background = null function _setBackgroundConnection (backgroundConnection) { background = backgroundConnection } @@ -2171,7 +2171,7 @@ function requestExportAccount () { } function exportAccount (password, address) { - var self = this + const self = this return function (dispatch) { dispatch(self.showLoadingIndication()) @@ -2305,7 +2305,7 @@ function pairUpdate (coin) { } function shapeShiftSubview () { - var pair = 'btc_eth' + const pair = 'btc_eth' return (dispatch) => { dispatch(actions.showSubLoadingIndication()) shapeShiftRequest('marketinfo', {pair}, (mktResponse) => { @@ -2334,7 +2334,7 @@ function coinShiftRquest (data, marketData) { if (response.error) { return dispatch(actions.displayWarning(response.error)) } - var message = ` + const message = ` Deposit your ${response.depositType} to the address below:` log.debug(`background.createShapeShiftTx`) background.createShapeShiftTx(response.deposit, response.depositType) @@ -2372,7 +2372,7 @@ function reshowQrCode (data, coin) { return dispatch(actions.displayWarning(mktResponse.error)) } - var message = [ + const message = [ `Deposit your ${coin} to the address below:`, `Deposit Limit: ${mktResponse.limit}`, `Deposit Minimum:${mktResponse.minimum}`, @@ -2385,10 +2385,10 @@ function reshowQrCode (data, coin) { } function shapeShiftRequest (query, options = {}, cb) { - var queryResponse, method + let queryResponse, method options.method ? method = options.method : method = 'GET' - var requestListner = function () { + const requestListner = function () { try { queryResponse = JSON.parse(this.responseText) if (cb) { @@ -2403,12 +2403,12 @@ function shapeShiftRequest (query, options = {}, cb) { } } - var shapShiftReq = new XMLHttpRequest() + const shapShiftReq = new XMLHttpRequest() shapShiftReq.addEventListener('load', requestListner) shapShiftReq.open(method, `https://shapeshift.io/${query}/${options.pair ? options.pair : ''}`, true) if (options.method === 'POST') { - var jsonObj = JSON.stringify(options.data) + const jsonObj = JSON.stringify(options.data) shapShiftReq.setRequestHeader('Content-Type', 'application/json') return shapShiftReq.send(jsonObj) } else { diff --git a/ui/index.js b/ui/index.js index 3360bf077a9e..6f7a4396394d 100644 --- a/ui/index.js +++ b/ui/index.js @@ -13,7 +13,7 @@ module.exports = launchMetamaskUi log.setLevel(global.METAMASK_DEBUG ? 'debug' : 'warn') function launchMetamaskUi (opts, cb) { - var {backgroundConnection} = opts + const {backgroundConnection} = opts actions._setBackgroundConnection(backgroundConnection) // check if we are unlocked first backgroundConnection.getState(function (err, metamaskState) { diff --git a/ui/lib/icon-factory.js b/ui/lib/icon-factory.js index 2ea943297dc8..cbaa496cd41d 100644 --- a/ui/lib/icon-factory.js +++ b/ui/lib/icon-factory.js @@ -1,4 +1,4 @@ -var iconFactory +let iconFactory const isValidAddress = require('ethereumjs-util').isValidAddress const { checksumAddress } = require('../app/helpers/utils/util') const contractMap = require('eth-contract-metadata') @@ -26,18 +26,18 @@ IconFactory.prototype.iconForAddress = function (address, diameter) { // returns svg dom element IconFactory.prototype.generateIdenticonSvg = function (address, diameter) { - var cacheId = `${address}:${diameter}` + const cacheId = `${address}:${diameter}` // check cache, lazily generate and populate cache - var identicon = this.cache[cacheId] || (this.cache[cacheId] = this.generateNewIdenticon(address, diameter)) + const identicon = this.cache[cacheId] || (this.cache[cacheId] = this.generateNewIdenticon(address, diameter)) // create a clean copy so you can modify it - var cleanCopy = identicon.cloneNode(true) + const cleanCopy = identicon.cloneNode(true) return cleanCopy } // creates a new identicon IconFactory.prototype.generateNewIdenticon = function (address, diameter) { - var numericRepresentation = jsNumberForAddress(address) - var identicon = this.jazzicon(diameter, numericRepresentation) + const numericRepresentation = jsNumberForAddress(address) + const identicon = this.jazzicon(diameter, numericRepresentation) return identicon } @@ -58,8 +58,8 @@ function imageElFor (address) { } function jsNumberForAddress (address) { - var addr = address.slice(2, 10) - var seed = parseInt(addr, 16) + const addr = address.slice(2, 10) + const seed = parseInt(addr, 16) return seed } diff --git a/ui/lib/persistent-form.js b/ui/lib/persistent-form.js index d4dc20b0300d..112e4415b980 100644 --- a/ui/lib/persistent-form.js +++ b/ui/lib/persistent-form.js @@ -15,7 +15,7 @@ PersistentForm.prototype.componentDidMount = function () { const fields = document.querySelectorAll('[data-persistent-formid]') const store = this.getPersistentStore() - for (var i = 0; i < fields.length; i++) { + for (let i = 0; i < fields.length; i++) { const field = fields[i] const key = field.getAttribute('data-persistent-formid') const cached = store[key] @@ -52,7 +52,7 @@ PersistentForm.prototype.persistentFieldDidUpdate = function (event) { PersistentForm.prototype.componentWillUnmount = function () { const fields = document.querySelectorAll('[data-persistent-formid]') - for (var i = 0; i < fields.length; i++) { + for (let i = 0; i < fields.length; i++) { const field = fields[i] field.removeEventListener(eventName, this.persistentFieldDidUpdate.bind(this)) } From 718f0010a4d676cc8be2caa976c560910482bdb0 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 3 Dec 2019 12:00:03 -0330 Subject: [PATCH 84/88] Enable react/no-unused-state rule for ESLint (#7609) * eslint: Enable react/no-unused-state rule * Fix unused state issues * Remove now unused validFileImport localized message --- .eslintrc | 1 + app/_locales/am/messages.json | 3 --- app/_locales/ar/messages.json | 3 --- app/_locales/bg/messages.json | 3 --- app/_locales/bn/messages.json | 3 --- app/_locales/ca/messages.json | 3 --- app/_locales/cs/messages.json | 3 --- app/_locales/da/messages.json | 3 --- app/_locales/de/messages.json | 3 --- app/_locales/el/messages.json | 3 --- app/_locales/en/messages.json | 3 --- app/_locales/es/messages.json | 3 --- app/_locales/es_419/messages.json | 3 --- app/_locales/et/messages.json | 3 --- app/_locales/fa/messages.json | 3 --- app/_locales/fi/messages.json | 3 --- app/_locales/fil/messages.json | 3 --- app/_locales/fr/messages.json | 3 --- app/_locales/he/messages.json | 3 --- app/_locales/hi/messages.json | 3 --- app/_locales/hn/messages.json | 3 --- app/_locales/hr/messages.json | 3 --- app/_locales/ht/messages.json | 3 --- app/_locales/hu/messages.json | 3 --- app/_locales/id/messages.json | 3 --- app/_locales/it/messages.json | 3 --- app/_locales/kn/messages.json | 3 --- app/_locales/ko/messages.json | 3 --- app/_locales/lt/messages.json | 3 --- app/_locales/lv/messages.json | 3 --- app/_locales/ms/messages.json | 3 --- app/_locales/nl/messages.json | 3 --- app/_locales/no/messages.json | 3 --- app/_locales/pl/messages.json | 3 --- app/_locales/pt/messages.json | 3 --- app/_locales/pt_BR/messages.json | 3 --- app/_locales/ro/messages.json | 3 --- app/_locales/ru/messages.json | 3 --- app/_locales/sk/messages.json | 3 --- app/_locales/sl/messages.json | 3 --- app/_locales/sr/messages.json | 3 --- app/_locales/sv/messages.json | 3 --- app/_locales/sw/messages.json | 3 --- app/_locales/ta/messages.json | 3 --- app/_locales/th/messages.json | 3 --- app/_locales/tr/messages.json | 3 --- app/_locales/uk/messages.json | 3 --- app/_locales/zh_CN/messages.json | 3 --- app/_locales/zh_TW/messages.json | 3 --- ...transaction-list-item-details.component.js | 1 - .../sender-to-recipient.component.js | 3 --- ui/app/pages/add-token/add-token.component.js | 6 +---- .../create-account/import-account/json.js | 24 ++++++------------- .../add-recipient/add-recipient.component.js | 1 - .../add-recipient/ens-input.component.js | 5 ++-- .../add-contact/add-contact.component.js | 2 +- 56 files changed, 12 insertions(+), 175 deletions(-) diff --git a/.eslintrc b/.eslintrc index b8a5c409497e..f77127da80d5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -150,6 +150,7 @@ "operator-linebreak": [2, "after", { "overrides": { "?": "ignore", ":": "ignore" } }], "padded-blocks": "off", "quotes": [2, "single", {"avoidEscape": true, "allowTemplateLiterals": true}], + "react/no-unused-state": 2, "react/jsx-boolean-value": 2, "react/jsx-curly-brace-presence": [2, { "props": "never", "children": "never" }], "react/jsx-equals-spacing": 2, diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 70da475f4dff..bbb076896568 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -1332,9 +1332,6 @@ "userName": { "message": "የተጣቃሚ ስም" }, - "validFileImport": { - "message": "የሚያስመጡትን ትክክለኛ ፋይል መምረጥ አለብዎ፡" - }, "viewAccount": { "message": "መለያን ይመልከቱ" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index f9bceb60de6b..2a9451d619e6 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -1328,9 +1328,6 @@ "userName": { "message": "اسم المستخدم" }, - "validFileImport": { - "message": "يجب عليك تحديد ملف صالح للاستيراد." - }, "viewAccount": { "message": "عرض حساب" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index c029ceb4bfda..bd66c78c7112 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -1331,9 +1331,6 @@ "userName": { "message": "Потребителско име" }, - "validFileImport": { - "message": "Трябва да изберете валиден файл, който да импортирате." - }, "viewAccount": { "message": "Преглед на профила" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index ee20241156f2..7580e8e534b1 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -1335,9 +1335,6 @@ "userName": { "message": "ইউজারনেম" }, - "validFileImport": { - "message": "আমদানি করার জন্য আপনাকে অবশ্যই একটি বৈধ ফাইল নির্বাচন করতে হবে।" - }, "viewAccount": { "message": "আ্যাকাউন্ট দেখুন" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 7b8bdf8968ef..07ec4c914d56 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -1304,9 +1304,6 @@ "userName": { "message": "Nom d'usuari" }, - "validFileImport": { - "message": "Has de seleccionar un arxiu vàlid per a importar." - }, "viewAccount": { "message": "Mostra el compte" }, diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index 72c4a7bce660..452e5fb5e066 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -514,9 +514,6 @@ "usedByClients": { "message": "Používána různými klienty" }, - "validFileImport": { - "message": "Musíte vybrat validní soubor k importu." - }, "viewAccount": { "message": "Zobrazit účet" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 9d68e86cfe33..d47cc30468ab 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -1301,9 +1301,6 @@ "userName": { "message": "Brugernavn" }, - "validFileImport": { - "message": "Du skal vælge en gyldig fil at importere." - }, "viewAccount": { "message": "Vis konto" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 1f7409ee2dc6..5ea773ba375f 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1292,9 +1292,6 @@ "userName": { "message": "Nutzername" }, - "validFileImport": { - "message": "Du musst eine gültige Datei für den Import auswählen." - }, "viewAccount": { "message": " Account einsehen" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 44fa55db0622..9d6725632c41 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1329,9 +1329,6 @@ "userName": { "message": "Όνομα χρήστη" }, - "validFileImport": { - "message": "Πρέπει να επιλέξετε έναν έγκυρο φάκελο για εισαγωγή." - }, "viewAccount": { "message": "Προβολή λογαριασμού" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f85b64a02f70..2afe8e0c313d 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1472,9 +1472,6 @@ "userName": { "message": "Username" }, - "validFileImport": { - "message": "You must select a valid file to import." - }, "viewAccount": { "message": "View Account" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 79d508a07b7f..5aeb4ebe028a 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1076,9 +1076,6 @@ "usedByClients": { "message": "Utilizado por una variedad de clientes diferentes" }, - "validFileImport": { - "message": "Debes selecionar un archivo valido para importar" - }, "viewAccount": { "message": "Mirar cuenta" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 39d45ddaff37..e75b4c27bf01 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1314,9 +1314,6 @@ "userName": { "message": "Nombre de usuario" }, - "validFileImport": { - "message": "Selecciona un archivo válido para importar." - }, "viewAccount": { "message": "Ver cuenta" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 63c7ca53e3b5..3b5f4ced8ffb 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -1325,9 +1325,6 @@ "userName": { "message": "Kasutajanimi" }, - "validFileImport": { - "message": "Peate valima importimiseks sobiva faili." - }, "viewAccount": { "message": "Kuva konto" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 1e93ec772d14..6d9741344078 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -1335,9 +1335,6 @@ "userName": { "message": "نام کاربری" }, - "validFileImport": { - "message": "شما باید یک فایل معتبر را جهت وارد سازی انتخاب کنید." - }, "viewAccount": { "message": "مشاهده حساب" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index e2d8a59c548d..352600b26228 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -1332,9 +1332,6 @@ "userName": { "message": "Käyttäjätunnus" }, - "validFileImport": { - "message": "Valittava tuotavaksi kelpaava tiedosto." - }, "viewAccount": { "message": "Näytä tili" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 2734fecc3262..8c453bca5b0d 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -1223,9 +1223,6 @@ "usedByClients": { "message": "Ginagamit ng iba't ibang client" }, - "validFileImport": { - "message": "Dapat kang pumili ng valid na file na ii-import." - }, "viewAccount": { "message": "Tingnan ang Account" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 98925ad696c7..ddcddb6be321 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1296,9 +1296,6 @@ "userName": { "message": "Nom d'utilisateur" }, - "validFileImport": { - "message": "Vous devez selectionner un fichier valide à importer." - }, "viewAccount": { "message": "Afficher le compte" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 9c9966edcfe9..62e69e1d5077 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -1329,9 +1329,6 @@ "userName": { "message": "שם משתמש" }, - "validFileImport": { - "message": "עליך לבחור קובץ חוקי לייבוא." - }, "viewAccount": { "message": "הצג חשבון" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 25e8014ffae9..92fa40af68a4 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1329,9 +1329,6 @@ "userName": { "message": "उपयोगकर्ता नाम" }, - "validFileImport": { - "message": "आयात करने के लिए आपको एक मान्य फ़ाइल को चुनना होगा।" - }, "viewAccount": { "message": "खाता देखें" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index e15b244ca055..1dd4fd117578 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -476,9 +476,6 @@ "usedByClients": { "message": "विभिन्न क्लाइंट्स द्वारा उपयोग किया जाता है" }, - "validFileImport": { - "message": "आयात करने के लिए आपको एक वैध फ़ाइल चुननी होगी।" - }, "viewAccount": { "message": "खाता देखें" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 318713b7d0f2..2e224f36f01f 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -1325,9 +1325,6 @@ "userName": { "message": "Korisničko ime" }, - "validFileImport": { - "message": "Morate odabrati valjanu datoteku za uvoz." - }, "viewAccount": { "message": "Prikaz računa" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index d3a9dd4bab73..4724090171af 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -836,9 +836,6 @@ "usedByClients": { "message": "Itilize pa yon varyete de kliyan diferan" }, - "validFileImport": { - "message": "Ou dwe chwazi yon dosye ki valab pou enpòte." - }, "viewAccount": { "message": "Wè Kont" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 870972e5bcb3..f1554299ba60 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -1325,9 +1325,6 @@ "userName": { "message": "Felhasználónév" }, - "validFileImport": { - "message": "Ki kell választanod egy érvényes fájlt az importáláshoz." - }, "viewAccount": { "message": "Fiók megtekintése" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 42d8472892c1..eaddf42ebb47 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1304,9 +1304,6 @@ "userName": { "message": "Nama Pengguna" }, - "validFileImport": { - "message": "Anda harus memilih berkas yang sah untuk diimpor." - }, "viewAccount": { "message": "Lihat Akun" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 83b63785905a..e51b5a477e1c 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1295,9 +1295,6 @@ "userName": { "message": "Nome utente" }, - "validFileImport": { - "message": "Devi selezionare un file valido da importare." - }, "viewAccount": { "message": "Vedi Account" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 480abe20d3b1..e4c8b38fe673 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -1335,9 +1335,6 @@ "userName": { "message": "ಬಳಕೆದಾರಹೆಸರು" }, - "validFileImport": { - "message": "ನೀವು ಆಮದು ಮಾಡಲು ಮಾನ್ಯ ಫೈಲ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಬೇಕು." - }, "viewAccount": { "message": "ಖಾತೆಯನ್ನು ವೀಕ್ಷಿಸಿ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 47af1dbffef2..39c68a85e612 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1326,9 +1326,6 @@ "userName": { "message": "사용자이름" }, - "validFileImport": { - "message": "가져오기 위해 유효한 파일을 선택해야 합니다." - }, "viewAccount": { "message": "계정 보기" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 51113ffe482d..961eedc9137c 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -1335,9 +1335,6 @@ "userName": { "message": "Vartotojo vardas" }, - "validFileImport": { - "message": "Turite pasirinkti galiojantį failą, kurį pageidaujate importuoti." - }, "viewAccount": { "message": "Žiūrėti paskyrą" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index db678240b06c..18d80c900f4b 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -1331,9 +1331,6 @@ "userName": { "message": "Lietotājvārds" }, - "validFileImport": { - "message": "Importēšanai jāatlasa derīga datne." - }, "viewAccount": { "message": "Skatīt kontu" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index ed1daeb3d177..e573eabc4f82 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -1303,9 +1303,6 @@ "userName": { "message": "Nama pengguna" }, - "validFileImport": { - "message": "Anda mesti pilih fail yang sah untuk diimport." - }, "viewAccount": { "message": "Paparkan Akaun" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index b026ec93a809..265542aedecd 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -463,9 +463,6 @@ "usedByClients": { "message": "Gebruikt door verschillende klanten" }, - "validFileImport": { - "message": "U moet een geldig bestand selecteren om te importeren." - }, "viewAccount": { "message": "Bekijk account" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 1f936842168a..b0bf0d6dec46 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -1307,9 +1307,6 @@ "userName": { "message": "Brukernavn" }, - "validFileImport": { - "message": "Du må velge en gyldig fil å importere" - }, "viewAccount": { "message": "Se konto" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index ea9bac563d6e..3fa36bd39809 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -1320,9 +1320,6 @@ "userName": { "message": "Nazwa użytkownika" }, - "validFileImport": { - "message": "Należy wybrać prawidłowy plik do zaimportowania." - }, "viewAccount": { "message": "Zobacz konto" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 0c8949603043..51936934953d 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -473,9 +473,6 @@ "usedByClients": { "message": "Utilizado por vários tipos de clientes" }, - "validFileImport": { - "message": "Deve selecionar um ficheiro válido para importar." - }, "viewAccount": { "message": "Ver Conta" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 6f496b57c147..44ed790efc8b 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -1314,9 +1314,6 @@ "userName": { "message": "Nome de usuário" }, - "validFileImport": { - "message": "Você precisa selecionar um arquivo válido para importar." - }, "viewAccount": { "message": "Visualizar conta" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index a5fe91697ef5..f891a40dfbe0 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -1316,9 +1316,6 @@ "userName": { "message": "Nume utilizator" }, - "validFileImport": { - "message": "Trebuie să selectați un fișier valabil pentru importare." - }, "viewAccount": { "message": "Afișați contul" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index ac6aa65e27bf..660b2799e406 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -527,9 +527,6 @@ "usedByClients": { "message": "Используется различными клиентами" }, - "validFileImport": { - "message": "Вам нужно выбрать правильный файл для импорта." - }, "viewAccount": { "message": "Посмотреть счет" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 2de10f9abfad..5238e076df7b 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -1289,9 +1289,6 @@ "userName": { "message": "Meno používateľa" }, - "validFileImport": { - "message": "Musíte vybrat validní soubor k importu." - }, "viewAccount": { "message": "Zobrazit účet" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 1e1884a26cb7..8530dd43dbaf 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -1317,9 +1317,6 @@ "userName": { "message": "Uporabniško ime" }, - "validFileImport": { - "message": "Za uvoz morate izbrati pravilno datoteko." - }, "viewAccount": { "message": "Poglej račun" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 58d31c183e76..d3fd1cbd4c64 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -1320,9 +1320,6 @@ "userName": { "message": "Корисничко име" }, - "validFileImport": { - "message": "Morate odabrati važeću datoteku da biste ih uvezli." - }, "viewAccount": { "message": "Прикажи налог" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index e808703f1807..1b7ecc06e3c2 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -1310,9 +1310,6 @@ "userName": { "message": "Användarnamn" }, - "validFileImport": { - "message": "Du måste välja en giltig fil för att importera." - }, "viewAccount": { "message": "Visa konto" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index ad58787339dd..c8c2e36eecbb 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -1313,9 +1313,6 @@ "userName": { "message": "Jina la mtumiaji" }, - "validFileImport": { - "message": "Ni lazima uchague faili halali ili uhamishe." - }, "viewAccount": { "message": "Angalia Akaunti" }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index ba173def5dd0..698349c24e5f 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -539,9 +539,6 @@ "usedByClients": { "message": "பல்வேறு வாடிக்கையாளர்கள் பல்வேறு பயன்படுத்திய" }, - "validFileImport": { - "message": "இறக்குமதி செய்ய சரியான கோப்பு தேர்ந்தெடுக்க வேண்டும்." - }, "viewAccount": { "message": "கணக்கைப் பார்" }, diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index c32044bb16ac..f07f3421eca8 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -641,9 +641,6 @@ "usedByClients": { "message": "ถูกใช้งานโดยหลายไคลเอนท์" }, - "validFileImport": { - "message": "คุณต้องเลือกไฟล์ที่ถูกต้องเพื่อนำเข้า" - }, "viewAccount": { "message": "ดูบัญชี" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index dbfe3cf08617..c6027a42d0fa 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -536,9 +536,6 @@ "usedByClients": { "message": "Farklı istemciler tarafından kullanılmakta" }, - "validFileImport": { - "message": "Almak için geçerli bir dosya seçmelisiniz" - }, "viewAccount": { "message": "Hesabı İncele" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index a4252cb3e8a8..49d04a096f5e 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -1335,9 +1335,6 @@ "userName": { "message": "Ім’я користувача" }, - "validFileImport": { - "message": "Потрібно вибрати дійсний файл для імпорту." - }, "viewAccount": { "message": "Переглянути обліковий запис" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index c0b10a9730d7..cade6ee71abe 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1314,9 +1314,6 @@ "userName": { "message": "用户名" }, - "validFileImport": { - "message": "您必须选择一个有效的文件进行导入." - }, "viewAccount": { "message": "查看账户" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 5a0a2e3ea3e1..3d0e299a6060 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1308,9 +1308,6 @@ "userName": { "message": "使用者名稱" }, - "validFileImport": { - "message": "您必須選擇一個合法的檔案來匯入." - }, "viewAccount": { "message": "查看帳戶" }, 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 f27c74970d86..554e99a5b22c 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 @@ -39,7 +39,6 @@ export default class TransactionListItemDetails extends PureComponent { state = { justCopied: false, - cancelDisabled: false, } handleEtherscanClick = () => { 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 3102f17e325e..01ad167ca161 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 @@ -39,7 +39,6 @@ export default class SenderToRecipient extends PureComponent { state = { senderAddressCopied: false, - recipientAddressCopied: false, } renderSenderIdenticon () { @@ -112,7 +111,6 @@ export default class SenderToRecipient extends PureComponent {
    { - this.setState({ recipientAddressCopied: true }) copyToClipboard(checksummedRecipientAddress) if (onRecipientClick) { onRecipientClick() @@ -136,7 +134,6 @@ export default class SenderToRecipient extends PureComponent { } wrapperClassName="sender-to-recipient__tooltip-wrapper" containerClassName="sender-to-recipient__tooltip-container" - onHidden={() => this.setState({ recipientAddressCopied: false })} >
    { addressOnly ? `${t('to')}: ` : '' } diff --git a/ui/app/pages/add-token/add-token.component.js b/ui/app/pages/add-token/add-token.component.js index 40c1ff7fd321..0db281b298ae 100644 --- a/ui/app/pages/add-token/add-token.component.js +++ b/ui/app/pages/add-token/add-token.component.js @@ -11,8 +11,6 @@ import PageContainer from '../../components/ui/page-container' import { Tabs, Tab } from '../../components/ui/tabs' const emptyAddr = '0x0000000000000000000000000000000000000000' -const SEARCH_TAB = 'SEARCH' -const CUSTOM_TOKEN_TAB = 'CUSTOM_TOKEN' class AddToken extends Component { static contextTypes = { @@ -42,7 +40,6 @@ class AddToken extends Component { customSymbolError: null, customDecimalsError: null, autoFilled: false, - displayedTab: SEARCH_TAB, forceEditSymbol: false, } } @@ -73,8 +70,7 @@ class AddToken extends Component { decimals: customDecimals = 0, } = customToken - const displayedTab = Object.keys(selectedTokens).length > 0 ? SEARCH_TAB : CUSTOM_TOKEN_TAB - this.setState({ selectedTokens, customAddress, customSymbol, customDecimals, displayedTab }) + this.setState({ selectedTokens, customAddress, customSymbol, customDecimals }) } } diff --git a/ui/app/pages/create-account/import-account/json.js b/ui/app/pages/create-account/import-account/json.js index c9ff8d926f52..7fd27264de3a 100644 --- a/ui/app/pages/create-account/import-account/json.js +++ b/ui/app/pages/create-account/import-account/json.js @@ -12,13 +12,8 @@ import Button from '../../../components/ui/button' const HELP_LINK = 'https://metamask.zendesk.com/hc/en-us/articles/360015489351-Importing-Accounts' class JsonImportSubview extends Component { - constructor (props) { - super(props) - - this.state = { - file: null, - fileContents: '', - } + state = { + fileContents: '', } render () { @@ -73,8 +68,10 @@ class JsonImportSubview extends Component { ) } - onLoad (event, file) { - this.setState({file: file, fileContents: event.target.result}) + onLoad (event) { + this.setState({ + fileContents: event.target.result, + }) } createKeyringOnEnter (event) { @@ -86,14 +83,7 @@ class JsonImportSubview extends Component { createNewKeychain () { const { firstAddress, displayWarning, importNewJsonAccount, setSelectedAddress, history } = this.props - const state = this.state - - if (!state) { - const message = this.context.t('validFileImport') - return displayWarning(message) - } - - const { fileContents } = state + const { fileContents } = this.state if (!fileContents) { const message = this.context.t('needImportFile') diff --git a/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js b/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js index e5edbc08da6a..bad912c0a6e5 100644 --- a/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js +++ b/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js @@ -64,7 +64,6 @@ export default class AddRecipient extends Component { state = { isShowingTransfer: false, - isShowingAllRecent: false, } selectRecipient = (to, nickname = '') => { diff --git a/ui/app/pages/send/send-content/add-recipient/ens-input.component.js b/ui/app/pages/send/send-content/add-recipient/ens-input.component.js index 5294388ac615..a4b5c8810059 100644 --- a/ui/app/pages/send/send-content/add-recipient/ens-input.component.js +++ b/ui/app/pages/send/send-content/add-recipient/ens-input.component.js @@ -37,10 +37,9 @@ export default class EnsInput extends Component { } state = { - recipient: null, input: '', toError: null, - toWarning: null, + ensResolution: undefined, } componentDidMount () { @@ -234,7 +233,7 @@ export default class EnsInput extends Component { } ensIconContents () { - const { loadingEns, ensFailure, ensResolution, toError } = this.state || { ensResolution: ZERO_ADDRESS } + const { loadingEns, ensFailure, ensResolution, toError } = this.state if (toError) { return diff --git a/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js b/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js index 9e3bc791bb0a..91489be1c870 100644 --- a/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js +++ b/ui/app/pages/settings/contact-list-tab/add-contact/add-contact.component.js @@ -23,7 +23,7 @@ export default class AddContact extends PureComponent { } state = { - nickname: '', + newName: '', ethAddress: '', ensAddress: '', error: '', From bb4c4189fb5c329f1ac79c95830dec181c7a6e34 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 3 Dec 2019 13:05:44 -0330 Subject: [PATCH 85/88] eslint: Enable more react/jsx-* rules (#7592) --- .eslintrc | 19 +++ development/mock-dev.js | 2 +- .../account-menu/account-menu.component.js | 16 +-- .../app/app-header/app-header.component.js | 3 +- ...onfirm-page-container-summary.component.js | 8 +- ...confirm-page-container-header.component.js | 54 ++++---- ...irm-page-container-navigation.component.js | 24 ++-- .../confirm-page-container.component.js | 20 +-- .../recipient-group.component.js | 8 +- .../components/network-dropdown-icon.js | 14 ++- .../app/dropdowns/tests/menu.test.js | 10 +- .../dropdowns/tests/network-dropdown.test.js | 2 +- .../advanced-gas-inputs.component.js | 22 ++-- .../advanced-tab-content.component.js | 22 ++-- .../advanced-tab-content-component.test.js | 26 ++-- .../basic-tab-content.component.js | 12 +- .../tests/basic-tab-content-component.test.js | 8 +- .../gas-modal-page-container.component.js | 15 +-- ...gas-modal-page-container-component.test.js | 84 +++++++------ .../gas-price-button-group.component.js | 34 ++--- .../gas-price-button-group-component.test.js | 8 +- .../gas-slider/gas-slider.component.js | 2 +- ui/app/components/app/input-number.js | 3 +- .../loading-network-screen.component.js | 64 +++++----- .../account-details-modal.component.js | 18 +-- .../confirm-remove-account.component.js | 4 +- .../deposit-ether-modal.component.js | 3 +- .../edit-approval-permission.component.js | 40 +++--- .../export-private-key-modal.component.js | 2 +- .../metametrics-opt-in-modal.component.js | 3 +- .../multiple-notifications.component.js | 10 +- .../network-display.component.js | 32 ++--- ...ovider-page-container-content.component.js | 2 +- .../tests/selected-account-component.test.js | 10 +- .../app/sidebars/sidebar.component.js | 16 +-- .../sidebars/tests/sidebars-component.test.js | 14 ++- .../signature-request-original.component.js | 50 ++++---- .../signature-request-header.component.js | 10 +- .../tests/signature-request.test.js | 15 ++- .../app/token-cell/token-cell.component.js | 3 +- ui/app/components/app/token-list.js | 12 +- .../transaction-action.component.test.js | 12 +- .../transaction-breakdown.component.js | 26 ++-- ...transaction-list-item-details.component.js | 20 +-- .../transaction-list-item.component.js | 18 +-- .../token-view-balance.component.test.js | 38 +++--- .../app/wallet-view/wallet-view.component.js | 8 +- .../ui/button-group/button-group.stories.js | 8 +- .../tests/button-group-component.test.js | 16 ++- ui/app/components/ui/button/button.stories.js | 28 ++--- .../tests/currency-display.component.test.js | 22 ++-- .../ui/eth-balance/eth-balance.component.js | 44 ++++--- .../tests/hex-to-decimal.component.test.js | 20 +-- .../tests/identicon.component.test.js | 2 +- .../page-container-footer.component.js | 18 +-- .../page-container-footer.component.test.js | 18 +-- .../page-container-header.component.js | 26 ++-- .../page-container-header.component.test.js | 20 +-- .../sender-to-recipient.component.js | 4 +- .../ui/text-field/text-field.stories.js | 28 ++--- .../token-list/token-list.component.js | 3 +- .../confirm-approve-content.component.js | 57 +++++---- .../confirm-approve.component.js | 40 +++--- .../confirm-transaction-base.component.js | 68 +++++----- .../connect-hardware/connect-screen.js | 3 +- .../create-account.component.js | 18 +-- .../create-account/import-account/index.js | 3 +- .../create-account/new-account.component.js | 11 +- .../import-with-seed-phrase.component.js | 3 +- .../new-account/new-account.component.js | 3 +- .../end-of-flow/end-of-flow.component.js | 9 +- .../metametrics-opt-in.component.js | 3 +- .../reveal-seed-phrase.component.js | 21 ++-- ui/app/pages/home/home.component.js | 90 +++++++------- .../account-list-item.component.js | 72 ++++++----- .../tests/account-list-item-component.test.js | 24 ++-- .../add-recipient/add-recipient.component.js | 2 +- .../tests/add-recipient-component.test.js | 36 +++--- .../tests/amount-max-button-component.test.js | 20 +-- .../tests/send-amount-row-component.test.js | 36 +++--- .../send-asset-row.component.js | 3 +- .../send-dropdown-list.component.js | 40 +++--- .../send-dropdown-list-component.test.js | 24 ++-- .../gas-fee-display.component.js | 16 ++- .../test/gas-fee-display.component.test.js | 18 +-- .../send-gas-row/send-gas-row.component.js | 117 ++++++++++-------- .../tests/send-gas-row-component.test.js | 30 ++--- .../send-row-error-message-component.test.js | 10 +- .../tests/send-row-wrapper-component.test.js | 52 ++++---- .../tests/send-footer-component.test.js | 90 +++++++------- .../tests/send-header-component.test.js | 12 +- .../pages/send/tests/send-component.test.js | 56 +++++---- .../add-contact/add-contact.component.js | 12 +- .../contact-list-tab.component.js | 49 +++++--- .../edit-contact/edit-contact.component.js | 2 +- .../networks-tab/networks-tab.component.js | 34 ++--- ui/app/pages/settings/settings.component.js | 20 +-- 97 files changed, 1244 insertions(+), 963 deletions(-) diff --git a/.eslintrc b/.eslintrc index f77127da80d5..74b30dcbed92 100644 --- a/.eslintrc +++ b/.eslintrc @@ -156,6 +156,25 @@ "react/jsx-equals-spacing": 2, "react/no-deprecated": 0, "react/default-props-match-prop-types": 2, + "react/jsx-closing-tag-location": 2, + "react/jsx-no-duplicate-props": 2, + "react/jsx-closing-bracket-location": 2, + "react/jsx-first-prop-new-line": 2, + "react/jsx-max-props-per-line": [2, { "maximum": 1, "when": "multiline"} ], + "react/jsx-tag-spacing": [2, { + "closingSlash": "never", + "beforeSelfClosing": "always", + "afterOpening": "never" + }], + "react/jsx-wrap-multilines": [2, { + "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" + }], "semi": [2, "never"], "semi-spacing": [2, { "before": false, "after": true }], "space-before-blocks": [2, "always"], diff --git a/development/mock-dev.js b/development/mock-dev.js index 16fdd0273a43..51a8cde46316 100644 --- a/development/mock-dev.js +++ b/development/mock-dev.js @@ -135,7 +135,7 @@ function startApp () { margin: '20px', }} > - +
    , container, 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 7be2bc5ddccc..c13163a8172d 100644 --- a/ui/app/components/app/account-menu/account-menu.component.js +++ b/ui/app/components/app/account-menu/account-menu.component.js @@ -253,12 +253,12 @@ export default class AccountMenu extends PureComponent { }) history.push(NEW_ACCOUNT_ROUTE) }} - icon={ + icon={( - } + )} text={t('createAccount')} /> - } + )} text={t('importAccount')} /> - } + )} text={t('connectHardwareWallet')} /> @@ -328,12 +328,12 @@ export default class AccountMenu extends PureComponent { }, }) }} - icon={ + icon={( - } + )} text={t('settings')} /> diff --git a/ui/app/components/app/app-header/app-header.component.js b/ui/app/components/app/app-header/app-header.component.js index e1bc0cf24e74..bd01558c5eee 100644 --- a/ui/app/components/app/app-header/app-header.component.js +++ b/ui/app/components/app/app-header/app-header.component.js @@ -89,7 +89,8 @@ export default class AppHeader extends PureComponent { return (
    + className={classnames('app-header', { 'app-header--back-drop': isUnlocked })} + >
    {
    { - hideSubtitle ||
    - { subtitleComponent || subtitle } -
    + hideSubtitle || ( +
    + { subtitleComponent || subtitle } +
    + ) }
    ) 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 898d59068923..4b91b4ddb2e6 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 @@ -34,36 +34,40 @@ export default class ConfirmPageContainerHeader extends Component { return (
    { !showAccountInHeader - ?
    - - onEdit()} + ? ( +
    - { this.context.t('edit') } - -
    + + onEdit()} + > + { this.context.t('edit') } + +
    + ) : null } { showAccountInHeader - ?
    -
    - -
    -
    - { addressSlicer(accountAddress) } + ? ( +
    +
    + +
    +
    + { addressSlicer(accountAddress) } +
    -
    + ) : null } { !isFullScreen && } 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 c24d24b1706a..dd1fd2da481b 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 @@ -5,23 +5,28 @@ const ConfirmPageContainerNavigation = props => { const { onNextTx, totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation, firstTx, lastTx, ofText, requestsWaitingText } = props return ( -
    -
    + }} + >
    onNextTx(firstTx)}> + onClick={() => onNextTx(firstTx)} + >
    onNextTx(prevTxId)}> + onClick={() => onNextTx(prevTxId)} + >
    @@ -37,15 +42,18 @@ const ConfirmPageContainerNavigation = props => { className="confirm-page-container-navigation__container" style={{ visibility: nextTxId ? 'initial' : 'hidden', - }}> + }} + >
    onNextTx(nextTxId)}> + onClick={() => onNextTx(nextTxId)} + >
    onNextTx(lastTx)}> + onClick={() => 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 86ce2bff713d..9ebae3d95dd1 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 @@ -133,15 +133,17 @@ export default class ConfirmPageContainer extends Component { > { hideSenderToRecipient ? null - : + : ( + + ) } { 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 a2248326ec2f..20e2b34946b5 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 @@ -15,9 +15,11 @@ export default function RecipientGroup ({ label, items, onSelect, selectedAddres return (
    - {label &&
    - {label} -
    } + {label && ( +
    + {label} +
    + )} { items.map(({ address, name }) => (
    -
    +
    ) } diff --git a/ui/app/components/app/dropdowns/tests/menu.test.js b/ui/app/components/app/dropdowns/tests/menu.test.js index 56cec93a3cf7..b3bc34fa9978 100644 --- a/ui/app/components/app/dropdowns/tests/menu.test.js +++ b/ui/app/components/app/dropdowns/tests/menu.test.js @@ -11,7 +11,7 @@ describe('Dropdown Menu Components', () => { beforeEach(() => { wrapper = shallow( - + ) }) @@ -73,9 +73,11 @@ describe('Dropdown Menu Components', () => { const onClickSpy = sinon.spy() beforeEach(() => { - wrapper = shallow() + wrapper = shallow(( + + )) }) it('simulates click', () => { 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 4a81b973fd9c..98cba1d2e287 100644 --- a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js +++ b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js @@ -57,7 +57,7 @@ describe('Network Dropdown', () => { beforeEach(() => { wrapper = mountWithRouter( - , + , ) }) 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 7fb5aa6f4002..b881db6e5aac 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 @@ -119,10 +119,12 @@ export default class AdvancedGasInputs extends Component { value={value} onChange={onChange} /> -
    +
    onChange({ target: { value: value + 1 } })} @@ -159,21 +161,21 @@ export default class AdvancedGasInputs extends Component { errorText: gasPriceErrorText, errorType: gasPriceErrorType, } = this.gasPriceError({ insufficientBalance, customPriceIsSafe, isSpeedUp, gasPrice }) - const gasPriceErrorComponent = gasPriceErrorType ? + const gasPriceErrorComponent = gasPriceErrorType ? (
    { gasPriceErrorText } -
    : - null +
    + ) : null const { errorText: gasLimitErrorText, errorType: gasLimitErrorType, } = this.gasLimitError({ insufficientBalance, gasLimit }) - const gasLimitErrorComponent = gasLimitErrorType ? + const gasLimitErrorComponent = gasLimitErrorType ? (
    { gasLimitErrorText } -
    : - null +
    + ) : null return (
    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 306dd03a0885..19e3aa776432 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 @@ -83,17 +83,19 @@ export default class AdvancedTabContent extends Component { />
    { isEthereumNetwork - ?
    -
    { t('liveGasPricePredictions') }
    - {!gasEstimatesLoading - ? - : - } -
    - { t('slower') } - { t('faster') } + ? ( +
    +
    { t('liveGasPricePredictions') }
    + {!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 05075f3ba14a..16b15df4125f 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 @@ -18,18 +18,20 @@ describe('AdvancedTabContent Component', function () { let wrapper beforeEach(() => { - wrapper = shallow() + wrapper = shallow(( + + )) }) afterEach(() => { 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 c804abe3a736..94d22ee4a100 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 @@ -21,11 +21,13 @@ export default class BasicTabContent extends Component {
    { 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 0989ac6770be..80fbffe05be3 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 @@ -38,9 +38,11 @@ describe('BasicTabContent Component', function () { let wrapper beforeEach(() => { - wrapper = shallow() + wrapper = shallow(( + + )) }) describe('render', () => { 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 f405cb7b9d07..daf91eae3e0f 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 @@ -160,13 +160,14 @@ export default class GasModalPageContainer extends Component { return ( - {tabsToRender.map(({ name, content }, i) => -
    - { content } - { this.renderInfoRows(newTotalFiat, newTotalEth, sendAmount, transactionFee) } -
    -
    - )} + {tabsToRender.map(({ name, content }, i) => ( + +
    + { content } + { this.renderInfoRows(newTotalFiat, newTotalEth, sendAmount, transactionFee) } +
    +
    + ))}
    ) } 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 3e416db4920a..50efb46f0a9d 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 @@ -63,23 +63,25 @@ describe('GasModalPageContainer Component', function () { let wrapper beforeEach(() => { - wrapper = shallow( 'mockupdateCustomGasPrice'} - updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} - customGasPrice={21} - customGasLimit={54321} - gasPriceButtonGroupProps={mockGasPriceButtonGroupProps} - infoRowProps={mockInfoRowProps} - currentTimeEstimate="1 min 31 sec" - customGasPriceInHex="mockCustomGasPriceInHex" - customGasLimitInHex="mockCustomGasLimitInHex" - insufficientBalance={false} - disableSave={false} - />) + wrapper = shallow(( + 'mockupdateCustomGasPrice'} + updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} + customGasPrice={21} + customGasLimit={54321} + gasPriceButtonGroupProps={mockGasPriceButtonGroupProps} + infoRowProps={mockInfoRowProps} + currentTimeEstimate="1 min 31 sec" + customGasPriceInHex="mockCustomGasPriceInHex" + customGasLimitInHex="mockCustomGasLimitInHex" + insufficientBalance={false} + disableSave={false} + /> + )) }) afterEach(() => { @@ -134,10 +136,12 @@ describe('GasModalPageContainer Component', function () { it('should pass the correct renderTabs property to PageContainer', () => { sinon.stub(GP, 'renderTabs').returns('mockTabs') - const renderTabsWrapperTester = shallow(, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }) + const renderTabsWrapperTester = shallow(( + + ), { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }) const { tabsComponent } = renderTabsWrapperTester.find(PageContainer).props() assert.equal(tabsComponent, 'mockTabs') GasModalPageContainer.prototype.renderTabs.restore() @@ -184,24 +188,26 @@ describe('GasModalPageContainer Component', function () { }) it('should not render the basic tab if hideBasic is true', () => { - wrapper = shallow( 'mockupdateCustomGasPrice'} - updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} - customGasPrice={21} - customGasLimit={54321} - gasPriceButtonGroupProps={mockGasPriceButtonGroupProps} - infoRowProps={mockInfoRowProps} - currentTimeEstimate="1 min 31 sec" - customGasPriceInHex="mockCustomGasPriceInHex" - customGasLimitInHex="mockCustomGasLimitInHex" - insufficientBalance={false} - disableSave={false} - hideBasic - />) + wrapper = shallow(( + 'mockupdateCustomGasPrice'} + updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} + customGasPrice={21} + customGasLimit={54321} + gasPriceButtonGroupProps={mockGasPriceButtonGroupProps} + infoRowProps={mockInfoRowProps} + currentTimeEstimate="1 min 31 sec" + customGasPriceInHex="mockCustomGasPriceInHex" + customGasLimitInHex="mockCustomGasLimitInHex" + insufficientBalance={false} + disableSave={false} + hideBasic + /> + )) const renderTabsResult = wrapper.instance().renderTabs() const renderedTabs = shallow(renderTabsResult) 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 0412b3381d11..b578ff1ed46a 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 @@ -49,13 +49,15 @@ export default class GasPriceButtonGroup extends Component { className, showCheck, }) { - return (
    - { gasEstimateType &&
    { this.gasEstimateTypeLabel(gasEstimateType) }
    } - { timeEstimate &&
    { timeEstimate }
    } - { feeInPrimaryCurrency &&
    { feeInPrimaryCurrency }
    } - { feeInSecondaryCurrency &&
    { feeInSecondaryCurrency }
    } - { showCheck &&
    } -
    ) + return ( +
    + { gasEstimateType &&
    { this.gasEstimateTypeLabel(gasEstimateType) }
    } + { timeEstimate &&
    { timeEstimate }
    } + { feeInPrimaryCurrency &&
    { feeInPrimaryCurrency }
    } + { feeInSecondaryCurrency &&
    { feeInSecondaryCurrency }
    } + { showCheck &&
    } +
    + ) } renderButton ({ @@ -88,14 +90,16 @@ export default class GasPriceButtonGroup extends Component { return ( !buttonDataLoading - ? - { gasButtonInfo.map((obj, index) => this.renderButton(obj, buttonPropsAndFlags, index)) } - + ? ( + + { gasButtonInfo.map((obj, index) => this.renderButton(obj, buttonPropsAndFlags, index)) } + + ) :
    { this.context.t('loading') }
    ) } 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 85f53d08e993..1d924f850ab4 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 @@ -48,9 +48,11 @@ describe('GasPriceButtonGroup Component', function () { let wrapper beforeEach(() => { - wrapper = shallow() + wrapper = shallow(( + + )) }) afterEach(() => { 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 8233dedb5adc..629d81f0ec26 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 @@ -36,7 +36,7 @@ export default class GasSlider extends Component { onChange={event => onChange(event.target.value)} />
    -
    +
    {lowLabel} diff --git a/ui/app/components/app/input-number.js b/ui/app/components/app/input-number.js index d511dd0d68a0..7506808b386d 100644 --- a/ui/app/components/app/input-number.js +++ b/ui/app/components/app/input-number.js @@ -69,7 +69,8 @@ InputNumber.prototype.render = function InputNumber () { /> {unitLabel}
    -
    this.setValue(addCurrencies(value, step, { toNumericBase: 'dec' }))} > 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 97b16d08fb57..22419aabee39 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 @@ -61,42 +61,46 @@ export default class LoadingNetworkScreen extends PureComponent { } renderLoadingScreenContent = () => { - return
    - - {this.renderMessage()} -
    + return ( +
    + + {this.renderMessage()} +
    + ) } renderErrorScreenContent = () => { const { showNetworkDropdown, setProviderArgs, setProviderType } = this.props - return
    - 😞 - { this.context.t('somethingWentWrong') } -
    - - - + return ( +
    + 😞 + { this.context.t('somethingWentWrong') } +
    + + + +
    -
    + ) } cancelCall = () => { 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 1b9a6a718520..b2ed1a8cc448 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 @@ -56,7 +56,7 @@ export default class AccountDetailsModal extends Component { }} /> -
    +
    + ? ( + + ) : null } diff --git a/ui/app/components/app/modals/confirm-remove-account/confirm-remove-account.component.js b/ui/app/components/app/modals/confirm-remove-account/confirm-remove-account.component.js index 7fe79be5b8b0..7bea983b4f66 100644 --- a/ui/app/components/app/modals/confirm-remove-account/confirm-remove-account.component.js +++ b/ui/app/components/app/modals/confirm-remove-account/confirm-remove-account.component.js @@ -78,7 +78,9 @@ export default class ConfirmRemoveAccount extends Component { + target="_blank" + href="https://metamask.zendesk.com/hc/en-us/articles/360015289932" + > { t('learnMore') }
    diff --git a/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js b/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js index c251aee667c7..d503d950ef50 100644 --- a/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js +++ b/ui/app/components/app/modals/deposit-ether-modal/deposit-ether-modal.component.js @@ -84,7 +84,8 @@ export default class DepositEtherModal extends Component { return (
    + className="page-container page-container--full-width page-container--full-height" + >
    {this.context.t('depositEther')} diff --git a/ui/app/components/app/modals/edit-approval-permission/edit-approval-permission.component.js b/ui/app/components/app/modals/edit-approval-permission/edit-approval-permission.component.js index 53ff473e4b51..661bbdefdb8a 100644 --- a/ui/app/components/app/modals/edit-approval-permission/edit-approval-permission.component.js +++ b/ui/app/components/app/modals/edit-approval-permission/edit-approval-permission.component.js @@ -76,18 +76,22 @@ export default class EditApprovalPermission extends PureComponent { className="edit-approval-permission__edit-section__radio-button" onClick={() => this.setState({ selectedOptionIsUnlimited: true })} > -
    +
    { selectedOptionIsUnlimited &&
    }
    -
    +
    { tokenAmount < tokenBalance ? t('proposedApprovalLimit') @@ -107,18 +111,22 @@ export default class EditApprovalPermission extends PureComponent { className="edit-approval-permission__edit-section__radio-button" onClick={() => this.setState({ selectedOptionIsUnlimited: false })} > -
    +
    { !selectedOptionIsUnlimited &&
    }
    -
    +
    { t('customSpendLimit') }
    diff --git a/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js index 264bcc04175d..fd70cbc5b24a 100644 --- a/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js +++ b/ui/app/components/app/modals/export-private-key-modal/export-private-key-modal.component.js @@ -149,7 +149,7 @@ export default class ExportPrivateKeyModal extends Component { inputClass="qr-ellip-address ellip-address" value={checksumAddress(address)} /> -
    +
    {this.context.t('showPrivateKeys')}
    {this.renderPasswordLabel(privateKey)} 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 6f3225382016..9dc9533156f3 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 @@ -75,7 +75,8 @@ export default class MetaMetricsOptInModal extends Component {
    - 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.setState({ showAll: !showAll })} > - {childrenToRender.length > 1 ? : null} + {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 bcac637bd4e0..1ecec3179d94 100644 --- a/ui/app/components/app/network-display/network-display.component.js +++ b/ui/app/components/app/network-display/network-display.component.js @@ -38,13 +38,15 @@ export default class NetworkDisplay extends Component { return networkClass ?
    - :
    + : ( +
    + ) } render () { @@ -61,13 +63,15 @@ export default class NetworkDisplay extends Component { { networkClass ?
    - :
    + : ( +
    + ) }
    { type === 'rpc' && nickname ? nickname : this.context.t(type) } diff --git a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js b/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js index 4062b130f69e..4f94015b13bc 100644 --- a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js +++ b/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js @@ -68,7 +68,7 @@ export default class ProviderPageContainerContent extends PureComponent {

    {t('providerRequest', [title])}

    {t('providerRequestInfo')} -
    +
    { it('should render checksummed address', () => { - const wrapper = render(, { context: { t: () => {}}}) + const wrapper = render(( + + ), { context: { t: () => {}}}) // Checksummed version of address is displayed 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 484b87e4b789..6437675c949f 100644 --- a/ui/app/components/app/sidebars/sidebar.component.js +++ b/ui/app/components/app/sidebars/sidebar.component.js @@ -20,13 +20,15 @@ export default class Sidebar extends Component { renderOverlay () { const { onOverlayClose } = this.props - return

    { - onOverlayClose && onOverlayClose() - this.props.hideSidebar() - } - } /> + return ( +
    { + onOverlayClose && onOverlayClose() + this.props.hideSidebar() + }} + /> + ) } renderSidebarContent () { 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 5f6657dde1a1..3416ad8f67b9 100644 --- a/ui/app/components/app/sidebars/tests/sidebars-component.test.js +++ b/ui/app/components/app/sidebars/tests/sidebars-component.test.js @@ -16,12 +16,14 @@ describe('Sidebar Component', function () { let wrapper beforeEach(() => { - wrapper = shallow() + wrapper = shallow(( + + )) }) afterEach(() => { 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 2485ae5068f4..9a92ba5fbeaf 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 @@ -171,22 +171,26 @@ export default class SignatureRequestOriginal extends Component {
    { domain - ?
    -

    - Domain -

    - -
    + ? ( +
    +

    + Domain +

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

    - Message -

    - -
    + ? ( +
    +

    + Message +

    + +
    + ) : '' }
    @@ -221,16 +225,18 @@ export default class SignatureRequestOriginal extends Component { { notice } { type === 'eth_sign' - ? { - global.platform.openWindow({ - url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751', - }) - }} - > - { this.context.t('learnMore') } - + ? ( + { + global.platform.openWindow({ + url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751', + }) + }} + > + { this.context.t('learnMore') } + + ) : null }
    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 3ac0c9afb61e..661a933a086b 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 @@ -14,10 +14,12 @@ export default class SignatureRequestHeader extends PureComponent { return (
    - {selectedAccount && } + {selectedAccount && ( + + )} {name}
    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 68b114dd8a69..6ff07effc389 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 @@ -8,11 +8,16 @@ describe('Signature Request Component', function () { let wrapper beforeEach(() => { - wrapper = shallow() + wrapper = shallow(( + + )) }) describe('render', () => { diff --git a/ui/app/components/app/token-cell/token-cell.component.js b/ui/app/components/app/token-cell/token-cell.component.js index 10a3447d122b..dc2bbb6d3a5c 100644 --- a/ui/app/components/app/token-cell/token-cell.component.js +++ b/ui/app/components/app/token-cell/token-cell.component.js @@ -107,7 +107,8 @@ export default class TokenCell extends Component {
    )}
    - { e.stopPropagation() this.setState({ tokenMenuOpen: true }) diff --git a/ui/app/components/app/token-list.js b/ui/app/components/app/token-list.js index 7917cd54ad83..ee2f85cacbee 100644 --- a/ui/app/components/app/token-list.js +++ b/ui/app/components/app/token-list.js @@ -66,12 +66,16 @@ TokenList.prototype.render = function TokenList () { if (error) { log.error(error) return ( -
    +
    {this.context.t('troubleTokenBalances')} { }, } - const wrapper = shallow(, { context: { t }}) + const wrapper = shallow(( + + ), { context: { t }}) assert.equal(wrapper.find('.transaction-action').length, 1) wrapper.setState({ transactionAction: 'sentEther' }) 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 5642e0fa528e..0e1073337573 100644 --- a/ui/app/components/app/transaction-breakdown/transaction-breakdown.component.js +++ b/ui/app/components/app/transaction-breakdown/transaction-breakdown.component.js @@ -50,10 +50,12 @@ export default class TransactionBreakdown extends PureComponent { className="transaction-breakdown__row-title" > {typeof gas !== 'undefined' - ? + ? ( + + ) : '?' } @@ -72,13 +74,15 @@ export default class TransactionBreakdown extends PureComponent { } {typeof gasPrice !== 'undefined' - ? + ? ( + + ) : '?' } 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 554e99a5b22c..f3bd51b9397c 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 @@ -191,15 +191,17 @@ export default class TransactionListItemDetails extends PureComponent { { - showRetry && - - + showRetry && ( + + + + ) }
    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 9ab0105f992f..3106f7fc3661 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 @@ -236,18 +236,22 @@ export default class TransactionListItem extends PureComponent { )} /> { showEstimatedTime - ? + ? ( + + ) : null } { this.renderPrimaryCurrency() } { this.renderSecondaryCurrency() }
    -
    +
    { showTransactionDetails && (
    diff --git a/ui/app/components/app/transaction-view-balance/tests/token-view-balance.component.test.js b/ui/app/components/app/transaction-view-balance/tests/token-view-balance.component.test.js index 0e2882e9c0e2..d948355fc3bd 100644 --- a/ui/app/components/app/transaction-view-balance/tests/token-view-balance.component.test.js +++ b/ui/app/components/app/transaction-view-balance/tests/token-view-balance.component.test.js @@ -25,14 +25,16 @@ describe('TransactionViewBalance Component', () => { }) it('should render ETH balance properly', () => { - const wrapper = shallow(, { context: { t, metricsEvent } }) + const wrapper = shallow(( + + ), { context: { t, metricsEvent } }) assert.equal(wrapper.find('.transaction-view-balance').length, 1) assert.equal(wrapper.find('.transaction-view-balance__button').length, 2) @@ -55,15 +57,17 @@ describe('TransactionViewBalance Component', () => { symbol: 'ABC', } - const wrapper = shallow(, { context: { t } }) + const wrapper = shallow(( + + ), { context: { t } }) assert.equal(wrapper.find('.transaction-view-balance').length, 1) assert.equal(wrapper.find('.transaction-view-balance__button').length, 1) diff --git a/ui/app/components/app/wallet-view/wallet-view.component.js b/ui/app/components/app/wallet-view/wallet-view.component.js index bf3c976500cf..ceccfea51bdc 100644 --- a/ui/app/components/app/wallet-view/wallet-view.component.js +++ b/ui/app/components/app/wallet-view/wallet-view.component.js @@ -44,9 +44,11 @@ export default class WalletView extends Component { } = this.props return ( -
    +
    { 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 c58c628b3353..1596680c1a4b 100644 --- a/ui/app/components/ui/button-group/button-group.stories.js +++ b/ui/app/components/ui/button-group/button-group.stories.js @@ -6,7 +6,7 @@ import Button from '../button' import { text, boolean } from '@storybook/addon-knobs/react' storiesOf('ButtonGroup', module) - .add('with Buttons', () => + .add('with Buttons', () => ( - ) - .add('with a disabled Button', () => + )) + .add('with a disabled Button', () => ( - ) + )) diff --git a/ui/app/components/ui/button-group/tests/button-group-component.test.js b/ui/app/components/ui/button-group/tests/button-group-component.test.js index 663d86c74c44..b07b16cc9238 100644 --- a/ui/app/components/ui/button-group/tests/button-group-component.test.js +++ b/ui/app/components/ui/button-group/tests/button-group-component.test.js @@ -21,12 +21,16 @@ describe('ButtonGroup Component', function () { let wrapper beforeEach(() => { - wrapper = shallow({mockButtons}) + wrapper = shallow(( + + {mockButtons} + + )) }) afterEach(() => { diff --git a/ui/app/components/ui/button/button.stories.js b/ui/app/components/ui/button/button.stories.js index 9df53439dde3..6540d5aa1fee 100644 --- a/ui/app/components/ui/button/button.stories.js +++ b/ui/app/components/ui/button/button.stories.js @@ -6,7 +6,7 @@ import { text, boolean } from '@storybook/addon-knobs/react' // ', 'secondary', 'default', 'warning', 'danger', 'danger-primary', 'link'], 'primary')} storiesOf('Button', module) - .add('Button - Primary', () => + .add('Button - Primary', () => ( - ) - .add('Button - Secondary', () => + )) + .add('Button - Secondary', () => ( - ) - .add('Button - Default', () => + )) + .add('Button - Default', () => ( - ) - .add('Button - Warning', () => + )) + .add('Button - Warning', () => ( - ) - .add('Button - Danger', () => + )) + .add('Button - Danger', () => ( - ) - .add('Button - Danger Primary', () => + )) + .add('Button - Danger Primary', () => ( - ) - .add('Button - Link', () => + )) + .add('Button - Link', () => ( - ) + )) 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 d9ef052f1bf2..387493da6499 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 @@ -5,21 +5,25 @@ import CurrencyDisplay from '../currency-display.component' describe('CurrencyDisplay Component', () => { it('should render text with a className', () => { - 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', () => { - 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/eth-balance/eth-balance.component.js b/ui/app/components/ui/eth-balance/eth-balance.component.js index fedbcc192c9e..925395602d4a 100644 --- a/ui/app/components/ui/eth-balance/eth-balance.component.js +++ b/ui/app/components/ui/eth-balance/eth-balance.component.js @@ -67,29 +67,36 @@ export default class EthBalance extends Component { return (
    -
    -
    +
    +
    { incoming ? `+${balanceToRender}` : balanceToRender }
    -
    +
    {label}
    @@ -120,7 +127,8 @@ export default class EthBalance extends Component {
    + }} + > {this.renderBalance(formattedValue)}
    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 c98da9ad40ba..848ef2c4f0bb 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,20 +5,24 @@ import HexToDecimal from '../hex-to-decimal.component' describe('HexToDecimal Component', () => { it('should render a prefixed hex as a decimal with a className', () => { - 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', () => { - 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/identicon/tests/identicon.component.test.js b/ui/app/components/ui/identicon/tests/identicon.component.test.js index 2944818f5f31..b1efb158cb17 100644 --- a/ui/app/components/ui/identicon/tests/identicon.component.test.js +++ b/ui/app/components/ui/identicon/tests/identicon.component.test.js @@ -18,7 +18,7 @@ describe('Identicon', () => { it('renders default eth_logo identicon with no props', () => { const wrapper = mount( - + ) assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg') 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 a2cf0100bf22..da8da45d1a06 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 @@ -37,14 +37,16 @@ export default class PageContainerFooter extends Component {
    - {!hideCancel && } + {!hideCancel && ( + + )} + > + {this.context.t('cancel')} + + > + {this.context.t('create')} +
    ) 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 1fae5351c08a..53d4614ade87 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 @@ -283,7 +283,8 @@ export default class ImportWithSeedPhrase extends PureComponent { {termsChecked ? : null}
    - I have read and agree to the
    : null}
    - I have read and agree to the ) diff --git a/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js b/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js index ad1ffbf428b3..14c85b92388e 100644 --- a/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js +++ b/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js @@ -142,7 +142,8 @@ export default class MetaMetricsOptIn extends Component { disabled={false} /> diff --git a/ui/app/pages/home/home.component.js b/ui/app/pages/home/home.component.js index e51c8217798a..64526fe31f19 100644 --- a/ui/app/pages/home/home.component.js +++ b/ui/app/pages/home/home.component.js @@ -124,56 +124,62 @@ export default class Home extends PureComponent { { showPrivacyModeNotification - ? { - unsetMigratedPrivacyMode() - window.open('https://medium.com/metamask/42549d4870fa', '_blank', 'noopener') - }} - ignoreText={t('dismiss')} - onIgnore={() => { - unsetMigratedPrivacyMode() - }} - key="home-privacyModeDefault" - /> + ? ( + { + unsetMigratedPrivacyMode() + window.open('https://medium.com/metamask/42549d4870fa', '_blank', 'noopener') + }} + ignoreText={t('dismiss')} + onIgnore={() => { + unsetMigratedPrivacyMode() + }} + key="home-privacyModeDefault" + /> + ) : null } { shouldShowSeedPhraseReminder - ? { - if (isPopup) { - global.platform.openExtensionInBrowser(INITIALIZE_BACKUP_SEED_PHRASE_ROUTE) - } else { - history.push(INITIALIZE_BACKUP_SEED_PHRASE_ROUTE) - } - }} - infoText={t('backupApprovalInfo')} - key="home-backupApprovalNotice" - /> + ? ( + { + if (isPopup) { + global.platform.openExtensionInBrowser(INITIALIZE_BACKUP_SEED_PHRASE_ROUTE) + } else { + history.push(INITIALIZE_BACKUP_SEED_PHRASE_ROUTE) + } + }} + infoText={t('backupApprovalInfo')} + key="home-backupApprovalNotice" + /> + ) : null } { threeBoxLastUpdated && showRestorePrompt - ? { - restoreFromThreeBox(selectedAddress) - .then(() => { - turnThreeBoxSyncingOn() - }) - }} - onIgnore={() => { - setShowRestorePromptToFalse() - }} - key="home-privacyModeDefault" - /> + ? ( + { + restoreFromThreeBox(selectedAddress) + .then(() => { + turnThreeBoxSyncingOn() + }) + }} + onIgnore={() => { + setShowRestorePromptToFalse() + }} + key="home-privacyModeDefault" + /> + ) : null } { diff --git a/ui/app/pages/send/account-list-item/account-list-item.component.js b/ui/app/pages/send/account-list-item/account-list-item.component.js index 20ced2f099e8..8c676f4197bb 100644 --- a/ui/app/pages/send/account-list-item/account-list-item.component.js +++ b/ui/app/pages/send/account-list-item/account-list-item.component.js @@ -44,30 +44,32 @@ export default class AccountListItem extends Component { const { name, address, balance } = account || {} - return (
    handleClick && handleClick({ name, address, balance })} - > + return ( +
    handleClick && handleClick({ name, address, balance })} + > -
    - +
    + -
    { name || address }
    +
    { name || address }
    - {icon &&
    { icon }
    } + {icon &&
    { icon }
    } -
    +
    - {displayAddress && name &&
    - { checksumAddress(address) } -
    } + {displayAddress && name && ( +
    + { checksumAddress(address) } +
    + )} - { - displayBalance && ( + {displayBalance && ( -
    +
    { - balanceIsCached ? * : null + balanceIsCached + ? * + : null }
    - { - showFiat && ( - - ) - } + {showFiat && ( + + )}
    - ) - } + )} -
    ) +
    + ) } } diff --git a/ui/app/pages/send/account-list-item/tests/account-list-item-component.test.js b/ui/app/pages/send/account-list-item/tests/account-list-item-component.test.js index 5a2bd563806b..e54a8c493eca 100644 --- a/ui/app/pages/send/account-list-item/tests/account-list-item-component.test.js +++ b/ui/app/pages/send/account-list-item/tests/account-list-item-component.test.js @@ -23,17 +23,19 @@ describe('AccountListItem Component', function () { let wrapper beforeEach(() => { - wrapper = shallow(} - />, { context: { t: str => str + '_t' } }) + wrapper = shallow(( + } + /> + ), { context: { t: str => str + '_t' } }) }) afterEach(() => { diff --git a/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js b/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js index bad912c0a6e5..a2e6b49db3ee 100644 --- a/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js +++ b/ui/app/pages/send/send-content/add-recipient/add-recipient.component.js @@ -155,7 +155,7 @@ export default class AddRecipient extends Component { className="send__select-recipient-wrapper__list__link" onClick={() => this.setState({ isShowingTransfer: false })} > -
    +
    { t('backToAll') }
    { - wrapper = shallow(, { context: { t: str => str + '_t' } }) + wrapper = shallow(( + + ), { context: { t: str => str + '_t' } }) instance = wrapper.instance() }) diff --git a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js index 30ef4c6789a1..48bc32d3ac59 100644 --- a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js +++ b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js @@ -18,15 +18,17 @@ describe('AmountMaxButton Component', function () { let instance beforeEach(() => { - wrapper = shallow(, { + wrapper = shallow(( + + ), { context: { t: str => str + '_t', metricsEvent: () => {}, diff --git a/ui/app/pages/send/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/pages/send/send-content/send-amount-row/tests/send-amount-row-component.test.js index bfc0f7e64baa..fe648d4d8091 100644 --- a/ui/app/pages/send/send-content/send-amount-row/tests/send-amount-row-component.test.js +++ b/ui/app/pages/send/send-content/send-amount-row/tests/send-amount-row-component.test.js @@ -25,23 +25,25 @@ describe('SendAmountRow Component', function () { let instance beforeEach(() => { - wrapper = shallow(, { context: { t: str => str + '_t' } }) + wrapper = shallow(( + + ), { context: { t: str => str + '_t' } }) instance = wrapper.instance() }) diff --git a/ui/app/pages/send/send-content/send-asset-row/send-asset-row.component.js b/ui/app/pages/send/send-content/send-asset-row/send-asset-row.component.js index 1dcd0bd2c2c5..c0b604505345 100644 --- a/ui/app/pages/send/send-content/send-asset-row/send-asset-row.component.js +++ b/ui/app/pages/send/send-content/send-asset-row/send-asset-row.component.js @@ -128,7 +128,8 @@ export default class SendAssetRow extends Component { return (
    this.selectToken(address)} >
    diff --git a/ui/app/pages/send/send-content/send-dropdown-list/send-dropdown-list.component.js b/ui/app/pages/send/send-content/send-dropdown-list/send-dropdown-list.component.js index 5f5d262311f9..42b19397b192 100644 --- a/ui/app/pages/send/send-content/send-dropdown-list/send-dropdown-list.component.js +++ b/ui/app/pages/send/send-content/send-dropdown-list/send-dropdown-list.component.js @@ -17,7 +17,7 @@ export default class SendDropdownList extends Component { getListItemIcon (accountAddress, activeAddress) { return accountAddress === activeAddress - ? + ? : null } @@ -29,24 +29,28 @@ export default class SendDropdownList extends Component { activeAddress, } = this.props - return (
    -
    closeDropdown()} - /> -
    - {accounts.map((account, index) => { - onSelect(account) - closeDropdown() - }} - icon={this.getListItemIcon(account.address, activeAddress)} - key={`send-dropdown-account-#${index}`} - />)} + return ( +
    +
    closeDropdown()} + /> +
    + {accounts.map((account, index) => ( + { + onSelect(account) + closeDropdown() + }} + icon={this.getListItemIcon(account.address, activeAddress)} + key={`send-dropdown-account-#${index}`} + /> + ))} +
    -
    ) + ) } } diff --git a/ui/app/pages/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js b/ui/app/pages/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js index bc6c9758633d..77efddfd43bf 100644 --- a/ui/app/pages/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js +++ b/ui/app/pages/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js @@ -17,16 +17,18 @@ describe('SendDropdownList Component', function () { let wrapper beforeEach(() => { - wrapper = shallow(, { context: { t: str => str + '_t' } }) + wrapper = shallow(( + + ), { context: { t: str => str + '_t' } }) }) afterEach(() => { @@ -39,7 +41,7 @@ describe('SendDropdownList Component', function () { it('should return check icon if the passed addresses are the same', () => { assert.deepEqual( wrapper.instance().getListItemIcon('mockAccount0', 'mockAccount0'), - + ) }) diff --git a/ui/app/pages/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js b/ui/app/pages/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js index 37af59e29139..473dbb0b146b 100644 --- a/ui/app/pages/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js +++ b/ui/app/pages/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js @@ -38,12 +38,16 @@ export default class GasFeeDisplay extends Component {
    ) : gasLoadingError - ?
    - {this.context.t('setGasPrice')} -
    - :
    - {this.context.t('loading')} -
    + ? ( +
    + {this.context.t('setGasPrice')} +
    + ) + : ( +
    + {this.context.t('loading')} +
    + ) } -
    + ? ( +
    + +
    + ) : null }
    diff --git a/ui/app/pages/settings/settings.component.js b/ui/app/pages/settings/settings.component.js index 975ab4e35ce5..b0ee55dc7f1c 100644 --- a/ui/app/pages/settings/settings.component.js +++ b/ui/app/pages/settings/settings.component.js @@ -135,13 +135,19 @@ class SettingsPage extends PureComponent {
    initialBreadCrumbRoute && history.push(initialBreadCrumbRoute)} - >{subheaderText}
    - {breadCrumbTextKey &&
    {' > '}{t(breadCrumbTextKey)}
    } - {isAddressEntryPage &&
    {' > '}{addressName}
    } + > + {subheaderText} +
    + {breadCrumbTextKey && ( +
    + {' > '}{t(breadCrumbTextKey)} +
    + )} + {isAddressEntryPage && ( +
    + {' > '}{addressName} +
    + )}
    ) } From 76b16996211d83aa27cc3b8b886149ce6e76864c Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Tue, 3 Dec 2019 09:35:56 -0800 Subject: [PATCH 86/88] Connect distinct accounts per site (#7004) * add PermissionsController remove provider approval controller integrate rpc-cap create PermissionsController move provider approval functionality to permissions controller add permissions approval ui, settings page add permissions activity and history move some functionality to metamask-inpage-provider rename siteMetadata -> domainMetadata add accountsChange notification to inpage provider move functionality to inpage provider update inpage provider Remove 'Connections' settings page (#7369) add hooks for exposing accounts in settings rename unused messages in non-English locales Add external extension id to metadata (#7396) update inpage provider, rpc-cap add eth_requestAccounts handling to background prevent notifying connections if extension is locked update inpage provider Fix lint errors add migration review fixes transaction controller review updates removed unused messages * Login Per Site UI (#7368) * LoginPerSite original UI changes to keep * First commit * Get necessary connected tab info for redirect and icon display for permissioned sites * Fix up designs and add missing features * Some lint fixes * More lint fixes * Ensures the tx controller + tx-state-manager orders transactions in the order they are received * Code cleanup for LoginPerSite-ui * Update e2e tests to use new connection flow * Fix display of connect screen and app header after login when connect request present * Update metamask-responsive-ui.spec for new item in accounts dropdown * Fix approve container by replacing approvedOrigins with domainMetaData * Adds test/e2e/permissions.spec.js * Correctly handle cancellation of a permissions request * Redirect to home after disconnecting all sites / cancelling all permissions * Fix display of site icons in menu * Fix height of permissions page container * Remove unused locale messages * Set default values for openExternalTabs and tabIdOrigins in account-menu.container * More code cleanup for LoginPerSite-ui * Use extensions api to close tab in permissions-connect * Remove unnecessary change in domIsReady() in contentscript * Remove unnecessary private function markers and class methods (for background tab info) in metamask-controller. * Adds getOriginOfCurrentTab selector * Adds IconWithFallback component and substitutes for appropriate cases * Add and utilize font mixins * Remove unused method in disconnect-all.container.js * Simplify buttonSizeLarge code in page-container-footer.component.js * Add and utilize getAccountsWithLabels selector * Remove console.log in ui/app/store/actions.js * Change last connected time format to yyyy-M-d * Fix css associated with IconWithFallback change * Ensure tracked openNonMetamaskTabsIDs are correctly set to inactive on tab changes * Code cleanup for LoginPerSite-ui * Use reusable function for modifying openNonMetamaskTabsIDs in background.js * Enables automatic switching to connected account when connected domain is open * Prevent exploit of tabIdOriginMap in background.js * Remove unneeded code from contentscript.js * Simplify current tab origin and window opener logic using remotePort listener tabs.queryTabs * Design and styling fixes for LoginPerSite-ui * Fix permissionHistory and permission logging for eth_requestAccounts and eth_accounts * Front end changes to support display of lastConnected time in connected and permissions screens * Fix lint errors * Refactor structure of permissionsHistory * Fix default values and object modifications for domain and permissionsHistory related data * Fix connecting to new accounts from modal * Replace retweet.svg with connect-white.svg * Fix signature-request.spec * Update metamask-inpage-provider version * Fix permissions e2e tests * Remove unneeded delay from test/e2e/signature-request.spec.js * Add delay before attempting to retrieve network id in dapp in ethereum-on=.spec * Use requestAccountTabIds strategy for determining tab id that opened a given window * Improve default values for permissions requests * Add some message descriptions to app/_locales/en/messages.json * Code clean up in permission controller * Stopped deep cloning object in mapObjectValues * Bump metamask-inpage-provider version * Add missing description in app/_locales/en/messages.json * Return promises from queryTabs and switchToTab of extension.js * Remove unused getAllPermissions function * Use default props in icon-with-fallback.component.js * Stop passing to permissions controller * Delete no longer used clear-approved-origins modal code * Remove duplicate imports in ui/app/components/app/index.scss * Use URL instead of regex in getOriginFromUrl() * Add runtime error checking to platform, promise based extension.tab methods * Support permission requests from external extensions * Improve font size and colour of the domain origin on the permission confirmation screen * Add support for toggling permissions * Ensure getRenderablePermissionsDomains only returns domains with exposedAccount caveat permissions * Remove unused code from LoginPerSite-ui branch * Ensure modal closes on Enter press for new-account-modal.component.js * Lint fix * fixup! Login Per Site UI (#7368) * Some code cleanup for LoginPerSite * Adds UX for connecting to dapps via the connected sites screen (#7593) * Adds UX for connecting to dapps via the connected sites screen * Use openMetaMaskTabIds from background.js to determine if current active tab is MetaMask * Delete unused permissions controller methods * Fixes two small bugs in the LoginPerSite ui (#7595) * Restore `providerRequest` message translations (#7600) This message was removed, but it was replaced with a very similar message called `likeToConnect`. The only difference is that the new message has "MetaMask" in it. Preserving these messages without "MetaMask" is probably better than deleting them, so these messages have all been restored and renamed to `likeToConnect`. * Login per site no sitemetadata fix (#7610) * Support connected sites for which we have no site metadata. * Change property containing subtitle info often populated by origin to a more accurate of purpose name * Lint fix * Improve disconnection modal messages (#7612) * Improve disconnectAccountModalDescription and disconnectAllModalDescription messages * Update disconnectAccountModalDescription app/_locales/en/messages.json Co-Authored-By: Mark Stacey * Improve disconnectAccount modal message clarity * Adds cancel button to the account selection screen of the permissions request flow (#7613) * Fix eth_accounts permission language & selectability (#7614) * fix eth_accounts language & selectability * fix MetaMask capitalization in all messages * Close sidebar when opening connected sites (#7611) The 'Connected Sites' button in the accounts details now closes the sidebar, if it is open. This was accomplished by pulling the click handler for that button up to the wallet view component, where another button already followed a similar pattern of closing the sidebar. It seemed confusing to me that one handler was in the `AccountsDetails` container component, and one was handed down from above, so I added PropTypes to the container component. I'm not sure that the WalletView component is the best place for this logic, but I've put it there for now to be consistent with the add token button. * Reject permissions request upon tab close (#7618) Permissions requests are now rejected when the page is closed. This only applies to the full-screen view, as that is the view permission requests should be handled in. The case where the user deals with the request through a different view is handled in #7617 * Handle tab update failure (#7619) `extension.tabs.update` can sometimes fail if the user interacts with the tabs directly around the same time. The redirect flow has been updated to ensure that the permissions tab is still closed in that case. The user is on their own to find the dapp tab again in that case. * Login per site tab popup fixes (#7617) * Handle redirect in response to state update in permissions-connect * Ensure origin is available to permissions-connect subcomponents during redirect * Hide app bar whenever on redirect route * Improvements to handling of redirects in permissions-connect * Ensure permission request id change handling only happens when page is not null * Lint fix * Decouple confirm transaction screen from the selected address (#7622) * Avoid race condtion that could prevent contextual account switching (#7623) There was a race condition in the logic responsible for switching the selected account based upon the active tab. It was asynchronously querying the active tab, then assuming it had been retrieved later. The active tab info itself was already in the redux store in another spot, one that is guaranteed to be set before the UI renders. The race condition was avoided by deleting the duplicate state, and using the other active tab state. * Only redirect back to dapp if current tab is active (#7621) The "redirect back to dapp" behaviour can be disruptive when the permissions connect tab is not active. The purpose of the redirect was to maintain context between the dapp and the permissions request, but if the user has already moved to another tab, that no longer applies. * Fix JSX style lint errors * Remove unused state --- app/_locales/am/messages.json | 20 +- app/_locales/ar/messages.json | 20 +- app/_locales/bg/messages.json | 20 +- app/_locales/bn/messages.json | 20 +- app/_locales/ca/messages.json | 22 +- app/_locales/cs/messages.json | 9 - app/_locales/da/messages.json | 20 +- app/_locales/de/messages.json | 20 +- app/_locales/el/messages.json | 20 +- app/_locales/en/messages.json | 109 +++-- app/_locales/es/messages.json | 20 +- app/_locales/es_419/messages.json | 20 +- app/_locales/et/messages.json | 24 +- app/_locales/fa/messages.json | 20 +- app/_locales/fi/messages.json | 20 +- app/_locales/fil/messages.json | 17 +- app/_locales/fr/messages.json | 20 +- app/_locales/gu/messages.json | 3 - app/_locales/he/messages.json | 20 +- app/_locales/hi/messages.json | 20 +- app/_locales/hn/messages.json | 9 - app/_locales/hr/messages.json | 20 +- app/_locales/ht/messages.json | 9 - app/_locales/hu/messages.json | 20 +- app/_locales/id/messages.json | 20 +- app/_locales/it/messages.json | 38 +- app/_locales/ja/messages.json | 16 +- app/_locales/kn/messages.json | 20 +- app/_locales/ko/messages.json | 20 +- app/_locales/lt/messages.json | 20 +- app/_locales/lv/messages.json | 20 +- app/_locales/ml/messages.json | 3 - app/_locales/mr/messages.json | 3 - app/_locales/ms/messages.json | 20 +- app/_locales/nl/messages.json | 9 - app/_locales/no/messages.json | 20 +- app/_locales/ph/messages.json | 9 - app/_locales/pl/messages.json | 20 +- app/_locales/pt/messages.json | 9 - app/_locales/pt_BR/messages.json | 20 +- app/_locales/pt_PT/messages.json | 3 - app/_locales/ro/messages.json | 20 +- app/_locales/ru/messages.json | 20 +- app/_locales/sk/messages.json | 20 +- app/_locales/sl/messages.json | 20 +- app/_locales/sr/messages.json | 20 +- app/_locales/sv/messages.json | 20 +- app/_locales/sw/messages.json | 20 +- app/_locales/ta/messages.json | 12 - app/_locales/te/messages.json | 3 - app/_locales/th/messages.json | 14 +- app/_locales/tr/messages.json | 9 - app/_locales/uk/messages.json | 20 +- app/_locales/vi/messages.json | 9 - app/_locales/zh_CN/messages.json | 22 +- app/_locales/zh_TW/messages.json | 20 +- app/images/broken-line.svg | 3 + app/images/connect-white.svg | 3 + ...proval-check.svg => permissions-check.svg} | 0 app/scripts/background.js | 25 +- app/scripts/contentscript.js | 96 +---- app/scripts/controllers/permissions/index.js | 377 ++++++++++++++++++ .../permissions/loggerMiddleware.js | 169 ++++++++ .../permissions/methodMiddleware.js | 90 +++++ .../permissions/permissions-safe-methods.json | 49 +++ .../permissions/restrictedMethods.js | 20 + app/scripts/controllers/preferences.js | 14 +- app/scripts/controllers/provider-approval.js | 177 -------- app/scripts/controllers/transactions/index.js | 83 ++-- app/scripts/createStandardProvider.js | 73 ---- app/scripts/inpage.js | 132 +----- app/scripts/lib/auto-reload.js | 5 +- app/scripts/lib/createOriginMiddleware.js | 1 + app/scripts/lib/local-store.js | 19 +- app/scripts/lib/message-manager.js | 4 +- app/scripts/lib/personal-message-manager.js | 4 +- app/scripts/lib/typed-message-manager.js | 4 +- app/scripts/lib/util.js | 29 ++ app/scripts/metamask-controller.js | 282 +++++++------ app/scripts/migrations/029.js | 1 - app/scripts/migrations/040.js | 23 ++ app/scripts/platforms/extension.js | 54 ++- docs/porting_to_new_environment.md | 13 +- package.json | 8 +- test/e2e/contract-test/contract.js | 12 + test/e2e/contract-test/index.html | 5 + test/e2e/ethereum-on.spec.js | 19 +- test/e2e/metamask-responsive-ui.spec.js | 2 +- test/e2e/metamask-ui.spec.js | 19 +- test/e2e/permissions.spec.js | 201 ++++++++++ test/e2e/run-all.sh | 8 + test/e2e/signature-request.spec.js | 24 +- .../preferences-controller-test.js | 3 +- .../app/controllers/provider-approval-test.js | 330 --------------- .../transactions/tx-controller-test.js | 5 +- .../account-details.component.js | 18 +- .../account-details.container.js | 17 +- .../components/app/account-details/index.scss | 6 + .../account-menu/account-menu.component.js | 15 + .../account-menu/account-menu.container.js | 9 +- ui/app/components/app/account-menu/index.scss | 4 + .../connected-sites-list.component.js | 157 ++++++++ .../connected-sites-list.container.js | 57 +++ .../app/connected-sites-list/index.js | 1 + .../app/connected-sites-list/index.scss | 125 ++++++ .../app/dropdowns/account-details-dropdown.js | 23 +- ui/app/components/app/index.scss | 12 +- .../components/app/modal/modal.component.js | 41 +- .../clear-approved-origins.component.js | 39 -- .../modals/clear-approved-origins/index.js | 1 - .../disconnect-account.component.js | 52 +++ .../disconnect-account.container.js | 44 ++ .../app/modals/disconnect-account/index.js | 1 + .../app/modals/disconnect-account/index.scss | 25 ++ .../disconnect-all.component.js | 54 +++ .../disconnect-all.container.js} | 12 +- .../app/modals/disconnect-all/index.js | 1 + .../app/modals/disconnect-all/index.scss | 38 ++ ui/app/components/app/modals/index.scss | 6 + ui/app/components/app/modals/modal.js | 98 ++++- .../app/modals/new-account-modal/index.js | 1 + .../app/modals/new-account-modal/index.scss | 37 ++ .../new-account-modal.component.js | 78 ++++ .../new-account-modal.container.js | 44 ++ .../app/permission-page-container/index.js | 3 + .../app/permission-page-container/index.scss | 281 +++++++++++++ .../index.js | 1 + ...ission-page-container-content.component.js | 163 ++++++++ .../permission-page-container-header/index.js | 1 + ...ission-page-container-header.component.js} | 4 +- .../permission-page-container.component.js | 151 +++++++ .../permission-page-container.container.js | 28 ++ .../app/provider-page-container/index.js | 3 - .../app/provider-page-container/index.scss | 121 ------ .../provider-page-container-content/index.js | 1 - ...ovider-page-container-content.component.js | 87 ---- ...ovider-page-container-content.container.js | 11 - .../provider-page-container-header/index.js | 1 - .../provider-page-container.component.js | 107 ----- .../app/wallet-view/wallet-view.component.js | 15 +- .../icon-with-fallback.component.js | 42 ++ .../components/ui/icon-with-fallback/index.js | 1 + .../ui/icon-with-fallback/index.scss | 30 ++ .../page-container-footer.component.js | 6 +- ui/app/css/itcss/components/pages/index.scss | 2 +- ...approval.scss => permission-approval.scss} | 4 +- ui/app/css/itcss/settings/variables.scss | 29 ++ ui/app/ducks/app/app.js | 18 + ui/app/helpers/constants/routes.js | 4 + ui/app/helpers/utils/util.js | 7 + .../confirm-approve.container.js | 4 +- .../confirm-transaction-base.container.js | 8 +- .../connected-sites.component.js | 36 ++ ui/app/pages/connected-sites/index.js | 1 + ui/app/pages/connected-sites/index.scss | 37 ++ ui/app/pages/home/home.component.js | 39 +- ui/app/pages/home/home.container.js | 12 +- ui/app/pages/index.scss | 4 + .../choose-account.component.js | 108 +++++ .../choose-account/index.js | 1 + .../choose-account/index.scss | 97 +++++ ui/app/pages/permissions-connect/index.js | 1 + ui/app/pages/permissions-connect/index.scss | 11 + .../permissions-connect-footer/index.js | 1 + .../permissions-connect-footer/index.scss | 27 ++ .../permissions-connect-footer.component.js | 27 ++ .../permissions-connect-header/index.js | 1 + .../permissions-connect-header/index.scss | 15 + .../permissions-connect-header.component.js | 25 ++ .../permissions-connect.component.js | 208 ++++++++++ .../permissions-connect.container.js | 66 +++ ui/app/pages/provider-approval/index.js | 1 - .../provider-approval.component.js | 36 -- .../provider-approval.container.js | 12 - ui/app/pages/routes/index.js | 60 ++- .../connected-site-row.component.js | 31 -- .../connected-site-row/index.js | 1 - .../connected-site-row/index.scss | 14 - .../connections-tab.component.js | 133 ------ .../connections-tab.container.js | 39 -- .../pages/settings/connections-tab/index.js | 1 - .../pages/settings/connections-tab/index.scss | 1 - ui/app/pages/settings/index.scss | 2 - ui/app/pages/settings/settings.component.js | 8 - ui/app/selectors/selectors.js | 189 +++++++++ ui/app/store/actions.js | 113 +++++- yarn.lock | 54 ++- 187 files changed, 4275 insertions(+), 2713 deletions(-) create mode 100644 app/images/broken-line.svg create mode 100644 app/images/connect-white.svg rename app/images/{provider-approval-check.svg => permissions-check.svg} (100%) create mode 100644 app/scripts/controllers/permissions/index.js create mode 100644 app/scripts/controllers/permissions/loggerMiddleware.js create mode 100644 app/scripts/controllers/permissions/methodMiddleware.js create mode 100644 app/scripts/controllers/permissions/permissions-safe-methods.json create mode 100644 app/scripts/controllers/permissions/restrictedMethods.js delete mode 100644 app/scripts/controllers/provider-approval.js delete mode 100644 app/scripts/createStandardProvider.js create mode 100644 app/scripts/migrations/040.js create mode 100644 test/e2e/permissions.spec.js delete mode 100644 test/unit/app/controllers/provider-approval-test.js create mode 100644 ui/app/components/app/connected-sites-list/connected-sites-list.component.js create mode 100644 ui/app/components/app/connected-sites-list/connected-sites-list.container.js create mode 100644 ui/app/components/app/connected-sites-list/index.js create mode 100644 ui/app/components/app/connected-sites-list/index.scss delete mode 100644 ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.component.js delete mode 100644 ui/app/components/app/modals/clear-approved-origins/index.js create mode 100644 ui/app/components/app/modals/disconnect-account/disconnect-account.component.js create mode 100644 ui/app/components/app/modals/disconnect-account/disconnect-account.container.js create mode 100644 ui/app/components/app/modals/disconnect-account/index.js create mode 100644 ui/app/components/app/modals/disconnect-account/index.scss create mode 100644 ui/app/components/app/modals/disconnect-all/disconnect-all.component.js rename ui/app/components/app/modals/{clear-approved-origins/clear-approved-origins.container.js => disconnect-all/disconnect-all.container.js} (53%) create mode 100644 ui/app/components/app/modals/disconnect-all/index.js create mode 100644 ui/app/components/app/modals/disconnect-all/index.scss create mode 100644 ui/app/components/app/modals/new-account-modal/index.js create mode 100644 ui/app/components/app/modals/new-account-modal/index.scss create mode 100644 ui/app/components/app/modals/new-account-modal/new-account-modal.component.js create mode 100644 ui/app/components/app/modals/new-account-modal/new-account-modal.container.js create mode 100644 ui/app/components/app/permission-page-container/index.js create mode 100644 ui/app/components/app/permission-page-container/index.scss create mode 100644 ui/app/components/app/permission-page-container/permission-page-container-content/index.js create mode 100644 ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js create mode 100644 ui/app/components/app/permission-page-container/permission-page-container-header/index.js rename ui/app/components/app/{provider-page-container/provider-page-container-header/provider-page-container-header.component.js => permission-page-container/permission-page-container-header/permission-page-container-header.component.js} (58%) create mode 100644 ui/app/components/app/permission-page-container/permission-page-container.component.js create mode 100644 ui/app/components/app/permission-page-container/permission-page-container.container.js delete mode 100644 ui/app/components/app/provider-page-container/index.js delete mode 100644 ui/app/components/app/provider-page-container/index.scss delete mode 100644 ui/app/components/app/provider-page-container/provider-page-container-content/index.js delete mode 100644 ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js delete mode 100644 ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.container.js delete mode 100644 ui/app/components/app/provider-page-container/provider-page-container-header/index.js delete mode 100644 ui/app/components/app/provider-page-container/provider-page-container.component.js create mode 100644 ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js create mode 100644 ui/app/components/ui/icon-with-fallback/index.js create mode 100644 ui/app/components/ui/icon-with-fallback/index.scss rename ui/app/css/itcss/components/pages/{provider-approval.scss => permission-approval.scss} (66%) create mode 100644 ui/app/pages/connected-sites/connected-sites.component.js create mode 100644 ui/app/pages/connected-sites/index.js create mode 100644 ui/app/pages/connected-sites/index.scss create mode 100644 ui/app/pages/permissions-connect/choose-account/choose-account.component.js create mode 100644 ui/app/pages/permissions-connect/choose-account/index.js create mode 100644 ui/app/pages/permissions-connect/choose-account/index.scss create mode 100644 ui/app/pages/permissions-connect/index.js create mode 100644 ui/app/pages/permissions-connect/index.scss create mode 100644 ui/app/pages/permissions-connect/permissions-connect-footer/index.js create mode 100644 ui/app/pages/permissions-connect/permissions-connect-footer/index.scss create mode 100644 ui/app/pages/permissions-connect/permissions-connect-footer/permissions-connect-footer.component.js create mode 100644 ui/app/pages/permissions-connect/permissions-connect-header/index.js create mode 100644 ui/app/pages/permissions-connect/permissions-connect-header/index.scss create mode 100644 ui/app/pages/permissions-connect/permissions-connect-header/permissions-connect-header.component.js create mode 100644 ui/app/pages/permissions-connect/permissions-connect.component.js create mode 100644 ui/app/pages/permissions-connect/permissions-connect.container.js delete mode 100644 ui/app/pages/provider-approval/index.js delete mode 100644 ui/app/pages/provider-approval/provider-approval.component.js delete mode 100644 ui/app/pages/provider-approval/provider-approval.container.js delete mode 100644 ui/app/pages/settings/connections-tab/connected-site-row/connected-site-row.component.js delete mode 100644 ui/app/pages/settings/connections-tab/connected-site-row/index.js delete mode 100644 ui/app/pages/settings/connections-tab/connected-site-row/index.scss delete mode 100644 ui/app/pages/settings/connections-tab/connections-tab.component.js delete mode 100644 ui/app/pages/settings/connections-tab/connections-tab.container.js delete mode 100644 ui/app/pages/settings/connections-tab/index.js delete mode 100644 ui/app/pages/settings/connections-tab/index.scss diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index bbb076896568..1b9026d4c858 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "የግላዊነት ኩነት አሁን በንቡር ነቅቷል" - }, "chartOnlyAvailableEth": { "message": "ቻርት የሚገኘው በ Ethereum አውታረ መረቦች ላይ ብቻ ነው።" }, - "confirmClear": { - "message": "የተፈቀዱ ድረ ገጾችን ለማጥራት እንደሚፈልጉ እርግጠኛ ነዎት?" - }, "contractInteraction": { "message": "የግንኙነት ተግባቦት" }, - "clearApprovalData": { - "message": "የግላዊነት ውሂብን አጥራ" - }, "reject": { "message": "አይቀበሉ" }, - "providerRequest": { + "likeToConnect": { "message": "$1ከመለያዎ ጋር ለመገናኘት ይፈልጋል" }, - "providerRequestInfo": { - "message": "ይህ ድረ ገጽ የእርስዎን መለያ ወቅታዊ አድራሻ ለማየት እየጠየቀ ነው። ምንጊዜም ግንኙነት የሚያደርጉባቸውን ድረ ገጾች የሚያምኗቸው መሆኑን ያረጋግጡ።" - }, "about": { "message": "ስለ" }, @@ -248,9 +236,6 @@ "connect": { "message": "ይገናኙ" }, - "connectRequest": { - "message": "የግንኙነት ጥያቄ" - }, "connectingTo": { "message": "ከ $1ጋር መገናኘት" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "ቀደም ሲል የተወሰነ Ether ካለዎት፣ በአዲሱ ቋትዎ Ether ለማግኘት ፈጣኑ መንገድ ቀጥተኛ ተቀማጭ ነው።" }, - "dismiss": { - "message": "አሰናብት" - }, "done": { "message": "ተጠናቅቋል" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index 2a9451d619e6..e686d498cf52 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "يتم تمكين وضع الخصوصية الآن بشكل افتراضي" - }, "chartOnlyAvailableEth": { "message": "الرسم البياني متاح فقط على شبكات إيثيريوم." }, - "confirmClear": { - "message": "هل أنت متأكد من أنك تريد مسح المواقع المعتمدة؟" - }, "contractInteraction": { "message": "التفاعل على العقد" }, - "clearApprovalData": { - "message": "مسح بيانات الخصوصية" - }, "reject": { "message": "رفض" }, - "providerRequest": { + "likeToConnect": { "message": "يرغب $1 في الاتصال بحسابك" }, - "providerRequestInfo": { - "message": "يطلب هذا الموقع حق الوصول لعرض عنوان حسابك الحالي. تأكد دائماً من ثقتك في المواقع التي تتفاعل معها." - }, "about": { "message": "حول" }, @@ -248,9 +236,6 @@ "connect": { "message": "اتصال" }, - "connectRequest": { - "message": "طلب اتصال" - }, "connectingTo": { "message": "جارِ الاتصال بـ $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "إذا كان لديك بالفعل بعض الأثير، فإن أسرع طريقة للحصول على الأثير في محفظتك الجديدة عن طريق الإيداع المباشر." }, - "dismiss": { - "message": "رفض" - }, "done": { "message": "تم" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index bd66c78c7112..249e1c77913a 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Режимът на поверителност вече е активиран по подразбиране" - }, "chartOnlyAvailableEth": { "message": "Диаграмата е достъпна само в мрежи на Ethereum." }, - "confirmClear": { - "message": "Сигурни ли сте, че искате да изчистите одобрените уебсайтове?" - }, "contractInteraction": { "message": "Взаимодействие с договор" }, - "clearApprovalData": { - "message": "Изчистване на данните за поверителност" - }, "reject": { "message": "Отхвърляне" }, - "providerRequest": { + "likeToConnect": { "message": "$1 би искал да се свърже с вашия акаунт" }, - "providerRequestInfo": { - "message": "Този сайт иска достъп за преглед на адреса на текущия ви акаунт. Винаги се уверявайте, че се доверявате на сайтовете, с които взаимодействате." - }, "about": { "message": "Информация" }, @@ -248,9 +236,6 @@ "connect": { "message": "Свързване" }, - "connectRequest": { - "message": "Свържете заявка" - }, "connectingTo": { "message": "Свързване с $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Ако вече имате някакъв етер, най-бързият начин да получите етер в новия си портфейл е чрез директен депозит." }, - "dismiss": { - "message": "Отхвърляне" - }, "done": { "message": "Готово" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index 7580e8e534b1..ae36440daca3 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "গোপনীয়তার মোড এখন ডিফল্ট হিসাবে সক্রিয় করা আছে" - }, "chartOnlyAvailableEth": { "message": "শুধুমাত্র Ethereum নেটওয়ার্কগুলিতে চার্ট উপলভ্য। " }, - "confirmClear": { - "message": "আপনি কি অনুমোদিত ওয়েবসাইটগুলি মুছে পরিস্কার করার বিষয়ে নিশ্চিত?" - }, "contractInteraction": { "message": "কন্ট্র্যাক্ট বাক্যালাপ" }, - "clearApprovalData": { - "message": "গোপনীয়তার ডেটা মুছে পরিস্কার করুন" - }, "reject": { "message": "প্রত্যাখ্যান" }, - "providerRequest": { + "likeToConnect": { "message": "$1 আপনার অ্যাকাউন্টের সাথে সংযোগ করতে চায়" }, - "providerRequestInfo": { - "message": "এই সাইটটি আপনার বর্তমান অ্যাকাউন্টের ঠিকানা দেখার অ্যাক্সেসের জন্য অনুরোধ জানাচ্ছে। সবসময় নিশ্চিত হয়ে নেবেন যে আপনি যে সাইটের সাথে যোগাযোগ করছেন সেটি বিশ্বাসযোগ্য কিনা।" - }, "about": { "message": "সম্পর্কে" }, @@ -248,9 +236,6 @@ "connect": { "message": "সংযুক্ত করুন" }, - "connectRequest": { - "message": "সংযোগের অনুরোধ" - }, "connectingTo": { "message": " $1 এর সাথে সংযোগ করছে" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "আপনার ইতিমধ্যে কিছু ইথার থেকে থাকলে আপনার নতুন ওয়ালেটে ইথার পাওয়ার দ্রুততম উপায় হল সরাসরি জমা করা।" }, - "dismiss": { - "message": "খারিজ" - }, "done": { "message": "সম্পন্ন " }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 07ec4c914d56..4c131ef09b67 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "El mode de privacitat ara està activat per defecte" - }, "chartOnlyAvailableEth": { "message": "Mostra només els disponibles a les xarxes Ethereum." }, - "confirmClear": { - "message": "Estàs segur que vols eliminar totes les pàgines web aprovades?" - }, "contractInteraction": { "message": "Contractar Interacció" }, - "clearApprovalData": { - "message": "Elimina les dades de privacitat" - }, "reject": { "message": "Rebutja" }, - "providerRequest": { + "likeToConnect": { "message": "a $1 li agradaria connectar-se al teu compte" }, - "providerRequestInfo": { - "message": "Aquesta pàgina està demanant accès a la teva adreça" - }, "about": { "message": "Informació" }, @@ -245,9 +233,6 @@ "connect": { "message": "Connecta" }, - "connectRequest": { - "message": "Sol·licitud de connexió" - }, "connectingTo": { "message": "Connectant a $1 " }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Si ja tens una mica d'Ether, la manera més ràpida de posar Ether al teu nou moneder és per dipòsit directe." }, - "dismiss": { - "message": "Omet" - }, "done": { "message": "Fet" }, @@ -687,7 +669,7 @@ "message": "Conectant-te a Ethereum i la web descentralitzada." }, "metamaskSeedWords": { - "message": "Frase de recuperació de Metamask" + "message": "Frase de recuperació de MetaMask" }, "metamaskVersion": { "message": "Versió MetaMask" diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index 452e5fb5e066..9d04ae048c55 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -1,16 +1,7 @@ { - "confirmClear": { - "message": "Naozaj chcete vymazať schválené webové stránky?" - }, - "clearApprovalData": { - "message": "Jasné údaje o schválení" - }, "reject": { "message": "Odmítnout" }, - "providerRequestInfo": { - "message": "Níže uvedená doména se pokouší požádat o přístup k API Ethereum, aby mohla komunikovat s blokádou Ethereum. Před schválením přístupu Ethereum vždy zkontrolujte, zda jste na správném místě." - }, "account": { "message": "Účet" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index d47cc30468ab..1c5fa4edb03c 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Privatlivstilstand er nu som udgangspunkt aktiveret" - }, "chartOnlyAvailableEth": { "message": "Skema kun tilgængeligt på Ethereum-netværk." }, - "confirmClear": { - "message": "Er du sikker på, at du vil rydde godkendte hjemmesider?" - }, "contractInteraction": { "message": "Kontraktinteraktion" }, - "clearApprovalData": { - "message": "Ryd fortrolighedsdata" - }, "reject": { "message": "Afvis" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ønsker at forbinde til din konto" }, - "providerRequestInfo": { - "message": "Denne side anmoder om at se din nuværende kontoadresse. Sørg altid for, at du stoler på de sider du interagerer med." - }, "about": { "message": "Om" }, @@ -248,9 +236,6 @@ "connect": { "message": "Få forbindelse" }, - "connectRequest": { - "message": "Tilslutningsanmodning" - }, "connectingTo": { "message": "Forbinder til $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Hvis du allerede har Ether, er den hurtigste måde at få Ether i din nye tegnebog ved direkte indbetaling." }, - "dismiss": { - "message": "Luk" - }, "done": { "message": "Færdig" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 5ea773ba375f..f964d0c2d190 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Der Datenschutzmodus ist jetzt standardmäßig aktiviert" - }, "chartOnlyAvailableEth": { "message": "Die Grafik ist nur in Ethereum-Netzwerken verfügbar." }, - "confirmClear": { - "message": "Möchten Sie die genehmigten Websites wirklich löschen?" - }, "contractInteraction": { "message": "Vertragsinteraktion" }, - "clearApprovalData": { - "message": "Genehmigungsdaten löschen" - }, "reject": { "message": "Ablehnen" }, - "providerRequest": { + "likeToConnect": { "message": "$1 möchte sich mit deinem Account verbinden" }, - "providerRequestInfo": { - "message": "Diese Website fordert Zugriff auf Ihre aktuelle Kontoadresse. Stellen Sie immer sicher, dass Sie den Websites vertrauen, mit denen Sie interagieren." - }, "about": { "message": "Über" }, @@ -236,9 +224,6 @@ "connect": { "message": "Verbinden" }, - "connectRequest": { - "message": "Verbindungsanfrage" - }, "connectingTo": { "message": "Verbindung mit $1 wird hergestellt" }, @@ -353,9 +338,6 @@ "directDepositEtherExplainer": { "message": "Wenn du bereits Ether besitzt, ist die sofortige Einzahlung die schnellste Methode Ether in deine neue Wallet zu bekommen." }, - "dismiss": { - "message": "Schließen" - }, "done": { "message": "Fertig" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 9d6725632c41..6f35b1447495 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Η Λειτουργία Απορρήτου είναι πλέον ενεργοποιημένη από προεπιλογή" - }, "chartOnlyAvailableEth": { "message": "Το διάγραμμα είναι διαθέσιμο μόνο σε δίκτυα Ethereum." }, - "confirmClear": { - "message": "Είστε βέβαιοι ότι θέλετε να διαγράψετε τους εγκεκριμένους ιστότοπους;" - }, "contractInteraction": { "message": "Αλληλεπίδραση Σύμβασης" }, - "clearApprovalData": { - "message": "Εκκαθάριση Δεδομένων Απορρήτου" - }, "reject": { "message": "Απόρριψη" }, - "providerRequest": { + "likeToConnect": { "message": "Αίτημα σύνδεσης στον λογαριασμό σας από $1" }, - "providerRequestInfo": { - "message": "Ο ιστότοπος ζητά πρόσβαση για προβολή της τρέχουσας διεύθυνσης του λογαριασμού σας. Να σιγουρεύεστε πάντα ότι εμπιστεύεστε τους ιστότοπους με τους οποίους αλληλεπιδράτε." - }, "about": { "message": "Σχετικά με" }, @@ -245,9 +233,6 @@ "connect": { "message": "Σύνδεση" }, - "connectRequest": { - "message": "Αίτημα Σύνδεσης" - }, "connectingTo": { "message": "Σύνδεση με $1" }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Αν έχετε ήδη κάποια Ether, ο πιο γρήγορος τρόπος για να πάρετε τα Ether στο νέο σας πορτοφόλι με άμεση κατάθεση." }, - "dismiss": { - "message": "Παράβλεψη" - }, "done": { "message": "Τέλος" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 2afe8e0c313d..b61349894073 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -14,47 +14,33 @@ "showIncomingTransactionsDescription": { "message": "Select this to use Etherscan to show incoming transactions in the transactions list" }, + "cancelledConnectionWithMetaMask": { + "message": "Cancelled Connection With MetaMask" + }, "chartOnlyAvailableEth": { "message": "Chart only available on Ethereum networks." }, - "confirmClear": { - "message": "Are you sure you want to clear approved websites?" - }, - "connections": { - "message": "Connections" - }, - "connectionsSettingsDescription": { - "message": "Sites allowed to read your accounts" - }, - "addSite": { - "message": "Add Site" + "connectedSites": { + "message": "Connected Sites" }, - "addSiteDescription": { - "message": "Manually add a site to allow it access to your accounts, useful for older dapps" + "connectingWithMetaMask": { + "message": "Connecting With MetaMask..." }, - "connected": { - "message": "Connected" + "connectTo": { + "message": "Connect to $1", + "description": "$1 is the name/origin of a site/dapp that the user can connect to metamask" }, - "connectedDescription": { - "message": "The list of sites allowed access to your addresses" - }, - "privacyModeDefault": { - "message": "Privacy Mode is now enabled by default" + "chooseAnAcount": { + "message": "Choose an account" }, "contractInteraction": { "message": "Contract Interaction" }, - "clearApprovalData": { - "message": "Remove all sites" - }, "reject": { "message": "Reject" }, - "providerRequest": { - "message": "$1 would like to connect to your account" - }, - "providerRequestInfo": { - "message": "This site is requesting access to view your current account address. Always make sure you trust the sites you interact with." + "redirectingBackToDapp": { + "message": "Redirecting back to dapp..." }, "about": { "message": "About" @@ -305,9 +291,6 @@ "connect": { "message": "Connect" }, - "connectRequest": { - "message": "Connect Request" - }, "connectingTo": { "message": "Connecting to $1" }, @@ -431,14 +414,36 @@ "details": { "message": "Details" }, + "disconnectAccount": { + "message": "Disconnect account" + }, + "disconnectAll": { + "message": "Disconnect All" + }, + "disconnectAllModalDescription": { + "message": "Are you sure? You will be disconnected from all sites on all accounts." + }, + "disconnectAccountModalDescription": { + "message": "Are you sure? Your account (\"$1\") will be disconnected from this site." + }, + "disconnectAccountQuestion": { + "message": "Disconnect account?" + }, + "disconnectFromThisAccount": { + "message": "Disconnect from this account?" + }, + "disconnectAllAccountsQuestion": { + "message": "Disconnect all accounts?" + }, "directDepositEther": { "message": "Directly Deposit Ether" }, "directDepositEtherExplainer": { "message": "If you already have some Ether, the quickest way to get Ether in your new wallet by direct deposit." }, - "dismiss": { - "message": "Dismiss" + "domainLastConnect": { + "message": "Last Connected: $1", + "description": "$1 is the date at which the user was last connected to a given domain" }, "done": { "message": "Done" @@ -500,6 +505,13 @@ "endOfFlowMessage10": { "message": "All Done" }, + "extensionId": { + "message": "Extension ID: $1", + "description": "$1 is a string of random letters that are the id of another extension connecting to MetaMask" + }, + "externalExtension": { + "message": "External Extension" + }, "onboardingReturnNotice": { "message": "\"$1\" will close this tab and direct back to $2", "description": "Return the user to the site that initiated onboarding" @@ -733,9 +745,15 @@ "max": { "message": "Max" }, + "lastConnected": { + "message": "Last Connected" + }, "learnMore": { "message": "Learn more" }, + "learnAboutRisks": { + "message": "Learn about the risks here." + }, "ledgerAccountRestriction": { "message": "You need to make use your last account before you can add a new one." }, @@ -745,6 +763,10 @@ "likeToAddTokens": { "message": "Would you like to add these tokens?" }, + "likeToConnect": { + "message": "$1 would like to connect to your MetaMask account", + "description": "$1 is the name/url of a site/dapp asking to connect to MetaMask" + }, "links": { "message": "Links" }, @@ -876,6 +898,9 @@ "rpcUrl": { "message": "New RPC URL" }, + "onlyConnectTrust": { + "message": "Only connect with sites you trust." + }, "optionalChainId": { "message": "ChainID (optional)" }, @@ -1078,6 +1103,9 @@ "readyToConnect": { "message": "Ready to Connect?" }, + "revokeInPermissions": { + "message": "* You can view and revoke permissions in MetaMask settings." + }, "rinkeby": { "message": "Rinkeby Test Network" }, @@ -1283,6 +1311,9 @@ "storePhrase": { "message": "Store this phrase in a password manager like 1Password." }, + "submit": { + "message": "Submit" + }, "submitted": { "message": "Submitted" }, @@ -1331,6 +1362,14 @@ "testFaucet": { "message": "Test Faucet" }, + "thisWillAllow": { + "message": "This will allow $1 to:", + "description": "$1 is the name or domain of a site/dapp that is requesting permissions" + }, + "thisWillAllowExternalExtension": { + "message": "This will allow an external extension with id $1 to:", + "description": "$1 is a string of random letters that are the id of another extension connecting to MetaMask" + }, "thisWillCreate": { "message": "This will create a new wallet and seed phrase" }, @@ -1343,6 +1382,10 @@ "toWithColon": { "message": "To:" }, + "toConnectWith": { + "message": "To connect with $1", + "description": "$1 is the name or domain of a site/dapp that asking to connect with MetaMask" + }, "toETHviaShapeShift": { "message": "$1 to ETH via ShapeShift", "description": "system will fill in deposit type in start of message" diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 5aeb4ebe028a..f64105f26361 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Modo Privado está activado ahora por defecto" - }, "chartOnlyAvailableEth": { "message": "Tabla solo disponible en redes Ethereum." }, - "confirmClear": { - "message": "¿Seguro que quieres borrar los sitios web aprobados?" - }, "contractInteraction": { "message": "Interacción con contrato" }, - "clearApprovalData": { - "message": "Borrar datos de aprobación" - }, "reject": { "message": "Rechazar" }, - "providerRequest": { + "likeToConnect": { "message": "$1 quisiera conectar con tu cuenta" }, - "providerRequestInfo": { - "message": "El dominio que se muestra a continuación intenta solicitar acceso a la API Ethereum para que pueda interactuar con la blockchain de Ethereum. Siempre verifique que esté en el sitio correcto antes de aprobar el acceso Ethereum." - }, "about": { "message": "Acerca" }, @@ -205,9 +193,6 @@ "connect": { "message": "Conectar" }, - "connectRequest": { - "message": "Petición para conectar" - }, "connectingTo": { "message": "Conectánodse a $1" }, @@ -325,9 +310,6 @@ "directDepositEtherExplainer": { "message": "Si posees Ether, la forma más rápida de transferirlo a tu nueva billetera es depositándolo directamente" }, - "dismiss": { - "message": "Descartar" - }, "done": { "message": "Completo" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index e75b4c27bf01..0645b0eafb6c 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "El modo de privacidad está habilitado de manera predeterminada" - }, "chartOnlyAvailableEth": { "message": "Chart está disponible únicamente en las redes de Ethereum." }, - "confirmClear": { - "message": "¿Estás seguro de que deseas borrar los sitios web aprobados?" - }, "contractInteraction": { "message": "Interacción contractual" }, - "clearApprovalData": { - "message": "Borrar datos de privacidad" - }, "reject": { "message": "Rechazar" }, - "providerRequest": { + "likeToConnect": { "message": "$1 desea conectarse a tu cuenta" }, - "providerRequestInfo": { - "message": "Este sitio está solicitando acceso para ver la dirección de tu cuenta corriente. Asegúrate siempre de que confías en los sitios con los que interactúas." - }, "about": { "message": "Acerca de" }, @@ -245,9 +233,6 @@ "connect": { "message": "Conectar" }, - "connectRequest": { - "message": "Solicitud de conexión" - }, "connectingTo": { "message": "Conexión con $1" }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Si ya tienes algunos Ethers, la forma más rápida de ingresarlos en tu nueva billetera es a través de un depósito directo." }, - "dismiss": { - "message": "Rechazar" - }, "done": { "message": "Listo" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 3b5f4ced8ffb..ad64a32cb6f4 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Privaatsusrežiim on nüüd vaikimisi lubatud" - }, "chartOnlyAvailableEth": { "message": "Tabel on saadaval vaid Ethereumi võrkudes." }, - "confirmClear": { - "message": "Kas soovite kindlasti kinnitatud veebisaidid kustutada?" - }, "contractInteraction": { "message": "Lepingu suhtlus" }, - "clearApprovalData": { - "message": "Tühjenda privaatsusandmed" - }, "reject": { "message": "Lükka tagasi" }, - "providerRequest": { + "likeToConnect": { "message": "$1 soovib teie kontoga ühenduse luua" }, - "providerRequestInfo": { - "message": "See sait taotleb juurdepääsu teie praeguse konto aadressi vaatamiseks. Veenduge alati, et usaldate saite, millega suhtlete." - }, "about": { "message": "Teave" }, @@ -248,9 +236,6 @@ "connect": { "message": "Ühendamine" }, - "connectRequest": { - "message": "Ühenduse taotlus" - }, "connectingTo": { "message": "Ühenduse loomine $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Kui teil on juba veidi eetrit, on kiirem viis eetri rahakotti saamiseks otsene sissemakse." }, - "dismiss": { - "message": "Loobu" - }, "done": { "message": "Valmis" }, @@ -420,7 +402,7 @@ "message": "Kui teil on küsimusi või näete midagi kahtlast, kirjutage meile support@metamask.io." }, "endOfFlowMessage8": { - "message": "Metamask ei saa teie seemnefraasi taastada. Lisateave." + "message": "MetaMask ei saa teie seemnefraasi taastada. Lisateave." }, "endOfFlowMessage9": { "message": "Lisateave." @@ -1180,7 +1162,7 @@ "message": "Saate sünkroonida oma kontod ja teabe oma mobiiliseadmega. Avage MetaMaski mobiilirakendus, avage \"Settings\" (Seaded) ja puudutage valikut \"Sync from Browser Extension\" (Sünkroonimine lehitseja laiendusest)" }, "syncWithMobileDescNewUsers": { - "message": "Järgige Metamaski mobiilirakenduse esmakordsel avamisel telefonis esitatud samme." + "message": "Järgige MetaMaski mobiilirakenduse esmakordsel avamisel telefonis esitatud samme." }, "syncWithMobileScanThisCode": { "message": "Skanneerige see kood MetaMaski mobiilirakendusega" diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 6d9741344078..5be054e7cace 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "وضعیت محرمیت حالا بصورت خودکار فعال است" - }, "chartOnlyAvailableEth": { "message": "تنها قابل دسترس را در شبکه های ایتریوم جدول بندی نمایید" }, - "confirmClear": { - "message": "آیا مطمئن هستید تا وب سایت های تصدیق شده را حذف کنید؟" - }, "contractInteraction": { "message": "تعامل قرارداد" }, - "clearApprovalData": { - "message": "حذف اطلاعات حریم خصوصی" - }, "reject": { "message": "عدم پذیرش" }, - "providerRequest": { + "likeToConnect": { "message": "1$1 میخواهید تا با حساب تان وصل شوید" }, - "providerRequestInfo": { - "message": "این سایت در حال درخواست دسترسی است تا آدرس فعلی حساب تان را مشاهده نماید. همیشه متوجه باشید که بالای سایتی که با آن معامله میکنید، اعتماد دارید یا خیر." - }, "about": { "message": "درباره" }, @@ -248,9 +236,6 @@ "connect": { "message": "اتصال" }, - "connectRequest": { - "message": "درخواست اتصال" - }, "connectingTo": { "message": "در حال اتصال به 1$1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "در صورتیکه شما کدام ایتر داشته باشید، سریعترین روش برای گرفتن ایتر در کیف جدید تان توسط پرداخت مستقیم." }, - "dismiss": { - "message": "لغو کردن" - }, "done": { "message": "تمام" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 352600b26228..56f48a6fda8a 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Yksityisyystila on nyt oletusarvoisesti käytössä" - }, "chartOnlyAvailableEth": { "message": "Kaavio saatavilla vain Ethereum-verkoissa." }, - "confirmClear": { - "message": "Haluatko varmasti tyhjentää hyväksytyt verkkosivustot?" - }, "contractInteraction": { "message": "Sopimustoiminta" }, - "clearApprovalData": { - "message": "Tyhjennä yksityisyystiedot" - }, "reject": { "message": "Hylkää" }, - "providerRequest": { + "likeToConnect": { "message": "$1 haluaisi yhdistää tiliisi" }, - "providerRequestInfo": { - "message": "Tämä sivusto pyytää oikeuksia nähdä nykyisen tiliosoitteesi. Varmista aina, että luotat sivustoihin, joiden kanssa toimit." - }, "about": { "message": "Tietoja asetuksista" }, @@ -245,9 +233,6 @@ "connect": { "message": "Muodosta yhteys" }, - "connectRequest": { - "message": "Yhdistämispyyntö" - }, "connectingTo": { "message": "Yhdistetään summaan $1 " }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Jos sinulla on jo etheriä, nopein tapa hankkia etheriä uuteen lompakkoosi on suoratalletus." }, - "dismiss": { - "message": "Piilota" - }, "done": { "message": "Valmis" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 8c453bca5b0d..cd9b31234354 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Naka-enable ang Privacy Mode bilang default" - }, "chartOnlyAvailableEth": { "message": "Available lang ang chart sa mga Ethereum network." }, - "confirmClear": { - "message": "Sigurado ka bang gusto mong i-clear ang mga inaprubahang website?" - }, "contractInteraction": { "message": "Paggamit sa Contract" }, - "clearApprovalData": { - "message": "I-clear ang Privacy Data" - }, "reject": { "message": "Tanggihan" }, - "providerRequest": { + "likeToConnect": { "message": "Gusto ng $1 na kumonekta sa iyong account" }, - "providerRequestInfo": { - "message": "Humihiling ng access ang site na ito na tingnan ang kasalukuyan mong account address. Palaging tiyaking pinagkakatiwalaan mo ang mga site na pinupuntahan mo." - }, "about": { "message": "Tungkol sa" }, @@ -338,9 +326,6 @@ "directDepositEtherExplainer": { "message": "Kung mayroon ka nang Ether, ang pinakamabilis na paraan para magkaroon ng Ether sa iyong bagong wallet ay sa pamamagitan ng direkang deposito." }, - "dismiss": { - "message": "Balewalain" - }, "done": { "message": "Tapos na" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index ddcddb6be321..1fc2a600d984 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Le mode conversation privée est maintenant activé par défaut" - }, "chartOnlyAvailableEth": { "message": "Tableau disponible uniquement sur les réseaux Ethereum." }, - "confirmClear": { - "message": "Êtes-vous sûr de vouloir supprimer les sites Web approuvés?" - }, "contractInteraction": { "message": "Interaction avec un contrat" }, - "clearApprovalData": { - "message": "Effacer les données d'approbation" - }, "reject": { "message": "Rejeter" }, - "providerRequest": { + "likeToConnect": { "message": "$1 voudrait se connecter à votre compte" }, - "providerRequestInfo": { - "message": "Le domaine répertorié ci-dessous tente de demander l'accès à l'API Ethereum pour pouvoir interagir avec la chaîne de blocs Ethereum. Vérifiez toujours que vous êtes sur le bon site avant d'autoriser l'accès à Ethereum." - }, "about": { "message": "À propos" }, @@ -236,9 +224,6 @@ "connect": { "message": "Connecter" }, - "connectRequest": { - "message": "Demande de connexion" - }, "connectingTo": { "message": "Connexion à $1" }, @@ -356,9 +341,6 @@ "directDepositEtherExplainer": { "message": "Si vous avez déjà de l'Ether, le moyen le plus rapide d'obtenir des Ether dans votre nouveau portefeuille est par dépôt direct." }, - "dismiss": { - "message": "Ignorer" - }, "done": { "message": "Terminé" }, diff --git a/app/_locales/gu/messages.json b/app/_locales/gu/messages.json index 39f5ab26c809..d04514fd90c9 100644 --- a/app/_locales/gu/messages.json +++ b/app/_locales/gu/messages.json @@ -54,9 +54,6 @@ "details": { "message": "વિગતો" }, - "dismiss": { - "message": "કાઢી નાખો" - }, "done": { "message": "થઈ ગયું" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 62e69e1d5077..d0f92848c93f 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "מצב פרטיות זמין עכשיו כברירת מחדל" - }, "chartOnlyAvailableEth": { "message": "טבלה זמינה רק ברשתות אתריום." }, - "confirmClear": { - "message": "הנך בטוח/ה כי ברצונך למחוק אתרים שאושרו?" - }, "contractInteraction": { "message": "אינטראקציית חוזה" }, - "clearApprovalData": { - "message": "נקה נתוני פרטיות" - }, "reject": { "message": "דחה" }, - "providerRequest": { + "likeToConnect": { "message": "$1 מבקש להתחבר לחשבון שלך" }, - "providerRequestInfo": { - "message": "אתר זה מבקש גישה לצפייה בכתובת החשבון הנוכחית שלך. יש לוודא תמיד כי הנך בוטח/ת באתרים עמם הנך מתקשר/ת." - }, "about": { "message": "מידע כללי" }, @@ -248,9 +236,6 @@ "connect": { "message": "התחברות" }, - "connectRequest": { - "message": "חבר/י בקשה" - }, "connectingTo": { "message": "מתחבר ל- $1 " }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "אם כבר יש ברשותך את'ר (Ether) , הדרך המהירה ביותר להכניס את'ר לארנק החדש שלך היא באמצעות הפקדה ישירה." }, - "dismiss": { - "message": "סגור" - }, "done": { "message": "סיום" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 92fa40af68a4..51aa21b84003 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "गोपनीय मोड अब डिफ़ॉल्ट रूप से सक्षम है" - }, "chartOnlyAvailableEth": { "message": "केवल ईथरअम नेटवर्क पर उपलब्ध चार्ट।" }, - "confirmClear": { - "message": "क्या आप वाकई स्वीकृत वेबसाइटों को क्लियर करना चाहते हैं?" - }, "contractInteraction": { "message": "कॉन्ट्रैक्ट की बातचीत" }, - "clearApprovalData": { - "message": "गोपनीयता डेटा रिक्त करें" - }, "reject": { "message": "अस्‍वीकार करें" }, - "providerRequest": { + "likeToConnect": { "message": "$1 आपके खाते से कनेक्ट होता चाहता हैं" }, - "providerRequestInfo": { - "message": "यह साइट आपके वर्तमान खाते का पता देखने के लिए एक्सेस का अनुरोध कर रही है। हमेशा सुनिश्चित करें कि आप जिन साइटों पर जाते हैं वे विश्वसनीय हैं।" - }, "about": { "message": "इसके बारे में" }, @@ -248,9 +236,6 @@ "connect": { "message": "कनेक्ट करें" }, - "connectRequest": { - "message": "संपर्क अनुरोध" - }, "connectingTo": { "message": "$1 से कनेक्ट हो रहा है" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "यदि आपके पास पहले से ही कुछ Ether हैं, तो अपने नए वॉलेट में Ether पाने का सबसे तेज़ तरीका सीधे जमा करना है।" }, - "dismiss": { - "message": "खारिज करें" - }, "done": { "message": "पूर्ण" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index 1dd4fd117578..8009077982b8 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -1,19 +1,10 @@ { - "confirmClear": { - "message": "क्या आप वाकई अनुमोदित वेबसाइटों को साफ़ करना चाहते हैं?" - }, - "clearApprovalData": { - "message": "अनुमोदन डेटा साफ़ करें" - }, "approve": { "message": "मंजूर" }, "reject": { "message": "अस्वीकार" }, - "providerRequestInfo": { - "message": "नीचे सूचीबद्ध डोमेन वेब 3 एपीआई तक पहुंच का अनुरोध करने का प्रयास कर रहा है ताकि यह एथेरियम ब्लॉकचेन से बातचीत कर सके। वेब 3 एक्सेस को मंजूरी देने से पहले हमेशा सही जांच करें कि आप सही साइट पर हैं।" - }, "account": { "message": "खाता" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 2e224f36f01f..57b4b0d4c2e4 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "Način se Privatnost sada zadano omogućava" - }, "chartOnlyAvailableEth": { "message": "Grafikon je dostupan samo na mrežama Ethereum." }, - "confirmClear": { - "message": "Sigurno želite očistiti odobrena mrežna mjesta?" - }, "contractInteraction": { "message": "Ugovorna interakcija" }, - "clearApprovalData": { - "message": "Očisti podatke o privatnosti" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Odbaci" }, - "providerRequest": { + "likeToConnect": { "message": "Korisnik $1 želi se povezati na vaš račun" }, - "providerRequestInfo": { - "message": "Na ovom se mjestu zahtijeva pristup za pregledavanje vaše trenutačne adrese računa. Uvijek pazite da vjerujete mrežnim mjestima s kojima rukujete." - }, "about": { "message": "O opcijama" }, @@ -248,9 +236,6 @@ "connect": { "message": "Povežite se" }, - "connectRequest": { - "message": "Zahtjev za povezivanjem" - }, "connectingTo": { "message": "Povezivanje na $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Ako imate nešto Ethera, najbrži je način prebacivanja Ethera u vaš novi novčanik izravan polog." }, - "dismiss": { - "message": "Odbaci" - }, "done": { "message": "Gotovo" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 4724090171af..dd63dce0c155 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -1,13 +1,4 @@ { - "confirmClear": { - "message": "Èske ou sèten ou vle klè sitwèb apwouve?" - }, - "clearApprovalData": { - "message": "Klè Done sou vi prive" - }, - "providerRequestInfo": { - "message": "Domèn ki nan lis anba a ap mande pou jwenn aksè a blòkchou Ethereum ak pou wè kont ou ye kounye a. Toujou double tcheke ke ou sou sit ki kòrèk la anvan apwouve aksè." - }, "accessingYourCamera": { "message": "Aksè a Kamera" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index f1554299ba60..33b8dac325fd 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "Az adatvédelmi mód mostantól alapbeállításként engedélyezve van" - }, "chartOnlyAvailableEth": { "message": "A diagram csak Ethereum hálózatokon érhető el" }, - "confirmClear": { - "message": "Biztosan törölni szeretnéd a jóváhagyott weboldalakat?" - }, "contractInteraction": { "message": "Szerződéses interakció" }, - "clearApprovalData": { - "message": "Adatvédelmi adatok törlése" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Elutasítás" }, - "providerRequest": { + "likeToConnect": { "message": "$1 szeretne kapcsolódni az ön fiókjához" }, - "providerRequestInfo": { - "message": "A webhely hozzáférést kér az ön jelenlegi fiókcímének megtekintéséhez. Mindig győződjön meg arról, hogy megbízható webhellyel létesít kapcsolatot." - }, "about": { "message": "Névjegy" }, @@ -248,9 +236,6 @@ "connect": { "message": "Csatlakozás" }, - "connectRequest": { - "message": "Csatlakozási kérelem" - }, "connectingTo": { "message": "Kapcsolódás: $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Amennyiben már rendelkezik némi Ether-rel, a közvetlen letéttel gyorsan elhelyezheti azt új pénztárcájában." }, - "dismiss": { - "message": "Elvetés" - }, "done": { "message": "Kész" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index eaddf42ebb47..874ca45761e0 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "Modus Privasi kini aktif secara default" - }, "chartOnlyAvailableEth": { "message": "Grafik hanya tersedia pada jaringan Ethereum." }, - "confirmClear": { - "message": "Yakin ingin mengosongkan website yang disetujui?" - }, "contractInteraction": { "message": "Interaksi Kontrak" }, - "clearApprovalData": { - "message": "Bersihkan Data Privasi" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Tolak" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ingin menghubungkan ke akun Anda" }, - "providerRequestInfo": { - "message": "Situs ini meminta akses untuk melihat alamat akun Anda saat ini. Selalu pastikan bahwa Anda bisa mempercayai situs yang berinteraksi dengan Anda." - }, "about": { "message": "Tentang" }, @@ -248,9 +236,6 @@ "connect": { "message": "Sambungkan" }, - "connectRequest": { - "message": "Permintaan Sambungan" - }, "connectingTo": { "message": "Menghubungkan ke $1" }, @@ -362,9 +347,6 @@ "directDepositEtherExplainer": { "message": "Jika Anda sudah memiliki Ether, cara tercepat mendapatkan Ether di dompet baru lewat deposit langsung." }, - "dismiss": { - "message": "Tutup" - }, "done": { "message": "Selesai" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index e51b5a477e1c..213407a3bd9f 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "La modalità privacy è ora abilitata per impostazione predefinita" - }, "chartOnlyAvailableEth": { "message": "Grafico disponibile solo per le reti Ethereum." }, - "confirmClear": { - "message": "Sei sicuro di voler cancellare i siti Web approvati?" - }, "contractInteraction": { "message": "Interazione Contratto" }, - "clearApprovalData": { - "message": "Cancella i dati di approvazione" - }, "reject": { "message": "Annulla" }, - "providerRequest": { + "likeToConnect": { "message": "$1 vorrebbe connettersi al tuo account" }, - "providerRequestInfo": { - "message": "Il dominio elencato di seguito sta tentando di richiedere l'accesso all'API Ethereum in modo che possa interagire con la blockchain di Ethereum. Controlla sempre di essere sul sito corretto prima di approvare l'accesso a Ethereum." - }, "about": { "message": "Informazioni" }, @@ -227,9 +215,6 @@ "connect": { "message": "Connetti" }, - "connectRequest": { - "message": "Richiesta Connessione" - }, "connectingTo": { "message": "Connessione in corso a $1" }, @@ -347,9 +332,6 @@ "directDepositEtherExplainer": { "message": "Se possiedi già degli Ether, questa è la via più veloce per aggiungere Ether al tuo portafoglio con un deposito diretto." }, - "dismiss": { - "message": "Ignora" - }, "done": { "message": "Finito" }, @@ -1343,24 +1325,6 @@ "zeroGasPriceOnSpeedUpError": { "message": "Prezzo del gas maggiore di zero" }, - "connections": { - "message": "Connessioni" - }, - "connectionsSettingsDescription": { - "message": "Siti autorizzati ad accedere ai tuoi accounts" - }, - "addSite": { - "message": "Aggiungi Sito" - }, - "addSiteDescription": { - "message": "Aggiungi un sito autorizzato ad accedere ai tuoi accounts, utile per dapps obsolete" - }, - "connected": { - "message": "Connesso" - }, - "connectedDescription": { - "message": "La lista di siti web autorizzati ad accedere ai tuoi indirizzi" - }, "contacts": { "message": "Contatti" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 4967db8a6604..18dfb068eea3 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "プライバシーモードがデフォルトで有効になりました" - }, "chartOnlyAvailableEth": { "message": "チャートはEthereumネットワークでのみ利用可能です。" }, - "confirmClear": { - "message": "承認されたウェブサイトをクリアしてもよろしいですか?" - }, "contractInteraction": { "message": "コントラクトへのアクセス" }, - "clearApprovalData": { - "message": "承認データのクリア" - }, "reject": { "message": "拒否" }, - "providerRequest": { + "likeToConnect": { "message": "$1 はあなたのアカウントにアクセスしようとしています。" }, - "providerRequestInfo": { - "message": "下記のドメインは、Ethereumブロックチェーンとやり取りできるようにEthereum APIへのアクセスをリクエストしようとしています。 Web3アクセスを承認する前に、正しいサイトにいることを常に確認してください。" - }, "aboutSettingsDescription": { "message": "バージョンやサポート、問合せ先など" }, @@ -84,7 +72,7 @@ "message": "推奨トークンを追加" }, "addAcquiredTokens": { - "message": "Metamaskで獲得したトークンを追加する" + "message": "MetaMaskで獲得したトークンを追加する" }, "amount": { "message": "金額" diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index e4c8b38fe673..7f3dd0f17359 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "ಗೌಪ್ಯತೆ ಮೋಡ್ ಅನ್ನು ಡೀಫಾಲ್ಟ್‌ ಆಗಿ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - }, "chartOnlyAvailableEth": { "message": "ಎಥೆರಿಯಮ್ ನೆಟ್‌ವರ್ಕ್‌ಗಳಲ್ಲಿ ಮಾತ್ರವೇ ಚಾರ್ಟ್‌ಗಳು ಲಭ್ಯವಿರುತ್ತವೆ." }, - "confirmClear": { - "message": "ನೀವು ಅನುಮೋದಿಸಿದ ವೆಬ್‌‌ಸೈಟ್‌ಗಳನ್ನು ತೆರವುಗೊಳಿಸಲು ಬಯಸುವಿರಾ?" - }, "contractInteraction": { "message": "ಒಪ್ಪಂದದ ಸಂವಹನ" }, - "clearApprovalData": { - "message": "ಗೌಪ್ಯತೆ ಡೇಟಾವನ್ನು ತೆರವುಗೊಳಿಸಿ" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "ತಿರಸ್ಕರಿಸಿ" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ನಿಮ್ಮ ಖಾತೆಗೆ ಸಂಪರ್ಕಿಸಲು ಬಯಸುತ್ತಿದೆ" }, - "providerRequestInfo": { - "message": "ಈ ಸೈಟ್ ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಖಾತೆ ವಿಳಾಸವನ್ನು ವೀಕ್ಷಿಸಲು ಪ್ರವೇಶವನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ. ನೀವು ಸಂವಹನ ನಡೆಸುವ ಸೈಟ್‌ಗಳನ್ನು ನೀವು ನಂಬಿರುವಿರಿ ಎಂಬುದನ್ನು ಯಾವಾಗಲೂ ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ." - }, "about": { "message": "ಕುರಿತು" }, @@ -248,9 +236,6 @@ "connect": { "message": "ಸಂಪರ್ಕಿಸು" }, - "connectRequest": { - "message": "ವಿನಂತಿಯನ್ನು ಸಂಪರ್ಕಪಡಿಸಿ" - }, "connectingTo": { "message": "$1 ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗುತ್ತಿದೆ" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "ನೀವು ಈಗಾಗಲೇ ಕೆಲವು ಎಥರ್ ಹೊಂದಿದ್ದರೆ, ನೇರ ಠೇವಣಿ ಮೂಲಕ ನಿಮ್ಮ ಹೊಸ ವ್ಯಾಲೆಟ್‌ನಲ್ಲಿ ಎಥರ್ ಅನ್ನು ಪಡೆಯುವ ತ್ವರಿತ ಮಾರ್ಗ." }, - "dismiss": { - "message": "ವಜಾಗೊಳಿಸಿ" - }, "done": { "message": "ಮುಗಿದಿದೆ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 39c68a85e612..bd412c75c023 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "이제 프라이버시 모드가 기본 설정으로 활성화됐습니다" - }, "chartOnlyAvailableEth": { "message": "이더리움 네트워크에서만 사용 가능한 차트." }, - "confirmClear": { - "message": "승인 된 웹 사이트를 삭제 하시겠습니까?" - }, "contractInteraction": { "message": "계약 상호 작용" }, - "clearApprovalData": { - "message": "승인 데이터 삭제" - }, "reject": { "message": "거부" }, - "providerRequest": { + "likeToConnect": { "message": "$1이 당신의 계정에 연결하길 원합니다." }, - "providerRequestInfo": { - "message": "아래 나열된 도메인은 Web3 API에 대한 액세스를 요청하여 Ethereum 블록 체인과 상호 작용할 수 있습니다. Ethereum 액세스를 승인하기 전에 항상 올바른 사이트에 있는지 다시 확인하십시오." - }, "about": { "message": "정보" }, @@ -245,9 +233,6 @@ "connect": { "message": "연결" }, - "connectRequest": { - "message": "연결 요청" - }, "connectingTo": { "message": "$1에 연결" }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "약간의 이더를 이미 보유하고 있다면, 새로 만든 지갑에 직접 입금하여 이더를 보유할 수 있습니다." }, - "dismiss": { - "message": "숨기기" - }, "done": { "message": "완료" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 961eedc9137c..c2a56ec54046 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Dabar privatumo režimas suaktyvintas pagal numatytąją nuostatą" - }, "chartOnlyAvailableEth": { "message": "Diagramos yra tik „Ethereum“ tinkluose." }, - "confirmClear": { - "message": "Ar tikrai norite panaikinti patvirtintas svetaines?" - }, "contractInteraction": { "message": "Sutartinė sąveika" }, - "clearApprovalData": { - "message": "Išvalyti asmeninius duomenis" - }, "reject": { "message": "Atmesti" }, - "providerRequest": { + "likeToConnect": { "message": "$1 norėtų prisijungti prie jūsų paskyros" }, - "providerRequestInfo": { - "message": "Ši svetainė prašo prieigos peržiūrėti jūsų dabartinės paskyros adresą. Visada patikrinkite, ar pasitikite svetainėmis, su kuriomis sąveikaujate." - }, "about": { "message": "Apie" }, @@ -248,9 +236,6 @@ "connect": { "message": "Prisijungti" }, - "connectRequest": { - "message": "Prijungimo užklausa" - }, "connectingTo": { "message": "Jungiamasi prie $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Jeigu jau turite šiek tiek eterių, sparčiausias būdas gauti eterių į naują piniginę yra tiesioginis įnašas." }, - "dismiss": { - "message": "Atsisakyti" - }, "done": { "message": "Atlikta" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 18d80c900f4b..0b5af9c4e373 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "Privātais režīms tagad ieslēgts pēc noklusējuma" - }, "chartOnlyAvailableEth": { "message": "Grafiks pieejams vienīgi Ethereum tīklos." }, - "confirmClear": { - "message": "Vai tiešām vēlaties dzēst apstiprinātās vietnes?" - }, "contractInteraction": { "message": "Līguma mijiedarbības" }, - "clearApprovalData": { - "message": "Notīrīt konfidencialitātes datus" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Noraidīt" }, - "providerRequest": { + "likeToConnect": { "message": "$1 vēlas izveidot savienojumu ar jūsu kontu" }, - "providerRequestInfo": { - "message": "Šī lapa pieprasa piekļuvi jūsu pašreizēja konta adreses informācijai. Vienmēr pārliecinieties, ka uzticaties lapām, kuras apmeklējat." - }, "about": { "message": "Par" }, @@ -248,9 +236,6 @@ "connect": { "message": "Pievienošana" }, - "connectRequest": { - "message": "Savienojuma pieprasījums" - }, "connectingTo": { "message": "Pieslēdzas $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Ja jums jau ir Ether, tad visātrāk Ether savā makā varat saņemt ar tiešo iemaksu." }, - "dismiss": { - "message": "Noraidīt" - }, "done": { "message": "Pabeigts" }, diff --git a/app/_locales/ml/messages.json b/app/_locales/ml/messages.json index cd9736e8c5f6..c898d1dc2c49 100644 --- a/app/_locales/ml/messages.json +++ b/app/_locales/ml/messages.json @@ -54,9 +54,6 @@ "details": { "message": "വിശദാംശങ്ങൾ‌" }, - "dismiss": { - "message": "ബഹിഷ്‌ക്കരിക്കുക" - }, "done": { "message": "പൂർത്തിയാക്കി" }, diff --git a/app/_locales/mr/messages.json b/app/_locales/mr/messages.json index fa8635a39832..ef341f40cea4 100644 --- a/app/_locales/mr/messages.json +++ b/app/_locales/mr/messages.json @@ -54,9 +54,6 @@ "details": { "message": "तपशील" }, - "dismiss": { - "message": "डिसमिस करा" - }, "done": { "message": "पूर्ण झाले" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index e573eabc4f82..7c591b6065f9 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Mod Privasi kini diaktifkan secara lalai" - }, "chartOnlyAvailableEth": { "message": "Carta hanya tersedia di rangkaian Ethereum." }, - "confirmClear": { - "message": "Adakah anda pasti mahu mengosongkan tapak web diluluskan?" - }, "contractInteraction": { "message": "Interaksi Kontrak" }, - "clearApprovalData": { - "message": "Kosongkan Data Privasi" - }, "reject": { "message": "Tolak" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ingin menyambung kepada akaun anda" }, - "providerRequestInfo": { - "message": "Tapak ini meminta akses untuk melihat alamat akaun semasa anda. Sentiasa pastikan anda mempercayai tapak web yang anda berinteraksi." - }, "about": { "message": "Mengenai" }, @@ -245,9 +233,6 @@ "connect": { "message": "Sambung" }, - "connectRequest": { - "message": "Sambungkan Permintaan" - }, "connectingTo": { "message": "Menyambungkan kepada $1" }, @@ -359,9 +344,6 @@ "directDepositEtherExplainer": { "message": "Jika anda sudah mempunyai Ether, cara paling cepat untuk mendapatkan Ether di dompet baru anda ialah dengan deposit langsung." }, - "dismiss": { - "message": "Singkirkan" - }, "done": { "message": "Selesai" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index 265542aedecd..7ba285208d06 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -1,16 +1,7 @@ { - "confirmClear": { - "message": "Weet je zeker dat je goedgekeurde websites wilt wissen?" - }, - "clearApprovalData": { - "message": "Gegevens over goedkeuring wissen" - }, "reject": { "message": "Afwijzen" }, - "providerRequestInfo": { - "message": "Het onderstaande domein probeert toegang tot de Ethereum API te vragen zodat deze kan communiceren met de Ethereum-blockchain. Controleer altijd eerst of u op de juiste site bent voordat u Ethereum-toegang goedkeurt." - }, "accountDetails": { "message": "Accountgegevens" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index b0bf0d6dec46..6617284b795c 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Personvernmodus er nå aktivert som standard" - }, "chartOnlyAvailableEth": { "message": "Diagram kun tilgjengelig på Ethereum-nettverk." }, - "confirmClear": { - "message": "Er du sikker på at du vil tømme godkjente nettsteder?" - }, "contractInteraction": { "message": "Kontraktssamhandling" }, - "clearApprovalData": { - "message": "Tøm personvernsdata" - }, "reject": { "message": "Avslå" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ønsker å forbindes med kontoen din " }, - "providerRequestInfo": { - "message": "Dette nettstedet ber om tilgang til å vise din nåværende kontoadresse. Alltid kontroller at du stoler på nettstedene du samhandler med." - }, "about": { "message": "Info" }, @@ -245,9 +233,6 @@ "connect": { "message": "Koble til" }, - "connectRequest": { - "message": "Kontaktforespørsel " - }, "connectingTo": { "message": "Forbinder til $1 " }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Hvis du allerede har noe Ether, er den raskeste måten å få Ether i den nye lommeboken din på ved hjelp av direkte innskudd." }, - "dismiss": { - "message": "Lukk" - }, "done": { "message": "Ferdig" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 6b66773f68fd..1a3807ad5516 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1,10 +1,4 @@ { - "confirmClear": { - "message": "Sigurado ka bang gusto mong i-clear ang mga naaprubahang website?" - }, - "clearApprovalData": { - "message": "Tanggalin ang data ng pag-apruba" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -15,9 +9,6 @@ "reject": { "message": "Tanggihan" }, - "providerRequestInfo": { - "message": "Ang domain na nakalista sa ibaba ay sinusubukang humiling ng access sa Ethereum API upang maaari itong makipag-ugnayan sa Ethereum blockchain. Laging i-double check na ikaw ay nasa tamang site bago aprubahan ang Ethereum access." - }, "accountDetails": { "message": "Detalye ng Account" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 3fa36bd39809..2441408f69d3 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Tryb prywatny jest domyślnie włączony" - }, "chartOnlyAvailableEth": { "message": "Wykres dostępny tylko w sieciach Ethereum" }, - "confirmClear": { - "message": "Czy na pewno chcesz usunąć zatwierdzone strony internetowe?" - }, "contractInteraction": { "message": "Interakcja z kontraktem" }, - "clearApprovalData": { - "message": "Usuń dane poufne" - }, "reject": { "message": "Odrzuć" }, - "providerRequest": { + "likeToConnect": { "message": "$1 chce połączyć się z Twoim kontem" }, - "providerRequestInfo": { - "message": "Ta strona prosi o dostęp, aby zobaczyć adres Twojego aktualnego konta. Zawsze upewnij się, że ufasz stronom, z którymi wchodzisz w interakcję." - }, "about": { "message": "Informacje" }, @@ -245,9 +233,6 @@ "connect": { "message": "Połącz" }, - "connectRequest": { - "message": "Potwierdź żądanie" - }, "connectingTo": { "message": "Łączenie z $1" }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Jeśli już masz Eter, najszybciej umieścisz go w swoim nowym portfelu przy pomocy bezpośredniego depozytu." }, - "dismiss": { - "message": "Zamknij" - }, "done": { "message": "Gotowe" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 51936934953d..9d9ed04509d3 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -1,16 +1,7 @@ { - "confirmClear": { - "message": "Tem certeza de que deseja limpar sites aprovados?" - }, - "clearApprovalData": { - "message": "Limpar dados de aprovação" - }, "reject": { "message": "Rejeitar" }, - "providerRequestInfo": { - "message": "O domínio listado abaixo está tentando solicitar acesso à API Ethereum para que ele possa interagir com o blockchain Ethereum. Sempre verifique se você está no site correto antes de aprovar o acesso à Ethereum." - }, "account": { "message": "Conta" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 44ed790efc8b..e2de06a19f9b 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "O Modo de Privacidade está ativado por padrão" - }, "chartOnlyAvailableEth": { "message": "Tabela disponível apenas em redes de Ethereum." }, - "confirmClear": { - "message": "Tem certeza de que deseja limpar os sites aprovados?" - }, "contractInteraction": { "message": "Interação do Contrato" }, - "clearApprovalData": { - "message": "Limpar Dados de Privacidade" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Rejeitar" }, - "providerRequest": { + "likeToConnect": { "message": "$1 gostaria de se conectar à sua conta" }, - "providerRequestInfo": { - "message": "Este site está solicitando acesso para visualizar o seu endereço de conta atual. Certifique-se sempre de confiar nos sites com os quais você interage." - }, "about": { "message": "Sobre" }, @@ -242,9 +230,6 @@ "connect": { "message": "Conectar-se" }, - "connectRequest": { - "message": "Solicitação de Conexão" - }, "connectingTo": { "message": "Conectando a $1" }, @@ -362,9 +347,6 @@ "directDepositEtherExplainer": { "message": "Se você já tem Ether, a forma mais rápida de colocá-lo em sua nova carteira é o depósito direto." }, - "dismiss": { - "message": "Dispensar" - }, "done": { "message": "Concluído" }, diff --git a/app/_locales/pt_PT/messages.json b/app/_locales/pt_PT/messages.json index b2f844fdd8c8..ae85eb26c119 100644 --- a/app/_locales/pt_PT/messages.json +++ b/app/_locales/pt_PT/messages.json @@ -63,9 +63,6 @@ "details": { "message": "Detalhes" }, - "dismiss": { - "message": "Ignorar" - }, "done": { "message": "Concluído" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index f891a40dfbe0..3ed11cb865eb 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Modul de confidențialitate este activat acum în mod implicit" - }, "chartOnlyAvailableEth": { "message": "Grafic disponibil numai pe rețelele Ethereum." }, - "confirmClear": { - "message": "Sunteți sigur că doriți să ștergeți site-urile aprobate?" - }, "contractInteraction": { "message": "Interacțiune contract" }, - "clearApprovalData": { - "message": "Ștergeți datele confidențiale" - }, "reject": { "message": "Respingeți" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ar dori să se conecteze la contul dvs." }, - "providerRequestInfo": { - "message": "Acest site solicită acces pentru a vedea adresa curentă a contului dvs. Asigurați-vă întotdeauna că aveți încredere în site-urile cu care interacționați." - }, "about": { "message": "Despre" }, @@ -248,9 +236,6 @@ "connect": { "message": "Conectează-te" }, - "connectRequest": { - "message": "Solicitare de conectare" - }, "connectingTo": { "message": "Se conectează la $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Dacă deja aveți Ether, cel mai rapid mod de a avea Ether în portofelul nou prin depunere directă." }, - "dismiss": { - "message": "Închide" - }, "done": { "message": "Efectuat" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 660b2799e406..43249d6bcdb8 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1,16 +1,7 @@ { - "confirmClear": { - "message": "Вы уверены, что хотите очистить утвержденные веб-сайты?Tem certeza de que deseja limpar sites aprovados?" - }, - "clearApprovalData": { - "message": "Четкие данные об утверждении" - }, "reject": { "message": "Отклонить" }, - "providerRequestInfo": { - "message": "Домен, указанный ниже, пытается запросить доступ к API-интерфейсу Ethereum, чтобы он мог взаимодействовать с блокчейном Ethereum. Всегда проверяйте, что вы находитесь на правильном сайте, прежде чем одобрять доступ к веб-сайту." - }, "account": { "message": "Счет" }, @@ -545,16 +536,13 @@ "youSign": { "message": "Вы подписываете" }, - "privacyModeDefault": { - "message": "Режим конфиденциальности теперь включен по умолчанию" - }, "chartOnlyAvailableEth": { "message": "Диаграмма доступна только в сетях Ethereum." }, "contractInteraction": { "message": "Взаимодействие с контрактом" }, - "providerRequest": { + "likeToConnect": { "message": "$1 запрашивает доступ к вашему аккаунту" }, "about": { @@ -707,9 +695,6 @@ "connect": { "message": "Подключиться" }, - "connectRequest": { - "message": "Запрос на подключение" - }, "connectingTo": { "message": "Подключение к $1" }, @@ -752,9 +737,6 @@ "deleteAccount": { "message": "Удалить аккаунт" }, - "dismiss": { - "message": "Отклюнить" - }, "downloadGoogleChrome": { "message": "Скачать Google Chrome" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 5238e076df7b..d975048d84b3 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Režim súkromia je povolený. Je prednastavený automaticky" - }, "chartOnlyAvailableEth": { "message": "Graf je k dispozícii iba v sieťach Ethereum." }, - "confirmClear": { - "message": "Naozaj chcete vymazať schválené webové stránky?" - }, "contractInteraction": { "message": "Zmluvná interakcia" }, - "clearApprovalData": { - "message": "Jasné údaje o schválení" - }, "reject": { "message": "Odmítnout" }, - "providerRequest": { + "likeToConnect": { "message": "$1 sa chce pripojiť k vášmu účtu" }, - "providerRequestInfo": { - "message": "Níže uvedená doména se pokouší požádat o přístup k API Ethereum, aby mohla komunikovat s blokádou Ethereum. Před schválením přístupu Ethereum vždy zkontrolujte, zda jste na správném místě." - }, "about": { "message": "Informácie" }, @@ -239,9 +227,6 @@ "connect": { "message": "Pripojenie" }, - "connectRequest": { - "message": "Požiadavka na pripojenie" - }, "connectingTo": { "message": "Pripája sa k $1" }, @@ -359,9 +344,6 @@ "directDepositEtherExplainer": { "message": "Pokud už vlastníte nějaký Ether, nejrychleji ho dostanete do peněženky přímým vkladem." }, - "dismiss": { - "message": "Zatvoriť" - }, "done": { "message": "Hotovo" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 8530dd43dbaf..312bcecfba23 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Zasebnostni način je zdaj privzeto omogočen" - }, "chartOnlyAvailableEth": { "message": "Grafikon na voljo le v glavnih omrežjih." }, - "confirmClear": { - "message": "Ste prepričani da želite počistiti odobrene spletne strani?" - }, "contractInteraction": { "message": "Interakcija s pogodbo" }, - "clearApprovalData": { - "message": "Počisti podatke o odobritvi" - }, "reject": { "message": "Zavrni" }, - "providerRequest": { + "likeToConnect": { "message": "$1 se želi povezati z vašim računom." }, - "providerRequestInfo": { - "message": "Domena zahteva dostop do verige blokov in ogled vašega računa. Pred potrditvjo vedno preverite ali ste na želeni spletni strani." - }, "about": { "message": "O možnostih" }, @@ -248,9 +236,6 @@ "connect": { "message": "Poveži" }, - "connectRequest": { - "message": "Zahteva za povezavo" - }, "connectingTo": { "message": "Povezovanje na $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Če že imate Ether, ga lahko najhitreje dobite v MetaMask z neposrednim vplačilom." }, - "dismiss": { - "message": "Opusti" - }, "done": { "message": "Končano" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index d3fd1cbd4c64..f4084996f677 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Režim privatnosti je podrazumevano omogućen" - }, "chartOnlyAvailableEth": { "message": "Grafikon dostupan jedino na mrežama Ethereum." }, - "confirmClear": { - "message": "Da li ste sigurni da želite da obrišete odobrene veb lokacije?" - }, "contractInteraction": { "message": "Ugovorna interakcija" }, - "clearApprovalData": { - "message": "Obrišite privatne podatke" - }, "reject": { "message": "Одбиј" }, - "providerRequest": { + "likeToConnect": { "message": "$1 bi hteo da se poveže sa vašim nalogom" }, - "providerRequestInfo": { - "message": "Ovaj sajt traži pristup kako bi video vašu trenutnu adresu naloga. Uvek budite sigurni da verujete sajtovima s kojima komunicirate." - }, "about": { "message": "Основни подаци" }, @@ -245,9 +233,6 @@ "connect": { "message": "Повезивање" }, - "connectRequest": { - "message": "Zahtev za povezivanjem" - }, "connectingTo": { "message": "Povezuje se na $1" }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "Ako već imate neki Ether, najbrži način da preuzmete Ether u svoj novi novčanik jeste direktnim deponovanjem." }, - "dismiss": { - "message": "Одбаци" - }, "done": { "message": "Gotovo" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 1b7ecc06e3c2..7503570450fb 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "Integritetsläge är nu aktiverat som standard" - }, "chartOnlyAvailableEth": { "message": "Tabellen är endast tillgänglig på Ethereum-nätverk." }, - "confirmClear": { - "message": "Är du säker på att du vill rensa godkända webbplatser?" - }, "contractInteraction": { "message": "Kontraktinteraktion" }, - "clearApprovalData": { - "message": "Rensa personlig data" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Avvisa" }, - "providerRequest": { + "likeToConnect": { "message": "$1 vill ansluta till ditt konto" }, - "providerRequestInfo": { - "message": "Den här sidan begär åtkomst till din aktuella kontoadress. Se till att du kan lita på de sidor du använder dig av." - }, "about": { "message": "Om" }, @@ -242,9 +230,6 @@ "connect": { "message": "Ansluta" }, - "connectRequest": { - "message": "Anslutningsförfrågan" - }, "connectingTo": { "message": "Ansluter till $1" }, @@ -362,9 +347,6 @@ "directDepositEtherExplainer": { "message": "Om du redan har Ether är det snabbaste sättet att få Ether i din nya plånbok att göra en direktinsättning." }, - "dismiss": { - "message": "Ta bort permanent" - }, "done": { "message": "Klart" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index c8c2e36eecbb..38c89aca8643 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -1,19 +1,10 @@ { - "privacyModeDefault": { - "message": "Hali ya Faragha sasa imewezeshwa kwa chaguomsingi" - }, "chartOnlyAvailableEth": { "message": "Zogoa inapatikana kwenye mitandao ya Ethereum pekee." }, - "confirmClear": { - "message": "Una uhakika unataka kufuta tovuti zilizodihinishwa?" - }, "contractInteraction": { "message": "Mwingiliono wa Mkataba" }, - "clearApprovalData": { - "message": "Futa Data za Faragha" - }, "appName": { "message": "MetaMask", "description": "The name of the application" @@ -21,12 +12,9 @@ "reject": { "message": "Kataa" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ingependa kuunganishwa kwenye akaunti yako" }, - "providerRequestInfo": { - "message": "Tovuti hii inaomba idhini ya kuangalia anwani yako ya akaunti ya sasa. Daima hakikisha unaziamami tovuti ambazo unaingiliana nazo." - }, "about": { "message": "Kuhusu" }, @@ -242,9 +230,6 @@ "connect": { "message": "Unganisha" }, - "connectRequest": { - "message": "Unganisha Ombi" - }, "connectingTo": { "message": "Inaunganisha kwenye $1" }, @@ -362,9 +347,6 @@ "directDepositEtherExplainer": { "message": "Ikiwa tayari una sarafu kadhaa za Ether, njia rahisi ya kupata Ether kwenye waleti yako mpya kupitia kuweka moja kwa moja." }, - "dismiss": { - "message": "Ondoa" - }, "done": { "message": "Imekamilika" }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index 698349c24e5f..dc48abb02dbf 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -1,19 +1,10 @@ { - "confirmClear": { - "message": "அங்கீகரிக்கப்பட்ட வலைத்தளங்களை நிச்சயமாக நீக்க விரும்புகிறீர்களா?" - }, - "clearApprovalData": { - "message": "ஒப்புதல் தரவை அழி" - }, "approve": { "message": "ஒப்புதல்" }, "reject": { "message": "நிராகரி" }, - "providerRequestInfo": { - "message": "கீழே பட்டியலிடப்பட்டுள்ள டொமைன் Web3 ஏபிஐ அணுகலைக் கோருவதற்கு முயற்சிக்கிறது, எனவே இது Ethereum blockchain உடன் தொடர்பு கொள்ள முடியும். Web3 அணுகுமுறையை அங்கீகரிப்பதற்கு முன் சரியான தளத்தில் இருப்பதை எப்போதும் இருமுறை சரிபார்க்கவும்." - }, "account": { "message": "கணக்கு" }, @@ -578,9 +569,6 @@ "delete": { "message": "நீக்கு" }, - "dismiss": { - "message": "நிராகரி" - }, "fast": { "message": "வேகமான" }, diff --git a/app/_locales/te/messages.json b/app/_locales/te/messages.json index 6de4b0464def..2df11217d5a7 100644 --- a/app/_locales/te/messages.json +++ b/app/_locales/te/messages.json @@ -54,9 +54,6 @@ "details": { "message": "వివరాలు" }, - "dismiss": { - "message": "తొలగించు" - }, "done": { "message": "పూర్తయింది" }, diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index f07f3421eca8..6b3686f45743 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -1,19 +1,10 @@ { - "confirmClear": { - "message": "คุณแน่ใจหรือไม่ว่าต้องการล้างเว็บไซต์ที่ผ่านการอนุมัติ" - }, - "clearApprovalData": { - "message": "ล้างข้อมูลการอนุมัติ" - }, "reject": { "message": "ปฏิเสธ" }, - "providerRequest": { + "likeToConnect": { "message": "$1 ต้องการเชื่อมต่อกับบัญชีของคุณ" }, - "providerRequestInfo": { - "message": "โดเมนที่แสดงด้านล่างกำลังพยายามขอเข้าถึง API ของ Ethereum เพื่อให้สามารถโต้ตอบกับบล็อค Ethereum ได้ ตรวจสอบว่าคุณอยู่ในไซต์ที่ถูกต้องก่อนที่จะอนุมัติการเข้าถึง Ethereum เสมอ" - }, "about": { "message": "เกี่ยวกับ" }, @@ -184,9 +175,6 @@ "directDepositEtherExplainer": { "message": "ถ้าคุณมีอีเธอร์อยู่แล้ววิธีการที่เร็วที่สุดในการเอาเงินเข้ากระเป๋าใหม่ก็คือการโอนตรงๆ" }, - "dismiss": { - "message": "ปิด" - }, "done": { "message": "เสร็จสิ้น" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index c6027a42d0fa..fdb1ae927cd2 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -1,16 +1,7 @@ { - "confirmClear": { - "message": "Onaylanmış web sitelerini silmek istediğinizden emin misiniz?" - }, - "clearApprovalData": { - "message": "Onay verilerini temizle" - }, "reject": { "message": "Reddetmek" }, - "providerRequestInfo": { - "message": "Aşağıda listelenen etki alanı, Ethereum API'sine erişim talep etmeye çalışmaktadır, böylece Ethereum blockchain ile etkileşime girebilir. Web3 erişimini onaylamadan önce her zaman doğru sitede olduğunuzu kontrol edin." - }, "account": { "message": "Hesap" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index 49d04a096f5e..cec516b6ccda 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "Режим конфіденційності тепер увімкнено за замовчуванням" - }, "chartOnlyAvailableEth": { "message": "Таблиця доступна тільки в мережах Ethereum." }, - "confirmClear": { - "message": "Ви впевнені, що хочете очистити затверджені веб-сайти?" - }, "contractInteraction": { "message": "Контрактна взаємодія" }, - "clearApprovalData": { - "message": "Очистити приватні дані" - }, "reject": { "message": "Відхилити" }, - "providerRequest": { + "likeToConnect": { "message": "$1 бажає підключитися до вашого облікового запису" }, - "providerRequestInfo": { - "message": "Цей сайт запитує доступ на перегляд вашої поточної адреси облікового запису. Завжди взаємодійте лише з веб-сайтами, яким довіряєте." - }, "about": { "message": "Про Google Chrome" }, @@ -248,9 +236,6 @@ "connect": { "message": "Під’єднатися" }, - "connectRequest": { - "message": "Запит на з'єднання" - }, "connectingTo": { "message": "Під'єднуємось до $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "Якщо ви вже маєте ефір, пряме переведення – найшвидший спосіб передати ефір у свій гаманець." }, - "dismiss": { - "message": "Відхилити" - }, "done": { "message": "Готово" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index bc017c9472cd..6136403baebc 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1,16 +1,7 @@ { - "confirmClear": { - "message": "Bạn có chắc chắn muốn xóa các trang web được phê duyệt không?" - }, - "clearApprovalData": { - "message": "Xóa dữ liệu phê duyệt" - }, "reject": { "message": "Từ chối" }, - "providerRequestInfo": { - "message": "Miền được liệt kê bên dưới đang cố gắng yêu cầu quyền truy cập vào API Ethereum để nó có thể tương tác với chuỗi khối Ethereum. Luôn kiểm tra kỹ xem bạn có đang ở đúng trang web trước khi phê duyệt quyền truy cập Ethereum hay không." - }, "account": { "message": "Tài khoản" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index cade6ee71abe..e92813a9a949 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "现已默认启用隐私模式" - }, "chartOnlyAvailableEth": { "message": "聊天功能仅对以太坊网络开放。" }, - "confirmClear": { - "message": "您确定要清除已批准的网站吗?" - }, "contractInteraction": { "message": "合约交互" }, - "clearApprovalData": { - "message": "清除批准数据" - }, "reject": { "message": "拒绝" }, - "providerRequest": { + "likeToConnect": { "message": "$1 希望关联您的账户" }, - "providerRequestInfo": { - "message": "下面列出的域正在尝试请求访问Ethereum API,以便它可以与以太坊区块链进行交互。在批准Ethereum访问之前,请务必仔细检查您是否在正确的站点上。" - }, "about": { "message": "关于" }, @@ -87,7 +75,7 @@ "message": "添加推荐代币" }, "addAcquiredTokens": { - "message": "在Metamask上添加已用的代币" + "message": "在MetaMask上添加已用的代币" }, "amount": { "message": "数量" @@ -248,9 +236,6 @@ "connect": { "message": "连接" }, - "connectRequest": { - "message": "关联请求" - }, "connectingTo": { "message": "正在连接 $1" }, @@ -368,9 +353,6 @@ "directDepositEtherExplainer": { "message": "如果你已经有了一些 Ether,通过直接转入是你的新钱包获取 Ether 的最快捷方式。" }, - "dismiss": { - "message": "关闭" - }, "done": { "message": "完成" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 3d0e299a6060..2859e8fd407d 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1,28 +1,16 @@ { - "privacyModeDefault": { - "message": "隱私模式現已根據預設開啟" - }, "chartOnlyAvailableEth": { "message": "圖表僅適用於以太坊網路。" }, - "confirmClear": { - "message": "您確定要清除已批准的網站紀錄?" - }, "contractInteraction": { "message": "合約互動" }, - "clearApprovalData": { - "message": "清除批准數據" - }, "reject": { "message": "拒絕" }, - "providerRequest": { + "likeToConnect": { "message": "$1 請求訪問帳戶權限" }, - "providerRequestInfo": { - "message": "此網站希望能讀取您的帳戶資訊。請務必確認您信任這個網站、並了解後續可能的交易行為。" - }, "about": { "message": "關於" }, @@ -245,9 +233,6 @@ "connect": { "message": "連線" }, - "connectRequest": { - "message": "連線請求" - }, "connectingTo": { "message": "連線到$1" }, @@ -365,9 +350,6 @@ "directDepositEtherExplainer": { "message": "如果您已經擁有乙太幣,直接存入功能是讓新錢包最快取得乙太幣的方式。" }, - "dismiss": { - "message": "關閉" - }, "done": { "message": "完成" }, diff --git a/app/images/broken-line.svg b/app/images/broken-line.svg new file mode 100644 index 000000000000..ec4ed0d9c64b --- /dev/null +++ b/app/images/broken-line.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/images/connect-white.svg b/app/images/connect-white.svg new file mode 100644 index 000000000000..e9063ae4639f --- /dev/null +++ b/app/images/connect-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/images/provider-approval-check.svg b/app/images/permissions-check.svg similarity index 100% rename from app/images/provider-approval-check.svg rename to app/images/permissions-check.svg diff --git a/app/scripts/background.js b/app/scripts/background.js index 18bdfdfb95ac..e5c9ea66516b 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -64,6 +64,7 @@ const isEdge = !isIE && !!window.StyleMedia let popupIsOpen = false let notificationIsOpen = false const openMetamaskTabsIDs = {} +const requestAccountTabIds = {} // state persistence const localStore = new LocalStore() @@ -75,7 +76,6 @@ initialize().catch(log.error) // setup metamask mesh testing container const { submitMeshMetricsEntry } = setupMetamaskMeshMetrics() - /** * An object representing a transaction, in whatever state it is in. * @typedef TransactionMeta @@ -248,6 +248,12 @@ function setupController (initState, initLangCode) { // platform specific api platform, encryptor: isEdge ? new EdgeEncryptor() : undefined, + getRequestAccountTabIds: () => { + return requestAccountTabIds + }, + getOpenMetamaskTabsIds: () => { + return openMetamaskTabsIDs + }, }) const provider = controller.provider @@ -387,6 +393,17 @@ function setupController (initState, initLangCode) { }) } } else { + if (remotePort.sender && remotePort.sender.tab && remotePort.sender.url) { + const tabId = remotePort.sender.tab.id + const url = new URL(remotePort.sender.url) + const origin = url.hostname + + remotePort.onMessage.addListener(msg => { + if (msg.data && msg.data.method === 'eth_requestAccounts') { + requestAccountTabIds[origin] = tabId + } + }) + } connectExternal(remotePort) } } @@ -411,7 +428,7 @@ function setupController (initState, initLangCode) { controller.messageManager.on('updateBadge', updateBadge) controller.personalMessageManager.on('updateBadge', updateBadge) controller.typedMessageManager.on('updateBadge', updateBadge) - controller.providerApprovalController.memStore.on('update', updateBadge) + controller.permissionsController.permissions.subscribe(updateBadge) /** * Updates the Web Extension's "badge" number, on the little fox in the toolbar. @@ -423,8 +440,8 @@ function setupController (initState, initLangCode) { const unapprovedMsgCount = controller.messageManager.unapprovedMsgCount const unapprovedPersonalMsgs = controller.personalMessageManager.unapprovedPersonalMsgCount const unapprovedTypedMsgs = controller.typedMessageManager.unapprovedTypedMessagesCount - const pendingProviderRequests = controller.providerApprovalController.memStore.getState().providerRequests.length - const count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgs + unapprovedTypedMsgs + pendingProviderRequests + const pendingPermissionRequests = Object.keys(controller.permissionsController.permissions.state.permissionsRequests).length + const count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgs + unapprovedTypedMsgs + pendingPermissionRequests if (count) { label = String(count) } diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 6ea2db740dd9..d583399aeff5 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -2,7 +2,6 @@ const fs = require('fs') const path = require('path') const pump = require('pump') const log = require('loglevel') -const Dnode = require('dnode') const querystring = require('querystring') const { Writable } = require('readable-stream') const LocalMessageDuplexStream = require('post-message-stream') @@ -21,7 +20,7 @@ const inpageBundle = inpageContent + inpageSuffix // If we create a FireFox-only code path using that API, // MetaMask will be much faster loading and performant on Firefox. -if (shouldInjectWeb3()) { +if (shouldInjectProvider()) { injectScript(inpageBundle) start() } @@ -40,7 +39,7 @@ function injectScript (content) { container.insertBefore(scriptTag, container.children[0]) container.removeChild(scriptTag) } catch (e) { - console.error('MetaMask script injection failed', e) + console.error('MetaMask provider injection failed.', e) } } @@ -132,12 +131,6 @@ async function setupStreams () { // connect "phishing" channel to warning system const phishingStream = extensionMux.createStream('phishing') phishingStream.once('data', redirectToPhishingWarning) - - // connect "publicApi" channel to submit page metadata - const publicApiStream = extensionMux.createStream('publicApi') - const background = await setupPublicApi(publicApiStream) - - return { background } } function forwardTrafficBetweenMuxers (channelName, muxA, muxB) { @@ -151,39 +144,6 @@ function forwardTrafficBetweenMuxers (channelName, muxA, muxB) { ) } -async function setupPublicApi (outStream) { - const api = { - getSiteMetadata: (cb) => cb(null, getSiteMetadata()), - } - const dnode = Dnode(api) - pump( - outStream, - dnode, - outStream, - (err) => { - // report any error - if (err) { - log.error(err) - } - } - ) - const background = await new Promise(resolve => dnode.once('remote', resolve)) - return background -} - -/** - * Gets site metadata and returns it - * - */ -function getSiteMetadata () { - // get metadata - const metadata = { - name: getSiteName(window), - icon: getSiteIcon(window), - } - return metadata -} - /** * Error handler for page to extension stream disconnections * @@ -199,11 +159,11 @@ function logStreamDisconnectWarning (remoteLabel, err) { } /** - * Determines if Web3 should be injected + * Determines if the provider should be injected * - * @returns {boolean} {@code true} if Web3 should be injected + * @returns {boolean} {@code true} if the provider should be injected */ -function shouldInjectWeb3 () { +function shouldInjectProvider () { return doctypeCheck() && suffixCheck() && documentElementCheck() && !blacklistedDomainCheck() } @@ -226,8 +186,8 @@ function doctypeCheck () { * Returns whether or not the extension (suffix) of the current document is prohibited * * This checks {@code window.location.pathname} against a set of file extensions - * that should not have web3 injected into them. This check is indifferent of query parameters - * in the location. + * that we should not inject the provider into. This check is indifferent of + * query parameters in the location. * * @returns {boolean} whether or not the extension of the current document is prohibited */ @@ -300,46 +260,6 @@ function redirectToPhishingWarning () { })}` } - -/** - * Extracts a name for the site from the DOM - */ -function getSiteName (window) { - const document = window.document - const siteName = document.querySelector('head > meta[property="og:site_name"]') - if (siteName) { - return siteName.content - } - - const metaTitle = document.querySelector('head > meta[name="title"]') - if (metaTitle) { - return metaTitle.content - } - - return document.title -} - -/** - * Extracts an icon for the site from the DOM - */ -function getSiteIcon (window) { - const document = window.document - - // Use the site's favicon if it exists - const shortcutIcon = document.querySelector('head > link[rel="shortcut icon"]') - if (shortcutIcon) { - return shortcutIcon.href - } - - // Search through available icons in no particular order - const icon = Array.from(document.querySelectorAll('head > link[rel="icon"]')).find((icon) => Boolean(icon.href)) - if (icon) { - return icon.href - } - - return null -} - /** * Returns a promise that resolves when the DOM is loaded (does not wait for images to load) */ @@ -349,5 +269,5 @@ async function domIsReady () { return } // wait for load - await 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/permissions/index.js b/app/scripts/controllers/permissions/index.js new file mode 100644 index 000000000000..899044b13e37 --- /dev/null +++ b/app/scripts/controllers/permissions/index.js @@ -0,0 +1,377 @@ +const JsonRpcEngine = require('json-rpc-engine') +const asMiddleware = require('json-rpc-engine/src/asMiddleware') +const ObservableStore = require('obs-store') +const RpcCap = require('rpc-cap').CapabilitiesController +const { ethErrors } = require('eth-json-rpc-errors') + +const getRestrictedMethods = require('./restrictedMethods') +const createMethodMiddleware = require('./methodMiddleware') +const createLoggerMiddleware = require('./loggerMiddleware') + +// Methods that do not require any permissions to use: +const SAFE_METHODS = require('./permissions-safe-methods.json') + +// some constants +const METADATA_STORE_KEY = 'domainMetadata' +const LOG_STORE_KEY = 'permissionsLog' +const HISTORY_STORE_KEY = 'permissionsHistory' +const WALLET_METHOD_PREFIX = 'wallet_' +const CAVEAT_NAMES = { + exposedAccounts: 'exposedAccounts', +} +const ACCOUNTS_CHANGED_NOTIFICATION = 'wallet_accountsChanged' + +class PermissionsController { + + constructor ( + { + platform, notifyDomain, notifyAllDomains, keyringController, + } = {}, + restoredPermissions = {}, + restoredState = {}) { + this.store = new ObservableStore({ + [METADATA_STORE_KEY]: restoredState[METADATA_STORE_KEY] || {}, + [LOG_STORE_KEY]: restoredState[LOG_STORE_KEY] || [], + [HISTORY_STORE_KEY]: restoredState[HISTORY_STORE_KEY] || {}, + }) + this.notifyDomain = notifyDomain + this.notifyAllDomains = notifyAllDomains + this.keyringController = keyringController + this._platform = platform + this._restrictedMethods = getRestrictedMethods(this) + this._initializePermissions(restoredPermissions) + } + + createMiddleware ({ origin, extensionId }) { + + if (extensionId) { + this.store.updateState({ + [METADATA_STORE_KEY]: { + ...this.store.getState()[METADATA_STORE_KEY], + [origin]: { extensionId }, + }, + }) + } + + const engine = new JsonRpcEngine() + + engine.push(createLoggerMiddleware({ + walletPrefix: WALLET_METHOD_PREFIX, + restrictedMethods: Object.keys(this._restrictedMethods), + ignoreMethods: [ 'wallet_sendDomainMetadata' ], + store: this.store, + logStoreKey: LOG_STORE_KEY, + historyStoreKey: HISTORY_STORE_KEY, + })) + + engine.push(createMethodMiddleware({ + store: this.store, + storeKey: METADATA_STORE_KEY, + getAccounts: this.getAccounts.bind(this, origin), + requestAccountsPermission: this._requestPermissions.bind( + this, origin, { eth_accounts: {} } + ), + })) + + engine.push(this.permissions.providerMiddlewareFunction.bind( + this.permissions, { origin } + )) + return asMiddleware(engine) + } + + /** + * Returns the accounts that should be exposed for the given origin domain, + * if any. This method exists for when a trusted context needs to know + * which accounts are exposed to a given domain. + * + * @param {string} origin - The origin string. + */ + getAccounts (origin) { + return new Promise((resolve, _) => { + + const req = { method: 'eth_accounts' } + const res = {} + this.permissions.providerMiddlewareFunction( + { origin }, req, res, () => {}, _end + ) + + function _end () { + if (res.error || !Array.isArray(res.result)) { + resolve([]) + } else { + resolve(res.result) + } + } + }) + } + + /** + * Submits a permissions request to rpc-cap. Internal use only. + * + * @param {string} origin - The origin string. + * @param {IRequestedPermissions} permissions - The requested permissions. + */ + _requestPermissions (origin, permissions) { + return new Promise((resolve, reject) => { + + const req = { method: 'wallet_requestPermissions', params: [permissions] } + const res = {} + this.permissions.providerMiddlewareFunction( + { origin }, req, res, () => {}, _end + ) + + function _end (err) { + if (err || res.error) { + reject(err || res.error) + } else { + resolve(res.result) + } + } + }) + } + + /** + * User approval callback. The request can fail if the request is invalid. + * + * @param {object} approved the approved request object + */ + async approvePermissionsRequest (approved, accounts) { + + const { id } = approved.metadata + const approval = this.pendingApprovals[id] + + try { + + // attempt to finalize the request and resolve it + await this.finalizePermissionsRequest(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, + })) + } + + delete this.pendingApprovals[id] + } + + /** + * User rejection callback. + * + * @param {string} id the id of the rejected request + */ + async rejectPermissionsRequest (id) { + const approval = this.pendingApprovals[id] + approval.reject(ethErrors.provider.userRejectedRequest()) + delete this.pendingApprovals[id] + } + + /** + * Grants the given origin the eth_accounts permission for the given account(s). + * This method should ONLY be called as a result of direct user action in the UI, + * with the intention of supporting legacy dapps that don't support EIP 1102. + * + * @param {string} origin - The origin to expose the account(s) to. + * @param {Array} accounts - The account(s) to expose. + */ + async legacyExposeAccounts (origin, accounts) { + + const permissions = { + eth_accounts: {}, + } + + await this.finalizePermissionsRequest(permissions, accounts) + + let error + try { + await new Promise((resolve, reject) => { + this.permissions.grantNewPermissions(origin, permissions, {}, err => err ? resolve() : reject(err)) + }) + } catch (err) { + error = err + } + + if (error) { + if (error.code === 4001) { + throw error + } else { + throw ethErrors.rpc.internal({ + message: `Failed to add 'eth_accounts' to '${origin}'.`, + data: { + originalError: error, + accounts, + }, + }) + } + } + } + + /** + * Update the accounts exposed to the given origin. + * Throws error if the update fails. + * + * @param {string} origin - The origin to change the exposed accounts for. + * @param {string[]} accounts - The new account(s) to expose. + */ + async updateExposedAccounts (origin, accounts) { + + await this.validateExposedAccounts(accounts) + + this.permissions.updateCaveatFor( + origin, 'eth_accounts', CAVEAT_NAMES.exposedAccounts, accounts + ) + + this.notifyDomain(origin, { + method: ACCOUNTS_CHANGED_NOTIFICATION, + result: accounts, + }) + } + + /** + * Finalizes a permissions request. + * Throws if request validation fails. + * + * @param {Object} requestedPermissions - The requested permissions. + * @param {string[]} accounts - The accounts to expose, if any. + */ + async finalizePermissionsRequest (requestedPermissions, accounts) { + + const { eth_accounts: ethAccounts } = requestedPermissions + + if (ethAccounts) { + + await this.validateExposedAccounts(accounts) + + if (!ethAccounts.caveats) { + ethAccounts.caveats = [] + } + + // caveat names are unique, and we will only construct this caveat here + ethAccounts.caveats = ethAccounts.caveats.filter(c => ( + c.name !== CAVEAT_NAMES.exposedAccounts + )) + + ethAccounts.caveats.push( + { + type: 'filterResponse', + value: accounts, + name: CAVEAT_NAMES.exposedAccounts, + }, + ) + } + } + + /** + * Validate an array of accounts representing accounts to be exposed + * to a domain. Throws error if validation fails. + * + * @param {string[]} accounts - An array of addresses. + */ + async validateExposedAccounts (accounts) { + + if (!Array.isArray(accounts) || accounts.length === 0) { + throw new Error('Must provide non-empty array of account(s).') + } + + // assert accounts exist + const allAccounts = await this.keyringController.getAccounts() + accounts.forEach(acc => { + if (!allAccounts.includes(acc)) { + throw new Error(`Unknown account: ${acc}`) + } + }) + } + + /** + * Removes the given permissions for the given domain. + * @param {object} domains { origin: [permissions] } + */ + removePermissionsFor (domains) { + + Object.entries(domains).forEach(([origin, perms]) => { + + this.permissions.removePermissionsFor( + origin, + perms.map(methodName => { + + if (methodName === 'eth_accounts') { + this.notifyDomain( + origin, + { method: ACCOUNTS_CHANGED_NOTIFICATION, result: [] } + ) + } + + return { parentCapability: methodName } + }) + ) + }) + } + + /** + * Removes all known domains and their related permissions. + */ + clearPermissions () { + this.permissions.clearDomains() + this.notifyAllDomains({ + method: ACCOUNTS_CHANGED_NOTIFICATION, + result: [], + }) + } + + /** + * A convenience method for retrieving a login object + * or creating a new one if needed. + * + * @param {string} origin = The origin string representing the domain. + */ + _initializePermissions (restoredState) { + + // these permission requests are almost certainly stale + const initState = { ...restoredState, permissionsRequests: [] } + + this.pendingApprovals = {} + + this.permissions = new RpcCap({ + + // Supports passthrough methods: + safeMethods: SAFE_METHODS, + + // optional prefix for internal methods + methodPrefix: WALLET_METHOD_PREFIX, + + 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 } } = req + + this._platform.openExtensionInBrowser('connect') + + return new Promise((resolve, reject) => { + this.pendingApprovals[id] = { resolve, reject } + }) + }, + }, initState) + } +} + +module.exports = { + PermissionsController, + addInternalMethodPrefix: prefix, + CAVEAT_NAMES, +} + + +function prefix (method) { + return WALLET_METHOD_PREFIX + method +} diff --git a/app/scripts/controllers/permissions/loggerMiddleware.js b/app/scripts/controllers/permissions/loggerMiddleware.js new file mode 100644 index 000000000000..0e3c7f39329e --- /dev/null +++ b/app/scripts/controllers/permissions/loggerMiddleware.js @@ -0,0 +1,169 @@ + +const clone = require('clone') +const { isValidAddress } = require('ethereumjs-util') + +const LOG_LIMIT = 100 + +/** + * Create middleware for logging requests and responses to restricted and + * permissions-related methods. + */ +module.exports = function createLoggerMiddleware ({ + walletPrefix, restrictedMethods, store, logStoreKey, historyStoreKey, ignoreMethods, +}) { + return (req, res, next, _end) => { + let activityEntry, requestedMethods + const { origin, method } = req + const isInternal = method.startsWith(walletPrefix) + if ((isInternal || restrictedMethods.includes(method)) && !ignoreMethods.includes(method)) { + activityEntry = logActivity(req, isInternal) + if (method === `${walletPrefix}requestPermissions`) { + requestedMethods = getRequestedMethods(req) + } + } else if (method === 'eth_requestAccounts') { + activityEntry = logActivity(req, isInternal) + requestedMethods = [ 'eth_accounts' ] + } else { + return next() + } + + next(cb => { + const time = Date.now() + addResponse(activityEntry, res, time) + if (!res.error && requestedMethods) { + logHistory(requestedMethods, origin, res.result, time, method === 'eth_requestAccounts') + } + cb() + }) + } + + function logActivity (request, isInternal) { + const activityEntry = { + id: request.id, + method: request.method, + methodType: isInternal ? 'internal' : 'restricted', + origin: request.origin, + request: cloneObj(request), + requestTime: Date.now(), + response: null, + responseTime: null, + success: null, + } + commitActivity(activityEntry) + return activityEntry + } + + function addResponse (activityEntry, response, time) { + if (!response) { + return + } + activityEntry.response = cloneObj(response) + activityEntry.responseTime = time + activityEntry.success = !response.error + } + + function commitActivity (entry) { + const logs = store.getState()[logStoreKey] + if (logs.length > LOG_LIMIT - 2) { + logs.pop() + } + logs.push(entry) + store.updateState({ [logStoreKey]: logs }) + } + + function getRequestedMethods (request) { + if ( + !request.params || + typeof request.params[0] !== 'object' || + Array.isArray(request.params[0]) + ) { + return null + } + return Object.keys(request.params[0]) + } + + function logHistory (requestedMethods, origin, result, time, isEthRequestAccounts) { + let accounts, entries + if (isEthRequestAccounts) { + accounts = result + const accountToTimeMap = accounts.reduce((acc, account) => ({ ...acc, [account]: time }), {}) + entries = { 'eth_accounts': { accounts: accountToTimeMap, lastApproved: time } } + } else { + entries = result + ? result + .map(perm => { + if (perm.parentCapability === 'eth_accounts') { + accounts = getAccountsFromPermission(perm) + } + return perm.parentCapability + }) + .reduce((acc, m) => { + if (requestedMethods.includes(m)) { + if (m === 'eth_accounts') { + const accountToTimeMap = accounts.reduce((acc, account) => ({ ...acc, [account]: time }), {}) + acc[m] = { lastApproved: time, accounts: accountToTimeMap } + } else { + acc[m] = { lastApproved: time } + } + } + return acc + }, {}) + : {} + } + + if (Object.keys(entries).length > 0) { + commitHistory(origin, entries) + } + } + + function commitHistory (origin, entries) { + const history = store.getState()[historyStoreKey] || {} + const newOriginHistory = { + ...history[origin], + ...entries, + } + + if (history[origin] && history[origin]['eth_accounts'] && entries['eth_accounts']) { + newOriginHistory['eth_accounts'] = { + lastApproved: entries['eth_accounts'].lastApproved, + accounts: { + ...history[origin]['eth_accounts'].accounts, + ...entries['eth_accounts'].accounts, + }, + } + } + + history[origin] = newOriginHistory + + store.updateState({ [historyStoreKey]: history }) + } +} + +// the call to clone is set to disallow circular references +// we attempt cloning at a depth of 3 and 2, then return a +// shallow copy of the object +function cloneObj (obj) { + for (let i = 3; i > 1; i--) { + try { + return clone(obj, false, i) + } catch (_) {} + } + return { ...obj } +} + +function getAccountsFromPermission (perm) { + if (perm.parentCapability !== 'eth_accounts' || !perm.caveats) { + return [] + } + const accounts = {} + for (const c of perm.caveats) { + if (c.type === 'filterResponse' && Array.isArray(c.value)) { + for (const v of c.value) { + if (isValidAddress(v)) { + accounts[v] = true + } + } + } + } + return Object.keys(accounts) +} diff --git a/app/scripts/controllers/permissions/methodMiddleware.js b/app/scripts/controllers/permissions/methodMiddleware.js new file mode 100644 index 000000000000..e0b451c9f631 --- /dev/null +++ b/app/scripts/controllers/permissions/methodMiddleware.js @@ -0,0 +1,90 @@ + +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const { ethErrors } = require('eth-json-rpc-errors') + +/** + * Create middleware for handling certain methods and preprocessing permissions requests. + */ +module.exports = function createMethodMiddleware ({ + store, storeKey, getAccounts, requestAccountsPermission, +}) { + return createAsyncMiddleware(async (req, res, next) => { + + if (typeof req.method !== 'string') { + res.error = ethErrors.rpc.invalidRequest({ data: req}) + return + } + + switch (req.method) { + + // intercepting eth_accounts requests for backwards compatibility, + // i.e. return an empty array instead of an error + case 'eth_accounts': + + res.result = await getAccounts() + return + + case 'eth_requestAccounts': + + // first, just try to get accounts + let accounts = await getAccounts() + if (accounts.length > 0) { + res.result = accounts + return + } + + // if no accounts, request the accounts permission + try { + await requestAccountsPermission() + } catch (err) { + res.error = err + return + } + + // get the accounts again + accounts = await getAccounts() + if (accounts.length > 0) { + res.result = accounts + } else { + // this should never happen + res.error = ethErrors.rpc.internal( + 'Accounts unexpectedly unavailable. Please report this bug.' + ) + } + + return + + // custom method for getting metadata from the requesting domain + case 'wallet_sendDomainMetadata': + + const storeState = store.getState()[storeKey] + const extensionId = storeState[req.origin] + ? storeState[req.origin].extensionId + : undefined + + if ( + req.domainMetadata && + typeof req.domainMetadata.name === 'string' + ) { + + store.updateState({ + [storeKey]: { + ...storeState, + [req.origin]: { + extensionId, + ...req.domainMetadata, + }, + }, + }) + } + + res.result = true + return + + default: + break + } + + next() + }) +} diff --git a/app/scripts/controllers/permissions/permissions-safe-methods.json b/app/scripts/controllers/permissions/permissions-safe-methods.json new file mode 100644 index 000000000000..17b46b531346 --- /dev/null +++ b/app/scripts/controllers/permissions/permissions-safe-methods.json @@ -0,0 +1,49 @@ +[ + "web3_sha3", + "net_listening", + "net_peerCount", + "net_version", + "eth_blockNumber", + "eth_call", + "eth_chainId", + "eth_coinbase", + "eth_estimateGas", + "eth_gasPrice", + "eth_getBalance", + "eth_getBlockByHash", + "eth_getBlockByNumber", + "eth_getBlockTransactionCountByHash", + "eth_getBlockTransactionCountByNumber", + "eth_getCode", + "eth_getFilterChanges", + "eth_getFilterLogs", + "eth_getLogs", + "eth_getStorageAt", + "eth_getTransactionByBlockHashAndIndex", + "eth_getTransactionByBlockNumberAndIndex", + "eth_getTransactionByHash", + "eth_getTransactionCount", + "eth_getTransactionReceipt", + "eth_getUncleByBlockHashAndIndex", + "eth_getUncleByBlockNumberAndIndex", + "eth_getUncleCountByBlockHash", + "eth_getUncleCountByBlockNumber", + "eth_getWork", + "eth_hashrate", + "eth_mining", + "eth_newBlockFilter", + "eth_newFilter", + "eth_newPendingTransactionFilter", + "eth_protocolVersion", + "eth_sendRawTransaction", + "eth_sendTransaction", + "eth_sign", + "personal_sign", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v3", + "eth_submitHashrate", + "eth_submitWork", + "eth_syncing", + "eth_uninstallFilter" +] \ No newline at end of file diff --git a/app/scripts/controllers/permissions/restrictedMethods.js b/app/scripts/controllers/permissions/restrictedMethods.js new file mode 100644 index 000000000000..cd87b2d57439 --- /dev/null +++ b/app/scripts/controllers/permissions/restrictedMethods.js @@ -0,0 +1,20 @@ + +module.exports = function getRestrictedMethods (permissionsController) { + return { + + 'eth_accounts': { + description: 'View the address of the selected account', + method: (_, res, __, end) => { + permissionsController.keyringController.getAccounts() + .then((accounts) => { + res.result = accounts + end() + }) + .catch((err) => { + res.error = err + end(err) + }) + }, + }, + } +} diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 22c6e999db19..409ce687667c 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,4 +1,5 @@ const ObservableStore = require('obs-store') +const { addInternalMethodPrefix } = require('./permissions') const normalizeAddress = require('eth-sig-util').normalize const { isValidAddress, sha3, bufferToHex } = require('ethereumjs-util') const extend = require('xtend') @@ -57,7 +58,6 @@ class PreferencesController { useNativeCurrencyAsPrimaryCurrency: true, }, completedOnboarding: false, - migratedPrivacyMode: false, metaMetricsId: null, metaMetricsSendCount: 0, }, opts.initState) @@ -187,7 +187,10 @@ class PreferencesController { * @param {Function} - end */ async requestWatchAsset (req, res, next, end) { - if (req.method === 'metamask_watchAsset' || req.method === 'wallet_watchAsset') { + if ( + req.method === 'metamask_watchAsset' || + req.method === addInternalMethodPrefix('watchAsset') + ) { const { type, options } = req.params switch (type) { case 'ERC20': @@ -644,13 +647,6 @@ class PreferencesController { return Promise.resolve(true) } - unsetMigratedPrivacyMode () { - this.store.updateState({ - migratedPrivacyMode: false, - }) - return Promise.resolve() - } - // // PRIVATE METHODS // diff --git a/app/scripts/controllers/provider-approval.js b/app/scripts/controllers/provider-approval.js deleted file mode 100644 index e54c7196f34a..000000000000 --- a/app/scripts/controllers/provider-approval.js +++ /dev/null @@ -1,177 +0,0 @@ -const ObservableStore = require('obs-store') -const SafeEventEmitter = require('safe-event-emitter') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') -const { errors: rpcErrors } = require('eth-json-rpc-errors') - -/** - * A controller that services user-approved requests for a full Ethereum provider API - */ -class ProviderApprovalController extends SafeEventEmitter { - /** - * Creates a ProviderApprovalController - * - * @param {Object} [config] - Options to configure controller - */ - constructor ({ closePopup, initState, keyringController, openPopup, preferencesController } = {}) { - super() - this.closePopup = closePopup - this.keyringController = keyringController - this.openPopup = openPopup - this.preferencesController = preferencesController - this.memStore = new ObservableStore({ - providerRequests: [], - }) - - const defaultState = { approvedOrigins: {} } - this.store = new ObservableStore(Object.assign(defaultState, initState)) - } - - /** - * Called when a user approves access to a full Ethereum provider API - * - * @param {object} opts - opts for the middleware contains the origin for the middleware - */ - createMiddleware ({ senderUrl, extensionId, getSiteMetadata }) { - return createAsyncMiddleware(async (req, res, next) => { - // only handle requestAccounts - if (req.method !== 'eth_requestAccounts') { - return next() - } - // if already approved or privacy mode disabled, return early - const isUnlocked = this.keyringController.memStore.getState().isUnlocked - const origin = senderUrl.hostname - if (this.shouldExposeAccounts(origin) && isUnlocked) { - res.result = [this.preferencesController.getSelectedAddress()] - return - } - // register the provider request - const metadata = { hostname: senderUrl.hostname, origin } - if (extensionId) { - metadata.extensionId = extensionId - } else { - const siteMetadata = await getSiteMetadata(origin) - Object.assign(metadata, { siteTitle: siteMetadata.name, siteImage: siteMetadata.icon}) - } - this._handleProviderRequest(metadata) - // wait for resolution of request - const approved = await new Promise(resolve => this.once(`resolvedRequest:${origin}`, ({ approved }) => resolve(approved))) - if (approved) { - res.result = [this.preferencesController.getSelectedAddress()] - } else { - throw rpcErrors.eth.userRejectedRequest('User denied account authorization') - } - }) - } - - /** - * @typedef {Object} SiteMetadata - * @param {string} hostname - The hostname of the site - * @param {string} origin - The origin of the site - * @param {string} [siteTitle] - The title of the site - * @param {string} [siteImage] - The icon for the site - * @param {string} [extensionId] - The extension ID of the extension - */ - /** - * Called when a tab requests access to a full Ethereum provider API - * - * @param {SiteMetadata} siteMetadata - The metadata for the site requesting full provider access - */ - _handleProviderRequest (siteMetadata) { - const { providerRequests } = this.memStore.getState() - const origin = siteMetadata.origin - this.memStore.updateState({ - providerRequests: [ - ...providerRequests, - siteMetadata, - ], - }) - const isUnlocked = this.keyringController.memStore.getState().isUnlocked - const { approvedOrigins } = this.store.getState() - const originAlreadyHandled = approvedOrigins[origin] - if (originAlreadyHandled && isUnlocked) { - return - } - this.openPopup && this.openPopup() - } - - /** - * Called when a user approves access to a full Ethereum provider API - * - * @param {string} origin - origin of the domain that had provider access approved - */ - approveProviderRequestByOrigin (origin) { - if (this.closePopup) { - this.closePopup() - } - - const { approvedOrigins } = this.store.getState() - const { providerRequests } = this.memStore.getState() - const providerRequest = providerRequests.find((request) => request.origin === origin) - const remainingProviderRequests = providerRequests.filter(request => request.origin !== origin) - this.store.updateState({ - approvedOrigins: { - ...approvedOrigins, - [origin]: { - siteTitle: providerRequest ? providerRequest.siteTitle : null, - siteImage: providerRequest ? providerRequest.siteImage : null, - hostname: providerRequest ? providerRequest.hostname : null, - }, - }, - }) - this.memStore.updateState({ providerRequests: remainingProviderRequests }) - this.emit(`resolvedRequest:${origin}`, { approved: true }) - } - - /** - * Called when a tab rejects access to a full Ethereum provider API - * - * @param {string} origin - origin of the domain that had provider access approved - */ - rejectProviderRequestByOrigin (origin) { - if (this.closePopup) { - this.closePopup() - } - - const { approvedOrigins } = this.store.getState() - const { providerRequests } = this.memStore.getState() - const remainingProviderRequests = providerRequests.filter(request => request.origin !== origin) - - // We're cloning and deleting keys here because we don't want to keep unneeded keys - const _approvedOrigins = Object.assign({}, approvedOrigins) - delete _approvedOrigins[origin] - - this.store.putState({ approvedOrigins: _approvedOrigins }) - this.memStore.putState({ providerRequests: remainingProviderRequests }) - this.emit(`resolvedRequest:${origin}`, { approved: false }) - } - - /** - * Clears any approvals for user-approved origins - */ - clearApprovedOrigins () { - this.store.updateState({ - approvedOrigins: {}, - }) - } - - /** - * Determines if a given origin should have accounts exposed - * - * @param {string} origin - Domain origin to check for approval status - * @returns {boolean} - True if the origin has been approved - */ - shouldExposeAccounts (origin) { - return Boolean(this.store.getState().approvedOrigins[origin]) - } - - /** - * Returns a merged state representation - * @return {object} - * @private - */ - _getMergedState () { - return Object.assign({}, this.memStore.getState(), this.store.getState()) - } -} - -module.exports = ProviderApprovalController diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 31f8cc103972..85733aa38247 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -3,7 +3,7 @@ const ObservableStore = require('obs-store') const ethUtil = require('ethereumjs-util') const Transaction = require('ethereumjs-tx') const EthQuery = require('ethjs-query') -const { errors: rpcErrors } = require('eth-json-rpc-errors') +const { ethErrors } = require('eth-json-rpc-errors') const abi = require('human-standard-token-abi') const abiDecoder = require('abi-decoder') abiDecoder.addABI(abi) @@ -54,6 +54,7 @@ const { hexToBn, bnToHex, BnMultiplyByFraction } = require('../../lib/util') @param {Object} opts.blockTracker - An instance of eth-blocktracker @param {Object} opts.provider - A network provider. @param {Function} opts.signTransaction - function the signs an ethereumjs-tx + @param {object} opts.getPermittedAccounts - get accounts that an origin has permissions for @param {Function} [opts.getGasPrice] - optional gas price calculator @param {Function} opts.signTransaction - ethTx signer that returns a rawTx @param {Number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state @@ -66,6 +67,7 @@ class TransactionController extends EventEmitter { this.networkStore = opts.networkStore || new ObservableStore({}) this.preferencesStore = opts.preferencesStore || new ObservableStore({}) this.provider = opts.provider + this.getPermittedAccounts = opts.getPermittedAccounts this.blockTracker = opts.blockTracker this.signEthTx = opts.signTransaction this.getGasPrice = opts.getGasPrice @@ -133,7 +135,7 @@ class TransactionController extends EventEmitter { /** Adds a tx to the txlist @emits ${txMeta.id}:unapproved -*/ + */ addTx (txMeta) { this.txStateManager.addTx(txMeta) this.emit(`${txMeta.id}:unapproved`, txMeta) @@ -148,18 +150,18 @@ class TransactionController extends EventEmitter { } /** - add a new unapproved transaction to the pipeline - - @returns {Promise} the hash of the transaction after being submitted to the network - @param txParams {object} - txParams for the transaction - @param opts {object} - with the key origin to put the origin on the txMeta + * Add a new unapproved transaction to the pipeline + * + * @returns {Promise} the hash of the transaction after being submitted to the network + * @param txParams {object} - txParams for the transaction + * @param opts {object} - with the key origin to put the origin on the txMeta */ - async newUnapprovedTransaction (txParams, opts = {}) { + log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) - const initialTxMeta = await this.addUnapprovedTransaction(txParams) - initialTxMeta.origin = opts.origin - this.txStateManager.updateTx(initialTxMeta, '#newUnapprovedTransaction - adding the 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) => { @@ -167,30 +169,27 @@ class TransactionController extends EventEmitter { case 'submitted': return resolve(finishedTxMeta.hash) case 'rejected': - return reject(cleanErrorStack(rpcErrors.eth.userRejectedRequest('MetaMask Tx Signature: User denied transaction signature.'))) + return reject(cleanErrorStack(ethErrors.provider.userRejectedRequest('MetaMask Tx Signature: User denied transaction signature.'))) case 'failed': - return reject(cleanErrorStack(rpcErrors.internal(finishedTxMeta.err.message))) + return reject(cleanErrorStack(ethErrors.rpc.internal(finishedTxMeta.err.message))) default: - return reject(cleanErrorStack(rpcErrors.internal(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))) + return reject(cleanErrorStack(ethErrors.rpc.internal(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))) } }) }) } /** - Validates and generates a txMeta with defaults and puts it in txStateManager - store - - @returns {txMeta} - */ + * Validates and generates a txMeta with defaults and puts it in txStateManager + * store. + * + * @returns {txMeta} + */ + async addUnapprovedTransaction (txParams, origin) { - async addUnapprovedTransaction (txParams) { // validate const normalizedTxParams = txUtils.normalizeTxParams(txParams) - // Assert the from address is the selected address - if (normalizedTxParams.from !== this.getSelectedAddress()) { - throw new Error(`Transaction from address isn't valid for this account`) - } + txUtils.validateTxParams(normalizedTxParams) /** `generateTxMeta` adds the default txMeta properties to the passed object. @@ -202,6 +201,30 @@ class TransactionController extends EventEmitter { txParams: normalizedTxParams, type: TRANSACTION_TYPE_STANDARD, }) + + if (origin === 'metamask') { + // Assert the from address is the selected address + if (normalizedTxParams.from !== this.getSelectedAddress()) { + throw ethErrors.rpc.internal({ + message: `Internally initiated transaction is using invalid account.`, + data: { + origin, + fromAddress: normalizedTxParams.from, + selectedAddress: this.getSelectedAddress(), + }, + }) + } + } else { + // Assert that the origin has permissions to initiate transactions from + // the specified address + const permittedAddresses = await this.getPermittedAccounts(origin) + if (!permittedAddresses.includes(normalizedTxParams.from)) { + throw ethErrors.provider.unauthorized({ data: { origin }}) + } + } + + txMeta['origin'] = origin + const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams) txMeta.transactionCategory = transactionCategory this.addTx(txMeta) @@ -222,15 +245,16 @@ class TransactionController extends EventEmitter { txMeta.loadingDefaults = false // save txMeta - this.txStateManager.updateTx(txMeta) + this.txStateManager.updateTx(txMeta, 'Added new unapproved transaction.') return txMeta } + /** - adds the tx gas defaults: gas && gasPrice - @param txMeta {Object} - the txMeta object - @returns {Promise} resolves with txMeta -*/ + * Adds the tx gas defaults: gas && gasPrice + * @param txMeta {Object} - the txMeta object + * @returns {Promise} resolves with txMeta + */ async addTxGasDefaults (txMeta, getCodeResponse) { const txParams = txMeta.txParams // ensure value @@ -416,6 +440,7 @@ class TransactionController extends EventEmitter { this.inProcessOfSigning.delete(txId) } } + /** adds the chain id and signs the transaction and set the status to signed @param txId {number} - the tx's Id diff --git a/app/scripts/createStandardProvider.js b/app/scripts/createStandardProvider.js deleted file mode 100644 index 2059b9b3a748..000000000000 --- a/app/scripts/createStandardProvider.js +++ /dev/null @@ -1,73 +0,0 @@ -class StandardProvider { - _isConnected - _provider - - constructor (provider) { - this._provider = provider - this._subscribe() - // indicate that we've connected, mostly just for standard compliance - setTimeout(() => { - this._onConnect() - }) - } - - _onClose () { - if (this._isConnected === undefined || this._isConnected) { - this._provider.emit('close', { - code: 1011, - reason: 'Network connection error', - }) - } - this._isConnected = false - } - - _onConnect () { - !this._isConnected && this._provider.emit('connect') - this._isConnected = true - } - - _subscribe () { - this._provider.on('data', (error, { method, params }) => { - if (!error && method === 'eth_subscription') { - this._provider.emit('notification', params.result) - } - }) - } - - /** - * Initiate an RPC method call - * - * @param {string} method - RPC method name to call - * @param {string[]} params - Array of RPC method parameters - * @returns {Promise<*>} Promise resolving to the result if successful - */ - send (method, params = []) { - return new Promise((resolve, reject) => { - try { - this._provider.sendAsync({ id: 1, jsonrpc: '2.0', method, params }, (error, response) => { - error = error || response.error - error ? reject(error) : resolve(response) - }) - } catch (error) { - reject(error) - } - }) - } -} - -/** - * Converts a legacy provider into an EIP-1193-compliant standard provider - * @param {Object} provider - Legacy provider to convert - * @returns {Object} Standard provider - */ -export default function createStandardProvider (provider) { - const standardProvider = new StandardProvider(provider) - const sendLegacy = provider.send - provider.send = (methodOrPayload, callbackOrArgs) => { - if (typeof methodOrPayload === 'string' && !callbackOrArgs || Array.isArray(callbackOrArgs)) { - return standardProvider.send(methodOrPayload, callbackOrArgs) - } - return sendLegacy.call(provider, methodOrPayload, callbackOrArgs) - } - return provider -} diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 0f752f1afb75..d81d8587b901 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -1,6 +1,5 @@ /*global Web3*/ - // need to make sure we aren't affected by overlapping namespaces // and that we dont affect the app with our namespace // mostly a fix for web3's BigNumber if AMD's "define" is defined... @@ -32,17 +31,14 @@ const restoreContextAfterImports = () => { } cleanContextForImports() -require('web3/dist/web3.min.js') + const log = require('loglevel') const LocalMessageDuplexStream = require('post-message-stream') -const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('metamask-inpage-provider') -const ObjectMultiplex = require('obj-multiplex') -const pump = require('pump') -const promisify = require('pify') -const createStandardProvider = require('./createStandardProvider').default -let warned = false +// TODO:deprecate:2020-01-13 +require('web3/dist/web3.min.js') +const setupDappAutoReload = require('./lib/auto-reload.js') restoreContextAfterImports() @@ -64,106 +60,6 @@ const inpageProvider = new MetamaskInpageProvider(metamaskStream) // set a high max listener count to avoid unnecesary warnings inpageProvider.setMaxListeners(100) -const pageMux = new ObjectMultiplex() -const onboardingStream = pageMux.createStream('onboarding') -pump( - pageMux, - metamaskStream, - error => log.error('MetaMask muxed in-page traffic failed', error) -) - -let warnedOfAutoRefreshDeprecation = false -// augment the provider with its enable method -inpageProvider.enable = function ({ force } = {}) { - if ( - !warnedOfAutoRefreshDeprecation && - inpageProvider.autoRefreshOnNetworkChange - ) { - console.warn(`MetaMask: MetaMask will soon stop reloading pages on network change. -If you rely upon this behavior, add a 'networkChanged' event handler to trigger the reload manually: https://metamask.github.io/metamask-docs/API_Reference/Ethereum_Provider#ethereum.on(eventname%2C-callback) -Set 'ethereum.autoRefreshOnNetworkChange' to 'false' to silence this warning: https://metamask.github.io/metamask-docs/API_Reference/Ethereum_Provider#ethereum.autorefreshonnetworkchange' -`) - warnedOfAutoRefreshDeprecation = true - } - return new Promise((resolve, reject) => { - inpageProvider.sendAsync({ method: 'eth_requestAccounts', params: [force] }, (error, response) => { - if (error || response.error) { - reject(error || response.error) - } else { - resolve(response.result) - } - }) - }) -} - -// give the dapps control of a refresh they can toggle this off on the window.ethereum -// this will be default true so it does not break any old apps. -inpageProvider.autoRefreshOnNetworkChange = true - - -// publicConfig isn't populated until we get a message from background. -// Using this getter will ensure the state is available -const getPublicConfigWhenReady = async () => { - const store = inpageProvider.publicConfigStore - let state = store.getState() - // if state is missing, wait for first update - if (!state.networkVersion) { - state = await new Promise(resolve => store.once('update', resolve)) - console.log('new state', state) - } - return state -} - -// add metamask-specific convenience methods -inpageProvider._metamask = new Proxy({ - /** - * Synchronously determines if this domain is currently enabled, with a potential false negative if called to soon - * - * @returns {boolean} - returns true if this domain is currently enabled - */ - isEnabled: function () { - const { isEnabled } = inpageProvider.publicConfigStore.getState() - return Boolean(isEnabled) - }, - - /** - * Asynchronously determines if this domain is currently enabled - * - * @returns {Promise} - Promise resolving to true if this domain is currently enabled - */ - isApproved: async function () { - const { isEnabled } = await getPublicConfigWhenReady() - return Boolean(isEnabled) - }, - - /** - * Determines if MetaMask is unlocked by the user - * - * @returns {Promise} - Promise resolving to true if MetaMask is currently unlocked - */ - isUnlocked: async function () { - const { isUnlocked } = await getPublicConfigWhenReady() - return Boolean(isUnlocked) - }, - - /** - * Registers a page as having initated onboarding. This facilitates MetaMask focusing the initiating tab after onboarding. - * - * @returns {Promise} - Promise resolving to undefined - */ - registerOnboarding: async () => { - await promisify(onboardingStream.write({ type: 'registerOnboarding' })) - }, -}, { - get: function (obj, prop) { - !warned && console.warn('Heads up! ethereum._metamask exposes methods that have ' + - 'not been standardized yet. This means that these methods may not be implemented ' + - 'in other dapp browsers and may be removed from MetaMask in the future.') - warned = true - return obj[prop] - }, -}) - // Work around for web3@1.0 deleting the bound `sendAsync` but not the unbound // `sendAsync` method on the prototype, causing `this` reference issues const proxiedInpageProvider = new Proxy(inpageProvider, { @@ -172,12 +68,12 @@ const proxiedInpageProvider = new Proxy(inpageProvider, { deleteProperty: () => true, }) -window.ethereum = createStandardProvider(proxiedInpageProvider) - // -// setup web3 +// TODO:deprecate:2020-01-13 // +// setup web3 + if (typeof window.web3 !== 'undefined') { throw new Error(`MetaMask detected another web3. MetaMask will not work reliably with another web3 extension. @@ -192,9 +88,13 @@ web3.setProvider = function () { } log.debug('MetaMask - injected web3') -setupDappAutoReload(web3, inpageProvider.publicConfigStore) +proxiedInpageProvider._web3Ref = web3.eth -// set web3 defaultAccount -inpageProvider.publicConfigStore.subscribe(function (state) { - web3.eth.defaultAccount = state.selectedAddress -}) +// setup dapp auto reload AND proxy web3 +setupDappAutoReload(web3, inpageProvider._publicConfigStore) + +// +// end deprecate:2020-01-13 +// + +window.ethereum = proxiedInpageProvider diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js index 343191f4c126..e2b9c17bd33b 100644 --- a/app/scripts/lib/auto-reload.js +++ b/app/scripts/lib/auto-reload.js @@ -1,3 +1,6 @@ + +// TODO:deprecate:2020-01-13 + module.exports = setupDappAutoReload function setupDappAutoReload (web3, observable) { @@ -13,7 +16,7 @@ function setupDappAutoReload (web3, observable) { lastTimeUsed = Date.now() // show warning once on web3 access if (!hasBeenWarned && key !== 'currentProvider') { - console.warn('MetaMask: web3 will be deprecated in the near future in favor of the ethereumProvider\nhttps://medium.com/metamask/4a899ad6e59e') + console.warn(`MetaMask: On 2020-01-13, MetaMask will no longer inject web3. For more information, see: https://medium.com/metamask/no-longer-injecting-web3-js-4a899ad6e59e`) hasBeenWarned = true } // return value normally diff --git a/app/scripts/lib/createOriginMiddleware.js b/app/scripts/lib/createOriginMiddleware.js index 98bb0e3b3996..4ff9a33862ae 100644 --- a/app/scripts/lib/createOriginMiddleware.js +++ b/app/scripts/lib/createOriginMiddleware.js @@ -1,3 +1,4 @@ + module.exports = createOriginMiddleware /** diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 49294c84dd64..b7212c980546 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -1,5 +1,6 @@ const extension = require('extensionizer') const log = require('loglevel') +const { checkForError } = require('./util') /** * A wrapper around the extension's storage local API @@ -90,21 +91,3 @@ module.exports = class ExtensionStore { function isEmpty (obj) { return Object.keys(obj).length === 0 } - -/** - * Returns an Error if extension.runtime.lastError is present - * this is a workaround for the non-standard error object thats used - * @returns {Error} - */ -function checkForError () { - const lastError = extension.runtime.lastError - if (!lastError) { - return - } - // if it quacks like an Error, its an Error - if (lastError.stack && lastError.message) { - return lastError - } - // repair incomplete error object (eg chromium v77) - return new Error(lastError.message) -} diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index c66b3a9e1afe..a947188e5325 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -1,7 +1,7 @@ const EventEmitter = require('events') const ObservableStore = require('obs-store') const ethUtil = require('ethereumjs-util') -const { errors: rpcErrors } = require('eth-json-rpc-errors') +const { ethErrors } = require('eth-json-rpc-errors') const createId = require('./random-id') /** @@ -85,7 +85,7 @@ module.exports = class MessageManager extends EventEmitter { case 'signed': return resolve(data.rawSig) case 'rejected': - return reject(rpcErrors.eth.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)}`)) } diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index c538ef17f023..fb30cc03ce9e 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -1,7 +1,7 @@ const EventEmitter = require('events') const ObservableStore = require('obs-store') const ethUtil = require('ethereumjs-util') -const { errors: rpcErrors } = require('eth-json-rpc-errors') +const { ethErrors } = require('eth-json-rpc-errors') const createId = require('./random-id') const hexRe = /^[0-9A-Fa-f]+$/g const log = require('loglevel') @@ -91,7 +91,7 @@ module.exports = class PersonalMessageManager extends EventEmitter { case 'signed': return resolve(data.rawSig) case 'rejected': - return reject(rpcErrors.eth.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)}`)) } diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index 7a73e7761378..5e3c480387d0 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -2,7 +2,7 @@ const EventEmitter = require('events') const ObservableStore = require('obs-store') const createId = require('./random-id') const assert = require('assert') -const { errors: rpcErrors } = require('eth-json-rpc-errors') +const { ethErrors } = require('eth-json-rpc-errors') const sigUtil = require('eth-sig-util') const log = require('loglevel') const jsonschema = require('jsonschema') @@ -81,7 +81,7 @@ module.exports = class TypedMessageManager extends EventEmitter { case 'signed': return resolve(data.rawSig) case 'rejected': - return reject(rpcErrors.eth.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}`)) default: diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js index 114203d7f8c8..36b836eb1107 100644 --- a/app/scripts/lib/util.js +++ b/app/scripts/lib/util.js @@ -1,3 +1,4 @@ +const extension = require('extensionizer') const ethUtil = require('ethereumjs-util') const assert = require('assert') const BN = require('bn.js') @@ -148,6 +149,32 @@ function getRandomArrayItem (array) { return array[Math.floor((Math.random() * array.length))] } +function mapObjectValues (object, cb) { + const mappedObject = {} + Object.keys(object).forEach(key => { + mappedObject[key] = cb(key, object[key]) + }) + return mappedObject +} + +/** + * Returns an Error if extension.runtime.lastError is present + * this is a workaround for the non-standard error object thats used + * @returns {Error} + */ +function checkForError () { + const lastError = extension.runtime.lastError + if (!lastError) { + return + } + // if it quacks like an Error, its an Error + if (lastError.stack && lastError.message) { + return lastError + } + // repair incomplete error object (eg chromium v77) + return new Error(lastError.message) +} + module.exports = { removeListeners, applyListeners, @@ -159,4 +186,6 @@ module.exports = { bnToHex, BnMultiplyByFraction, getRandomArrayItem, + mapObjectValues, + checkForError, } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 9b38451a4e4b..246ae511d36d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -8,11 +8,9 @@ const assert = require('assert').strict const EventEmitter = require('events') const pump = require('pump') const Dnode = require('dnode') -const pify = require('pify') const extension = require('extensionizer') const ObservableStore = require('obs-store') const ComposableObservableStore = require('./lib/ComposableObservableStore') -const createDnodeRemoteGetter = require('./lib/createDnodeRemoteGetter') const asStream = require('obs-store/lib/asStream') const AccountTracker = require('./lib/account-tracker') const RpcEngine = require('json-rpc-engine') @@ -20,8 +18,8 @@ const debounce = require('debounce') const createEngineStream = require('json-rpc-middleware-stream/engineStream') const createFilterMiddleware = require('eth-json-rpc-filters') const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager') -const createOriginMiddleware = require('./lib/createOriginMiddleware') const createLoggerMiddleware = require('./lib/createLoggerMiddleware') +const createOriginMiddleware = require('./lib/createOriginMiddleware') const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware') const {setupMultiplex} = require('./lib/stream-utils.js') const KeyringController = require('eth-keyring-controller') @@ -41,8 +39,8 @@ const TypedMessageManager = require('./lib/typed-message-manager') const TransactionController = require('./controllers/transactions') const TokenRatesController = require('./controllers/token-rates') const DetectTokensController = require('./controllers/detect-tokens') -const ProviderApprovalController = require('./controllers/provider-approval') const ABTestController = require('./controllers/ab-test') +const { PermissionsController } = require('./controllers/permissions/') const nodeify = require('./lib/nodeify') const accountImporter = require('./account-import-strategies') const getBuyEthUrl = require('./lib/buy-eth-url') @@ -58,6 +56,7 @@ const TrezorKeyring = require('eth-trezor-keyring') const LedgerBridgeKeyring = require('eth-ledger-bridge-keyring') const EthQuery = require('eth-query') const ethUtil = require('ethereumjs-util') +const nanoid = require('nanoid') const contractMap = require('eth-contract-metadata') const { AddressBookController, @@ -90,16 +89,24 @@ module.exports = class MetamaskController extends EventEmitter { // platform-specific api this.platform = opts.platform + this.getRequestAccountTabIds = opts.getRequestAccountTabIds + this.getOpenMetamaskTabsIds = opts.getOpenMetamaskTabsIds + // observable state store this.store = new ComposableObservableStore(initState) + // external connections by origin + // Do not modify directly. Use the associated methods. + this.connections = {} + // lock to ensure only one vault created at once this.createVaultMutex = new Mutex() - // network store + // next, we will initialize the controllers + // controller initializaiton order matters + this.networkController = new NetworkController(initState.NetworkController) - // preferences controller this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, @@ -107,17 +114,14 @@ module.exports = class MetamaskController extends EventEmitter { network: this.networkController, }) - // app-state controller this.appStateController = new AppStateController({ preferencesStore: this.preferencesController.store, onInactiveTimeout: () => this.setLocked(), initState: initState.AppStateController, }) - // currency controller this.currencyRateController = new CurrencyRateController(undefined, initState.CurrencyController) - // infura controller this.infuraController = new InfuraController({ initState: initState.InfuraController, }) @@ -125,7 +129,7 @@ module.exports = class MetamaskController extends EventEmitter { this.phishingController = new PhishingController() - // rpc provider + // now we can initialize the RPC provider, which other controllers require this.initializeProvider() this.provider = this.networkController.getProviderAndBlockTracker().provider this.blockTracker = this.networkController.getProviderAndBlockTracker().blockTracker @@ -154,7 +158,7 @@ module.exports = class MetamaskController extends EventEmitter { initState: initState.IncomingTransactionsController, }) - // account tracker watches balances, nonces, and any code at their address. + // account tracker watches balances, nonces, and any code at their address this.accountTracker = new AccountTracker({ provider: this.provider, blockTracker: this.blockTracker, @@ -188,7 +192,6 @@ module.exports = class MetamaskController extends EventEmitter { this.accountTracker._updateAccounts() }) - // key mgmt const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring] this.keyringController = new KeyringController({ keyringTypes: additionalKeyrings, @@ -196,16 +199,25 @@ module.exports = class MetamaskController extends EventEmitter { getNetwork: this.networkController.getNetworkState.bind(this.networkController), encryptor: opts.encryptor || undefined, }) - this.keyringController.memStore.subscribe((s) => this._onKeyringControllerUpdate(s)) - // detect tokens controller + this.permissionsController = new PermissionsController({ + keyringController: this.keyringController, + platform: opts.platform, + notifyDomain: this.notifyConnections.bind(this), + notifyAllDomains: this.notifyAllConnections.bind(this), + }, initState.PermissionsController, initState.PermissionsMetadata) + this.detectTokensController = new DetectTokensController({ preferences: this.preferencesController, network: this.networkController, keyringMemStore: this.keyringController.memStore, }) + this.abTestController = new ABTestController({ + initState: initState.ABTestController, + }) + this.addressBookController = new AddressBookController(undefined, initState.AddressBookController) this.threeBoxController = new ThreeBoxController({ @@ -217,9 +229,9 @@ module.exports = class MetamaskController extends EventEmitter { version, }) - // tx mgmt this.txController = new TransactionController({ initState: initState.TransactionController || initState.TransactionManager, + getPermittedAccounts: this.permissionsController.getAccounts.bind(this.permissionsController), networkStore: this.networkController.networkStore, preferencesStore: this.preferencesController.store, txHistoryLimit: 40, @@ -270,18 +282,6 @@ module.exports = class MetamaskController extends EventEmitter { this.isClientOpenAndUnlocked = memState.isUnlocked && this._isClientOpen }) - this.providerApprovalController = new ProviderApprovalController({ - closePopup: opts.closePopup, - initState: initState.ProviderApprovalController, - keyringController: this.keyringController, - openPopup: opts.openPopup, - preferencesController: this.preferencesController, - }) - - this.abTestController = new ABTestController({ - initState: initState.ABTestController, - }) - this.store.updateStructure({ AppStateController: this.appStateController.store, TransactionController: this.txController.store, @@ -294,10 +294,11 @@ module.exports = class MetamaskController extends EventEmitter { InfuraController: this.infuraController.store, CachedBalancesController: this.cachedBalancesController.store, OnboardingController: this.onboardingController.store, - ProviderApprovalController: this.providerApprovalController.store, IncomingTransactionsController: this.incomingTransactionsController.store, - ThreeBoxController: this.threeBoxController.store, ABTestController: this.abTestController.store, + PermissionsController: this.permissionsController.permissions, + PermissionsMetadata: this.permissionsController.store, + ThreeBoxController: this.threeBoxController.store, }) this.memStore = new ComposableObservableStore(null, { @@ -318,11 +319,9 @@ module.exports = class MetamaskController extends EventEmitter { ShapeshiftController: this.shapeshiftController, InfuraController: this.infuraController.store, OnboardingController: this.onboardingController.store, - // ProviderApprovalController - ProviderApprovalController: this.providerApprovalController.store, - ProviderApprovalControllerMemStore: this.providerApprovalController.memStore, IncomingTransactionsController: this.incomingTransactionsController.store, - // ThreeBoxController + PermissionsController: this.permissionsController.permissions, + PermissionsMetadata: this.permissionsController.store, ThreeBoxController: this.threeBoxController.store, ABTestController: this.abTestController.store, // ENS Controller @@ -343,20 +342,15 @@ module.exports = class MetamaskController extends EventEmitter { version, // account mgmt getAccounts: async ({ origin }) => { - // Expose no accounts if this origin has not been approved, preventing - // account-requring RPC methods from completing successfully - const exposeAccounts = this.providerApprovalController.shouldExposeAccounts(origin) - if (origin !== 'metamask' && !exposeAccounts) { - return [] - } - const isUnlocked = this.keyringController.memStore.getState().isUnlocked - const selectedAddress = this.preferencesController.getSelectedAddress() - // only show address if account is unlocked - if (isUnlocked && selectedAddress) { - return [selectedAddress] - } else { - return [] + if (origin === 'metamask') { + const selectedAddress = this.preferencesController.getSelectedAddress() + return selectedAddress ? [selectedAddress] : [] + } else if ( + this.keyringController.memStore.getState().isUnlocked + ) { + return await this.permissionsController.getAccounts(origin) } + return [] // changing this is a breaking change }, // tx signing processTransaction: this.newUnapprovedTransaction.bind(this), @@ -377,7 +371,7 @@ module.exports = 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 ({ checkIsEnabled }) { + createPublicConfigStore () { // subset of state for metamask inpage provider const publicConfigStore = new ObservableStore() @@ -390,23 +384,16 @@ module.exports = class MetamaskController extends EventEmitter { } function updatePublicConfigStore (memState) { - const publicState = selectPublicState(memState) - publicConfigStore.putState(publicState) + publicConfigStore.putState(selectPublicState(memState)) } - function selectPublicState ({ isUnlocked, selectedAddress, network, provider }) { - const isEnabled = checkIsEnabled() - const isReady = isUnlocked && isEnabled - const result = { + function selectPublicState ({ isUnlocked, network, provider }) { + return { isUnlocked, - isEnabled, - selectedAddress: isReady ? selectedAddress : null, networkVersion: network, chainId: selectChainId({ network, provider }), } - return result } - return publicConfigStore } @@ -438,13 +425,13 @@ module.exports = class MetamaskController extends EventEmitter { */ getApi () { const keyringController = this.keyringController - const preferencesController = this.preferencesController - const txController = this.txController const networkController = this.networkController - const providerApprovalController = this.providerApprovalController const onboardingController = this.onboardingController + const permissionsController = this.permissionsController + const preferencesController = this.preferencesController const threeBoxController = this.threeBoxController const abTestController = this.abTestController + const txController = this.txController return { // etc @@ -502,7 +489,6 @@ module.exports = class MetamaskController extends EventEmitter { setPreference: nodeify(preferencesController.setPreference, preferencesController), completeOnboarding: nodeify(preferencesController.completeOnboarding, preferencesController), addKnownMethodData: nodeify(preferencesController.addKnownMethodData, preferencesController), - unsetMigratedPrivacyMode: nodeify(preferencesController.unsetMigratedPrivacyMode, preferencesController), // BlacklistController whitelistPhishingDomain: this.whitelistPhishingDomain.bind(this), @@ -550,11 +536,6 @@ module.exports = class MetamaskController extends EventEmitter { signTypedMessage: nodeify(this.signTypedMessage, this), cancelTypedMessage: this.cancelTypedMessage.bind(this), - // provider approval - approveProviderRequestByOrigin: providerApprovalController.approveProviderRequestByOrigin.bind(providerApprovalController), - rejectProviderRequestByOrigin: providerApprovalController.rejectProviderRequestByOrigin.bind(providerApprovalController), - clearApprovedOrigins: providerApprovalController.clearApprovedOrigins.bind(providerApprovalController), - // onboarding controller setSeedPhraseBackedUp: nodeify(onboardingController.setSeedPhraseBackedUp, onboardingController), @@ -568,10 +549,21 @@ module.exports = class MetamaskController extends EventEmitter { // a/b test controller getAssignedABTestGroupName: nodeify(abTestController.getAssignedABTestGroupName, abTestController), + + // permissions + approvePermissionsRequest: nodeify(permissionsController.approvePermissionsRequest, permissionsController), + clearPermissions: permissionsController.clearPermissions.bind(permissionsController), + getApprovedAccounts: nodeify(permissionsController.getAccounts.bind(permissionsController)), + rejectPermissionsRequest: nodeify(permissionsController.rejectPermissionsRequest, permissionsController), + removePermissionsFor: permissionsController.removePermissionsFor.bind(permissionsController), + updateExposedAccounts: nodeify(permissionsController.updateExposedAccounts, permissionsController), + legacyExposeAccounts: nodeify(permissionsController.legacyExposeAccounts, permissionsController), + + getRequestAccountTabIds: (cb) => cb(null, this.getRequestAccountTabIds()), + getOpenMetamaskTabsIds: (cb) => cb(null, this.getOpenMetamaskTabsIds()), } } - //============================================================================= // VAULT / KEYRING RELATED METHODS //============================================================================= @@ -1351,10 +1343,10 @@ module.exports = class MetamaskController extends EventEmitter { // setup multiplexing const mux = setupMultiplex(connectionStream) - // connect features - const publicApi = this.setupPublicApi(mux.createStream('publicApi')) - this.setupProviderConnection(mux.createStream('provider'), senderUrl, extensionId, publicApi) - this.setupPublicConfig(mux.createStream('publicConfig'), senderUrl) + + // messages between inpage and background + this.setupProviderConnection(mux.createStream('provider'), senderUrl, extensionId) + this.setupPublicConfig(mux.createStream('publicConfig')) } /** @@ -1432,13 +1424,15 @@ module.exports = class MetamaskController extends EventEmitter { * resource is an extension. * @param {object} publicApi - The public API */ - setupProviderConnection (outStream, senderUrl, extensionId, publicApi) { - const getSiteMetadata = publicApi && publicApi.getSiteMetadata - const engine = this.setupProviderEngine(senderUrl, extensionId, getSiteMetadata) + setupProviderConnection (outStream, senderUrl, extensionId) { + const origin = senderUrl.hostname + const engine = this.setupProviderEngine(senderUrl, extensionId) // setup connection const providerStream = createEngineStream({ engine }) + const connectionId = this.addConnection(origin, { engine }) + pump( outStream, providerStream, @@ -1450,6 +1444,7 @@ module.exports = class MetamaskController extends EventEmitter { mid.destroy() } }) + connectionId && this.removeConnection(origin, connectionId) if (err) { log.error(err) } @@ -1460,7 +1455,8 @@ module.exports = class MetamaskController extends EventEmitter { /** * A method for creating a provider that is safely restricted for the requesting domain. **/ - setupProviderEngine (senderUrl, extensionId, getSiteMetadata) { + setupProviderEngine (senderUrl, extensionId) { + const origin = senderUrl.hostname // setup json rpc engine stack const engine = new RpcEngine() @@ -1474,20 +1470,17 @@ module.exports = class MetamaskController extends EventEmitter { const subscriptionManager = createSubscriptionManager({ provider, blockTracker }) subscriptionManager.events.on('notification', (message) => engine.emit('notification', message)) - // metadata + // append origin to each request engine.push(createOriginMiddleware({ origin })) + // logging engine.push(createLoggerMiddleware({ origin })) // filter and subscription polyfills engine.push(filterMiddleware) engine.push(subscriptionManager.middleware) + // permissions + engine.push(this.permissionsController.createMiddleware({ origin, extensionId })) // watch asset engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController)) - // requestAccounts - engine.push(this.providerApprovalController.createMiddleware({ - senderUrl, - extensionId, - getSiteMetadata, - })) // forward to metamask primary provider engine.push(providerAsMiddleware(provider)) return engine @@ -1502,13 +1495,9 @@ module.exports = class MetamaskController extends EventEmitter { * this is a good candidate for deprecation. * * @param {*} outStream - The stream to provide public config over. - * @param {URL} senderUrl - The URL of requesting resource */ - setupPublicConfig (outStream, senderUrl) { - const configStore = this.createPublicConfigStore({ - // check the providerApprovalController's approvedOrigins - checkIsEnabled: () => this.providerApprovalController.shouldExposeAccounts(senderUrl.hostname), - }) + setupPublicConfig (outStream) { + const configStore = this.createPublicConfigStore() const configStream = asStream(configStore) pump( @@ -1524,6 +1513,8 @@ module.exports = class MetamaskController extends EventEmitter { ) } + // manage external connections + onMessage (message, sender, sendResponse) { if (!message || !message.type) { log.debug(`Ignoring invalid message: '${JSON.stringify(message)}'`) @@ -1562,39 +1553,98 @@ module.exports = class MetamaskController extends EventEmitter { } /** - * A method for providing our public api over a stream. - * This includes a method for setting site metadata like title and image + * Adds a reference to a connection by origin. Ignores the 'metamask' origin. + * Caller must ensure that the returned id is stored such that the reference + * can be deleted later. * - * @param {*} outStream - The stream to provide the api over. + * @param {string} origin - The connection's origin string. + * @param {Object} options - Data associated with the connection + * @param {Object} options.engine - The connection's JSON Rpc Engine + * @returns {string} - The connection's id (so that it can be deleted later) */ - setupPublicApi (outStream) { - const dnode = Dnode() - // connect dnode api to remote connection - pump( - outStream, - dnode, - outStream, - (err) => { - // report any error - if (err) { - log.error(err) - } - } - ) + addConnection (origin, { engine }) { + + if (origin === 'metamask') { + return null + } - const getRemote = createDnodeRemoteGetter(dnode) + if (!this.connections[origin]) { + this.connections[origin] = {} + } - const publicApi = { - // wrap with an await remote - getSiteMetadata: async () => { - const remote = await getRemote() - return await pify(remote.getSiteMetadata)() - }, + const id = nanoid() + this.connections[origin][id] = { + engine, + } + + return id + } + + /** + * Deletes a reference to a connection, by origin and id. + * Ignores unknown origins. + * + * @param {string} origin - The connection's origin string. + * @param {string} id - The connection's id, as returned from addConnection. + */ + removeConnection (origin, id) { + + const connections = this.connections[origin] + if (!connections) { + return + } + + delete connections[id] + + if (Object.keys(connections.length === 0)) { + delete this.connections[origin] + } + } + + /** + * Causes the RPC engines associated with the connections to the given origin + * to emit a notification event with the given payload. + * Does nothing if the extension is locked or the origin is unknown. + * + * @param {string} origin - The connection's origin string. + * @param {any} payload - The event payload. + */ + notifyConnections (origin, payload) { + + const { isUnlocked } = this.getState() + const connections = this.connections[origin] + if (!isUnlocked || !connections) { + return } - return publicApi + Object.values(connections).forEach(conn => { + conn.engine && conn.engine.emit('notification', payload) + }) } + /** + * Causes the RPC engines associated with all connections to emit a + * notification event with the given payload. + * Does nothing if the extension is locked. + * + * @param {any} payload - The event payload. + */ + notifyAllConnections (payload) { + + const { isUnlocked } = this.getState() + if (!isUnlocked) { + return + } + + Object.values(this.connections).forEach(origin => { + Object.values(origin).forEach(conn => { + conn.engine && conn.engine.emit('notification', payload) + }) + }) + } + + // handlers + /** * Handle a KeyringController update * @param {object} state the KC state @@ -1623,6 +1673,8 @@ module.exports = class MetamaskController extends EventEmitter { } } + // misc + /** * A method for emitting the full MetaMask state to all registered listeners. * @private @@ -1631,6 +1683,10 @@ module.exports = class MetamaskController extends EventEmitter { this.emit('update', this.getState()) } + //============================================================================= + // MISCELLANEOUS + //============================================================================= + /** * A method for estimating a good gas price at recent prices. * Returns the lowest price that would have been included in diff --git a/app/scripts/migrations/029.js b/app/scripts/migrations/029.js index e17479ccc21a..59724c1545f7 100644 --- a/app/scripts/migrations/029.js +++ b/app/scripts/migrations/029.js @@ -24,4 +24,3 @@ module.exports = { return isApproved && now - createdTime > unacceptableDelay }), } - diff --git a/app/scripts/migrations/040.js b/app/scripts/migrations/040.js new file mode 100644 index 000000000000..042f499b2cd0 --- /dev/null +++ b/app/scripts/migrations/040.js @@ -0,0 +1,23 @@ +const version = 40 +const clone = require('clone') + +/** + * Site connections are now managed by the PermissionsController, and the + * ProviderApprovalController is removed. This migration deletes all + * ProviderApprovalController state. + */ +module.exports = { + version, + migrate: async function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + const state = versionedData.data + versionedData.data = transformState(state) + return versionedData + }, +} + +function transformState (state) { + delete state.ProviderApprovalController + return state +} diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index d54a8a7b323a..5ae05d23040b 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -1,7 +1,7 @@ const extension = require('extensionizer') const {createExplorerLink: explorerLink} = require('etherscan-link') -const {getEnvironmentType} = require('../lib/util') +const { getEnvironmentType, checkForError } = require('../lib/util') const {ENVIRONMENT_TYPE_BACKGROUND} = require('../lib/enums') class ExtensionPlatform { @@ -66,6 +66,58 @@ class ExtensionPlatform { } } + queryTabs () { + return new Promise((resolve, reject) => { + extension.tabs.query({}, tabs => { + const err = checkForError() + if (err) { + reject(err) + } else { + resolve(tabs) + } + }) + }) + } + + currentTab () { + return new Promise((resolve, reject) => { + extension.tabs.getCurrent(tab => { + const err = checkForError() + if (err) { + reject(err) + } else { + resolve(tab) + } + }) + }) + } + + switchToTab (tabId) { + return new Promise((resolve, reject) => { + extension.tabs.update(tabId, {highlighted: true}, (tab) => { + const err = checkForError() + if (err) { + reject(err) + } else { + resolve(tab) + } + }) + }) + } + + closeTab (tabId) { + return new Promise((resolve, reject) => { + extension.tabs.remove(tabId, () => { + const err = checkForError() + if (err) { + reject(err) + } else { + resolve() + } + }) + }) + } + _showConfirmedTransaction (txMeta) { this._subscribeToNotificationClicked() diff --git a/docs/porting_to_new_environment.md b/docs/porting_to_new_environment.md index 9cb8e9c2dc64..92f06f37db63 100644 --- a/docs/porting_to_new_environment.md +++ b/docs/porting_to_new_environment.md @@ -18,8 +18,8 @@ const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine') /** * returns a provider restricted to the requesting domain **/ -function incomingConnection (domain, getSiteMetadata) { - const engine = metamaskController.setupProviderEngine(domain, getSiteMetadata) +function incomingConnection (domain) { + const engine = metamaskController.setupProviderEngine(domain) const provider = providerFromEngine(engine) return provider } @@ -32,15 +32,6 @@ const filterMiddleware = engine._middleware.filter(mid => mid.name === 'filterMi filterMiddleware.destroy() ``` -### getSiteMetadata() - -This method is used to enhance our confirmation screens with images and text representing the requesting domain. - -It should return a promise that resolves with an object with the following properties: - -- `name`: The requesting site's name. -- `icon`: A URI representing the site's logo. - ### Using the Streams Interface Only use this if you intend to construct the [metamask-inpage-provider](https://github.com/MetaMask/metamask-inpage-provider) over a stream! diff --git a/package.json b/package.json index f7df8b7e57eb..48683a14e07b 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "eth-block-tracker": "^4.4.2", "eth-contract-metadata": "^1.11.0", "eth-ens-namehash": "^2.0.8", - "eth-json-rpc-errors": "^1.1.0", + "eth-json-rpc-errors": "^2.0.0", "eth-json-rpc-filters": "^4.1.1", "eth-json-rpc-infura": "^4.0.1", "eth-json-rpc-middleware": "^4.2.0", @@ -116,6 +116,7 @@ "ethjs-query": "^0.3.4", "extension-port-stream": "^1.0.0", "extensionizer": "^1.0.1", + "fast-deep-equal": "^2.0.1", "fast-json-patch": "^2.0.4", "fuse.js": "^3.2.0", "gaba": "^1.9.0", @@ -128,10 +129,11 @@ "lodash.shuffle": "^4.2.0", "loglevel": "^1.4.1", "luxon": "^1.8.2", - "metamask-inpage-provider": "^3.0.0", + "metamask-inpage-provider": "^4.0.2", "metamask-logo": "^2.1.4", "mkdirp": "^0.5.1", "multihashes": "^0.4.12", + "nanoid": "^2.1.6", "nonce-tracker": "^1.0.0", "number-to-bn": "^1.7.0", "obj-multiplex": "^1.0.0", @@ -173,7 +175,9 @@ "redux-thunk": "^2.2.0", "request-promise": "^4.2.1", "reselect": "^3.0.1", + "rpc-cap": "^1.0.1", "safe-event-emitter": "^1.0.1", + "safe-json-stringify": "^1.2.0", "single-call-balance-checker-abi": "^1.0.0", "string.prototype.matchall": "^3.0.1", "swappable-obj-proxy": "^1.1.0", diff --git a/test/e2e/contract-test/contract.js b/test/e2e/contract-test/contract.js index a6b5f110bf01..6c3941b9deef 100644 --- a/test/e2e/contract-test/contract.js +++ b/test/e2e/contract-test/contract.js @@ -49,6 +49,8 @@ const initialize = () => { const approveTokensWithoutGas = document.getElementById('approveTokensWithoutGas') const signTypedData = document.getElementById('signTypedData') const signTypedDataResults = document.getElementById('signTypedDataResult') + const getAccountsButton = document.getElementById('getAccounts') + const getAccountsResults = document.getElementById('getAccountsResult') const contractStatus = document.getElementById('contractStatus') const tokenAddress = document.getElementById('tokenAddress') @@ -317,6 +319,16 @@ const initialize = () => { }) }) + getAccountsButton.addEventListener('click', async () => { + try { + const accounts = await ethereum.send({ method: 'eth_accounts' }) + getAccountsResults.innerHTML = accounts[0] || 'Not able to get accounts' + } catch (error) { + console.error(error) + getAccountsResults.innerHTML = `Error: ${error}` + } + }) + } updateButtons() diff --git a/test/e2e/contract-test/index.html b/test/e2e/contract-test/index.html index 9454a67dd28d..7655b87866f9 100644 --- a/test/e2e/contract-test/index.html +++ b/test/e2e/contract-test/index.html @@ -42,6 +42,11 @@

    Send Tokens

    +
    +

    Get Accounts

    + +
    +

    Status

    diff --git a/test/e2e/ethereum-on.spec.js b/test/e2e/ethereum-on.spec.js index ca062ca26a8b..c50615521dc3 100644 --- a/test/e2e/ethereum-on.spec.js +++ b/test/e2e/ethereum-on.spec.js @@ -113,7 +113,8 @@ describe('MetaMask', function () { let extension let popup let dapp - it('switches to a dapp', async () => { + + it('connects to the dapp', async () => { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) @@ -126,19 +127,27 @@ describe('MetaMask', function () { const windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) - dapp = windowHandles.find(handle => handle !== extension && handle !== popup) + dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + popup = windowHandles.find(handle => handle !== extension && handle !== dapp) + + await driver.switchTo().window(popup) await delay(regularDelayMs) - const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) - await approveButton.click() + const accountButton = await findElement(driver, By.css('.permissions-connect-choose-account__account')) + await accountButton.click() + + const submitButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Submit')]`)) + await submitButton.click() + + await waitUntilXWindowHandles(driver, 2) await driver.switchTo().window(dapp) await delay(regularDelayMs) }) it('has the ganache network id within the dapp', async () => { const networkDiv = await findElement(driver, By.css('#network')) + await delay(regularDelayMs) assert.equal(await networkDiv.getText(), '5777') }) diff --git a/test/e2e/metamask-responsive-ui.spec.js b/test/e2e/metamask-responsive-ui.spec.js index 90cf35710805..143e759ee822 100644 --- a/test/e2e/metamask-responsive-ui.spec.js +++ b/test/e2e/metamask-responsive-ui.spec.js @@ -134,7 +134,7 @@ describe('MetaMask', function () { it('show account details dropdown menu', async () => { await driver.findElement(By.css('div.menu-bar__open-in-browser')).click() const options = await driver.findElements(By.css('div.menu.account-details-dropdown div.menu__item')) - assert.equal(options.length, 3) // HD Wallet type does not have to show the Remove Account option + assert.equal(options.length, 4) // HD Wallet type does not have to show the Remove Account option await delay(regularDelayMs) }) }) diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index b5a8220b0a29..a22c0c1ca121 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -432,7 +432,7 @@ describe('MetaMask', function () { await delay(largeDelayMs) }) - it('starts a send transaction inside the dapp', async () => { + it('connects the dapp', async () => { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) @@ -445,15 +445,22 @@ describe('MetaMask', function () { windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) - dapp = windowHandles.find(handle => handle !== extension && handle !== popup) + dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + popup = windowHandles.find(handle => handle !== extension && handle !== dapp) + + await driver.switchTo().window(popup) await delay(regularDelayMs) - const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) - await approveButton.click() + const accountButton = await findElement(driver, By.css('.permissions-connect-choose-account__account')) + await accountButton.click() + + const submitButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Submit')]`)) + await submitButton.click() + + await waitUntilXWindowHandles(driver, 2) await driver.switchTo().window(dapp) - await delay(2000) + await delay(regularDelayMs) }) it('initiates a send from the dapp', async () => { diff --git a/test/e2e/permissions.spec.js b/test/e2e/permissions.spec.js new file mode 100644 index 000000000000..b7147d7a2701 --- /dev/null +++ b/test/e2e/permissions.spec.js @@ -0,0 +1,201 @@ +const assert = require('assert') +const webdriver = require('selenium-webdriver') +const { By, until } = webdriver +const { + delay, +} = require('./func') +const { + checkBrowserForConsoleErrors, + findElement, + findElements, + openNewPage, + verboseReportOnFailure, + waitUntilXWindowHandles, + switchToWindowWithTitle, + setupFetchMocking, + prepareExtensionForTesting, +} = require('./helpers') +const enLocaleMessages = require('../../app/_locales/en/messages.json') + +describe('MetaMask', function () { + let driver + let publicAddress + + const tinyDelayMs = 200 + const regularDelayMs = tinyDelayMs * 2 + const largeDelayMs = regularDelayMs * 2 + + this.timeout(0) + this.bail(true) + + before(async function () { + const result = await prepareExtensionForTesting() + driver = result.driver + await setupFetchMocking(driver) + }) + + afterEach(async function () { + if (process.env.SELENIUM_BROWSER === 'chrome') { + const errors = await checkBrowserForConsoleErrors(driver) + if (errors.length) { + const errorReports = errors.map(err => err.message) + const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + console.error(new Error(errorMessage)) + } + } + if (this.currentTest.state === 'failed') { + await verboseReportOnFailure(driver, this.currentTest) + } + }) + + after(async function () { + await driver.quit() + }) + + describe('Going through the first time flow, but skipping the seed phrase challenge', () => { + it('clicks the continue button on the welcome screen', async () => { + await findElement(driver, By.css('.welcome-page__header')) + const welcomeScreenBtn = await findElement(driver, By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) + welcomeScreenBtn.click() + await delay(largeDelayMs) + }) + + it('clicks the "Create New Wallet" option', async () => { + const customRpcButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Create a Wallet')]`)) + customRpcButton.click() + await delay(largeDelayMs) + }) + + it('clicks the "No thanks" option on the metametrics opt-in screen', async () => { + const optOutButton = await findElement(driver, By.css('.btn-default')) + optOutButton.click() + await delay(largeDelayMs) + }) + + it('accepts a secure password', async () => { + const passwordBox = await findElement(driver, By.css('.first-time-flow__form #create-password')) + const passwordBoxConfirm = await findElement(driver, By.css('.first-time-flow__form #confirm-password')) + const button = await findElement(driver, By.css('.first-time-flow__form button')) + + await passwordBox.sendKeys('correct horse battery staple') + await passwordBoxConfirm.sendKeys('correct horse battery staple') + + const tosCheckBox = await findElement(driver, By.css('.first-time-flow__checkbox')) + await tosCheckBox.click() + + await button.click() + await delay(largeDelayMs) + }) + + it('skips the seed phrase challenge', async () => { + const button = await findElement(driver, By.xpath(`//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`)) + await button.click() + await delay(regularDelayMs) + + const detailsButton = await findElement(driver, By.css('.account-details__details-button')) + await detailsButton.click() + await delay(regularDelayMs) + }) + + it('gets the current accounts address', async () => { + const addressInput = await findElement(driver, By.css('.qr-ellip-address')) + publicAddress = await addressInput.getAttribute('value') + const accountModal = await driver.findElement(By.css('span .modal')) + + await driver.executeScript("document.querySelector('.account-modal-close').click()") + + await driver.wait(until.stalenessOf(accountModal)) + await delay(regularDelayMs) + }) + }) + + describe('sets permissions', () => { + let extension + let popup + let dapp + + it('connects to the dapp', async () => { + await openNewPage(driver, 'http://127.0.0.1:8080/') + await delay(regularDelayMs) + + const connectButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await connectButton.click() + + await waitUntilXWindowHandles(driver, 3) + const windowHandles = await driver.getAllWindowHandles() + + extension = windowHandles[0] + dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + popup = windowHandles.find(handle => handle !== extension && handle !== dapp) + + await driver.switchTo().window(popup) + + await delay(regularDelayMs) + + const accountButton = await findElement(driver, By.css('.permissions-connect-choose-account__account')) + await accountButton.click() + + const submitButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Submit')]`)) + await submitButton.click() + + await waitUntilXWindowHandles(driver, 2) + await driver.switchTo().window(extension) + await delay(regularDelayMs) + }) + + it('shows connected sites', async () => { + const connectedSites = await findElement(driver, By.xpath(`//button[contains(text(), 'Connected Sites')]`)) + await connectedSites.click() + + await findElement(driver, By.css('.connected-sites__title')) + + const domains = await findElements(driver, By.css('.connected-sites-list__domain')) + assert.equal(domains.length, 1) + + const domainName = await findElement(driver, By.css('.connected-sites-list__domain-name')) + assert.equal(await domainName.getText(), 'E2E Test Dapp') + + await domains[0].click() + + const permissionDescription = await findElement(driver, By.css('.connected-sites-list__permission-description')) + assert.equal(await permissionDescription.getText(), 'View the address of the selected account') + }) + + it('can get accounts within the dapp', async () => { + await driver.switchTo().window(dapp) + await delay(regularDelayMs) + + const getAccountsButton = await findElement(driver, By.xpath(`//button[contains(text(), 'eth_accounts')]`)) + await getAccountsButton.click() + + const getAccountsResult = await findElement(driver, By.css('#getAccountsResult')) + assert.equal((await getAccountsResult.getText()).toLowerCase(), publicAddress.toLowerCase()) + }) + + it('can disconnect all accounts', async () => { + await driver.switchTo().window(extension) + + const disconnectAllButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Disconnect All')]`)) + await disconnectAllButton.click() + + const disconnectModal = await driver.findElement(By.css('span .modal')) + + const disconnectAllModalButton = await findElement(driver, By.css('.disconnect-all-modal .btn-danger')) + await disconnectAllModalButton.click() + + await driver.wait(until.stalenessOf(disconnectModal)) + await delay(regularDelayMs) + }) + + it('can no longer get accounts within the dapp', async () => { + await driver.switchTo().window(dapp) + await delay(regularDelayMs) + + const getAccountsButton = await findElement(driver, By.xpath(`//button[contains(text(), 'eth_accounts')]`)) + await getAccountsButton.click() + + const getAccountsResult = await findElement(driver, By.css('#getAccountsResult')) + assert.equal(await getAccountsResult.getText(), 'Not able to get accounts') + }) + }) +}) diff --git a/test/e2e/run-all.sh b/test/e2e/run-all.sh index 33c2428dab08..55a06fc88846 100755 --- a/test/e2e/run-all.sh +++ b/test/e2e/run-all.sh @@ -60,6 +60,14 @@ concurrently --kill-others \ 'yarn dapp' \ 'sleep 5 && mocha test/e2e/ethereum-on.spec' +concurrently --kill-others \ + --names 'ganache,dapp,e2e' \ + --prefix '[{time}][{name}]' \ + --success first \ + 'yarn ganache:start' \ + 'yarn dapp' \ + 'sleep 5 && mocha test/e2e/permissions.spec' + export GANACHE_ARGS="${BASE_GANACHE_ARGS} --deterministic --account=0x250F458997A364988956409A164BA4E16F0F99F916ACDD73ADCD3A1DE30CF8D1,0 --account=0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9,25000000000000000000" concurrently --kill-others \ --names 'ganache,sendwithprivatedapp,e2e' \ diff --git a/test/e2e/signature-request.spec.js b/test/e2e/signature-request.spec.js index a5be61baf077..f36b6ac5131f 100644 --- a/test/e2e/signature-request.spec.js +++ b/test/e2e/signature-request.spec.js @@ -119,12 +119,13 @@ describe('MetaMask', function () { }) }) - describe('provider listening for events', () => { + describe('successfuly signs typed data', () => { let extension let popup let dapp let windowHandles - it('switches to a dapp', async () => { + + it('connects to the dapp', async () => { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) @@ -134,18 +135,24 @@ describe('MetaMask', function () { await delay(regularDelayMs) await waitUntilXWindowHandles(driver, 3) - windowHandles = await driver.getAllWindowHandles() + const windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] - popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) - dapp = windowHandles.find(handle => handle !== extension && handle !== popup) + dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + popup = windowHandles.find(handle => handle !== extension && handle !== dapp) + + await driver.switchTo().window(popup) await delay(regularDelayMs) - const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) - await approveButton.click() + const accountButton = await findElement(driver, By.css('.permissions-connect-choose-account__account')) + await accountButton.click() + + const submitButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Submit')]`)) + await submitButton.click() + + await waitUntilXWindowHandles(driver, 2) await driver.switchTo().window(dapp) - await delay(regularDelayMs) }) it('creates a sign typed data signature request', async () => { @@ -153,6 +160,7 @@ describe('MetaMask', function () { await signTypedMessage.click() await delay(largeDelayMs) + await delay(regularDelayMs) windowHandles = await driver.getAllWindowHandles() await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) await delay(regularDelayMs) diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index f49e518c3f98..7aea39a36959 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -1,6 +1,7 @@ const assert = require('assert') const ObservableStore = require('obs-store') const PreferencesController = require('../../../../app/scripts/controllers/preferences') +const { addInternalMethodPrefix } = require('../../../../app/scripts/controllers/permissions') const sinon = require('sinon') describe('preferences controller', function () { @@ -375,7 +376,7 @@ describe('preferences controller', function () { await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) sandbox.assert.called(stubEnd) sandbox.assert.notCalled(stubNext) - req.method = 'wallet_watchAsset' + req.method = addInternalMethodPrefix('watchAsset') req.params.type = 'someasset' await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) sandbox.assert.calledTwice(stubEnd) diff --git a/test/unit/app/controllers/provider-approval-test.js b/test/unit/app/controllers/provider-approval-test.js deleted file mode 100644 index eeb9e813b26b..000000000000 --- a/test/unit/app/controllers/provider-approval-test.js +++ /dev/null @@ -1,330 +0,0 @@ -const assert = require('assert') -const sinon = require('sinon') -const ProviderApprovalController = require('../../../../app/scripts/controllers/provider-approval') - -const mockLockedKeyringController = { - memStore: { - getState: () => ({ - isUnlocked: false, - }), - }, -} - -const mockUnlockedKeyringController = { - memStore: { - getState: () => ({ - isUnlocked: true, - }), - }, -} - -describe('ProviderApprovalController', () => { - describe('#_handleProviderRequest', () => { - it('should add a pending provider request when unlocked', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - - controller._handleProviderRequest(metadata) - assert.deepEqual(controller._getMergedState(), { - approvedOrigins: {}, - providerRequests: [metadata], - }) - }) - - it('should add a pending provider request when locked', () => { - const controller = new ProviderApprovalController({ - keyringController: mockLockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - assert.deepEqual(controller._getMergedState(), { - approvedOrigins: {}, - providerRequests: [metadata], - }) - }) - - it('should add a 2nd pending provider request when unlocked', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = [{ - hostname: 'https://example1.com', - origin: 'example1.com', - siteTitle: 'Example 1', - siteImage: 'https://example1.com/logo.svg', - }, { - hostname: 'https://example2.com', - origin: 'example2.com', - siteTitle: 'Example 2', - siteImage: 'https://example2.com/logo.svg', - }] - - controller._handleProviderRequest(metadata[0]) - controller._handleProviderRequest(metadata[1]) - assert.deepEqual(controller._getMergedState(), { - approvedOrigins: {}, - providerRequests: metadata, - }) - }) - - it('should add a 2nd pending provider request when locked', () => { - const controller = new ProviderApprovalController({ - keyringController: mockLockedKeyringController, - }) - - const metadata = [{ - hostname: 'https://example1.com', - origin: 'example1.com', - siteTitle: 'Example 1', - siteImage: 'https://example1.com/logo.svg', - }, { - hostname: 'https://example2.com', - origin: 'example2.com', - siteTitle: 'Example 2', - siteImage: 'https://example2.com/logo.svg', - }] - - controller._handleProviderRequest(metadata[0]) - controller._handleProviderRequest(metadata[1]) - assert.deepEqual(controller._getMergedState(), { - approvedOrigins: {}, - providerRequests: metadata, - }) - }) - - it('should call openPopup when unlocked and when given', () => { - const openPopup = sinon.spy() - const controller = new ProviderApprovalController({ - openPopup, - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - assert.ok(openPopup.calledOnce) - }) - - it('should call openPopup when locked and when given', () => { - const openPopup = sinon.spy() - const controller = new ProviderApprovalController({ - openPopup, - keyringController: mockLockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - assert.ok(openPopup.calledOnce) - }) - - it('should NOT call openPopup when unlocked and when the domain has already been approved', () => { - const openPopup = sinon.spy() - const controller = new ProviderApprovalController({ - openPopup, - keyringController: mockUnlockedKeyringController, - }) - - controller.store.updateState({ - approvedOrigins: { - 'example.com': { - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - }, - }, - }) - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - assert.ok(openPopup.notCalled) - }) - }) - - describe('#approveProviderRequestByOrigin', () => { - it('should mark the origin as approved and remove the provider request', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - controller.approveProviderRequestByOrigin('example.com') - assert.deepEqual(controller._getMergedState(), { - providerRequests: [], - approvedOrigins: { - 'example.com': { - hostname: 'https://example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - }, - }, - }) - }) - - it('should mark the origin as approved and multiple requests for the same domain', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - controller._handleProviderRequest(metadata) - controller.approveProviderRequestByOrigin('example.com') - assert.deepEqual(controller._getMergedState(), { - providerRequests: [], - approvedOrigins: { - 'example.com': { - hostname: 'https://example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - }, - }, - }) - }) - - it('should mark the origin as approved without a provider request', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - controller.approveProviderRequestByOrigin('example.com') - assert.deepEqual(controller._getMergedState(), { - providerRequests: [], - approvedOrigins: { - 'example.com': { - hostname: null, - siteTitle: null, - siteImage: null, - }, - }, - }) - }) - }) - - describe('#rejectProviderRequestByOrigin', () => { - it('should remove the origin from approved', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - controller.approveProviderRequestByOrigin('example.com') - controller.rejectProviderRequestByOrigin('example.com') - assert.deepEqual(controller._getMergedState(), { - providerRequests: [], - approvedOrigins: {}, - }) - }) - - it('should reject the origin even without a pending request', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - controller.rejectProviderRequestByOrigin('example.com') - assert.deepEqual(controller._getMergedState(), { - providerRequests: [], - approvedOrigins: {}, - }) - }) - }) - - describe('#clearApprovedOrigins', () => { - it('should clear the approved origins', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - controller.approveProviderRequestByOrigin('example.com') - controller.clearApprovedOrigins() - assert.deepEqual(controller._getMergedState(), { - providerRequests: [], - approvedOrigins: {}, - }) - }) - }) - - describe('#shouldExposeAccounts', () => { - it('should return true for an approved origin', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - controller.approveProviderRequestByOrigin('example.com') - assert.ok(controller.shouldExposeAccounts('example.com')) - }) - - it('should return false for an origin not yet approved', () => { - const controller = new ProviderApprovalController({ - keyringController: mockUnlockedKeyringController, - }) - - const metadata = { - hostname: 'https://example.com', - origin: 'example.com', - siteTitle: 'Example', - siteImage: 'https://example.com/logo.svg', - } - controller._handleProviderRequest(metadata) - controller.approveProviderRequestByOrigin('example.com') - assert.ok(!controller.shouldExposeAccounts('bad.website')) - }) - }) -}) diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index d0a989e71e16..d398c7e04f0c 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -48,6 +48,7 @@ describe('Transaction Controller', function () { ethTx.sign(fromAccount.key) resolve() }), + getPermittedAccounts: () => {}, }) txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop }) }) @@ -176,13 +177,15 @@ describe('Transaction Controller', function () { describe('#addUnapprovedTransaction', function () { const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d' - let getSelectedAddress + let getSelectedAddress, getPermittedAccounts beforeEach(function () { getSelectedAddress = sinon.stub(txController, 'getSelectedAddress').returns(selectedAddress) + getPermittedAccounts = sinon.stub(txController, 'getPermittedAccounts').returns([selectedAddress]) }) afterEach(function () { getSelectedAddress.restore() + getPermittedAccounts.restore() }) it('should add an unapproved transaction and return a valid txMeta', function (done) { diff --git a/ui/app/components/app/account-details/account-details.component.js b/ui/app/components/app/account-details/account-details.component.js index 55078cee0df0..e75e777a6d92 100644 --- a/ui/app/components/app/account-details/account-details.component.js +++ b/ui/app/components/app/account-details/account-details.component.js @@ -19,9 +19,11 @@ export default class AccountDetails extends Component { static propTypes = { hideSidebar: PropTypes.func, showAccountDetailModal: PropTypes.func, + showConnectedSites: PropTypes.func.isRequired, label: PropTypes.string.isRequired, checksummedAddress: PropTypes.string.isRequired, name: PropTypes.string.isRequired, + history: PropTypes.object.isRequired, } state = { @@ -48,6 +50,7 @@ export default class AccountDetails extends Component { const { hideSidebar, showAccountDetailModal, + showConnectedSites, label, checksummedAddress, name, @@ -65,14 +68,19 @@ export default class AccountDetails extends Component {
    {label}
    -
    - +
    + {name} - +
    + + +
    list.concat(keyring.accounts), []) @@ -71,6 +76,8 @@ export default class AccountMenu extends PureComponent { const keyring = keyrings.find(kr => { return kr.accounts.includes(simpleAddress) || kr.accounts.includes(identity.address) }) + const addressDomains = addressConnectedDomainMap[identity.address] || {} + const iconAndNameForOpenDomain = addressDomains[originOfCurrentTab] return (
    + { iconAndNameForOpenDomain + ? ( +
    + +
    + ) + : null + } { this.renderKeyringType(keyring) } { this.renderRemoveAccount(keyring, identity) }
    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 ae2e28e7698e..00a0666ec3ce 100644 --- a/ui/app/components/app/account-menu/account-menu.container.js +++ b/ui/app/components/app/account-menu/account-menu.container.js @@ -11,7 +11,12 @@ import { showInfoPage, showModal, } from '../../../store/actions' -import { getMetaMaskAccounts } from '../../../selectors/selectors' +import { + getAddressConnectedDomainMap, + getMetaMaskAccounts, + getOriginOfCurrentTab, +} from '../../../selectors/selectors' + import AccountMenu from './account-menu.component' function mapStateToProps (state) { @@ -23,6 +28,8 @@ function mapStateToProps (state) { keyrings, identities, accounts: getMetaMaskAccounts(state), + addressConnectedDomainMap: getAddressConnectedDomainMap(state), + originOfCurrentTab: getOriginOfCurrentTab(state), } } diff --git a/ui/app/components/app/account-menu/index.scss b/ui/app/components/app/account-menu/index.scss index 614e191041e3..93b9766d35c1 100644 --- a/ui/app/components/app/account-menu/index.scss +++ b/ui/app/components/app/account-menu/index.scss @@ -175,4 +175,8 @@ opacity: 1; } } + + &__icon-list { + display: flex; + } } diff --git a/ui/app/components/app/connected-sites-list/connected-sites-list.component.js b/ui/app/components/app/connected-sites-list/connected-sites-list.component.js new file mode 100644 index 000000000000..a04f87486c04 --- /dev/null +++ b/ui/app/components/app/connected-sites-list/connected-sites-list.component.js @@ -0,0 +1,157 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import Button from '../../ui/button' +import IconWithFallBack from '../../ui/icon-with-fallback' + +export default class ConnectedSitesList extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + renderableDomains: PropTypes.arrayOf(PropTypes.shape({ + name: PropTypes.string, + icon: PropTypes.string, + key: PropTypes.string, + lastConnectedTime: PropTypes.string, + permissionDescriptions: PropTypes.array, + })).isRequired, + domains: PropTypes.object, + showDisconnectAccountModal: PropTypes.func.isRequired, + showDisconnectAllModal: PropTypes.func.isRequired, + tabToConnect: PropTypes.object, + legacyExposeAccounts: PropTypes.func.isRequired, + selectedAddress: PropTypes.string.isRequired, + getOpenMetamaskTabsIds: PropTypes.func.isRequired, + } + + state = { + expandedDomain: '', + } + + componentWillMount () { + const { getOpenMetamaskTabsIds } = this.props + getOpenMetamaskTabsIds() + } + + handleDomainItemClick (domainKey) { + if (this.state.expandedDomain === domainKey) { + this.setState({ expandedDomain: '' }) + } else { + this.setState({ expandedDomain: domainKey }) + } + } + + render () { + const { + renderableDomains, + domains, + showDisconnectAccountModal, + showDisconnectAllModal, + tabToConnect, + legacyExposeAccounts, + selectedAddress, + } = this.props + const { expandedDomain } = this.state + const { t } = this.context + + return ( +
    + { + renderableDomains.map((domain, domainIndex) => { + const domainIsExpanded = expandedDomain === domain.key + return ( +
    +
    this.handleDomainItemClick(domain.key) }> +
    + + +
    +
    +
    + { domain.extensionId ? t('externalExtension') : domain.name } +
    +
    + { domain.lastConnectedTime + ? ( +
    + { t('domainLastConnect', [domain.lastConnectedTime]) } +
    + ) + : null + } + {domainIsExpanded + ? ( +
    + { domain.extensionId ? t('extensionId', [domain.extensionId]) : domain.secondaryName } +
    + ) + : null + } +
    +
    +
    + { domainIsExpanded ? : } +
    +
    + { domainIsExpanded + ? ( +
    +
    + { + domain.permissionDescriptions.map((description, pdIndex) => { + return ( +
    + +
    + { description } +
    +
    + ) + }) + } +
    +
    showDisconnectAccountModal(domain.key, domains[domain.key]) } + > + { t('disconnectAccount') } +
    +
    + ) + : null + } +
    + ) + }) + } +
    +
    + +
    + { tabToConnect + ? ( +
    + +
    + ) + : null + } +
    +
    + ) + } +} diff --git a/ui/app/components/app/connected-sites-list/connected-sites-list.container.js b/ui/app/components/app/connected-sites-list/connected-sites-list.container.js new file mode 100644 index 000000000000..de45831a9df7 --- /dev/null +++ b/ui/app/components/app/connected-sites-list/connected-sites-list.container.js @@ -0,0 +1,57 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' + +import ConnectedSitesList from './connected-sites-list.component' +import { + showModal, + legacyExposeAccounts, + getOpenMetamaskTabsIds, +} from '../../../store/actions' +import { + getRenderablePermissionsDomains, + getPermissionsDomains, + getAddressConnectedToCurrentTab, + getSelectedAddress, +} from '../../../selectors/selectors' +import { getOriginFromUrl } from '../../../helpers/utils/util' + +const mapStateToProps = state => { + const addressConnectedToCurrentTab = getAddressConnectedToCurrentTab(state) + const { openMetaMaskTabs } = state.appState + const { title, url, id } = state.activeTab + + let tabToConnect + + if (!addressConnectedToCurrentTab && url && !openMetaMaskTabs[id]) { + tabToConnect = { + title, + origin: getOriginFromUrl(url), + } + } + + return { + domains: getPermissionsDomains(state), + renderableDomains: getRenderablePermissionsDomains(state), + tabToConnect, + selectedAddress: getSelectedAddress(state), + } +} + +const mapDispatchToProps = dispatch => { + return { + showDisconnectAccountModal: (domainKey, domain) => { + dispatch(showModal({ name: 'DISCONNECT_ACCOUNT', domainKey, domain })) + }, + showDisconnectAllModal: () => { + dispatch(showModal({ name: 'DISCONNECT_ALL' })) + }, + legacyExposeAccounts: (origin, account) => { + dispatch(legacyExposeAccounts(origin, [account])) + }, + getOpenMetamaskTabsIds: () => dispatch(getOpenMetamaskTabsIds()), + } +} + +export default compose( + connect(mapStateToProps, mapDispatchToProps) +)(ConnectedSitesList) diff --git a/ui/app/components/app/connected-sites-list/index.js b/ui/app/components/app/connected-sites-list/index.js new file mode 100644 index 000000000000..431a3a8eb6da --- /dev/null +++ b/ui/app/components/app/connected-sites-list/index.js @@ -0,0 +1 @@ +export { default } from './connected-sites-list.container' diff --git a/ui/app/components/app/connected-sites-list/index.scss b/ui/app/components/app/connected-sites-list/index.scss new file mode 100644 index 000000000000..c2d98d2aa0c1 --- /dev/null +++ b/ui/app/components/app/connected-sites-list/index.scss @@ -0,0 +1,125 @@ +.connected-sites-list { + font-family: Roboto; + font-style: normal; + font-weight: normal; + + &__domain, &__domain--expanded { + border-bottom: 1px solid #c4c4c4; + } + + &__domain { + cursor: pointer; + } + + &__domain--expanded { + background: #FAFBFC; + cursor: initial; + } + + &__domain-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px; + } + + &__domain-item-info-container { + display: flex; + } + + &__identicon-container { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 32px; + width: 32px; + } + + &__identicon-border { + height: 32px; + width: 32px; + border-radius: 50%; + border: 1px solid #F2F3F4; + position: absolute; + background: #FFFFFF; + } + + &__identicon { + width: 24px; + height: 24px; + z-index: 1; + + &--default { + z-index: 1; + color: black; + } + } + + &__domain-info { + display: flex; + flex-direction: column; + margin-left: 16px; + } + + &__domain-names { + display: flex; + align-items: center; + } + + &__domain-name { + font-size: 18px; + color: #24292E; + } + + &__domain-origin, &__domain-last-connected { + font-size: 12px; + color: #6A737D; + } + + &__domain-last-connected { + margin-top: 2px; + } + + &__expand-arrow { + align-self: flex-start; + margin-top: 6px; + } + + &__permissions { + padding-left: 16px; + padding-bottom: 24px; + } + + &__permission { + display: flex; + align-items: center; + color: #6A737D; + margin-left: 16px; + } + + &__permission-description { + margin-left: 18px; + } + + &__disconnect { + margin-top: 24px; + color: #D73A49; + cursor: pointer; + } + + &__bottom-buttons { + display: flex; + align-items: center; + } + + &__disconnect-all { + padding: 10px; + width: 50%; + } + + &__connect-to { + padding: 10px; + width: 50%; + } +} \ No newline at end of file diff --git a/ui/app/components/app/dropdowns/account-details-dropdown.js b/ui/app/components/app/dropdowns/account-details-dropdown.js index 89e7f91ef60c..dc09b8c64336 100644 --- a/ui/app/components/app/dropdowns/account-details-dropdown.js +++ b/ui/app/components/app/dropdowns/account-details-dropdown.js @@ -1,9 +1,12 @@ import React, { Component } from 'react' const PropTypes = require('prop-types') +const { compose } = require('recompose') +const { withRouter } = require('react-router-dom') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../../store/actions') const { getSelectedIdentity, getRpcPrefsForCurrentProvider } = require('../../../selectors/selectors') +const { CONNECTED_ROUTE } = require('../../../helpers/constants/routes') const genAccountLink = require('../../../../lib/account-link.js') const { Menu, Item, CloseArea } = require('./components/menu') @@ -12,7 +15,7 @@ AccountDetailsDropdown.contextTypes = { metricsEvent: PropTypes.func, } -module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsDropdown) +module.exports = compose(withRouter, connect(mapStateToProps, mapDispatchToProps))(AccountDetailsDropdown) function mapStateToProps (state) { return { @@ -58,6 +61,7 @@ AccountDetailsDropdown.prototype.render = function AccountDetailsDropdown () { viewOnEtherscan, showRemoveAccountConfirmationModal, rpcPrefs, + history, } = this.props const address = selectedIdentity.address @@ -134,6 +138,23 @@ AccountDetailsDropdown.prototype.render = function AccountDetailsDropdown () { )} /> + { + e.stopPropagation() + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Account Options', + name: 'Opened Connected Sites', + }, + }) + history.push(CONNECTED_ROUTE) + }} + text={this.context.t('connectedSites')} + icon={( + + )} + /> { isRemovable ? ( diff --git a/ui/app/components/app/index.scss b/ui/app/components/app/index.scss index 1afbebd00484..7578aa204a76 100644 --- a/ui/app/components/app/index.scss +++ b/ui/app/components/app/index.scss @@ -38,7 +38,7 @@ @import '../../pages/index'; -@import 'provider-page-container/index'; +@import 'permission-page-container/index'; @import 'selected-account/index'; @@ -64,18 +64,12 @@ @import 'transaction-status/index'; -@import 'app-header/index'; - @import 'sidebars/index'; @import '../ui/unit-input/index'; @import 'gas-customization/gas-modal-page-container/index'; -@import 'gas-customization/gas-modal-page-container/index'; - -@import 'gas-customization/gas-modal-page-container/index'; - @import 'gas-customization/index'; @import 'gas-customization/gas-price-button-group/index'; @@ -87,3 +81,7 @@ @import 'multiple-notifications/index'; @import 'signature-request/index'; + +@import 'connected-sites-list/index'; + +@import '../ui/icon-with-fallback/index'; diff --git a/ui/app/components/app/modal/modal.component.js b/ui/app/components/app/modal/modal.component.js index f0fdd3bd522a..6c45160fdc63 100644 --- a/ui/app/components/app/modal/modal.component.js +++ b/ui/app/components/app/modal/modal.component.js @@ -16,6 +16,7 @@ export default class Modal extends PureComponent { submitType: PropTypes.string, submitText: PropTypes.string, submitDisabled: PropTypes.bool, + hideFooter: PropTypes.bool, // Cancel button (left button) onCancel: PropTypes.func, cancelType: PropTypes.string, @@ -41,6 +42,7 @@ export default class Modal extends PureComponent { cancelText, contentClass, containerClass, + hideFooter, } = this.props return ( @@ -61,27 +63,32 @@ export default class Modal extends PureComponent {
    { children }
    -
    - { - onCancel && ( + { !hideFooter + ? ( +
    + { + onCancel && ( + + ) + } - ) - } - -
    +
    + ) + : null + } ) } diff --git a/ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.component.js b/ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.component.js deleted file mode 100644 index ceaa20a951b0..000000000000 --- a/ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.component.js +++ /dev/null @@ -1,39 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Modal, { ModalContent } from '../../modal' - -export default class ClearApprovedOrigins extends PureComponent { - static propTypes = { - hideModal: PropTypes.func.isRequired, - clearApprovedOrigins: PropTypes.func.isRequired, - } - - static contextTypes = { - t: PropTypes.func, - } - - handleClear = () => { - const { clearApprovedOrigins, hideModal } = this.props - clearApprovedOrigins() - hideModal() - } - - render () { - const { t } = this.context - - return ( - this.props.hideModal()} - submitText={t('ok')} - cancelText={t('nevermind')} - submitType="secondary" - > - - - ) - } -} diff --git a/ui/app/components/app/modals/clear-approved-origins/index.js b/ui/app/components/app/modals/clear-approved-origins/index.js deleted file mode 100644 index b3e321995189..000000000000 --- a/ui/app/components/app/modals/clear-approved-origins/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './clear-approved-origins.container' diff --git a/ui/app/components/app/modals/disconnect-account/disconnect-account.component.js b/ui/app/components/app/modals/disconnect-account/disconnect-account.component.js new file mode 100644 index 000000000000..4fe5c7227eff --- /dev/null +++ b/ui/app/components/app/modals/disconnect-account/disconnect-account.component.js @@ -0,0 +1,52 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Modal from '../../modal' +import Button from '../../../ui/button' + + +export default class DisconnectAccount extends PureComponent { + static propTypes = { + hideModal: PropTypes.func.isRequired, + disconnectAccount: PropTypes.func.isRequired, + accountLabel: PropTypes.string.isRequired, + } + + static contextTypes = { + t: PropTypes.func, + } + + render () { + const { t } = this.context + const { hideModal, disconnectAccount, accountLabel } = this.props + + return ( + hideModal()} + hideFooter + > +
    +
    + { t('disconnectAccountModalDescription', [ accountLabel ]) } +
    + + +
    +
    + ) + } +} diff --git a/ui/app/components/app/modals/disconnect-account/disconnect-account.container.js b/ui/app/components/app/modals/disconnect-account/disconnect-account.container.js new file mode 100644 index 000000000000..b0511bb47261 --- /dev/null +++ b/ui/app/components/app/modals/disconnect-account/disconnect-account.container.js @@ -0,0 +1,44 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import withModalProps from '../../../../helpers/higher-order-components/with-modal-props' +import DisconnectAccount from './disconnect-account.component' +import { getCurrentAccountWithSendEtherInfo } from '../../../../selectors/selectors' +import { removePermissionsFor } from '../../../../store/actions' + +const mapStateToProps = state => { + return { + ...state.appState.modal.modalState.props || {}, + accountLabel: getCurrentAccountWithSendEtherInfo(state).name, + } +} + +const mapDispatchToProps = dispatch => { + return { + disconnectAccount: (domainKey, domain) => { + const permissionMethodNames = domain.permissions.map(perm => perm.parentCapability) + dispatch(removePermissionsFor({ [domainKey]: permissionMethodNames })) + }, + } +} + +const mergeProps = (stateProps, dispatchProps, ownProps) => { + const { + domainKey, + domain, + } = stateProps + const { + disconnectAccount: dispatchDisconnectAccount, + } = dispatchProps + + return { + ...ownProps, + ...stateProps, + ...dispatchProps, + disconnectAccount: () => dispatchDisconnectAccount(domainKey, domain), + } +} + +export default compose( + withModalProps, + connect(mapStateToProps, mapDispatchToProps, mergeProps) +)(DisconnectAccount) diff --git a/ui/app/components/app/modals/disconnect-account/index.js b/ui/app/components/app/modals/disconnect-account/index.js new file mode 100644 index 000000000000..43bfac9fdcec --- /dev/null +++ b/ui/app/components/app/modals/disconnect-account/index.js @@ -0,0 +1 @@ +export { default } from './disconnect-account.container' diff --git a/ui/app/components/app/modals/disconnect-account/index.scss b/ui/app/components/app/modals/disconnect-account/index.scss new file mode 100644 index 000000000000..861b7cec224e --- /dev/null +++ b/ui/app/components/app/modals/disconnect-account/index.scss @@ -0,0 +1,25 @@ +.disconnect-account-modal { + &__description { + color: #24292E; + margin-bottom: 24px; + } + + &__cancel-button { + border: none; + margin-top: 12px; + } +} + +.disconnect-account-modal-container { + .modal-container__header-text { + @extend %header--18; + } + + .modal-container__content { + padding-bottom: 18px; + + @media screen and (max-width: 575px) { + padding-bottom: 18px; + } + } +} \ No newline at end of file diff --git a/ui/app/components/app/modals/disconnect-all/disconnect-all.component.js b/ui/app/components/app/modals/disconnect-all/disconnect-all.component.js new file mode 100644 index 000000000000..2d29fd9ea092 --- /dev/null +++ b/ui/app/components/app/modals/disconnect-all/disconnect-all.component.js @@ -0,0 +1,54 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Modal from '../../modal' +import Button from '../../../ui/button' +import { DEFAULT_ROUTE } from '../../../../helpers/constants/routes' + +export default class DisconnectAll extends PureComponent { + static propTypes = { + hideModal: PropTypes.func.isRequired, + disconnectAll: PropTypes.func.isRequired, + history: PropTypes.object.isRequired, + } + + static contextTypes = { + t: PropTypes.func, + } + + render () { + const { t } = this.context + const { hideModal, disconnectAll, history } = this.props + + return ( + hideModal()} + hideFooter + > +
    +
    + { t('disconnectAllModalDescription') } +
    + + +
    +
    + ) + } +} diff --git a/ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.container.js b/ui/app/components/app/modals/disconnect-all/disconnect-all.container.js similarity index 53% rename from ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.container.js rename to ui/app/components/app/modals/disconnect-all/disconnect-all.container.js index 2276bc7e7822..2415c3fa9fad 100644 --- a/ui/app/components/app/modals/clear-approved-origins/clear-approved-origins.container.js +++ b/ui/app/components/app/modals/disconnect-all/disconnect-all.container.js @@ -1,16 +1,20 @@ import { connect } from 'react-redux' import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' import withModalProps from '../../../../helpers/higher-order-components/with-modal-props' -import ClearApprovedOriginsComponent from './clear-approved-origins.component' -import { clearApprovedOrigins } from '../../../../store/actions' +import DisconnectAll from './disconnect-all.component' +import { clearPermissions } from '../../../../store/actions' const mapDispatchToProps = dispatch => { return { - clearApprovedOrigins: () => dispatch(clearApprovedOrigins()), + disconnectAll: () => { + dispatch(clearPermissions()) + }, } } export default compose( withModalProps, + withRouter, connect(null, mapDispatchToProps) -)(ClearApprovedOriginsComponent) +)(DisconnectAll) diff --git a/ui/app/components/app/modals/disconnect-all/index.js b/ui/app/components/app/modals/disconnect-all/index.js new file mode 100644 index 000000000000..7fdfac530bc2 --- /dev/null +++ b/ui/app/components/app/modals/disconnect-all/index.js @@ -0,0 +1 @@ +export { default } from './disconnect-all.container' diff --git a/ui/app/components/app/modals/disconnect-all/index.scss b/ui/app/components/app/modals/disconnect-all/index.scss new file mode 100644 index 000000000000..8f69baadebb0 --- /dev/null +++ b/ui/app/components/app/modals/disconnect-all/index.scss @@ -0,0 +1,38 @@ +.disconnect-all-modal { + height: 160px; + display: flex; + flex-direction: column; + justify-content: space-between; + + &__description { + color: #24292E; + margin-bottom: 24px; + } + + &__cancel-button { + border: none; + margin-top: 12px; + } + + .btn-secondary { + border: none; + } +} + +.disconnect-all-modal-container { + .modal-container__header-text { + font-family: Roboto; + font-style: normal; + font-weight: bold; + font-size: 18px; + color: #24292E; + } + + .modal-container__content { + padding-bottom: 18px; + + @media screen and (max-width: 575px) { + padding-bottom: 18px; + } + } +} diff --git a/ui/app/components/app/modals/index.scss b/ui/app/components/app/modals/index.scss index da7a27b84086..dbf47265f3c5 100644 --- a/ui/app/components/app/modals/index.scss +++ b/ui/app/components/app/modals/index.scss @@ -11,3 +11,9 @@ @import './add-to-addressbook-modal/index'; @import './edit-approval-permission/index'; + +@import './disconnect-account/index'; + +@import './disconnect-all/index'; + +@import './new-account-modal/index'; diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js index 02690722b676..0409e901fb11 100644 --- a/ui/app/components/app/modals/modal.js +++ b/ui/app/components/app/modals/modal.js @@ -24,11 +24,13 @@ import CancelTransaction from './cancel-transaction' import MetaMetricsOptInModal from './metametrics-opt-in-modal' import RejectTransactions from './reject-transactions' -import ClearApprovedOrigins from './clear-approved-origins' import ConfirmCustomizeGasModal from '../gas-customization/gas-modal-page-container' import ConfirmDeleteNetwork from './confirm-delete-network' import AddToAddressBookModal from './add-to-addressbook-modal' import EditApprovalPermission from './edit-approval-permission' +import NewAccountModal from './new-account-modal' +import DisconnectAccount from './disconnect-account' +import DisconnectAll from './disconnect-all' const modalContainerBaseStyle = { transform: 'translate3d(-50%, 0, 0px)', @@ -139,6 +141,87 @@ const MODALS = { }, }, + NEW_ACCOUNT: { + contents: , + mobileModalStyle: { + width: '95%', + top: '10%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + borderRadius: '10px', + }, + laptopModalStyle: { + width: '375px', + top: '10%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + borderRadius: '10px', + }, + contentStyle: { + borderRadius: '10px', + }, + }, + + DISCONNECT_ACCOUNT: { + contents: , + mobileModalStyle: { + width: '95%', + top: '10%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + borderRadius: '10px', + }, + laptopModalStyle: { + width: '375px', + top: '10%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + borderRadius: '10px', + }, + contentStyle: { + borderRadius: '10px', + }, + }, + + DISCONNECT_ALL: { + contents: , + mobileModalStyle: { + width: '95%', + top: '10%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + borderRadius: '10px', + }, + laptopModalStyle: { + width: '375px', + top: '10%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + borderRadius: '10px', + }, + contentStyle: { + borderRadius: '10px', + }, + }, + ACCOUNT_DETAILS: { contents: , ...accountModalStyle, @@ -161,19 +244,6 @@ const MODALS = { }, }, - CLEAR_APPROVED_ORIGINS: { - contents: , - mobileModalStyle: { - ...modalContainerMobileStyle, - }, - laptopModalStyle: { - ...modalContainerLaptopStyle, - }, - contentStyle: { - borderRadius: '8px', - }, - }, - METAMETRICS_OPT_IN_MODAL: { contents: , mobileModalStyle: { diff --git a/ui/app/components/app/modals/new-account-modal/index.js b/ui/app/components/app/modals/new-account-modal/index.js new file mode 100644 index 000000000000..2c8b788904a4 --- /dev/null +++ b/ui/app/components/app/modals/new-account-modal/index.js @@ -0,0 +1 @@ +export { default } from './new-account-modal.container' diff --git a/ui/app/components/app/modals/new-account-modal/index.scss b/ui/app/components/app/modals/new-account-modal/index.scss new file mode 100644 index 000000000000..d6c2d0ac1c97 --- /dev/null +++ b/ui/app/components/app/modals/new-account-modal/index.scss @@ -0,0 +1,37 @@ +.new-account-modal { + @extend %col-nowrap; + @extend %modal; + + &__content { + @extend %col-nowrap; + padding: 1.5rem; + border-bottom: 1px solid $Grey-100; + + &__header { + @extend %h3; + } + } + + &__input-label { + color: $Grey-600; + margin-top: 1.25rem; + } + + &__input { + @extend %input; + margin-top: 0.75rem; + + &::placeholder { + color: $Grey-300; + } + } + + &__footer { + @extend %row-nowrap; + padding: 1rem; + + button + button { + margin-left: 1rem; + } + } +} 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 new file mode 100644 index 000000000000..26224ae63b13 --- /dev/null +++ b/ui/app/components/app/modals/new-account-modal/new-account-modal.component.js @@ -0,0 +1,78 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import Button from '../../../ui/button/button.component' + +export default class NewAccountModal extends Component { + + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + hideModal: PropTypes.func.isRequired, + newAccountNumber: PropTypes.number.isRequired, + onSave: PropTypes.func.isRequired, + } + + state = { + alias: '', + } + + onChange = e => { + this.setState({ + alias: e.target.value, + }) + } + + onSubmit = () => { + this.props.onSave(this.state.alias) + .then(this.props.hideModal) + } + + onKeyPress = e => { + if (e.key === 'Enter' && this.state.alias) { + this.onSubmit() + } + } + + render () { + const { t } = this.context + + return ( +
    +
    +
    + {t('newAccount')} +
    +
    + {t('accountName')} +
    + +
    +
    + + +
    +
    + ) + } +} diff --git a/ui/app/components/app/modals/new-account-modal/new-account-modal.container.js b/ui/app/components/app/modals/new-account-modal/new-account-modal.container.js new file mode 100644 index 000000000000..812e98dbd137 --- /dev/null +++ b/ui/app/components/app/modals/new-account-modal/new-account-modal.container.js @@ -0,0 +1,44 @@ +import { connect } from 'react-redux' +import NewAccountModal from './new-account-modal.component' +import actions from '../../../../store/actions' + +function mapStateToProps (state) { + return { + ...state.appState.modal.modalState.props || {}, + } +} + +function mapDispatchToProps (dispatch) { + return { + hideModal: () => dispatch(actions.hideModal()), + createAccount: newAccountName => { + return dispatch(actions.addNewAccount()) + .then(newAccountAddress => { + if (newAccountName) { + dispatch(actions.setAccountLabel(newAccountAddress, newAccountName)) + } + return newAccountAddress + }) + }, + } +} + +function mergeProps (stateProps, dispatchProps) { + const { + onCreateNewAccount, + } = stateProps + const { + createAccount, + } = dispatchProps + + return { + ...stateProps, + ...dispatchProps, + onSave: (newAccountName) => { + return createAccount(newAccountName) + .then(newAccountAddress => onCreateNewAccount(newAccountAddress)) + }, + } +} + +export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(NewAccountModal) diff --git a/ui/app/components/app/permission-page-container/index.js b/ui/app/components/app/permission-page-container/index.js new file mode 100644 index 000000000000..ea3b8daaa2a6 --- /dev/null +++ b/ui/app/components/app/permission-page-container/index.js @@ -0,0 +1,3 @@ +export {default} from './permission-page-container.container' +export {default as PermissionPageContainerContent} from './permission-page-container-content' +export {default as PermissionPageContainerHeader} from './permission-page-container-header' diff --git a/ui/app/components/app/permission-page-container/index.scss b/ui/app/components/app/permission-page-container/index.scss new file mode 100644 index 000000000000..7979867fa71d --- /dev/null +++ b/ui/app/components/app/permission-page-container/index.scss @@ -0,0 +1,281 @@ +.permission-approval-container { + display: flex; + border: none; + box-shadow: none; + margin-top: 45px; + width: 466px; + min-height: 468px; + + &__header { + display: flex; + flex-direction: column; + align-items: flex-end; + border-bottom: 1px solid $geyser; + padding: 9px; + } + + &__title { + @extend %header--18; + line-height: 25px; + text-align: center; + position: fixed; + left: 0; + width: 100%; + } + + &__content { + display: flex; + overflow-y: auto; + flex: 1; + flex-direction: column; + color: #7C808E; + + &--redirect { + margin-top: 60px; + } + + h1, h2 { + color: #4A4A4A; + display: flex; + justify-content: center; + text-align: center; + } + + h2 { + font-size: 16px; + line-height: 18px; + padding: 20px; + } + + h1 { + font-size: 22px; + line-height: 26px; + padding: 20px; + } + + p { + padding: 0 40px; + text-align: center; + font-size: 12px; + line-height: 18px; + } + + a, a:hover { + color: $dodger-blue; + } + + section { + h1 { + padding: 30px 0px 0px 0px; + } + + h2 { + padding: 0px 0px 20px 0px; + } + } + + &__requested { + text-align: left; + } + + &__revoke-note { + margin-top: 24px; + } + + &__checkbox { + margin-right: 10px; + } + + &__permission { + margin-top: 18px; + + i { + color: #6A737D; + } + label { + margin-left: 6px; + color: #24292E; + } + } + + .permission-approval-visual { + display: flex; + flex-direction: row; + justify-content: space-evenly; + position: relative; + margin: 0 32px; + margin-top: 40px; + + section { + display: flex; + flex-direction: column; + align-items: center; + flex: 1; + } + + h1 { + font-size: 14px; + line-height: 18px; + padding: 8px 0 0; + } + + h2 { + font-size: 12px; + line-height: 17px; + color: #6A737D; + padding: 0; + } + + &__check { + width: 40px; + height: 40px; + background: white url("/images/permissions-check.svg") no-repeat; + margin-top: 24px; + z-index: 1; + } + + &__reject { + background: white; + z-index: 1; + display: flex; + justify-content: center; + align-items: center; + + i { + color: #D73A49; + transform: scale(3); + } + } + + &__broken-line { + z-index: 0; + position: absolute; + top: 43px; + } + + &__identicon, .icon-with-fallback__identicon { + width: 32px; + height: 32px; + z-index: 1; + + &--default { + background-color: #777A87; + color: white; + width: 64px; + height: 64px; + border-radius: 32px; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + z-index: 1; + } + } + + &__identicon-container, .icon-with-fallback__identicon-container { + padding: 1rem; + flex: 1; + position: relative; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + } + + &__identicon-border, .icon-with-fallback__identicon-border { + height: 64px; + width: 64px; + border-radius: 50%; + border: 1px solid white; + position: absolute; + background: #FFFFFF; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25); + } + + &:before { + border-top: 2px dashed #CDD1E4; + content: ""; + margin: 0 auto; + position: absolute; + top: 32px; + left: 0; + bottom: 0; + right: 0; + width: 65%; + z-index: -1; + } + + &__account-info { + display: flex; + flex-direction: column; + align-items: center; + + &__label { + @extend %content-text; + line-height: 20px; + color: #000000; + } + + &__address { + @extend %font; + font-size: 12px; + line-height: 17px; + color: #6A737D; + } + } + } + + .secure-badge { + display: flex; + justify-content: center; + padding: 25px; + } + } + + &__permissions-header { + @extend %content-text; + line-height: 20px; + color: #6A737D; + + &--redirect { + text-align: center; + } + } + + &__permissions-container { + display: flex; + flex-direction: column; + margin-top: 33px; + } + + .page-container__footer { + border-top: none; + align-items: center; + + header { + width: 300px; + } + } + + &__permissions-header-redirect { + text-align: center; + } + + @media screen and (max-width: 575px) { + width: 100%; + margin-top: 25px; + padding: 10px; + + &__title { + position: initial; + } + + &__content-approval-visual { + margin-top: 16px; + } + + .page-container__footer header { + padding: 0; + } + } +} diff --git a/ui/app/components/app/permission-page-container/permission-page-container-content/index.js b/ui/app/components/app/permission-page-container/permission-page-container-content/index.js new file mode 100644 index 000000000000..899d168f930f --- /dev/null +++ b/ui/app/components/app/permission-page-container/permission-page-container-content/index.js @@ -0,0 +1 @@ +export {default} from './permission-page-container-content.component' 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 new file mode 100644 index 000000000000..d6a62dbbfa69 --- /dev/null +++ b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js @@ -0,0 +1,163 @@ +import PropTypes from 'prop-types' +import React, { PureComponent } from 'react' +import Identicon from '../../../ui/identicon' +import IconWithFallBack from '../../../ui/icon-with-fallback' +import classnames from 'classnames' + +export default class PermissionPageContainerContent extends PureComponent { + + static propTypes = { + requestMetadata: PropTypes.object.isRequired, + domainMetadata: PropTypes.object.isRequired, + selectedPermissions: PropTypes.object.isRequired, + permissionsDescriptions: PropTypes.object.isRequired, + onPermissionToggle: PropTypes.func.isRequired, + selectedAccount: PropTypes.object, + redirect: PropTypes.bool, + permissionRejected: PropTypes.bool, + } + + static defaultProps = { + redirect: null, + permissionRejected: null, + selectedAccount: {}, + } + + static contextTypes = { + t: PropTypes.func, + } + + renderAccountInfo = (account) => { + return ( +
    +
    + { account.label } +
    +
    + { account.truncatedAddress } +
    +
    + ) + } + + renderPermissionApprovalVisual = () => { + const { + requestMetadata, domainMetadata, selectedAccount, redirect, permissionRejected, + } = this.props + + return ( +
    +
    + + { redirect ? null :

    {domainMetadata.name}

    } + { redirect ? null :

    {requestMetadata.origin}

    } +
    + { permissionRejected + ? + : + } + +
    +
    +
    + +
    + { redirect ? null : this.renderAccountInfo(selectedAccount) } +
    +
    + ) + } + + renderRequestedPermissions () { + const { + selectedPermissions, permissionsDescriptions, onPermissionToggle, + } = this.props + const { t } = this.context + + const items = Object.keys(selectedPermissions).map((methodName) => { + + // the request will almost certainly be reject by rpc-cap if this happens + if (!permissionsDescriptions[methodName]) { + console.warn(`Unknown permission requested: ${methodName}`) + } + const description = permissionsDescriptions[methodName] || methodName + // don't allow deselecting eth_accounts + const isDisabled = methodName === 'eth_accounts' + + return ( +
    { + if (!isDisabled) { + onPermissionToggle(methodName) + } + }} + > + { selectedPermissions[methodName] + ? + : + } + +
    + ) + }) + + return ( +
    + {items} +
    { t('revokeInPermissions') }
    +
    + ) + } + + render () { + const { domainMetadata, redirect, permissionRejected } = this.props + const { t } = this.context + + let titleArgs + if (redirect && permissionRejected) { + titleArgs = [ 'cancelledConnectionWithMetaMask' ] + } else if (redirect) { + titleArgs = [ 'connectingWithMetaMask' ] + } else if (domainMetadata.extensionId) { + titleArgs = [ 'externalExtension', [domainMetadata.extensionId] ] + } else { + titleArgs = [ 'likeToConnect', [domainMetadata.name] ] + } + + return ( +
    +
    + { t(...titleArgs) } +
    + {this.renderPermissionApprovalVisual()} + { !redirect + ? ( +
    +
    + { domainMetadata.extensionId + ? t('thisWillAllowExternalExtension', [domainMetadata.extensionId]) + : t('thisWillAllow', [domainMetadata.name]) + } +
    + { this.renderRequestedPermissions() } +
    + ) + : ( +
    + { t('redirectingBackToDapp') } +
    + ) + } +
    + ) + } +} diff --git a/ui/app/components/app/permission-page-container/permission-page-container-header/index.js b/ui/app/components/app/permission-page-container/permission-page-container-header/index.js new file mode 100644 index 000000000000..45ef9036b168 --- /dev/null +++ b/ui/app/components/app/permission-page-container/permission-page-container-header/index.js @@ -0,0 +1 @@ +export {default} from './permission-page-container-header.component' diff --git a/ui/app/components/app/provider-page-container/provider-page-container-header/provider-page-container-header.component.js b/ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js similarity index 58% rename from ui/app/components/app/provider-page-container/provider-page-container-header/provider-page-container-header.component.js rename to ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js index 41bf6c3dd244..8ba3444ba2f6 100644 --- a/ui/app/components/app/provider-page-container/provider-page-container-header/provider-page-container-header.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js @@ -1,10 +1,10 @@ import React, {PureComponent} from 'react' import NetworkDisplay from '../../network-display' -export default class ProviderPageContainerHeader extends PureComponent { +export default class PermissionPageContainerHeader extends PureComponent { render () { return ( -
    +
    ) 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 new file mode 100644 index 000000000000..b7cbcd6ba652 --- /dev/null +++ b/ui/app/components/app/permission-page-container/permission-page-container.component.js @@ -0,0 +1,151 @@ +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import deepEqual from 'fast-deep-equal' +import { PermissionPageContainerContent } from '.' +import { PageContainerFooter } from '../../ui/page-container' + +export default class PermissionPageContainer extends Component { + + static propTypes = { + approvePermissionsRequest: PropTypes.func.isRequired, + rejectPermissionsRequest: PropTypes.func.isRequired, + selectedIdentity: PropTypes.object, + permissionsDescriptions: PropTypes.object.isRequired, + request: PropTypes.object, + redirect: PropTypes.bool, + permissionRejected: PropTypes.bool, + requestMetadata: PropTypes.object, + targetDomainMetadata: PropTypes.object.isRequired, + }; + + static defaultProps = { + redirect: null, + permissionRejected: null, + request: {}, + requestMetadata: {}, + selectedIdentity: {}, + }; + + static contextTypes = { + t: PropTypes.func, + metricsEvent: PropTypes.func, + }; + + state = { + selectedPermissions: this.getRequestedMethodState( + this.getRequestedMethodNames(this.props) + ), + } + + componentDidUpdate () { + const newMethodNames = this.getRequestedMethodNames(this.props) + + if (!deepEqual(Object.keys(this.state.selectedPermissions), newMethodNames)) { + // this should be a new request, so just overwrite + this.setState({ + selectedPermissions: this.getRequestedMethodState(newMethodNames), + }) + } + } + + getRequestedMethodState (methodNames) { + return methodNames.reduce( + (acc, methodName) => { + acc[methodName] = true + return acc + }, + {} + ) + } + + getRequestedMethodNames (props) { + return Object.keys(props.request.permissions || {}) + } + + onPermissionToggle = methodName => { + this.setState({ + selectedPermissions: { + ...this.state.selectedPermissions, + [methodName]: !this.state.selectedPermissions[methodName], + }, + }) + } + + componentDidMount () { + this.context.metricsEvent({ + eventOpts: { + category: 'Auth', + action: 'Connect', + name: 'Tab Opened', + }, + }) + } + + onCancel = () => { + const { request, rejectPermissionsRequest } = this.props + rejectPermissionsRequest(request.metadata.id) + } + + onSubmit = () => { + const { + request: _request, approvePermissionsRequest, rejectPermissionsRequest, selectedIdentity, + } = this.props + + const request = { + ..._request, + permissions: { ..._request.permissions }, + } + + Object.keys(this.state.selectedPermissions).forEach(key => { + if (!this.state.selectedPermissions[key]) { + delete request.permissions[key] + } + }) + + if (Object.keys(request.permissions).length > 0) { + approvePermissionsRequest(request, [selectedIdentity.address]) + } else { + rejectPermissionsRequest(request.metadata.id) + } + } + + render () { + const { + requestMetadata, + targetDomainMetadata, + permissionsDescriptions, + selectedIdentity, + redirect, + permissionRejected, + } = this.props + + return ( +
    + + { !redirect + ? ( + this.onCancel()} + cancelText={this.context.t('cancel')} + onSubmit={() => this.onSubmit()} + submitText={this.context.t('submit')} + submitButtonType="confirm" + buttonSizeLarge={false} + /> + ) + : null + } +
    + ) + } +} 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 new file mode 100644 index 000000000000..f83393c70e11 --- /dev/null +++ b/ui/app/components/app/permission-page-container/permission-page-container.container.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' +import PermissionPageContainer from './permission-page-container.component' +import { + getPermissionsDescriptions, + getDomainMetadata, +} from '../../../selectors/selectors' + +const mapStateToProps = (state, ownProps) => { + const { request, cachedOrigin } = ownProps + const { metadata: requestMetadata = {} } = request || {} + + const domainMetadata = getDomainMetadata(state) + const origin = requestMetadata.origin || cachedOrigin + const targetDomainMetadata = (domainMetadata[origin] || { name: origin, icon: null }) + + return { + permissionsDescriptions: getPermissionsDescriptions(state), + requestMetadata, + targetDomainMetadata, + } +} + +export default compose( + withRouter, + connect(mapStateToProps) +)(PermissionPageContainer) diff --git a/ui/app/components/app/provider-page-container/index.js b/ui/app/components/app/provider-page-container/index.js deleted file mode 100644 index 927c35940cb1..000000000000 --- a/ui/app/components/app/provider-page-container/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export {default} from './provider-page-container.component' -export {default as ProviderPageContainerContent} from './provider-page-container-content' -export {default as ProviderPageContainerHeader} from './provider-page-container-header' diff --git a/ui/app/components/app/provider-page-container/index.scss b/ui/app/components/app/provider-page-container/index.scss deleted file mode 100644 index 8d35ac179052..000000000000 --- a/ui/app/components/app/provider-page-container/index.scss +++ /dev/null @@ -1,121 +0,0 @@ -.provider-approval-container { - display: flex; - - &__header { - display: flex; - flex-direction: column; - align-items: flex-end; - border-bottom: 1px solid $geyser; - padding: 9px; - } - - &__content { - display: flex; - overflow-y: auto; - flex: 1; - flex-direction: column; - justify-content: space-between; - color: #7C808E; - - h1, h2 { - color: #4A4A4A; - display: flex; - justify-content: center; - text-align: center; - } - - h2 { - font-size: 16px; - line-height: 18px; - padding: 20px; - } - - h1 { - font-size: 22px; - line-height: 26px; - padding: 20px; - } - - p { - padding: 0 40px; - text-align: center; - font-size: 12px; - line-height: 18px; - } - - a, a:hover { - color: $dodger-blue; - } - - .provider-approval-visual { - display: flex; - flex-direction: row; - justify-content: space-evenly; - position: relative; - margin: 0 32px; - - section { - display: flex; - flex-direction: column; - align-items: center; - flex: 1; - } - - h1 { - font-size: 14px; - line-height: 18px; - padding: 8px 0 0; - } - - h2 { - font-size: 10px; - line-height: 14px; - padding: 0; - color: #A2A4AC; - } - - &__check { - width: 40px; - height: 40px; - background: white url("/images/provider-approval-check.svg") no-repeat; - margin-top: 14px; - } - - &__identicon { - width: 64px; - height: 64px; - - &--default { - background-color: #777A87; - color: white; - width: 64px; - height: 64px; - border-radius: 32px; - display: flex; - align-items: center; - justify-content: center; - font-weight: bold; - } - } - - &:before { - border-top: 2px dashed #CDD1E4; - content: ""; - margin: 0 auto; - position: absolute; - top: 32px; - left: 0; - bottom: 0; - right: 0; - width: 65%; - z-index: -1; - } - } - - .secure-badge { - display: flex; - justify-content: center; - padding: 25px; - } - } -} diff --git a/ui/app/components/app/provider-page-container/provider-page-container-content/index.js b/ui/app/components/app/provider-page-container/provider-page-container-content/index.js deleted file mode 100644 index 73e491adc89f..000000000000 --- a/ui/app/components/app/provider-page-container/provider-page-container-content/index.js +++ /dev/null @@ -1 +0,0 @@ -export {default} from './provider-page-container-content.container' diff --git a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js b/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js deleted file mode 100644 index 4f94015b13bc..000000000000 --- a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js +++ /dev/null @@ -1,87 +0,0 @@ -import PropTypes from 'prop-types' -import React, {PureComponent} from 'react' -import Identicon from '../../../ui/identicon' - -export default class ProviderPageContainerContent extends PureComponent { - static propTypes = { - origin: PropTypes.string.isRequired, - selectedIdentity: PropTypes.object.isRequired, - siteImage: PropTypes.string, - siteTitle: PropTypes.string, - hostname: PropTypes.string, - extensionId: PropTypes.string, - } - - static contextTypes = { - t: PropTypes.func, - }; - - renderConnectVisual = (title, identifier) => { - const { selectedIdentity, siteImage } = this.props - - return ( -
    -
    - {siteImage ? ( - - ) : ( - - {title.charAt(0).toUpperCase()} - - )} -

    {title}

    -

    {identifier}

    -
    - -
    - -

    {selectedIdentity.name}

    -
    -
    - ) - } - - render () { - const { siteTitle, hostname, extensionId } = this.props - const { t } = this.context - - const title = extensionId ? - 'External Extension' : - siteTitle || hostname - - const identifier = extensionId ? - `Extension ID: '${extensionId}'` : - hostname - - return ( -
    -
    -

    {t('connectRequest')}

    - {this.renderConnectVisual(title, identifier)} -

    {t('providerRequest', [title])}

    -

    - {t('providerRequestInfo')} -
    - - {t('learnMore')}. - -

    -
    -
    - -
    -
    - ) - } -} diff --git a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.container.js b/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.container.js deleted file mode 100644 index 4dbdddd161b0..000000000000 --- a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.container.js +++ /dev/null @@ -1,11 +0,0 @@ -import { connect } from 'react-redux' -import ProviderPageContainerContent from './provider-page-container-content.component' -import { getSelectedIdentity } from '../../../../selectors/selectors' - -const mapStateToProps = (state) => { - return { - selectedIdentity: getSelectedIdentity(state), - } -} - -export default connect(mapStateToProps)(ProviderPageContainerContent) diff --git a/ui/app/components/app/provider-page-container/provider-page-container-header/index.js b/ui/app/components/app/provider-page-container/provider-page-container-header/index.js deleted file mode 100644 index 430627d3a3ae..000000000000 --- a/ui/app/components/app/provider-page-container/provider-page-container-header/index.js +++ /dev/null @@ -1 +0,0 @@ -export {default} from './provider-page-container-header.component' diff --git a/ui/app/components/app/provider-page-container/provider-page-container.component.js b/ui/app/components/app/provider-page-container/provider-page-container.component.js deleted file mode 100644 index 7d152e4cbb49..000000000000 --- a/ui/app/components/app/provider-page-container/provider-page-container.component.js +++ /dev/null @@ -1,107 +0,0 @@ -import PropTypes from 'prop-types' -import React, {PureComponent} from 'react' -import { ProviderPageContainerContent, ProviderPageContainerHeader } from '.' -import { PageContainerFooter } from '../../ui/page-container' -import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../../app/scripts/lib/enums' -import { getEnvironmentType } from '../../../../../app/scripts/lib/util' - -export default class ProviderPageContainer extends PureComponent { - static propTypes = { - approveProviderRequestByOrigin: PropTypes.func.isRequired, - rejectProviderRequestByOrigin: PropTypes.func.isRequired, - origin: PropTypes.string.isRequired, - siteImage: PropTypes.string, - siteTitle: PropTypes.string, - hostname: PropTypes.string, - extensionId: PropTypes.string, - }; - - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - }; - - componentDidMount () { - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) { - window.addEventListener('beforeunload', this._beforeUnload) - } - this.context.metricsEvent({ - eventOpts: { - category: 'Auth', - action: 'Connect', - name: 'Popup Opened', - }, - }) - } - - _beforeUnload = () => { - const { origin, rejectProviderRequestByOrigin } = this.props - this.context.metricsEvent({ - eventOpts: { - category: 'Auth', - action: 'Connect', - name: 'Cancel Connect Request Via Notification Close', - }, - }) - this._removeBeforeUnload() - rejectProviderRequestByOrigin(origin) - } - - _removeBeforeUnload () { - window.removeEventListener('beforeunload', this._beforeUnload) - } - - componentWillUnmount () { - this._removeBeforeUnload() - } - - onCancel = () => { - const { origin, rejectProviderRequestByOrigin } = this.props - this.context.metricsEvent({ - eventOpts: { - category: 'Auth', - action: 'Connect', - name: 'Canceled', - }, - }) - this._removeBeforeUnload() - rejectProviderRequestByOrigin(origin) - } - - onSubmit = () => { - const { approveProviderRequestByOrigin, origin } = this.props - this.context.metricsEvent({ - eventOpts: { - category: 'Auth', - action: 'Connect', - name: 'Confirmed', - }, - }) - this._removeBeforeUnload() - approveProviderRequestByOrigin(origin) - } - - render () { - const {origin, siteImage, siteTitle, hostname, extensionId} = this.props - - return ( -
    - - - this.onCancel()} - cancelText={this.context.t('cancel')} - onSubmit={() => this.onSubmit()} - submitText={this.context.t('connect')} - submitButtonType="confirm" - /> -
    - ) - } -} diff --git a/ui/app/components/app/wallet-view/wallet-view.component.js b/ui/app/components/app/wallet-view/wallet-view.component.js index ceccfea51bdc..dc3abf25933e 100644 --- a/ui/app/components/app/wallet-view/wallet-view.component.js +++ b/ui/app/components/app/wallet-view/wallet-view.component.js @@ -7,7 +7,7 @@ import AccountDetails from '../account-details' const { checksumAddress } = require('../../../helpers/utils/util') const TokenList = require('../token-list') -const { ADD_TOKEN_ROUTE } = require('../../../helpers/constants/routes') +const { ADD_TOKEN_ROUTE, CONNECTED_ROUTE } = require('../../../helpers/constants/routes') export default class WalletView extends Component { static contextTypes = { @@ -91,6 +91,18 @@ export default class WalletView extends Component { ) } + showConnectedSites = () => { + const { + sidebarOpen, + hideSidebar, + history, + } = this.props + history.push(CONNECTED_ROUTE) + if (sidebarOpen) { + hideSidebar() + } + } + render () { const { responsiveDisplayClassname, @@ -124,6 +136,7 @@ export default class WalletView extends Component { label={label} checksummedAddress={checksummedAddress} name={identities[selectedAddress].name} + showConnectedSites={this.showConnectedSites} /> {this.renderWalletBalance()} diff --git a/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js b/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js new file mode 100644 index 000000000000..13b3e93d783a --- /dev/null +++ b/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js @@ -0,0 +1,42 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' + +export default class IconWithFallback extends PureComponent { + static propTypes = { + icon: PropTypes.string, + name: PropTypes.string, + } + + static defaultProps = { + name: '', + icon: null, + } + + state = { + iconError: false, + } + + render () { + const { icon, name } = this.props + + return ( +
    +
    + { !this.state.iconError && icon + ? ( + this.setState({ iconError: true })} + /> + ) + : ( + + { name.length ? name.charAt(0).toUpperCase() : '' } + + ) + } +
    + ) + } +} diff --git a/ui/app/components/ui/icon-with-fallback/index.js b/ui/app/components/ui/icon-with-fallback/index.js new file mode 100644 index 000000000000..8c1f9a154bfe --- /dev/null +++ b/ui/app/components/ui/icon-with-fallback/index.js @@ -0,0 +1 @@ +export { default } from './icon-with-fallback.component' diff --git a/ui/app/components/ui/icon-with-fallback/index.scss b/ui/app/components/ui/icon-with-fallback/index.scss new file mode 100644 index 000000000000..02ffe371dfde --- /dev/null +++ b/ui/app/components/ui/icon-with-fallback/index.scss @@ -0,0 +1,30 @@ +.icon-with-fallback { + &__identicon-container { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 32px; + width: 32px; + } + + &__identicon-border { + height: 32px; + width: 32px; + border-radius: 50%; + border: 1px solid #F2F3F4; + position: absolute; + background: #FFFFFF; + } + + &__identicon { + width: 24px; + height: 24px; + z-index: 1; + + &--default { + z-index: 1; + color: black; + } + } +} 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 da8da45d1a06..338df83d894a 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 @@ -14,6 +14,7 @@ export default class PageContainerFooter extends Component { disabled: PropTypes.bool, submitButtonType: PropTypes.string, hideCancel: PropTypes.bool, + buttonSizeLarge: PropTypes.bool, } static contextTypes = { @@ -31,6 +32,7 @@ export default class PageContainerFooter extends Component { submitButtonType, hideCancel, cancelButtonType, + buttonSizeLarge = false, } = this.props return ( @@ -40,7 +42,7 @@ export default class PageContainerFooter extends Component { {!hideCancel && ( -
    -
    - - ) - } - - renderApprovedOriginsList () { - const { t } = this.context - const { approvedOrigins, rejectProviderRequestByOrigin, showClearApprovalModal } = this.props - const approvedEntries = Object.entries(approvedOrigins) - const approvalListEmpty = approvedEntries.length === 0 - - return ( -
    -
    - { t('connected') } - - { t('connectedDescription') } - -
    -
    - { - approvalListEmpty - ?
    - : null - } - { - approvedEntries.map(([origin, { siteTitle, siteImage }]) => ( - { - rejectProviderRequestByOrigin(origin) - }} - /> - )) - } -
    -
    - -
    -
    - ) - } - - render () { - return ( -
    - { this.renderNewOriginInput() } - { this.renderApprovedOriginsList() } -
    - ) - } -} diff --git a/ui/app/pages/settings/connections-tab/connections-tab.container.js b/ui/app/pages/settings/connections-tab/connections-tab.container.js deleted file mode 100644 index cf3efc2b46cb..000000000000 --- a/ui/app/pages/settings/connections-tab/connections-tab.container.js +++ /dev/null @@ -1,39 +0,0 @@ -import ConnectionsTab from './connections-tab.component' -import { compose } from 'recompose' -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { - approveProviderRequestByOrigin, - rejectProviderRequestByOrigin, - showModal, -} from '../../../store/actions' - -export const mapStateToProps = state => { - const { - activeTab, - metamask, - } = state - const { - approvedOrigins, - } = metamask - - return { - activeTab, - approvedOrigins, - } -} - -export const mapDispatchToProps = dispatch => { - return { - approveProviderRequestByOrigin: (origin) => dispatch(approveProviderRequestByOrigin(origin)), - rejectProviderRequestByOrigin: (origin) => dispatch(rejectProviderRequestByOrigin(origin)), - showClearApprovalModal: () => dispatch(showModal({ - name: 'CLEAR_APPROVED_ORIGINS', - })), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(ConnectionsTab) diff --git a/ui/app/pages/settings/connections-tab/index.js b/ui/app/pages/settings/connections-tab/index.js deleted file mode 100644 index b04f4e33a67a..000000000000 --- a/ui/app/pages/settings/connections-tab/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './connections-tab.container' diff --git a/ui/app/pages/settings/connections-tab/index.scss b/ui/app/pages/settings/connections-tab/index.scss deleted file mode 100644 index 249a7193f731..000000000000 --- a/ui/app/pages/settings/connections-tab/index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './connected-site-row/index'; diff --git a/ui/app/pages/settings/index.scss b/ui/app/pages/settings/index.scss index 19545eb51363..780b930e742f 100644 --- a/ui/app/pages/settings/index.scss +++ b/ui/app/pages/settings/index.scss @@ -4,8 +4,6 @@ @import 'settings-tab/index'; -@import 'connections-tab/index'; - @import 'contact-list-tab/index'; .settings-page { diff --git a/ui/app/pages/settings/settings.component.js b/ui/app/pages/settings/settings.component.js index b0ee55dc7f1c..12d395f31501 100644 --- a/ui/app/pages/settings/settings.component.js +++ b/ui/app/pages/settings/settings.component.js @@ -4,7 +4,6 @@ import { Switch, Route, matchPath, withRouter } from 'react-router-dom' import TabBar from '../../components/app/tab-bar' import c from 'classnames' import SettingsTab from './settings-tab' -import ConnectionsTab from './connections-tab' import NetworksTab from './networks-tab' import AdvancedTab from './advanced-tab' import InfoTab from './info-tab' @@ -15,7 +14,6 @@ import { ADVANCED_ROUTE, SECURITY_ROUTE, GENERAL_ROUTE, - CONNECTIONS_ROUTE, ABOUT_US_ROUTE, SETTINGS_ROUTE, NETWORKS_ROUTE, @@ -160,7 +158,6 @@ class SettingsPage extends PureComponent { - { + const { address, name, balance } = account + return { + address, + truncatedAddress: `${address.slice(0, 6)}...${address.slice(-4)}`, + addressLabel: `${name} (...${address.slice(address.length - 4)})`, + label: name, + balance, + } + }) + return accountsWithLabels +} + function getCurrentAccountWithSendEtherInfo (state) { const currentAddress = getSelectedAddress(state) const accounts = accountsWithSendEtherInfoSelector(state) @@ -353,6 +385,22 @@ function getCustomNonceValue (state) { return String(state.metamask.customNonceValue) } +function getPermissionsDescriptions (state) { + return state.metamask.permissionsDescriptions +} + +function getPermissionsRequests (state) { + return state.metamask.permissionsRequests +} + +function getDomainMetadata (state) { + return state.metamask.domainMetadata +} + +function getActiveTab (state) { + return state.activeTab +} + function getMetaMetricState (state) { return { network: getCurrentNetworkId(state), @@ -386,3 +434,144 @@ function getKnownMethodData (state, data) { function getFeatureFlags (state) { return state.metamask.featureFlags } + +function getFirstPermissionRequest (state) { + const requests = getPermissionsRequests(state) + return requests && requests[0] ? requests[0] : null +} + +function hasPermissionRequests (state) { + return Boolean(getFirstPermissionRequest(state)) +} + +function getPermissionsDomains (state) { + return state.metamask.domains +} + +function getAddressConnectedDomainMap (state) { + const { + domains, + domainMetadata, + } = state.metamask + + const addressConnectedIconMap = {} + + if (domains) { + Object.keys(domains).forEach(domainKey => { + const { permissions } = domains[domainKey] + const { icon, name } = domainMetadata[domainKey] || {} + permissions.forEach(perm => { + const caveats = perm.caveats || [] + const exposedAccountCaveat = caveats.find(caveat => caveat.name === 'exposedAccounts') + if (exposedAccountCaveat && exposedAccountCaveat.value && exposedAccountCaveat.value.length) { + exposedAccountCaveat.value.forEach(address => { + const nameToRender = name || domainKey + addressConnectedIconMap[address] = addressConnectedIconMap[address] + ? { ...addressConnectedIconMap[address], [domainKey]: { icon, name: nameToRender } } + : { [domainKey]: { icon, name: nameToRender } } + }) + } + }) + }) + } + + return addressConnectedIconMap +} + +function getDomainToConnectedAddressMap (state) { + const { domains = {} } = state.metamask + + const domainToConnectedAddressMap = mapObjectValues(domains, (_, { permissions }) => { + const ethAccountsPermissions = permissions.filter(permission => permission.parentCapability === 'eth_accounts') + const ethAccountsPermissionsExposedAccountAddresses = ethAccountsPermissions.map(permission => { + const caveats = permission.caveats + const exposedAccountsCaveats = caveats.filter(caveat => caveat.name === 'exposedAccounts') + const exposedAccountsAddresses = exposedAccountsCaveats.map(caveat => caveat.value[0]) + return exposedAccountsAddresses + }) + const allAddressesConnectedToDomain = ethAccountsPermissionsExposedAccountAddresses.reduce((acc, arrayOfAddresses) => { + return [ ...acc, ...arrayOfAddresses ] + }, []) + return allAddressesConnectedToDomain + }) + + return domainToConnectedAddressMap +} + +function getAddressConnectedToCurrentTab (state) { + const domainToConnectedAddressMap = getDomainToConnectedAddressMap(state) + const originOfCurrentTab = getOriginOfCurrentTab(state) + const addressesConnectedToCurrentTab = domainToConnectedAddressMap[originOfCurrentTab] + const addressConnectedToCurrentTab = addressesConnectedToCurrentTab && addressesConnectedToCurrentTab[0] + return addressConnectedToCurrentTab +} + +function getRenderablePermissionsDomains (state) { + const { + domains = {}, + domainMetadata, + permissionsHistory, + permissionsDescriptions, + selectedAddress, + } = state.metamask + + const renderableDomains = Object.keys(domains).reduce((acc, domainKey) => { + const { permissions } = domains[domainKey] + const permissionsWithCaveatsForSelectedAddress = permissions.filter(perm => { + const caveats = perm.caveats || [] + const exposedAccountCaveat = caveats.find(caveat => caveat.name === 'exposedAccounts') + const exposedAccountCaveatValue = exposedAccountCaveat && exposedAccountCaveat.value && exposedAccountCaveat.value.length + ? exposedAccountCaveat.value[0] + : {} + return exposedAccountCaveatValue === selectedAddress + }) + + if (permissionsWithCaveatsForSelectedAddress.length) { + const permissionKeys = permissions.map(permission => permission.parentCapability) + const { + name, + icon, + extensionId, + } = domainMetadata[domainKey] || {} + const permissionsHistoryForDomain = permissionsHistory[domainKey] || {} + const ethAccountsPermissionsForDomain = permissionsHistoryForDomain['eth_accounts'] || {} + const accountsLastConnectedTime = ethAccountsPermissionsForDomain.accounts || {} + const selectedAddressLastConnectedTime = accountsLastConnectedTime[selectedAddress] + + const lastConnectedTime = selectedAddressLastConnectedTime + ? formatDate(selectedAddressLastConnectedTime, 'yyyy-M-d') + : '' + + return [ ...acc, { + name: name || domainKey, + secondaryName: name ? domainKey : '', + icon, + key: domainKey, + lastConnectedTime, + permissionDescriptions: permissionKeys.map(permissionKey => permissionsDescriptions[permissionKey]), + extensionId, + }] + } else { + return acc + } + }, []) + + return renderableDomains +} + +function getOriginOfCurrentTab (state) { + const { activeTab } = state + return activeTab && activeTab.url && getOriginFromUrl(activeTab.url) +} + +function getLastConnectedInfo (state) { + const { permissionsHistory = {} } = state.metamask + const lastConnectedInfoData = Object.keys(permissionsHistory).reduce((acc, origin) => { + const ethAccountsHistory = JSON.parse(JSON.stringify(permissionsHistory[origin]['eth_accounts'])) + return { + ...acc, + [origin]: ethAccountsHistory.accounts, + } + }, {}) + return lastConnectedInfoData +} diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index d6c29fcd6759..a09548f0f104 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -328,7 +328,6 @@ const actions = { setUseNativeCurrencyAsPrimaryCurrencyPreference, setShowFiatConversionOnTestnetsPreference, setAutoLogoutTimeLimit, - unsetMigratedPrivacyMode, // Onboarding setCompletedOnboarding, @@ -352,9 +351,12 @@ const actions = { createSpeedUpTransaction, createRetryTransaction, - approveProviderRequestByOrigin, - rejectProviderRequestByOrigin, - clearApprovedOrigins, + // Permissions + approvePermissionsRequest, + clearPermissions, + rejectPermissionsRequest, + removePermissionsFor, + legacyExposeAccounts, setFirstTimeFlowType, SET_FIRST_TIME_FLOW_TYPE: 'SET_FIRST_TIME_FLOW_TYPE', @@ -395,6 +397,13 @@ const actions = { turnThreeBoxSyncingOnAndInitialize, tryReverseResolveAddress, + + getRequestAccountTabIds, + getCurrentWindowTab, + SET_REQUEST_ACCOUNT_TABS: 'SET_REQUEST_ACCOUNT_TABS', + SET_CURRENT_WINDOW_TAB: 'SET_CURRENT_WINDOW_TAB', + getOpenMetamaskTabsIds, + SET_OPEN_METAMASK_TAB_IDS: 'SET_OPEN_METAMASK_TAB_IDS', } module.exports = actions @@ -2709,24 +2718,59 @@ function setPendingTokens (pendingTokens) { } } -function approveProviderRequestByOrigin (origin) { +// Permissions + +/** + * Approves the permission requests with the given IDs. + * @param {string} requestId - The id of the permissions request. + * @param {string[]} accounts - The accounts to expose, if any. + */ +function approvePermissionsRequest (requestId, accounts) { return () => { - background.approveProviderRequestByOrigin(origin) + background.approvePermissionsRequest(requestId, accounts) } } -function rejectProviderRequestByOrigin (origin) { +/** + * Rejects the permission requests with the given IDs. + * @param {Array} requestId + */ +function rejectPermissionsRequest (requestId) { return () => { - background.rejectProviderRequestByOrigin(origin) + background.rejectPermissionsRequest(requestId) } } -function clearApprovedOrigins () { +/** + * Exposes the given account(s) to the given origin. + * Call ONLY as a result of direct user action. + */ +function legacyExposeAccounts (origin, accounts) { return () => { - background.clearApprovedOrigins() + return background.legacyExposeAccounts(origin, accounts) } } +/** + * Clears the given permissions for the given origin. + */ +function removePermissionsFor (domains) { + return () => { + background.removePermissionsFor(domains) + } +} + +/** + * Clears all permissions for all domains. + */ +function clearPermissions () { + return () => { + background.clearPermissions() + } +} + +// //// + function setFirstTimeFlowType (type) { return (dispatch) => { log.debug(`background.setFirstTimeFlowType`) @@ -2847,12 +2891,6 @@ function getTokenParams (tokenAddress) { } } -function unsetMigratedPrivacyMode () { - return () => { - background.unsetMigratedPrivacyMode() - } -} - function setSeedPhraseBackedUp (seedPhraseBackupState) { return (dispatch) => { log.debug(`background.setSeedPhraseBackedUp`) @@ -2990,3 +3028,46 @@ function getNextNonce () { }) } } + +function setRequestAccountTabIds (requestAccountTabIds) { + return { + type: actions.SET_REQUEST_ACCOUNT_TABS, + value: requestAccountTabIds, + } +} + +function getRequestAccountTabIds () { + return async (dispatch) => { + const requestAccountTabIds = await pify(background.getRequestAccountTabIds).call(background) + dispatch(setRequestAccountTabIds(requestAccountTabIds)) + } +} + +function setOpenMetamaskTabsIDs (openMetaMaskTabIDs) { + return { + type: actions.SET_OPEN_METAMASK_TAB_IDS, + value: openMetaMaskTabIDs, + } +} + +function getOpenMetamaskTabsIds () { + return async (dispatch) => { + const openMetaMaskTabIDs = await pify(background.getOpenMetamaskTabsIds).call(background) + dispatch(setOpenMetamaskTabsIDs(openMetaMaskTabIDs)) + } +} + +function setCurrentWindowTab (currentWindowTab) { + return { + type: actions.SET_CURRENT_WINDOW_TAB, + value: currentWindowTab, + } +} + + +function getCurrentWindowTab () { + return async (dispatch) => { + const currentWindowTab = await global.platform.currentTab() + dispatch(setCurrentWindowTab(currentWindowTab)) + } +} diff --git a/yarn.lock b/yarn.lock index edd2a97fb86d..86748862727c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10075,7 +10075,7 @@ eth-hd-keyring@^3.4.0: events "^1.1.1" xtend "^4.0.1" -eth-json-rpc-errors@^1.0.1, eth-json-rpc-errors@^1.1.0: +eth-json-rpc-errors@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.0.tgz#2a4291fb20c0483c99b53286a814ed14ca4efb2e" integrity sha512-AAA76BmwwSR5Mws+ivZUYxoDwMygDuMWxSTEmqDXhRPTExSWe5wuJLT/rSfvPSy9+owSudy67JmyRQ02RAOOYQ== @@ -12164,7 +12164,7 @@ fuse.js@^3.4.4: resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.5.tgz#8954fb43f9729bd5dbcb8c08f251db552595a7a6" integrity sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ== -gaba@^1.9.0: +gaba@^1.6.0, gaba@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/gaba/-/gaba-1.9.0.tgz#ccd9f99c56687b5acd39f9e3ceb435b2a59b6aa1" integrity sha512-HoVreAdZssL0jNHuzZ7WP+YKZ0riu44jVDWxhQ9hsgPuzxbVEsz9fO/HDxqAdNZS1Cswayq6+ciZ3HSCFWMKbQ== @@ -14247,6 +14247,11 @@ interpret@^1.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== +intersect-objects@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/intersect-objects/-/intersect-objects-1.0.0.tgz#b7630d28994b89b0f04d44728106136549ce816e" + integrity sha512-MS1xypHKJhWopnJgn4IbitVvt2vFy2KjINQJAPhAtDejZ+ZbMDfyPc6JsS/mWFRt9Eoku4A4usE4f2loEOoeKQ== + into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" @@ -17596,12 +17601,12 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash@4.17.14, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.10, lodash@~4.17.2, lodash@~4.17.4: +lodash@4.17.14, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.10, lodash@~4.17.2, lodash@~4.17.4: version "4.17.14" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== -lodash@=3.10.1, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: +lodash@=3.10.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -18213,12 +18218,14 @@ mersenne-twister@^1.0.1: resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a" integrity sha1-+RZhjuQ9cXnvz2Qb7EUx65Zwl4o= -metamask-inpage-provider@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/metamask-inpage-provider/-/metamask-inpage-provider-3.0.0.tgz#3b9d4bae6f67962b6a7b1a9ee1efaf424f67b6f4" - integrity sha512-44bBCbQwcFF/XGaXSweCWHJaslKhJEFgvcHdxZf9Fm1QfK7VN4U3iAI0BVOLAIkRg0xV3w7xYGLpx2cM1BU7Qw== +metamask-inpage-provider@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/metamask-inpage-provider/-/metamask-inpage-provider-4.0.2.tgz#50d9e46b5fdd6610ce185a165004e3c6b762dbb3" + integrity sha512-GXoMa7rP+fx9CriCA+RPHjvJJpfy9531eRdMvbDKv0q95/1pvtzYkj6BdzjxtbM91n4zYl6tmeKDILu+le9Qog== dependencies: - json-rpc-engine "^5.1.3" + eth-json-rpc-errors "^2.0.0" + fast-deep-equal "^2.0.1" + json-rpc-engine "^5.1.5" json-rpc-middleware-stream "^2.1.1" loglevel "^1.6.1" obj-multiplex "^1.0.0" @@ -18890,6 +18897,11 @@ nanoid@^2.0.0: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.0.3.tgz#dde999e173bc9d7bd2ee2746b89909ade98e075e" integrity sha512-NbaoqdhIYmY6FXDRB4eYtDVC9Z9eCbn8TyaiC16LNKtpPv/aqa0tOPD8y6gNE4yUNnaZ7LLhYtXOev/6+cBtfw== +nanoid@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.6.tgz#0665418f692e54cf44f34d4010761f3240a03314" + integrity sha512-2NDzpiuEy3+H0AVtdt8LoFi7PnqkOnIzYmJQp7xsEU6VexLluHQwKREuiz57XaQC5006seIadPrIZJhyS2n7aw== + nanomatch@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" @@ -23669,6 +23681,21 @@ rn-host-detect@^1.1.5: resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.1.5.tgz#fbecb982b73932f34529e97932b9a63e58d8deb6" integrity sha512-ufk2dFT3QeP9HyZ/xTuMtW27KnFy815CYitJMqQm+pgG3ZAtHBsrU8nXizNKkqXGy3bQmhEoloVbrfbvMJMqkg== +rpc-cap@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rpc-cap/-/rpc-cap-1.0.1.tgz#c19f6651d9d003256c73831422e0bd60b4fa8b55" + integrity sha512-M75F5IfohYkwGvitWmstimP9OL+9h10m1ZRC2zCB1Nli4EPzL8n5re58xlrcOnwOO38FdSSPfcwcCzMuVT8K2g== + dependencies: + clone "^2.1.2" + eth-json-rpc-errors "^2.0.0" + fast-deep-equal "^2.0.1" + gaba "^1.6.0" + intersect-objects "^1.0.0" + is-subset "^0.1.1" + json-rpc-engine "^5.1.3" + obs-store "^4.0.3" + uuid "^3.3.2" + rsa-pem-to-jwk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/rsa-pem-to-jwk/-/rsa-pem-to-jwk-1.1.3.tgz#245e76bdb7e7234cfee7ca032d31b54c38fab98e" @@ -23804,6 +23831,11 @@ safe-json-parse@~1.0.1: resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= +safe-json-stringify@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" + integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -27220,7 +27252,7 @@ uuid@3.2.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA== -uuid@3.3.2, uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.2.2, uuid@^3.3.2: +uuid@3.3.2, uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.2.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== @@ -27230,7 +27262,7 @@ uuid@^2.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho= -uuid@^3.3.3: +uuid@^3.3.2, uuid@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== From ff85173329b29c7cdcd82a2b13790a5f50d1a5ba Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Thu, 28 Nov 2019 19:42:29 +0000 Subject: [PATCH 87/88] Version v7.7.0 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a37d5c989bac..5670c0b25ec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## Current Develop Branch + +## 7.7.0 Thu Nov 28 2019 - [#7480](https://github.com/MetaMask/metamask-extension/pull/7480): Fixed link on root README.md ## 7.6.1 Tue Nov 19 2019 diff --git a/app/manifest.json b/app/manifest.json index f9e25ceda656..58d4e1308159 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "7.6.1", + "version": "7.7.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 4100c1c104f0f44e65b3b2fadcdf45bf4c0f9756 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Thu, 28 Nov 2019 16:23:41 -0330 Subject: [PATCH 88/88] Update changelog for v7.7.0 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5670c0b25ec2..65b25c13d786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,17 @@ ## Current Develop Branch ## 7.7.0 Thu Nov 28 2019 +- [#7004](https://github.com/MetaMask/metamask-extension/pull/7004): Connect distinct accounts per site - [#7480](https://github.com/MetaMask/metamask-extension/pull/7480): Fixed link on root README.md +- [#7482](https://github.com/MetaMask/metamask-extension/pull/7482): Update Wyre ETH purchase url +- [#7484](https://github.com/MetaMask/metamask-extension/pull/7484): Ensure transactions are shown in the order they are received +- [#7491](https://github.com/MetaMask/metamask-extension/pull/7491): Update gas when token is changed on the send screen +- [#7501](https://github.com/MetaMask/metamask-extension/pull/7501): Fix accessibility of first-time-flow terms checkboxes +- [#7502](https://github.com/MetaMask/metamask-extension/pull/7502): Fix chainId for non standard networks +- [#7579](https://github.com/MetaMask/metamask-extension/pull/7579): Fix timing of DAI migration notifications after dismissal +- [#7519](https://github.com/MetaMask/metamask-extension/pull/7519): Fixing hardware connect error display +- [#7558](https://github.com/MetaMask/metamask-extension/pull/7558): Use localized messages for NotificationModal buttons +- [#7488](https://github.com/MetaMask/metamask-extension/pull/7488): Fix text overlap when expanding transaction ## 7.6.1 Tue Nov 19 2019 - [#7475](https://github.com/MetaMask/metamask-extension/pull/7475): Add 'Remind Me Later' to the Maker notification