mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-27 21:00:13 +01:00
5f254f7325
* Add UseNonce toggle * Get the toggle actually working and dispatching * Display nonce field on confirmation page * Remove console.log * Add placeholder * Set customNonceValue * Add nonce key/value to txParams * remove customNonceValue from component state * Use translation file and existing CSS class * Use existing TextField component * Remove console.log * Fix lint nits * Okay this sorta works? * Move nonce toggle to advanced tab * Set min to 0 * Wrap value in Number() * Add customNonceMap * Update custom nonce translation * Update styles * Reset CustomNonce * Fix lint * Get tests passing * Add customNonceValue to defaults * Fix test * Fix comments * Update tests * Use camel case * Ensure custom nonce can only be whole number * Correct font size for custom nonce input * UX improvements for custom nonce feature * Fix advanced-tab-component tests for custom nonce changes * Update title of nonce toggle in settings * Remove unused locale message * Cast custom nonce to string in confirm-transaction-base.component * Handle string conversion and invalid values for custom nonces in handler * Don't call getNonceLock in tx controller if there is a custom nonce * Set nonce details for cases where nonce is customized * Fix incorrectly use value for deciding whether to getnoncelock in approveTransaction * Default nonceLock to empty object in approveTransaction * Reapply use on nonceLock in cases where customNonceValue in approveTransaction. * Show warning message if custom nonce is higher than MetaMask's next nonce * Fix e2e test failure caused by custom nonce and 3box toggle conflict * Update nonce warning message to include the suggested nonce * Handle nextNonce comparison and update logic in lifecycle * Default nonce field to suggested nonce * Clear custom nonce on reject or confirm * Fix bug where nonces are not shown in tx list on self sent transactions * Ensure custom nonce is reset after tx is created in background * Convert customNonceValue to number in approve tranasction controller * Lint fix * Call getNextNonce after updating custom nonce
288 lines
8.3 KiB
JavaScript
288 lines
8.3 KiB
JavaScript
import { connect } from 'react-redux'
|
|
import { compose } from 'recompose'
|
|
import { withRouter } from 'react-router-dom'
|
|
import R from 'ramda'
|
|
import contractMap from 'eth-contract-metadata'
|
|
import ConfirmTransactionBase from './confirm-transaction-base.component'
|
|
import {
|
|
clearConfirmTransaction,
|
|
} from '../../ducks/confirm-transaction/confirm-transaction.duck'
|
|
|
|
import {
|
|
updateCustomNonce,
|
|
clearSend,
|
|
cancelTx,
|
|
cancelTxs,
|
|
updateAndApproveTx,
|
|
showModal,
|
|
setMetaMetricsSendCount,
|
|
updateTransaction,
|
|
getNextNonce,
|
|
} from '../../store/actions'
|
|
import {
|
|
INSUFFICIENT_FUNDS_ERROR_KEY,
|
|
GAS_LIMIT_TOO_LOW_ERROR_KEY,
|
|
} from '../../helpers/constants/error-keys'
|
|
import { getHexGasTotal } from '../../helpers/utils/confirm-tx.util'
|
|
import { isBalanceSufficient, calcGasTotal } from '../send/send.utils'
|
|
import { conversionGreaterThan } from '../../helpers/utils/conversion-util'
|
|
import { MIN_GAS_LIMIT_DEC } from '../send/send.constants'
|
|
import { checksumAddress, addressSlicer, valuesFor } from '../../helpers/utils/util'
|
|
import { getMetaMaskAccounts, getCustomNonceValue, getUseNonceField, getAdvancedInlineGasShown, preferencesSelector, getIsMainnet, getKnownMethodData } from '../../selectors/selectors'
|
|
import { transactionFeeSelector } from '../../selectors/confirm-transaction'
|
|
|
|
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
|
|
return {
|
|
...acc,
|
|
[base.toLowerCase()]: contractMap[base],
|
|
}
|
|
}, {})
|
|
|
|
let customNonceValue = ''
|
|
const customNonceMerge = txData => customNonceValue ? ({
|
|
...txData,
|
|
customNonceValue,
|
|
}) : txData
|
|
|
|
const mapStateToProps = (state, ownProps) => {
|
|
const { toAddress: propsToAddress, match: { params = {} } } = ownProps
|
|
const { id: paramsTransactionId } = params
|
|
const { showFiatInTestnets } = preferencesSelector(state)
|
|
const isMainnet = getIsMainnet(state)
|
|
const { confirmTransaction, metamask } = state
|
|
const {
|
|
conversionRate,
|
|
identities,
|
|
addressBook,
|
|
currentCurrency,
|
|
selectedAddress,
|
|
selectedAddressTxList,
|
|
assetImages,
|
|
network,
|
|
unapprovedTxs,
|
|
metaMetricsSendCount,
|
|
nextNonce,
|
|
} = metamask
|
|
const {
|
|
tokenData,
|
|
txData,
|
|
tokenProps,
|
|
nonce,
|
|
} = confirmTransaction
|
|
const { txParams = {}, lastGasPrice, id: transactionId, transactionCategory } = txData
|
|
const transaction = R.find(({ id }) => id === (transactionId || Number(paramsTransactionId)))(selectedAddressTxList) || {}
|
|
const {
|
|
from: fromAddress,
|
|
to: txParamsToAddress,
|
|
gasPrice,
|
|
gas: gasLimit,
|
|
value: amount,
|
|
data,
|
|
} = transaction && transaction.txParams || txParams
|
|
const accounts = getMetaMaskAccounts(state)
|
|
const assetImage = assetImages[txParamsToAddress]
|
|
|
|
const { balance } = accounts[selectedAddress]
|
|
const { name: fromName } = identities[selectedAddress]
|
|
const toAddress = propsToAddress || txParamsToAddress
|
|
const toName = identities[toAddress]
|
|
? identities[toAddress].name
|
|
: (
|
|
casedContractMap[toAddress]
|
|
? casedContractMap[toAddress].name
|
|
: addressSlicer(checksumAddress(toAddress))
|
|
)
|
|
|
|
const addressBookObject = addressBook[checksumAddress(toAddress)]
|
|
const toNickname = addressBookObject ? addressBookObject.name : ''
|
|
const isTxReprice = Boolean(lastGasPrice)
|
|
const transactionStatus = transaction ? transaction.status : ''
|
|
|
|
const {
|
|
ethTransactionAmount,
|
|
ethTransactionFee,
|
|
ethTransactionTotal,
|
|
fiatTransactionAmount,
|
|
fiatTransactionFee,
|
|
fiatTransactionTotal,
|
|
hexTransactionAmount,
|
|
hexTransactionFee,
|
|
hexTransactionTotal,
|
|
} = transactionFeeSelector(state, transaction)
|
|
|
|
if (transaction && transaction.simulationFails) {
|
|
txData.simulationFails = transaction.simulationFails
|
|
}
|
|
|
|
const currentNetworkUnapprovedTxs = R.filter(
|
|
({ metamaskNetworkId }) => metamaskNetworkId === network,
|
|
unapprovedTxs,
|
|
)
|
|
const unapprovedTxCount = valuesFor(currentNetworkUnapprovedTxs).length
|
|
|
|
const insufficientBalance = !isBalanceSufficient({
|
|
amount,
|
|
gasTotal: calcGasTotal(gasLimit, gasPrice),
|
|
balance,
|
|
conversionRate,
|
|
})
|
|
|
|
const methodData = getKnownMethodData(state, data) || {}
|
|
|
|
return {
|
|
balance,
|
|
fromAddress,
|
|
fromName,
|
|
toAddress,
|
|
toName,
|
|
toNickname,
|
|
ethTransactionAmount,
|
|
ethTransactionFee,
|
|
ethTransactionTotal,
|
|
fiatTransactionAmount,
|
|
fiatTransactionFee,
|
|
fiatTransactionTotal,
|
|
hexTransactionAmount,
|
|
hexTransactionFee,
|
|
hexTransactionTotal,
|
|
txData: { ...txData, ...transaction },
|
|
tokenData,
|
|
methodData,
|
|
tokenProps,
|
|
isTxReprice,
|
|
currentCurrency,
|
|
conversionRate,
|
|
transactionStatus,
|
|
nonce,
|
|
assetImage,
|
|
unapprovedTxs,
|
|
unapprovedTxCount,
|
|
currentNetworkUnapprovedTxs,
|
|
customGas: {
|
|
gasLimit,
|
|
gasPrice,
|
|
},
|
|
advancedInlineGasShown: getAdvancedInlineGasShown(state),
|
|
useNonceField: getUseNonceField(state),
|
|
customNonceValue: getCustomNonceValue(state),
|
|
insufficientBalance,
|
|
hideSubtitle: (!isMainnet && !showFiatInTestnets),
|
|
hideFiatConversion: (!isMainnet && !showFiatInTestnets),
|
|
metaMetricsSendCount,
|
|
transactionCategory,
|
|
nextNonce,
|
|
}
|
|
}
|
|
|
|
export const mapDispatchToProps = dispatch => {
|
|
return {
|
|
updateCustomNonce: value => {
|
|
customNonceValue = value
|
|
dispatch(updateCustomNonce(value))
|
|
},
|
|
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
|
|
clearSend: () => dispatch(clearSend()),
|
|
showTransactionConfirmedModal: ({ onSubmit }) => {
|
|
return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit }))
|
|
},
|
|
showCustomizeGasModal: ({ txData, onSubmit, validate }) => {
|
|
return dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData, onSubmit, validate }))
|
|
},
|
|
updateGasAndCalculate: (updatedTx) => {
|
|
return dispatch(updateTransaction(updatedTx))
|
|
},
|
|
showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => {
|
|
return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount }))
|
|
},
|
|
cancelTransaction: ({ id }) => dispatch(cancelTx({ id })),
|
|
cancelAllTransactions: (txList) => dispatch(cancelTxs(txList)),
|
|
sendTransaction: txData => dispatch(updateAndApproveTx(customNonceMerge(txData))),
|
|
setMetaMetricsSendCount: val => dispatch(setMetaMetricsSendCount(val)),
|
|
getNextNonce: () => dispatch(getNextNonce()),
|
|
}
|
|
}
|
|
|
|
const getValidateEditGas = ({ balance, conversionRate, txData }) => {
|
|
const { txParams: { value: amount } = {} } = txData
|
|
|
|
return ({ gasLimit, gasPrice }) => {
|
|
const gasTotal = getHexGasTotal({ gasLimit, gasPrice })
|
|
const hasSufficientBalance = isBalanceSufficient({
|
|
amount,
|
|
gasTotal,
|
|
balance,
|
|
conversionRate,
|
|
})
|
|
|
|
if (!hasSufficientBalance) {
|
|
return {
|
|
valid: false,
|
|
errorKey: INSUFFICIENT_FUNDS_ERROR_KEY,
|
|
}
|
|
}
|
|
|
|
const gasLimitTooLow = gasLimit && conversionGreaterThan(
|
|
{
|
|
value: MIN_GAS_LIMIT_DEC,
|
|
fromNumericBase: 'dec',
|
|
conversionRate,
|
|
},
|
|
{
|
|
value: gasLimit,
|
|
fromNumericBase: 'hex',
|
|
},
|
|
)
|
|
|
|
if (gasLimitTooLow) {
|
|
return {
|
|
valid: false,
|
|
errorKey: GAS_LIMIT_TOO_LOW_ERROR_KEY,
|
|
}
|
|
}
|
|
|
|
return {
|
|
valid: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|
const { balance, conversionRate, txData, unapprovedTxs } = stateProps
|
|
const {
|
|
cancelAllTransactions: dispatchCancelAllTransactions,
|
|
showCustomizeGasModal: dispatchShowCustomizeGasModal,
|
|
updateGasAndCalculate: dispatchUpdateGasAndCalculate,
|
|
...otherDispatchProps
|
|
} = dispatchProps
|
|
|
|
const validateEditGas = getValidateEditGas({ balance, conversionRate, txData })
|
|
|
|
return {
|
|
...stateProps,
|
|
...otherDispatchProps,
|
|
...ownProps,
|
|
showCustomizeGasModal: () => dispatchShowCustomizeGasModal({
|
|
txData,
|
|
onSubmit: customGas => dispatchUpdateGasAndCalculate(customGas),
|
|
validate: validateEditGas,
|
|
}),
|
|
cancelAllTransactions: () => dispatchCancelAllTransactions(valuesFor(unapprovedTxs)),
|
|
updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
|
|
const updatedTx = {
|
|
...txData,
|
|
txParams: {
|
|
...txData.txParams,
|
|
gas: gasLimit,
|
|
gasPrice,
|
|
},
|
|
}
|
|
dispatchUpdateGasAndCalculate(updatedTx)
|
|
},
|
|
}
|
|
}
|
|
|
|
export default compose(
|
|
withRouter,
|
|
connect(mapStateToProps, mapDispatchToProps, mergeProps)
|
|
)(ConfirmTransactionBase)
|