Merge pull request #7635 from MetaMask/Version-v7.7.1

Version v7.7.1 RC
feature/default_network_editable
Dan Finlay 5 years ago committed by GitHub
commit 70bbb689d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      CHANGELOG.md
  2. 2
      app/manifest.json
  3. 2
      app/scripts/controllers/app-state.js
  4. 11
      app/scripts/controllers/transactions/index.js
  5. 7
      app/scripts/controllers/transactions/tx-state-manager.js
  6. 16
      app/scripts/lib/ens-ipfs/setup.js
  7. 4
      app/scripts/lib/select-chain-id.js
  8. 1
      app/scripts/metamask-controller.js
  9. 3
      ui/app/components/app/account-menu/account-menu.component.js
  10. 1
      ui/app/components/app/dropdowns/components/dropdown.js
  11. 10
      ui/app/components/app/modals/notification-modal.js
  12. 1
      ui/app/components/app/transaction-list-item/index.scss
  13. 4
      ui/app/ducks/metamask/metamask.js
  14. 13
      ui/app/pages/create-account/connect-hardware/index.js
  15. 18
      ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js
  16. 25
      ui/app/pages/first-time-flow/create-password/new-account/new-account.component.js
  17. 1
      ui/app/pages/send/send.component.js
  18. 40
      ui/app/pages/send/tests/send-component.test.js

