mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #997 from MetaMask/integrateTxManagerUI
Integrate tx manager ui
This commit is contained in:
commit
c1253016fc
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Current Master
|
## Current Master
|
||||||
|
|
||||||
|
- Create visible difference in transaction history between a approved but not yet included in a block transaction and a transaction who has been confirmed.
|
||||||
- Fix memory leak in RPC Cache
|
- Fix memory leak in RPC Cache
|
||||||
- Override RPC commands eth_syncing and web3_clientVersion
|
- Override RPC commands eth_syncing and web3_clientVersion
|
||||||
- Remove certain non-essential permissions from certain builds.
|
- Remove certain non-essential permissions from certain builds.
|
||||||
|
@ -27,7 +27,6 @@ function triggerUi () {
|
|||||||
if (!popupIsOpen) notification.show()
|
if (!popupIsOpen) notification.show()
|
||||||
}
|
}
|
||||||
// On first install, open a window to MetaMask website to how-it-works.
|
// On first install, open a window to MetaMask website to how-it-works.
|
||||||
|
|
||||||
extension.runtime.onInstalled.addListener(function (details) {
|
extension.runtime.onInstalled.addListener(function (details) {
|
||||||
if ((details.reason === 'install') && (!METAMASK_DEBUG)) {
|
if ((details.reason === 'install') && (!METAMASK_DEBUG)) {
|
||||||
extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
|
extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
|
||||||
|
@ -95,7 +95,6 @@ module.exports = class KeyringController extends EventEmitter {
|
|||||||
isInitialized: (!!wallet || !!vault),
|
isInitialized: (!!wallet || !!vault),
|
||||||
isUnlocked: Boolean(this.password),
|
isUnlocked: Boolean(this.password),
|
||||||
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(),
|
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(),
|
||||||
transactions: this.configManager.getTxList(),
|
|
||||||
unconfMsgs: messageManager.unconfirmedMsgs(),
|
unconfMsgs: messageManager.unconfirmedMsgs(),
|
||||||
messages: messageManager.getMsgList(),
|
messages: messageManager.getMsgList(),
|
||||||
selectedAccount: address,
|
selectedAccount: address,
|
||||||
|
@ -65,6 +65,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
|
|
||||||
this.ethStore.on('update', this.sendUpdate.bind(this))
|
this.ethStore.on('update', this.sendUpdate.bind(this))
|
||||||
this.keyringController.on('update', this.sendUpdate.bind(this))
|
this.keyringController.on('update', this.sendUpdate.bind(this))
|
||||||
|
this.txManager.on('update', this.sendUpdate.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
getState () {
|
getState () {
|
||||||
|
@ -83,6 +83,7 @@ module.exports = class TransactionManager extends EventEmitter {
|
|||||||
var index = txList.findIndex(txData => txData.id === txId)
|
var index = txList.findIndex(txData => txData.id === txId)
|
||||||
txList[index] = txMeta
|
txList[index] = txMeta
|
||||||
this._saveTxList(txList)
|
this._saveTxList(txList)
|
||||||
|
this.emit('update')
|
||||||
}
|
}
|
||||||
|
|
||||||
get unapprovedTxCount () {
|
get unapprovedTxCount () {
|
||||||
@ -113,10 +114,26 @@ module.exports = class TransactionManager extends EventEmitter {
|
|||||||
|
|
||||||
txDidComplete (txMeta, onTxDoneCb, cb, err) {
|
txDidComplete (txMeta, onTxDoneCb, cb, err) {
|
||||||
if (err) return cb(err)
|
if (err) return cb(err)
|
||||||
|
var {maxCost, txFee} = this.getMaxTxCostAndFee(txMeta)
|
||||||
|
txMeta.maxCost = maxCost
|
||||||
|
txMeta.txFee = txFee
|
||||||
this.addTx(txMeta, onTxDoneCb)
|
this.addTx(txMeta, onTxDoneCb)
|
||||||
cb(null, txMeta)
|
cb(null, txMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMaxTxCostAndFee (txMeta) {
|
||||||
|
var txParams = txMeta.txParams
|
||||||
|
|
||||||
|
var gasMultiplier = txMeta.gasMultiplier
|
||||||
|
var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txMeta.estimatedGas), 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 txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
|
||||||
|
var maxCost = txValue.add(txFee)
|
||||||
|
return {maxCost, txFee}
|
||||||
|
}
|
||||||
|
|
||||||
getUnapprovedTxList () {
|
getUnapprovedTxList () {
|
||||||
var txList = this.getTxList()
|
var txList = this.getTxList()
|
||||||
return txList.filter((txMeta) => txMeta.status === 'unapproved')
|
return txList.filter((txMeta) => txMeta.status === 'unapproved')
|
||||||
@ -167,7 +184,6 @@ module.exports = class TransactionManager extends EventEmitter {
|
|||||||
this.updateTx(metaTx)
|
this.updateTx(metaTx)
|
||||||
var rawTx = ethUtil.bufferToHex(tx.serialize())
|
var rawTx = ethUtil.bufferToHex(tx.serialize())
|
||||||
return Promise.resolve(rawTx)
|
return Promise.resolve(rawTx)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -240,19 +256,31 @@ module.exports = class TransactionManager extends EventEmitter {
|
|||||||
// checks if a signed tx is in a block and
|
// checks if a signed tx is in a block and
|
||||||
// if included sets the tx status as 'confirmed'
|
// if included sets the tx status as 'confirmed'
|
||||||
checkForTxInBlock () {
|
checkForTxInBlock () {
|
||||||
var signedTxList = this.getFilteredTxList({status: 'signed', err: undefined})
|
var signedTxList = this.getFilteredTxList({status: 'signed'})
|
||||||
if (!signedTxList.length) return
|
if (!signedTxList.length) return
|
||||||
signedTxList.forEach((tx) => {
|
signedTxList.forEach((txMeta) => {
|
||||||
var txHash = tx.hash
|
var txHash = txMeta.hash
|
||||||
var txId = tx.id
|
var txId = txMeta.id
|
||||||
if (!txHash) return
|
if (!txHash) {
|
||||||
this.txProviderUtils.query.getTransactionByHash(txHash, (err, txMeta) => {
|
txMeta.err = {
|
||||||
if (err || !txMeta) {
|
errCode: 'No hash was provided',
|
||||||
tx.err = err || 'Tx could possibly have not been submitted'
|
message: 'We had an error while submitting this transaction, please try again.',
|
||||||
this.updateTx(tx)
|
|
||||||
return txMeta ? console.error(err) : console.debug(`txMeta is ${txMeta} for:`, tx)
|
|
||||||
}
|
}
|
||||||
if (txMeta.blockNumber) {
|
this.updateTx(txMeta)
|
||||||
|
return this._setTxStatus(txId, 'failed')
|
||||||
|
}
|
||||||
|
this.txProviderUtils.query.getTransactionByHash(txHash, (err, txParams) => {
|
||||||
|
if (err || !txParams) {
|
||||||
|
if (!txParams) return
|
||||||
|
txMeta.err = {
|
||||||
|
isWarning: true,
|
||||||
|
errorCode: err,
|
||||||
|
message: 'There was a problem loading this transaction.',
|
||||||
|
}
|
||||||
|
this.updateTx(txMeta)
|
||||||
|
return console.error(err)
|
||||||
|
}
|
||||||
|
if (txParams.blockNumber) {
|
||||||
this.setTxStatusConfirmed(txId)
|
this.setTxStatusConfirmed(txId)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -26,11 +26,10 @@ function mapStateToProps (state) {
|
|||||||
accounts: state.metamask.accounts,
|
accounts: state.metamask.accounts,
|
||||||
address: state.metamask.selectedAccount,
|
address: state.metamask.selectedAccount,
|
||||||
accountDetail: state.appState.accountDetail,
|
accountDetail: state.appState.accountDetail,
|
||||||
transactions: state.metamask.transactions,
|
|
||||||
network: state.metamask.network,
|
network: state.metamask.network,
|
||||||
unconfTxs: valuesFor(state.metamask.unconfTxs),
|
|
||||||
unconfMsgs: valuesFor(state.metamask.unconfMsgs),
|
unconfMsgs: valuesFor(state.metamask.unconfMsgs),
|
||||||
shapeShiftTxList: state.metamask.shapeShiftTxList,
|
shapeShiftTxList: state.metamask.shapeShiftTxList,
|
||||||
|
transactions: state.metamask.selectedAccountTxList || [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,20 +247,10 @@ AccountDetailScreen.prototype.subview = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AccountDetailScreen.prototype.transactionList = function () {
|
AccountDetailScreen.prototype.transactionList = function () {
|
||||||
const { transactions, unconfTxs, unconfMsgs, address, network, shapeShiftTxList } = this.props
|
const {transactions, unconfMsgs, address, network, shapeShiftTxList } = this.props
|
||||||
|
|
||||||
var txsToRender = transactions.concat(unconfTxs)
|
|
||||||
// only transactions that are from the current address
|
|
||||||
.filter(tx => tx.txParams.from === address)
|
|
||||||
// only transactions that are on the current network
|
|
||||||
.filter(tx => tx.txParams.metamaskNetworkId === network)
|
|
||||||
// sort by recency
|
|
||||||
.sort((a, b) => b.time - a.time)
|
|
||||||
|
|
||||||
return h(TransactionList, {
|
return h(TransactionList, {
|
||||||
txsToRender,
|
transactions: transactions.sort((a, b) => b.time - a.time),
|
||||||
network,
|
network,
|
||||||
unconfTxs,
|
|
||||||
unconfMsgs,
|
unconfMsgs,
|
||||||
address,
|
address,
|
||||||
shapeShiftTxList,
|
shapeShiftTxList,
|
||||||
|
@ -7,8 +7,6 @@ const EthBalance = require('./eth-balance')
|
|||||||
const util = require('../util')
|
const util = require('../util')
|
||||||
const addressSummary = util.addressSummary
|
const addressSummary = util.addressSummary
|
||||||
const nameForAddress = require('../../lib/contract-namer')
|
const nameForAddress = require('../../lib/contract-namer')
|
||||||
const ethUtil = require('ethereumjs-util')
|
|
||||||
const BN = ethUtil.BN
|
|
||||||
|
|
||||||
module.exports = PendingTxDetails
|
module.exports = PendingTxDetails
|
||||||
|
|
||||||
@ -29,15 +27,9 @@ 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 txFee = txData.txFee || ''
|
||||||
var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txData.estimatedGas), 16)
|
var maxCost = txData.maxCost || ''
|
||||||
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 txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
|
|
||||||
var maxCost = txValue.add(txFee)
|
|
||||||
var dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
|
var dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
|
||||||
|
|
||||||
var imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
|
var imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -13,13 +13,40 @@ function TransactionIcon () {
|
|||||||
|
|
||||||
TransactionIcon.prototype.render = function () {
|
TransactionIcon.prototype.render = function () {
|
||||||
const { transaction, txParams, isMsg } = this.props
|
const { transaction, txParams, isMsg } = this.props
|
||||||
|
switch (transaction.status) {
|
||||||
|
case 'unapproved':
|
||||||
|
return h('.unapproved-tx', {
|
||||||
|
style: {
|
||||||
|
width: '24px',
|
||||||
|
height: '24px',
|
||||||
|
background: '#4dffff',
|
||||||
|
border: 'solid',
|
||||||
|
borderColor: '#AEAEAE',
|
||||||
|
borderWidth: '0.5px',
|
||||||
|
borderRadius: '13px',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
if (transaction.status === 'rejected') {
|
case 'rejected':
|
||||||
return h('i.fa.fa-exclamation-triangle.fa-lg.warning', {
|
return h('i.fa.fa-exclamation-triangle.fa-lg.warning', {
|
||||||
style: {
|
style: {
|
||||||
width: '24px',
|
width: '24px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
case 'failed':
|
||||||
|
return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
|
||||||
|
style: {
|
||||||
|
width: '24px',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
case 'signed':
|
||||||
|
return h('i.fa.fa-ellipsis-h', {
|
||||||
|
style: {
|
||||||
|
fontSize: '27px',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMsg) {
|
if (isMsg) {
|
||||||
|
@ -8,6 +8,7 @@ const explorerLink = require('../../lib/explorer-link')
|
|||||||
const CopyButton = require('./copyButton')
|
const CopyButton = require('./copyButton')
|
||||||
const vreme = new (require('vreme'))
|
const vreme = new (require('vreme'))
|
||||||
const extension = require('../../../app/scripts/lib/extension')
|
const extension = require('../../../app/scripts/lib/extension')
|
||||||
|
const Tooltip = require('./tooltip')
|
||||||
|
|
||||||
const TransactionIcon = require('./transaction-list-item-icon')
|
const TransactionIcon = require('./transaction-list-item-icon')
|
||||||
const ShiftListItem = require('./shift-list-item')
|
const ShiftListItem = require('./shift-list-item')
|
||||||
@ -59,11 +60,7 @@ TransactionListItem.prototype.render = function () {
|
|||||||
}, [
|
}, [
|
||||||
|
|
||||||
h('.identicon-wrapper.flex-column.flex-center.select-none', [
|
h('.identicon-wrapper.flex-column.flex-center.select-none', [
|
||||||
transaction.status === 'unapproved' ? h('i.fa.fa-ellipsis-h', {
|
h('.pop-hover', {
|
||||||
style: {
|
|
||||||
fontSize: '27px',
|
|
||||||
},
|
|
||||||
}) : h('.pop-hover', {
|
|
||||||
onClick: (event) => {
|
onClick: (event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
if (!isTx || isPending) return
|
if (!isTx || isPending) return
|
||||||
@ -139,7 +136,14 @@ function failIfFailed (transaction) {
|
|||||||
if (transaction.status === 'rejected') {
|
if (transaction.status === 'rejected') {
|
||||||
return h('span.error', ' (Rejected)')
|
return h('span.error', ' (Rejected)')
|
||||||
}
|
}
|
||||||
if (transaction.status === 'failed') {
|
if (transaction.err) {
|
||||||
return h('span.error', ' (Failed)')
|
|
||||||
|
return h(Tooltip, {
|
||||||
|
title: transaction.err.message,
|
||||||
|
position: 'bottom',
|
||||||
|
}, [
|
||||||
|
h('span.error', ' (Failed)'),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,13 @@ function TransactionList () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TransactionList.prototype.render = function () {
|
TransactionList.prototype.render = function () {
|
||||||
const { txsToRender, network, unconfMsgs } = this.props
|
const { transactions, network, unconfMsgs } = this.props
|
||||||
|
|
||||||
var shapeShiftTxList
|
var shapeShiftTxList
|
||||||
if (network === '1') {
|
if (network === '1') {
|
||||||
shapeShiftTxList = this.props.shapeShiftTxList
|
shapeShiftTxList = this.props.shapeShiftTxList
|
||||||
}
|
}
|
||||||
const transactions = !shapeShiftTxList ? txsToRender.concat(unconfMsgs) : txsToRender.concat(unconfMsgs, shapeShiftTxList)
|
const txsToRender = !shapeShiftTxList ? transactions.concat(unconfMsgs) : transactions.concat(unconfMsgs, shapeShiftTxList)
|
||||||
.sort((a, b) => b.time - a.time)
|
.sort((a, b) => b.time - a.time)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -55,8 +56,8 @@ TransactionList.prototype.render = function () {
|
|||||||
},
|
},
|
||||||
}, [
|
}, [
|
||||||
|
|
||||||
transactions.length
|
txsToRender.length
|
||||||
? transactions.map((transaction, i) => {
|
? txsToRender.map((transaction, i) => {
|
||||||
let key
|
let key
|
||||||
switch (transaction.key) {
|
switch (transaction.key) {
|
||||||
case 'shapeshift':
|
case 'shapeshift':
|
||||||
|
@ -43,10 +43,9 @@ ConfirmTxScreen.prototype.render = function () {
|
|||||||
var unconfMsgs = state.unconfMsgs
|
var unconfMsgs = state.unconfMsgs
|
||||||
var unconfTxList = txHelper(unconfTxs, unconfMsgs, network)
|
var unconfTxList = txHelper(unconfTxs, unconfMsgs, network)
|
||||||
var index = state.index !== undefined ? state.index : 0
|
var index = state.index !== undefined ? state.index : 0
|
||||||
var txData = unconfTxList[index] || unconfTxList[0] || {}
|
var txData = unconfTxList[index] || {txParams: {}}
|
||||||
var txParams = txData.txParams || {}
|
var txParams = txData.txParams || {}
|
||||||
var isNotification = isPopupOrNotification() === 'notification'
|
var isNotification = isPopupOrNotification() === 'notification'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
h('.flex-column.flex-grow', [
|
h('.flex-column.flex-grow', [
|
||||||
@ -125,17 +124,10 @@ function currentTxView (opts) {
|
|||||||
}
|
}
|
||||||
ConfirmTxScreen.prototype.checkBalanceAgainstTx = function (txData) {
|
ConfirmTxScreen.prototype.checkBalanceAgainstTx = function (txData) {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
|
var address = txData.txParams.from || state.selectedAccount
|
||||||
var txParams = txData.txParams || {}
|
|
||||||
var address = txParams.from || state.selectedAccount
|
|
||||||
var account = state.accounts[address]
|
var account = state.accounts[address]
|
||||||
var balance = account ? account.balance : '0x0'
|
var balance = account ? account.balance : '0x0'
|
||||||
|
var maxCost = new BN(txData.maxCost)
|
||||||
var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txData.estimatedGas), 16)
|
|
||||||
var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice || '0x4a817c800'), 16)
|
|
||||||
var txFee = gasCost.mul(gasPrice)
|
|
||||||
var txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
|
|
||||||
var maxCost = txValue.add(txFee)
|
|
||||||
|
|
||||||
var balanceBn = new BN(ethUtil.stripHexPrefix(balance), 16)
|
var balanceBn = new BN(ethUtil.stripHexPrefix(balance), 16)
|
||||||
return maxCost.gt(balanceBn)
|
return maxCost.gt(balanceBn)
|
||||||
|
Loading…
Reference in New Issue
Block a user