import { AppState } from 'reducers'; import { getCurrentTo, getCurrentValue } from './current'; import { getFields } from './fields'; import { makeTransaction, IHexStrTransaction } from 'libs/transaction'; import EthTx from 'ethereumjs-tx'; import { getUnit } from 'selectors/transaction/meta'; import { reduceToValues, isFullTx } from 'selectors/transaction/helpers'; import { getGasPrice, getGasLimit, getDataExists, getSerializedTransaction, getValidGasCost, isEtherTransaction } from 'selectors/transaction'; import { Wei } from 'libs/units'; import { getTransactionFields } from 'libs/transaction/utils/ether'; import { getNetworkConfig } from 'selectors/config'; const getTransactionState = (state: AppState) => state.transaction; export interface IGetTransaction { transaction: EthTx; isFullTransaction: boolean; //if the user has filled all the fields } const getTransaction = (state: AppState): IGetTransaction => { const currentTo = getCurrentTo(state); const currentValue = getCurrentValue(state); const transactionFields = getFields(state); const unit = getUnit(state); const reducedValues = reduceToValues(transactionFields); const transaction: EthTx = makeTransaction(reducedValues); const dataExists = getDataExists(state); const validGasCost = getValidGasCost(state); const isFullTransaction = isFullTx( state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit ); return { transaction, isFullTransaction }; }; const nonStandardTransaction = (state: AppState): boolean => { const etherTransaction = isEtherTransaction(state); const { isFullTransaction } = getTransaction(state); const dataExists = getDataExists(state); return isFullTransaction && dataExists && etherTransaction; }; const getGasCost = (state: AppState) => { const gasPrice = getGasPrice(state); const gasLimit = getGasLimit(state); return gasLimit.value ? gasPrice.value.mul(gasLimit.value) : Wei('0'); }; const serializedAndTransactionFieldsMatch = (state: AppState, isLocallySigned: boolean) => { const serialzedTransaction = getSerializedTransaction(state); const { transaction, isFullTransaction } = getTransaction(state); if (!isFullTransaction || !serialzedTransaction) { return false; } const t1 = getTransactionFields(transaction); // inject chainId into t1 as it wont have it from the fields const networkConfig = getNetworkConfig(state); if (!networkConfig) { return false; } const { chainId } = networkConfig; t1.chainId = chainId; const t2 = getTransactionFields(makeTransaction(serialzedTransaction)); const checkValidity = (tx: IHexStrTransaction) => Object.keys(tx).reduce( (match, currField: keyof IHexStrTransaction) => match && t1[currField] === t2[currField], true ); //reduce both ways to make sure both are exact same const transactionsMatch = checkValidity(t1) && checkValidity(t2); // if its signed then verify the signature too return transactionsMatch && isLocallySigned ? makeTransaction(serialzedTransaction).verifySignature() : true; }; export { getTransaction, getTransactionState, getGasCost, nonStandardTransaction, serializedAndTransactionFieldsMatch };