From ed841f71965771b07f85db11436ed05d7adbbcc1 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 11:09:38 +0300 Subject: [PATCH 01/13] Increase max token symbol length up to 12 --- CHANGELOG.md | 1 + old-ui/app/components/add-token/add-token.component.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c68aae7..a34d48bc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- [#366](https://github.com/poanetwork/nifty-wallet/pull/366) - (Fix) Increase max token symbol length up to 12 - [#363](https://github.com/poanetwork/nifty-wallet/pull/363) - (Fix) token decimals display in pending tx screen ## 5.0.2 Thu Apr 16 2020 diff --git a/old-ui/app/components/add-token/add-token.component.js b/old-ui/app/components/add-token/add-token.component.js index 546fca16a..9845960ee 100644 --- a/old-ui/app/components/add-token/add-token.component.js +++ b/old-ui/app/components/add-token/add-token.component.js @@ -368,9 +368,9 @@ export default class AddTokenScreen extends Component { } const symbolLen = symbol.trim().length - const validSymbol = symbolLen > 0 && symbolLen < 10 + const validSymbol = symbolLen > 0 && symbolLen < 12 if (!validSymbol) { - msg += 'Symbol must be between 0 and 10 characters.' + msg += 'Symbol must be between 0 and 12 characters.' } let ownAddress = identitiesList.includes(standardAddress) @@ -527,8 +527,8 @@ export default class AddTokenScreen extends Component { const symbolLength = customSymbol.length let customSymbolError = null - if (symbolLength <= 0 || symbolLength >= 10) { - customSymbolError = 'Symbol must be between 0 and 10 characters.' /* this.context.t('symbolBetweenZeroTen')*/ + if (symbolLength <= 0 || symbolLength >= 12) { + customSymbolError = 'Symbol must be between 0 and 12 characters.' /* this.context.t('symbolBetweenZeroTen')*/ } this.setState({ customSymbol, customSymbolError }) From 051813f1f3b6ccaa24788d829a9ceed400c4c0f0 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 13:10:04 +0300 Subject: [PATCH 02/13] Extend available Symbol length to 22 to support yDAI+yUSDC+yUSDT+yTUSD --- old-ui/app/components/add-token/add-token.component.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/old-ui/app/components/add-token/add-token.component.js b/old-ui/app/components/add-token/add-token.component.js index 9845960ee..4bbb92583 100644 --- a/old-ui/app/components/add-token/add-token.component.js +++ b/old-ui/app/components/add-token/add-token.component.js @@ -368,9 +368,9 @@ export default class AddTokenScreen extends Component { } const symbolLen = symbol.trim().length - const validSymbol = symbolLen > 0 && symbolLen < 12 + const validSymbol = symbolLen > 0 && symbolLen < 23 if (!validSymbol) { - msg += 'Symbol must be between 0 and 12 characters.' + msg += 'Symbol must be between 0 and 23 characters.' } let ownAddress = identitiesList.includes(standardAddress) @@ -527,8 +527,8 @@ export default class AddTokenScreen extends Component { const symbolLength = customSymbol.length let customSymbolError = null - if (symbolLength <= 0 || symbolLength >= 12) { - customSymbolError = 'Symbol must be between 0 and 12 characters.' /* this.context.t('symbolBetweenZeroTen')*/ + if (symbolLength <= 0 || symbolLength >= 23) { + customSymbolError = 'Symbol must be between 0 and 23 characters.' /* this.context.t('symbolBetweenZeroTen')*/ } this.setState({ customSymbol, customSymbolError }) From 1fa277ba8d368148610b63c9e3911b00aec50f19 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 13:28:29 +0300 Subject: [PATCH 03/13] Keystore file import without password --- old-ui/app/accounts/import/json.js | 21 ++++++++------------- package-lock.json | 13 ++++++------- package.json | 2 +- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/old-ui/app/accounts/import/json.js b/old-ui/app/accounts/import/json.js index 60dd2bfd5..6d0b83bf7 100644 --- a/old-ui/app/accounts/import/json.js +++ b/old-ui/app/accounts/import/json.js @@ -1,9 +1,9 @@ const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +import { connect } from 'react-redux' const actions = require('../../../../ui/app/actions') const FileInput = require('react-simple-file-input').default -const PropTypes = require('prop-types') +import PropTypes from 'prop-types' class JsonImportSubview extends Component { constructor (props) { @@ -75,31 +75,26 @@ class JsonImportSubview extends Component { } createNewKeychain () { + const { displayWarning, importNewJsonAccount } = this.props const { fileContents } = this.state if (!fileContents) { const message = 'You must select a file to import.' - return this.props.displayWarning(message) + return displayWarning(message) } const passwordInput = document.getElementById('json-password-box') const password = passwordInput.value - if (!password) { - const message = 'You must enter a password for the selected file.' - return this.props.displayWarning(message) - } - - this.props.importNewAccount([ fileContents, password ]) - // JS runtime requires caught rejections but failures are handled by Redux - .catch() + importNewJsonAccount([ fileContents, password ]) + .catch((err) => err && displayWarning(err.message || err)) } } JsonImportSubview.propTypes = { error: PropTypes.string, displayWarning: PropTypes.func, - importNewAccount: PropTypes.func, + importNewJsonAccount: PropTypes.func, } const mapStateToProps = state => { @@ -112,7 +107,7 @@ const mapDispatchToProps = dispatch => { return { goHome: () => dispatch(actions.goHome()), displayWarning: warning => dispatch(actions.displayWarning(warning)), - importNewAccount: options => dispatch(actions.importNewAccount('JSON File', options)), + importNewJsonAccount: options => dispatch(actions.importNewAccount('JSON File', options)), } } diff --git a/package-lock.json b/package-lock.json index 5f20689de..cece4756e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11369,8 +11369,8 @@ } }, "eth-hd-keyring": { - "version": "github:vbaranov/eth-hd-keyring#2c761c59e7cc978da6a612bf6d9833d8ea95efb5", - "from": "github:vbaranov/eth-hd-keyring#2.1.0", + "version": "github:vbaranov/eth-hd-keyring#487eec0e853cee95723f2efede99a0c722826b34", + "from": "github:vbaranov/eth-hd-keyring#2.1.1", "requires": { "bip39": "^2.2.0", "eth-sig-util": "^2.4.4", @@ -11632,19 +11632,18 @@ } }, "eth-keychain-controller": { - "version": "github:vbaranov/KeyringController#a39087f825b1cbffc663ef002d7d66ade3c5944b", - "from": "github:vbaranov/KeyringController#5.2.0", + "version": "github:vbaranov/KeyringController#7c32b3d0d7a35d09d2a85f8f339f499e3df44811", + "from": "github:vbaranov/KeyringController#5.3.1", "requires": { "bip39": "^2.4.0", "bluebird": "^3.5.0", "browser-passworder": "^2.0.3", - "eth-hd-keyring": "github:vbaranov/eth-hd-keyring#2.1.0", + "eth-hd-keyring": "github:vbaranov/eth-hd-keyring#2.1.1", "eth-sig-util": "^1.4.0", "eth-simple-keyring": "^3.5.0", "ethereumjs-util": "^5.1.2", "loglevel": "^1.5.0", - "obs-store": "^4.0.3", - "promise-filter": "^1.1.0" + "obs-store": "^4.0.3" }, "dependencies": { "eth-sig-util": { diff --git a/package.json b/package.json index b6e4e0089..d29ed6c0b 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "eth-json-rpc-filters": "github:poanetwork/eth-json-rpc-filters#3.0.2", "eth-json-rpc-infura": "^4.0.2", "eth-json-rpc-middleware": "^4.4.1", - "eth-keychain-controller": "github:vbaranov/KeyringController#5.2.0", + "eth-keychain-controller": "github:vbaranov/KeyringController#5.3.1", "eth-ledger-bridge-keyring": "github:vbaranov/eth-ledger-bridge-keyring#0.1.0-clear-accounts-flag", "eth-method-registry": "^1.0.0", "eth-net-props": "^1.0.33", From 2b0e11338f7f9d187c46b8ee196db49fade1e85e Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 13:37:26 +0300 Subject: [PATCH 04/13] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c68aae7..218fefeb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- [#368](https://github.com/poanetwork/nifty-wallet/pull/368) - (Fix) Ability to import Keystore file if it is not secured by password - [#363](https://github.com/poanetwork/nifty-wallet/pull/363) - (Fix) token decimals display in pending tx screen ## 5.0.2 Thu Apr 16 2020 From b20644da1e1c5160232e3f906aa6b708b82ba122 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 16:09:40 +0300 Subject: [PATCH 05/13] RSK: fix GasPrice calculation (changed output of minimumGasPrice) --- app/scripts/metamask-controller.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6f4d4c941..e9db53a8d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1886,7 +1886,7 @@ module.exports = class MetamaskController extends EventEmitter { resolve(gasPrice) } } else if (isRSK) { - gasPrice = this.getGasPriceFromLastBlockRSK(networkId) + gasPrice = this.getGasPriceFromLastBlockRSK() resolve(gasPrice) } else { gasPrice = this.getGasPriceFromBlocks(networkId) @@ -1937,7 +1937,7 @@ module.exports = class MetamaskController extends EventEmitter { * Related issue: https://github.com/poanetwork/nifty-wallet/issues/301 * @returns {string} A hex representation of the suggested wei gas price. */ - getGasPriceFromLastBlockRSK (networkId) { + getGasPriceFromLastBlockRSK () { const { recentBlocksController } = this const { recentBlocks } = recentBlocksController.store.getState() @@ -1946,10 +1946,8 @@ module.exports = class MetamaskController extends EventEmitter { const gasPrice = recentBlock && recentBlock.minimumGasPrice - const gasPriceInt = parseInt(gasPrice, 10) - - if (gasPriceInt !== 0) { - return '0x' + gasPriceInt.toString(16) + if (gasPrice !== 0) { + return gasPrice } else { return '0x' + GWEI_BN.toString(16) } From 1799d54fd61c6cfaffabc277119cad89d83b67ee Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 16:16:09 +0300 Subject: [PATCH 06/13] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffddd2cb7..248a2feef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- [#369](https://github.com/poanetwork/nifty-wallet/pull/369) - (Fix) RSK: fix GasPrice calculation (changed interface of minimumGasPrice - hex instead of integer) - [#368](https://github.com/poanetwork/nifty-wallet/pull/368) - (Fix) Ability to import Keystore file if it is not secured by password - [#366](https://github.com/poanetwork/nifty-wallet/pull/366) - (Fix) Increase max token symbol length up to 12 - [#363](https://github.com/poanetwork/nifty-wallet/pull/363) - (Fix) token decimals display in pending tx screen From 18d64749ae4e5c76dff0c5b227a9b5398d9e7960 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Wed, 29 Apr 2020 16:42:06 +0300 Subject: [PATCH 07/13] Fix unit tests --- app/scripts/metamask-controller.js | 6 +++--- test/unit/app/controllers/metamask-controller-test.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index e9db53a8d..3421e07de 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1944,9 +1944,9 @@ module.exports = class MetamaskController extends EventEmitter { const recentBlock = recentBlocks .sort((block1, block2) => block1.number - block2.number)[recentBlocks.length - 1] - const gasPrice = recentBlock && recentBlock.minimumGasPrice - - if (gasPrice !== 0) { + const gasPrice = recentBlock && recentBlock.minimumGasPrice && recentBlock.minimumGasPrice.toString() + + if (gasPrice !== '0x' && gasPrice !== '0x0' && gasPrice !== '') { return gasPrice } else { return '0x' + GWEI_BN.toString(16) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 0bfbb5a75..6ceb5da81 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -161,9 +161,9 @@ describe('MetaMaskController', function () { getState: () => { return { recentBlocks: [ - { number: '0x1', minimumGasPrice: '59240010' }, - { number: '0x2', minimumGasPrice: '59240005' }, - { number: '0x3', minimumGasPrice: '59240000' }, + { number: '0x1', minimumGasPrice: '0x387ee48' }, + { number: '0x2', minimumGasPrice: '0x387ee42' }, + { number: '0x3', minimumGasPrice: '0x387ee40' }, ], } }, @@ -175,7 +175,7 @@ describe('MetaMaskController', function () { getState: () => { return { recentBlocks: [ - { number: '0x4', minimumGasPrice: '0' }, + { number: '0x4', minimumGasPrice: '0x' }, ], } }, From 5b11748cf37c3e02f5865ba15164266b3341915b Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Thu, 30 Apr 2020 12:45:54 +0300 Subject: [PATCH 08/13] Update RSK contracts metadata repo --- app/scripts/controllers/detect-tokens.js | 4 ++-- gulpfile.js | 4 ++-- .../add-token/token-search/token-search.component.js | 4 ++-- old-ui/app/components/token-list.js | 4 ++-- old-ui/lib/icon-factory.js | 4 ++-- package-lock.json | 12 ++++++++---- package.json | 4 ++-- ui/app/token-util.js | 4 ++-- 8 files changed, 22 insertions(+), 18 deletions(-) diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index 80381f402..f468213fb 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -1,8 +1,8 @@ import Web3 from 'web3' import contractsETH from 'eth-contract-metadata' import contractsPOA from 'poa-contract-metadata' -import contractsRSK from 'rsk-contract-metadata' -import contractsRSKTest from 'rsk-test-contract-metadata' +import contractsRSK from '@rsksmart/rsk-contract-metadata' +import contractsRSKTest from '@rsksmart/rsk-testnet-contract-metadata' import { warn } from 'loglevel' const { MAINNET, POA, RSK, RSK_TESTNET } = require('./network/enums') // By default, poll every 3 minutes diff --git a/gulpfile.js b/gulpfile.js index d4508336b..9e5326c2a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -73,11 +73,11 @@ createCopyTasks('contractImagesPOA', { destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractPOA`), }) createCopyTasks('contractImagesRSK', { - source: './node_modules/rsk-contract-metadata/images/', + source: './node_modules/@rsksmart/rsk-contract-metadata/images/', destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractRSK`), }) createCopyTasks('contractImagesRSKTest', { - source: './node_modules/rsk-test-contract-metadata/images/', + source: './node_modules/@rsksmart/rsk-testnet-contract-metadata/images/', destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractRSKTest`), }) createCopyTasks('fonts', { diff --git a/old-ui/app/components/add-token/token-search/token-search.component.js b/old-ui/app/components/add-token/token-search/token-search.component.js index e3a36b8b9..c17828655 100644 --- a/old-ui/app/components/add-token/token-search/token-search.component.js +++ b/old-ui/app/components/add-token/token-search/token-search.component.js @@ -2,8 +2,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import contractMapETH from 'eth-contract-metadata' import contractMapPOA from 'poa-contract-metadata' -import contractMapRSK from 'rsk-contract-metadata' -import contractMapRSKTest from 'rsk-test-contract-metadata' +import contractMapRSK from '@rsksmart/rsk-contract-metadata' +import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata' import Fuse from 'fuse.js' import InputAdornment from '@material-ui/core/InputAdornment' import TextField from '../../../../../ui/app/components/text-field' diff --git a/old-ui/app/components/token-list.js b/old-ui/app/components/token-list.js index 95550b545..eee577044 100644 --- a/old-ui/app/components/token-list.js +++ b/old-ui/app/components/token-list.js @@ -19,8 +19,8 @@ const defaultTokens = [] const contractsETH = require('eth-contract-metadata') const contractsPOA = require('poa-contract-metadata') -const contractsRSK = require('rsk-contract-metadata') -const contractsRSKTest = require('rsk-test-contract-metadata') +const contractsRSK = require('@rsksmart/rsk-contract-metadata') +const contractsRSKTest = require('@rsksmart/rsk-testnet-contract-metadata') for (const address in contractsETH) { const contract = contractsETH[address] if (contract.erc20) { diff --git a/old-ui/lib/icon-factory.js b/old-ui/lib/icon-factory.js index 74ef65e56..9db318f6f 100644 --- a/old-ui/lib/icon-factory.js +++ b/old-ui/lib/icon-factory.js @@ -1,8 +1,8 @@ import { isValidAddress } from 'ethereumjs-util' import contractMapETH from 'eth-contract-metadata' import contractMapPOA from 'poa-contract-metadata' -import contractMapRSK from 'rsk-contract-metadata' -import contractMapRSKTest from 'rsk-test-contract-metadata' +import contractMapRSK from '@rsksmart/rsk-contract-metadata' +import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata' import { MAINNET_CODE, POA_CODE, RSK_CODE, RSK_TESTNET_CODE } from '../../app/scripts/controllers/network/enums' const colors = require('../../colors') const { toChecksumAddress, getTokenImageFolder } = require('../app/util') diff --git a/package-lock.json b/package-lock.json index cece4756e..e3f52d9e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1966,6 +1966,14 @@ "react-lifecycles-compat": "^3.0.4" } }, + "@rsksmart/rsk-contract-metadata": { + "version": "github:rsksmart/rsk-contract-metadata#d7913739e5ee93dac8667043e2c17b0ef339c206", + "from": "github:rsksmart/rsk-contract-metadata#master" + }, + "@rsksmart/rsk-testnet-contract-metadata": { + "version": "github:rsksmart/rsk-testnet-contract-metadata#2b89e70d36d2aa58cae68ac817debbf3c451690a", + "from": "github:rsksmart/rsk-testnet-contract-metadata#master" + }, "@sentry/cli": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.52.0.tgz", @@ -49791,10 +49799,6 @@ "uuid": "^3.3.2" } }, - "rsk-contract-metadata": { - "version": "github:rsksmart/rsk-contract-metadata#262495abfa6ff83fb9cd46c7fb9f85690e4e5d4b", - "from": "github:rsksmart/rsk-contract-metadata#master" - }, "rsk-test-contract-metadata": { "version": "github:rsksmart/rsk-testnet-contract-metadata#69ff2d652b286648e9264e2689009e940ec7ccad", "from": "github:rsksmart/rsk-testnet-contract-metadata#master" diff --git a/package.json b/package.json index d29ed6c0b..e7d4a39c4 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,8 @@ "dependencies": { "@babel/runtime": "^7.5.5", "@material-ui/core": "^4.1.1", + "@rsksmart/rsk-contract-metadata": "github:rsksmart/rsk-contract-metadata#master", + "@rsksmart/rsk-testnet-contract-metadata": "github:rsksmart/rsk-testnet-contract-metadata#master", "@zxing/library": "^0.8.0", "abi-decoder": "^1.2.0", "asmcrypto.js": "0.22.0", @@ -198,8 +200,6 @@ "reselect": "^3.0.1", "rockicon": "^1.0.0", "rpc-cap": "^2.0.0", - "rsk-contract-metadata": "github:rsksmart/rsk-contract-metadata#master", - "rsk-test-contract-metadata": "github:rsksmart/rsk-testnet-contract-metadata#master", "sandwich-expando": "^1.1.3", "semaphore": "^1.0.5", "semver": "^5.4.1", diff --git a/ui/app/token-util.js b/ui/app/token-util.js index 2e516bf4d..d72f042e8 100644 --- a/ui/app/token-util.js +++ b/ui/app/token-util.js @@ -2,8 +2,8 @@ import log from 'loglevel' import BigNumber from 'bignumber.js' import contractMapETH from 'eth-contract-metadata' import contractMapPOA from 'poa-contract-metadata' -import contractMapRSK from 'rsk-contract-metadata' -import contractMapRSKTest from 'rsk-test-contract-metadata' +import contractMapRSK from '@rsksmart/rsk-contract-metadata' +import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata' const util = require('./util') const casedContractMapETH = Object.keys(contractMapETH).reduce((acc, base) => { From dcc03caad12112137f1f5aacbe2947cb48e21f0c Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Thu, 30 Apr 2020 12:53:43 +0300 Subject: [PATCH 09/13] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 248a2feef..0c494e51d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- [#372](https://github.com/poanetwork/nifty-wallet/pull/372) - (Chore) Update RSK contracts metadata repo - [#369](https://github.com/poanetwork/nifty-wallet/pull/369) - (Fix) RSK: fix GasPrice calculation (changed interface of minimumGasPrice - hex instead of integer) - [#368](https://github.com/poanetwork/nifty-wallet/pull/368) - (Fix) Ability to import Keystore file if it is not secured by password - [#366](https://github.com/poanetwork/nifty-wallet/pull/366) - (Fix) Increase max token symbol length up to 12 From c9def98cf77f53a3790a3170d036a9b3555c0b78 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Fri, 1 May 2020 17:06:22 +0300 Subject: [PATCH 10/13] Add Stake token --- package-lock.json | 10 +++------- package.json | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3f52d9e7..90407ee7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11363,9 +11363,9 @@ } }, "eth-contract-metadata": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/eth-contract-metadata/-/eth-contract-metadata-1.12.1.tgz", - "integrity": "sha512-9u2jUcdxaKIv4RvA9RtjyD4+M2yWt4yCulR5bpdQTiG3HUFnN9lHtNL5NIRDpvQVJKerFhexrgEM2WdGP3a6VA==" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/eth-contract-metadata/-/eth-contract-metadata-1.13.0.tgz", + "integrity": "sha512-9CjXHX8IdXysUEvOHdbCsjdAwM1E98jaeK2HeOqm/9S/vOZ8YryaBBt/YSiBq3MkpCwf+d1pEQ53p96rsdy52w==" }, "eth-ens-namehash": { "version": "2.0.8", @@ -49799,10 +49799,6 @@ "uuid": "^3.3.2" } }, - "rsk-test-contract-metadata": { - "version": "github:rsksmart/rsk-testnet-contract-metadata#69ff2d652b286648e9264e2689009e940ec7ccad", - "from": "github:rsksmart/rsk-testnet-contract-metadata#master" - }, "rst-selector-parser": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", diff --git a/package.json b/package.json index e7d4a39c4..463f61538 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "dnode": "^1.2.2", "end-of-stream": "^1.4.4", "eth-block-tracker": "^4.4.2", - "eth-contract-metadata": "^1.12.1", + "eth-contract-metadata": "^1.13.0", "eth-ens-namehash": "^2.0.8", "eth-json-rpc-errors": "^2.0.2", "eth-json-rpc-filters": "github:poanetwork/eth-json-rpc-filters#3.0.2", From 975799589745381e64b9c09ee1bb945548942b9a Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Fri, 1 May 2020 17:07:57 +0300 Subject: [PATCH 11/13] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c494e51d..c799d3805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- [#373](https://github.com/poanetwork/nifty-wallet/pull/373) - (Feature) Add STAKE token - [#372](https://github.com/poanetwork/nifty-wallet/pull/372) - (Chore) Update RSK contracts metadata repo - [#369](https://github.com/poanetwork/nifty-wallet/pull/369) - (Fix) RSK: fix GasPrice calculation (changed interface of minimumGasPrice - hex instead of integer) - [#368](https://github.com/poanetwork/nifty-wallet/pull/368) - (Fix) Ability to import Keystore file if it is not secured by password From 5e49fa72b46080689a4dc1d2c3c8c91cf352c865 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Fri, 1 May 2020 17:24:26 +0300 Subject: [PATCH 12/13] Bump version: 5.0.3 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c799d3805..a8b6d258e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 5.0.3 Fri May 01 2020 + - [#373](https://github.com/poanetwork/nifty-wallet/pull/373) - (Feature) Add STAKE token - [#372](https://github.com/poanetwork/nifty-wallet/pull/372) - (Chore) Update RSK contracts metadata repo - [#369](https://github.com/poanetwork/nifty-wallet/pull/369) - (Fix) RSK: fix GasPrice calculation (changed interface of minimumGasPrice - hex instead of integer) diff --git a/app/manifest.json b/app/manifest.json index c4c49818c..8350e7259 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "5.0.2", + "version": "5.0.3", "manifest_version": 2, "author": "POA Network", "description": "__MSG_appDescription__", From bd1e5d50a65537aba7fbc1ad2ef0d0a8b4280931 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Thu, 23 Apr 2020 22:30:28 +0300 Subject: [PATCH 13/13] Change notification windows order --- CHANGELOG.md | 2 + app/scripts/background.js | 58 +-- app/scripts/controllers/preferences.js | 4 +- app/scripts/edge-encryptor.js | 97 ---- app/scripts/lib/notification-manager.js | 94 ++-- app/scripts/lib/setupMetamaskMeshMetrics.js | 12 - app/scripts/lib/util.js | 22 +- app/scripts/metamask-controller.js | 4 +- app/scripts/platforms/extension.js | 107 +++- app/scripts/ui.js | 11 - .../connect-hardware/connect-screen.js | 2 +- old-ui/app/components/pending-tx.js | 47 +- old-ui/app/components/shift-list-item.js | 2 +- old-ui/app/conf-tx.js | 473 ++++++++++-------- test/e2e/elements.js | 4 +- .../import-ganache-seed-phrase.spec.js | 2 + .../preferences-controller-test.js | 4 +- test/unit/app/edge-encryptor-test.js | 101 ---- ui/app/actions.js | 129 ++--- .../dropdowns/token-menu-dropdown.js | 2 +- ui/app/reducers/app.js | 20 +- ui/app/selectors/confirm-transaction.js | 43 +- ui/index.js | 3 +- 23 files changed, 544 insertions(+), 699 deletions(-) delete mode 100644 app/scripts/edge-encryptor.js delete mode 100644 app/scripts/lib/setupMetamaskMeshMetrics.js delete mode 100644 test/unit/app/edge-encryptor-test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index a8b6d258e..d9e97eec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- [#364](https://github.com/poanetwork/nifty-wallet/pull/364) - Fix notifications order in batch requests + ## 5.0.3 Fri May 01 2020 - [#373](https://github.com/poanetwork/nifty-wallet/pull/373) - (Feature) Add STAKE token diff --git a/app/scripts/background.js b/app/scripts/background.js index c30ac7bce..cd4f71597 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -5,11 +5,11 @@ // this needs to run before anything else require('./lib/setupFetchDebugging')() -const endOfStream = require('end-of-stream') -const pump = require('pump') -const debounce = require('debounce-stream') -const log = require('loglevel') -const extension = require('extensionizer') +import endOfStream from 'end-of-stream' +import pump from 'pump' +import debounce from 'debounce-stream' +import log from 'loglevel' +import extension from 'extensionizer' const LocalStorageStore = require('obs-store/lib/localStorage') const LocalStore = require('./lib/local-store') const storeTransform = require('obs-store/lib/transform') @@ -19,13 +19,11 @@ const Migrator = require('./lib/migrator/') const migrations = require('./migrations/') const PortStream = require('extension-port-stream') const createStreamSink = require('./lib/createStreamSink') -const NotificationManager = require('./lib/notification-manager.js') +import NotificationManager from './lib/notification-manager.js' const MetamaskController = require('./metamask-controller') const rawFirstTimeState = require('./first-time-state') const setupRaven = require('./lib/setupRaven') const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') -const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') -const EdgeEncryptor = require('./edge-encryptor') const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const getObjStructure = require('./lib/getObjStructure') @@ -51,12 +49,6 @@ global.METAMASK_NOTIFIER = notificationManager const release = platform.getVersion() const raven = setupRaven({ release }) -// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser -// Internet Explorer 6-11 -const isIE = !!document.documentMode -// Edge 20+ -const isEdge = !isIE && !!window.StyleMedia - let popupIsOpen = false let notificationIsOpen = false const openMetamaskTabsIDs = {} @@ -70,9 +62,6 @@ let versionedData // initialization flow initialize().catch(log.error) -// setup metamask mesh testing container -setupMetamaskMeshMetrics() - /** * An object representing a transaction, in whatever state it is in. @@ -177,6 +166,7 @@ async function initialize () { async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) + migrator.on('error', console.warn) // read from disk // first from preferred, async API: @@ -256,7 +246,7 @@ function setupController (initState, initLangCode) { showUnconfirmedMessage: triggerUi, unlockAccountMessage: triggerUi, showUnapprovedTx: triggerUi, - showWatchAssetUi: showWatchAssetUi, + openPopup: openPopup, // initial state initState, // initial locale code @@ -269,7 +259,6 @@ function setupController (initState, initLangCode) { getOpenMetamaskTabsIds: () => { return openMetamaskTabsIDs }, - encryptor: isEdge ? new EdgeEncryptor() : undefined, }) global.metamaskController = controller @@ -460,28 +449,27 @@ function setupController (initState, initLangCode) { /** * Opens the browser popup for user confirmation */ -function triggerUi () { - extension.tabs.query({ active: true }, tabs => { - const currentlyActiveMetamaskTab = Boolean(tabs.find(tab => openMetamaskTabsIDs[tab.id])) - /** - * https://github.com/poanetwork/metamask-extension/issues/19 - * !notificationIsOpen was removed from the check, because notification can be opened, but it can be behind the DApp - * for some reasons. For example, if notification popup was opened, but user moved focus to DApp. - * New transaction, in this case, will not appear in front of DApp. - */ - if (!popupIsOpen && !currentlyActiveMetamaskTab) { - notificationManager.showPopup() - } - }) +async function triggerUi () { + const tabs = await platform.getActiveTabs() + const currentlyActiveMetamaskTab = Boolean(tabs.find((tab) => openMetamaskTabsIDs[tab.id])) + /** + * https://github.com/poanetwork/metamask-extension/issues/19 + * !notificationIsOpen was removed from the check, because notification can be opened, but it can be behind the DApp + * for some reasons. For example, if notification popup was opened, but user moved focus to DApp. + * New transaction, in this case, will not appear in front of DApp. + */ + if (!popupIsOpen && !currentlyActiveMetamaskTab) { + await notificationManager.showPopup() + } } /** * Opens the browser popup for user confirmation of watchAsset * then it waits until user interact with the UI */ -function showWatchAssetUi () { - triggerUi() - return new Promise( +async function openPopup () { + await triggerUi() + await new Promise( (resolve) => { const interval = setInterval(() => { if (!notificationIsOpen) { diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 21db813be..501251f2a 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -47,7 +47,7 @@ class PreferencesController { this.diagnostics = opts.diagnostics this.network = opts.network this.store = new ObservableStore(initState) - this.showWatchAssetUi = opts.showWatchAssetUi + this.openPopup = opts.openPopup this._subscribeProviderType() } // PUBLIC METHODS @@ -591,7 +591,7 @@ class PreferencesController { } const tokenOpts = { rawAddress, decimals, symbol, image } this.addSuggestedERC20Asset(tokenOpts) - return this.showWatchAssetUi().then(() => { + return this.openPopup().then(() => { const tokenAddresses = this.getTokens().filter(token => token.address === normalizeAddress(rawAddress)) return tokenAddresses.length > 0 }) diff --git a/app/scripts/edge-encryptor.js b/app/scripts/edge-encryptor.js deleted file mode 100644 index c5fd0685a..000000000 --- a/app/scripts/edge-encryptor.js +++ /dev/null @@ -1,97 +0,0 @@ -const asmcrypto = require('asmcrypto.js') -const Unibabel = require('browserify-unibabel') - -/** - * A Microsoft Edge-specific encryption class that exposes - * the interface expected by eth-keykeyring-controller - */ -class EdgeEncryptor { - /** - * Encrypts an arbitrary object to ciphertext - * - * @param {string} password Used to generate a key to encrypt the data - * @param {Object} dataObject Data to encrypt - * @returns {Promise} Promise resolving to an object with ciphertext - */ - encrypt (password, dataObject) { - const salt = this._generateSalt() - return this._keyFromPassword(password, salt) - .then(function (key) { - 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) - - const buffer = new Uint8Array(resultbuffer) - const vectorStr = Unibabel.bufferToBase64(vector) - const vaultStr = Unibabel.bufferToBase64(buffer) - return JSON.stringify({ - data: vaultStr, - iv: vectorStr, - salt: salt, - }) - }) - } - - /** - * Decrypts an arbitrary object from ciphertext - * - * @param {string} password Used to generate a key to decrypt the data - * @param {string} text Ciphertext of an encrypted object - * @returns {Promise} Promise resolving to copy of decrypted object - */ - decrypt (password, text) { - const payload = JSON.parse(text) - const salt = payload.salt - return this._keyFromPassword(password, salt) - .then(function (key) { - const encryptedData = Unibabel.base64ToBuffer(payload.data) - const vector = Unibabel.base64ToBuffer(payload.iv) - return new Promise((resolve, reject) => { - let result - try { - result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector) - } catch (err) { - return reject(new Error('Incorrect password')) - } - const decryptedData = new Uint8Array(result) - const decryptedStr = Unibabel.bufferToUtf8(decryptedData) - const decryptedObj = JSON.parse(decryptedStr) - resolve(decryptedObj) - }) - }) - } - - /** - * Retrieves a cryptographic key using a password - * - * @private - * @param {string} password Password used to unlock a cryptographic key - * @param {string} salt Random base64 data - * @returns {Promise} Promise resolving to a derived key - */ - _keyFromPassword (password, salt) { - - const passBuffer = Unibabel.utf8ToBuffer(password) - const saltBuffer = Unibabel.base64ToBuffer(salt) - return new Promise((resolve) => { - const key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000) - resolve(key) - }) - } - - /** - * Generates random base64 encoded data - * - * @private - * @returns {string} Randomized base64 encoded data - */ - _generateSalt (byteCount = 32) { - const view = new Uint8Array(byteCount) - global.crypto.getRandomValues(view) - const b64encoded = btoa(String.fromCharCode.apply(null, view)) - return b64encoded - } -} - -module.exports = EdgeEncryptor diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index 6f2dd63ee..4716dc791 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -1,7 +1,7 @@ -const extension = require('extensionizer') -const height = 620 -const width = 360 +import ExtensionPlatform from '../platforms/extension' +const NOTIFICATION_HEIGHT = 620 +const NOTIFICATION_WIDTH = 360 class NotificationManager { @@ -12,47 +12,45 @@ class NotificationManager { * */ + constructor () { + this.platform = new ExtensionPlatform() + } + /** * Either brings an existing MetaMask notification window into focus, or creates a new notification window. New * notification windows are given a 'popup' type. * */ - showPopup () { - this._getPopup((err, popup) => { - if (err) throw err + async showPopup () { + const popup = await this._getPopup() - // Bring focus to chrome popup - if (popup) { - // bring focus to existing chrome popup - extension.windows.update(popup.id, { focused: true }) - } else { - const cb = (currentPopup) => { - this._popupId = currentPopup.id - extension.windows.update(currentPopup.id, { focused: true }) - } - // create new notification popup - const creation = extension.windows.create({ - url: 'notification.html', - type: 'popup', - width, - height, - }, cb) - creation && creation.then && creation.then(cb) - } - }) + // Bring focus to chrome popup + if (popup) { + // bring focus to existing chrome popup + await this.platform.focusWindow(popup.id) + } else { + + // create new notification popup + const popupWindow = await this.platform.openWindow({ + url: 'notification.html', + type: 'popup', + width: NOTIFICATION_WIDTH, + height: NOTIFICATION_HEIGHT, + }) + this._popupId = popupWindow.id + } } /** * Closes a MetaMask notification if it window exists. * */ - closePopup () { - // closes notification popup - this._getPopup((err, popup) => { - if (err) throw err - if (!popup) return - extension.windows.remove(popup.id, console.error) - }) + async closePopup () { + const popup = this._getPopup() + if (!popup) { + return + } + await this.platform.removeWindow(popup.id) } /** @@ -60,39 +58,19 @@ class NotificationManager { * type 'popup') * * @private - * @param {Function} cb A node style callback that to whcih the found notification window will be passed. + * @param {Function} cb - A node style callback that to whcih the found notification window will be passed. * */ - _getPopup (cb) { - this._getWindows((err, windows) => { - if (err) throw err - cb(null, this._getPopupIn(windows)) - }) - } - - /** - * Returns all open MetaMask windows. - * - * @private - * @param {Function} cb A node style callback that to which the windows will be passed. - * - */ - _getWindows (cb) { - // Ignore in test environment - if (!extension.windows) { - return cb() - } - - extension.windows.getAll({}, (windows) => { - cb(null, windows) - }) + async _getPopup () { + const windows = await this.platform.getAllWindows() + return this._getPopupIn(windows) } /** * Given an array of windows, returns the 'popup' that has been opened by MetaMask, or null if no such window exists. * * @private - * @param {array} windows An array of objects containing data about the open MetaMask extension windows. + * @param {array} windows - An array of objects containing data about the open MetaMask extension windows. * */ _getPopupIn (windows) { @@ -104,4 +82,4 @@ class NotificationManager { } -module.exports = NotificationManager +export default NotificationManager diff --git a/app/scripts/lib/setupMetamaskMeshMetrics.js b/app/scripts/lib/setupMetamaskMeshMetrics.js deleted file mode 100644 index 1d59c0d4a..000000000 --- a/app/scripts/lib/setupMetamaskMeshMetrics.js +++ /dev/null @@ -1,12 +0,0 @@ - -module.exports = setupMetamaskMeshMetrics - -/** - * Injects an iframe into the current document for testing - */ -function setupMetamaskMeshMetrics () { - const testingContainer = document.createElement('iframe') - testingContainer.src = 'https://metamask.github.io/mesh-testing/' - console.log('Injecting Nifty Wallet Mesh testing client') - document.head.appendChild(testingContainer) -} diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js index 4e3f2a8dd..3286e964b 100644 --- a/app/scripts/lib/util.js +++ b/app/scripts/lib/util.js @@ -6,6 +6,7 @@ const { ENVIRONMENT_TYPE_POPUP, ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_FULLSCREEN, + ENVIRONMENT_TYPE_BACKGROUND, PLATFORM_FIREFOX, PLATFORM_OPERA, PLATFORM_CHROME, @@ -13,17 +14,6 @@ const { PLATFORM_BRAVE, } = require('./enums') -/** - * Generates an example stack trace - * - * @returns {string} A stack trace - * - */ -function getStack () { - const stack = new Error('Stack trace generator - not an error').stack - return stack -} - /** * Used to determine the window type through which the app is being viewed. * - 'popup' refers to the extension opened through the browser app icon (in top right corner in chrome and firefox) @@ -34,12 +24,15 @@ function getStack () { * */ const getEnvironmentType = (url = window.location.href) => { - if (url.match(/popup.html(?:#.*)*$/)) { + const parsedUrl = new URL(url) + if (parsedUrl.pathname === '/popup.html') { return ENVIRONMENT_TYPE_POPUP - } else if (url.match(/home.html(?:\?.+)*$/) || url.match(/home.html(?:#.*)*$/)) { + } else if (['/home.html', '/phishing.html'].includes(parsedUrl.pathname)) { return ENVIRONMENT_TYPE_FULLSCREEN - } else { + } else if (parsedUrl.pathname === '/notification.html') { return ENVIRONMENT_TYPE_NOTIFICATION + } else { + return ENVIRONMENT_TYPE_BACKGROUND } } @@ -175,7 +168,6 @@ module.exports = { removeListeners, applyListeners, getPlatform, - getStack, getEnvironmentType, sufficientBalance, hexToBn, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 3421e07de..97a466014 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -111,7 +111,7 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, - showWatchAssetUi: opts.showWatchAssetUi, + openPopup: opts.openPopup, network: this.networkController, }) @@ -1945,7 +1945,7 @@ module.exports = class MetamaskController extends EventEmitter { .sort((block1, block2) => block1.number - block2.number)[recentBlocks.length - 1] const gasPrice = recentBlock && recentBlock.minimumGasPrice && recentBlock.minimumGasPrice.toString() - + if (gasPrice !== '0x' && gasPrice !== '0x0' && gasPrice !== '') { return gasPrice } else { diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index c2ebc3bf3..3d12c7a91 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -12,8 +12,64 @@ class ExtensionPlatform { extension.runtime.reload() } - openWindow ({ url }) { - extension.tabs.create({ url }) + openTab (options) { + return new Promise((resolve, reject) => { + extension.tabs.create(options, (newTab) => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve(newTab) + }) + }) + } + + openWindow (options) { + return new Promise((resolve, reject) => { + extension.windows.create(options, (newWindow) => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve(newWindow) + }) + }) + } + + closeWindow (windowId) { + return new Promise((resolve, reject) => { + extension.windows.remove(windowId, () => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve() + }) + }) + } + + focusWindow (windowId) { + return new Promise((resolve, reject) => { + extension.windows.update(windowId, { focused: true }, () => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve() + }) + }) + } + + getLastFocusedWindow () { + return new Promise((resolve, reject) => { + extension.windows.getLastFocused((windowObject) => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve(windowObject) + }) + }) } closeCurrentWindow () { @@ -22,27 +78,6 @@ class ExtensionPlatform { }) } - /** - * Closes all notifications windows, when action is confirmed in popup - * or closes notification window itself, when action is confirmed from it - */ - closeNotificationWindow () { - return extension.windows.getCurrent((curWindowsDetails) => { - if (curWindowsDetails.type === 'popup') { - return extension.windows.remove(curWindowsDetails.id) - } else { - extension.windows.getAll((windowsDetails) => { - const windowsDetailsFiltered = windowsDetails.filter((windowDetails) => windowDetails.id !== curWindowsDetails.id) - return windowsDetailsFiltered.forEach((windowDetails) => { - if (windowDetails.type === 'popup') { - extension.windows.remove(windowDetails.id) - } - }) - }) - } - }) - } - getVersion () { return extension.runtime.getManifest().version } @@ -57,7 +92,7 @@ class ExtensionPlatform { if (route) { extensionURL += `#${route}` } - this.openWindow({ url: extensionURL }) + this.openTab({ url: extensionURL }) if (getEnvironmentType() !== ENVIRONMENT_TYPE_BACKGROUND) { window.close() } @@ -86,6 +121,30 @@ class ExtensionPlatform { } } + getAllWindows () { + return new Promise((resolve, reject) => { + extension.windows.getAll((windows) => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve(windows) + }) + }) + } + + getActiveTabs () { + return new Promise((resolve, reject) => { + extension.tabs.query({ active: true }, (tabs) => { + const error = checkForError() + if (error) { + return reject(error) + } + return resolve(tabs) + }) + }) + } + currentTab () { return new Promise((resolve, reject) => { extension.tabs.getCurrent((tab) => { diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 5f6c7708e..40657d67c 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -3,11 +3,8 @@ const OldMetaMaskUiCss = require('../../old-ui/css') const startPopup = require('./popup-core') const PortStream = require('extension-port-stream') const { getEnvironmentType } = require('./lib/util') -const { ENVIRONMENT_TYPE_NOTIFICATION } = require('./lib/enums') import extension from 'extensionizer' const ExtensionPlatform = require('./platforms/extension') -const NotificationManager = require('./lib/notification-manager') -const notificationManager = new NotificationManager() const setupRaven = require('./lib/setupRaven') const log = require('loglevel') @@ -29,7 +26,6 @@ async function start () { // identify window type (popup, notification) const windowType = getEnvironmentType(window.location.href) global.METAMASK_UI_TYPE = windowType - closePopupIfOpen(windowType) // setup stream to background const extensionPort = extension.runtime.connect({ name: windowType }) @@ -51,13 +47,6 @@ async function start () { }) - function closePopupIfOpen (windowType) { - if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) { - // should close only chrome popup - notificationManager.closePopup() - } - } - function displayCriticalError (err) { container.innerHTML = '
The Nifty Wallet app failed to load: please open and close Nifty Wallet again to restart.
' container.style.height = '80px' diff --git a/old-ui/app/components/connect-hardware/connect-screen.js b/old-ui/app/components/connect-hardware/connect-screen.js index b9700a47d..4d38ae3ea 100644 --- a/old-ui/app/components/connect-hardware/connect-screen.js +++ b/old-ui/app/components/connect-hardware/connect-screen.js @@ -74,7 +74,7 @@ class ConnectScreen extends Component { diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js index 78516880b..7b0484037 100644 --- a/old-ui/app/components/pending-tx.js +++ b/old-ui/app/components/pending-tx.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types' import clone from 'clone' import log from 'loglevel' -const ethUtil = require('ethereumjs-util') +import ethUtil from 'ethereumjs-util' const BN = ethUtil.BN const hexToBn = require('../../../app/scripts/lib/hex-to-bn') const util = require('../util') @@ -47,12 +47,12 @@ class PendingTx extends Component { isUnlocked: PropTypes.bool, currentCurrency: PropTypes.string, conversionRate: PropTypes.number, - unconfTxListLength: PropTypes.number, provider: PropTypes.object, index: PropTypes.number, blockGasLimit: PropTypes.string, tokensToSend: PropTypes.objectOf(BigNumber), tokensTransferTo: PropTypes.string, + unapprovedTxs: PropTypes.object, } constructor (opts = {}) { @@ -132,12 +132,13 @@ class PendingTx extends Component { const dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0 + const { totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation } = this.getNavigateTxData() + const balanceBn = hexToBn(balance) const insufficientBalance = balanceBn.lt(maxCost) const dangerousGasLimit = gasBn.gte(saferGasLimitBN) const gasLimitSpecified = txMeta.gasLimitSpecified const buyDisabled = insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting - const showRejectAll = props.unconfTxListLength > 1 const isNotification = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION @@ -158,7 +159,6 @@ class PendingTx extends Component { } const isError = txMeta.simulationFails || !isValidAddress || insufficientBalance || (dangerousGasLimit && !gasLimitSpecified) - return ( h('div', { @@ -179,7 +179,7 @@ class PendingTx extends Component { h('.flex-row.flex-center', { style: { maxWidth: '100%', - padding: showRejectAll ? '20px 20px 50px 20px' : '20px 20px 20px 20px', + padding: showNavigation ? '20px 20px 50px 20px' : '20px 20px 20px 20px', background: 'linear-gradient(rgb(84, 36, 147), rgb(104, 45, 182))', position: 'relative', }, @@ -197,22 +197,22 @@ class PendingTx extends Component { h('h3', { style: { alignSelf: 'center', - display: props.unconfTxListLength > 1 ? 'block' : 'none', + display: showNavigation ? 'block' : 'none', fontSize: '14px', }, }, [ h('i.fa.white-arrow-left.fa-lg.cursor-pointer', { style: { - display: props.index === 0 ? 'none' : 'inline-block', + display: positionOfCurrentTx === 1 ? 'none' : 'inline-block', }, - onClick: () => props.actions.previousTx(), + onClick: () => props.actions.nextTx(prevTxId), }), - ` ${props.index + 1} of ${props.unconfTxListLength} `, + ` ${positionOfCurrentTx} of ${totalTx} `, h('i.fa.white-arrow-right.fa-lg.cursor-pointer', { style: { - display: props.index + 1 === props.unconfTxListLength ? 'none' : 'inline-block', + display: positionOfCurrentTx === totalTx ? 'none' : 'inline-block', }, - onClick: () => props.actions.nextTx(), + onClick: () => props.actions.nextTx(nextTxId), }), ])], ), @@ -519,7 +519,7 @@ class PendingTx extends Component { onClick: props.cancelTransaction, }, 'Reject'), ]), - showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', { + showNavigation ? h('.flex-row.flex-space-around.conf-buttons', { style: { display: 'flex', justifyContent: 'flex-end', @@ -731,6 +731,23 @@ class PendingTx extends Component { } } + getNavigateTxData () { + const { unapprovedTxs, network, txData: { id } = {} } = this.props + const currentNetworkUnapprovedTxs = Object.keys(unapprovedTxs) + .filter((key) => unapprovedTxs[key].metamaskNetworkId === network) + .reduce((acc, key) => ({ ...acc, [key]: unapprovedTxs[key] }), {}) + const enumUnapprovedTxs = Object.keys(currentNetworkUnapprovedTxs) + const currentPosition = enumUnapprovedTxs.indexOf(id ? id.toString() : '') + + return { + totalTx: enumUnapprovedTxs.length, + positionOfCurrentTx: currentPosition + 1, + nextTxId: enumUnapprovedTxs[currentPosition + 1], + prevTxId: enumUnapprovedTxs[currentPosition - 1], + showNavigation: enumUnapprovedTxs.length > 1, + } + } + } function forwardCarrat () { @@ -755,7 +772,7 @@ function mapStateToProps (state) { unapprovedMsgs: state.metamask.unapprovedMsgs, unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs, unapprovedTypedMessages: state.metamask.unapprovedTypedMessages, - index: state.appState.currentView.pendingTxIndex || 0, + index: state.appState.currentView.key || 0, warning: state.appState.warning, network: state.metamask.network, provider: state.metamask.provider, @@ -764,14 +781,14 @@ function mapStateToProps (state) { currentCurrency: state.metamask.currentCurrency, blockGasLimit: state.metamask.currentBlockGasLimit, computedBalances: state.metamask.computedBalances, + pendingTxIndex: state.appState.currentView.pendingTxIndex || 0, } } const mapDispatchToProps = (dispatch) => { return { actions: { - previousTx: () => dispatch(actions.previousTx()), - nextTx: () => dispatch(actions.nextTx()), + nextTx: (txId) => dispatch(actions.nextTx(txId)), displayWarning: (msg) => dispatch(actions.displayWarning(msg)), goHome: () => dispatch(actions.goHome()), }, diff --git a/old-ui/app/components/shift-list-item.js b/old-ui/app/components/shift-list-item.js index 90ea27c88..d1fd8a31f 100644 --- a/old-ui/app/components/shift-list-item.js +++ b/old-ui/app/components/shift-list-item.js @@ -212,7 +212,7 @@ ShiftListItem.prototype.renderInfo = function () { paddingLeft: '29px', textAlign: 'left', }, - onClick: () => global.platform.openWindow({ url }), + onClick: () => global.platform.openTab({ url }), }, [ h('div', { style: { diff --git a/old-ui/app/conf-tx.js b/old-ui/app/conf-tx.js index e833b4674..8c5bb27eb 100644 --- a/old-ui/app/conf-tx.js +++ b/old-ui/app/conf-tx.js @@ -1,11 +1,11 @@ -const inherits = require('util').inherits -const Component = require('react').Component +import PropTypes from 'prop-types' +import { Component } from 'react' +import { connect } from 'react-redux' const h = require('react-hyperscript') -const connect = require('react-redux').connect const actions = require('../../ui/app/actions') const LoadingIndicator = require('./components/loading') const txHelper = require('../lib/tx-helper') -const log = require('loglevel') +import log from 'loglevel' const { getCurrentKeyring, ifContractAcc } = require('./util') const PendingTx = require('./components/pending-tx') @@ -15,118 +15,224 @@ import PendingTypedMsg from './components/pending-typed-msg' const Loading = require('./components/loading') const { DAI_CODE, POA_SOKOL_CODE, RSK_TESTNET_CODE, GOERLI_TESTNET_CODE } = require('../../app/scripts/controllers/network/enums') const { getMetaMaskAccounts } = require('../../ui/app/selectors') +import BigNumber from 'bignumber.js' -module.exports = connect(mapStateToProps)(ConfirmTxScreen) -function mapStateToProps (state) { - const { metamask, appState } = state - const { screenParams, pendingTxIndex } = appState.currentView - return { - identities: metamask.identities, - accounts: getMetaMaskAccounts(state), - keyrings: metamask.keyrings, - selectedAddress: metamask.selectedAddress, - unapprovedTxs: metamask.unapprovedTxs, - unapprovedMsgs: metamask.unapprovedMsgs, - unapprovedPersonalMsgs: metamask.unapprovedPersonalMsgs, - unapprovedTypedMessages: metamask.unapprovedTypedMessages, - index: pendingTxIndex || 0, - warning: appState.warning, - network: metamask.network, - provider: metamask.provider, - conversionRate: metamask.conversionRate, - currentCurrency: metamask.currentCurrency, - blockGasLimit: metamask.currentBlockGasLimit, - computedBalances: metamask.computedBalances, - isToken: (screenParams && screenParams.isToken), - tokenSymbol: (screenParams && screenParams.tokenSymbol), - tokensToSend: (screenParams && screenParams.tokensToSend), - tokensTransferTo: (screenParams && screenParams.tokensTransferTo), - isContractExecutionByUser: (screenParams && screenParams.isContractExecutionByUser), - } -} - -inherits(ConfirmTxScreen, Component) -function ConfirmTxScreen () { - Component.call(this) -} - -ConfirmTxScreen.prototype.render = function () { - const props = this.props - const { network, unapprovedTxs, currentCurrency, computedBalances, - unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, blockGasLimit } = props - let { conversionRate } = props - - const isTestnet = parseInt(network) === POA_SOKOL_CODE || parseInt(network) === RSK_TESTNET_CODE || parseInt(network) === GOERLI_TESTNET_CODE - const isDai = parseInt(network) === DAI_CODE - if (isTestnet) { - conversionRate = 0 - } else if (isDai) { - conversionRate = 1 +class ConfirmTxScreen extends Component { + static propTypes = { + network: PropTypes.string, + identities: PropTypes.objectOf(PropTypes.object), + keyrings: PropTypes.array, + actions: PropTypes.objectOf(PropTypes.func), + isToken: PropTypes.bool, + isContractExecutionByUser: PropTypes.bool, + selectedAddress: PropTypes.string, + warning: PropTypes.string, + unapprovedTxs: PropTypes.object, + unapprovedMsgs: PropTypes.object, + unapprovedPersonalMsgs: PropTypes.object, + unapprovedTypedMessages: PropTypes.object, + pendingTxIndex: PropTypes.number, + blockGasLimit: PropTypes.string, + accounts: PropTypes.object, + currentCurrency: PropTypes.string, + computedBalances: PropTypes.object, + conversionRate: PropTypes.number, + tokenSymbol: PropTypes.string, + tokensToSend: PropTypes.objectOf(BigNumber), + tokensTransferTo: PropTypes.string, } - const unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) - const ind = props.index || 0 - const txData = unconfTxList[ind] || {} - const txParams = txData.params || {} + render () { + const props = this.props + const { network, unapprovedTxs, currentCurrency, computedBalances, + unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, blockGasLimit } = props + let { conversionRate } = props - log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) - if (unconfTxList.length === 0) return h(Loading, { isLoading: true }) + const isTestnet = parseInt(network) === POA_SOKOL_CODE || parseInt(network) === RSK_TESTNET_CODE || parseInt(network) === GOERLI_TESTNET_CODE + const isDai = parseInt(network) === DAI_CODE + if (isTestnet) { + conversionRate = 0 + } else if (isDai) { + conversionRate = 1 + } - const unconfTxListLength = unconfTxList.length + const unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) + const ind = props.pendingTxIndex || 0 + const txData = unconfTxList[ind] || {} + const txParams = txData.params || {} - return ( + log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) + if (unconfTxList.length === 0) return h(Loading, { isLoading: true }) - h('.flex-column.flex-grow', { - style: { - width: '100%', - }, - }, [ + const unconfTxListLength = unconfTxList.length - h(LoadingIndicator, { - isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults, - loadingMessage: 'Estimating transaction cost…', - canBypass: true, - bypass: () => { - this.setState({bypassLoadingScreen: true}) + return ( + + h('.flex-column.flex-grow', { + style: { + width: '100%', }, - }), + }, [ - // subtitle and nav + h(LoadingIndicator, { + isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults, + loadingMessage: 'Estimating transaction cost…', + canBypass: true, + bypass: () => { + this.setState({bypassLoadingScreen: true}) + }, + }), - warningIfExists(props.warning), + // subtitle and nav - currentTxView({ - // Properties - txData: txData, - key: txData.id, - selectedAddress: props.selectedAddress, - accounts: props.accounts, - identities: props.identities, - conversionRate, - currentCurrency, - blockGasLimit, - unconfTxListLength, - computedBalances, - network, - isToken: props.isToken, - tokenSymbol: props.tokenSymbol, - tokensToSend: props.tokensToSend, - tokensTransferTo: props.tokensTransferTo, - // Actions - buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser), - sendTransaction: this.sendTransaction.bind(this), - cancelTransaction: this.cancelTransaction.bind(this, txData), - cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList), - 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), - }), - ]) - ) + warningIfExists(props.warning), + + currentTxView({ + // Properties + txData: txData, + key: txData.id, + selectedAddress: props.selectedAddress, + accounts: props.accounts, + identities: props.identities, + conversionRate, + currentCurrency, + blockGasLimit, + unconfTxListLength, + computedBalances, + network, + isToken: props.isToken, + tokenSymbol: props.tokenSymbol, + tokensToSend: props.tokensToSend, + tokensTransferTo: props.tokensTransferTo, + // Actions + buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser), + sendTransaction: this.sendTransaction.bind(this), + cancelTransaction: this.cancelTransaction.bind(this, txData), + cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList), + 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), + }), + ]) + ) + } + + buyEth (address, isContractExecutionByUser, event) { + event.preventDefault() + this.props.actions.buyEthView(address, isContractExecutionByUser) + } + + sendTransaction (txData, event) { + this.stopPropagation(event) + this.props.actions.updateAndApproveTx(txData) + this._checkIfContractExecutionAndUnlockContract(txData) + } + + cancelTransaction (txData, event) { + this.stopPropagation(event) + event.preventDefault() + this.props.actions.cancelTx(txData) + this._checkIfContractExecutionAndUnlockContract(txData) + } + + cancelAllTransactions (unconfTxList, event) { + this.stopPropagation(event) + event.preventDefault() + this.props.actions.cancelTxs(unconfTxList) + this._checkIfMultipleContractExecutionAndUnlockContract(unconfTxList) + } + + signMessage (msgData, event) { + log.info('conf-tx.js: signing message') + const params = msgData.msgParams + params.metamaskId = msgData.id + this.stopPropagation(event) + this.props.actions.signMsg(params) + } + + stopPropagation (event) { + if (event.stopPropagation) { + event.stopPropagation() + } + } + + signPersonalMessage (msgData, event) { + log.info('conf-tx.js: signing personal message') + const params = msgData.msgParams + params.metamaskId = msgData.id + this.stopPropagation(event) + this.props.actions.signPersonalMsg(params) + } + + signTypedMessage (msgData, event) { + log.info('conf-tx.js: signing typed message') + const params = msgData.msgParams + params.metamaskId = msgData.id + this.stopPropagation(event) + this.props.actions.signTypedMsg(params) + } + + cancelMessage (msgData, event) { + log.info('canceling message') + this.stopPropagation(event) + this.props.actions.cancelMsg(msgData) + } + + cancelPersonalMessage (msgData, event) { + log.info('canceling personal message') + this.stopPropagation(event) + this.props.actions.cancelPersonalMsg(msgData) + } + + cancelTypedMessage (msgData, event) { + log.info('canceling typed message') + this.stopPropagation(event) + this.props.actions.cancelTypedMsg(msgData) + } + + _checkIfMultipleContractExecutionAndUnlockContract (unconfTxList) { + const areTxsToOneContractFromTheList = unconfTxList.slice(0).reduce((res, txData, ind, unconfTxList) => { + if (txData.txParams.data && this.props.isContractExecutionByUser) { + const to = txData && txData.txParams && txData.txParams.to + const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to) + if (targetContractIsInTheList && Object.keys(res).length === 0) { + res = { status: true, to } + } else if (res.status && res.to !== to) { + res = { status: false } + unconfTxList.splice(1) + } + } else { + res = { status: false } + unconfTxList.splice(1) + } + return res + }, {}) + + if (areTxsToOneContractFromTheList.status) { + this._unlockContract(areTxsToOneContractFromTheList.to) + } + } + + _checkIfContractExecutionAndUnlockContract (txData) { + if (txData.txParams.data && this.props.isContractExecutionByUser) { + const to = txData && txData.txParams && txData.txParams.to + const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to) + if (targetContractIsInTheList) { + this._unlockContract(to) + } + } + } + + _unlockContract (to) { + const currentKeyring = getCurrentKeyring(to, this.props.network, this.props.keyrings, this.props.identities) + if (ifContractAcc(currentKeyring)) { + this.props.actions.showAccountDetail(to) + } + } } function currentTxView (opts) { @@ -153,119 +259,6 @@ function currentTxView (opts) { } } -ConfirmTxScreen.prototype.buyEth = function (address, isContractExecutionByUser, event) { - event.preventDefault() - this.props.dispatch(actions.buyEthView(address, isContractExecutionByUser)) -} - -ConfirmTxScreen.prototype.sendTransaction = function (txData, event) { - this.stopPropagation(event) - this.props.dispatch(actions.updateAndApproveTx(txData)) - this._checkIfContractExecutionAndUnlockContract(txData) -} - -ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) { - this.stopPropagation(event) - event.preventDefault() - this.props.dispatch(actions.cancelTx(txData)) - this._checkIfContractExecutionAndUnlockContract(txData) -} - -ConfirmTxScreen.prototype.cancelAllTransactions = function (unconfTxList, event) { - this.stopPropagation(event) - event.preventDefault() - this.props.dispatch(actions.cancelAllTx(unconfTxList)) - this._checkIfMultipleContractExecutionAndUnlockContract(unconfTxList) -} - -ConfirmTxScreen.prototype.signMessage = function (msgData, event) { - log.info('conf-tx.js: signing message') - const params = msgData.msgParams - params.metamaskId = msgData.id - this.stopPropagation(event) - this.props.dispatch(actions.signMsg(params)) -} - -ConfirmTxScreen.prototype.stopPropagation = function (event) { - if (event.stopPropagation) { - event.stopPropagation() - } -} - -ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) { - log.info('conf-tx.js: signing personal message') - const params = msgData.msgParams - params.metamaskId = msgData.id - this.stopPropagation(event) - this.props.dispatch(actions.signPersonalMsg(params)) -} - -ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) { - log.info('conf-tx.js: signing typed message') - const params = msgData.msgParams - params.metamaskId = msgData.id - this.stopPropagation(event) - this.props.dispatch(actions.signTypedMsg(params)) -} - -ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) { - log.info('canceling message') - this.stopPropagation(event) - this.props.dispatch(actions.cancelMsg(msgData)) -} - -ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) { - log.info('canceling personal message') - this.stopPropagation(event) - this.props.dispatch(actions.cancelPersonalMsg(msgData)) -} - -ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) { - log.info('canceling typed message') - this.stopPropagation(event) - this.props.dispatch(actions.cancelTypedMsg(msgData)) -} - -ConfirmTxScreen.prototype._checkIfMultipleContractExecutionAndUnlockContract = function (unconfTxList) { - const areTxsToOneContractFromTheList = unconfTxList.slice(0).reduce((res, txData, ind, unconfTxList) => { - if (txData.txParams.data && this.props.isContractExecutionByUser) { - const to = txData && txData.txParams && txData.txParams.to - const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to) - if (targetContractIsInTheList && Object.keys(res).length === 0) { - res = { status: true, to } - } else if (res.status && res.to !== to) { - res = { status: false } - unconfTxList.splice(1) - } - } else { - res = { status: false } - unconfTxList.splice(1) - } - return res - }, {}) - - if (areTxsToOneContractFromTheList.status) { - this._unlockContract(areTxsToOneContractFromTheList.to) - } -} - -ConfirmTxScreen.prototype._checkIfContractExecutionAndUnlockContract = function (txData) { - if (txData.txParams.data && this.props.isContractExecutionByUser) { - const to = txData && txData.txParams && txData.txParams.to - const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to) - if (targetContractIsInTheList) { - this._unlockContract(to) - } - } -} - -ConfirmTxScreen.prototype._unlockContract = function (to) { - const currentKeyring = getCurrentKeyring(to, this.props.network, this.props.keyrings, this.props.identities) - if (ifContractAcc(currentKeyring)) { - this.props.dispatch(actions.showAccountDetail(to)) - } -} - function warningIfExists (warning) { if (warning && // Do not display user rejections on this screen: @@ -277,3 +270,51 @@ function warningIfExists (warning) { }, warning) } } + +function mapStateToProps (state) { + const { metamask, appState } = state + const { screenParams, pendingTxIndex } = appState.currentView + return { + identities: metamask.identities, + accounts: getMetaMaskAccounts(state), + keyrings: metamask.keyrings, + selectedAddress: metamask.selectedAddress, + unapprovedTxs: metamask.unapprovedTxs, + unapprovedMsgs: metamask.unapprovedMsgs, + unapprovedPersonalMsgs: metamask.unapprovedPersonalMsgs, + unapprovedTypedMessages: metamask.unapprovedTypedMessages, + pendingTxIndex: pendingTxIndex || 0, + warning: appState.warning, + network: metamask.network, + provider: metamask.provider, + conversionRate: metamask.conversionRate, + currentCurrency: metamask.currentCurrency, + blockGasLimit: metamask.currentBlockGasLimit, + computedBalances: metamask.computedBalances, + isToken: (screenParams && screenParams.isToken), + tokenSymbol: (screenParams && screenParams.tokenSymbol), + tokensToSend: (screenParams && screenParams.tokensToSend), + tokensTransferTo: (screenParams && screenParams.tokensTransferTo), + isContractExecutionByUser: (screenParams && screenParams.isContractExecutionByUser), + } +} + +function mapDispatchToProps (dispatch) { + return { + actions: { + buyEthView: (address, isContractExecutionByUser) => dispatch(actions.buyEthView(address, isContractExecutionByUser)), + updateAndApproveTx: (txData) => dispatch(actions.updateAndApproveTx(txData)), + cancelTx: (txData) => dispatch(actions.cancelTx(txData)), + cancelTxs: (unconfTxList) => dispatch(actions.cancelTxs(unconfTxList)), + signMsg: (params) => dispatch(actions.signMsg(params)), + signPersonalMsg: (params) => dispatch(actions.signPersonalMsg(params)), + signTypedMsg: (params) => dispatch(actions.signTypedMsg(params)), + cancelMsg: (msgData) => dispatch(actions.cancelMsg(msgData)), + cancelPersonalMsg: (msgData) => dispatch(actions.cancelPersonalMsg(msgData)), + cancelTypedMsg: (msgData) => dispatch(actions.cancelTypedMsg(msgData)), + showAccountDetail: (to) => dispatch(actions.showAccountDetail(to)), + }, + } +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmTxScreen) diff --git a/test/e2e/elements.js b/test/e2e/elements.js index cd27c895a..a3e503788 100644 --- a/test/e2e/elements.js +++ b/test/e2e/elements.js @@ -298,7 +298,7 @@ module.exports = { accountName: By.className('font-medium color-forest'), edit: By.className('edit-text'), iconCopy: By.className('clipboard cursor-pointer white'), - transactionList: By.css('#app-content > div > div.app-primary.from-left > div > section > section > div > div > div > div.ether-balance.ether-balance-amount > div > div > div > div:nth-child(1)'), + transactionList: By.css('#app-content > div > div.app-primary.from-left > div > section > section > div > div > div > div.ether-balance.ether-balance-amount > div > div.flex-column > div > div:nth-child(1)'), buttons: { send: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(4)'), buy: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(3)'), @@ -309,7 +309,7 @@ module.exports = { }, network: By.className('network-name'), sent: { - menu: By.className('wallet-view__tab-history'), + menu: By.css('#wallet-view__tab-history'), tokens: By.className('activeForm right'), }, // balance: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > div.ether-balance.ether-balance-amount > div > div > div:nth-child(1) > div:nth-child(1)'), diff --git a/test/e2e/test-cases/import-ganache-seed-phrase.spec.js b/test/e2e/test-cases/import-ganache-seed-phrase.spec.js index 42c268059..abb13995e 100644 --- a/test/e2e/test-cases/import-ganache-seed-phrase.spec.js +++ b/test/e2e/test-cases/import-ganache-seed-phrase.spec.js @@ -60,6 +60,8 @@ const importGanacheSeedPhrase = async (f, account2, password) => { }) it('finds the transaction in the transactions list', async () => { + const sentTab = await f.waitUntilShowUp(screens.main.sent.menu) + await sentTab.click() const transactionAmount = await f.waitUntilShowUp(screens.main.transactionList) assert.equal(await transactionAmount.getText(), '10.0') }) diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index 7f1ee3cd0..74ff88127 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -443,7 +443,7 @@ describe('preferences controller', function () { req.params.options = { address, symbol, decimals, image } sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) - preferencesController.showWatchAssetUi = async () => {} + preferencesController.openPopup = async () => {} await preferencesController._handleWatchAssetERC20(req.params.options) const suggested = preferencesController.getSuggestedTokens() @@ -463,7 +463,7 @@ describe('preferences controller', function () { req.params.options = { address, symbol, decimals, image } sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) - preferencesController.showWatchAssetUi = async () => { + preferencesController.openPopup = async () => { await preferencesController.addToken(address, symbol, decimals, image) } diff --git a/test/unit/app/edge-encryptor-test.js b/test/unit/app/edge-encryptor-test.js deleted file mode 100644 index 1a6255b36..000000000 --- a/test/unit/app/edge-encryptor-test.js +++ /dev/null @@ -1,101 +0,0 @@ -const assert = require('assert') - -const EdgeEncryptor = require('../../../app/scripts/edge-encryptor') - -var password = 'passw0rd1' -var data = 'some random data' - -global.crypto = global.crypto || { - getRandomValues: function (array) { - for (let i = 0; i < array.length; i++) { - array[i] = Math.random() * 100 - } - return array - }, -} - -describe('EdgeEncryptor', function () { - - const edgeEncryptor = new EdgeEncryptor() - describe('encrypt', function () { - - it('should encrypt the data.', function (done) { - edgeEncryptor.encrypt(password, data) - .then(function (encryptedData) { - assert.notEqual(data, encryptedData) - assert.notEqual(encryptedData.length, 0) - done() - }).catch(function (err) { - done(err) - }) - }) - - it('should return proper format.', function (done) { - edgeEncryptor.encrypt(password, data) - .then(function (encryptedData) { - const encryptedObject = JSON.parse(encryptedData) - assert.ok(encryptedObject.data, 'there is no data') - assert.ok(encryptedObject.iv && encryptedObject.iv.length !== 0, 'there is no iv') - assert.ok(encryptedObject.salt && encryptedObject.salt.length !== 0, 'there is no salt') - done() - }).catch(function (err) { - done(err) - }) - }) - - it('should not return the same twice.', function (done) { - - const encryptPromises = [] - encryptPromises.push(edgeEncryptor.encrypt(password, data)) - encryptPromises.push(edgeEncryptor.encrypt(password, data)) - - Promise.all(encryptPromises).then((encryptedData) => { - assert.equal(encryptedData.length, 2) - assert.notEqual(encryptedData[0], encryptedData[1]) - assert.notEqual(encryptedData[0].length, 0) - assert.notEqual(encryptedData[1].length, 0) - done() - }) - }) - }) - - describe('decrypt', function () { - it('should be able to decrypt the encrypted data.', function (done) { - - edgeEncryptor.encrypt(password, data) - .then(function (encryptedData) { - edgeEncryptor.decrypt(password, encryptedData) - .then(function (decryptedData) { - assert.equal(decryptedData, data) - done() - }) - .catch(function (err) { - done(err) - }) - }) - .catch(function (err) { - done(err) - }) - }) - - it('cannot decrypt the encrypted data with wrong password.', function (done) { - - edgeEncryptor.encrypt(password, data) - .then(function (encryptedData) { - edgeEncryptor.decrypt('wrong password', encryptedData) - .then(function (decryptedData) { - assert.fail('could decrypt with wrong password') - done() - }) - .catch(function (err) { - assert.ok(err instanceof Error) - assert.equal(err.message, 'Incorrect password') - done() - }) - }) - .catch(function (err) { - done(err) - }) - }) - }) -}) diff --git a/ui/app/actions.js b/ui/app/actions.js index be1fd3970..3c6ea9846 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -19,6 +19,7 @@ const { POA, CLASSIC } = require('../../app/scripts/controllers/network/enums') const { hasUnconfirmedTransactions } = require('./helpers/confirm-transaction/util') const WebcamUtils = require('../lib/webcam-utils') +import { getEnvironmentType } from '../../app/scripts/lib/util' const actions = { _setBackgroundConnection: _setBackgroundConnection, @@ -30,6 +31,9 @@ const actions = { MODAL_CLOSE: 'UI_MODAL_CLOSE', showModal: showModal, hideModal: hideModal, + + CLOSE_NOTIFICATION_WINDOW: 'CLOSE_NOTIFICATION_WINDOW', + // sidebar state SIDEBAR_OPEN: 'UI_SIDEBAR_OPEN', SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE', @@ -173,7 +177,6 @@ const actions = { COMPLETED_TX: 'COMPLETED_TX', TRANSACTION_ERROR: 'TRANSACTION_ERROR', NEXT_TX: 'NEXT_TX', - PREVIOUS_TX: 'PREV_TX', EDIT_TX: 'EDIT_TX', signMsg: signMsg, cancelMsg: cancelMsg, @@ -186,14 +189,12 @@ const actions = { signTokenTx: signTokenTx, updateTransaction, updateAndApproveTx, - cancelTx: cancelTx, + cancelTx, cancelTxs, completedTx: completedTx, txError: txError, nextTx: nextTx, editTx, - previousTx: previousTx, - cancelAllTx: cancelAllTx, viewPendingTx: viewPendingTx, VIEW_PENDING_TX: 'VIEW_PENDING_TX', updateTransactionParams, @@ -370,6 +371,8 @@ const actions = { getRequestAccountTabIds, setOpenMetamaskTabsIDs, getOpenMetamaskTabsIds, + closeCurrentNotificationWindow, + closeNotificationWindow, } module.exports = actions @@ -918,9 +921,8 @@ function setCurrentCurrency (currencyCode) { function signMsg (msgData) { log.debug('action - signMsg') - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) - return new Promise((resolve, reject) => { log.debug(`actions calling background.signMessage`) background.signMessage(msgData, (err, newState) => { @@ -935,10 +937,7 @@ function signMsg (msgData) { } dispatch(actions.completedTx(msgData.metamaskId)) - - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(closeCurrentNotificationWindow()) return resolve(msgData) }) @@ -948,7 +947,7 @@ function signMsg (msgData) { function signPersonalMsg (msgData) { log.debug('action - signPersonalMsg') - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { @@ -966,9 +965,7 @@ function signPersonalMsg (msgData) { dispatch(actions.completedTx(msgData.metamaskId)) - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return resolve(msgData) }) @@ -978,7 +975,7 @@ function signPersonalMsg (msgData) { function signTypedMsg (msgData) { log.debug('action - signTypedMsg') - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { @@ -996,9 +993,7 @@ function signTypedMsg (msgData) { dispatch(actions.completedTx(msgData.metamaskId)) - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return resolve(msgData) }) @@ -1205,7 +1200,7 @@ function clearSend () { function sendTx (txData) { log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`) - return (dispatch, getState) => { + return (dispatch) => { log.debug(`actions calling background.approveTransaction`) background.approveTransaction(txData.id, (err) => { if (err) { @@ -1214,10 +1209,7 @@ function sendTx (txData) { return log.error(err) } dispatch(actions.completedTx(txData.id)) - - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) }) } } @@ -1267,10 +1259,9 @@ function updateTransaction (txData) { function updateAndApproveTx (txData) { log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData)) - return (dispatch, getState) => { + return (dispatch) => { log.debug(`actions calling background.updateAndApproveTx`) dispatch(actions.showLoadingIndication()) - return new Promise((resolve, reject) => { background.updateAndApproveTransaction(txData, err => { dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) @@ -1293,11 +1284,7 @@ function updateAndApproveTx (txData) { dispatch(actions.clearSend()) dispatch(actions.completedTx(txData.id)) dispatch(actions.hideLoadingIndication()) - dispatch(actions.setCurrentAccountTab('history')) - - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return txData }) @@ -1331,7 +1318,7 @@ function txError (err) { } function cancelMsg (msgData) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { @@ -1346,9 +1333,7 @@ function cancelMsg (msgData) { dispatch(actions.completedTx(msgData.id)) - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return resolve(msgData) }) @@ -1357,7 +1342,7 @@ function cancelMsg (msgData) { } function cancelPersonalMsg (msgData) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { @@ -1372,9 +1357,7 @@ function cancelPersonalMsg (msgData) { dispatch(actions.completedTx(id)) - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return resolve(msgData) }) @@ -1383,7 +1366,7 @@ function cancelPersonalMsg (msgData) { } function cancelTypedMsg (msgData) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { @@ -1398,9 +1381,7 @@ function cancelTypedMsg (msgData) { dispatch(actions.completedTx(id)) - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return resolve(msgData) }) @@ -1409,12 +1390,11 @@ function cancelTypedMsg (msgData) { } function cancelTx (txData) { - return (dispatch, getState) => { + return (dispatch) => { log.debug(`background.cancelTransaction`) dispatch(actions.showLoadingIndication()) - return new Promise((resolve, reject) => { - background.cancelTransaction(txData.id, err => { + background.cancelTransaction(txData.id, (err) => { if (err) { return reject(err) } @@ -1423,15 +1403,12 @@ function cancelTx (txData) { }) }) .then(() => updateMetamaskStateFromBackground()) - .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then((newState) => dispatch(actions.updateMetamaskState(newState))) .then(() => { dispatch(actions.clearSend()) dispatch(actions.completedTx(txData.id)) dispatch(actions.hideLoadingIndication()) - - if (!hasUnconfirmedTransactions(getState())) { - return global.platform.closeNotificationWindow() - } + dispatch(actions.closeCurrentNotificationWindow()) return txData }) @@ -1444,9 +1421,9 @@ function cancelTx (txData) { * @return {function(*): Promise} */ function cancelTxs (txDataList) { - return async (dispatch, getState) => { + return async (dispatch) => { dispatch(actions.showLoadingIndication()) - const txIds = txDataList.map(({id}) => id) + const txIds = txDataList.map(({ id }) => id) const cancellations = txIds.map((id) => new Promise((resolve, reject) => { background.cancelTransaction(id, (err) => { if (err) { @@ -1468,30 +1445,12 @@ function cancelTxs (txDataList) { dispatch(actions.hideLoadingIndication()) - if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) { + if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { return global.platform.closeCurrentWindow() } } } -/** - * @deprecated - * @param {Array} txsData - * @return {Function} - */ -function cancelAllTx (txsData) { - return (dispatch) => { - txsData.forEach((txData, i) => { - background.cancelTransaction(txData.id, () => { - dispatch(actions.completedTx(txData.id)) - if (i === txsData.length - 1) { - dispatch(actions.goHome()) - global.platform.closeNotificationWindow() - } - }) - }) - } -} // // initialize screen // @@ -1762,9 +1721,10 @@ function showConfTxPage (screenParams) { } } -function nextTx () { +function nextTx (txId) { return { type: actions.NEXT_TX, + value: txId, } } @@ -1775,12 +1735,6 @@ function viewPendingTx (txId) { } } -function previousTx () { - return { - type: actions.PREVIOUS_TX, - } -} - function editTx (txId) { return { type: actions.EDIT_TX, @@ -2131,6 +2085,23 @@ function hideModal (payload) { } } +function closeCurrentNotificationWindow () { + return (dispatch, getState) => { + if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION && + !hasUnconfirmedTransactions(getState())) { + global.platform.closeCurrentWindow() + + dispatch(actions.closeNotificationWindow()) + } + } +} + +function closeNotificationWindow () { + return { + type: actions.CLOSE_NOTIFICATION_WINDOW, + } +} + function showSidebar ({ transitionName, type }) { return { type: actions.SIDEBAR_OPEN, @@ -2335,7 +2306,7 @@ function showSendContractPage ({methodSelected, methodABI, inputValues}) { function buyEth (opts) { return (dispatch) => { const url = getBuyEthUrl(opts) - global.platform.openWindow({ url }) + global.platform.openTab({ url }) dispatch({ type: actions.BUY_ETH, }) diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index 22f7e5c23..ed3ea34d5 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -68,7 +68,7 @@ TokenMenuDropdown.prototype.render = function () { onClick: (e) => { e.stopPropagation() const url = ethNetProps.explorerLinks.getExplorerAccountLinkFor(this.props.token.address, this.props.network) - global.platform.openWindow({ url }) + global.platform.openTab({ url }) this.props.onClose() }, text: this.context.t('viewOnEtherscan'), diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index b86adde20..230da2438 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -79,7 +79,8 @@ function reduceApp (state, action) { customHdPaths: customHdPaths, }, state.appState) - let curPendingTxIndex = appState.currentView.pendingTxIndex || 0 + const curPendingTxIndex = appState.currentView.pendingTxIndex || 0 + const curPendingTxId = appState.currentView.pendingTxId || 0 switch (action.type) { // dropdown methods @@ -507,6 +508,7 @@ function reduceApp (state, action) { currentView: { name: 'confTx', pendingTxIndex: action.id ? indexForPending(state, action.id) : 0, + pendingTxId: action.id, screenParams: action.value, }, transForward: action.transForward, @@ -559,11 +561,14 @@ function reduceApp (state, action) { } case actions.NEXT_TX: + const increment = (action.value - curPendingTxId) return extend(appState, { transForward: true, currentView: { name: 'confTx', - pendingTxIndex: ++curPendingTxIndex, + pendingTxIndex: curPendingTxIndex + increment, + pendingTxId: action.value, + index: curPendingTxIndex + increment, warning: null, }, }) @@ -575,16 +580,7 @@ function reduceApp (state, action) { currentView: { name: 'confTx', pendingTxIndex, - warning: null, - }, - }) - - case actions.PREVIOUS_TX: - return extend(appState, { - transForward: false, - currentView: { - name: 'confTx', - pendingTxIndex: --curPendingTxIndex, + pendingTxId: action.value, warning: null, }, }) diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js index cf2848dcc..594fa93fe 100644 --- a/ui/app/selectors/confirm-transaction.js +++ b/ui/app/selectors/confirm-transaction.js @@ -6,6 +6,8 @@ import { roundExponential } from '../helpers/confirm-transaction/util' const unapprovedTxsSelector = state => state.metamask.unapprovedTxs const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs const unapprovedPersonalMsgsSelector = state => state.metamask.unapprovedPersonalMsgs +const unapprovedDecryptMsgsSelector = (state) => state.metamask.unapprovedDecryptMsgs +const unapprovedEncryptionPublicKeyMsgsSelector = (state) => state.metamask.unapprovedEncryptionPublicKeyMsgs const unapprovedTypedMessagesSelector = state => state.metamask.unapprovedTypedMessages const networkSelector = state => state.metamask.network @@ -13,18 +15,24 @@ export const unconfirmedTransactionsListSelector = createSelector( unapprovedTxsSelector, unapprovedMsgsSelector, unapprovedPersonalMsgsSelector, + unapprovedDecryptMsgsSelector, + unapprovedEncryptionPublicKeyMsgsSelector, unapprovedTypedMessagesSelector, networkSelector, ( unapprovedTxs = {}, unapprovedMsgs = {}, unapprovedPersonalMsgs = {}, + unapprovedDecryptMsgs = {}, + unapprovedEncryptionPublicKeyMsgs = {}, unapprovedTypedMessages = {}, network, ) => txHelper( unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, + unapprovedDecryptMsgs, + unapprovedEncryptionPublicKeyMsgs, unapprovedTypedMessages, network, ) || [], @@ -34,12 +42,16 @@ export const unconfirmedTransactionsHashSelector = createSelector( unapprovedTxsSelector, unapprovedMsgsSelector, unapprovedPersonalMsgsSelector, + unapprovedDecryptMsgsSelector, + unapprovedEncryptionPublicKeyMsgsSelector, unapprovedTypedMessagesSelector, networkSelector, ( unapprovedTxs = {}, unapprovedMsgs = {}, unapprovedPersonalMsgs = {}, + unapprovedDecryptMsgs = {}, + unapprovedEncryptionPublicKeyMsgs = {}, unapprovedTypedMessages = {}, network, ) => { @@ -58,6 +70,8 @@ export const unconfirmedTransactionsHashSelector = createSelector( ...filteredUnapprovedTxs, ...unapprovedMsgs, ...unapprovedPersonalMsgs, + ...unapprovedDecryptMsgs, + ...unapprovedEncryptionPublicKeyMsgs, ...unapprovedTypedMessages, } }, @@ -65,18 +79,24 @@ export const unconfirmedTransactionsHashSelector = createSelector( const unapprovedMsgCountSelector = state => state.metamask.unapprovedMsgCount const unapprovedPersonalMsgCountSelector = state => state.metamask.unapprovedPersonalMsgCount +const unapprovedDecryptMsgCountSelector = (state) => state.metamask.unapprovedDecryptMsgCount +const unapprovedEncryptionPublicKeyMsgCountSelector = (state) => state.metamask.unapprovedEncryptionPublicKeyMsgCount const unapprovedTypedMessagesCountSelector = state => state.metamask.unapprovedTypedMessagesCount export const unconfirmedTransactionsCountSelector = createSelector( unapprovedTxsSelector, unapprovedMsgCountSelector, unapprovedPersonalMsgCountSelector, + unapprovedDecryptMsgCountSelector, + unapprovedEncryptionPublicKeyMsgCountSelector, unapprovedTypedMessagesCountSelector, networkSelector, ( unapprovedTxs = {}, unapprovedMsgCount = 0, unapprovedPersonalMsgCount = 0, + unapprovedDecryptMsgCount = 0, + unapprovedEncryptionPublicKeyMsgCount = 0, unapprovedTypedMessagesCount = 0, network, ) => { @@ -86,7 +106,7 @@ export const unconfirmedTransactionsCountSelector = createSelector( }) return filteredUnapprovedTxIds.length + unapprovedTypedMessagesCount + unapprovedMsgCount + - unapprovedPersonalMsgCount + unapprovedPersonalMsgCount + unapprovedDecryptMsgCount + unapprovedEncryptionPublicKeyMsgCount }, ) @@ -132,15 +152,16 @@ export const tokenAmountAndToAddressSelector = createSelector( let tokenAmount = 0 if (params && params.length) { - const toParam = params.find(param => param.name === TOKEN_PARAM_TO) - const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE) + const toParam = params.find((param) => param.name === TOKEN_PARAM_TO) + const valueParam = params.find((param) => param.name === TOKEN_PARAM_VALUE) toAddress = toParam ? toParam.value : params[0].value const value = valueParam ? Number(valueParam.value) : Number(params[1].value) - tokenAmount = roundExponential(value) if (tokenDecimals) { - tokenAmount = calcTokenAmount(value, tokenDecimals) + tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber() } + + tokenAmount = roundExponential(tokenAmount) } return { @@ -158,11 +179,11 @@ export const approveTokenAmountAndToAddressSelector = createSelector( let tokenAmount = 0 if (params && params.length) { - toAddress = params.find(param => param.name === TOKEN_PARAM_SPENDER).value - const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) + toAddress = params.find((param) => param.name === TOKEN_PARAM_SPENDER).value + const value = Number(params.find((param) => param.name === TOKEN_PARAM_VALUE).value) if (tokenDecimals) { - tokenAmount = calcTokenAmount(value, tokenDecimals) + tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber() } tokenAmount = roundExponential(tokenAmount) @@ -183,11 +204,11 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector( let tokenAmount = 0 if (params && params.length) { - toAddress = params.find(param => param.name === TOKEN_PARAM_TO).value - let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) + toAddress = params.find((param) => param.name === TOKEN_PARAM_TO).value + let value = Number(params.find((param) => param.name === TOKEN_PARAM_VALUE).value) if (tokenDecimals) { - value = calcTokenAmount(value, tokenDecimals) + value = calcTokenAmount(value, tokenDecimals).toNumber() } tokenAmount = roundExponential(value) diff --git a/ui/index.js b/ui/index.js index e5fab15a3..2ae86f616 100644 --- a/ui/index.js +++ b/ui/index.js @@ -54,9 +54,8 @@ async function startApp (metamaskState, accountManager, opts) { const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network) const numberOfUnapprivedTx = unapprovedTxsAll.length if (numberOfUnapprivedTx > 0) { - store.dispatch(actions.showConfTxPage({ - id: unapprovedTxsAll[numberOfUnapprivedTx - 1].id, + id: unapprovedTxsAll[0].id, })) }