100 lines
3.2 KiB
TypeScript
100 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) => 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
|
|
};
|