mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-10 10:07:00 +00:00
[FEATURE] Add Deposit field
This commit is contained in:
parent
02ba3ea0c3
commit
353eeb5384
@ -18,7 +18,8 @@ import {
|
||||
SetScheduleTypeAction,
|
||||
SetSchedulingToggleAction,
|
||||
SetScheduleGasPriceFieldAction,
|
||||
SetScheduleGasLimitFieldAction
|
||||
SetScheduleGasLimitFieldAction,
|
||||
SetScheduleDepositFieldAction
|
||||
} from '../actionTypes';
|
||||
import { TypeKeys } from 'actions/transaction/constants';
|
||||
|
||||
@ -146,6 +147,12 @@ const setScheduleGasLimitField = (payload: SetScheduleGasLimitFieldAction['paylo
|
||||
payload
|
||||
});
|
||||
|
||||
type TSetScheduleDepositField = typeof setScheduleDepositField;
|
||||
const setScheduleDepositField = (payload: SetScheduleDepositFieldAction['payload']) => ({
|
||||
type: TypeKeys.SCHEDULE_DEPOSIT_FIELD_SET,
|
||||
payload
|
||||
});
|
||||
|
||||
type TReset = typeof reset;
|
||||
const reset = (payload: ResetAction['payload'] = { include: {}, exclude: {} }): ResetAction => ({
|
||||
type: TypeKeys.RESET,
|
||||
@ -172,6 +179,7 @@ export {
|
||||
TSetSchedulingToggle,
|
||||
TSetScheduleGasPriceField,
|
||||
TSetScheduleGasLimitField,
|
||||
TSetScheduleDepositField,
|
||||
TReset,
|
||||
inputGasLimit,
|
||||
inputGasPrice,
|
||||
@ -192,5 +200,6 @@ export {
|
||||
setSchedulingToggle,
|
||||
setScheduleGasPriceField,
|
||||
setScheduleGasLimitField,
|
||||
setScheduleDepositField,
|
||||
reset
|
||||
};
|
||||
|
@ -147,6 +147,14 @@ interface SetScheduleGasLimitFieldAction {
|
||||
};
|
||||
}
|
||||
|
||||
interface SetScheduleDepositFieldAction {
|
||||
type: TypeKeys.SCHEDULE_DEPOSIT_FIELD_SET;
|
||||
payload: {
|
||||
raw: string;
|
||||
value: Wei | null;
|
||||
};
|
||||
}
|
||||
|
||||
type InputFieldAction = InputNonceAction | InputGasLimitAction | InputDataAction;
|
||||
|
||||
type FieldAction =
|
||||
@ -163,7 +171,8 @@ type FieldAction =
|
||||
| SetScheduleTypeAction
|
||||
| SetSchedulingToggleAction
|
||||
| SetScheduleGasPriceFieldAction
|
||||
| SetScheduleGasLimitFieldAction;
|
||||
| SetScheduleGasLimitFieldAction
|
||||
| SetScheduleDepositFieldAction;
|
||||
|
||||
export {
|
||||
InputGasLimitAction,
|
||||
@ -188,5 +197,6 @@ export {
|
||||
SetScheduleTypeAction,
|
||||
SetSchedulingToggleAction,
|
||||
SetScheduleGasPriceFieldAction,
|
||||
SetScheduleGasLimitFieldAction
|
||||
SetScheduleGasLimitFieldAction,
|
||||
SetScheduleDepositFieldAction
|
||||
};
|
||||
|
@ -55,6 +55,7 @@ export enum TypeKeys {
|
||||
SCHEDULE_TIMEZONE_SET = 'SCHEDULE_TIMEZONE_SET',
|
||||
SCHEDULE_TYPE_SET = 'SCHEDULE_TYPE_SET',
|
||||
SCHEDULING_TOGGLE_SET = 'SCHEDULING_TOGGLE_SET',
|
||||
SCHEDULE_DEPOSIT_FIELD_SET = 'SCHEDULE_DEPOSIT_FIELD_SET',
|
||||
|
||||
TOKEN_TO_META_SET = 'TOKEN_TO_META_SET',
|
||||
UNIT_META_SET = 'UNIT_META_SET',
|
||||
|
@ -5,6 +5,7 @@ import { inputGasLimit, TInputGasLimit } from 'actions/transaction';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from 'reducers';
|
||||
import { sanitizeNumericalInput } from 'libs/values';
|
||||
import { getSchedulingToggle } from 'selectors/transaction';
|
||||
|
||||
const defaultGasLimit = '21000';
|
||||
|
||||
@ -18,16 +19,24 @@ export interface CallBackProps {
|
||||
interface DispatchProps {
|
||||
inputGasLimit: TInputGasLimit;
|
||||
}
|
||||
|
||||
interface OwnProps {
|
||||
gasLimit: string | null;
|
||||
scheduling: boolean;
|
||||
|
||||
withProps(props: CallBackProps): React.ReactElement<any> | null;
|
||||
}
|
||||
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
class GasLimitFieldClass extends Component<Props, {}> {
|
||||
class GasLimitFieldClass extends Component<Props> {
|
||||
public componentDidMount() {
|
||||
const { gasLimit } = this.props;
|
||||
const { gasLimit, scheduling } = this.props;
|
||||
|
||||
if (scheduling) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gasLimit) {
|
||||
this.props.inputGasLimit(gasLimit);
|
||||
} else {
|
||||
@ -45,7 +54,12 @@ class GasLimitFieldClass extends Component<Props, {}> {
|
||||
};
|
||||
}
|
||||
|
||||
const GasLimitField = connect(null, { inputGasLimit })(GasLimitFieldClass);
|
||||
const GasLimitField = connect(
|
||||
(state: AppState) => ({
|
||||
scheduling: getSchedulingToggle(state).value
|
||||
}),
|
||||
{ inputGasLimit }
|
||||
)(GasLimitFieldClass);
|
||||
|
||||
interface DefaultGasLimitFieldProps {
|
||||
withProps(props: CallBackProps): React.ReactElement<any> | null;
|
||||
|
@ -11,7 +11,7 @@ export const ScheduleTimestampField: React.SFC<Props> = ({ isReadOnly }) => (
|
||||
withProps={({ currentScheduleTimestamp, isValid, onChange, readOnly }) => (
|
||||
<div className="input-group-wrapper">
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('SCHEDULE_timestamp')}</div>
|
||||
<div className="input-group-header">{translate('SCHEDULE_TIMESTAMP')}</div>
|
||||
<input
|
||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
||||
type="text"
|
||||
|
@ -0,0 +1,62 @@
|
||||
import { connect } from 'react-redux';
|
||||
import React, { Component } from 'react';
|
||||
import { AppState } from 'reducers';
|
||||
import { setScheduleDepositField, TSetScheduleDepositField } from 'actions/transaction';
|
||||
import { translateRaw } from 'translations';
|
||||
import { Input } from 'components/ui';
|
||||
import { getScheduleDeposit, isValidScheduleDeposit, getDecimal } from 'selectors/transaction';
|
||||
import { toWei } from 'libs/units';
|
||||
|
||||
interface OwnProps {
|
||||
decimal: number;
|
||||
scheduleDeposit: any;
|
||||
validScheduleDeposit: boolean;
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
setScheduleDepositField: TSetScheduleDepositField;
|
||||
}
|
||||
|
||||
type Props = OwnProps & DispatchProps;
|
||||
|
||||
class ScheduleDepositFieldClass extends Component<Props> {
|
||||
public render() {
|
||||
const { scheduleDeposit, validScheduleDeposit } = this.props;
|
||||
|
||||
return (
|
||||
<div className="input-group-wrapper">
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translateRaw('SCHEDULE_DEPOSIT')}</div>
|
||||
<Input
|
||||
className={!!scheduleDeposit.raw && !validScheduleDeposit ? 'invalid' : ''}
|
||||
type="number"
|
||||
placeholder={translateRaw('SCHEDULE_DEPOSIT_PLACEHOLDER')}
|
||||
value={scheduleDeposit.raw}
|
||||
onChange={this.handleDepositChange}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private handleDepositChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||
const { decimal } = this.props;
|
||||
const { value } = ev.currentTarget;
|
||||
|
||||
this.props.setScheduleDepositField({
|
||||
raw: value,
|
||||
value: value ? toWei(value, decimal) : null
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const ScheduleDepositField = connect(
|
||||
(state: AppState) => ({
|
||||
decimal: getDecimal(state),
|
||||
scheduleDeposit: getScheduleDeposit(state),
|
||||
validScheduleDeposit: isValidScheduleDeposit(state)
|
||||
}),
|
||||
{
|
||||
setScheduleDepositField
|
||||
}
|
||||
)(ScheduleDepositFieldClass);
|
@ -43,7 +43,7 @@ class ScheduleGasPriceFieldClass extends React.Component<Props> {
|
||||
|
||||
this.props.setScheduleGasPriceField({
|
||||
raw: value,
|
||||
value: gasPriceToBase(parseInt(value, 10))
|
||||
value: value ? gasPriceToBase(parseInt(value, 10)) : null
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import { WindowStartInputFactory } from './WindowStartInputFactory';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { ICurrentWindowStart } from 'selectors/transaction';
|
||||
import { getLatestBlock } from 'selectors/config';
|
||||
import { AppState } from 'reducers';
|
||||
|
||||
interface DispatchProps {
|
||||
setCurrentWindowStart: TSetCurrentWindowStart;
|
||||
@ -11,6 +13,7 @@ interface DispatchProps {
|
||||
|
||||
interface OwnProps {
|
||||
windowStart: string | null;
|
||||
latestBlock: string;
|
||||
withProps(props: CallbackProps): React.ReactElement<any> | null;
|
||||
}
|
||||
|
||||
@ -25,9 +28,12 @@ type Props = DispatchProps & OwnProps;
|
||||
|
||||
class WindowStartFieldFactoryClass extends React.Component<Props> {
|
||||
public componentDidMount() {
|
||||
const { windowStart } = this.props;
|
||||
const { latestBlock, windowStart } = this.props;
|
||||
|
||||
if (windowStart) {
|
||||
this.props.setCurrentWindowStart(windowStart);
|
||||
} else {
|
||||
this.props.setCurrentWindowStart(latestBlock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,9 +49,12 @@ class WindowStartFieldFactoryClass extends React.Component<Props> {
|
||||
};
|
||||
}
|
||||
|
||||
const WindowStartFieldFactory = connect(null, { setCurrentWindowStart })(
|
||||
WindowStartFieldFactoryClass
|
||||
);
|
||||
const WindowStartFieldFactory = connect(
|
||||
(state: AppState) => ({
|
||||
latestBlock: getLatestBlock(state)
|
||||
}),
|
||||
{ setCurrentWindowStart }
|
||||
)(WindowStartFieldFactoryClass);
|
||||
|
||||
interface DefaultWindowStartFieldProps {
|
||||
withProps(props: CallbackProps): React.ReactElement<any> | null;
|
||||
|
@ -1,3 +1,5 @@
|
||||
@import 'common/sass/variables';
|
||||
|
||||
.scheduled-tx-settings {
|
||||
padding: 0 20px 20px 20px;
|
||||
border: 1px solid #e5ecf3;
|
||||
@ -11,7 +13,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.vcenter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.vcenter-sm {
|
||||
@media (min-width: $screen-sm) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
@ -7,7 +7,8 @@ import {
|
||||
TimeBountyField,
|
||||
WindowStartField,
|
||||
ScheduleGasPriceField,
|
||||
ScheduleGasLimitField
|
||||
ScheduleGasLimitField,
|
||||
ScheduleDepositField
|
||||
} from '.';
|
||||
import { ScheduleTimezoneDropDown, ScheduleTimestampField, ScheduleType } from 'components';
|
||||
import './ScheduleFields.scss';
|
||||
@ -25,7 +26,7 @@ class ScheduleFieldsClass extends React.Component<Props> {
|
||||
<div className="scheduled-tx-settings_title">Scheduled Transaction Settings</div>
|
||||
<br />
|
||||
|
||||
<div className="row form-group vcenter">
|
||||
<div className="row form-group vcenter-sm">
|
||||
<div className="col-xs-12 col-sm-6 col-md-3 col-md-push-9">
|
||||
<ScheduleType />
|
||||
</div>
|
||||
@ -58,6 +59,9 @@ class ScheduleFieldsClass extends React.Component<Props> {
|
||||
<div className="col-xs-6">
|
||||
<TimeBountyField />
|
||||
</div>
|
||||
<div className="col-xs-6">
|
||||
<ScheduleDepositField />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row form-group">
|
||||
|
@ -4,4 +4,5 @@ export * from './Fields/WindowSize/WindowSizeField';
|
||||
export * from './Fields/SchedulingToggle/SchedulingToggle';
|
||||
export * from './Fields/ScheduleGasPriceField';
|
||||
export * from './Fields/ScheduleGasLimitField';
|
||||
export * from './Fields/ScheduleDepositField';
|
||||
export * from './ScheduleFields';
|
||||
|
@ -11,7 +11,6 @@ export const EAC_SCHEDULING_CONFIG = {
|
||||
FEE: new BN('2242000000000000'), // $2
|
||||
FEE_MULTIPLIER: new BN('2'),
|
||||
FUTURE_EXECUTION_COST: new BN('180000'),
|
||||
REQUIRED_DEPOSIT: 0,
|
||||
SCHEDULING_GAS_LIMIT: new BN('1500000'),
|
||||
TIME_BOUNTY_MIN,
|
||||
TIME_BOUNTY_DEFAULT: TIME_BOUNTY_MIN,
|
||||
@ -68,8 +67,12 @@ export const getScheduleData = (
|
||||
windowStart: any,
|
||||
callGasPrice: BN | null,
|
||||
timeBounty: BN | null,
|
||||
requiredDeposit: any
|
||||
requiredDeposit: BN | null
|
||||
) => {
|
||||
if (!requiredDeposit || requiredDeposit.lt(new BN(0))) {
|
||||
requiredDeposit = new BN(0);
|
||||
}
|
||||
|
||||
if (
|
||||
!callValue ||
|
||||
!callGas ||
|
||||
|
@ -40,7 +40,8 @@ const INITIAL_STATE: State = {
|
||||
scheduleGasPrice: {
|
||||
raw: EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK.toString(),
|
||||
value: gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK)
|
||||
}
|
||||
},
|
||||
scheduleDeposit: { raw: '', value: null }
|
||||
};
|
||||
|
||||
const updateField = (key: keyof State): Reducer<State> => (state: State, action: FieldAction) => ({
|
||||
@ -106,6 +107,8 @@ export const fields = (
|
||||
return updateField('scheduleGasLimit')(state, action);
|
||||
case TK.SCHEDULE_GAS_PRICE_FIELD_SET:
|
||||
return updateField('scheduleGasPrice')(state, action);
|
||||
case TK.SCHEDULE_DEPOSIT_FIELD_SET:
|
||||
return updateField('scheduleDeposit')(state, action);
|
||||
case TK.TOKEN_TO_ETHER_SWAP:
|
||||
return tokenToEther(state, action);
|
||||
case TK.ETHER_TO_TOKEN_SWAP:
|
||||
|
@ -9,7 +9,8 @@ import {
|
||||
SetScheduleTypeAction,
|
||||
SetSchedulingToggleAction,
|
||||
SetScheduleGasPriceFieldAction,
|
||||
SetScheduleGasLimitFieldAction
|
||||
SetScheduleGasLimitFieldAction,
|
||||
SetScheduleDepositFieldAction
|
||||
} from 'actions/transaction';
|
||||
import { Wei } from 'libs/units';
|
||||
|
||||
@ -28,4 +29,5 @@ export interface State {
|
||||
scheduleType: SetScheduleTypeAction['payload'];
|
||||
scheduleGasLimit: SetScheduleGasLimitFieldAction['payload'];
|
||||
scheduleGasPrice: SetScheduleGasPriceFieldAction['payload'];
|
||||
scheduleDeposit: SetScheduleDepositFieldAction['payload'];
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import {
|
||||
getDataExists,
|
||||
getGasPrice,
|
||||
getGasLimit,
|
||||
getScheduleGasLimit
|
||||
getScheduleGasLimit,
|
||||
getScheduleDeposit
|
||||
} from 'selectors/transaction';
|
||||
import { isNetworkUnit } from 'selectors/config';
|
||||
import { getAddressMessage, AddressMessage } from 'config';
|
||||
import BN from 'bn.js';
|
||||
|
||||
interface ICurrentValue {
|
||||
raw: string;
|
||||
@ -55,6 +57,16 @@ const isValidScheduleGasPrice = (state: AppState): boolean =>
|
||||
const isValidScheduleGasLimit = (state: AppState): boolean =>
|
||||
gasLimitValidator(getScheduleGasLimit(state).raw);
|
||||
|
||||
const isValidScheduleDeposit = (state: AppState): boolean => {
|
||||
const depositValue = getScheduleDeposit(state).value;
|
||||
|
||||
if (!depositValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return depositValue.gte(new BN('0'));
|
||||
};
|
||||
|
||||
function getCurrentToAddressMessage(state: AppState): AddressMessage | undefined {
|
||||
const to = getCurrentTo(state);
|
||||
return getAddressMessage(to.raw);
|
||||
@ -71,5 +83,6 @@ export {
|
||||
isValidGasLimit,
|
||||
isValidScheduleGasLimit,
|
||||
isValidScheduleGasPrice,
|
||||
isValidScheduleDeposit,
|
||||
getCurrentToAddressMessage
|
||||
};
|
||||
|
@ -18,6 +18,7 @@ const getScheduleType = (state: AppState) => getFields(state).scheduleType;
|
||||
const getSchedulingToggle = (state: AppState) => getFields(state).schedulingToggle;
|
||||
const getScheduleGasLimit = (state: AppState) => getFields(state).scheduleGasLimit;
|
||||
const getScheduleGasPrice = (state: AppState) => getFields(state).scheduleGasPrice;
|
||||
const getScheduleDeposit = (state: AppState) => getFields(state).scheduleDeposit;
|
||||
|
||||
const getDataExists = (state: AppState) => {
|
||||
const { value } = getData(state);
|
||||
@ -51,5 +52,6 @@ export {
|
||||
getScheduleType,
|
||||
getSchedulingToggle,
|
||||
getScheduleGasLimit,
|
||||
getScheduleGasPrice
|
||||
getScheduleGasPrice,
|
||||
getScheduleDeposit
|
||||
};
|
||||
|
@ -33,6 +33,9 @@ export const isFullTx = (
|
||||
delete partialParamsToCheck.windowSize;
|
||||
delete partialParamsToCheck.scheduleTimestamp;
|
||||
delete partialParamsToCheck.schedulingToggle;
|
||||
delete partialParamsToCheck.scheduleDeposit;
|
||||
delete partialParamsToCheck.scheduleGasLimit;
|
||||
delete partialParamsToCheck.scheduleGasPrice;
|
||||
|
||||
const validPartialParams = Object.values(partialParamsToCheck).reduce<boolean>(
|
||||
(isValid, v: AppState['transaction']['fields'] & ICurrentTo & ICurrentValue) =>
|
||||
|
@ -29,7 +29,9 @@ import {
|
||||
getScheduleGasPrice,
|
||||
isValidScheduleGasPrice,
|
||||
isValidScheduleGasLimit,
|
||||
getScheduleGasLimit
|
||||
getScheduleGasLimit,
|
||||
isValidScheduleDeposit,
|
||||
getScheduleDeposit
|
||||
} from 'selectors/transaction';
|
||||
import { Wei, Address, gasPriceToBase } from 'libs/units';
|
||||
import { getTransactionFields } from 'libs/transaction/utils/ether';
|
||||
@ -92,13 +94,16 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
||||
const scheduleGasPriceValid = isValidScheduleGasPrice(state);
|
||||
const scheduleGasLimit = getScheduleGasLimit(state);
|
||||
const scheduleGasLimitValid = isValidScheduleGasLimit(state);
|
||||
const depositValid = isValidScheduleDeposit(state);
|
||||
const deposit = getScheduleDeposit(state);
|
||||
|
||||
const isFullTransaction =
|
||||
isFullTx(state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit) &&
|
||||
(windowStartValid || scheduleTimestampValid) &&
|
||||
windowSizeValid &&
|
||||
scheduleGasPriceValid &&
|
||||
scheduleGasLimitValid;
|
||||
scheduleGasLimitValid &&
|
||||
depositValid;
|
||||
|
||||
const transactionData = getScheduleData(
|
||||
currentTo.raw,
|
||||
@ -109,7 +114,7 @@ const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
||||
windowStart.value,
|
||||
scheduleGasPrice.value,
|
||||
timeBounty.value,
|
||||
EAC_SCHEDULING_CONFIG.REQUIRED_DEPOSIT
|
||||
deposit.value
|
||||
);
|
||||
|
||||
const endowment = calcEACEndowment(
|
||||
|
@ -29,7 +29,8 @@ describe('fields reducer', () => {
|
||||
raw: EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK.toString(),
|
||||
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 }
|
||||
};
|
||||
const testPayload = { raw: 'test', value: null };
|
||||
|
||||
|
@ -71,6 +71,10 @@ describe('fields selector', () => {
|
||||
scheduleGasLimit: {
|
||||
raw: '21000',
|
||||
value: Wei('21000')
|
||||
},
|
||||
scheduleDeposit: {
|
||||
raw: '1000000000',
|
||||
value: Wei('1000000000')
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -75,6 +75,10 @@ describe('helpers selector', () => {
|
||||
scheduleGasLimit: {
|
||||
raw: '21000',
|
||||
value: Wei('21000')
|
||||
},
|
||||
scheduleDeposit: {
|
||||
raw: '1000000000',
|
||||
value: Wei('1000000000')
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -94,7 +98,8 @@ describe('helpers selector', () => {
|
||||
scheduleTimestamp: null,
|
||||
scheduleType: 'time',
|
||||
scheduleGasPrice: Wei('1500'),
|
||||
scheduleGasLimit: Wei('21000')
|
||||
scheduleGasLimit: Wei('21000'),
|
||||
scheduleDeposit: Wei('1000000000')
|
||||
};
|
||||
expect(reduceToValues(state.transaction.fields)).toEqual(values);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user