Merge branch 'master' into version-debugging

feature/default_network_editable
Kevin Serrano 7 years ago
commit 1816eca914
No known key found for this signature in database
GPG Key ID: BF999DEFC7371BA1
  1. 4
      CHANGELOG.md
  2. 3
      app/scripts/background.js
  3. 1
      app/scripts/controllers/transactions.js
  4. 12
      app/scripts/lib/nodeify.js
  5. 21
      app/scripts/lib/pending-tx-tracker.js
  6. 8
      app/scripts/lib/tx-state-manager.js
  7. 123
      app/scripts/lib/typed-message-manager.js
  8. 57
      app/scripts/metamask-controller.js
  9. 6
      package.json
  10. 38
      test/unit/components/bn-as-decimal-input-test.js
  11. 7
      test/unit/nodeify-test.js
  12. 54
      test/unit/pending-tx-test.js
  13. 27
      ui/app/actions.js
  14. 11
      ui/app/components/bn-as-decimal-input.js
  15. 59
      ui/app/components/pending-typed-msg-details.js
  16. 46
      ui/app/components/pending-typed-msg.js
  17. 42
      ui/app/components/typed-message-renderer.js
  18. 25
      ui/app/conf-tx.js
  19. 4
      ui/app/reducers/app.js
  20. 2
      ui/index.js
  21. 13
      ui/lib/tx-helper.js

@ -2,6 +2,10 @@
## Current Master
- Add new support for new eth_signTypedData method per EIP 712.
- Fix bug where some transactions would be shown as pending forever, even after successfully mined.
- Fix bug where a transaction might be shown as pending forever if another tx with the same nonce was mined.
## 3.10.9 2017-10-5
- Only rebrodcast transactions for a day not a days worth of blocks

@ -124,7 +124,8 @@ function setupController (initState) {
var unapprovedTxCount = controller.txController.getUnapprovedTxCount()
var unapprovedMsgCount = controller.messageManager.unapprovedMsgCount
var unapprovedPersonalMsgs = controller.personalMessageManager.unapprovedPersonalMsgCount
var count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgs
var unapprovedTypedMsgs = controller.typedMessageManager.unapprovedTypedMessagesCount
var count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgs + unapprovedTypedMsgs
if (count) {
label = String(count)
}

@ -62,6 +62,7 @@ module.exports = class TransactionController extends EventEmitter {
retryTimePeriod: 86400000, // Retry 3500 blocks, or about 1 day.
publishTransaction: (rawTx) => this.query.sendRawTransaction(rawTx),
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
getCompletedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager),
})
this.txStateManager.store.subscribe(() => this.emit('update:badge'))

@ -1,10 +1,18 @@
const promiseToCallback = require('promise-to-callback')
const noop = function(){}
module.exports = function nodeify (fn, context) {
return function(){
const args = [].slice.call(arguments)
const callback = args.pop()
if (typeof callback !== 'function') throw new Error('callback is not a function')
const lastArg = args[args.length - 1]
const lastArgIsCallback = typeof lastArg === 'function'
let callback
if (lastArgIsCallback) {
callback = lastArg
args.pop()
} else {
callback = noop
}
promiseToCallback(fn.apply(context, args))(callback)
}
}

