nifty-wallet/ui/app/conf-tx.js

230 lines
7.4 KiB
JavaScript
Raw Normal View History

const inherits = require('util').inherits
const Component = require('react').Component
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('./actions')
const NetworkIndicator = require('./components/network')
const txHelper = require('../lib/tx-helper')
2016-08-22 17:29:47 -07:00
const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notification')
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
2016-06-24 12:48:52 -07:00
const PendingTx = require('./components/pending-tx')
const PendingMsg = require('./components/pending-msg')
2017-02-22 16:23:13 -08:00
const PendingPersonalMsg = require('./components/pending-personal-msg')
const Loading = require('./components/loading')
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
2016-06-21 13:18:32 -07:00
function mapStateToProps (state) {
return {
identities: state.metamask.identities,
accounts: state.metamask.accounts,
selectedAddress: state.metamask.selectedAddress,
unapprovedTxs: state.metamask.unapprovedTxs,
unapprovedMsgs: state.metamask.unapprovedMsgs,
2017-02-22 16:23:13 -08:00
unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs,
index: state.appState.currentView.context,
warning: state.appState.warning,
2016-09-08 12:56:04 -07:00
network: state.metamask.network,
provider: state.metamask.provider,
}
}
inherits(ConfirmTxScreen, Component)
2016-06-21 13:18:32 -07:00
function ConfirmTxScreen () {
Component.call(this)
}
2016-06-21 13:18:32 -07:00
ConfirmTxScreen.prototype.render = function () {
2017-02-22 16:23:13 -08:00
const props = this.props
const { network, provider, unapprovedTxs,
unapprovedMsgs, unapprovedPersonalMsgs } = props
2017-02-22 16:23:13 -08:00
var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network)
var index = props.index !== undefined && unconfTxList[index] ? props.index : 0
var txData = unconfTxList[index] || {}
var txParams = txData.params || {}
2016-08-22 17:29:47 -07:00
var isNotification = isPopupOrNotification() === 'notification'
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
if (unconfTxList.length === 0) return h(Loading)
return (
h('.flex-column.flex-grow', [
// subtitle and nav
h('.section-title.flex-row.flex-center', [
!isNotification ? h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: this.goHome.bind(this),
}) : null,
2017-01-05 08:31:54 -08:00
h('h2.page-subtitle', 'Confirm Transaction'),
isNotification ? h(NetworkIndicator, {
network: network,
provider: provider,
}) : null,
]),
h('h3', {
style: {
alignSelf: 'center',
display: unconfTxList.length > 1 ? 'block' : 'none',
},
}, [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
style: {
display: props.index === 0 ? 'none' : 'inline-block',
},
onClick: () => props.dispatch(actions.previousTx()),
}),
` ${props.index + 1} of ${unconfTxList.length} `,
h('i.fa.fa-arrow-right.fa-lg.cursor-pointer', {
style: {
display: props.index + 1 === unconfTxList.length ? 'none' : 'inline-block',
},
onClick: () => props.dispatch(actions.nextTx()),
}),
]),
warningIfExists(props.warning),
h(ReactCSSTransitionGroup, {
className: 'css-transition-group',
transitionName: 'main',
transitionEnterTimeout: 300,
transitionLeaveTimeout: 300,
}, [
currentTxView({
// Properties
txData: txData,
key: txData.id,
selectedAddress: props.selectedAddress,
accounts: props.accounts,
identities: props.identities,
2017-01-06 14:41:40 -08:00
insufficientBalance: this.checkBalanceAgainstTx(txData),
2017-02-27 18:33:33 -08:00
// State actions
2017-02-28 10:06:59 -08:00
onTxChange: this.onTxChange.bind(this),
// Actions
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress),
sendTransaction: this.sendTransaction.bind(this, txData),
cancelTransaction: this.cancelTransaction.bind(this, txData),
signMessage: this.signMessage.bind(this, txData),
signPersonalMessage: this.signPersonalMessage.bind(this, txData),
cancelMessage: this.cancelMessage.bind(this, txData),
2017-02-23 16:00:43 -08:00
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
}),
]),
])
)
}
function currentTxView (opts) {
log.info('rendering current tx view')
const { txData } = opts
const { txParams, msgParams, type } = txData
if (txParams) {
log.debug('txParams detected, rendering pending tx')
2016-06-24 12:48:52 -07:00
return h(PendingTx, opts)
} else if (msgParams) {
log.debug('msgParams detected, rendering pending msg')
if (type === 'eth_sign') {
log.debug('rendering eth_sign message')
return h(PendingMsg, opts)
} else if (type === 'personal_sign') {
log.debug('rendering personal_sign message')
return h(PendingPersonalMsg, opts)
}
}
}
2017-01-06 14:41:40 -08:00
ConfirmTxScreen.prototype.checkBalanceAgainstTx = function (txData) {
if (!txData.txParams) return false
var props = this.props
var address = txData.txParams.from || props.selectedAddress
var account = props.accounts[address]
var balance = account ? account.balance : '0x0'
2017-01-24 14:53:45 -08:00
var maxCost = new BN(txData.maxCost, 16)
2017-01-24 14:53:45 -08:00
var balanceBn = new BN(ethUtil.stripHexPrefix(balance), 16)
2016-09-15 14:31:45 -07:00
return maxCost.gt(balanceBn)
}
ConfirmTxScreen.prototype.buyEth = function (address, event) {
event.stopPropagation()
2016-09-15 14:31:45 -07:00
this.props.dispatch(actions.buyEthView(address))
}
2017-02-27 18:33:33 -08:00
// Allows the detail view to update the gas calculations,
// for manual gas controls.
ConfirmTxScreen.prototype.onTxChange = function (txData) {
2017-02-28 11:35:04 -08:00
log.debug(`conf-tx onTxChange triggered with ${JSON.stringify(txData)}`)
2017-02-27 18:33:33 -08:00
this.setState({ txData })
}
// Must default to any local state txData,
// to allow manual override of gas calculations.
2016-09-15 14:31:45 -07:00
ConfirmTxScreen.prototype.sendTransaction = function (txData, event) {
event.stopPropagation()
2017-02-27 18:33:33 -08:00
const state = this.state || {}
const txMeta = state.txData
this.props.dispatch(actions.sendTx(txMeta || txData))
}
2016-06-21 13:18:32 -07:00
ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) {
event.stopPropagation()
this.props.dispatch(actions.cancelTx(txData))
}
2016-06-21 13:18:32 -07:00
ConfirmTxScreen.prototype.signMessage = function (msgData, event) {
log.info('conf-tx.js: signing message')
var params = msgData.msgParams
params.metamaskId = msgData.id
event.stopPropagation()
this.props.dispatch(actions.signMsg(params))
}
ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) {
log.info('conf-tx.js: signing personal message')
var params = msgData.msgParams
params.metamaskId = msgData.id
event.stopPropagation()
this.props.dispatch(actions.signPersonalMsg(params))
}
2016-06-21 13:18:32 -07:00
ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) {
log.info('canceling message')
event.stopPropagation()
this.props.dispatch(actions.cancelMsg(msgData))
}
2017-02-23 16:00:43 -08:00
ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) {
log.info('canceling personal message')
event.stopPropagation()
this.props.dispatch(actions.cancelPersonalMsg(msgData))
}
2016-06-21 13:18:32 -07:00
ConfirmTxScreen.prototype.goHome = function (event) {
event.stopPropagation()
this.props.dispatch(actions.goHome())
}
2016-06-21 13:18:32 -07:00
function warningIfExists (warning) {
if (warning &&
// Do not display user rejections on this screen:
warning.indexOf('User denied transaction signature') === -1) {
2016-11-10 22:13:30 -08:00
return h('.error', {
style: {
margin: 'auto',
2016-11-10 22:20:58 -08:00
},
}, warning)
}
}