diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 2eb215504..1f948bf56 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -54,15 +54,11 @@ const ethUtil = require('ethereumjs-util') const sigUtil = require('eth-sig-util') const { importTypes } = require('../../old-ui/app/accounts/import/enums') const { LEDGER, TREZOR } = require('../../old-ui/app/components/connect-hardware/enum') +const { ifPOA, ifRSK } = require('../../old-ui/app/util') const { - POA_CODE, - DAI_CODE, - POA_SOKOL_CODE, CLASSIC_CODE, - MAINNET_CODE, - RSK_CODE, - RSK_TESTNET_CODE } = require('./controllers/network/enums') + MAINNET_CODE } = require('./controllers/network/enums') const accountsPerPage = 5 module.exports = class MetamaskController extends EventEmitter { @@ -1522,6 +1518,7 @@ module.exports = class MetamaskController extends EventEmitter { const networkIdStr = networkController.store.getState().network const networkId = parseInt(networkIdStr) const isETHC = networkId === CLASSIC_CODE || networkId === MAINNET_CODE + const isRSK = ifRSK(networkId) let gasPrice if (isETHC) { @@ -1537,6 +1534,9 @@ module.exports = class MetamaskController extends EventEmitter { gasPrice = this.getGasPriceFromBlocks(networkId) resolve(gasPrice) } + } else if (isRSK) { + gasPrice = this.getGasPriceFromLastBlockRSK(networkId) + resolve(gasPrice) } else { gasPrice = this.getGasPriceFromBlocks(networkId) resolve(gasPrice) @@ -1554,7 +1554,7 @@ module.exports = class MetamaskController extends EventEmitter { getGasPriceFromBlocks (networkId) { const { recentBlocksController } = this const { recentBlocks } = recentBlocksController.store.getState() - const isPOA = networkId === POA_SOKOL_CODE || networkId === POA_CODE || networkId === DAI_CODE + const isPOA = ifPOA(networkId) // Return 1 gwei if using a POA network or if there are no blocks have been observed: if (isPOA || recentBlocks.length === 0) { @@ -1575,17 +1575,35 @@ module.exports = class MetamaskController extends EventEmitter { }) .map(number => number && number.div(GWEI_BN).toNumber()).filter(number => typeof number !== 'undefined' && number !== 0) - if (networkId === RSK_CODE || networkId === RSK_TESTNET_CODE) { - if (lowestPrices.length === 0) { - lowestPrices.push(1) - } - } - const percentileNum = percentile(65, lowestPrices) const percentileNumBn = new BN(percentileNum) return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) } + /** + * A method to get min gas price from the best block (last block in the chain) for RSK. + * https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP09.md + * Related issue: https://github.com/poanetwork/nifty-wallet/issues/301 + * @returns {string} A hex representation of the suggested wei gas price. + */ + getGasPriceFromLastBlockRSK (networkId) { + const { recentBlocksController } = this + const { recentBlocks } = recentBlocksController.store.getState() + + const recentBlock = recentBlocks + .sort((block1, block2) => block1.number - block2.number)[recentBlocks.length - 1] + + const gasPrice = recentBlock && recentBlock.minimumGasPrice + + const gasPriceInt = parseInt(gasPrice, 10) + + if (gasPriceInt !== 0) { + return '0x' + gasPriceInt.toString(16) + } else { + return '0x' + GWEI_BN.toString(16) + } + } + /** * A method for retrieving of gas price from POA gas price oracles * diff --git a/old-ui/app/util.js b/old-ui/app/util.js index a05fb3219..15c45c45a 100644 --- a/old-ui/app/util.js +++ b/old-ui/app/util.js @@ -1,6 +1,9 @@ const ethUtil = require('ethereumjs-util') const ethNetProps = require('eth-net-props') const { + POA_SOKOL_CODE, + POA_CODE, + DAI_CODE, RSK_CODE, RSK_TESTNET_CODE, } = require('../../app/scripts/controllers/network/enums') @@ -51,6 +54,7 @@ module.exports = { ifHardwareAcc, getAllKeyRingsAccounts, ifRSK, + ifPOA, toChecksumAddress, isValidChecksumAddress, } @@ -387,6 +391,12 @@ function ifRSK (network) { return numericNet === RSK_CODE || numericNet === RSK_TESTNET_CODE } +function ifPOA (network) { + if (!network) return false + const numericNet = isNaN(network) ? network : parseInt(network) + return numericNet === POA_SOKOL_CODE || numericNet === POA_CODE || numericNet === DAI_CODE +} + function toChecksumAddressRSK (address, chainId = null) { const zeroX = '0x' const stripAddress = ethUtil.stripHexPrefix(address).toLowerCase() diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index e32e17b94..074cd62b1 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -96,7 +96,7 @@ describe('MetaMaskController', function () { }) }) - describe('#getGasPrice', function () { + describe('#getGasPrice (ETH)', function () { it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () { const realRecentBlocksController = metamaskController.recentBlocksController @@ -115,6 +115,17 @@ describe('MetaMaskController', function () { }, } + + metamaskController.networkController = { + store: { + getState: () => { + return { + network: '1', + } + }, + }, + } + const gasPrice = await metamaskController.getGasPrice() assert.equal(gasPrice, '0x174876e800', 'accurately estimates 65th percentile accepted gas price') @@ -122,6 +133,71 @@ describe('MetaMaskController', function () { }) }) + describe('#getGasPrice (RSK)', function () { + + const networkController = { + store: { + getState: () => { + return { + network: '30', + } + }, + }, + } + + const recentBlocksController1 = { + store: { + getState: () => { + return { + recentBlocks: [ + { number: '0x1', minimumGasPrice: '59240010' }, + { number: '0x2', minimumGasPrice: '59240005' }, + { number: '0x3', minimumGasPrice: '59240000' }, + ], + } + }, + }, + } + + const recentBlocksController2 = { + store: { + getState: () => { + return { + recentBlocks: [ + { number: '0x4', minimumGasPrice: '0' }, + ], + } + }, + }, + } + + it('gives the min gas price from the latest block', async function () { + + metamaskController.networkController = networkController + const realRecentBlocksController = metamaskController.recentBlocksController + + metamaskController.recentBlocksController = recentBlocksController1 + + const gasPrice = await metamaskController.getGasPrice() + assert.equal(gasPrice, '0x387ee40', 'takes the min gas price from the latest block') + + metamaskController.recentBlocksController = realRecentBlocksController + }) + + it('returns not 0 gas price from the latest block', async function () { + + metamaskController.networkController = networkController + const realRecentBlocksController = metamaskController.recentBlocksController + + metamaskController.recentBlocksController = recentBlocksController2 + + const gasPrice = await metamaskController.getGasPrice() + assert.equal(gasPrice, '0x3b9aca00', 'returns not 0 for min gas price from the latest block') + + metamaskController.recentBlocksController = realRecentBlocksController + }) + }) + describe('#createNewVaultAndKeychain', function () { it('can only create new vault on keyringController once', async function () { const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity') diff --git a/test/unit/old-ui/app/util.spec.js b/test/unit/old-ui/app/util.spec.js index 4ff18eebf..6ce8dd383 100644 --- a/test/unit/old-ui/app/util.spec.js +++ b/test/unit/old-ui/app/util.spec.js @@ -14,6 +14,7 @@ const { normalizeNumberToWei, isHex, ifRSK, + ifPOA, toChecksumAddress, isValidChecksumAddress, } = require('../../../../old-ui/app/util') @@ -346,6 +347,22 @@ describe('normalizing values', function () { }) }) + + describe('#ifPOA', function () { + it('checks if this is POA chain', function () { + var resultSokol = ifPOA(77) + assert(resultSokol) + var resultCore = ifPOA(99) + assert(resultCore) + var resultXDai = ifPOA(100) + assert(resultXDai) + var resultMainnet = ifPOA(1) + assert(!resultMainnet) + var result4 = ifPOA() + assert(!result4) + }) + }) + const addr = '0xB707b030A7887a21cc595Cd139746A8c2Ed91615' const addrRSKMainnet = '0xB707b030A7887a21Cc595cD139746A8c2ED91615' const addrRSKTestnet = '0xB707b030a7887a21Cc595CD139746a8C2ED91615'