@ -25,7 +25,9 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
// default is one day
this.retryTimePeriod = config.retryTimePeriod || 86400000
this.getPendingTransactions = config.getPendingTransactions
this.getCompletedTransactions = config.getCompletedTransactions
this.publishTransaction = config.publishTransaction
this._checkPendingTxs()
}
// checks if a signed tx is in a block and
@ -120,6 +122,7 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
async _checkPendingTx (txMeta) {
const txHash = txMeta.hash
const txId = txMeta.id
// extra check in case there was an uncaught error during the
// signature and submission process
if (!txHash) {
@ -128,6 +131,15 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
this.emit('tx:failed', txId, noTxHashErr)
return
}
// If another tx with the same nonce is mined, set as failed.
const taken = await this._checkIfNonceIsTaken(txMeta)
if (taken) {
const nonceTakenErr = new Error('Another transaction with this nonce has been mined.')
nonceTakenErr.name = 'NonceTakenErr'
return this.emit('tx:failed', txId, nonceTakenErr)
}
// get latest transaction status
let txParams
try {
@ -159,4 +171,13 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
}
nonceGlobalLock.releaseLock()
}
async _checkIfNonceIsTaken (txMeta) {
const completed = this.getCompletedTransactions()
const sameNonce = completed.filter((otherMeta) => {
return otherMeta.txParams.nonce === txMeta.txParams.nonce
})
return sameNonce.length > 0
}
}

@ -46,6 +46,12 @@ module.exports = class TransactionStateManger extends EventEmitter {
return this.getFilteredTxList(opts)
}
getConfirmedTransactions (address) {
const opts = { status: 'confirmed' }
if (address) opts.from = address
return this.getFilteredTxList(opts)
}
addTx (txMeta) {
this.once(`${txMeta.id}:signed`, function (txId) {
this.removeAllListeners(`${txMeta.id}:rejected`)
@ -242,4 +248,4 @@ module.exports = class TransactionStateManger extends EventEmitter {
_saveTxList (transactions) {
this.store.updateState({ transactions })
}
}
}

@ -0,0 +1,123 @@
const EventEmitter = require('events')
const ObservableStore = require('obs-store')
const createId = require('./random-id')
const assert = require('assert')
const sigUtil = require('eth-sig-util')
module.exports = class TypedMessageManager extends EventEmitter {
constructor (opts) {
super()
this.memStore = new ObservableStore({
unapprovedTypedMessages: {},
unapprovedTypedMessagesCount: 0,
})
this.messages = []
}
get unapprovedTypedMessagesCount () {
return Object.keys(this.getUnapprovedMsgs()).length
}
getUnapprovedMsgs () {
return this.messages.filter(msg => msg.status === 'unapproved')
.reduce((result, msg) => { result[msg.id] = msg; return result }, {})
}
addUnapprovedMessage (msgParams) {
this.validateParams(msgParams)
log.debug(`TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`)
// create txData obj with parameters and meta data
var time = (new Date()).getTime()
var msgId = createId()
var msgData = {
id: msgId,
msgParams: msgParams,
time: time,
status: 'unapproved',
type: 'eth_signTypedData',
}
this.addMsg(msgData)
// signal update
this.emit('update')
return msgId
}
validateParams (params) {
assert.equal(typeof params, 'object', 'Params should ben an object.')
assert.ok('data' in params, 'Params must include a data field.')
assert.ok('from' in params, 'Params must include a from field.')
assert.ok(Array.isArray(params.data), 'Data should be an array.')
assert.equal(typeof params.from, 'string', 'From field must be a string.')
assert.doesNotThrow(() => {
sigUtil.typedSignatureHash(params.data)
}, 'Expected EIP712 typed data')
}
addMsg (msg) {
this.messages.push(msg)
this._saveMsgList()
}
getMsg (msgId) {
return this.messages.find(msg => msg.id === msgId)
}
approveMessage (msgParams) {
this.setMsgStatusApproved(msgParams.metamaskId)
return this.prepMsgForSigning(msgParams)
}
setMsgStatusApproved (msgId) {
this._setMsgStatus(msgId, 'approved')
}
setMsgStatusSigned (msgId, rawSig) {
const msg = this.getMsg(msgId)
msg.rawSig = rawSig
this._updateMsg(msg)
this._setMsgStatus(msgId, 'signed')
}
prepMsgForSigning (msgParams) {
delete msgParams.metamaskId
return Promise.resolve(msgParams)
}
rejectMsg (msgId) {
this._setMsgStatus(msgId, 'rejected')
}
//
// PRIVATE METHODS
//
_setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId)
if (!msg) throw new Error('TypedMessageManager - Message not found for id: "${msgId}".')
msg.status = status
this._updateMsg(msg)
this.emit(`${msgId}:${status}`, msg)
if (status === 'rejected' || status === 'signed') {
this.emit(`${msgId}:finished`, msg)
}
}
_updateMsg (msg) {
const index = this.messages.findIndex((message) => message.id === msg.id)
if (index !== -1) {
this.messages[index] = msg
}
this._saveMsgList()
}
_saveMsgList () {
const unapprovedTypedMessages = this.getUnapprovedMsgs()
const unapprovedTypedMessagesCount = Object.keys(unapprovedTypedMessages).length
this.memStore.updateState({ unapprovedTypedMessages, unapprovedTypedMessagesCount })
this.emit('updateBadge')
}
}

