A Metamask fork with Infura removed and default networks editable
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
ciphermask/ui/pages/confirm-transaction-base/confirm-transaction-base.co...

335 lines
9.3 KiB

import { connect } from 'react-redux';
import { compose } from 'redux';
import { withRouter } from 'react-router-dom';
import contractMap from '@metamask/contract-metadata';
import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck';
import {
updateCustomNonce,
cancelTx,
cancelTxs,
updateAndApproveTx,
showModal,
setMetaMetricsSendCount,
updateTransaction,
getNextNonce,
tryReverseResolveAddress,
setDefaultHomeActiveTabName,
} 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 { shortenAddress, valuesFor } from '../../helpers/utils/util';
import {
getAdvancedInlineGasShown,
getCustomNonceValue,
getIsMainnet,
getKnownMethodData,
getMetaMaskAccounts,
getUseNonceField,
getPreferences,
transactionFeeSelector,
getNoGasPriceFetched,
getIsEthGasPriceFetched,
} from '../../selectors';
import { getMostRecentOverviewPage } from '../../ducks/history/history';
import { transactionMatchesNetwork } from '../../../shared/modules/transaction.utils';
import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
import ConfirmTransactionBase from './confirm-transaction-base.component';
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,
customTxParamsData,
match: { params = {} },
} = ownProps;
const { id: paramsTransactionId } = params;
const { showFiatInTestnets } = getPreferences(state);
const isMainnet = getIsMainnet(state);
const { confirmTransaction, metamask } = state;
const {
ensResolutionsByAddress,
conversionRate,
identities,
addressBook,
assetImages,
network,
unapprovedTxs,
metaMetricsSendCount,
nextNonce,
provider: { chainId },
} = metamask;
const { tokenData, txData, tokenProps, nonce } = confirmTransaction;
const { txParams = {}, lastGasPrice, id: transactionId, type } = txData;
const transaction =
Object.values(unapprovedTxs).find(
({ id }) => id === (transactionId || Number(paramsTransactionId)),
) || {};
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[fromAddress];
const { name: fromName } = identities[fromAddress];
const toAddress = propsToAddress || txParamsToAddress;
const toName =
identities[toAddress]?.name ||
casedContractMap[toAddress]?.name ||
shortenAddress(toChecksumHexAddress(toAddress));
const checksummedAddress = toChecksumHexAddress(toAddress);
const addressBookObject = addressBook[checksummedAddress];
const toEns = ensResolutionsByAddress[checksummedAddress] || '';
const toNickname = addressBookObject ? addressBookObject.name : '';
const isTxReprice = Boolean(lastGasPrice);
const transactionStatus = transaction ? transaction.status : '';
const {
hexTransactionAmount,
hexTransactionFee,
hexTransactionTotal,
} = transactionFeeSelector(state, transaction);
if (transaction && transaction.simulationFails) {
txData.simulationFails = transaction.simulationFails;
}
const currentNetworkUnapprovedTxs = Object.keys(unapprovedTxs)
.filter((key) =>
transactionMatchesNetwork(unapprovedTxs[key], chainId, network),
)
.reduce((acc, key) => ({ ...acc, [key]: unapprovedTxs[key] }), {});
const unapprovedTxCount = valuesFor(currentNetworkUnapprovedTxs).length;
const insufficientBalance = !isBalanceSufficient({
amount,
gasTotal: calcGasTotal(gasLimit, gasPrice),
balance,
conversionRate,
});
const methodData = getKnownMethodData(state, data) || {};
let fullTxData = { ...txData, ...transaction };
if (customTxParamsData) {
fullTxData = {
...fullTxData,
txParams: {
...fullTxData.txParams,
data: customTxParamsData,
},
};
}
customNonceValue = getCustomNonceValue(state);
const isEthGasPrice = getIsEthGasPriceFetched(state);
const noGasPrice = getNoGasPriceFetched(state);
return {
balance,
fromAddress,
fromName,
toAddress,
toEns,
toName,
toNickname,
hexTransactionAmount,
hexTransactionFee,
hexTransactionTotal,
txData: fullTxData,
tokenData,
methodData,
tokenProps,
isTxReprice,
conversionRate,
transactionStatus,
nonce,
assetImage,
unapprovedTxs,
unapprovedTxCount,
currentNetworkUnapprovedTxs,
customGas: {
gasLimit,
gasPrice,
},
advancedInlineGasShown: getAdvancedInlineGasShown(state),
useNonceField: getUseNonceField(state),
customNonceValue,
insufficientBalance,
hideSubtitle: !isMainnet && !showFiatInTestnets,
hideFiatConversion: !isMainnet && !showFiatInTestnets,
metaMetricsSendCount,
type,
nextNonce,
mostRecentOverviewPage: getMostRecentOverviewPage(state),
isMainnet,
isEthGasPrice,
noGasPrice,
};
};
export const mapDispatchToProps = (dispatch) => {
return {
tryReverseResolveAddress: (address) => {
return dispatch(tryReverseResolveAddress(address));
},
updateCustomNonce: (value) => {
customNonceValue = value;
dispatch(updateCustomNonce(value));
},
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
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()),
setDefaultHomeActiveTabName: (tabName) =>
dispatch(setDefaultHomeActiveTabName(tabName)),
};
};
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);