send tokens

This commit is contained in:
Victor Baranov 2018-09-26 21:19:00 +03:00
parent 62f3369dd3
commit 29f87f1d90
12 changed files with 609 additions and 40 deletions

View File

@ -15,6 +15,7 @@ const UnlockScreen = require('./unlock')
// accounts
const AccountDetailScreen = require('./account-detail')
const SendTransactionScreen = require('./send')
const SendTokenScreen = require('./send-token')
const ConfirmTxScreen = require('./conf-tx')
// notice
const NoticeScreen = require('./components/notice')
@ -577,6 +578,10 @@ App.prototype.renderPrimary = function () {
log.debug('rendering send tx screen')
return h(SendTransactionScreen, {key: 'send-transaction'})
case 'sendToken':
log.debug('rendering send tx screen')
return h(SendTokenScreen, {key: 'send-token'})
case 'newKeychain':
log.debug('rendering new keychain screen')
return h(NewKeyChainScreen, {key: 'new-keychain'})

View File

@ -16,9 +16,9 @@ function EthBalanceComponent () {
EthBalanceComponent.prototype.render = function () {
var props = this.props
let { value } = props
const { style, width, network } = props
const { style, width, network, isToken, tokenSymbol } = props
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
value = value ? formatBalance(value, 6, needsParse, network) : '...'
value = value ? formatBalance(value, 6, needsParse, network, isToken, tokenSymbol) : '...'
return (

View File

@ -12,6 +12,7 @@ const util = require('../util')
const MiniAccountPanel = require('./mini-account-panel')
const Copyable = require('./copyable')
const EthBalance = require('./eth-balance')
const TokenBalance = require('./token-balance')
const addressSummary = util.addressSummary
const accountSummary = util.accountSummary
const nameForAddress = require('../../lib/contract-namer')
@ -20,6 +21,9 @@ const { getEnvironmentType } = require('../../../app/scripts/lib/util')
const NetworkIndicator = require('../components/network')
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../../app/scripts/lib/enums')
const connect = require('react-redux').connect
const abiDecoder = require('abi-decoder')
const { tokenInfoGetter, calcTokenAmount } = require('../../../ui/app/token-util')
const BigNumber = require('bignumber.js')
const MIN_GAS_PRICE_BN = new BN('0')
const MIN_GAS_LIMIT_BN = new BN('21000')
@ -32,7 +36,11 @@ function PendingTx () {
valid: true,
txData: null,
submitting: false,
tokenSymbol: '',
tokenDecimals: 0,
tokenDataRetrieved: false,
}
this.tokenInfoGetter = tokenInfoGetter()
}
function mapStateToProps (state) {
@ -57,12 +65,31 @@ function mapStateToProps (state) {
}
PendingTx.prototype.render = function () {
if (!this.state.tokenDataRetrieved) return null
const props = this.props
const { currentCurrency, blockGasLimit, network, provider, isUnlocked } = props
const conversionRate = props.conversionRate
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
let { isToken, tokensToSend, tokensTransferTo } = props
let token = {
address: txParams.to,
}
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
if (decodedData && decodedData.name === 'transfer') {
isToken = true
const tokenValBN = new BigNumber(calcTokenAmount(decodedData.params[1].value, this.state.tokenDecimals))
const multiplier = Math.pow(10, 18)
tokensToSend = tokenValBN.mul(multiplier).toString(16)
tokensTransferTo = decodedData.params[0].value
token = {
address: txParams.to,
decimals: this.state.tokenDecimals,
symbol: this.state.tokenSymbol,
}
}
// Allow retry txs
const { lastGasPrice } = txMeta
@ -217,7 +244,10 @@ PendingTx.prototype.render = function () {
fontFamily: 'Nunito Regular',
},
}, [
h(EthBalance, {
isToken ? h(TokenBalance, {
token,
fontSize: '12px',
}) : h(EthBalance, {
fontSize: '12px',
value: balance,
conversionRate,
@ -231,7 +261,7 @@ PendingTx.prototype.render = function () {
forwardCarrat(),
this.miniAccountPanelForRecipient(),
this.miniAccountPanelForRecipient(isToken, tokensTransferTo),
]),
h('style', `
@ -326,7 +356,17 @@ PendingTx.prototype.render = function () {
// in the way that gas and gasLimit currently are.
h('.row', [
h('.cell.label', 'Amount'),
h(EthBalance, { valueStyle, dimStyle, value: txParams.value, currentCurrency, conversionRate, network }),
h(EthBalance, {
valueStyle,
dimStyle,
value: isToken ? tokensToSend/* (new BN(tokensToSend)).mul(1e18)*/ : txParams.value,
currentCurrency,
conversionRate,
network,
isToken,
tokenSymbol: this.state.tokenSymbol,
showFiat: !isToken,
}),
]),
// Gas Limit (customizable)
@ -381,7 +421,14 @@ PendingTx.prototype.render = function () {
// Max Transaction Fee (calculated)
h('.cell.row', [
h('.cell.label', 'Max Transaction Fee'),
h(EthBalance, { valueStyle, dimStyle, value: txFeeBn.toString(16), currentCurrency, conversionRate, network }),
h(EthBalance, {
valueStyle,
dimStyle,
value: txFeeBn.toString(16),
currentCurrency,
conversionRate,
network,
}),
]),
h('.cell.row', {
@ -482,11 +529,12 @@ PendingTx.prototype.render = function () {
)
}
PendingTx.prototype.miniAccountPanelForRecipient = function () {
PendingTx.prototype.miniAccountPanelForRecipient = function (isToken, tokensTransferTo) {
const props = this.props
const txData = props.txData
const txParams = txData.txParams || {}
const isContractDeploy = !('to' in txParams)
const to = isToken ? tokensTransferTo : txParams.to
// If it's not a contract deploy, send to the account
if (!isContractDeploy) {
@ -506,17 +554,17 @@ PendingTx.prototype.miniAccountPanelForRecipient = function () {
display: 'inline-block',
whiteSpace: 'nowrap',
},
}, accountSummary(nameForAddress(txParams.to, props.identities)), 6, 4),
}, accountSummary(nameForAddress(to, props.identities)), 6, 4),
h(Copyable, {
value: ethUtil.toChecksumAddress(txParams.to),
value: ethUtil.toChecksumAddress(to),
}, [
h('span.font-small', {
style: {
fontFamily: 'Nunito Regular',
color: 'rgba(255, 255, 255, 0.7)',
},
}, addressSummary(txParams.to, 6, 4, false)),
}, addressSummary(to, 6, 4, false)),
]),
]),
])
@ -536,6 +584,29 @@ PendingTx.prototype.miniAccountPanelForRecipient = function () {
}
}
PendingTx.prototype.componentWillMount = function () {
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
this.updateTokenInfo(txParams)
}
PendingTx.prototype.componentWillUnmount = function () {
this.setState({
tokenSymbol: '',
tokenDecimals: 0,
tokenDataRetrieved: false,
})
}
PendingTx.prototype.updateTokenInfo = async function (txParams) {
const tokenParams = await this.tokenInfoGetter(txParams.to)
this.setState({
tokenSymbol: tokenParams.symbol,
tokenDecimals: tokenParams.decimals,
tokenDataRetrieved: true,
})
}
PendingTx.prototype.gasPriceChanged = function (newBN, valid) {
log.info(`Gas price changed to: ${newBN.toString(10)}`)
const txMeta = this.gatherTxMeta()

View File

@ -0,0 +1,143 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const TokenTracker = require('eth-token-watcher')
const connect = require('react-redux').connect
const selectors = require('../../../ui/app/selectors')
const log = require('loglevel')
function mapStateToProps (state) {
return {
userAddress: selectors.getSelectedAddress(state),
}
}
module.exports = connect(mapStateToProps)(TokenBalance)
inherits(TokenBalance, Component)
function TokenBalance () {
this.state = {
string: '',
symbol: '',
isLoading: true,
error: null,
}
Component.call(this)
}
TokenBalance.prototype.render = function () {
const state = this.state
const props = this.props
const { symbol, string, isLoading } = state
const { balanceOnly } = this.props
const valueStyle = props.valueStyle ? props.valueStyle : {
color: '#ffffff',
width: '100%',
fontSize: props.fontSize || '14px',
textAlign: 'right',
}
const dimStyle = props.dimStyle ? props.dimStyle : {
color: ' #60db97',
fontSize: props.fontSize || '14px',
marginLeft: '5px',
}
return isLoading
? h('div', '')
: h('.flex-row', {
style: {
alignItems: 'flex-end',
lineHeight: '20px',
textRendering: 'geometricPrecision',
},
}, [
h('div.hide-text-overflow.token-balance__amount', {
style: valueStyle,
}, string),
!balanceOnly && h('span.token-balance__symbol', {
style: dimStyle,
}, symbol),
])
}
TokenBalance.prototype.componentDidMount = function () {
this.createFreshTokenTracker()
}
TokenBalance.prototype.createFreshTokenTracker = function () {
if (this.tracker) {
// Clean up old trackers when refreshing:
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}
if (!global.ethereumProvider) return
const { userAddress, token } = this.props
this.tracker = new TokenTracker({
userAddress,
provider: global.ethereumProvider,
tokens: [token],
pollingInterval: 8000,
})
// Set up listener instances for cleaning up
this.balanceUpdater = this.updateBalance.bind(this)
this.showError = error => {
this.setState({ error, isLoading: false })
}
this.tracker.on('update', this.balanceUpdater)
this.tracker.on('error', this.showError)
this.tracker.updateBalances()
.then(() => {
this.updateBalance(this.tracker.serialize())
})
.catch((reason) => {
log.error(`Problem updating balances`, reason)
this.setState({ isLoading: false })
})
}
TokenBalance.prototype.componentDidUpdate = function (nextProps) {
const {
userAddress: oldAddress,
token: { address: oldTokenAddress },
} = this.props
const {
userAddress: newAddress,
token: { address: newTokenAddress },
} = nextProps
if ((!oldAddress || !newAddress) && (!oldTokenAddress || !newTokenAddress)) return
if ((oldAddress === newAddress) && (oldTokenAddress === newTokenAddress)) return
this.setState({ isLoading: true })
this.createFreshTokenTracker()
}
TokenBalance.prototype.updateBalance = function (tokens = []) {
if (!this.tracker.running) {
return
}
const [{ string, symbol }] = tokens
this.setState({
string,
symbol,
isLoading: false,
})
}
TokenBalance.prototype.componentWillUnmount = function () {
if (!this.tracker) return
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}

View File

@ -7,11 +7,11 @@ const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
const ethUtil = require('ethereumjs-util')
const copyToClipboard = require('copy-to-clipboard')
const actions = require('../../../ui/app/actions')
const connect = require('react-redux').connect
const tokenCellDropDownPrefix = 'token-cell_dropdown_'
module.exports = TokenCell
inherits(TokenCell, Component)
function TokenCell () {
Component.call(this)
@ -76,7 +76,7 @@ TokenCell.prototype.render = function () {
}
TokenCell.prototype.renderTokenOptions = function (menuToTop, ind) {
const { address, symbol, string, network, userAddress } = this.props
const { address, symbol, string, network, userAddress, showSendTokenPage } = this.props
const { optionsMenuActive } = this.state
return h(
@ -100,6 +100,16 @@ TokenCell.prototype.renderTokenOptions = function (menuToTop, ind) {
},
},
[
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
showSendTokenPage(address)
},
},
`Send`,
),
h(
DropdownMenuItem,
{
@ -161,3 +171,11 @@ function tokenFactoryFor (tokenAddress) {
return `https://tokenfactory.surge.sh/#/token/${tokenAddress}`
}
const mapDispatchToProps = dispatch => {
return {
showSendTokenPage: (tokenAddress) => dispatch(actions.showSendTokenPage(tokenAddress)),
}
}
module.exports = connect(null, mapDispatchToProps)(TokenCell)

View File

@ -16,22 +16,28 @@ const Loading = require('./components/loading')
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
function mapStateToProps (state) {
const { metamask, appState } = state
const { screenParams, pendingTxIndex } = appState.currentView
return {
identities: state.metamask.identities,
accounts: state.metamask.accounts,
selectedAddress: state.metamask.selectedAddress,
unapprovedTxs: state.metamask.unapprovedTxs,
unapprovedMsgs: state.metamask.unapprovedMsgs,
unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs,
unapprovedTypedMessages: state.metamask.unapprovedTypedMessages,
index: state.appState.currentView.pendingTxIndex || 0,
warning: state.appState.warning,
network: state.metamask.network,
provider: state.metamask.provider,
conversionRate: state.metamask.conversionRate,
currentCurrency: state.metamask.currentCurrency,
blockGasLimit: state.metamask.currentBlockGasLimit,
computedBalances: state.metamask.computedBalances,
identities: metamask.identities,
accounts: metamask.accounts,
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),
}
}
@ -95,6 +101,10 @@ ConfirmTxScreen.prototype.render = function () {
unconfTxListLength,
computedBalances,
network,
isToken: props.isToken,
tokenSymbol: props.tokenSymbol,
tokensToSend: props.tokensToSend,
tokensTransferTo: props.tokensTransferTo,
// Actions
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress),
sendTransaction: this.sendTransaction.bind(this),

315
old-ui/app/send-token.js Normal file
View File

@ -0,0 +1,315 @@
const inherits = require('util').inherits
const PersistentForm = require('../lib/persistent-form')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const Identicon = require('./components/identicon')
const actions = require('../../ui/app/actions')
const util = require('./util')
const numericBalance = require('./util').numericBalance
const addressSummary = require('./util').addressSummary
const EthBalance = require('./components/eth-balance')
const EnsInput = require('./components/ens-input')
const ethUtil = require('ethereumjs-util')
const { tokenInfoGetter } = require('../../ui/app/token-util')
const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb'
module.exports = connect(mapStateToProps)(SendTransactionScreen)
function mapStateToProps (state) {
var result = {
address: state.metamask.selectedAddress,
accounts: state.metamask.accounts,
identities: state.metamask.identities,
warning: state.appState.warning,
network: state.metamask.network,
addressBook: state.metamask.addressBook,
conversionRate: state.metamask.conversionRate,
currentCurrency: state.metamask.currentCurrency,
tokenAddress: state.appState.currentView.tokenAddress,
}
result.error = result.warning && result.warning.split('.')[0]
result.account = result.accounts[result.address]
result.identity = result.identities[result.address]
result.balance = result.account ? numericBalance(result.account.balance) : null
return result
}
inherits(SendTransactionScreen, PersistentForm)
function SendTransactionScreen () {
PersistentForm.call(this)
}
SendTransactionScreen.prototype.render = function () {
this.persistentFormParentId = 'send-tx-form'
const props = this.props
const {
address,
account,
identity,
network,
identities,
addressBook,
conversionRate,
currentCurrency,
} = props
return (
h('.send-screen.flex-column.flex-grow', [
//
// Sender Profile
//
h('.account-data-subsection.flex-row.flex-grow', {
style: {
background: 'linear-gradient(rgb(84, 36, 147), rgb(104, 45, 182))',
padding: '30px',
},
}, [
// header - identicon + nav
h('.flex-row.flex-space-between', [
// large identicon
h('.identicon-wrapper.flex-column.flex-center.select-none', {
style: {
display: 'inline-block',
},
}, [
h(Identicon, {
diameter: 62,
address: address,
}),
]),
// invisible place holder
h('i.fa.fa-users.fa-lg.invisible', {
style: {
marginTop: '28px',
},
}),
]),
// account label
h('.flex-column', {
style: {
alignItems: 'flex-start',
},
}, [
h('h2.font-medium.flex-center', {
style: {
color: '#ffffff',
paddingTop: '8px',
marginBottom: '8px',
},
}, identity && identity.name),
// address and getter actions
h('.flex-row.flex-center', {
style: {
color: 'rgba(255, 255, 255, 0.7)',
marginBottom: '30px',
},
}, [
h('div', {
style: {
lineHeight: '16px',
fontSize: '14px',
},
}, addressSummary(address)),
]),
// balance
h('.flex-row.flex-center', [
h(EthBalance, {
value: account && account.balance,
conversionRate,
currentCurrency,
network,
}),
]),
]),
]),
//
// Required Fields
//
h('h3.flex-center', {
style: {
color: '#333333',
marginTop: '18px',
marginBottom: '14px',
},
}, [
// back button
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
style: {
position: 'absolute',
left: '30px',
},
onClick: this.back.bind(this),
}),
'Send Tokens',
]),
// error message
props.error && h('div', {style: {
marginLeft: '30px',
marginRight: '30px',
}}, [
h('div.error.flex-center', props.error),
]),
// 'to' field
h('section.flex-row.flex-center', [
h(EnsInput, {
name: 'address',
placeholder: 'Recipient Address',
onChange: this.recipientDidChange.bind(this),
network,
identities,
addressBook,
}),
]),
// 'amount' and send button
h('section.flex-row.flex-center', [
h('input.large-input', {
name: 'amount',
placeholder: 'Amount',
type: 'number',
style: {
marginRight: '6px',
},
dataset: {
persistentFormId: 'tx-amount',
},
}),
h('button', {
onClick: this.onSubmit.bind(this),
}, 'Next'),
]),
])
)
}
SendTransactionScreen.prototype.componentWillUnmount = function () {
this.props.dispatch(actions.displayWarning(''))
}
SendTransactionScreen.prototype.navigateToAccounts = function (event) {
event.stopPropagation()
this.props.dispatch(actions.showAccountsPage())
}
SendTransactionScreen.prototype.back = function () {
var address = this.props.address
this.props.dispatch(actions.backToAccountDetail(address))
}
SendTransactionScreen.prototype.recipientDidChange = function (recipient, nickname) {
this.setState({
recipient: recipient,
nickname: nickname,
})
}
SendTransactionScreen.prototype.onSubmit = async function () {
const { tokenAddress } = this.props
const state = this.state || {}
const recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
const nickname = state.nickname || ' '
const input = document.querySelector('input[name="amount"]').value
const parts = input.split('')
this.tokenInfoGetter = tokenInfoGetter()
let message
if (isNaN(input) || input === '') {
message = 'Invalid ether value.'
return this.props.dispatch(actions.displayWarning(message))
}
if (parts[1]) {
var decimal = parts[1]
if (decimal.length > 18) {
message = 'Ether amount is too precise.'
return this.props.dispatch(actions.displayWarning(message))
}
}
const value = util.normalizeEthStringToWei(input)
// const balance = this.props.balance
// if (value.gt(balance)) {
// message = 'Insufficient token\'s balance.'
// return this.props.dispatch(actions.displayWarning(message))
// }
if (input < 0) {
message = 'Can not send negative amounts of ETH.'
return this.props.dispatch(actions.displayWarning(message))
}
if ((util.isInvalidChecksumAddress(recipient))) {
message = 'Recipient address checksum is invalid.'
return this.props.dispatch(actions.displayWarning(message))
}
if (!util.isValidAddress(recipient) || (!recipient)) {
message = 'Recipient address is invalid.'
return this.props.dispatch(actions.displayWarning(message))
}
this.props.dispatch(actions.hideWarning())
this.props.dispatch(actions.addToAddressBook(recipient, nickname))
var txParams = {
from: this.props.address,
value: '0x',
}
const toAddress = ethUtil.addHexPrefix(recipient)
if (recipient) txParams.to = ethUtil.addHexPrefix(tokenAddress)
const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(txParams.to)
const tokeValRaw = value / 1e18 * `1e${decimals}` // todo: use calcTokenAmount function
const tokenVal = `0x${tokeValRaw.toString(16)}`
const encoded = this.generateTokenTransferData({toAddress, amount: tokenVal})
txParams.data = encoded
const confTxScreenParams = {
isToken: true,
tokenSymbol: symbol,
tokensToSend: value,
tokensTransferTo: toAddress,
}
this.props.dispatch(actions.signTokenTx(tokenAddress, toAddress, value, txParams, confTxScreenParams))
}
SendTransactionScreen.prototype.generateTokenTransferData = function ({ toAddress = '0x0', amount = '0x0' }) {
const abi = require('ethereumjs-abi')
return TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call(
abi.rawEncode(['address', 'uint256'], [toAddress, ethUtil.addHexPrefix(amount)]),
x => ('00' + x.toString(16)).slice(-2)
).join('')
}

View File

@ -111,10 +111,11 @@ function parseBalance (balance) {
// Takes wei hex, returns an object with three properties.
// Its "formatted" property is what we generally use to render values.
function formatBalance (balance, decimalsToKeep, needsParse = true, network) {
function formatBalance (balance, decimalsToKeep, needsParse = true, network, isToken, tokenSymbol) {
const isSokol = parseInt(network) === 77
const isPOA = parseInt(network) === 99
const coinName = isPOA ? 'POA' : isSokol ? 'SPOA' : 'ETH'
const assetName = isToken ? tokenSymbol : coinName
var parsed = needsParse ? parseBalance(balance) : balance.split('.')
var beforeDecimal = parsed[0]
var afterDecimal = parsed[1]
@ -124,14 +125,14 @@ function formatBalance (balance, decimalsToKeep, needsParse = true, network) {
if (afterDecimal !== '0') {
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
if (sigFigs) { afterDecimal = sigFigs[0] }
formatted = '0.' + afterDecimal + ` ${coinName}`
formatted = '0.' + afterDecimal + ` ${assetName}`
}
} else {
formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${coinName}`
formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${assetName}`
}
} else {
afterDecimal += Array(decimalsToKeep).join('0')
formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${coinName}`
formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${assetName}`
}
return formatted
}

View File

@ -1074,7 +1074,7 @@ function sendTx (txData) {
}
}
function signTokenTx (tokenAddress, toAddress, amount, txData) {
function signTokenTx (tokenAddress, toAddress, amount, txData, confTxScreenParams) {
return dispatch => {
dispatch(actions.showLoadingIndication())
const token = global.eth.contract(abi).at(tokenAddress)
@ -1083,7 +1083,7 @@ function signTokenTx (tokenAddress, toAddress, amount, txData) {
dispatch(actions.hideLoadingIndication())
dispatch(actions.displayWarning(err.message))
})
dispatch(actions.showConfTxPage({}))
dispatch(actions.showConfTxPage(confTxScreenParams || {}))
}
}
@ -1109,7 +1109,7 @@ function updateTransaction (txData) {
.then(() => updateMetamaskStateFromBackground())
.then(newState => dispatch(actions.updateMetamaskState(newState)))
.then(() => {
dispatch(actions.showConfTxPage({ id: txData.id }))
dispatch(actions.showConfTxPage({ id: txData.id}))
dispatch(actions.hideLoadingIndication())
return txData
})
@ -1542,11 +1542,12 @@ function showAccountsPage () {
}
}
function showConfTxPage ({transForward = true, id}) {
function showConfTxPage (screenParams) {
return {
type: actions.SHOW_CONF_TX_PAGE,
transForward,
id,
transForward: (screenParams.transForward || true),
id: screenParams.id,
value: screenParams,
}
}
@ -1994,9 +1995,11 @@ function showSendPage () {
}
}
function showSendTokenPage () {
function showSendTokenPage (address) {
return {
type: actions.SHOW_SEND_TOKEN_PAGE,
value: address,
}
}

View File

@ -122,7 +122,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
if (isUnapproved) {
opts.onClick = () => {
this.props.showConfTxPage({ id: transactionId })
this.props.showConfTxPage({ id: transactionId})
history.push(CONFIRM_TRANSACTION_ROUTE)
}
opts.transactionStatus = this.context.t('notStarted')

View File

@ -297,6 +297,7 @@ function reduceApp (state, action) {
currentView: {
name: 'sendToken',
context: appState.currentView.context,
tokenAddress: action.value,
},
transForward: true,
warning: null,
@ -438,6 +439,7 @@ function reduceApp (state, action) {
currentView: {
name: 'confTx',
pendingTxIndex: action.id ? indexForPending(state, action.id) : 0,
screenParams: action.value,
},
transForward: action.transForward,
warning: null,

View File

@ -54,6 +54,7 @@ async function startApp (metamaskState, accountManager, opts) {
const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network)
const numberOfUnapprivedTx = unapprovedTxsAll.length
if (numberOfUnapprivedTx > 0) {
store.dispatch(actions.showConfTxPage({
id: unapprovedTxsAll[numberOfUnapprivedTx - 1].id,
}))