mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-23 02:10:12 +01:00
Fix calculation of data property for gas estimation on token transfers.
This commit is contained in:
parent
701611e317
commit
1b879f45bc
@ -732,7 +732,6 @@ function setGasTotal (gasTotal) {
|
||||
|
||||
function updateGasData ({
|
||||
blockGasLimit,
|
||||
data,
|
||||
recentBlocks,
|
||||
selectedAddress,
|
||||
selectedToken,
|
||||
@ -746,7 +745,6 @@ function updateGasData ({
|
||||
estimateGas({
|
||||
estimateGasMethod: background.estimateGas,
|
||||
blockGasLimit,
|
||||
data,
|
||||
selectedAddress,
|
||||
selectedToken,
|
||||
to,
|
||||
|
@ -20,7 +20,6 @@ export default class SendTransactionScreen extends PersistentForm {
|
||||
]),
|
||||
blockGasLimit: PropTypes.string,
|
||||
conversionRate: PropTypes.number,
|
||||
data: PropTypes.string,
|
||||
editingTransactionId: PropTypes.string,
|
||||
from: PropTypes.object,
|
||||
gasLimit: PropTypes.string,
|
||||
@ -43,7 +42,6 @@ export default class SendTransactionScreen extends PersistentForm {
|
||||
const {
|
||||
amount,
|
||||
blockGasLimit,
|
||||
data,
|
||||
editingTransactionId,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
@ -55,7 +53,6 @@ export default class SendTransactionScreen extends PersistentForm {
|
||||
|
||||
updateAndSetGasTotal({
|
||||
blockGasLimit,
|
||||
data,
|
||||
editingTransactionId,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
|
@ -31,7 +31,6 @@ import {
|
||||
} from '../../ducks/send.duck'
|
||||
import {
|
||||
calcGasTotal,
|
||||
generateTokenTransferData,
|
||||
} from './send.utils.js'
|
||||
|
||||
module.exports = compose(
|
||||
@ -40,15 +39,11 @@ module.exports = compose(
|
||||
)(SendEther)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const selectedAddress = getSelectedAddress(state)
|
||||
const selectedToken = getSelectedToken(state)
|
||||
|
||||
return {
|
||||
amount: getSendAmount(state),
|
||||
amountConversionRate: getAmountConversionRate(state),
|
||||
blockGasLimit: getBlockGasLimit(state),
|
||||
conversionRate: getConversionRate(state),
|
||||
data: generateTokenTransferData(selectedAddress, selectedToken),
|
||||
editingTransactionId: getSendEditingTransactionId(state),
|
||||
from: getSendFromObject(state),
|
||||
gasLimit: getGasLimit(state),
|
||||
@ -69,7 +64,6 @@ function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
updateAndSetGasTotal: ({
|
||||
blockGasLimit,
|
||||
data,
|
||||
editingTransactionId,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
@ -80,7 +74,7 @@ function mapDispatchToProps (dispatch) {
|
||||
value,
|
||||
}) => {
|
||||
!editingTransactionId
|
||||
? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, data, blockGasLimit, to, value }))
|
||||
? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, blockGasLimit, to, value }))
|
||||
: dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice)))
|
||||
},
|
||||
updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => {
|
||||
|
@ -14,6 +14,7 @@ const {
|
||||
NEGATIVE_ETH_ERROR,
|
||||
ONE_GWEI_IN_WEI_HEX,
|
||||
SIMPLE_GAS_COST,
|
||||
TOKEN_TRANSFER_FUNCTION_SIGNATURE,
|
||||
} = require('./send.constants')
|
||||
const abi = require('ethereumjs-abi')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
@ -165,26 +166,23 @@ function doesAmountErrorRequireUpdate ({
|
||||
return amountErrorRequiresUpdate
|
||||
}
|
||||
|
||||
async function estimateGas ({ selectedAddress, selectedToken, data, blockGasLimit, to, value, gasPrice, estimateGasMethod }) {
|
||||
const { symbol } = selectedToken || {}
|
||||
async function estimateGas ({ selectedAddress, selectedToken, blockGasLimit, to, value, gasPrice, estimateGasMethod }) {
|
||||
const paramsForGasEstimate = { from: selectedAddress, value, gasPrice }
|
||||
|
||||
if (symbol) {
|
||||
Object.assign(paramsForGasEstimate, { value: '0x0' })
|
||||
if (selectedToken) {
|
||||
paramsForGasEstimate.value = '0x0'
|
||||
paramsForGasEstimate.data = generateTokenTransferData({ toAddress: to, amount: value, selectedToken })
|
||||
}
|
||||
|
||||
if (data) {
|
||||
Object.assign(paramsForGasEstimate, { data })
|
||||
}
|
||||
// if recipient has no code, gas is 21k max:
|
||||
const hasRecipient = Boolean(to)
|
||||
let code
|
||||
if (hasRecipient) code = await global.eth.getCode(to)
|
||||
if (hasRecipient && (!code || code === '0x')) {
|
||||
if (hasRecipient && (!code || code === '0x') && !selectedToken) {
|
||||
return SIMPLE_GAS_COST
|
||||
}
|
||||
|
||||
paramsForGasEstimate.to = to
|
||||
paramsForGasEstimate.to = selectedToken ? selectedToken.address : to
|
||||
|
||||
// if not, fall back to block gasLimit
|
||||
paramsForGasEstimate.gas = ethUtil.addHexPrefix(multiplyCurrencies(blockGasLimit, 0.95, {
|
||||
@ -212,11 +210,10 @@ async function estimateGas ({ selectedAddress, selectedToken, data, blockGasLimi
|
||||
})
|
||||
}
|
||||
|
||||
function generateTokenTransferData (selectedAddress, selectedToken) {
|
||||
function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', selectedToken }) {
|
||||
if (!selectedToken) return
|
||||
console.log(`abi.rawEncode`, abi.rawEncode)
|
||||
return Array.prototype.map.call(
|
||||
abi.rawEncode(['address', 'uint256'], [selectedAddress, '0x0']),
|
||||
return TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call(
|
||||
abi.rawEncode(['address', 'uint256'], [toAddress, ethUtil.addHexPrefix(amount)]),
|
||||
x => ('00' + x.toString(16)).slice(-2)
|
||||
).join('')
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ describe('Send Component', function () {
|
||||
amountConversionRate={'mockAmountConversionRate'}
|
||||
blockGasLimit={'mockBlockGasLimit'}
|
||||
conversionRate={10}
|
||||
data={'mockData'}
|
||||
editingTransactionId={'mockEditingTransactionId'}
|
||||
from={ { address: 'mockAddress', balance: 'mockBalance' } }
|
||||
gasLimit={'mockGasLimit'}
|
||||
@ -210,7 +209,6 @@ describe('Send Component', function () {
|
||||
propsMethodSpies.updateAndSetGasTotal.getCall(0).args[0],
|
||||
{
|
||||
blockGasLimit: 'mockBlockGasLimit',
|
||||
data: 'mockData',
|
||||
editingTransactionId: 'mockEditingTransactionId',
|
||||
gasLimit: 'mockGasLimit',
|
||||
gasPrice: 'mockGasPrice',
|
||||
|
@ -47,7 +47,6 @@ proxyquire('../send.container.js', {
|
||||
'../../ducks/send.duck': duckActionSpies,
|
||||
'./send.utils.js': {
|
||||
calcGasTotal: (gasLimit, gasPrice) => gasLimit + gasPrice,
|
||||
generateTokenTransferData: (a, b) => `mockData:${a + b}`,
|
||||
},
|
||||
})
|
||||
|
||||
@ -61,7 +60,6 @@ describe('send container', () => {
|
||||
amountConversionRate: 'mockAmountConversionRate:mockState',
|
||||
blockGasLimit: 'mockBlockGasLimit:mockState',
|
||||
conversionRate: 'mockConversionRate:mockState',
|
||||
data: 'mockData:mockSelectedAddress:mockStatemockSelectedToken:mockState',
|
||||
editingTransactionId: 'mockEditingTransactionId:mockState',
|
||||
from: 'mockFrom:mockState',
|
||||
gasLimit: 'mockGasLimit:mockState',
|
||||
@ -92,7 +90,6 @@ describe('send container', () => {
|
||||
describe('updateAndSetGasTotal()', () => {
|
||||
const mockProps = {
|
||||
blockGasLimit: 'mockBlockGasLimit',
|
||||
data: '0x1',
|
||||
editingTransactionId: '0x2',
|
||||
gasLimit: '0x3',
|
||||
gasPrice: '0x4',
|
||||
@ -113,14 +110,14 @@ describe('send container', () => {
|
||||
})
|
||||
|
||||
it('should dispatch an updateGasData action when editingTransactionId is falsy', () => {
|
||||
const { selectedAddress, selectedToken, data, recentBlocks, blockGasLimit, to, value } = mockProps
|
||||
const { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value } = mockProps
|
||||
mapDispatchToPropsObject.updateAndSetGasTotal(
|
||||
Object.assign({}, mockProps, {editingTransactionId: false})
|
||||
)
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
actionSpies.updateGasData.getCall(0).args[0],
|
||||
{ selectedAddress, selectedToken, data, recentBlocks, blockGasLimit, to, value }
|
||||
{ selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -106,11 +106,23 @@ describe('send utils', () => {
|
||||
|
||||
describe('generateTokenTransferData()', () => {
|
||||
it('should return undefined if not passed a selected token', () => {
|
||||
assert.equal(generateTokenTransferData('mockAddress', false), undefined)
|
||||
assert.equal(generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', selectedToken: false}), undefined)
|
||||
})
|
||||
|
||||
it('should call abi.rawEncode with the correct params', () => {
|
||||
stubs.rawEncode.resetHistory()
|
||||
generateTokenTransferData({ toAddress: 'mockAddress', amount: 'ab', selectedToken: true})
|
||||
assert.deepEqual(
|
||||
stubs.rawEncode.getCall(0).args,
|
||||
[['address', 'uint256'], ['mockAddress', '0xab']]
|
||||
)
|
||||
})
|
||||
|
||||
it('should return encoded token transfer data', () => {
|
||||
assert.equal(generateTokenTransferData('mockAddress', true), '104c')
|
||||
assert.equal(
|
||||
generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', selectedToken: true}),
|
||||
'0xa9059cbb104c'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -276,22 +288,17 @@ describe('send utils', () => {
|
||||
assert.equal(result, 'mockToString:16')
|
||||
})
|
||||
|
||||
it('should call ethQuery.estimateGas with a value of 0x0 if the passed selectedToken has a symbol', async () => {
|
||||
const result = await estimateGas(Object.assign({ selectedToken: { symbol: true } }, baseMockParams))
|
||||
it('should call ethQuery.estimateGas with a value of 0x0 and the expected data and to if passed a selectedToken', async () => {
|
||||
const result = await estimateGas(Object.assign({ data: 'mockData', selectedToken: { address: 'mockAddress' } }, baseMockParams))
|
||||
assert.equal(baseMockParams.estimateGasMethod.callCount, 1)
|
||||
assert.deepEqual(
|
||||
baseMockParams.estimateGasMethod.getCall(0).args[0],
|
||||
Object.assign({ gasPrice: undefined, value: '0x0' }, baseExpectedCall)
|
||||
)
|
||||
assert.equal(result, 'mockToString:16')
|
||||
})
|
||||
|
||||
it('should call ethQuery.estimateGas with data if data is passed', async () => {
|
||||
const result = await estimateGas(Object.assign({ data: 'mockData' }, baseMockParams))
|
||||
assert.equal(baseMockParams.estimateGasMethod.callCount, 1)
|
||||
assert.deepEqual(
|
||||
baseMockParams.estimateGasMethod.getCall(0).args[0],
|
||||
Object.assign({ gasPrice: undefined, value: undefined, data: 'mockData' }, baseExpectedCall)
|
||||
Object.assign({}, baseExpectedCall, {
|
||||
gasPrice: undefined,
|
||||
value: '0x0',
|
||||
data: '0xa9059cbb104c',
|
||||
to: 'mockAddress',
|
||||
})
|
||||
)
|
||||
assert.equal(result, 'mockToString:16')
|
||||
})
|
||||
@ -302,6 +309,12 @@ describe('send utils', () => {
|
||||
assert.equal(result, SIMPLE_GAS_COST)
|
||||
})
|
||||
|
||||
it(`should not return ${SIMPLE_GAS_COST} if passed a selectedToken`, async () => {
|
||||
assert.equal(baseMockParams.estimateGasMethod.callCount, 0)
|
||||
const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123', selectedToken: { address: '' } }))
|
||||
assert.notEqual(result, SIMPLE_GAS_COST)
|
||||
})
|
||||
|
||||
it(`should return the adjusted blockGasLimit if it fails with a 'Transaction execution error.'`, async () => {
|
||||
const result = await estimateGas(Object.assign({}, baseMockParams, {
|
||||
to: 'isContract willFailBecauseOf:Transaction execution error.',
|
||||
|
Loading…
Reference in New Issue
Block a user