@ -25,6 +25,7 @@ const InfuraController = require('./controllers/infura')
const BlacklistController = require('./controllers/blacklist')
const MessageManager = require('./lib/message-manager')
const PersonalMessageManager = require('./lib/personal-message-manager')
const TypedMessageManager = require('./lib/typed-message-manager')
const TransactionController = require('./controllers/transactions')
const BalancesController = require('./controllers/computed-balances')
const ConfigManager = require('./lib/config-manager')
@ -161,6 +162,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.networkController.lookupNetwork()
this.messageManager = new MessageManager()
this.personalMessageManager = new PersonalMessageManager()
this.typedMessageManager = new TypedMessageManager()
this.publicConfigStore = this.initPublicConfigStore()
// manual disk state subscriptions
@ -202,6 +204,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.balancesController.store.subscribe(this.sendUpdate.bind(this))
this.messageManager.memStore.subscribe(this.sendUpdate.bind(this))
this.personalMessageManager.memStore.subscribe(this.sendUpdate.bind(this))
this.typedMessageManager.memStore.subscribe(this.sendUpdate.bind(this))
this.keyringController.memStore.subscribe(this.sendUpdate.bind(this))
this.preferencesController.store.subscribe(this.sendUpdate.bind(this))
this.addressBookController.store.subscribe(this.sendUpdate.bind(this))
@ -239,6 +242,7 @@ module.exports = class MetamaskController extends EventEmitter {
processMessage: this.newUnsignedMessage.bind(this),
// personal_sign msg signing
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
processTypedMessage: this.newUnsignedTypedMessage.bind(this),
}
const providerProxy = this.networkController.initializeProvider(providerOpts)
return providerProxy
@ -283,6 +287,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.txController.memStore.getState(),
this.messageManager.memStore.getState(),
this.personalMessageManager.memStore.getState(),
this.typedMessageManager.memStore.getState(),
this.keyringController.memStore.getState(),
this.balancesController.store.getState(),
this.preferencesController.store.getState(),
@ -364,6 +369,10 @@ module.exports = class MetamaskController extends EventEmitter {
signPersonalMessage: nodeify(this.signPersonalMessage, this),
cancelPersonalMessage: this.cancelPersonalMessage.bind(this),
// personalMessageManager
signTypedMessage: nodeify(this.signTypedMessage, this),
cancelTypedMessage: this.cancelTypedMessage.bind(this),
// notices
checkNotices: noticeController.updateNoticesList.bind(noticeController),
markNoticeRead: noticeController.markNoticeRead.bind(noticeController),
@ -556,6 +565,28 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
newUnsignedTypedMessage (msgParams, cb) {
let msgId
try {
msgId = this.typedMessageManager.addUnapprovedMessage(msgParams)
this.sendUpdate()
this.opts.showUnconfirmedMessage()
} catch (e) {
return cb(e)
}
this.typedMessageManager.once(`${msgId}:finished`, (data) => {
switch (data.status) {
case 'signed':
return cb(null, data.rawSig)
case 'rejected':
return cb(new Error('MetaMask Message Signature: User denied message signature.'))
default:
return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))
}
})
}
signMessage (msgParams, cb) {
log.info('MetaMaskController - signMessage')
const msgId = msgParams.metamaskId
@ -618,6 +649,24 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
signTypedMessage (msgParams) {
log.info('MetaMaskController - signTypedMessage')
const msgId = msgParams.metamaskId
// sets the status op the message to 'approved'
// and removes the metamaskId for signing
return this.typedMessageManager.approveMessage(msgParams)
.then((cleanMsgParams) => {
// signs the message
return this.keyringController.signTypedMessage(cleanMsgParams)
})
.then((rawSig) => {
// tells the listener that the message has been signed
// and can be returned to the dapp
this.typedMessageManager.setMsgStatusSigned(msgId, rawSig)
return this.getState()
})
}
cancelPersonalMessage (msgId, cb) {
const messageManager = this.personalMessageManager
messageManager.rejectMsg(msgId)
@ -626,6 +675,14 @@ module.exports = class MetamaskController extends EventEmitter {
}
}
cancelTypedMessage (msgId, cb) {
const messageManager = this.typedMessageManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
cb(null, this.getState())
}
}
markAccountsFound (cb) {
this.configManager.setLostAccounts([])
this.sendUpdate()

@ -71,10 +71,10 @@
"eth-contract-metadata": "^1.1.4",
"eth-hd-keyring": "^1.2.1",
"eth-json-rpc-filters": "^1.2.2",
"eth-keyring-controller": "^2.0.0",
"eth-keyring-controller": "^2.1.0",
"eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2",
"eth-sig-util": "^1.2.2",
"eth-sig-util": "^1.4.0",
"eth-simple-keyring": "^1.1.1",
"eth-token-tracker": "^1.1.4",
"ethereumjs-tx": "^1.3.0",
@ -141,7 +141,7 @@
"valid-url": "^1.0.9",
"vreme": "^3.0.2",
"web3": "^0.20.1",
"web3-provider-engine": "^13.3.1",
"web3-provider-engine": "^13.3.2",
"web3-stream-provider": "^3.0.1",
"xtend": "^4.0.1"
},

