diff --git a/common/actions/transaction/actionCreators/fields.ts b/common/actions/transaction/actionCreators/fields.ts index 6df955db..0660cc3e 100644 --- a/common/actions/transaction/actionCreators/fields.ts +++ b/common/actions/transaction/actionCreators/fields.ts @@ -20,7 +20,8 @@ import { SetScheduleTimezoneAction, SetScheduleGasPriceFieldAction, SetScheduleGasLimitFieldAction, - SetScheduleDepositFieldAction + SetScheduleDepositFieldAction, + SetScheduleParamsValidityAction } from '../actionTypes'; import { TypeKeys } from 'actions/transaction/constants'; @@ -162,6 +163,12 @@ const setScheduleDepositField = (payload: SetScheduleDepositFieldAction['payload payload }); +type TSetScheduleParamsValidity = typeof setScheduleParamsValidity; +const setScheduleParamsValidity = (payload: SetScheduleParamsValidityAction['payload']) => ({ + type: TypeKeys.SCHEDULE_PARAMS_VALIDITY_SET, + payload +}); + type TReset = typeof reset; const reset = (payload: ResetAction['payload'] = { include: {}, exclude: {} }): ResetAction => ({ type: TypeKeys.RESET, @@ -190,6 +197,7 @@ export { TSetScheduleGasPriceField, TSetScheduleGasLimitField, TSetScheduleDepositField, + TSetScheduleParamsValidity, TReset, inputGasLimit, inputGasPrice, @@ -212,5 +220,6 @@ export { setScheduleGasPriceField, setScheduleGasLimitField, setScheduleDepositField, + setScheduleParamsValidity, reset }; diff --git a/common/actions/transaction/actionTypes/fields.ts b/common/actions/transaction/actionTypes/fields.ts index c7de7d8c..cf2b0469 100644 --- a/common/actions/transaction/actionTypes/fields.ts +++ b/common/actions/transaction/actionTypes/fields.ts @@ -163,6 +163,14 @@ interface SetScheduleDepositFieldAction { }; } +interface SetScheduleParamsValidityAction { + type: TypeKeys.SCHEDULE_PARAMS_VALIDITY_SET; + payload: { + raw: boolean; + value: boolean; + }; +} + type InputFieldAction = InputNonceAction | InputGasLimitAction | InputDataAction; type FieldAction = @@ -181,7 +189,8 @@ type FieldAction = | SetScheduleGasPriceFieldAction | SetScheduleGasLimitFieldAction | SetScheduleDepositFieldAction - | SetScheduleTimezoneAction; + | SetScheduleTimezoneAction + | SetScheduleParamsValidityAction; export { InputGasLimitAction, @@ -208,5 +217,6 @@ export { SetScheduleGasPriceFieldAction, SetScheduleGasLimitFieldAction, SetScheduleDepositFieldAction, - SetScheduleTimezoneAction + SetScheduleTimezoneAction, + SetScheduleParamsValidityAction }; diff --git a/common/actions/transaction/constants.ts b/common/actions/transaction/constants.ts index 9480442b..f07ff6c0 100644 --- a/common/actions/transaction/constants.ts +++ b/common/actions/transaction/constants.ts @@ -57,6 +57,7 @@ export enum TypeKeys { SCHEDULE_TYPE_SET = 'SCHEDULE_TYPE_SET', SCHEDULING_TOGGLE_SET = 'SCHEDULING_TOGGLE_SET', SCHEDULE_DEPOSIT_FIELD_SET = 'SCHEDULE_DEPOSIT_FIELD_SET', + SCHEDULE_PARAMS_VALIDITY_SET = 'SCHEDULE_PARAMS_VALIDITY_SET', TOKEN_TO_META_SET = 'TOKEN_TO_META_SET', UNIT_META_SET = 'UNIT_META_SET', diff --git a/common/containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButton.tsx b/common/containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButton.tsx index 8291d74f..3fdf26d4 100644 --- a/common/containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButton.tsx +++ b/common/containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButton.tsx @@ -1,32 +1,48 @@ -import React from 'react'; +import React, { Component } from 'react'; import translate from 'translations'; import { ConfirmationModal } from 'components/ConfirmationModal'; import { SigningStatus } from 'components'; import { SendScheduleTransactionButtonFactory } from 'containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButtonFactory'; +import { connect } from 'react-redux'; +import { AppState } from 'reducers'; +import { getScheduleParamsValidity } from 'selectors/transaction'; -export const SendScheduleTransactionButton: React.SFC<{ +interface Props { className?: string; signing?: boolean; customModal?: typeof ConfirmationModal; -}> = ({ signing, customModal, className }) => ( - - ( - - - - )} - /> - - -); + paramsValidity: boolean; +} + +class SendScheduleTransactionButtonClass extends Component { + public render() { + const { className, customModal, paramsValidity, signing } = this.props; + + return ( + + ( + + + + )} + /> + + + ); + } +} + +export const SendScheduleTransactionButton = connect((state: AppState) => ({ + paramsValidity: getScheduleParamsValidity(state).value +}))(SendScheduleTransactionButtonClass); diff --git a/common/containers/Tabs/ScheduleTransaction/sagas/transaction/network/index.ts b/common/containers/Tabs/ScheduleTransaction/sagas/transaction/network/index.ts new file mode 100644 index 00000000..74378fb8 --- /dev/null +++ b/common/containers/Tabs/ScheduleTransaction/sagas/transaction/network/index.ts @@ -0,0 +1,3 @@ +import { schedulingParamsValidity } from './paramsValidity'; + +export const schedulingTransactionNetworkSagas = [schedulingParamsValidity]; diff --git a/common/containers/Tabs/ScheduleTransaction/sagas/transaction/network/paramsValidity.ts b/common/containers/Tabs/ScheduleTransaction/sagas/transaction/network/paramsValidity.ts new file mode 100644 index 00000000..e0db1d61 --- /dev/null +++ b/common/containers/Tabs/ScheduleTransaction/sagas/transaction/network/paramsValidity.ts @@ -0,0 +1,149 @@ +import { SagaIterator, delay } from 'redux-saga'; +import { select, fork, call, take, apply, put } from 'redux-saga/effects'; +import { getOffline, getNodeLib } from 'selectors/config'; +import { + ICurrentSchedulingToggle, + ICurrentWindowSize +} from 'containers/Tabs/ScheduleTransaction/selectors'; +import { + getSchedulingToggle, + getScheduleTimestamp, + getScheduleTimezone +} from '../../../selectors/fields'; +import { + TypeKeys, + SetScheduleParamsValidityAction, + setScheduleParamsValidity +} from 'actions/transaction'; +import { + getCurrentTo, + getCurrentValue, + getData, + getScheduleType, + getWindowStart, + getWindowSize, + getTimeBounty, + getScheduleGasPrice, + getScheduleGasLimit, + getScheduleDeposit +} from 'selectors/transaction'; +import { getWalletInst } from 'selectors/wallet'; +import { + EAC_SCHEDULING_CONFIG, + calcEACEndowment, + getValidateRequestParamsData, + EAC_ADDRESSES, + parseSchedulingParametersValidity +} from 'libs/scheduling'; +import { gasPriceToBase } from 'libs/units'; +import BN from 'bn.js'; +import { bufferToHex } from 'ethereumjs-util'; +import RequestFactory from 'libs/scheduling/contracts/RequestFactory'; +import { dateTimeToUnixTimestamp, windowSizeBlockToMin } from 'selectors/transaction/helpers'; + +export function* shouldValidateParams(): SagaIterator { + while (true) { + yield take([ + TypeKeys.TO_FIELD_SET, + TypeKeys.DATA_FIELD_SET, + TypeKeys.CURRENT_TIME_BOUNTY_SET, + TypeKeys.WINDOW_SIZE_FIELD_SET, + TypeKeys.WINDOW_START_FIELD_SET, + TypeKeys.SCHEDULE_TIMESTAMP_FIELD_SET, + TypeKeys.TIME_BOUNTY_FIELD_SET, + TypeKeys.SCHEDULE_TYPE_SET, + TypeKeys.SCHEDULING_TOGGLE_SET, + TypeKeys.SCHEDULE_TIMEZONE_SET + ]); + + yield call(delay, 250); + + const isOffline: boolean = yield select(getOffline); + const schedulingToggle: ICurrentSchedulingToggle = yield select(getSchedulingToggle); + const scheduling = Boolean(schedulingToggle && schedulingToggle.value); + + if (isOffline || !scheduling) { + continue; + } + + yield call(checkSchedulingParametersValidity); + } +} + +function* checkSchedulingParametersValidity() { + const currentTo = yield select(getCurrentTo); + const currentValue = yield select(getCurrentValue); + const callData = yield select(getData); + const scheduleType = yield select(getScheduleType); + const windowStart = yield select(getWindowStart); + const windowSize: ICurrentWindowSize = yield select(getWindowSize); + const timeBounty = yield select(getTimeBounty); + const scheduleGasPrice = yield select(getScheduleGasPrice); + const scheduleGasLimit = yield select(getScheduleGasLimit); + const deposit = yield select(getScheduleDeposit); + const node = yield select(getNodeLib); + const wallet = yield select(getWalletInst); + const scheduleTimestamp = yield select(getScheduleTimestamp); + const scheduleTimezone = yield select(getScheduleTimezone); + + if ( + !currentValue.value || + !currentTo.value || + !scheduleGasPrice.value || + !wallet || + !windowSize.value + ) { + return; + } + + const callGasLimit = scheduleGasLimit.value || EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK; + + const endowment = calcEACEndowment( + callGasLimit, + currentValue.value || new BN(0), + scheduleGasPrice.value || gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK), + timeBounty.value + ); + + const fromAddress = yield apply(wallet, wallet.getAddressString); + + const data = getValidateRequestParamsData( + bufferToHex(currentTo.value), + callData.value ? bufferToHex(callData.value) : '', + callGasLimit, + currentValue.value, + windowSizeBlockToMin(windowSize.value, scheduleType.value) || 0, + scheduleType.value === 'time' + ? dateTimeToUnixTimestamp(scheduleTimestamp, scheduleTimezone.value) + : windowStart.value, + scheduleGasPrice.value, + timeBounty.value, + deposit.value || new BN(0), + scheduleType.value === 'time', + endowment, + fromAddress + ); + + const callResult: string = yield apply(node, node.sendCallRequest, [ + { + to: EAC_ADDRESSES.KOVAN.requestFactory, + data + } + ]); + + const { paramsValidity } = RequestFactory.validateRequestParams.decodeOutput(callResult); + + const errors = parseSchedulingParametersValidity(paramsValidity); + const paramsValid = errors.length === 0; + + yield call(setField, { + raw: paramsValid, + value: paramsValid + }); +} + +export function* setField(payload: SetScheduleParamsValidityAction['payload']) { + yield put(setScheduleParamsValidity(payload)); +} + +export const schedulingParamsValidity = fork(shouldValidateParams); diff --git a/common/containers/Tabs/ScheduleTransaction/selectors/fields.ts b/common/containers/Tabs/ScheduleTransaction/selectors/fields.ts index 07a5d261..85da5024 100644 --- a/common/containers/Tabs/ScheduleTransaction/selectors/fields.ts +++ b/common/containers/Tabs/ScheduleTransaction/selectors/fields.ts @@ -11,6 +11,7 @@ const getSchedulingToggle = (state: AppState) => getFields(state).schedulingTogg const getScheduleGasLimit = (state: AppState) => getFields(state).scheduleGasLimit; const getScheduleGasPrice = (state: AppState) => getFields(state).scheduleGasPrice; const getScheduleDeposit = (state: AppState) => getFields(state).scheduleDeposit; +const getScheduleParamsValidity = (state: AppState) => getFields(state).scheduleParamsValidity; const schedulingFields = [ 'windowStart', @@ -20,7 +21,8 @@ const schedulingFields = [ 'schedulingToggle', 'scheduleDeposit', 'scheduleGasLimit', - 'scheduleGasPrice' + 'scheduleGasPrice', + 'scheduleParamsValidity' ]; export { @@ -34,5 +36,6 @@ export { getScheduleGasLimit, getScheduleGasPrice, getScheduleDeposit, - schedulingFields + schedulingFields, + getScheduleParamsValidity }; diff --git a/common/containers/Tabs/ScheduleTransaction/selectors/transaction.ts b/common/containers/Tabs/ScheduleTransaction/selectors/transaction.ts index 48c349b6..d1ab1a56 100644 --- a/common/containers/Tabs/ScheduleTransaction/selectors/transaction.ts +++ b/common/containers/Tabs/ScheduleTransaction/selectors/transaction.ts @@ -1,6 +1,5 @@ import { AppState } from 'reducers'; import { - IGetTransaction, getCurrentTo, getCurrentValue, getFields, @@ -21,7 +20,8 @@ import { isValidScheduleDeposit, getScheduleDeposit, getScheduleTimestamp, - getScheduleTimezone + getScheduleTimezone, + IGetTransaction } from 'selectors/transaction'; import { Address, gasPriceToBase } from 'libs/units'; import { @@ -43,7 +43,7 @@ import { import EthTx from 'ethereumjs-tx'; import { getLatestBlock } from 'selectors/config'; -const getSchedulingTransaction = (state: AppState): IGetTransaction => { +export const getSchedulingTransaction = (state: AppState): IGetTransaction => { const currentTo = getCurrentTo(state); const currentValue = getCurrentValue(state); const transactionFields = getFields(state); @@ -69,6 +69,13 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => { const depositValid = isValidScheduleDeposit(state); const deposit = getScheduleDeposit(state); + const endowment = calcEACEndowment( + scheduleGasLimit.value || EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK, + currentValue.value || new BN(0), + scheduleGasPrice.value || gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK), + timeBounty.value + ); + const isFullTransaction = isFullTx(state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit) && (windowStartValid || scheduleTimestampValid) && @@ -77,26 +84,23 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => { scheduleGasLimitValid && depositValid; - const transactionData = getScheduleData( - currentTo.raw, - callData.raw, - scheduleGasLimit.value, - currentValue.value, - windowSizeBlockToMin(windowSize.value, scheduleType.value), - scheduleType.value === 'time' - ? dateTimeToUnixTimestamp(scheduleTimestamp, scheduleTimezone.value) - : windowStart.value, - scheduleGasPrice.value, - timeBounty.value, - deposit.value - ); + let transactionData = null; - const endowment = calcEACEndowment( - scheduleGasLimit.value || EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK, - currentValue.value || new BN(0), - scheduleGasPrice.value || gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK), - timeBounty.value - ); + if (isFullTransaction) { + transactionData = getScheduleData( + currentTo.raw, + callData.raw, + scheduleGasLimit.value, + currentValue.value, + windowSizeBlockToMin(windowSize.value, scheduleType.value), + scheduleType.value === 'time' + ? dateTimeToUnixTimestamp(scheduleTimestamp, scheduleTimezone.value) + : windowStart.value, + scheduleGasPrice.value, + timeBounty.value, + deposit.value + ); + } const transactionOptions = { to: Address( @@ -122,5 +126,3 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => { isFullTransaction }; }; - -export { getSchedulingTransaction }; diff --git a/common/libs/contracts/ABIFunction.ts b/common/libs/contracts/ABIFunction.ts index cb27143c..2453368b 100644 --- a/common/libs/contracts/ABIFunction.ts +++ b/common/libs/contracts/ABIFunction.ts @@ -120,7 +120,7 @@ export default class AbiFunction { this.inputNames.map(name => { const type = this.funcParams[name].type; //TODO: parse args based on type - if (!suppliedArgs[name]) { + if (typeof suppliedArgs[name] === 'undefined') { throw Error( `Expected argument "${name}" of type "${type}" missing, suppliedArgs: ${JSON.stringify( suppliedArgs, diff --git a/common/libs/scheduling/contracts/RequestFactory.ts b/common/libs/scheduling/contracts/RequestFactory.ts new file mode 100644 index 00000000..8524afa7 --- /dev/null +++ b/common/libs/scheduling/contracts/RequestFactory.ts @@ -0,0 +1,58 @@ +import Contract from 'libs/contracts'; + +interface ABIFunc { + encodeInput(x: T): string; + decodeInput(argStr: string): T; + decodeOutput(argStr: string): K; +} + +type address = any; +type uint256 = any; +type bytes = any; + +interface IRequestFactory { + validateRequestParams: ABIFunc< + { _addressArgs: address[]; _uintArgs: uint256[]; _callData: bytes; _endowment: uint256 }, + { paramsValidity: boolean[] } + >; +} + +const requestFactoryAbi = [ + { + constant: true, + inputs: [ + { + name: '_addressArgs', + type: 'address[3]' + }, + { + name: '_uintArgs', + type: 'uint256[12]' + }, + { + name: '_callData', + type: 'bytes' + }, + { + name: '_endowment', + type: 'uint256' + } + ], + name: 'validateRequestParams', + outputs: [ + { + name: '', + type: 'bool[6]' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + } +]; + +const outputMappings = { + validateRequestParams: ['paramsValidity'] +}; + +export default (new Contract(requestFactoryAbi, outputMappings) as any) as IRequestFactory; diff --git a/common/libs/scheduling.ts b/common/libs/scheduling/index.ts similarity index 63% rename from common/libs/scheduling.ts rename to common/libs/scheduling/index.ts index aacc13af..4cab1f96 100644 --- a/common/libs/scheduling.ts +++ b/common/libs/scheduling/index.ts @@ -1,7 +1,8 @@ import BN from 'bn.js'; import abi from 'ethereumjs-abi'; -import { toWei, Units } from './units'; +import { toWei, Units } from '../units'; import { toBuffer } from 'ethereumjs-util'; +import RequestFactory from './contracts/RequestFactory'; const TIME_BOUNTY_MIN = new BN('1'); @@ -25,6 +26,7 @@ export const EAC_SCHEDULING_CONFIG = { export const EAC_ADDRESSES = { KOVAN: { blockScheduler: '0x1afc19a7e642761ba2b55d2a45b32c7ef08269d1', + requestFactory: '0x496e2b6089bde77293a994469b08e9f266d87adb', timestampScheduler: '0xc6370807f0164bdf10a66c08d0dab1028dbe80a3' } }; @@ -106,6 +108,67 @@ export const getScheduleData = ( ]); }; +export const parseSchedulingParametersValidity = (isValid: boolean[]) => { + const Errors = [ + 'InsufficientEndowment', + 'ReservedWindowBiggerThanExecutionWindow', + 'InvalidTemporalUnit', + 'ExecutionWindowTooSoon', + 'CallGasTooHigh', + 'EmptyToAddress' + ]; + const errors: string[] = []; + + isValid.forEach((boolIsTrue, index) => { + if (!boolIsTrue) { + errors.push(Errors[index]); + } + }); + + return errors; +}; + +export const getValidateRequestParamsData = ( + toAddress: string, + callData = '', + callGas: BN, + callValue: any, + windowSize: number, + windowStart: BN, + gasPrice: BN, + timeBounty: BN, + requiredDeposit: BN, + isTimestamp: boolean, + endowment: BN, + fromAddress: string +): string => { + const temporalUnit = isTimestamp ? 2 : 1; + const freezePeriod = isTimestamp ? 3 * 60 : 10; // 3 minutes or 10 blocks + const reservedWindowSize = isTimestamp ? 5 * 60 : 16; // 5 minutes or 16 blocks + const claimWindowSize = isTimestamp ? 60 * 60 : 255; // 60 minutes or 255 blocks + const feeRecipient = '0x0'; // stub + + return RequestFactory.validateRequestParams.encodeInput({ + _addressArgs: [fromAddress, feeRecipient, toAddress], + _uintArgs: [ + EAC_SCHEDULING_CONFIG.FEE, + timeBounty, + claimWindowSize, + freezePeriod, + reservedWindowSize, + temporalUnit, + windowSize, + windowStart, + callGas, + callValue, + gasPrice, + requiredDeposit + ], + _callData: callData, + _endowment: endowment + }); +}; + export const getTXDetailsCheckURL = (txHash: string) => { return `${EAC_SCHEDULING_CONFIG.DAPP_ADDRESS}/awaiting/scheduler/${txHash}`; }; diff --git a/common/reducers/transaction/fields/fields.ts b/common/reducers/transaction/fields/fields.ts index 8c9255b9..7ac9e408 100644 --- a/common/reducers/transaction/fields/fields.ts +++ b/common/reducers/transaction/fields/fields.ts @@ -44,7 +44,8 @@ const INITIAL_STATE: State = { raw: EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK.toString(), value: gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK) }, - scheduleDeposit: { raw: '', value: null } + scheduleDeposit: { raw: '', value: null }, + scheduleParamsValidity: { raw: true, value: true } }; const updateField = (key: keyof State): Reducer => (state: State, action: FieldAction) => ({ @@ -114,6 +115,8 @@ export const fields = ( return updateField('scheduleGasPrice')(state, action); case TK.SCHEDULE_DEPOSIT_FIELD_SET: return updateField('scheduleDeposit')(state, action); + case TK.SCHEDULE_PARAMS_VALIDITY_SET: + return updateField('scheduleParamsValidity')(state, action); case TK.TOKEN_TO_ETHER_SWAP: return tokenToEther(state, action); case TK.ETHER_TO_TOKEN_SWAP: diff --git a/common/reducers/transaction/fields/typings.ts b/common/reducers/transaction/fields/typings.ts index 6d338bc6..8447d986 100644 --- a/common/reducers/transaction/fields/typings.ts +++ b/common/reducers/transaction/fields/typings.ts @@ -11,7 +11,8 @@ import { SetScheduleGasPriceFieldAction, SetScheduleGasLimitFieldAction, SetScheduleDepositFieldAction, - SetScheduleTimezoneAction + SetScheduleTimezoneAction, + SetScheduleParamsValidityAction } from 'actions/transaction'; import { Wei } from 'libs/units'; @@ -32,4 +33,5 @@ export interface State { scheduleGasLimit: SetScheduleGasLimitFieldAction['payload']; scheduleGasPrice: SetScheduleGasPriceFieldAction['payload']; scheduleDeposit: SetScheduleDepositFieldAction['payload']; + scheduleParamsValidity: SetScheduleParamsValidityAction['payload']; } diff --git a/common/sagas/transaction/network/index.ts b/common/sagas/transaction/network/index.ts index 9d6168d5..668ddeac 100644 --- a/common/sagas/transaction/network/index.ts +++ b/common/sagas/transaction/network/index.ts @@ -1,4 +1,6 @@ import { from } from './from'; import { gas } from './gas'; import { nonce } from './nonce'; -export const network = [from, ...gas, nonce]; +import { schedulingTransactionNetworkSagas } from '../../../containers/Tabs/ScheduleTransaction/sagas/transaction/network'; + +export const network = [from, ...gas, nonce, ...schedulingTransactionNetworkSagas]; diff --git a/spec/reducers/transaction/fields/fields.spec.ts b/spec/reducers/transaction/fields/fields.spec.ts index bb20c77c..9bb3163b 100644 --- a/spec/reducers/transaction/fields/fields.spec.ts +++ b/spec/reducers/transaction/fields/fields.spec.ts @@ -33,7 +33,8 @@ describe('fields reducer', () => { value: gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK) }, scheduleGasLimit: { raw: '21000', value: new BN(21000) }, - scheduleDeposit: { raw: '', value: null } + scheduleDeposit: { raw: '', value: null }, + scheduleParamsValidity: { raw: true, value: true } }; const testPayload = { raw: 'test', value: null }; diff --git a/spec/selectors/transaction/fields.spec.ts b/spec/selectors/transaction/fields.spec.ts index d3e04d23..b1686c08 100644 --- a/spec/selectors/transaction/fields.spec.ts +++ b/spec/selectors/transaction/fields.spec.ts @@ -81,6 +81,10 @@ describe('fields selector', () => { scheduleDeposit: { raw: '1000000000', value: Wei('1000000000') + }, + scheduleParamsValidity: { + raw: false, + value: false } }; diff --git a/spec/selectors/transaction/helpers.spec.ts b/spec/selectors/transaction/helpers.spec.ts index e9f26d4f..0bf0b3ba 100644 --- a/spec/selectors/transaction/helpers.spec.ts +++ b/spec/selectors/transaction/helpers.spec.ts @@ -85,6 +85,10 @@ describe('helpers selector', () => { scheduleDeposit: { raw: '1000000000', value: Wei('1000000000') + }, + scheduleParamsValidity: { + raw: false, + value: false } } }; @@ -106,7 +110,8 @@ describe('helpers selector', () => { scheduleTimezone: moment.tz.guess(), scheduleGasPrice: Wei('1500'), scheduleGasLimit: Wei('21000'), - scheduleDeposit: Wei('1000000000') + scheduleDeposit: Wei('1000000000'), + scheduleParamsValidity: false }; expect(reduceToValues(state.transaction.fields)).toEqual(values); });