1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 18:00:18 +01:00

Merge pull request #720 from MetaMask/i#495CustomGasField

add a gasPrice field
This commit is contained in:
kumavis 2016-10-16 12:54:23 -07:00 committed by GitHub
commit 11c114599c
9 changed files with 224 additions and 48 deletions

View File

@ -2,6 +2,8 @@
## Current Master ## Current Master
- Add a custom transaction fee field to send form.
## 2.13.3 2016-10-4 ## 2.13.3 2016-10-4
- Fix bug where log queries were filtered out. - Fix bug where log queries were filtered out.

View File

@ -384,3 +384,15 @@ ConfigManager.prototype.createShapeShiftTx = function (depositAddress, depositTy
} }
this.setData(data) this.setData(data)
} }
ConfigManager.prototype.getGasMultiplier = function () {
var data = this.getData()
return ('gasMultiplier' in data) && data.gasMultiplier
}
ConfigManager.prototype.setGasMultiplier = function (gasMultiplier) {
var data = this.getData()
data.gasMultiplier = gasMultiplier
this.setData(data)
}

View File

@ -7,6 +7,7 @@
*/ */
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const Transaction = require('ethereumjs-tx') const Transaction = require('ethereumjs-tx')
module.exports = IdManagement module.exports = IdManagement
@ -24,7 +25,13 @@ function IdManagement (opts) {
} }
this.signTx = function (txParams) { this.signTx = function (txParams) {
// calculate gas with custom gas multiplier
var gasMultiplier = this.configManager.getGasMultiplier() || 1
var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice), 16)
gasPrice = gasPrice.mul(new BN(gasMultiplier * 100, 10)).div(new BN(100, 10))
txParams.gasPrice = ethUtil.intToHex(gasPrice.toNumber())
// normalize values // normalize values
txParams.to = ethUtil.addHexPrefix(txParams.to) txParams.to = ethUtil.addHexPrefix(txParams.to)
txParams.from = ethUtil.addHexPrefix(txParams.from.toLowerCase()) txParams.from = ethUtil.addHexPrefix(txParams.from.toLowerCase())
txParams.value = ethUtil.addHexPrefix(txParams.value) txParams.value = ethUtil.addHexPrefix(txParams.value)

View File

@ -112,6 +112,8 @@ IdentityStore.prototype.getState = function () {
currentFiat: configManager.getCurrentFiat(), currentFiat: configManager.getCurrentFiat(),
conversionRate: configManager.getConversionRate(), conversionRate: configManager.getConversionRate(),
conversionDate: configManager.getConversionDate(), conversionDate: configManager.getConversionDate(),
gasMultiplier: configManager.getGasMultiplier(),
})) }))
} }
@ -211,6 +213,7 @@ IdentityStore.prototype.exportAccount = function (address, cb) {
// comes from dapp via zero-client hooked-wallet provider // comes from dapp via zero-client hooked-wallet provider
IdentityStore.prototype.addUnconfirmedTransaction = function (txParams, onTxDoneCb, cb) { IdentityStore.prototype.addUnconfirmedTransaction = function (txParams, onTxDoneCb, cb) {
const configManager = this.configManager const configManager = this.configManager
var self = this var self = this
// create txData obj with parameters and meta data // create txData obj with parameters and meta data
var time = (new Date()).getTime() var time = (new Date()).getTime()
@ -222,6 +225,7 @@ IdentityStore.prototype.addUnconfirmedTransaction = function (txParams, onTxDone
txParams: txParams, txParams: txParams,
time: time, time: time,
status: 'unconfirmed', status: 'unconfirmed',
gasMultiplier: configManager.getGasMultiplier() || 1,
} }
console.log('addUnconfirmedTransaction:', txData) console.log('addUnconfirmedTransaction:', txData)

View File

@ -55,6 +55,7 @@ module.exports = class MetamaskController {
agreeToEthWarning: this.agreeToEthWarning.bind(this), agreeToEthWarning: this.agreeToEthWarning.bind(this),
setTOSHash: this.setTOSHash.bind(this), setTOSHash: this.setTOSHash.bind(this),
checkTOSChange: this.checkTOSChange.bind(this), checkTOSChange: this.checkTOSChange.bind(this),
setGasMultiplier: this.setGasMultiplier.bind(this),
// forward directly to idStore // forward directly to idStore
createNewVault: idStore.createNewVault.bind(idStore), createNewVault: idStore.createNewVault.bind(idStore),
@ -377,4 +378,13 @@ module.exports = class MetamaskController {
createShapeShiftTx (depositAddress, depositType) { createShapeShiftTx (depositAddress, depositType) {
this.configManager.createShapeShiftTx(depositAddress, depositType) this.configManager.createShapeShiftTx(depositAddress, depositType)
} }
setGasMultiplier (gasMultiplier, cb) {
try {
this.configManager.setGasMultiplier(gasMultiplier)
cb()
} catch (e) {
cb(e)
}
}
} }

View File

@ -278,14 +278,16 @@ function signMsg (msgData) {
function signTx (txData) { function signTx (txData) {
return (dispatch) => { return (dispatch) => {
web3.eth.sendTransaction(txData, (err, data) => { _accountManager.setGasMultiplier(txData.gasMultiplier, (err) => {
dispatch(actions.hideLoadingIndication())
if (err) return dispatch(actions.displayWarning(err.message)) if (err) return dispatch(actions.displayWarning(err.message))
dispatch(actions.hideWarning()) web3.eth.sendTransaction(txData, (err, data) => {
dispatch(actions.goHome()) dispatch(actions.hideLoadingIndication())
if (err) return dispatch(actions.displayWarning(err.message))
dispatch(actions.hideWarning())
dispatch(actions.goHome())
})
dispatch(this.showConfTxPage())
}) })
dispatch(this.showConfTxPage())
} }
} }

View File

@ -29,8 +29,10 @@ PTXP.render = function () {
var account = props.accounts[address] var account = props.accounts[address]
var balance = account ? account.balance : '0x0' var balance = account ? account.balance : '0x0'
var gasMultiplier = txData.gasMultiplier
var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txData.estimatedGas), 16) var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txData.estimatedGas), 16)
var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice || '0x4a817c800'), 16) var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice || '0x4a817c800'), 16)
gasPrice = gasPrice.mul(new BN(gasMultiplier * 100), 10).div(new BN(100, 10))
var txFee = gasCost.mul(gasPrice) var txFee = gasCost.mul(gasPrice)
var txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16) var txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
var maxCost = txValue.add(txFee) var maxCost = txValue.add(txFee)

