211 lines
6.1 KiB
TypeScript
211 lines
6.1 KiB
TypeScript
|
import { SagaIterator, delay } from 'redux-saga';
|
||
|
import { select, take, call, apply, fork, put, all, takeLatest } from 'redux-saga/effects';
|
||
|
import BN from 'bn.js';
|
||
|
|
||
|
import { toTokenBase, Wei } from 'libs/units';
|
||
|
import { EAC_SCHEDULING_CONFIG, parseSchedulingParametersValidity } from 'libs/scheduling';
|
||
|
import RequestFactory from 'libs/scheduling/contracts/RequestFactory';
|
||
|
import { validDecimal, validNumber } from 'libs/validators';
|
||
|
import * as derivedSelectors from 'features/selectors';
|
||
|
import * as configMetaSelectors from 'features/config/meta/selectors';
|
||
|
import * as configNodesSelectors from 'features/config/nodes/selectors';
|
||
|
import {
|
||
|
transactionFieldsTypes,
|
||
|
transactionFieldsActions,
|
||
|
transactionMetaSelectors,
|
||
|
transactionHelpers
|
||
|
} from 'features/transaction';
|
||
|
import * as types from './types';
|
||
|
import * as actions from './actions';
|
||
|
import * as selectors from './selectors';
|
||
|
|
||
|
//#region Schedule Timestamp
|
||
|
export function* setCurrentScheduleTimestampSaga({
|
||
|
payload: raw
|
||
|
}: types.SetCurrentScheduleTimestampAction): SagaIterator {
|
||
|
let value: Date | null = null;
|
||
|
|
||
|
value = new Date(raw);
|
||
|
|
||
|
yield put(actions.setScheduleTimestampField({ value, raw }));
|
||
|
}
|
||
|
|
||
|
export const currentScheduleTimestamp = takeLatest(
|
||
|
[types.ScheduleActions.CURRENT_SCHEDULE_TIMESTAMP_SET],
|
||
|
setCurrentScheduleTimestampSaga
|
||
|
);
|
||
|
//#endregion Schedule Timestamp
|
||
|
|
||
|
//#region Schedule Timezone
|
||
|
export function* setCurrentScheduleTimezoneSaga({
|
||
|
payload: raw
|
||
|
}: types.SetCurrentScheduleTimezoneAction): SagaIterator {
|
||
|
const value = raw;
|
||
|
|
||
|
yield put(actions.setScheduleTimezone({ value, raw }));
|
||
|
}
|
||
|
|
||
|
export const currentScheduleTimezone = takeLatest(
|
||
|
[types.ScheduleActions.CURRENT_SCHEDULE_TIMEZONE_SET],
|
||
|
setCurrentScheduleTimezoneSaga
|
||
|
);
|
||
|
//#endregion Schedule Timezone
|
||
|
|
||
|
//#region Scheduling Toggle
|
||
|
export function* setGasLimitForSchedulingSaga({
|
||
|
payload: { value: useScheduling }
|
||
|
}: types.SetSchedulingToggleAction): SagaIterator {
|
||
|
const gasLimit = useScheduling
|
||
|
? EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT
|
||
|
: EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK;
|
||
|
|
||
|
yield put(
|
||
|
transactionFieldsActions.setGasLimitField({
|
||
|
raw: gasLimit.toString(),
|
||
|
value: gasLimit
|
||
|
})
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export const currentSchedulingToggle = takeLatest(
|
||
|
[types.ScheduleActions.TOGGLE_SET],
|
||
|
setGasLimitForSchedulingSaga
|
||
|
);
|
||
|
//#endregion Scheduling Toggle
|
||
|
|
||
|
//#region Time Bounty
|
||
|
export function* setCurrentTimeBountySaga({
|
||
|
payload: raw
|
||
|
}: types.SetCurrentTimeBountyAction): SagaIterator {
|
||
|
const decimal: number = yield select(transactionMetaSelectors.getDecimal);
|
||
|
const unit: string = yield select(derivedSelectors.getUnit);
|
||
|
|
||
|
if (!validNumber(parseInt(raw, 10)) || !validDecimal(raw, decimal)) {
|
||
|
yield put(actions.setTimeBountyField({ raw, value: null }));
|
||
|
}
|
||
|
|
||
|
const value = toTokenBase(raw, decimal);
|
||
|
const isInputValid: boolean = yield call(transactionHelpers.validateInput, value, unit);
|
||
|
|
||
|
const isValid = isInputValid && value.gte(Wei('0'));
|
||
|
|
||
|
yield put(actions.setTimeBountyField({ raw, value: isValid ? value : null }));
|
||
|
}
|
||
|
|
||
|
export const currentTimeBounty = takeLatest(
|
||
|
[types.ScheduleActions.CURRENT_TIME_BOUNTY_SET],
|
||
|
setCurrentTimeBountySaga
|
||
|
);
|
||
|
//#endregion Time Bounty
|
||
|
|
||
|
//#region Window Size
|
||
|
export function* setCurrentWindowSizeSaga({
|
||
|
payload: raw
|
||
|
}: types.SetCurrentWindowSizeAction): SagaIterator {
|
||
|
let value: BN | null = null;
|
||
|
|
||
|
if (!validNumber(parseInt(raw, 10))) {
|
||
|
yield put(actions.setWindowSizeField({ raw, value: null }));
|
||
|
}
|
||
|
|
||
|
value = new BN(raw);
|
||
|
|
||
|
yield put(actions.setWindowSizeField({ value, raw }));
|
||
|
}
|
||
|
|
||
|
export const currentWindowSize = takeLatest(
|
||
|
[types.ScheduleActions.CURRENT_WINDOW_SIZE_SET],
|
||
|
setCurrentWindowSizeSaga
|
||
|
);
|
||
|
//#endregion Window Size
|
||
|
|
||
|
//#region Window Start
|
||
|
export function* setCurrentWindowStartSaga({
|
||
|
payload: raw
|
||
|
}: types.SetCurrentWindowStartAction): SagaIterator {
|
||
|
let value: number | null = null;
|
||
|
|
||
|
value = parseInt(raw, 10);
|
||
|
|
||
|
yield put(actions.setWindowStartField({ value, raw }));
|
||
|
}
|
||
|
|
||
|
export const currentWindowStart = takeLatest(
|
||
|
[types.ScheduleActions.CURRENT_WINDOW_START_SET],
|
||
|
setCurrentWindowStartSaga
|
||
|
);
|
||
|
//#endregion Window Start
|
||
|
|
||
|
//#region Params Validity
|
||
|
export function* shouldValidateParams(): SagaIterator {
|
||
|
while (true) {
|
||
|
yield take([
|
||
|
transactionFieldsTypes.TransactionFieldsActions.TO_FIELD_SET,
|
||
|
transactionFieldsTypes.TransactionFieldsActions.DATA_FIELD_SET,
|
||
|
transactionFieldsTypes.TransactionFieldsActions.VALUE_FIELD_SET,
|
||
|
types.ScheduleActions.CURRENT_TIME_BOUNTY_SET,
|
||
|
types.ScheduleActions.WINDOW_SIZE_FIELD_SET,
|
||
|
types.ScheduleActions.WINDOW_START_FIELD_SET,
|
||
|
types.ScheduleActions.TIMESTAMP_FIELD_SET,
|
||
|
types.ScheduleActions.TIME_BOUNTY_FIELD_SET,
|
||
|
types.ScheduleActions.TYPE_SET,
|
||
|
types.ScheduleActions.TOGGLE_SET,
|
||
|
types.ScheduleActions.TIMEZONE_SET
|
||
|
]);
|
||
|
|
||
|
yield call(delay, 250);
|
||
|
|
||
|
const isOffline: boolean = yield select(configMetaSelectors.getOffline);
|
||
|
const scheduling: boolean = yield select(selectors.isSchedulingEnabled);
|
||
|
|
||
|
if (isOffline || !scheduling) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
yield call(checkSchedulingParametersValidity);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function* checkSchedulingParametersValidity() {
|
||
|
const validateParamsCallData: derivedSelectors.IGetValidateScheduleParamsCallPayload = yield select(
|
||
|
derivedSelectors.getValidateScheduleParamsCallPayload
|
||
|
);
|
||
|
|
||
|
if (!validateParamsCallData) {
|
||
|
return yield put(
|
||
|
actions.setScheduleParamsValidity({
|
||
|
value: false
|
||
|
})
|
||
|
);
|
||
|
}
|
||
|
|
||
|
const node = yield select(configNodesSelectors.getNodeLib);
|
||
|
|
||
|
const callResult: string = yield apply(node, node.sendCallRequest, [validateParamsCallData]);
|
||
|
|
||
|
const { paramsValidity } = RequestFactory.validateRequestParams.decodeOutput(callResult);
|
||
|
|
||
|
const errors = parseSchedulingParametersValidity(paramsValidity);
|
||
|
|
||
|
yield put(
|
||
|
actions.setScheduleParamsValidity({
|
||
|
value: errors.length === 0
|
||
|
})
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export const schedulingParamsValidity = fork(shouldValidateParams);
|
||
|
//#endregion Params Validity
|
||
|
|
||
|
export function* scheduleSaga(): SagaIterator {
|
||
|
yield all([
|
||
|
currentWindowSize,
|
||
|
currentWindowStart,
|
||
|
currentScheduleTimestamp,
|
||
|
currentTimeBounty,
|
||
|
currentSchedulingToggle,
|
||
|
currentScheduleTimezone,
|
||
|
schedulingParamsValidity
|
||
|
]);
|
||
|
}
|