mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-14 20:19:47 +00:00
Allow 0 ETH Transactions (#1307)
* Allow zero number * Fail when request payment is zero value, or if you try to send token with zero value. * Parseint instead of addition casting to catch empty string.
This commit is contained in:
parent
16469e1a62
commit
4b8adc81ce
@ -12,7 +12,7 @@ import {
|
||||
ICurrentValue
|
||||
} from 'selectors/transaction/current';
|
||||
import BN from 'bn.js';
|
||||
import { validNumber, validDecimal } from 'libs/validators';
|
||||
import { validPositiveNumber, validDecimal } from 'libs/validators';
|
||||
import { getGasLimit } from 'selectors/transaction';
|
||||
import { AddressField, AmountField, TXMetaDataPanel } from 'components';
|
||||
import { SetGasLimitFieldAction } from 'actions/transaction/actionTypes/fields';
|
||||
@ -45,7 +45,7 @@ interface ActionProps {
|
||||
type Props = OwnProps & StateProps & ActionProps;
|
||||
|
||||
const isValidAmount = (decimal: number) => (amount: string) =>
|
||||
validNumber(+amount) && validDecimal(amount, decimal);
|
||||
validPositiveNumber(+amount) && validDecimal(amount, decimal);
|
||||
|
||||
class RequestPayment extends React.Component<Props, {}> {
|
||||
public state = {
|
||||
|
@ -103,7 +103,8 @@ export function isValidEncryptedPrivKey(privkey: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export const validNumber = (num: number) => isFinite(num) && num > 0;
|
||||
export const validNumber = (num: number) => isFinite(num) && num >= 0;
|
||||
export const validPositiveNumber = (num: number) => validNumber(num) && num !== 0;
|
||||
|
||||
export const validDecimal = (input: string, decimal: number) => {
|
||||
const arr = input.split('.');
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
} from 'actions/transaction';
|
||||
import { toTokenBase } from 'libs/units';
|
||||
import { validateInput, IInput } from 'sagas/transaction/validationHelpers';
|
||||
import { validNumber, validDecimal } from 'libs/validators';
|
||||
import { validNumber, validPositiveNumber, validDecimal } from 'libs/validators';
|
||||
|
||||
export function* setCurrentValue(action: SetCurrentValueAction): SagaIterator {
|
||||
const etherTransaction = yield select(isEtherTransaction);
|
||||
@ -30,8 +30,10 @@ export function* valueHandler(
|
||||
) {
|
||||
const decimal: number = yield select(getDecimal);
|
||||
const unit: string = yield select(getUnit);
|
||||
const isEth = yield select(isEtherTransaction);
|
||||
const validNum = isEth ? validNumber : validPositiveNumber;
|
||||
|
||||
if (!validNumber(+payload) || !validDecimal(payload, decimal)) {
|
||||
if (!validNum(parseInt(payload, 10)) || !validDecimal(payload, decimal)) {
|
||||
return yield put(setter({ raw: payload, value: null }));
|
||||
}
|
||||
const value = toTokenBase(payload, decimal);
|
||||
@ -53,9 +55,11 @@ export function* revalidateCurrentValue(): SagaIterator {
|
||||
}
|
||||
|
||||
export function* reparseCurrentValue(value: IInput): SagaIterator {
|
||||
const isEth = yield select(isEtherTransaction);
|
||||
const decimal = yield select(getDecimal);
|
||||
const validNum = isEth ? validNumber : validPositiveNumber;
|
||||
|
||||
if (validNumber(+value.raw) && validDecimal(value.raw, decimal)) {
|
||||
if (validNum(parseInt(value.raw, 10)) && validDecimal(value.raw, decimal)) {
|
||||
return {
|
||||
raw: value.raw,
|
||||
value: toTokenBase(value.raw, decimal)
|
||||
|
@ -28,7 +28,7 @@ export function* rebaseUserInput(value: IInput): SagaIterator {
|
||||
// get decimal
|
||||
const newDecimal: number = yield select(getDecimalFromUnit, unit);
|
||||
|
||||
if (validNumber(+value.raw) && validDecimal(value.raw, newDecimal)) {
|
||||
if (validNumber(parseInt(value.raw, 10)) && validDecimal(value.raw, newDecimal)) {
|
||||
return {
|
||||
raw: value.raw,
|
||||
value: toTokenBase(value.raw, newDecimal)
|
||||
|
@ -20,6 +20,7 @@ const itShouldBeDone = (gen: SagaIterator) => {
|
||||
|
||||
describe('valueHandler', () => {
|
||||
const action: any = { payload: '5.1' };
|
||||
const zeroAction: any = { payload: '0' };
|
||||
const setter = setValueField;
|
||||
const decimal = 1;
|
||||
const gen: { [key: string]: SagaIteratorClone } = {};
|
||||
@ -29,45 +30,86 @@ describe('valueHandler', () => {
|
||||
invalidNumber: {
|
||||
decimal: 1,
|
||||
action: { payload: 'x' }
|
||||
},
|
||||
invalidZeroToken: {
|
||||
unit: 'GNT',
|
||||
isEth: false,
|
||||
setter: setTokenValue
|
||||
}
|
||||
};
|
||||
|
||||
gen.pass = cloneableGenerator(valueHandler)(action, setter);
|
||||
gen.zeroPass = cloneableGenerator(valueHandler)(zeroAction, setter);
|
||||
gen.invalidNumber = cloneableGenerator(valueHandler)(
|
||||
failCases.invalidNumber.action as any,
|
||||
setter
|
||||
);
|
||||
gen.invalidZeroToken = cloneableGenerator(valueHandler)(zeroAction, setTokenValue);
|
||||
const value = toTokenBase(action.payload, decimal);
|
||||
const zeroValue = toTokenBase(zeroAction.payload, decimal);
|
||||
const unit = 'eth';
|
||||
const isEth = true;
|
||||
|
||||
it('should select getDecimal', () => {
|
||||
expect(gen.pass.next().value).toEqual(select(getDecimal));
|
||||
expect(gen.zeroPass.next().value).toEqual(select(getDecimal));
|
||||
expect(gen.invalidNumber.next().value).toEqual(select(getDecimal));
|
||||
expect(gen.invalidZeroToken.next().value).toEqual(select(getDecimal));
|
||||
});
|
||||
|
||||
it('should select getUnit', () => {
|
||||
gen.invalidDecimal = gen.pass.clone();
|
||||
expect(gen.pass.next(decimal).value).toEqual(select(getUnit));
|
||||
expect(gen.zeroPass.next(decimal).value).toEqual(select(getUnit));
|
||||
expect(gen.invalidNumber.next(decimal).value).toEqual(select(getUnit));
|
||||
expect(gen.invalidDecimal.next(failCases.invalidDecimal).value).toEqual(select(getUnit));
|
||||
expect(gen.invalidZeroToken.next(decimal).value).toEqual(select(getUnit));
|
||||
});
|
||||
|
||||
it('should fail on invalid number or decimal and put null as a value', () => {
|
||||
expect(gen.invalidNumber.next(unit).value).toEqual(
|
||||
it('should select isEtherTransaction', () => {
|
||||
expect(gen.pass.next(unit).value).toEqual(select(isEtherTransaction));
|
||||
expect(gen.zeroPass.next(unit).value).toEqual(select(isEtherTransaction));
|
||||
expect(gen.invalidNumber.next(unit).value).toEqual(select(isEtherTransaction));
|
||||
expect(gen.invalidDecimal.next(unit).value).toEqual(select(isEtherTransaction));
|
||||
expect(gen.invalidZeroToken.next(failCases.invalidZeroToken.unit).value).toEqual(
|
||||
select(isEtherTransaction)
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail on invalid number or decimal and put null as value', () => {
|
||||
expect(gen.invalidNumber.next(isEth).value).toEqual(
|
||||
put(setter({ raw: failCases.invalidNumber.action.payload, value: null }))
|
||||
);
|
||||
expect(gen.invalidDecimal.next(unit).value).toEqual(
|
||||
expect(gen.invalidDecimal.next(isEth).value).toEqual(
|
||||
put(setter({ raw: action.payload, value: null }))
|
||||
);
|
||||
});
|
||||
|
||||
it('should call isValid', () => {
|
||||
expect(gen.pass.next(unit).value).toEqual(call(validateInput, value, unit));
|
||||
it('should fail if token is given zero value and put null as value', () => {
|
||||
expect(gen.invalidZeroToken.next(failCases.invalidZeroToken.isEth).value).toEqual(
|
||||
put(failCases.invalidZeroToken.setter({ raw: zeroAction.payload, value: null }))
|
||||
);
|
||||
});
|
||||
|
||||
it('should call isValid', () => {
|
||||
expect(gen.pass.next(isEth).value).toEqual(call(validateInput, value, unit));
|
||||
expect(gen.zeroPass.next(isEth).value).toEqual(call(validateInput, zeroValue, unit));
|
||||
});
|
||||
|
||||
it('should put setter', () => {
|
||||
expect(gen.pass.next(true).value).toEqual(put(setter({ raw: action.payload, value })));
|
||||
expect(gen.zeroPass.next(true).value).toEqual(
|
||||
put(
|
||||
setter({
|
||||
raw: zeroAction.payload,
|
||||
value: zeroValue
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
itShouldBeDone(gen.pass);
|
||||
itShouldBeDone(gen.zeroPass);
|
||||
});
|
||||
|
||||
describe('setCurrentValue*', () => {
|
||||
@ -164,20 +206,25 @@ describe('revalidateCurrentValue*', () => {
|
||||
});
|
||||
|
||||
describe('reparseCurrentValue*', () => {
|
||||
const sharedLogic = (gen: SagaIterator) => {
|
||||
const decimal = 5;
|
||||
|
||||
const sharedLogic = (gen: SagaIterator, isEth: boolean) => {
|
||||
it('should select isEtherTransaction', () => {
|
||||
expect(gen.next().value).toEqual(select(isEtherTransaction));
|
||||
});
|
||||
|
||||
it('should select getDecimal', () => {
|
||||
expect(gen.next().value).toEqual(select(getDecimal));
|
||||
expect(gen.next(isEth).value).toEqual(select(getDecimal));
|
||||
});
|
||||
};
|
||||
|
||||
describe('when valid number and valid decimal', () => {
|
||||
describe('when eth tx value is positive number and valid decimal', () => {
|
||||
const value: any = {
|
||||
raw: '100.0000'
|
||||
};
|
||||
const decimal = 5;
|
||||
const gen = reparseCurrentValue(value);
|
||||
|
||||
sharedLogic(gen);
|
||||
sharedLogic(gen, true);
|
||||
|
||||
it('should return correctly', () => {
|
||||
expect(gen.next(decimal).value).toEqual({
|
||||
@ -189,14 +236,46 @@ describe('reparseCurrentValue*', () => {
|
||||
itShouldBeDone(gen);
|
||||
});
|
||||
|
||||
describe('when invalid number', () => {
|
||||
describe('when eth tx value is zero and decimal is valid', () => {
|
||||
const value: any = {
|
||||
raw: '0'
|
||||
};
|
||||
const gen = reparseCurrentValue(value);
|
||||
|
||||
sharedLogic(gen, true);
|
||||
|
||||
it('should return correctly', () => {
|
||||
expect(gen.next(decimal).value).toEqual({
|
||||
raw: value.raw,
|
||||
value: toTokenBase(value.raw, decimal)
|
||||
});
|
||||
});
|
||||
|
||||
itShouldBeDone(gen);
|
||||
});
|
||||
|
||||
describe('when eth tx value is invalid', () => {
|
||||
const value: any = {
|
||||
raw: 'invalidNumber'
|
||||
};
|
||||
const decimal = 5;
|
||||
const gen = reparseCurrentValue(value);
|
||||
|
||||
sharedLogic(gen);
|
||||
sharedLogic(gen, true);
|
||||
|
||||
it('should return null', () => {
|
||||
expect(gen.next(decimal).value).toEqual(null);
|
||||
});
|
||||
|
||||
itShouldBeDone(gen);
|
||||
});
|
||||
|
||||
describe('when non-eth tx value is zero and valid decimal', () => {
|
||||
const value: any = {
|
||||
raw: '0'
|
||||
};
|
||||
const gen = reparseCurrentValue(value);
|
||||
|
||||
sharedLogic(gen, false);
|
||||
|
||||
it('should return null', () => {
|
||||
expect(gen.next(decimal).value).toEqual(null);
|
||||
|
@ -24,8 +24,8 @@ describe('rebaseUserInput*', () => {
|
||||
value: Wei('1')
|
||||
};
|
||||
const notValidNumberValue: any = {
|
||||
raw: '0x0',
|
||||
value: '0x0'
|
||||
raw: '-1',
|
||||
value: '-1'
|
||||
};
|
||||
const unit = 'unit';
|
||||
const newDecimal = 1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user