@ -48,4 +48,42 @@ describe('BnInput', function () {
checkValidity () { return true } },
})
})
it('can tolerate wei precision', function (done) {
const renderer = ReactTestUtils.createRenderer()
let valueStr = '1000000000'
const value = new BN(valueStr, 10)
const inputStr = '1.000000001'
let targetStr = '1000000001'
const target = new BN(targetStr, 10)
const precision = 9 // gwei precision
const scale = 9
const props = {
value,
scale,
precision,
onChange: (newBn) => {
assert.equal(newBn.toString(), target.toString(), 'should tolerate increase')
const reInput = BnInput.prototype.downsize(newBn.toString(), 9, 9)
assert.equal(reInput.toString(), inputStr, 'should tolerate increase')
done()
},
}
const inputComponent = h(BnInput, props)
const component = additions.renderIntoDocument(inputComponent)
renderer.render(inputComponent)
const input = additions.find(component, 'input.hex-input')[0]
ReactTestUtils.Simulate.change(input, { preventDefault () {}, target: {
value: inputStr,
checkValidity () { return true } },
})
})
})

@ -18,14 +18,13 @@ describe('nodeify', function () {
})
})
it('should throw if the last argument is not a function', function (done) {
it('should allow the last argument to not be a function', function (done) {
const nodified = nodeify(obj.promiseFunc, obj)
try {
nodified('baz')
done(new Error('should have thrown if the last argument is not a function'))
} catch (err) {
assert.equal(err.message, 'callback is not a function')
done()
} catch (err) {
done(new Error('should not have thrown if the last argument is not a function'))
}
})
})

