MyCrypto/common/features/transaction/meta/sagas.ts

156 lines
5.5 KiB
TypeScript

import { SagaIterator } from 'redux-saga';
import { put, select, call, takeEvery } from 'redux-saga/effects';
import { bufferToHex } from 'ethereumjs-util';
import { encodeTransfer } from 'libs/transaction';
import { Address, TokenValue } from 'libs/units';
import { AppState } from 'features/reducers';
import * as derivedSelectors from 'features/selectors';
import * as configSelectors from 'features/config/selectors';
import { walletTypes } from 'features/wallet';
import { scheduleActions } from 'features/schedule';
import { transactionFieldsActions, transactionFieldsSelectors } from '../fields';
import * as transactionActions from '../actions';
import * as transactionSelectors from '../selectors';
import * as helpers from '../helpers';
import * as types from './types';
import * as selectors from './selectors';
//#region Token
export function* handleTokenTo({ payload }: types.SetTokenToMetaAction): SagaIterator {
const tokenValue: AppState['transaction']['meta']['tokenValue'] = yield select(
selectors.getTokenValue
);
if (!(tokenValue.value && payload.value)) {
return;
}
// encode token data and dispatch it
const data = yield call(encodeTransfer, payload.value, tokenValue.value);
yield put(transactionFieldsActions.setDataField({ raw: bufferToHex(data), value: data }));
}
export function* handleTokenValue({ payload }: types.SetTokenValueMetaAction) {
const tokenTo: AppState['transaction']['meta']['tokenTo'] = yield select(selectors.getTokenTo);
const prevData = yield select(transactionFieldsSelectors.getData);
if (!(tokenTo.value && payload.value)) {
return;
}
const data = yield call(encodeTransfer, tokenTo.value, payload.value);
if (prevData.raw === bufferToHex(data)) {
return;
}
yield put(transactionFieldsActions.setDataField({ raw: bufferToHex(data), value: data }));
}
export const handleToken = [
takeEvery(types.TransactionMetaActions.TOKEN_TO_META_SET, handleTokenTo),
takeEvery(types.TransactionMetaActions.TOKEN_VALUE_META_SET, handleTokenValue)
];
//#endregion Token
//#region Set Unit
export function* handleSetUnitMeta({
payload: currentUnit
}: types.SetUnitMetaAction): SagaIterator {
const previousUnit: string = yield select(transactionSelectors.getPreviousUnit);
const prevUnit = yield select(configSelectors.isNetworkUnit, previousUnit);
const currUnit = yield select(configSelectors.isNetworkUnit, currentUnit);
const etherToEther = currUnit && prevUnit;
const etherToToken = !currUnit && prevUnit;
const tokenToEther = currUnit && !prevUnit;
const tokenToToken = !currUnit && !prevUnit;
const decimal: number = yield select(derivedSelectors.getDecimalFromUnit, currentUnit);
if (etherToEther || previousUnit === '') {
return;
}
if (tokenToEther) {
const tokenTo: AppState['transaction']['meta']['tokenTo'] = yield select(selectors.getTokenTo);
const tokenValue: AppState['transaction']['meta']['tokenValue'] = yield select(
selectors.getTokenValue
);
//set the 'to' field from what the token 'to' field was
// if switching to ether, clear token data and value
const { value, raw }: helpers.IInput = yield call(helpers.rebaseUserInput, tokenValue);
const isValid = yield call(helpers.validateInput, value, currentUnit);
return yield put(
transactionActions.swapTokenToEther({
to: tokenTo,
value: { raw, value: isValid ? value : null },
decimal
})
);
}
if (etherToToken || tokenToToken) {
const currentToken: walletTypes.MergedToken | undefined = yield select(
derivedSelectors.getToken,
currentUnit
);
if (!currentToken) {
throw Error('Could not find token during unit swap');
}
const input:
| AppState['transaction']['fields']['value']
| AppState['transaction']['meta']['tokenValue'] = etherToToken
? yield select(transactionFieldsSelectors.getValue)
: yield select(selectors.getTokenValue);
const { raw, value }: helpers.IInput = yield call(helpers.rebaseUserInput, input);
const isValid = yield call(helpers.validateInput, value, currentUnit);
const to: AppState['transaction']['fields']['to'] = yield select(
transactionFieldsSelectors.getTo
);
const valueToEncode = isValid && value ? value : TokenValue('0');
let addressToEncode;
if (etherToToken) {
addressToEncode = to.value || Address('0x0');
} else {
const tokenTo: AppState['transaction']['meta']['tokenTo'] = yield select(
selectors.getTokenTo
);
addressToEncode = tokenTo.value || Address('0x0');
}
const data = encodeTransfer(addressToEncode, valueToEncode);
const basePayload = {
data: { raw: bufferToHex(data), value: data },
to: { raw: '', value: Address(currentToken.address) },
tokenValue: { raw, value: isValid ? value : null },
decimal
};
// need to set meta fields for tokenTo and tokenValue
if (etherToToken) {
yield put(
scheduleActions.setSchedulingToggle({
value: false
})
);
return yield put(
transactionActions.swapEtherToToken({
...basePayload,
tokenTo: to
})
);
}
// need to rebase the token if the decimal has changed and re-validate
if (tokenToToken) {
return yield put(transactionActions.swapTokenToToken(basePayload));
}
}
}
export const handleSetUnit = [
takeEvery(types.TransactionMetaActions.UNIT_META_SET, handleSetUnitMeta)
];
//#endregion Set Unit
export const metaSaga = [...handleToken, ...handleSetUnit];