2017-11-14 08:04:23 -08:00
|
|
|
const inherits = require('util').inherits
|
|
|
|
const Component = require('react').Component
|
|
|
|
const h = require('react-hyperscript')
|
|
|
|
const connect = require('react-redux').connect
|
2017-11-15 09:35:18 -08:00
|
|
|
const actions = require('../../ui/app/actions')
|
2018-01-16 18:17:28 -08:00
|
|
|
const LoadingIndicator = require('./components/loading')
|
2017-11-14 08:04:23 -08:00
|
|
|
const txHelper = require('../lib/tx-helper')
|
2018-04-12 14:06:59 -07:00
|
|
|
const log = require('loglevel')
|
2018-12-24 08:22:14 -08:00
|
|
|
const { getCurrentKeyring, ifContractAcc } = require('./util')
|
2017-11-14 08:04:23 -08:00
|
|
|
|
|
|
|
const PendingTx = require('./components/pending-tx')
|
2018-10-30 07:30:51 -07:00
|
|
|
import PendingMsg from './components/pending-msg'
|
|
|
|
import PendingPersonalMsg from './components/pending-personal-msg'
|
|
|
|
import PendingTypedMsg from './components/pending-typed-msg'
|
2017-11-14 08:04:23 -08:00
|
|
|
const Loading = require('./components/loading')
|
2019-02-06 08:21:56 -08:00
|
|
|
const { DAI_CODE, POA_SOKOL_CODE, GOERLI_TESTNET_CODE } = require('../../app/scripts/controllers/network/enums')
|
2018-11-30 14:51:24 -08:00
|
|
|
const { getMetaMaskAccounts } = require('../../ui/app/selectors')
|
2017-11-14 08:04:23 -08:00
|
|
|
|
|
|
|
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
|
|
|
|
|
|
|
|
function mapStateToProps (state) {
|
2018-09-26 11:19:00 -07:00
|
|
|
const { metamask, appState } = state
|
|
|
|
const { screenParams, pendingTxIndex } = appState.currentView
|
2017-11-14 08:04:23 -08:00
|
|
|
return {
|
2018-09-26 11:19:00 -07:00
|
|
|
identities: metamask.identities,
|
2018-11-30 14:51:24 -08:00
|
|
|
accounts: getMetaMaskAccounts(state),
|
2018-12-24 08:22:14 -08:00
|
|
|
keyrings: metamask.keyrings,
|
2018-09-26 11:19:00 -07:00
|
|
|
selectedAddress: metamask.selectedAddress,
|
|
|
|
unapprovedTxs: metamask.unapprovedTxs,
|
|
|
|
unapprovedMsgs: metamask.unapprovedMsgs,
|
|
|
|
unapprovedPersonalMsgs: metamask.unapprovedPersonalMsgs,
|
|
|
|
unapprovedTypedMessages: metamask.unapprovedTypedMessages,
|
|
|
|
index: pendingTxIndex || 0,
|
|
|
|
warning: appState.warning,
|
|
|
|
network: metamask.network,
|
|
|
|
provider: metamask.provider,
|
|
|
|
conversionRate: metamask.conversionRate,
|
|
|
|
currentCurrency: metamask.currentCurrency,
|
|
|
|
blockGasLimit: metamask.currentBlockGasLimit,
|
|
|
|
computedBalances: metamask.computedBalances,
|
|
|
|
isToken: (screenParams && screenParams.isToken),
|
|
|
|
tokenSymbol: (screenParams && screenParams.tokenSymbol),
|
|
|
|
tokensToSend: (screenParams && screenParams.tokensToSend),
|
|
|
|
tokensTransferTo: (screenParams && screenParams.tokensTransferTo),
|
2018-12-24 08:22:14 -08:00
|
|
|
isContractExecutionByUser: (screenParams && screenParams.isContractExecutionByUser),
|
2017-11-14 08:04:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inherits(ConfirmTxScreen, Component)
|
|
|
|
function ConfirmTxScreen () {
|
|
|
|
Component.call(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.render = function () {
|
|
|
|
const props = this.props
|
2018-07-30 06:01:21 -07:00
|
|
|
const { network, unapprovedTxs, currentCurrency, computedBalances,
|
2018-07-19 05:01:18 -07:00
|
|
|
unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, blockGasLimit } = props
|
|
|
|
let { conversionRate } = props
|
|
|
|
|
2019-02-06 08:21:56 -08:00
|
|
|
const isTestnet = parseInt(network) === POA_SOKOL_CODE || parseInt(network) === GOERLI_TESTNET_CODE
|
2019-01-10 08:59:43 -08:00
|
|
|
const isDai = parseInt(network) === DAI_CODE
|
2019-01-10 10:01:33 -08:00
|
|
|
if (isTestnet) {
|
2018-07-19 05:01:18 -07:00
|
|
|
conversionRate = 0
|
2018-10-11 10:54:28 -07:00
|
|
|
} else if (isDai) {
|
|
|
|
conversionRate = 1
|
2018-07-19 05:01:18 -07:00
|
|
|
}
|
2017-11-14 08:04:23 -08:00
|
|
|
|
|
|
|
var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network)
|
2018-08-23 07:01:28 -07:00
|
|
|
const ind = props.index || 0
|
|
|
|
var txData = unconfTxList[ind] || {}
|
2017-11-14 08:04:23 -08:00
|
|
|
var txParams = txData.params || {}
|
|
|
|
|
|
|
|
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
|
|
|
if (unconfTxList.length === 0) return h(Loading, { isLoading: true })
|
|
|
|
|
|
|
|
const unconfTxListLength = unconfTxList.length
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
2018-07-27 08:21:01 -07:00
|
|
|
h('.flex-column.flex-grow', {
|
|
|
|
style: {
|
|
|
|
width: '100%',
|
2018-07-27 09:54:23 -07:00
|
|
|
},
|
2018-07-27 08:21:01 -07:00
|
|
|
}, [
|
2017-11-14 08:04:23 -08:00
|
|
|
|
2018-01-16 18:17:28 -08:00
|
|
|
h(LoadingIndicator, {
|
2018-01-23 01:12:50 -08:00
|
|
|
isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults,
|
2018-01-16 18:17:28 -08:00
|
|
|
loadingMessage: 'Estimating transaction cost…',
|
2018-01-23 01:12:50 -08:00
|
|
|
canBypass: true,
|
|
|
|
bypass: () => {
|
|
|
|
this.setState({bypassLoadingScreen: true})
|
|
|
|
},
|
2018-01-16 18:17:28 -08:00
|
|
|
}),
|
|
|
|
|
2017-11-14 08:04:23 -08:00
|
|
|
// subtitle and nav
|
|
|
|
|
|
|
|
warningIfExists(props.warning),
|
|
|
|
|
|
|
|
currentTxView({
|
|
|
|
// Properties
|
|
|
|
txData: txData,
|
|
|
|
key: txData.id,
|
|
|
|
selectedAddress: props.selectedAddress,
|
|
|
|
accounts: props.accounts,
|
|
|
|
identities: props.identities,
|
|
|
|
conversionRate,
|
|
|
|
currentCurrency,
|
|
|
|
blockGasLimit,
|
|
|
|
unconfTxListLength,
|
|
|
|
computedBalances,
|
2018-07-19 05:01:18 -07:00
|
|
|
network,
|
2018-09-26 11:19:00 -07:00
|
|
|
isToken: props.isToken,
|
|
|
|
tokenSymbol: props.tokenSymbol,
|
|
|
|
tokensToSend: props.tokensToSend,
|
|
|
|
tokensTransferTo: props.tokensTransferTo,
|
2017-11-14 08:04:23 -08:00
|
|
|
// Actions
|
2018-12-24 12:59:14 -08:00
|
|
|
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser),
|
2017-11-14 08:04:23 -08:00
|
|
|
sendTransaction: this.sendTransaction.bind(this),
|
|
|
|
cancelTransaction: this.cancelTransaction.bind(this, txData),
|
|
|
|
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),
|
|
|
|
}),
|
|
|
|
])
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
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')
|
|
|
|
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)
|
|
|
|
} else if (type === 'eth_signTypedData') {
|
|
|
|
log.debug('rendering eth_signTypedData message')
|
|
|
|
return h(PendingTypedMsg, opts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-24 12:59:14 -08:00
|
|
|
ConfirmTxScreen.prototype.buyEth = function (address, isContractExecutionByUser, event) {
|
2017-11-14 08:04:23 -08:00
|
|
|
event.preventDefault()
|
2018-12-24 12:59:14 -08:00
|
|
|
this.props.dispatch(actions.buyEthView(address, isContractExecutionByUser))
|
2017-11-14 08:04:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.sendTransaction = function (txData, event) {
|
|
|
|
this.stopPropagation(event)
|
|
|
|
this.props.dispatch(actions.updateAndApproveTx(txData))
|
2018-12-24 08:22:14 -08:00
|
|
|
this._checkIfContractExecutionAndUnlockContract(txData)
|
2017-11-14 08:04:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) {
|
|
|
|
this.stopPropagation(event)
|
|
|
|
event.preventDefault()
|
|
|
|
this.props.dispatch(actions.cancelTx(txData))
|
2018-12-24 08:22:14 -08:00
|
|
|
this._checkIfContractExecutionAndUnlockContract(txData)
|
2017-11-14 08:04:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.cancelAllTransactions = function (unconfTxList, event) {
|
|
|
|
this.stopPropagation(event)
|
|
|
|
event.preventDefault()
|
|
|
|
this.props.dispatch(actions.cancelAllTx(unconfTxList))
|
2018-12-24 08:22:14 -08:00
|
|
|
this._checkIfMultipleContractExecutionAndUnlockContract(unconfTxList)
|
2017-11-14 08:04:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.signMessage = function (msgData, event) {
|
|
|
|
log.info('conf-tx.js: signing message')
|
|
|
|
var params = msgData.msgParams
|
|
|
|
params.metamaskId = msgData.id
|
|
|
|
this.stopPropagation(event)
|
|
|
|
this.props.dispatch(actions.signMsg(params))
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.stopPropagation = function (event) {
|
|
|
|
if (event.stopPropagation) {
|
|
|
|
event.stopPropagation()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) {
|
|
|
|
log.info('conf-tx.js: signing personal message')
|
|
|
|
var params = msgData.msgParams
|
|
|
|
params.metamaskId = msgData.id
|
|
|
|
this.stopPropagation(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)
|
|
|
|
this.props.dispatch(actions.cancelMsg(msgData))
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) {
|
|
|
|
log.info('canceling personal message')
|
|
|
|
this.stopPropagation(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))
|
|
|
|
}
|
|
|
|
|
2018-12-24 08:22:14 -08:00
|
|
|
ConfirmTxScreen.prototype._checkIfMultipleContractExecutionAndUnlockContract = function (unconfTxList) {
|
|
|
|
const areTxsToOneContractFromTheList = unconfTxList.slice(0).reduce((res, txData, ind, unconfTxList) => {
|
|
|
|
if (txData.txParams.data && this.props.isContractExecutionByUser) {
|
|
|
|
const to = txData && txData.txParams && txData.txParams.to
|
|
|
|
const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to)
|
|
|
|
if (targetContractIsInTheList && Object.keys(res).length === 0) {
|
|
|
|
res = { status: true, to }
|
|
|
|
} else if (res.status && res.to !== to) {
|
|
|
|
res = { status: false }
|
|
|
|
unconfTxList.splice(1)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res = { status: false }
|
|
|
|
unconfTxList.splice(1)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}, {})
|
|
|
|
|
|
|
|
if (areTxsToOneContractFromTheList.status) {
|
|
|
|
this._unlockContract(areTxsToOneContractFromTheList.to)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype._checkIfContractExecutionAndUnlockContract = function (txData) {
|
|
|
|
if (txData.txParams.data && this.props.isContractExecutionByUser) {
|
|
|
|
const to = txData && txData.txParams && txData.txParams.to
|
|
|
|
const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to)
|
|
|
|
if (targetContractIsInTheList) {
|
|
|
|
this._unlockContract(to)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfirmTxScreen.prototype._unlockContract = function (to) {
|
|
|
|
const currentKeyring = getCurrentKeyring(to, this.props.network, this.props.keyrings, this.props.identities)
|
|
|
|
if (ifContractAcc(currentKeyring)) {
|
|
|
|
this.props.dispatch(actions.showAccountDetail(to))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-14 08:04:23 -08:00
|
|
|
function warningIfExists (warning) {
|
|
|
|
if (warning &&
|
|
|
|
// Do not display user rejections on this screen:
|
|
|
|
warning.indexOf('User denied transaction signature') === -1) {
|
|
|
|
return h('.error', {
|
|
|
|
style: {
|
|
|
|
margin: 'auto',
|
|
|
|
},
|
|
|
|
}, warning)
|
|
|
|
}
|
|
|
|
}
|