@ -5,6 +5,8 @@ const ObservableStore = require('obs-store')
const clone = require('clone')
const { createStubedProvider } = require('../stub/provider')
const PendingTransactionTracker = require('../../app/scripts/lib/pending-tx-tracker')
const MockTxGen = require('../lib/mock-tx-gen')
const sinon = require('sinon')
const noop = () => true
const currentNetworkId = 42
const otherNetworkId = 36
@ -46,10 +48,60 @@ describe('PendingTransactionTracker', function () {
}
},
getPendingTransactions: () => {return []},
getCompletedTransactions: () => {return []},
publishTransaction: () => {},
})
})
describe('_checkPendingTx state management', function () {
let stub
afterEach(function () {
if (stub) {
stub.restore()
}
})
it('should become failed if another tx with the same nonce succeeds', async function () {
// SETUP
const txGen = new MockTxGen()
txGen.generate({
id: '456',
value: '0x01',
hash: '0xbad',
status: 'confirmed',
nonce: '0x01',
}, { count: 1 })
const pending = txGen.generate({
id: '123',
value: '0x02',
hash: '0xfad',
status: 'submitted',
nonce: '0x01',
}, { count: 1 })[0]
stub = sinon.stub(pendingTxTracker, 'getCompletedTransactions')
.returns(txGen.txs)
// THE EXPECTATION
const spy = sinon.spy()
pendingTxTracker.on('tx:failed', (txId, err) => {
assert.equal(txId, pending.id, 'should fail the pending tx')
assert.equal(err.name, 'NonceTakenErr', 'should emit a nonce taken error.')
spy(txId, err)
})
// THE METHOD
await pendingTxTracker._checkPendingTx(pending)
// THE ASSERTION
assert.ok(spy.calledWith(pending.id), 'tx failed should be emitted')
})
})
describe('#checkForTxInBlock', function () {
it('should return if no pending transactions', function () {
// throw a type error if it trys to do anything on the block
@ -239,4 +291,4 @@ describe('PendingTransactionTracker', function () {
})
})
})
})
})

