diff --git a/CHANGELOG.md b/CHANGELOG.md
index a42139678..c2d1ff61c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
## Current Develop Branch
+## 8.1.2 Mon Oct 19 2020
+- [#9608](https://github.com/MetaMask/metamask-extension/pull/9608): Ensure QR code scanner works
+- [#9624](https://github.com/MetaMask/metamask-extension/pull/9624): Help users avoid insufficient gas prices in swaps
+- [#9614](https://github.com/MetaMask/metamask-extension/pull/9614): Update swaps network fee tooltip
+- [#9623](https://github.com/MetaMask/metamask-extension/pull/9623): Prevent reducing the gas limit for swaps
+- [#9630](https://github.com/MetaMask/metamask-extension/pull/9630): Fix UI crash when trying to render estimated time remaining of non-submitted transaction
+- [#9633](https://github.com/MetaMask/metamask-extension/pull/9633): Update View Quote page to better represent the MetaMask fee
+
## 8.1.1 Tue Oct 13 2020
- [#9586](https://github.com/MetaMask/metamask-extension/pull/9586): Prevent build quote crash when swapping from non-tracked token with balance (#9586)
- [#9592](https://github.com/MetaMask/metamask-extension/pull/9592): Remove commitment to maintain a public metrics dashboard (#9592)
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 3188d7894..a4710ccbf 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -708,6 +708,10 @@
"gasLimitTooLow": {
"message": "Gas limit must be at least 21000"
},
+ "gasLimitTooLowWithDynamicFee": {
+ "message": "Gas limit must be at least $1",
+ "description": "$1 is the custom gas limit, in decimal."
+ },
"gasPrice": {
"message": "Gas Price (GWEI)"
},
@@ -1643,6 +1647,10 @@
"swapEstimatedNetworkFee": {
"message": "Estimated network fee"
},
+ "swapEstimatedNetworkFeeSummary": {
+ "message": "The “$1” is what we expect the actual fee to be. The exact amount depends on network conditions.",
+ "description": "$1 will be the translation of swapEstimatedNetworkFee, with the font bolded"
+ },
"swapEstimatedNetworkFees": {
"message": "Estimated network fees"
},
@@ -1677,6 +1685,9 @@
"swapFinalizing": {
"message": "Finalizing..."
},
+ "swapGasFeeSummary": {
+ "message": "The gas fee covers the cost of processing your swap and storing it on the Ethereum network. MetaMask does not profit from this fee."
+ },
"swapGetQuotes": {
"message": "Get quotes"
},
@@ -1705,7 +1716,8 @@
"message": "Transaction may fail, max slippage too low."
},
"swapMaxNetworkFeeInfo": {
- "message": "The Max network fee is the most you’ll pay to complete your transaction. The max fee helps ensure your Swap has the best chance of succeeding. MetaMask does not profit from network fees."
+ "message": "“$1” is the most you’ll spend. When the network is volatile this can be a large amount.",
+ "description": "$1 will be the translation of swapMaxNetworkFees, with the font bolded"
},
"swapMaxNetworkFees": {
"message": "Max network fee"
@@ -1717,7 +1729,7 @@
"message": "MetaMask fee"
},
"swapMetaMaskFeeDescription": {
- "message": "A service fee of $1% is automatically factored into each quote, which supports ongoing development to make MetaMask even better.",
+ "message": "We find the best price from the top liquidity sources, every time. A fee of $1% is automatically factored into each quote, which supports ongoing development to make MetaMask even better.",
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNQuotesAvailable": {
@@ -1741,6 +1753,10 @@
"swapQuoteDetailsSlippageInfo": {
"message": "If the price changes between the time your order is placed and confirmed it’s called \"slippage\". Your Swap will automatically cancel if slippage exceeds your \"max slippage\" setting."
},
+ "swapQuoteIncludesRate": {
+ "message": "Quote includes a $1% MetaMask fee",
+ "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
+ },
"swapQuoteNofN": {
"message": "Quote $1 of $2",
"description": "A count of loaded quotes shown to the user while they are waiting for quotes to be fetched. $1 is the number of quotes already loaded, and $2 is the total number of quotes to load."
diff --git a/app/manifest/_base.json b/app/manifest/_base.json
index 09bb58e6d..f32d4e9bb 100644
--- a/app/manifest/_base.json
+++ b/app/manifest/_base.json
@@ -68,6 +68,6 @@
"notifications"
],
"short_name": "__MSG_appName__",
- "version": "8.1.1",
+ "version": "8.1.2",
"web_accessible_resources": ["inpage.js", "phishing.html"]
}
diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js
index 2d97a1382..bb5563606 100644
--- a/app/scripts/lib/account-tracker.js
+++ b/app/scripts/lib/account-tracker.js
@@ -14,7 +14,7 @@ import log from 'loglevel'
import pify from 'pify'
import Web3 from 'web3'
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi'
-import { MAINNET_NETWORK_ID, RINKEBY_NETWORK_ID, ROPSTEN_NETWORK_ID, KOVAN_NETWORK_ID } from '../controllers/network/enums'
+import { MAINNET_CHAIN_ID, RINKEBY_CHAIN_ID, ROPSTEN_CHAIN_ID, KOVAN_CHAIN_ID } from '../controllers/network/enums'
import {
SINGLE_CALL_BALANCES_ADDRESS,
@@ -24,25 +24,30 @@ import {
} from '../controllers/network/contract-addresses'
import { bnToHex } from './util'
+/**
+ * This module is responsible for tracking any number of accounts and caching their current balances & transaction
+ * counts.
+ *
+ * It also tracks transaction hashes, and checks their inclusion status on each new block.
+ *
+ * @typedef {Object} AccountTracker
+ * @property {Object} store The stored object containing all accounts to track, as well as the current block's gas limit.
+ * @property {Object} store.accounts The accounts currently stored in this AccountTracker
+ * @property {string} store.currentBlockGasLimit A hex string indicating the gas limit of the current block
+ * @property {Object} _provider A provider needed to create the EthQuery instance used within this AccountTracker.
+ * @property {EthQuery} _query An EthQuery instance used to access account information from the blockchain
+ * @property {BlockTracker} _blockTracker A BlockTracker instance. Needed to ensure that accounts and their info updates
+ * when a new block is created.
+ * @property {Object} _currentBlockNumber Reference to a property on the _blockTracker: the number (i.e. an id) of the the current block
+ *
+ */
export default class AccountTracker {
/**
- * This module is responsible for tracking any number of accounts and caching their current balances & transaction
- * counts.
- *
- * It also tracks transaction hashes, and checks their inclusion status on each new block.
- *
- * @typedef {Object} AccountTracker
- * @param {Object} opts - Initialize various properties of the class.
- * @property {Object} store The stored object containing all accounts to track, as well as the current block's gas limit.
- * @property {Object} store.accounts The accounts currently stored in this AccountTracker
- * @property {string} store.currentBlockGasLimit A hex string indicating the gas limit of the current block
- * @property {Object} _provider A provider needed to create the EthQuery instance used within this AccountTracker.
- * @property {EthQuery} _query An EthQuery instance used to access account information from the blockchain
- * @property {BlockTracker} _blockTracker A BlockTracker instance. Needed to ensure that accounts and their info updates
- * when a new block is created.
- * @property {Object} _currentBlockNumber Reference to a property on the _blockTracker: the number (i.e. an id) of the the current block
- *
+ * @param {Object} opts - Options for initializing the controller
+ * @param {Object} opts.provider - An EIP-1193 provider instance that uses the current global network
+ * @param {Object} opts.blockTracker - A block tracker, which emits events for each new block
+ * @param {Function} opts.getCurrentChainId - A function that returns the `chainId` for the current global network
*/
constructor (opts = {}) {
const initState = {
@@ -61,7 +66,7 @@ export default class AccountTracker {
})
// bind function for easier listener syntax
this._updateForBlock = this._updateForBlock.bind(this)
- this.network = opts.network
+ this.getCurrentChainId = opts.getCurrentChainId
this.web3 = new Web3(this._provider)
}
@@ -196,22 +201,22 @@ export default class AccountTracker {
async _updateAccounts () {
const { accounts } = this.store.getState()
const addresses = Object.keys(accounts)
- const currentNetwork = this.network.getNetworkState()
+ const chainId = this.getCurrentChainId()
- switch (currentNetwork) {
- case MAINNET_NETWORK_ID.toString():
+ switch (chainId) {
+ case MAINNET_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS)
break
- case RINKEBY_NETWORK_ID.toString():
+ case RINKEBY_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_RINKEBY)
break
- case ROPSTEN_NETWORK_ID.toString():
+ case ROPSTEN_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN)
break
- case KOVAN_NETWORK_ID.toString():
+ case KOVAN_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_KOVAN)
break
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index b4166bde5..f66091d80 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -168,7 +168,7 @@ export default class MetamaskController extends EventEmitter {
this.accountTracker = new AccountTracker({
provider: this.provider,
blockTracker: this.blockTracker,
- network: this.networkController,
+ getCurrentChainId: this.networkController.getCurrentChainId.bind(this.networkController),
})
// start and stop polling for balances based on activeControllerConnections
diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
index 75319090d..5886f75d9 100644
--- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
+++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import classnames from 'classnames'
import { debounce } from 'lodash'
import Tooltip from '../../../ui/tooltip'
+import { MIN_GAS_LIMIT_DEC } from '../../../../pages/send/send.constants'
export default class AdvancedGasInputs extends Component {
static contextTypes = {
@@ -18,6 +19,11 @@ export default class AdvancedGasInputs extends Component {
customPriceIsSafe: PropTypes.bool,
isSpeedUp: PropTypes.bool,
customGasLimitMessage: PropTypes.string,
+ minimumGasLimit: PropTypes.number,
+ }
+
+ static defaultProps = {
+ minimumGasLimit: Number(MIN_GAS_LIMIT_DEC),
}
constructor (props) {
@@ -84,7 +90,7 @@ export default class AdvancedGasInputs extends Component {
return {}
}
- gasLimitError ({ insufficientBalance, gasLimit }) {
+ gasLimitError ({ insufficientBalance, gasLimit, minimumGasLimit }) {
const { t } = this.context
if (insufficientBalance) {
@@ -92,9 +98,9 @@ export default class AdvancedGasInputs extends Component {
errorText: t('insufficientBalance'),
errorType: 'error',
}
- } else if (gasLimit < 21000) {
+ } else if (gasLimit < minimumGasLimit) {
return {
- errorText: t('gasLimitTooLow'),
+ errorText: t('gasLimitTooLowWithDynamicFee', [minimumGasLimit]),
errorType: 'error',
}
}
@@ -153,6 +159,7 @@ export default class AdvancedGasInputs extends Component {
customPriceIsSafe,
isSpeedUp,
customGasLimitMessage,
+ minimumGasLimit,
} = this.props
const {
gasPrice,
@@ -172,7 +179,7 @@ export default class AdvancedGasInputs extends Component {
const {
errorText: gasLimitErrorText,
errorType: gasLimitErrorType,
- } = this.gasLimitError({ insufficientBalance, gasLimit })
+ } = this.gasLimitError({ insufficientBalance, gasLimit, minimumGasLimit })
const gasLimitErrorComponent = gasLimitErrorType ? (