mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-03 23:03:40 +00:00
[FEATURE] Call contract to validate scheduling params
This commit is contained in:
parent
1630e9fee9
commit
2cf2cc5b26
@ -20,7 +20,8 @@ import {
|
|||||||
SetScheduleTimezoneAction,
|
SetScheduleTimezoneAction,
|
||||||
SetScheduleGasPriceFieldAction,
|
SetScheduleGasPriceFieldAction,
|
||||||
SetScheduleGasLimitFieldAction,
|
SetScheduleGasLimitFieldAction,
|
||||||
SetScheduleDepositFieldAction
|
SetScheduleDepositFieldAction,
|
||||||
|
SetScheduleParamsValidityAction
|
||||||
} from '../actionTypes';
|
} from '../actionTypes';
|
||||||
import { TypeKeys } from 'actions/transaction/constants';
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
|
|
||||||
@ -162,6 +163,12 @@ const setScheduleDepositField = (payload: SetScheduleDepositFieldAction['payload
|
|||||||
payload
|
payload
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type TSetScheduleParamsValidity = typeof setScheduleParamsValidity;
|
||||||
|
const setScheduleParamsValidity = (payload: SetScheduleParamsValidityAction['payload']) => ({
|
||||||
|
type: TypeKeys.SCHEDULE_PARAMS_VALIDITY_SET,
|
||||||
|
payload
|
||||||
|
});
|
||||||
|
|
||||||
type TReset = typeof reset;
|
type TReset = typeof reset;
|
||||||
const reset = (payload: ResetAction['payload'] = { include: {}, exclude: {} }): ResetAction => ({
|
const reset = (payload: ResetAction['payload'] = { include: {}, exclude: {} }): ResetAction => ({
|
||||||
type: TypeKeys.RESET,
|
type: TypeKeys.RESET,
|
||||||
@ -190,6 +197,7 @@ export {
|
|||||||
TSetScheduleGasPriceField,
|
TSetScheduleGasPriceField,
|
||||||
TSetScheduleGasLimitField,
|
TSetScheduleGasLimitField,
|
||||||
TSetScheduleDepositField,
|
TSetScheduleDepositField,
|
||||||
|
TSetScheduleParamsValidity,
|
||||||
TReset,
|
TReset,
|
||||||
inputGasLimit,
|
inputGasLimit,
|
||||||
inputGasPrice,
|
inputGasPrice,
|
||||||
@ -212,5 +220,6 @@ export {
|
|||||||
setScheduleGasPriceField,
|
setScheduleGasPriceField,
|
||||||
setScheduleGasLimitField,
|
setScheduleGasLimitField,
|
||||||
setScheduleDepositField,
|
setScheduleDepositField,
|
||||||
|
setScheduleParamsValidity,
|
||||||
reset
|
reset
|
||||||
};
|
};
|
||||||
|
@ -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 InputFieldAction = InputNonceAction | InputGasLimitAction | InputDataAction;
|
||||||
|
|
||||||
type FieldAction =
|
type FieldAction =
|
||||||
@ -181,7 +189,8 @@ type FieldAction =
|
|||||||
| SetScheduleGasPriceFieldAction
|
| SetScheduleGasPriceFieldAction
|
||||||
| SetScheduleGasLimitFieldAction
|
| SetScheduleGasLimitFieldAction
|
||||||
| SetScheduleDepositFieldAction
|
| SetScheduleDepositFieldAction
|
||||||
| SetScheduleTimezoneAction;
|
| SetScheduleTimezoneAction
|
||||||
|
| SetScheduleParamsValidityAction;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
InputGasLimitAction,
|
InputGasLimitAction,
|
||||||
@ -208,5 +217,6 @@ export {
|
|||||||
SetScheduleGasPriceFieldAction,
|
SetScheduleGasPriceFieldAction,
|
||||||
SetScheduleGasLimitFieldAction,
|
SetScheduleGasLimitFieldAction,
|
||||||
SetScheduleDepositFieldAction,
|
SetScheduleDepositFieldAction,
|
||||||
SetScheduleTimezoneAction
|
SetScheduleTimezoneAction,
|
||||||
|
SetScheduleParamsValidityAction
|
||||||
};
|
};
|
||||||
|
@ -57,6 +57,7 @@ export enum TypeKeys {
|
|||||||
SCHEDULE_TYPE_SET = 'SCHEDULE_TYPE_SET',
|
SCHEDULE_TYPE_SET = 'SCHEDULE_TYPE_SET',
|
||||||
SCHEDULING_TOGGLE_SET = 'SCHEDULING_TOGGLE_SET',
|
SCHEDULING_TOGGLE_SET = 'SCHEDULING_TOGGLE_SET',
|
||||||
SCHEDULE_DEPOSIT_FIELD_SET = 'SCHEDULE_DEPOSIT_FIELD_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',
|
TOKEN_TO_META_SET = 'TOKEN_TO_META_SET',
|
||||||
UNIT_META_SET = 'UNIT_META_SET',
|
UNIT_META_SET = 'UNIT_META_SET',
|
||||||
|
@ -1,32 +1,48 @@
|
|||||||
import React from 'react';
|
import React, { Component } from 'react';
|
||||||
import translate from 'translations';
|
import translate from 'translations';
|
||||||
import { ConfirmationModal } from 'components/ConfirmationModal';
|
import { ConfirmationModal } from 'components/ConfirmationModal';
|
||||||
import { SigningStatus } from 'components';
|
import { SigningStatus } from 'components';
|
||||||
import { SendScheduleTransactionButtonFactory } from 'containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButtonFactory';
|
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;
|
className?: string;
|
||||||
signing?: boolean;
|
signing?: boolean;
|
||||||
customModal?: typeof ConfirmationModal;
|
customModal?: typeof ConfirmationModal;
|
||||||
}> = ({ signing, customModal, className }) => (
|
paramsValidity: boolean;
|
||||||
<React.Fragment>
|
}
|
||||||
<SendScheduleTransactionButtonFactory
|
|
||||||
signing={signing}
|
class SendScheduleTransactionButtonClass extends Component<Props> {
|
||||||
Modal={customModal ? customModal : ConfirmationModal}
|
public render() {
|
||||||
withProps={({ disabled, openModal, signTx }) => (
|
const { className, customModal, paramsValidity, signing } = this.props;
|
||||||
<React.Fragment>
|
|
||||||
<button
|
return (
|
||||||
disabled={disabled}
|
<React.Fragment>
|
||||||
className={`SendButton btn btn-primary btn-block ${className}`}
|
<SendScheduleTransactionButtonFactory
|
||||||
onClick={() => {
|
signing={signing}
|
||||||
!!signing ? (signTx(), openModal()) : openModal();
|
Modal={customModal ? customModal : ConfirmationModal}
|
||||||
}}
|
withProps={({ disabled, openModal, signTx }) => (
|
||||||
>
|
<React.Fragment>
|
||||||
{translate('SCHEDULE_SCHEDULE')}
|
<button
|
||||||
</button>
|
disabled={disabled || !paramsValidity}
|
||||||
</React.Fragment>
|
className={`SendButton btn btn-primary btn-block ${className}`}
|
||||||
)}
|
onClick={() => {
|
||||||
/>
|
!!signing ? (signTx(), openModal()) : openModal();
|
||||||
<SigningStatus />
|
}}
|
||||||
</React.Fragment>
|
>
|
||||||
);
|
{translate('SCHEDULE_SCHEDULE')}
|
||||||
|
</button>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<SigningStatus />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SendScheduleTransactionButton = connect((state: AppState) => ({
|
||||||
|
paramsValidity: getScheduleParamsValidity(state).value
|
||||||
|
}))(SendScheduleTransactionButtonClass);
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
import { schedulingParamsValidity } from './paramsValidity';
|
||||||
|
|
||||||
|
export const schedulingTransactionNetworkSagas = [schedulingParamsValidity];
|
@ -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);
|
@ -11,6 +11,7 @@ const getSchedulingToggle = (state: AppState) => getFields(state).schedulingTogg
|
|||||||
const getScheduleGasLimit = (state: AppState) => getFields(state).scheduleGasLimit;
|
const getScheduleGasLimit = (state: AppState) => getFields(state).scheduleGasLimit;
|
||||||
const getScheduleGasPrice = (state: AppState) => getFields(state).scheduleGasPrice;
|
const getScheduleGasPrice = (state: AppState) => getFields(state).scheduleGasPrice;
|
||||||
const getScheduleDeposit = (state: AppState) => getFields(state).scheduleDeposit;
|
const getScheduleDeposit = (state: AppState) => getFields(state).scheduleDeposit;
|
||||||
|
const getScheduleParamsValidity = (state: AppState) => getFields(state).scheduleParamsValidity;
|
||||||
|
|
||||||
const schedulingFields = [
|
const schedulingFields = [
|
||||||
'windowStart',
|
'windowStart',
|
||||||
@ -20,7 +21,8 @@ const schedulingFields = [
|
|||||||
'schedulingToggle',
|
'schedulingToggle',
|
||||||
'scheduleDeposit',
|
'scheduleDeposit',
|
||||||
'scheduleGasLimit',
|
'scheduleGasLimit',
|
||||||
'scheduleGasPrice'
|
'scheduleGasPrice',
|
||||||
|
'scheduleParamsValidity'
|
||||||
];
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -34,5 +36,6 @@ export {
|
|||||||
getScheduleGasLimit,
|
getScheduleGasLimit,
|
||||||
getScheduleGasPrice,
|
getScheduleGasPrice,
|
||||||
getScheduleDeposit,
|
getScheduleDeposit,
|
||||||
schedulingFields
|
schedulingFields,
|
||||||
|
getScheduleParamsValidity
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import {
|
import {
|
||||||
IGetTransaction,
|
|
||||||
getCurrentTo,
|
getCurrentTo,
|
||||||
getCurrentValue,
|
getCurrentValue,
|
||||||
getFields,
|
getFields,
|
||||||
@ -21,7 +20,8 @@ import {
|
|||||||
isValidScheduleDeposit,
|
isValidScheduleDeposit,
|
||||||
getScheduleDeposit,
|
getScheduleDeposit,
|
||||||
getScheduleTimestamp,
|
getScheduleTimestamp,
|
||||||
getScheduleTimezone
|
getScheduleTimezone,
|
||||||
|
IGetTransaction
|
||||||
} from 'selectors/transaction';
|
} from 'selectors/transaction';
|
||||||
import { Address, gasPriceToBase } from 'libs/units';
|
import { Address, gasPriceToBase } from 'libs/units';
|
||||||
import {
|
import {
|
||||||
@ -43,7 +43,7 @@ import {
|
|||||||
import EthTx from 'ethereumjs-tx';
|
import EthTx from 'ethereumjs-tx';
|
||||||
import { getLatestBlock } from 'selectors/config';
|
import { getLatestBlock } from 'selectors/config';
|
||||||
|
|
||||||
const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
export const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
||||||
const currentTo = getCurrentTo(state);
|
const currentTo = getCurrentTo(state);
|
||||||
const currentValue = getCurrentValue(state);
|
const currentValue = getCurrentValue(state);
|
||||||
const transactionFields = getFields(state);
|
const transactionFields = getFields(state);
|
||||||
@ -69,6 +69,13 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
|||||||
const depositValid = isValidScheduleDeposit(state);
|
const depositValid = isValidScheduleDeposit(state);
|
||||||
const deposit = getScheduleDeposit(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 =
|
const isFullTransaction =
|
||||||
isFullTx(state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit) &&
|
isFullTx(state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit) &&
|
||||||
(windowStartValid || scheduleTimestampValid) &&
|
(windowStartValid || scheduleTimestampValid) &&
|
||||||
@ -77,26 +84,23 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
|||||||
scheduleGasLimitValid &&
|
scheduleGasLimitValid &&
|
||||||
depositValid;
|
depositValid;
|
||||||
|
|
||||||
const transactionData = getScheduleData(
|
let transactionData = null;
|
||||||
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 endowment = calcEACEndowment(
|
if (isFullTransaction) {
|
||||||
scheduleGasLimit.value || EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK,
|
transactionData = getScheduleData(
|
||||||
currentValue.value || new BN(0),
|
currentTo.raw,
|
||||||
scheduleGasPrice.value || gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK),
|
callData.raw,
|
||||||
timeBounty.value
|
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 = {
|
const transactionOptions = {
|
||||||
to: Address(
|
to: Address(
|
||||||
@ -122,5 +126,3 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
|||||||
isFullTransaction
|
isFullTransaction
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getSchedulingTransaction };
|
|
||||||
|
@ -120,7 +120,7 @@ export default class AbiFunction {
|
|||||||
this.inputNames.map(name => {
|
this.inputNames.map(name => {
|
||||||
const type = this.funcParams[name].type;
|
const type = this.funcParams[name].type;
|
||||||
//TODO: parse args based on type
|
//TODO: parse args based on type
|
||||||
if (!suppliedArgs[name]) {
|
if (typeof suppliedArgs[name] === 'undefined') {
|
||||||
throw Error(
|
throw Error(
|
||||||
`Expected argument "${name}" of type "${type}" missing, suppliedArgs: ${JSON.stringify(
|
`Expected argument "${name}" of type "${type}" missing, suppliedArgs: ${JSON.stringify(
|
||||||
suppliedArgs,
|
suppliedArgs,
|
||||||
|
58
common/libs/scheduling/contracts/RequestFactory.ts
Normal file
58
common/libs/scheduling/contracts/RequestFactory.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import Contract from 'libs/contracts';
|
||||||
|
|
||||||
|
interface ABIFunc<T, K = void> {
|
||||||
|
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;
|
@ -1,7 +1,8 @@
|
|||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import abi from 'ethereumjs-abi';
|
import abi from 'ethereumjs-abi';
|
||||||
import { toWei, Units } from './units';
|
import { toWei, Units } from '../units';
|
||||||
import { toBuffer } from 'ethereumjs-util';
|
import { toBuffer } from 'ethereumjs-util';
|
||||||
|
import RequestFactory from './contracts/RequestFactory';
|
||||||
|
|
||||||
const TIME_BOUNTY_MIN = new BN('1');
|
const TIME_BOUNTY_MIN = new BN('1');
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ export const EAC_SCHEDULING_CONFIG = {
|
|||||||
export const EAC_ADDRESSES = {
|
export const EAC_ADDRESSES = {
|
||||||
KOVAN: {
|
KOVAN: {
|
||||||
blockScheduler: '0x1afc19a7e642761ba2b55d2a45b32c7ef08269d1',
|
blockScheduler: '0x1afc19a7e642761ba2b55d2a45b32c7ef08269d1',
|
||||||
|
requestFactory: '0x496e2b6089bde77293a994469b08e9f266d87adb',
|
||||||
timestampScheduler: '0xc6370807f0164bdf10a66c08d0dab1028dbe80a3'
|
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) => {
|
export const getTXDetailsCheckURL = (txHash: string) => {
|
||||||
return `${EAC_SCHEDULING_CONFIG.DAPP_ADDRESS}/awaiting/scheduler/${txHash}`;
|
return `${EAC_SCHEDULING_CONFIG.DAPP_ADDRESS}/awaiting/scheduler/${txHash}`;
|
||||||
};
|
};
|
@ -44,7 +44,8 @@ const INITIAL_STATE: State = {
|
|||||||
raw: EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK.toString(),
|
raw: EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK.toString(),
|
||||||
value: gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK)
|
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: State, action: FieldAction) => ({
|
const updateField = (key: keyof State): Reducer<State> => (state: State, action: FieldAction) => ({
|
||||||
@ -114,6 +115,8 @@ export const fields = (
|
|||||||
return updateField('scheduleGasPrice')(state, action);
|
return updateField('scheduleGasPrice')(state, action);
|
||||||
case TK.SCHEDULE_DEPOSIT_FIELD_SET:
|
case TK.SCHEDULE_DEPOSIT_FIELD_SET:
|
||||||
return updateField('scheduleDeposit')(state, action);
|
return updateField('scheduleDeposit')(state, action);
|
||||||
|
case TK.SCHEDULE_PARAMS_VALIDITY_SET:
|
||||||
|
return updateField('scheduleParamsValidity')(state, action);
|
||||||
case TK.TOKEN_TO_ETHER_SWAP:
|
case TK.TOKEN_TO_ETHER_SWAP:
|
||||||
return tokenToEther(state, action);
|
return tokenToEther(state, action);
|
||||||
case TK.ETHER_TO_TOKEN_SWAP:
|
case TK.ETHER_TO_TOKEN_SWAP:
|
||||||
|
@ -11,7 +11,8 @@ import {
|
|||||||
SetScheduleGasPriceFieldAction,
|
SetScheduleGasPriceFieldAction,
|
||||||
SetScheduleGasLimitFieldAction,
|
SetScheduleGasLimitFieldAction,
|
||||||
SetScheduleDepositFieldAction,
|
SetScheduleDepositFieldAction,
|
||||||
SetScheduleTimezoneAction
|
SetScheduleTimezoneAction,
|
||||||
|
SetScheduleParamsValidityAction
|
||||||
} from 'actions/transaction';
|
} from 'actions/transaction';
|
||||||
import { Wei } from 'libs/units';
|
import { Wei } from 'libs/units';
|
||||||
|
|
||||||
@ -32,4 +33,5 @@ export interface State {
|
|||||||
scheduleGasLimit: SetScheduleGasLimitFieldAction['payload'];
|
scheduleGasLimit: SetScheduleGasLimitFieldAction['payload'];
|
||||||
scheduleGasPrice: SetScheduleGasPriceFieldAction['payload'];
|
scheduleGasPrice: SetScheduleGasPriceFieldAction['payload'];
|
||||||
scheduleDeposit: SetScheduleDepositFieldAction['payload'];
|
scheduleDeposit: SetScheduleDepositFieldAction['payload'];
|
||||||
|
scheduleParamsValidity: SetScheduleParamsValidityAction['payload'];
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { from } from './from';
|
import { from } from './from';
|
||||||
import { gas } from './gas';
|
import { gas } from './gas';
|
||||||
import { nonce } from './nonce';
|
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];
|
||||||
|
@ -33,7 +33,8 @@ describe('fields reducer', () => {
|
|||||||
value: gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK)
|
value: gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK)
|
||||||
},
|
},
|
||||||
scheduleGasLimit: { raw: '21000', value: new BN(21000) },
|
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 };
|
const testPayload = { raw: 'test', value: null };
|
||||||
|
|
||||||
|
@ -81,6 +81,10 @@ describe('fields selector', () => {
|
|||||||
scheduleDeposit: {
|
scheduleDeposit: {
|
||||||
raw: '1000000000',
|
raw: '1000000000',
|
||||||
value: Wei('1000000000')
|
value: Wei('1000000000')
|
||||||
|
},
|
||||||
|
scheduleParamsValidity: {
|
||||||
|
raw: false,
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,6 +85,10 @@ describe('helpers selector', () => {
|
|||||||
scheduleDeposit: {
|
scheduleDeposit: {
|
||||||
raw: '1000000000',
|
raw: '1000000000',
|
||||||
value: Wei('1000000000')
|
value: Wei('1000000000')
|
||||||
|
},
|
||||||
|
scheduleParamsValidity: {
|
||||||
|
raw: false,
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -106,7 +110,8 @@ describe('helpers selector', () => {
|
|||||||
scheduleTimezone: moment.tz.guess(),
|
scheduleTimezone: moment.tz.guess(),
|
||||||
scheduleGasPrice: Wei('1500'),
|
scheduleGasPrice: Wei('1500'),
|
||||||
scheduleGasLimit: Wei('21000'),
|
scheduleGasLimit: Wei('21000'),
|
||||||
scheduleDeposit: Wei('1000000000')
|
scheduleDeposit: Wei('1000000000'),
|
||||||
|
scheduleParamsValidity: false
|
||||||
};
|
};
|
||||||
expect(reduceToValues(state.transaction.fields)).toEqual(values);
|
expect(reduceToValues(state.transaction.fields)).toEqual(values);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user