MyCrypto/common/features/schedule/sagas.ts

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
]);
}