View File

@ -0,0 +1,58 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
module.exports = RangeSlider
inherits(RangeSlider, Component)
function RangeSlider () {
Component.call(this)
}
RangeSlider.prototype.render = function () {
const state = this.state || {}
const props = this.props
const onInput = props.onInput || function () {}
const name = props.name
const {
min = 0,
max = 100,
increment = 1,
defaultValue = 50,
mirrorInput = false,
} = this.props.options
const {container, input, range} = props.style
return (
h('.flex-row', {
style: container,
}, [
h('input', {
type: 'range',
name: name,
min: min,
max: max,
step: increment,
style: range,
value: state.value || defaultValue,
onChange: mirrorInput ? this.mirrorInputs.bind(this, event) : onInput,
}),
// Mirrored input for range
mirrorInput ? h('input.large-input', {
type: 'number',
name: `${name}Mirror`,
min: min,
max: max,
value: state.value || defaultValue,
step: increment,
style: input,
onChange: this.mirrorInputs.bind(this, event),
}) : null,
])
)
}
RangeSlider.prototype.mirrorInputs = function (event) {
this.setState({value: event.target.value})
}

View File

@ -9,7 +9,8 @@ const numericBalance = require('./util').numericBalance
const addressSummary = require('./util').addressSummary const addressSummary = require('./util').addressSummary
const EthBalance = require('./components/eth-balance') const EthBalance = require('./components/eth-balance')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const RangeSlider = require('./components/range-slider')
const Tooltip = require('./components/tooltip')
module.exports = connect(mapStateToProps)(SendTransactionScreen) module.exports = connect(mapStateToProps)(SendTransactionScreen)
function mapStateToProps (state) { function mapStateToProps (state) {
@ -50,7 +51,7 @@ SendTransactionScreen.prototype.render = function () {
// Sender Profile // Sender Profile
// //
h('.account-data-subsection.flex-column.flex-grow', { h('.account-data-subsection.flex-row.flex-grow', {
style: { style: {
margin: '0 20px', margin: '0 20px',
}, },
@ -59,10 +60,9 @@ SendTransactionScreen.prototype.render = function () {
// header - identicon + nav // header - identicon + nav
h('.flex-row.flex-space-between', { h('.flex-row.flex-space-between', {
style: { style: {
marginTop: 28, marginTop: '15px',
}, },
}, [ }, [
// back button // back button
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
onClick: this.back.bind(this), onClick: this.back.bind(this),
@ -77,42 +77,53 @@ SendTransactionScreen.prototype.render = function () {
]), ]),
// invisible place holder // invisible place holder
h('i.fa.fa-users.fa-lg.invisible'), h('i.fa.fa-users.fa-lg.invisible', {
]),
// account label
h('h2.font-medium.color-forest.flex-center', {
style: {
paddingTop: 8,
marginBottom: 8,
},
}, identity && identity.name),
// address and getter actions
h('.flex-row.flex-center', {
style: {
marginBottom: 8,
},
}, [
h('div', {
style: { style: {
lineHeight: '16px', marginTop: '28px',
}, },
}, addressSummary(address)),
]),
// balance
h('.flex-row.flex-center', [
h(EthBalance, {
value: account && account.balance,
}), }),
]), ]),
// account label
h('.flex-column', {
style: {
marginTop: '10px',
alignItems: 'flex-start',
},
}, [
h('h2.font-medium.color-forest.flex-center', {
style: {
paddingTop: '8px',
marginBottom: '8px',
},
}, identity && identity.name),
// address and getter actions
h('.flex-row.flex-center', {
style: {
marginBottom: '8px',
},
}, [
h('div', {
style: {
lineHeight: '16px',
},
}, addressSummary(address)),
]),
// balance
h('.flex-row.flex-center', [
h(EthBalance, {
value: account && account.balance,
}),
]),
]),
]), ]),
// //
@ -123,8 +134,8 @@ SendTransactionScreen.prototype.render = function () {
style: { style: {
background: '#EBEBEB', background: '#EBEBEB',
color: '#AEAEAE', color: '#AEAEAE',
marginTop: 32, marginTop: '15px',
marginBottom: 16, marginBottom: '16px',
}, },
}, [ }, [
'Send Transaction', 'Send Transaction',
@ -152,7 +163,7 @@ SendTransactionScreen.prototype.render = function () {
placeholder: 'Amount', placeholder: 'Amount',
type: 'number', type: 'number',
style: { style: {
marginRight: 6, marginRight: '6px',
}, },
dataset: { dataset: {
persistentFormId: 'tx-amount', persistentFormId: 'tx-amount',
@ -171,20 +182,19 @@ SendTransactionScreen.prototype.render = function () {
// //
// Optional Fields // Optional Fields
// //
h('h3.flex-center.text-transform-uppercase', { h('h3.flex-center.text-transform-uppercase', {
style: { style: {
background: '#EBEBEB', background: '#EBEBEB',
color: '#AEAEAE', color: '#AEAEAE',
marginTop: 16, marginTop: '16px',
marginBottom: 16, marginBottom: '16px',
}, },
}, [ }, [
'Transactional Data (optional)', 'Transactional Data (optional)',
]), ]),
// 'data' field // 'data' field
h('section.flex-row.flex-center', [ h('section.flex-column.flex-center', [
h('input.large-input', { h('input.large-input', {
name: 'txData', name: 'txData',
placeholder: '0x01234', placeholder: '0x01234',
@ -197,6 +207,73 @@ SendTransactionScreen.prototype.render = function () {
}, },
}), }),
]), ]),
// custom gasPrice field
h('h3.flex-center.text-transform-uppercase', {
style: {
background: '#EBEBEB',
color: '#AEAEAE',
marginBottom: '5px',
},
}, [
'Transaction Fee (optional)',
h(Tooltip, {
title: `
This is used to set the transaction's gas price.
Setting it to 100% will use the full recommended value. `,
}, [
h('i.fa.fa-question-circle', {
style: {
marginLeft: '5px',
},
}),
]),
]),
h('section.flex-column.flex-center', [
h('.flex-row', [
h(RangeSlider, {
name: 'gasInput',
options: {
mirrorInput: true,
defaultValue: 100,
min: 80,
max: 220,
},
style: {
container: {
marginBottom: '16px',
},
range: {
width: '68vw',
},
input: {
width: '5em',
marginLeft: '5px',
},
},
}),
h('div', {
style: {
fontSize: '12px',
paddingTop: '8px',
paddingLeft: '5px',
},
}, '%'),
]),
h('.flex-row', {
style: {
justifyContent: 'space-between',
width: '243px',
position: 'relative',
fontSize: '12px',
right: '42px',
bottom: '30px',
},
}, [
h('span', 'Cheaper'), h('span', 'Faster'),
]),
]),
]) ])
) )
} }
@ -211,11 +288,12 @@ SendTransactionScreen.prototype.back = function () {
this.props.dispatch(actions.backToAccountDetail(address)) this.props.dispatch(actions.backToAccountDetail(address))
} }
SendTransactionScreen.prototype.onSubmit = function () { SendTransactionScreen.prototype.onSubmit = function (gasPrice) {
const recipient = document.querySelector('input[name="address"]').value const recipient = document.querySelector('input[name="address"]').value
const input = document.querySelector('input[name="amount"]').value const input = document.querySelector('input[name="amount"]').value
const value = util.normalizeEthStringToWei(input) const value = util.normalizeEthStringToWei(input)
const txData = document.querySelector('input[name="txData"]').value const txData = document.querySelector('input[name="txData"]').value
const gasMultiplier = document.querySelector('input[name="gasInput"]').value
const balance = this.props.balance const balance = this.props.balance
let message let message
@ -239,6 +317,7 @@ SendTransactionScreen.prototype.onSubmit = function () {
var txParams = { var txParams = {
from: this.props.address, from: this.props.address,
value: '0x' + value.toString(16), value: '0x' + value.toString(16),
gasMultiplier: gasMultiplier * 0.01,
} }
if (recipient) txParams.to = ethUtil.addHexPrefix(recipient) if (recipient) txParams.to = ethUtil.addHexPrefix(recipient)