MyCrypto/common/selectors/transaction/transaction.ts

103 lines
3.2 KiB
TypeScript

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);
if (!gasLimit.value) {
return Wei('0');
}
const cost = gasLimit.value.mul(gasPrice.value);
return cost;
};
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
};