@ -97,6 +97,8 @@ var actions = {
cancelMsg: cancelMsg,
signPersonalMsg,
cancelPersonalMsg,
signTypedMsg,
cancelTypedMsg,
signTx: signTx,
updateAndApproveTx,
cancelTx: cancelTx,
@ -392,6 +394,25 @@ function signPersonalMsg (msgData) {
}
}
function signTypedMsg (msgData) {
log.debug('action - signTypedMsg')
return (dispatch) => {
dispatch(actions.showLoadingIndication())
log.debug(`actions calling background.signTypedMessage`)
background.signTypedMessage(msgData, (err, newState) => {
log.debug('signTypedMessage called back')
dispatch(actions.updateMetamaskState(newState))
dispatch(actions.hideLoadingIndication())
if (err) log.error(err)
if (err) return dispatch(actions.displayWarning(err.message))
dispatch(actions.completedTx(msgData.metamaskId))
})
}
}
function signTx (txData) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
@ -446,6 +467,12 @@ function cancelPersonalMsg (msgData) {
return actions.completedTx(id)
}
function cancelTypedMsg (msgData) {
const id = msgData.id
background.cancelTypedMessage(id)
return actions.completedTx(id)
}
function cancelTx (txData) {
return (dispatch) => {
log.debug(`background.cancelTransaction`)

@ -31,7 +31,7 @@ BnAsDecimalInput.prototype.render = function () {
const suffix = props.suffix
const style = props.style
const valueString = value.toString(10)
const newValue = this.downsize(valueString, scale, precision)
const newValue = this.downsize(valueString, scale)
return (
h('.flex-column', [
@ -145,14 +145,17 @@ BnAsDecimalInput.prototype.constructWarning = function () {
}
BnAsDecimalInput.prototype.downsize = function (number, scale, precision) {
BnAsDecimalInput.prototype.downsize = function (number, scale) {
// if there is no scaling, simply return the number
if (scale === 0) {
return Number(number)
} else {
// if the scale is the same as the precision, account for this edge case.
var decimals = (scale === precision) ? -1 : scale - precision
return Number(number.slice(0, -scale) + '.' + number.slice(-scale, decimals))
var adjustedNumber = number
while (adjustedNumber.length < scale) {
adjustedNumber = '0' + adjustedNumber
}
return Number(adjustedNumber.slice(0, -scale) + '.' + adjustedNumber.slice(-scale))
}
}

@ -0,0 +1,59 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const AccountPanel = require('./account-panel')
const TypedMessageRenderer = require('./typed-message-renderer')
module.exports = PendingMsgDetails
inherits(PendingMsgDetails, Component)
function PendingMsgDetails () {
Component.call(this)
}
PendingMsgDetails.prototype.render = function () {
var state = this.props
var msgData = state.txData
var msgParams = msgData.msgParams || {}
var address = msgParams.from || state.selectedAddress
var identity = state.identities[address] || { address: address }
var account = state.accounts[address] || { address: address }
var { data } = msgParams
return (
h('div', {
key: msgData.id,
style: {
margin: '10px 20px',
},
}, [
// account that will sign
h(AccountPanel, {
showFullAddress: true,
identity: identity,
account: account,
imageifyIdenticons: state.imageifyIdenticons,
}),
// message data
h('div', {
style: {
height: '260px',
},
}, [
h('label.font-small', { style: { display: 'block' } }, 'YOU ARE SIGNING'),
h(TypedMessageRenderer, {
value: data,
style: {
height: '215px',
},
}),
]),
])
)
}

@ -0,0 +1,46 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const PendingTxDetails = require('./pending-typed-msg-details')
module.exports = PendingMsg
inherits(PendingMsg, Component)
function PendingMsg () {
Component.call(this)
}
PendingMsg.prototype.render = function () {
var state = this.props
var msgData = state.txData
return (
h('div', {
key: msgData.id,
}, [
// header
h('h3', {
style: {
fontWeight: 'bold',
textAlign: 'center',
},
}, 'Sign Message'),
// message details
h(PendingTxDetails, state),
// sign + cancel
h('.flex-row.flex-space-around', [
h('button', {
onClick: state.cancelTypedMessage,
}, 'Cancel'),
h('button', {
onClick: state.signTypedMessage,
}, 'Sign'),
]),
])
)
}

@ -0,0 +1,42 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const extend = require('xtend')
module.exports = TypedMessageRenderer
inherits(TypedMessageRenderer, Component)
function TypedMessageRenderer () {
Component.call(this)
}
TypedMessageRenderer.prototype.render = function () {
const props = this.props
const { value, style } = props
const text = renderTypedData(value)
const defaultStyle = extend({
width: '315px',
maxHeight: '210px',
resize: 'none',
border: 'none',
background: 'white',
padding: '3px',
overflow: 'scroll',
}, style)
return (
h('div.font-small', {
style: defaultStyle,
}, text)
)
}
function renderTypedData(values) {
return values.map(function (value) {
return h('div', {}, [
h('strong', {style: {display: 'block', fontWeight: 'bold'}}, String(value.name) + ':'),
h('div', {}, value.value),
])
})
}

@ -10,6 +10,7 @@ const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notific
const PendingTx = require('./components/pending-tx')
const PendingMsg = require('./components/pending-msg')
const PendingPersonalMsg = require('./components/pending-personal-msg')
const PendingTypedMsg = require('./components/pending-typed-msg')
const Loading = require('./components/loading')
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
@ -22,6 +23,7 @@ function mapStateToProps (state) {
unapprovedTxs: state.metamask.unapprovedTxs,
unapprovedMsgs: state.metamask.unapprovedMsgs,
unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs,
unapprovedTypedMessages: state.metamask.unapprovedTypedMessages,
index: state.appState.currentView.context,
warning: state.appState.warning,
network: state.metamask.network,
@ -41,9 +43,9 @@ function ConfirmTxScreen () {
ConfirmTxScreen.prototype.render = function () {
const props = this.props
const { network, provider, unapprovedTxs, currentCurrency, computedBalances,
unapprovedMsgs, unapprovedPersonalMsgs, conversionRate, blockGasLimit } = props
unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, conversionRate, blockGasLimit } = props
var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network)
var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network)
var txData = unconfTxList[props.index] || {}
var txParams = txData.params || {}
@ -112,8 +114,10 @@ ConfirmTxScreen.prototype.render = function () {
cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList),
signMessage: this.signMessage.bind(this, txData),
signPersonalMessage: this.signPersonalMessage.bind(this, txData),
signTypedMessage: this.signTypedMessage.bind(this, txData),
cancelMessage: this.cancelMessage.bind(this, txData),
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
}),
])
)
@ -136,6 +140,9 @@ function currentTxView (opts) {
} else if (type === 'personal_sign') {
log.debug('rendering personal_sign message')
return h(PendingPersonalMsg, opts)
} else if (type === 'eth_signTypedData') {
log.debug('rendering eth_signTypedData message')
return h(PendingTypedMsg, opts)
}
}
}
@ -184,6 +191,14 @@ ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) {
this.props.dispatch(actions.signPersonalMsg(params))
}
ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) {
log.info('conf-tx.js: signing typed message')
var params = msgData.msgParams
params.metamaskId = msgData.id
this.stopPropagation(event)
this.props.dispatch(actions.signTypedMsg(params))
}
ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) {
log.info('canceling message')
this.stopPropagation(event)
@ -196,6 +211,12 @@ ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) {
this.props.dispatch(actions.cancelPersonalMsg(msgData))
}
ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) {
log.info('canceling typed message')
this.stopPropagation(event)
this.props.dispatch(actions.cancelTypedMsg(msgData))
}
ConfirmTxScreen.prototype.goHome = function (event) {
this.stopPropagation(event)
this.props.dispatch(actions.goHome())

@ -574,9 +574,9 @@ function checkUnconfActions (state) {
function getUnconfActionList (state) {
const { unapprovedTxs, unapprovedMsgs,
unapprovedPersonalMsgs, network } = state.metamask
unapprovedPersonalMsgs, unapprovedTypedMessages, network } = state.metamask
const unconfActionList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network)
const unconfActionList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network)
return unconfActionList
}