@ -2,6 +2,33 @@
## Current Develop Branch
## 7.7.1 Wed Dec 04 2019
- [#7488](https://github.com/MetaMask/metamask-extension/pull/7488): Fix text overlap when expanding transaction
- [#7491](https://github.com/MetaMask/metamask-extension/pull/7491): Update gas when asset is changed on send screen
- [#7500](https://github.com/MetaMask/metamask-extension/pull/7500): Remove unused onClick prop from Dropdown component
- [#7502](https://github.com/MetaMask/metamask-extension/pull/7502): Fix chainId for non standard networks
- [#7519](https://github.com/MetaMask/metamask-extension/pull/7519): Fixing hardware connect error display
- [#7501](https://github.com/MetaMask/metamask-extension/pull/7501): Fix accessibility of first-time-flow terms checkboxes
- [#7579](https://github.com/MetaMask/metamask-extension/pull/7579): Prevent Maker migration dismissal timeout state from being overwritten
- [#7581](https://github.com/MetaMask/metamask-extension/pull/7581): Persist Maker migration dismissal timeout
- [#7484](https://github.com/MetaMask/metamask-extension/pull/7484): Ensure transactions are shown in the order they are received
- [#7604](https://github.com/MetaMask/metamask-extension/pull/7604): Process URL fragment for ens-ipfs redirects
- [#7628](https://github.com/MetaMask/metamask-extension/pull/7628): Fix typo that resulted in degrated account menu performance
- [#7558](https://github.com/MetaMask/metamask-extension/pull/7558): Use localized messages for NotificationModal buttons
## 7.7.0 Thu Nov 28 2019 [WITHDRAWN]
- [#7004](https://github.com/MetaMask/metamask-extension/pull/7004): Connect distinct accounts per site
- [#7480](https://github.com/MetaMask/metamask-extension/pull/7480): Fixed link on root README.md
- [#7482](https://github.com/MetaMask/metamask-extension/pull/7482): Update Wyre ETH purchase url
- [#7484](https://github.com/MetaMask/metamask-extension/pull/7484): Ensure transactions are shown in the order they are received
- [#7491](https://github.com/MetaMask/metamask-extension/pull/7491): Update gas when token is changed on the send screen
- [#7501](https://github.com/MetaMask/metamask-extension/pull/7501): Fix accessibility of first-time-flow terms checkboxes
- [#7502](https://github.com/MetaMask/metamask-extension/pull/7502): Fix chainId for non standard networks
- [#7579](https://github.com/MetaMask/metamask-extension/pull/7579): Fix timing of DAI migration notifications after dismissal
- [#7519](https://github.com/MetaMask/metamask-extension/pull/7519): Fixing hardware connect error display
- [#7558](https://github.com/MetaMask/metamask-extension/pull/7558): Use localized messages for NotificationModal buttons
- [#7488](https://github.com/MetaMask/metamask-extension/pull/7488): Fix text overlap when expanding transaction
## 7.6.1 Tue Nov 19 2019
- [#7475](https://github.com/MetaMask/metamask-extension/pull/7475): Add 'Remind Me Later' to the Maker notification
- [#7436](https://github.com/MetaMask/metamask-extension/pull/7436): Add additional rpcUrl verification

@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
"version": "7.6.1",
"version": "7.7.1",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",

@ -45,7 +45,7 @@ class AppStateController {
* @private
*/
_setInactiveTimeout (timeoutMinutes) {
this.store.putState({
this.store.updateState({
timeoutMinutes,
})

@ -192,13 +192,18 @@ class TransactionController extends EventEmitter {
throw new Error(`Transaction from address isn't valid for this account`)
}
txUtils.validateTxParams(normalizedTxParams)
// construct txMeta
const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams)
/**
`generateTxMeta` adds the default txMeta properties to the passed object.
These include the tx's `id`. As we use the id for determining order of
txes in the tx-state-manager, it is necessary to call the asynchronous
method `this._determineTransactionCategory` after `generateTxMeta`.
*/
let txMeta = this.txStateManager.generateTxMeta({
txParams: normalizedTxParams,
type: TRANSACTION_TYPE_STANDARD,
transactionCategory,
})
const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams)
txMeta.transactionCategory = transactionCategory
this.addTx(txMeta)
this.emit('newUnapprovedTx', txMeta)

@ -159,7 +159,12 @@ class TransactionStateManager extends EventEmitter {
transactions.splice(index, 1)
}
}
transactions.push(txMeta)
const newTxIndex = transactions
.findIndex((currentTxMeta) => currentTxMeta.time > txMeta.time)
newTxIndex === -1
? transactions.push(txMeta)
: transactions.splice(newTxIndex, 0, txMeta)
this._saveTxList(transactions)
return txMeta
}

@ -26,22 +26,22 @@ function setupEnsIpfsResolver ({ provider }) {
if (tabId === -1) return
// parse ens name
const urlData = urlUtil.parse(url)
const { hostname: name, path, search } = urlData
const { hostname: name, path, search, hash: fragment } = urlData
const domainParts = name.split('.')
const topLevelDomain = domainParts[domainParts.length - 1]
// if unsupported TLD, abort
if (!supportedTopLevelDomains.includes(topLevelDomain)) return
// otherwise attempt resolve
attemptResolve({ tabId, name, path, search })
attemptResolve({ tabId, name, path, search, fragment })
}
async function attemptResolve ({ tabId, name, path, search }) {
async function attemptResolve ({ tabId, name, path, search, fragment }) {
extension.tabs.update(tabId, { url: `loading.html` })
let url = `https://manager.ens.domains/name/${name}`
let url = `https://app.ens.domains/name/${name}`
try {
const {type, hash} = await resolveEnsToIpfsContentId({ provider, name })
if (type === 'ipfs-ns') {
const resolvedUrl = `https://gateway.ipfs.io/ipfs/${hash}${path}${search || ''}`
const resolvedUrl = `https://gateway.ipfs.io/ipfs/${hash}${path}${search || ''}${fragment || ''}`
try {
// check if ipfs gateway has result
const response = await fetch(resolvedUrl, { method: 'HEAD' })
@ -50,11 +50,11 @@ function setupEnsIpfsResolver ({ provider }) {
console.warn(err)
}
} else if (type === 'swarm-ns') {
url = `https://swarm-gateways.net/bzz:/${hash}${path}${search || ''}`
url = `https://swarm-gateways.net/bzz:/${hash}${path}${search || ''}${fragment || ''}`
} else if (type === 'onion' || type === 'onion3') {
url = `http://${hash}.onion${path}${search || ''}`
url = `http://${hash}.onion${path}${search || ''}${fragment || ''}`
} else if (type === 'zeronet') {
url = `http://127.0.0.1:43110/${hash}${path}${search || ''}`
url = `http://127.0.0.1:43110/${hash}${path}${search || ''}${fragment || ''}`
}
} catch (err) {
console.warn(err)

@ -15,8 +15,8 @@ const standardNetworkId = {
}
function selectChainId (metamaskState) {
const { network, provider: { chaindId } } = metamaskState
return standardNetworkId[network] || `0x${parseInt(chaindId, 10).toString(16)}`
const { network, provider: { chainId } } = metamaskState
return standardNetworkId[network] || `0x${parseInt(chainId, 10).toString(16)}`
}
module.exports = selectChainId

@ -109,6 +109,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.appStateController = new AppStateController({
preferencesStore: this.preferencesController.store,
onInactiveTimeout: () => this.setLocked(),
initState: initState.AppStateController,
})
// currency controller

@ -28,7 +28,6 @@ export default class AccountMenu extends PureComponent {
history: PropTypes.object,
identities: PropTypes.object,
isAccountMenuOpen: PropTypes.bool,
prevIsAccountMenuOpen: PropTypes.bool,
keyrings: PropTypes.array,
lockMetamask: PropTypes.func,
selectedAddress: PropTypes.string,
@ -42,7 +41,7 @@ export default class AccountMenu extends PureComponent {
}
componentDidUpdate (prevProps) {
const { prevIsAccountMenuOpen } = prevProps
const { isAccountMenuOpen: prevIsAccountMenuOpen } = prevProps
const { isAccountMenuOpen } = this.props
if (!prevIsAccountMenuOpen && isAccountMenuOpen) {

@ -58,7 +58,6 @@ Dropdown.defaultProps = {
Dropdown.propTypes = {
isOpen: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
children: PropTypes.node,
style: PropTypes.object.isRequired,
onClickOutside: PropTypes.func,

@ -5,6 +5,10 @@ const connect = require('react-redux').connect
const actions = require('../../../store/actions')
class NotificationModal extends Component {
static contextProps = {
t: PropTypes.func.isRequired,
}
render () {
const {
header,
@ -15,6 +19,8 @@ class NotificationModal extends Component {
onConfirm,
} = this.props
const { t } = this.context
const showButtons = showCancelButton || showConfirmButton
return h('div', [
@ -39,14 +45,14 @@ class NotificationModal extends Component {
showCancelButton && h('div.btn-default.notification-modal__buttons__btn', {
onClick: hideModal,
}, 'Cancel'),
}, t('cancel')),
showConfirmButton && h('div.button.btn-secondary.notification-modal__buttons__btn', {
onClick: () => {
onConfirm()
hideModal()
},
}, 'Confirm'),
}, t('confirm')),
]),

@ -139,6 +139,7 @@
&__expander {
max-height: 0px;
width: 100%;
overflow: hidden;
&--show {
max-height: 1000px;

@ -322,7 +322,9 @@ function reduceMetamask (state, action) {
let { selectedAddressTxList } = metamaskState
selectedAddressTxList = selectedAddressTxList.map(tx => {
if (tx.id === txId) {
tx.txParams = value
const newTx = Object.assign({}, tx)
newTx.txParams = value
return newTx
}
return tx
})

@ -116,10 +116,11 @@ class ConnectHardwareForm extends Component {
}
})
.catch(e => {
if (e === 'Window blocked') {
const errorMessage = e.message
if (errorMessage === 'Window blocked') {
this.setState({ browserSupported: false, error: null})
} else if (e !== 'Window closed' && e !== 'Popup closed') {
this.setState({ error: e.toString() })
} else if (errorMessage !== 'Window closed' && errorMessage !== 'Popup closed') {
this.setState({ error: errorMessage })
}
})
}
@ -134,7 +135,7 @@ class ConnectHardwareForm extends Component {
unlocked: false,
})
}).catch(e => {
this.setState({ error: e.toString() })
this.setState({ error: e.message })
})
}
@ -162,10 +163,10 @@ class ConnectHardwareForm extends Component {
name: 'Error connecting hardware wallet',
},
customVariables: {
error: e.toString(),
error: e.message,
},
})
this.setState({ error: e.toString() })
this.setState({ error: e.message })
})
}

@ -175,6 +175,12 @@ export default class ImportWithSeedPhrase extends PureComponent {
return !passwordError && !confirmPasswordError && !seedPhraseError
}
onTermsKeyPress = ({key}) => {
if (key === ' ' || key === 'Enter') {
this.toggleTermsCheck()
}
}
toggleTermsCheck = () => {
this.context.metricsEvent({
eventOpts: {
@ -183,7 +189,6 @@ export default class ImportWithSeedPhrase extends PureComponent {
name: 'Check ToS',
},
})
this.setState((prevState) => ({
termsChecked: !prevState.termsChecked,
}))
@ -267,10 +272,17 @@ export default class ImportWithSeedPhrase extends PureComponent {
largeLabel
/>
<div className="first-time-flow__checkbox-container" onClick={this.toggleTermsCheck}>
<div className="first-time-flow__checkbox">
<div
className="first-time-flow__checkbox"
tabIndex="0"
role="checkbox"
onKeyPress={this.onTermsKeyPress}
aria-checked={termsChecked}
aria-labelledby="ftf-chk1-label"
>
{termsChecked ? <i className="fa fa-check fa-2x" /> : null}
</div>
<span className="first-time-flow__checkbox-label">
<span id="ftf-chk1-label" className="first-time-flow__checkbox-label">
I have read and agree to the <a
href="https://metamask.io/terms.html"
target="_blank"

@ -3,7 +3,6 @@ import PropTypes from 'prop-types'
import Button from '../../../../components/ui/button'
import {
INITIALIZE_SEED_PHRASE_ROUTE,
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
INITIALIZE_SELECT_ACTION_ROUTE,
} from '../../../../helpers/constants/routes'
import TextField from '../../../../components/ui/text-field'
@ -115,13 +114,6 @@ export default class NewAccount extends PureComponent {
}
}
handleImportWithSeedPhrase = event => {
const { history } = this.props
event.preventDefault()
history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE)
}
toggleTermsCheck = () => {
this.context.metricsEvent({
eventOpts: {
@ -136,6 +128,12 @@ export default class NewAccount extends PureComponent {
}))
}
onTermsKeyPress = ({key}) => {
if (key === ' ' || key === 'Enter') {
this.toggleTermsCheck()
}
}
render () {
const { t } = this.context
const { password, confirmPassword, passwordError, confirmPasswordError, termsChecked } = this.state
@ -195,10 +193,17 @@ export default class NewAccount extends PureComponent {
largeLabel
/>
<div className="first-time-flow__checkbox-container" onClick={this.toggleTermsCheck}>
<div className="first-time-flow__checkbox">
<div
className="first-time-flow__checkbox"
tabIndex="0"
role="checkbox"
onKeyPress={this.onTermsKeyPress}
aria-checked={termsChecked}
aria-labelledby="ftf-chk1-label"
>
{termsChecked ? <i className="fa fa-check fa-2x" /> : null}
</div>
<span className="first-time-flow__checkbox-label">
<span id="ftf-chk1-label" className="first-time-flow__checkbox-label">
I have read and agree to the <a
href="https://metamask.io/terms.html"
target="_blank"

@ -165,6 +165,7 @@ export default class SendTransactionScreen extends PersistentForm {
if (selectedTokenAddress && prevTokenAddress !== selectedTokenAddress) {
this.updateSendToken()
this.updateGas()
}
}

@ -57,10 +57,10 @@ describe('Send Component', function () {
primaryCurrency="mockPrimaryCurrency"
recentBlocks={['mockBlock']}
selectedAddress="mockSelectedAddress"
selectedToken="mockSelectedToken"
selectedToken={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }}
showHexData
tokenBalance="mockTokenBalance"
tokenContract="mockTokenContract"
tokenContract={{ method: 'mockTokenMethod' }}
updateAndSetGasLimit={propsMethodSpies.updateAndSetGasLimit}
updateSendErrors={propsMethodSpies.updateSendErrors}
updateSendTokenBalance={propsMethodSpies.updateSendTokenBalance}
@ -79,6 +79,7 @@ describe('Send Component', function () {
propsMethodSpies.updateAndSetGasLimit.resetHistory()
propsMethodSpies.updateSendErrors.resetHistory()
propsMethodSpies.updateSendTokenBalance.resetHistory()
propsMethodSpies.updateToNicknameIfNecessary.resetHistory()
})
it('should call componentDidMount', () => {
@ -129,7 +130,7 @@ describe('Send Component', function () {
prevBalance: '',
prevGasTotal: undefined,
prevTokenBalance: undefined,
selectedToken: 'mockSelectedToken',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
tokenBalance: 'mockTokenBalance',
}
)
@ -162,7 +163,7 @@ describe('Send Component', function () {
conversionRate: 10,
gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency',
selectedToken: 'mockSelectedToken',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
tokenBalance: 'mockTokenBalance',
}
)
@ -184,7 +185,7 @@ describe('Send Component', function () {
conversionRate: 10,
gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency',
selectedToken: 'mockSelectedToken',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
}
)
})
@ -225,7 +226,7 @@ describe('Send Component', function () {
it('should call updateSendErrors with the expected params if selectedToken is truthy', () => {
propsMethodSpies.updateSendErrors.resetHistory()
wrapper.setProps({ selectedToken: 'someToken' })
wrapper.setProps({ selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }})
wrapper.instance().componentDidUpdate({
from: {
balance: 'balanceChanged',
@ -246,6 +247,7 @@ describe('Send Component', function () {
balance: 'balanceChanged',
},
network: '3',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
})
assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0)
assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0)
@ -260,6 +262,7 @@ describe('Send Component', function () {
balance: 'balanceChanged',
},
network: '3',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
})
assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0)
assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0)
@ -273,13 +276,14 @@ describe('Send Component', function () {
balance: 'balanceChanged',
},
network: '2',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
})
assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 1)
assert.deepEqual(
propsMethodSpies.updateSendTokenBalance.getCall(0).args[0],
{
selectedToken: 'mockSelectedToken',
tokenContract: 'mockTokenContract',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
tokenContract: { method: 'mockTokenMethod' },
address: 'mockAddress',
}
)
@ -289,6 +293,20 @@ describe('Send Component', function () {
[]
)
})
it('should call updateGas when selectedToken.address is changed', () => {
SendTransactionScreen.prototype.updateGas.resetHistory()
propsMethodSpies.updateAndSetGasLimit.resetHistory()
wrapper.instance().componentDidUpdate({
from: {
balance: 'balancedChanged',
},
network: '3', // Make sure not to hit updateGas when changing network
selectedToken: { address: 'newSelectedToken' },
})
assert.equal(propsMethodSpies.updateToNicknameIfNecessary.callCount, 0) // Network did not change
assert.equal(propsMethodSpies.updateAndSetGasLimit.callCount, 1)
})
})
describe('updateGas', () => {
@ -305,7 +323,7 @@ describe('Send Component', function () {
gasPrice: 'mockGasPrice',
recentBlocks: ['mockBlock'],
selectedAddress: 'mockSelectedAddress',
selectedToken: 'mockSelectedToken',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
to: '',
value: 'mockAmount',
data: undefined,
@ -431,9 +449,7 @@ describe('Send Component', function () {
})
it('should warn when send to a known token contract address', () => {
wrapper.setProps({
selectedToken: '0x888',
})
wrapper.setProps({ address: '0x888', decimals: 18, symbol: '888' })
const instance = wrapper.instance()
instance.onRecipientInputChange('0x13cb85823f78Cff38f0B0E90D3e975b8CB3AAd64')

Loading…
Cancel
Save