1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-30 16:18:07 +01:00
metamask-extension/ui/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
2021-09-09 10:14:07 -05:00

330 lines
9.8 KiB
JavaScript

import { connect } from 'react-redux';
import { addHexPrefix } from '../../../../../app/scripts/lib/util';
import {
hideModal,
createRetryTransaction,
createSpeedUpTransaction,
} from '../../../../store/actions';
import {
setCustomGasPrice,
setCustomGasLimit,
resetCustomData,
} from '../../../../ducks/gas/gas.duck';
import {
getSendMaxModeState,
getGasLimit,
getGasPrice,
getSendAmount,
updateGasLimit,
updateGasPrice,
useCustomGas,
getSendAsset,
ASSET_TYPES,
} from '../../../../ducks/send';
import {
conversionRateSelector as getConversionRate,
getCurrentCurrency,
getCurrentEthBalance,
getIsMainnet,
getIsTestnet,
getBasicGasEstimateLoadingStatus,
getCustomGasLimit,
getCustomGasPrice,
getDefaultActiveButtonIndex,
getRenderableBasicEstimateData,
isCustomPriceSafe,
isCustomPriceSafeForCustomNetwork,
getAveragePriceEstimateInHexWEI,
isCustomPriceExcessive,
getIsGasEstimatesFetched,
getShouldShowFiat,
getIsCustomNetworkGasPriceFetched,
} from '../../../../selectors';
import {
addHexes,
subtractHexWEIsToDec,
hexWEIToDecGWEI,
getValueFromWeiHex,
sumHexWEIsToRenderableFiat,
} from '../../../../helpers/utils/conversions.util';
import { formatETHFee } from '../../../../helpers/utils/formatters';
import {
calcGasTotal,
isBalanceSufficient,
} from '../../../../pages/send/send.utils';
import { MIN_GAS_LIMIT_DEC } from '../../../../pages/send/send.constants';
import { TRANSACTION_STATUSES } from '../../../../../shared/constants/transaction';
import { GAS_LIMITS } from '../../../../../shared/constants/gas';
import { updateTransactionGasFees } from '../../../../ducks/metamask/metamask';
import GasModalPageContainer from './gas-modal-page-container.component';
const mapStateToProps = (state, ownProps) => {
const gasLimit = getGasLimit(state);
const gasPrice = getGasPrice(state);
const amount = getSendAmount(state);
const { currentNetworkTxList } = state.metamask;
const { modalState: { props: modalProps } = {} } = state.appState.modal || {};
const { txData = {} } = modalProps || {};
const { transaction = {}, onSubmit } = ownProps;
const selectedTransaction = currentNetworkTxList.find(
({ id }) => id === (transaction.id || txData.id),
);
const buttonDataLoading = getBasicGasEstimateLoadingStatus(state);
const asset = getSendAsset(state);
// a "default" txParams is used during the send flow, since the transaction doesn't exist yet in that case
const txParams = selectedTransaction?.txParams
? selectedTransaction.txParams
: {
gas: gasLimit || GAS_LIMITS.SIMPLE,
gasPrice: gasPrice || getAveragePriceEstimateInHexWEI(state, true),
value: asset.type === ASSET_TYPES.TOKEN ? '0x0' : amount,
};
const { gasPrice: currentGasPrice, gas: currentGasLimit } = txParams;
const value = ownProps.transaction?.txParams?.value || txParams.value;
const customModalGasPriceInHex = getCustomGasPrice(state) || currentGasPrice;
const customModalGasLimitInHex =
getCustomGasLimit(state) || currentGasLimit || GAS_LIMITS.SIMPLE;
const customGasTotal = calcGasTotal(
customModalGasLimitInHex,
customModalGasPriceInHex,
);
const gasButtonInfo = getRenderableBasicEstimateData(
state,
customModalGasLimitInHex,
);
const currentCurrency = getCurrentCurrency(state);
const conversionRate = getConversionRate(state);
const newTotalFiat = sumHexWEIsToRenderableFiat(
[value, customGasTotal],
currentCurrency,
conversionRate,
);
const { hideBasic } = state.appState.modal.modalState.props;
const customGasPrice = calcCustomGasPrice(customModalGasPriceInHex);
const maxModeOn = getSendMaxModeState(state);
const balance = getCurrentEthBalance(state);
const isMainnet = getIsMainnet(state);
const isTestnet = getIsTestnet(state);
const showFiat = getShouldShowFiat(state);
const newTotalEth =
maxModeOn && asset.type === ASSET_TYPES.NATIVE
? sumHexWEIsToRenderableEth([balance, '0x0'])
: sumHexWEIsToRenderableEth([value, customGasTotal]);
const sendAmount =
maxModeOn && asset.type === ASSET_TYPES.NATIVE
? subtractHexWEIsFromRenderableEth(balance, customGasTotal)
: sumHexWEIsToRenderableEth([value, '0x0']);
const insufficientBalance = maxModeOn
? false
: !isBalanceSufficient({
amount: value,
gasTotal: customGasTotal,
balance,
conversionRate,
});
const isGasEstimate = getIsGasEstimatesFetched(state);
const customNetworkEstimateWasFetched = getIsCustomNetworkGasPriceFetched(
state,
);
let customPriceIsSafe = true;
if ((isMainnet || process.env.IN_TEST) && isGasEstimate) {
customPriceIsSafe = isCustomPriceSafe(state);
} else if (
!(isMainnet || process.env.IN_TEST || isTestnet) &&
customNetworkEstimateWasFetched
) {
customPriceIsSafe = isCustomPriceSafeForCustomNetwork(state);
}
return {
hideBasic,
isConfirm: isConfirm(state),
customModalGasPriceInHex,
customModalGasLimitInHex,
customGasPrice,
customGasLimit: calcCustomGasLimit(customModalGasLimitInHex),
customGasTotal,
newTotalFiat,
customPriceIsSafe,
customPriceIsExcessive: isCustomPriceExcessive(state),
maxModeOn,
gasPriceButtonGroupProps: {
buttonDataLoading,
defaultActiveButtonIndex: getDefaultActiveButtonIndex(
gasButtonInfo,
customModalGasPriceInHex,
),
gasButtonInfo,
},
infoRowProps: {
originalTotalFiat: sumHexWEIsToRenderableFiat(
[value, customGasTotal],
currentCurrency,
conversionRate,
),
originalTotalEth: sumHexWEIsToRenderableEth([value, customGasTotal]),
newTotalFiat: showFiat ? newTotalFiat : '',
newTotalEth,
transactionFee: sumHexWEIsToRenderableEth(['0x0', customGasTotal]),
sendAmount,
},
transaction: txData || transaction,
isSpeedUp: transaction.status === TRANSACTION_STATUSES.SUBMITTED,
isRetry: transaction.status === TRANSACTION_STATUSES.FAILED,
txId: transaction.id,
insufficientBalance,
isMainnet,
balance,
conversionRate,
value,
onSubmit,
};
};
const mapDispatchToProps = (dispatch) => {
const updateCustomGasPrice = (newPrice) =>
dispatch(setCustomGasPrice(addHexPrefix(newPrice)));
return {
cancelAndClose: () => {
dispatch(resetCustomData());
dispatch(hideModal());
},
hideModal: () => dispatch(hideModal()),
useCustomGas: () => dispatch(useCustomGas()),
updateTransactionGasFees: (gasFees) => {
dispatch(updateTransactionGasFees({ ...gasFees, expectHexWei: true }));
},
updateCustomGasPrice,
updateCustomGasLimit: (newLimit) =>
dispatch(setCustomGasLimit(addHexPrefix(newLimit))),
setGasData: (newLimit, newPrice) => {
dispatch(updateGasLimit(newLimit));
dispatch(updateGasPrice(newPrice));
},
createRetryTransaction: (txId, customGasSettings) => {
return dispatch(createRetryTransaction(txId, customGasSettings));
},
createSpeedUpTransaction: (txId, customGasSettings) => {
return dispatch(createSpeedUpTransaction(txId, customGasSettings));
},
};
};
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const {
gasPriceButtonGroupProps,
// eslint-disable-next-line no-shadow
isConfirm,
txId,
isSpeedUp,
isRetry,
insufficientBalance,
customGasPrice,
customGasLimit,
transaction,
} = stateProps;
const {
useCustomGas: dispatchUseCustomGas,
setGasData: dispatchSetGasData,
createSpeedUpTransaction: dispatchCreateSpeedUpTransaction,
createRetryTransaction: dispatchCreateRetryTransaction,
updateTransactionGasFees: dispatchUpdateTransactionGasFees,
cancelAndClose: dispatchCancelAndClose,
hideModal: dispatchHideModal,
...otherDispatchProps
} = dispatchProps;
return {
...stateProps,
...otherDispatchProps,
...ownProps,
onSubmit: (gasLimit, gasPrice) => {
if (ownProps.onSubmit) {
dispatchCancelAndClose();
ownProps.onSubmit({ gasLimit, gasPrice });
return;
}
if (isConfirm) {
dispatchUpdateTransactionGasFees({
gasLimit,
gasPrice,
transaction,
isModal: true,
});
dispatchHideModal();
dispatchCancelAndClose();
} else if (isSpeedUp) {
dispatchCreateSpeedUpTransaction(txId, { gasPrice, gasLimit });
dispatchCancelAndClose();
} else if (isRetry) {
dispatchCreateRetryTransaction(txId, { gasPrice, gasLimit });
dispatchCancelAndClose();
} else {
dispatchSetGasData(gasLimit, gasPrice);
dispatchUseCustomGas();
dispatchCancelAndClose();
}
},
gasPriceButtonGroupProps: {
...gasPriceButtonGroupProps,
handleGasPriceSelection: ({ gasPrice }) =>
otherDispatchProps.updateCustomGasPrice(gasPrice),
},
cancelAndClose: () => {
dispatchCancelAndClose();
},
disableSave:
insufficientBalance ||
(isSpeedUp && customGasPrice === 0) ||
customGasLimit < Number(MIN_GAS_LIMIT_DEC),
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
)(GasModalPageContainer);
function isConfirm(state) {
return Boolean(Object.keys(state.confirmTransaction.txData).length);
}
function calcCustomGasPrice(customGasPriceInHex) {
return Number(hexWEIToDecGWEI(customGasPriceInHex));
}
function calcCustomGasLimit(customGasLimitInHex) {
return parseInt(customGasLimitInHex, 16);
}
function sumHexWEIsToRenderableEth(hexWEIs) {
const hexWEIsSum = hexWEIs.filter(Boolean).reduce(addHexes);
return formatETHFee(
getValueFromWeiHex({
value: hexWEIsSum,
toCurrency: 'ETH',
numberOfDecimals: 6,
}),
);
}
function subtractHexWEIsFromRenderableEth(aHexWEI, bHexWEI) {
return formatETHFee(subtractHexWEIsToDec(aHexWEI, bHexWEI));
}