@ -37,7 +37,7 @@ function startApp (metamaskState, accountManager, opts) {
})
// if unconfirmed txs, start on txConf page
const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.network)
const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network)
if (unapprovedTxsAll.length > 0) {
store.dispatch(actions.showConfTxPage())
}

@ -1,20 +1,27 @@
const valuesFor = require('../app/util').valuesFor
module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, network) {
module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network) {
log.debug('tx-helper called with params:')
log.debug({ unapprovedTxs, unapprovedMsgs, personalMsgs, network })
log.debug({ unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network })
const txValues = network ? valuesFor(unapprovedTxs).filter(txMeta => txMeta.metamaskNetworkId === network) : valuesFor(unapprovedTxs)
log.debug(`tx helper found ${txValues.length} unapproved txs`)
const msgValues = valuesFor(unapprovedMsgs)
log.debug(`tx helper found ${msgValues.length} unsigned messages`)
let allValues = txValues.concat(msgValues)
const personalValues = valuesFor(personalMsgs)
log.debug(`tx helper found ${personalValues.length} unsigned personal messages`)
allValues = allValues.concat(personalValues)
const typedValues = valuesFor(typedMessages)
log.debug(`tx helper found ${typedValues.length} unsigned typed messages`)
allValues = allValues.concat(typedValues)
allValues = allValues.sort((a, b) => {
return a.time > b.time
})
return allValues
}
}
Loading…
Cancel
Save