mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-11 19:44:21 +00:00
[FEATURE] TimeBounty slider.
This commit is contained in:
parent
eb19dd9f0b
commit
d2b3d9c47f
@ -7,13 +7,16 @@ import {
|
|||||||
InputGasLimitAction,
|
InputGasLimitAction,
|
||||||
InputGasPriceAction,
|
InputGasPriceAction,
|
||||||
InputGasPriceIntentAction,
|
InputGasPriceIntentAction,
|
||||||
|
InputTimeBountyAction,
|
||||||
InputDataAction,
|
InputDataAction,
|
||||||
InputNonceAction,
|
InputNonceAction,
|
||||||
ResetAction,
|
ResetAction,
|
||||||
SetGasPriceFieldAction,
|
SetGasPriceFieldAction,
|
||||||
|
SetTimeBountyFieldAction,
|
||||||
SetWindowStartFieldAction
|
SetWindowStartFieldAction
|
||||||
} from '../actionTypes';
|
} from '../actionTypes';
|
||||||
import { TypeKeys } from 'actions/transaction/constants';
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
|
import { InputTimeBountyIntentAction } from 'actions/transaction';
|
||||||
|
|
||||||
type TInputGasLimit = typeof inputGasLimit;
|
type TInputGasLimit = typeof inputGasLimit;
|
||||||
const inputGasLimit = (payload: InputGasLimitAction['payload']) => ({
|
const inputGasLimit = (payload: InputGasLimitAction['payload']) => ({
|
||||||
@ -33,6 +36,26 @@ const inputGasPriceIntent = (payload: InputGasPriceIntentAction['payload']) => (
|
|||||||
payload
|
payload
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type TInputTimeBounty = typeof inputTimeBounty;
|
||||||
|
const inputTimeBounty = (payload: InputTimeBountyAction['payload']) => ({
|
||||||
|
type: TypeKeys.TIME_BOUNTY_INPUT,
|
||||||
|
payload
|
||||||
|
});
|
||||||
|
|
||||||
|
type TInputTimeBountyIntent = typeof inputTimeBounty;
|
||||||
|
const inputTimeBountyIntent = (payload: InputTimeBountyIntentAction['payload']) => ({
|
||||||
|
type: TypeKeys.TIME_BOUNTY_INPUT_INTENT,
|
||||||
|
payload
|
||||||
|
});
|
||||||
|
|
||||||
|
type TSetTimeBountyField = typeof setTimeBountyField;
|
||||||
|
const setTimeBountyField = (
|
||||||
|
payload: SetTimeBountyFieldAction['payload']
|
||||||
|
): SetTimeBountyFieldAction => ({
|
||||||
|
type: TypeKeys.TIME_BOUNTY_FIELD_SET,
|
||||||
|
payload
|
||||||
|
});
|
||||||
|
|
||||||
type TInputNonce = typeof inputNonce;
|
type TInputNonce = typeof inputNonce;
|
||||||
const inputNonce = (payload: InputNonceAction['payload']) => ({
|
const inputNonce = (payload: InputNonceAction['payload']) => ({
|
||||||
type: TypeKeys.NONCE_INPUT,
|
type: TypeKeys.NONCE_INPUT,
|
||||||
@ -99,6 +122,8 @@ export {
|
|||||||
TInputGasLimit,
|
TInputGasLimit,
|
||||||
TInputGasPrice,
|
TInputGasPrice,
|
||||||
TInputGasPriceIntent,
|
TInputGasPriceIntent,
|
||||||
|
TInputTimeBounty,
|
||||||
|
TInputTimeBountyIntent,
|
||||||
TInputNonce,
|
TInputNonce,
|
||||||
TInputData,
|
TInputData,
|
||||||
TSetGasLimitField,
|
TSetGasLimitField,
|
||||||
@ -108,10 +133,14 @@ export {
|
|||||||
TSetValueField,
|
TSetValueField,
|
||||||
TSetGasPriceField,
|
TSetGasPriceField,
|
||||||
TSetWindowStartField,
|
TSetWindowStartField,
|
||||||
|
TSetTimeBountyField,
|
||||||
TReset,
|
TReset,
|
||||||
inputGasLimit,
|
inputGasLimit,
|
||||||
inputGasPrice,
|
inputGasPrice,
|
||||||
inputGasPriceIntent,
|
inputGasPriceIntent,
|
||||||
|
inputTimeBounty,
|
||||||
|
inputTimeBountyIntent,
|
||||||
|
setTimeBountyField,
|
||||||
inputNonce,
|
inputNonce,
|
||||||
inputData,
|
inputData,
|
||||||
setGasLimitField,
|
setGasLimitField,
|
||||||
|
@ -14,6 +14,14 @@ interface InputGasPriceIntentAction {
|
|||||||
type: TypeKeys.GAS_PRICE_INPUT_INTENT;
|
type: TypeKeys.GAS_PRICE_INPUT_INTENT;
|
||||||
payload: string;
|
payload: string;
|
||||||
}
|
}
|
||||||
|
interface InputTimeBountyAction {
|
||||||
|
type: TypeKeys.TIME_BOUNTY_INPUT;
|
||||||
|
payload: string;
|
||||||
|
}
|
||||||
|
interface InputTimeBountyIntentAction {
|
||||||
|
type: TypeKeys.TIME_BOUNTY_INPUT_INTENT;
|
||||||
|
payload: string;
|
||||||
|
}
|
||||||
interface InputDataAction {
|
interface InputDataAction {
|
||||||
type: TypeKeys.DATA_FIELD_INPUT;
|
type: TypeKeys.DATA_FIELD_INPUT;
|
||||||
payload: string;
|
payload: string;
|
||||||
@ -43,6 +51,14 @@ interface SetGasPriceFieldAction {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SetTimeBountyFieldAction {
|
||||||
|
type: TypeKeys.TIME_BOUNTY_FIELD_SET;
|
||||||
|
payload: {
|
||||||
|
raw: string;
|
||||||
|
value: Wei | null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface SetDataFieldAction {
|
interface SetDataFieldAction {
|
||||||
type: TypeKeys.DATA_FIELD_SET;
|
type: TypeKeys.DATA_FIELD_SET;
|
||||||
payload: {
|
payload: {
|
||||||
@ -92,12 +108,15 @@ type FieldAction =
|
|||||||
| SetNonceFieldAction
|
| SetNonceFieldAction
|
||||||
| SetValueFieldAction
|
| SetValueFieldAction
|
||||||
| SetGasPriceFieldAction
|
| SetGasPriceFieldAction
|
||||||
|
| SetTimeBountyFieldAction
|
||||||
| SetWindowStartFieldAction;
|
| SetWindowStartFieldAction;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
InputGasLimitAction,
|
InputGasLimitAction,
|
||||||
InputGasPriceAction,
|
InputGasPriceAction,
|
||||||
InputGasPriceIntentAction,
|
InputGasPriceIntentAction,
|
||||||
|
InputTimeBountyAction,
|
||||||
|
InputTimeBountyIntentAction,
|
||||||
InputDataAction,
|
InputDataAction,
|
||||||
InputNonceAction,
|
InputNonceAction,
|
||||||
SetGasLimitFieldAction,
|
SetGasLimitFieldAction,
|
||||||
@ -108,5 +127,6 @@ export {
|
|||||||
FieldAction,
|
FieldAction,
|
||||||
InputFieldAction,
|
InputFieldAction,
|
||||||
SetGasPriceFieldAction,
|
SetGasPriceFieldAction,
|
||||||
|
SetTimeBountyFieldAction,
|
||||||
SetWindowStartFieldAction
|
SetWindowStartFieldAction
|
||||||
};
|
};
|
||||||
|
@ -31,6 +31,8 @@ export enum TypeKeys {
|
|||||||
GAS_LIMIT_INPUT = 'GAS_LIMIT_INPUT',
|
GAS_LIMIT_INPUT = 'GAS_LIMIT_INPUT',
|
||||||
GAS_PRICE_INPUT = 'GAS_PRICE_INPUT',
|
GAS_PRICE_INPUT = 'GAS_PRICE_INPUT',
|
||||||
GAS_PRICE_INPUT_INTENT = 'GAS_PRICE_INPUT_INTENT',
|
GAS_PRICE_INPUT_INTENT = 'GAS_PRICE_INPUT_INTENT',
|
||||||
|
TIME_BOUNTY_INPUT = 'TIME_BOUNTY_INPUT',
|
||||||
|
TIME_BOUNTY_INPUT_INTENT = 'TIME_BOUNTY_INPUT_INTENT',
|
||||||
NONCE_INPUT = 'NONCE_INPUT',
|
NONCE_INPUT = 'NONCE_INPUT',
|
||||||
|
|
||||||
DATA_FIELD_SET = 'DATA_FIELD_SET',
|
DATA_FIELD_SET = 'DATA_FIELD_SET',
|
||||||
@ -39,6 +41,7 @@ export enum TypeKeys {
|
|||||||
VALUE_FIELD_SET = 'VALUE_FIELD_SET',
|
VALUE_FIELD_SET = 'VALUE_FIELD_SET',
|
||||||
NONCE_FIELD_SET = 'NONCE_FIELD_SET',
|
NONCE_FIELD_SET = 'NONCE_FIELD_SET',
|
||||||
GAS_PRICE_FIELD_SET = 'GAS_PRICE_FIELD_SET',
|
GAS_PRICE_FIELD_SET = 'GAS_PRICE_FIELD_SET',
|
||||||
|
TIME_BOUNTY_FIELD_SET = 'TIME_BOUNTY_FIELD_SET',
|
||||||
WINDOW_START_FIELD_SET = 'WINDOW_START_FIELD_SET',
|
WINDOW_START_FIELD_SET = 'WINDOW_START_FIELD_SET',
|
||||||
|
|
||||||
TOKEN_TO_META_SET = 'TOKEN_TO_META_SET',
|
TOKEN_TO_META_SET = 'TOKEN_TO_META_SET',
|
||||||
|
@ -94,8 +94,10 @@ class TXMetaDataPanel extends React.Component<Props, State> {
|
|||||||
const { offline, disableToggle, advancedGasOptions, className = '', scheduling } = this.props;
|
const { offline, disableToggle, advancedGasOptions, className = '', scheduling } = this.props;
|
||||||
const { gasPrice } = this.state;
|
const { gasPrice } = this.state;
|
||||||
const showAdvanced = this.state.sliderState === 'advanced' || offline;
|
const showAdvanced = this.state.sliderState === 'advanced' || offline;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`Gas col-md-12 ${className}`}>
|
<div className={`Gas col-md-12 ${className}`}>
|
||||||
|
<br />
|
||||||
{showAdvanced ? (
|
{showAdvanced ? (
|
||||||
<AdvancedGas
|
<AdvancedGas
|
||||||
gasPrice={gasPrice}
|
gasPrice={gasPrice}
|
||||||
|
@ -10,7 +10,7 @@ import { connect } from 'react-redux';
|
|||||||
import { getAutoGasLimitEnabled } from 'selectors/config';
|
import { getAutoGasLimitEnabled } from 'selectors/config';
|
||||||
import { isValidGasPrice } from 'selectors/transaction';
|
import { isValidGasPrice } from 'selectors/transaction';
|
||||||
import { sanitizeNumericalInput } from 'libs/values';
|
import { sanitizeNumericalInput } from 'libs/values';
|
||||||
import { Input } from 'components/ui';
|
import { Input, UnitDisplay } from 'components/ui';
|
||||||
import SchedulingFeeSummary from './SchedulingFeeSummary';
|
import SchedulingFeeSummary from './SchedulingFeeSummary';
|
||||||
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ interface OwnProps {
|
|||||||
gasPrice: AppState['transaction']['fields']['gasPrice'];
|
gasPrice: AppState['transaction']['fields']['gasPrice'];
|
||||||
options?: AdvancedOptions;
|
options?: AdvancedOptions;
|
||||||
scheduling?: boolean;
|
scheduling?: boolean;
|
||||||
|
timeBounty?: AppState['transaction']['fields']['timeBounty'];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
@ -117,7 +118,7 @@ class AdvancedGas extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderFee() {
|
private renderFee() {
|
||||||
const { gasPrice, scheduling } = this.props;
|
const { gasPrice, scheduling, timeBounty } = this.props;
|
||||||
const { feeSummary } = this.state.options;
|
const { feeSummary } = this.state.options;
|
||||||
|
|
||||||
if (!feeSummary) {
|
if (!feeSummary) {
|
||||||
@ -132,11 +133,17 @@ class AdvancedGas extends React.Component<Props, State> {
|
|||||||
render={({ gasPriceWei, gasLimit, fee, usd }) => (
|
render={({ gasPriceWei, gasLimit, fee, usd }) => (
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
{EAC_SCHEDULING_CONFIG.PAYMENT} + {gasPriceWei} * ({
|
<UnitDisplay
|
||||||
EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT
|
value={EAC_SCHEDULING_CONFIG.FEE.mul(EAC_SCHEDULING_CONFIG.FEE_MULTIPLIER)}
|
||||||
}{' '}
|
unit={'ether'}
|
||||||
+ {EAC_SCHEDULING_CONFIG.FUTURE_EXECUTION_COST} + {gasLimit}) = {fee}{' '}
|
displayShortBalance={true}
|
||||||
{usd && <span>~= ${usd} USD</span>}
|
checkOffline={true}
|
||||||
|
symbol="ETH"
|
||||||
|
/>{' '}
|
||||||
|
+ {timeBounty && timeBounty.value.toString()} + {gasPriceWei} * ({EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT.add(
|
||||||
|
EAC_SCHEDULING_CONFIG.FUTURE_EXECUTION_COST
|
||||||
|
).toString()}{' '}
|
||||||
|
+ {gasLimit}) = {fee} {usd && <span>~= ${usd} USD</span>}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -9,3 +9,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SchedulingFeeSummary {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
@ -4,11 +4,11 @@ import { connect } from 'react-redux';
|
|||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { getNetworkConfig, getOffline } from 'selectors/config';
|
import { getNetworkConfig, getOffline } from 'selectors/config';
|
||||||
import { getIsEstimating } from 'selectors/gas';
|
import { getIsEstimating } from 'selectors/gas';
|
||||||
import { getGasLimit } from 'selectors/transaction';
|
import { getGasLimit, getTimeBounty } from 'selectors/transaction';
|
||||||
import { UnitDisplay, Spinner } from 'components/ui';
|
import { UnitDisplay, Spinner } from 'components/ui';
|
||||||
import { NetworkConfig } from 'types/network';
|
import { NetworkConfig } from 'types/network';
|
||||||
import './FeeSummary.scss';
|
import './FeeSummary.scss';
|
||||||
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
import { calcEACTotalCost } from 'libs/scheduling';
|
||||||
|
|
||||||
interface RenderData {
|
interface RenderData {
|
||||||
gasPriceWei: string;
|
gasPriceWei: string;
|
||||||
@ -24,6 +24,7 @@ interface ReduxStateProps {
|
|||||||
network: NetworkConfig;
|
network: NetworkConfig;
|
||||||
isOffline: AppState['config']['meta']['offline'];
|
isOffline: AppState['config']['meta']['offline'];
|
||||||
isGasEstimating: AppState['gas']['isEstimating'];
|
isGasEstimating: AppState['gas']['isEstimating'];
|
||||||
|
timeBounty: AppState['transaction']['fields']['timeBounty'];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OwnProps {
|
interface OwnProps {
|
||||||
@ -35,7 +36,15 @@ type Props = OwnProps & ReduxStateProps;
|
|||||||
|
|
||||||
class SchedulingFeeSummary extends React.Component<Props> {
|
class SchedulingFeeSummary extends React.Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const { gasPrice, gasLimit, rates, network, isOffline, isGasEstimating } = this.props;
|
const {
|
||||||
|
gasPrice,
|
||||||
|
gasLimit,
|
||||||
|
rates,
|
||||||
|
network,
|
||||||
|
isOffline,
|
||||||
|
isGasEstimating,
|
||||||
|
timeBounty
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (isGasEstimating) {
|
if (isGasEstimating) {
|
||||||
return (
|
return (
|
||||||
@ -48,13 +57,8 @@ class SchedulingFeeSummary extends React.Component<Props> {
|
|||||||
const feeBig =
|
const feeBig =
|
||||||
gasPrice.value &&
|
gasPrice.value &&
|
||||||
gasLimit.value &&
|
gasLimit.value &&
|
||||||
gasPrice.value
|
timeBounty.value &&
|
||||||
.mul(
|
calcEACTotalCost(gasLimit.value, gasPrice.value, timeBounty.value);
|
||||||
gasLimit.value
|
|
||||||
.add(new BN(EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT))
|
|
||||||
.add(new BN(EAC_SCHEDULING_CONFIG.FUTURE_EXECUTION_COST))
|
|
||||||
)
|
|
||||||
.add(new BN(EAC_SCHEDULING_CONFIG.PAYMENT));
|
|
||||||
|
|
||||||
const fee = (
|
const fee = (
|
||||||
<UnitDisplay
|
<UnitDisplay
|
||||||
@ -80,7 +84,7 @@ class SchedulingFeeSummary extends React.Component<Props> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="FeeSummary">
|
<div className="FeeSummary SchedulingFeeSummary">
|
||||||
{this.props.render({
|
{this.props.render({
|
||||||
gasPriceWei: gasPrice.value.toString(),
|
gasPriceWei: gasPrice.value.toString(),
|
||||||
gasPriceGwei: gasPrice.raw,
|
gasPriceGwei: gasPrice.raw,
|
||||||
@ -99,7 +103,8 @@ function mapStateToProps(state: AppState): ReduxStateProps {
|
|||||||
rates: state.rates.rates,
|
rates: state.rates.rates,
|
||||||
network: getNetworkConfig(state),
|
network: getNetworkConfig(state),
|
||||||
isOffline: getOffline(state),
|
isOffline: getOffline(state),
|
||||||
isGasEstimating: getIsEstimating(state)
|
isGasEstimating: getIsEstimating(state),
|
||||||
|
timeBounty: getTimeBounty(state)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
75
common/components/TXMetaDataPanel/components/TimeBounty.tsx
Normal file
75
common/components/TXMetaDataPanel/components/TimeBounty.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Slider, { createSliderWithTooltip } from 'rc-slider';
|
||||||
|
import translate from 'translations';
|
||||||
|
import { AppState } from 'reducers';
|
||||||
|
import {
|
||||||
|
Wei,
|
||||||
|
fromTokenBase,
|
||||||
|
getDecimalFromEtherUnit,
|
||||||
|
timeBountyValueToRaw,
|
||||||
|
timeBountyRawToValue
|
||||||
|
} from 'libs/units';
|
||||||
|
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
||||||
|
const SliderWithTooltip = createSliderWithTooltip(Slider);
|
||||||
|
|
||||||
|
interface OwnProps {
|
||||||
|
timeBounty: AppState['transaction']['fields']['timeBounty'];
|
||||||
|
|
||||||
|
inputTimeBounty(rawTimeBounty: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeBounty extends React.Component<OwnProps> {
|
||||||
|
public render() {
|
||||||
|
const { timeBounty } = this.props;
|
||||||
|
|
||||||
|
const bounds = {
|
||||||
|
max: EAC_SCHEDULING_CONFIG.TIME_BOUNTY_MAX,
|
||||||
|
min: EAC_SCHEDULING_CONFIG.TIME_BOUNTY_MIN
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="flex-wrapper">
|
||||||
|
<label>{translate('SCHEDULE_bounty')} </label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="SimpleGas-input-group">
|
||||||
|
<div className="SimpleGas-slider">
|
||||||
|
<SliderWithTooltip
|
||||||
|
onChange={this.handleSlider}
|
||||||
|
min={bounds.min}
|
||||||
|
max={bounds.max}
|
||||||
|
step={bounds.min < 1 ? 0.1 : 1}
|
||||||
|
value={this.getTimeBountyRaw(timeBounty.value)}
|
||||||
|
tipFormatter={this.formatTooltip}
|
||||||
|
disabled={false}
|
||||||
|
/>
|
||||||
|
<div className="SimpleGas-slider-labels">
|
||||||
|
<span>{translate('Small')}</span>
|
||||||
|
<span>{translate('Big')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSlider = (timeBounty: number) => {
|
||||||
|
this.props.inputTimeBounty(timeBounty.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
private getTimeBountyRaw(timeBountyValue: Wei) {
|
||||||
|
return parseFloat(timeBountyValueToRaw(timeBountyValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatTooltip = (timeBounty: number) => {
|
||||||
|
const valueInETH = fromTokenBase(
|
||||||
|
timeBountyRawToValue(timeBounty),
|
||||||
|
getDecimalFromEtherUnit('ether')
|
||||||
|
);
|
||||||
|
|
||||||
|
return `${valueInETH} ETH`;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimeBounty;
|
@ -1,7 +1,67 @@
|
|||||||
|
import BN from 'bn.js';
|
||||||
|
import abi from 'ethereumjs-abi';
|
||||||
|
|
||||||
export const EAC_SCHEDULING_CONFIG = {
|
export const EAC_SCHEDULING_CONFIG = {
|
||||||
SCHEDULING_GAS_LIMIT: 1500000,
|
FEE: new BN('2242000000000000'), // $2
|
||||||
FUTURE_EXECUTION_COST: 180000,
|
FEE_MULTIPLIER: new BN('2'),
|
||||||
FEE_MULTIPLIER: 2,
|
FUTURE_EXECUTION_COST: new BN('180000'),
|
||||||
PAYMENT: 10000000,
|
REQUIRED_DEPOSIT: 0,
|
||||||
|
SCHEDULING_GAS_LIMIT: new BN('1500000'),
|
||||||
|
TIME_BOUNTY_MIN: 1, // $0.1
|
||||||
|
TIME_BOUNTY_DEFAULT: 10, // $1
|
||||||
|
TIME_BOUNTY_MAX: 100, // $10
|
||||||
|
TIME_BOUNTY_TO_WEI_MULTIPLIER: new BN('100000000000000'),
|
||||||
WINDOW_SIZE_IN_BLOCKS: 90
|
WINDOW_SIZE_IN_BLOCKS: 90
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const EAC_ADDRESSES = {
|
||||||
|
KOVAN: {
|
||||||
|
blockScheduler: '0x1afc19a7e642761ba2b55d2a45b32c7ef08269d1'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const calcEACFutureExecutionCost = (callGas: BN, gasPrice: BN, timeBounty: BN) => {
|
||||||
|
const totalGas = callGas.add(EAC_SCHEDULING_CONFIG.FUTURE_EXECUTION_COST);
|
||||||
|
|
||||||
|
return timeBounty
|
||||||
|
.add(EAC_SCHEDULING_CONFIG.FEE.mul(EAC_SCHEDULING_CONFIG.FEE_MULTIPLIER))
|
||||||
|
.add(totalGas.mul(gasPrice));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const calcEACEndowment = (callGas: BN, callValue: BN, gasPrice: BN, timeBounty: BN) =>
|
||||||
|
callValue.add(calcEACFutureExecutionCost(callGas, gasPrice, timeBounty));
|
||||||
|
|
||||||
|
export const calcEACTotalCost = (callGas: BN, gasPrice: BN, timeBounty: BN) => {
|
||||||
|
const deployCost = gasPrice.mul(EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT);
|
||||||
|
|
||||||
|
const futureExecutionCost = calcEACFutureExecutionCost(callGas, gasPrice, timeBounty);
|
||||||
|
|
||||||
|
return deployCost.add(futureExecutionCost);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getScheduleData = (
|
||||||
|
toAddress: string,
|
||||||
|
callData = '',
|
||||||
|
callGas: number,
|
||||||
|
callValue: BN | null,
|
||||||
|
windowSize: number,
|
||||||
|
windowStart: any,
|
||||||
|
gasPrice: BN | null,
|
||||||
|
timeBounty: any,
|
||||||
|
requiredDeposit: any
|
||||||
|
) => {
|
||||||
|
if (!callValue || !gasPrice || !windowStart) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return abi.simpleEncode('schedule(address,bytes,uint[8]):(address)', toAddress, callData, [
|
||||||
|
callGas,
|
||||||
|
callValue,
|
||||||
|
windowSize,
|
||||||
|
windowStart,
|
||||||
|
gasPrice,
|
||||||
|
EAC_SCHEDULING_CONFIG.FEE,
|
||||||
|
timeBounty,
|
||||||
|
requiredDeposit
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import { toBuffer, addHexPrefix } from 'ethereumjs-util';
|
import { toBuffer, addHexPrefix } from 'ethereumjs-util';
|
||||||
import { stripHexPrefix } from 'libs/values';
|
import { stripHexPrefix } from 'libs/values';
|
||||||
|
import { EAC_SCHEDULING_CONFIG } from './scheduling';
|
||||||
|
|
||||||
type UnitKey = keyof typeof Units;
|
type UnitKey = keyof typeof Units;
|
||||||
type Wei = BN;
|
type Wei = BN;
|
||||||
@ -110,7 +111,19 @@ const convertTokenBase = (value: TokenValue, oldDecimal: number, newDecimal: num
|
|||||||
return toTokenBase(fromTokenBase(value, oldDecimal), newDecimal);
|
return toTokenBase(fromTokenBase(value, oldDecimal), newDecimal);
|
||||||
};
|
};
|
||||||
|
|
||||||
const gasPricetoBase = (price: number) => toWei(price.toString(), getDecimalFromEtherUnit('gwei'));
|
const gasPriceToBase = (price: number) => toWei(price.toString(), getDecimalFromEtherUnit('gwei'));
|
||||||
|
|
||||||
|
const timeBountyRawToValue = (timeBounty: number) =>
|
||||||
|
toWei(
|
||||||
|
timeBounty.toString(),
|
||||||
|
EAC_SCHEDULING_CONFIG.TIME_BOUNTY_TO_WEI_MULTIPLIER.toString().length - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
const timeBountyValueToRaw = (timeBounty: BN) =>
|
||||||
|
baseToConvertedUnit(
|
||||||
|
timeBounty.toString(),
|
||||||
|
EAC_SCHEDULING_CONFIG.TIME_BOUNTY_TO_WEI_MULTIPLIER.toString().length - 1
|
||||||
|
);
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Data,
|
Data,
|
||||||
@ -126,5 +139,7 @@ export {
|
|||||||
UnitKey,
|
UnitKey,
|
||||||
Nonce,
|
Nonce,
|
||||||
handleValues,
|
handleValues,
|
||||||
gasPricetoBase
|
gasPriceToBase,
|
||||||
|
timeBountyRawToValue,
|
||||||
|
timeBountyValueToRaw
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
GAS_PRICE_GWEI_UPPER_BOUND
|
GAS_PRICE_GWEI_UPPER_BOUND
|
||||||
} from 'config/constants';
|
} from 'config/constants';
|
||||||
import { dPathRegex } from 'config/dpaths';
|
import { dPathRegex } from 'config/dpaths';
|
||||||
|
import { EAC_SCHEDULING_CONFIG } from './scheduling';
|
||||||
|
|
||||||
// FIXME we probably want to do checksum checks sideways
|
// FIXME we probably want to do checksum checks sideways
|
||||||
export function isValidETHAddress(address: string): boolean {
|
export function isValidETHAddress(address: string): boolean {
|
||||||
@ -148,6 +149,15 @@ export const gasPriceValidator = (gasPrice: number | string): boolean => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const timeBountyValidator = (timeBounty: number | string): boolean => {
|
||||||
|
const timeBountyFloat = typeof timeBounty === 'string' ? parseFloat(timeBounty) : timeBounty;
|
||||||
|
return (
|
||||||
|
validNumber(timeBountyFloat) &&
|
||||||
|
timeBountyFloat >= EAC_SCHEDULING_CONFIG.TIME_BOUNTY_MIN &&
|
||||||
|
timeBountyFloat <= EAC_SCHEDULING_CONFIG.TIME_BOUNTY_MAX
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const isValidByteCode = (byteCode: string) =>
|
export const isValidByteCode = (byteCode: string) =>
|
||||||
byteCode && byteCode.length > 0 && byteCode.length % 2 === 0;
|
byteCode && byteCode.length > 0 && byteCode.length % 2 === 0;
|
||||||
|
|
||||||
|
@ -10,8 +10,9 @@ import {
|
|||||||
} from 'actions/transaction';
|
} from 'actions/transaction';
|
||||||
import { Reducer } from 'redux';
|
import { Reducer } from 'redux';
|
||||||
import { State } from './typings';
|
import { State } from './typings';
|
||||||
import { gasPricetoBase } from 'libs/units';
|
import { gasPriceToBase, timeBountyRawToValue } from 'libs/units';
|
||||||
import { resetHOF } from 'reducers/transaction/shared';
|
import { resetHOF } from 'reducers/transaction/shared';
|
||||||
|
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
||||||
|
|
||||||
const INITIAL_STATE: State = {
|
const INITIAL_STATE: State = {
|
||||||
to: { raw: '', value: null },
|
to: { raw: '', value: null },
|
||||||
@ -20,7 +21,11 @@ const INITIAL_STATE: State = {
|
|||||||
value: { raw: '', value: null },
|
value: { raw: '', value: null },
|
||||||
windowStart: { raw: '', value: null },
|
windowStart: { raw: '', value: null },
|
||||||
gasLimit: { raw: '21000', value: new BN(21000) },
|
gasLimit: { raw: '21000', value: new BN(21000) },
|
||||||
gasPrice: { raw: '20', value: gasPricetoBase(20) }
|
gasPrice: { raw: '20', value: gasPriceToBase(20) },
|
||||||
|
timeBounty: {
|
||||||
|
raw: EAC_SCHEDULING_CONFIG.TIME_BOUNTY_DEFAULT.toString(),
|
||||||
|
value: timeBountyRawToValue(EAC_SCHEDULING_CONFIG.TIME_BOUNTY_DEFAULT)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateField = (key: keyof State): Reducer<State> => (state: State, action: FieldAction) => ({
|
const updateField = (key: keyof State): Reducer<State> => (state: State, action: FieldAction) => ({
|
||||||
@ -70,6 +75,8 @@ export const fields = (
|
|||||||
return updateField('nonce')(state, action);
|
return updateField('nonce')(state, action);
|
||||||
case TK.GAS_PRICE_FIELD_SET:
|
case TK.GAS_PRICE_FIELD_SET:
|
||||||
return updateField('gasPrice')(state, action);
|
return updateField('gasPrice')(state, action);
|
||||||
|
case TK.TIME_BOUNTY_FIELD_SET:
|
||||||
|
return updateField('timeBounty')(state, action);
|
||||||
case TK.WINDOW_START_FIELD_SET:
|
case TK.WINDOW_START_FIELD_SET:
|
||||||
return updateField('windowStart')(state, action);
|
return updateField('windowStart')(state, action);
|
||||||
case TK.TOKEN_TO_ETHER_SWAP:
|
case TK.TOKEN_TO_ETHER_SWAP:
|
||||||
|
@ -11,8 +11,9 @@ export interface State {
|
|||||||
to: SetToFieldAction['payload'];
|
to: SetToFieldAction['payload'];
|
||||||
data: SetDataFieldAction['payload'];
|
data: SetDataFieldAction['payload'];
|
||||||
nonce: SetNonceFieldAction['payload'];
|
nonce: SetNonceFieldAction['payload'];
|
||||||
windowStart: SetWindowStartFieldAction['payload'];
|
|
||||||
value: { raw: string; value: Wei | null }; // TODO: fix this workaround since some of the payload is optional
|
value: { raw: string; value: Wei | null }; // TODO: fix this workaround since some of the payload is optional
|
||||||
gasLimit: SetGasLimitFieldAction['payload'];
|
gasLimit: SetGasLimitFieldAction['payload'];
|
||||||
gasPrice: { raw: string; value: Wei };
|
gasPrice: { raw: string; value: Wei };
|
||||||
|
timeBounty: { raw: string; value: Wei };
|
||||||
|
windowStart: SetWindowStartFieldAction['payload'];
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,11 @@ import { call, put, takeEvery, takeLatest } from 'redux-saga/effects';
|
|||||||
import { SagaIterator, delay } from 'redux-saga';
|
import { SagaIterator, delay } from 'redux-saga';
|
||||||
import {
|
import {
|
||||||
inputGasPrice,
|
inputGasPrice,
|
||||||
|
inputTimeBounty,
|
||||||
setDataField,
|
setDataField,
|
||||||
setGasLimitField,
|
setGasLimitField,
|
||||||
setGasPriceField,
|
setGasPriceField,
|
||||||
|
setTimeBountyField,
|
||||||
setNonceField
|
setNonceField
|
||||||
} from 'actions/transaction/actionCreators';
|
} from 'actions/transaction/actionCreators';
|
||||||
import {
|
import {
|
||||||
@ -14,10 +16,20 @@ import {
|
|||||||
InputGasPriceAction,
|
InputGasPriceAction,
|
||||||
InputGasPriceIntentAction,
|
InputGasPriceIntentAction,
|
||||||
InputNonceAction,
|
InputNonceAction,
|
||||||
TypeKeys
|
TypeKeys,
|
||||||
|
InputTimeBountyIntentAction,
|
||||||
|
InputTimeBountyAction
|
||||||
} from 'actions/transaction';
|
} from 'actions/transaction';
|
||||||
import { isValidHex, isValidNonce, gasPriceValidator, gasLimitValidator } from 'libs/validators';
|
import {
|
||||||
import { Data, Wei, Nonce, gasPricetoBase } from 'libs/units';
|
isValidHex,
|
||||||
|
isValidNonce,
|
||||||
|
gasPriceValidator,
|
||||||
|
gasLimitValidator,
|
||||||
|
timeBountyValidator
|
||||||
|
} from 'libs/validators';
|
||||||
|
import { Data, Wei, Nonce, gasPriceToBase, timeBountyRawToValue } from 'libs/units';
|
||||||
|
|
||||||
|
const SLIDER_DEBOUNCE_INPUT_DELAY = 300;
|
||||||
|
|
||||||
export function* handleDataInput({ payload }: InputDataAction): SagaIterator {
|
export function* handleDataInput({ payload }: InputDataAction): SagaIterator {
|
||||||
const validData: boolean = yield call(isValidHex, payload);
|
const validData: boolean = yield call(isValidHex, payload);
|
||||||
@ -35,13 +47,13 @@ export function* handleGasPriceInput({ payload }: InputGasPriceAction): SagaIter
|
|||||||
yield put(
|
yield put(
|
||||||
setGasPriceField({
|
setGasPriceField({
|
||||||
raw: payload,
|
raw: payload,
|
||||||
value: validGasPrice ? gasPricetoBase(priceFloat) : new BN(0)
|
value: validGasPrice ? gasPriceToBase(priceFloat) : new BN(0)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* handleGasPriceInputIntent({ payload }: InputGasPriceIntentAction): SagaIterator {
|
export function* handleGasPriceInputIntent({ payload }: InputGasPriceIntentAction): SagaIterator {
|
||||||
yield call(delay, 300);
|
yield call(delay, SLIDER_DEBOUNCE_INPUT_DELAY);
|
||||||
// Important to put and not fork handleGasPriceInput, we want
|
// Important to put and not fork handleGasPriceInput, we want
|
||||||
// action to go to reducers.
|
// action to go to reducers.
|
||||||
yield put(inputGasPrice(payload));
|
yield put(inputGasPrice(payload));
|
||||||
@ -52,10 +64,32 @@ export function* handleNonceInput({ payload }: InputNonceAction): SagaIterator {
|
|||||||
yield put(setNonceField({ raw: payload, value: validNonce ? Nonce(payload) : null }));
|
yield put(setNonceField({ raw: payload, value: validNonce ? Nonce(payload) : null }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* handleTimeBountyInputIntent({
|
||||||
|
payload
|
||||||
|
}: InputTimeBountyIntentAction): SagaIterator {
|
||||||
|
yield call(delay, SLIDER_DEBOUNCE_INPUT_DELAY);
|
||||||
|
|
||||||
|
yield put(inputTimeBounty(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* handleTimeBountyInput({ payload }: InputTimeBountyAction): SagaIterator {
|
||||||
|
const timeBountyFloat = parseFloat(payload);
|
||||||
|
const validTimeBounty: boolean = yield call(timeBountyValidator, timeBountyFloat);
|
||||||
|
|
||||||
|
yield put(
|
||||||
|
setTimeBountyField({
|
||||||
|
raw: payload,
|
||||||
|
value: validTimeBounty ? timeBountyRawToValue(timeBountyFloat) : new BN(0)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const fields = [
|
export const fields = [
|
||||||
takeEvery(TypeKeys.DATA_FIELD_INPUT, handleDataInput),
|
takeEvery(TypeKeys.DATA_FIELD_INPUT, handleDataInput),
|
||||||
takeEvery(TypeKeys.GAS_LIMIT_INPUT, handleGasLimitInput),
|
takeEvery(TypeKeys.GAS_LIMIT_INPUT, handleGasLimitInput),
|
||||||
takeEvery(TypeKeys.GAS_PRICE_INPUT, handleGasPriceInput),
|
takeEvery(TypeKeys.GAS_PRICE_INPUT, handleGasPriceInput),
|
||||||
|
takeEvery(TypeKeys.TIME_BOUNTY_INPUT, handleTimeBountyInput),
|
||||||
takeEvery(TypeKeys.NONCE_INPUT, handleNonceInput),
|
takeEvery(TypeKeys.NONCE_INPUT, handleNonceInput),
|
||||||
takeLatest(TypeKeys.GAS_PRICE_INPUT_INTENT, handleGasPriceInputIntent)
|
takeLatest(TypeKeys.GAS_PRICE_INPUT_INTENT, handleGasPriceInputIntent),
|
||||||
|
takeLatest(TypeKeys.TIME_BOUNTY_INPUT_INTENT, handleTimeBountyInputIntent)
|
||||||
];
|
];
|
||||||
|
@ -10,6 +10,7 @@ const getGasLimit = (state: AppState) => getFields(state).gasLimit;
|
|||||||
const getGasPrice = (state: AppState) => getFields(state).gasPrice;
|
const getGasPrice = (state: AppState) => getFields(state).gasPrice;
|
||||||
const getValue = (state: AppState) => getFields(state).value;
|
const getValue = (state: AppState) => getFields(state).value;
|
||||||
const getNonce = (state: AppState) => getFields(state).nonce;
|
const getNonce = (state: AppState) => getFields(state).nonce;
|
||||||
|
const getTimeBounty = (state: AppState) => getFields(state).timeBounty;
|
||||||
const getWindowStart = (state: AppState) => getFields(state).windowStart;
|
const getWindowStart = (state: AppState) => getFields(state).windowStart;
|
||||||
|
|
||||||
const getDataExists = (state: AppState) => {
|
const getDataExists = (state: AppState) => {
|
||||||
@ -37,5 +38,6 @@ export {
|
|||||||
getGasPrice,
|
getGasPrice,
|
||||||
getDataExists,
|
getDataExists,
|
||||||
getValidGasCost,
|
getValidGasCost,
|
||||||
|
getTimeBounty,
|
||||||
getWindowStart
|
getWindowStart
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { getCurrentTo, getCurrentValue } from './current';
|
import { getCurrentTo, getCurrentValue } from './current';
|
||||||
import { getFields, getData, getWindowStart, getNonce } from './fields';
|
import { getFields, getData, getWindowStart, getNonce, getTimeBounty } from './fields';
|
||||||
import { makeTransaction, IHexStrTransaction } from 'libs/transaction';
|
import { makeTransaction, IHexStrTransaction } from 'libs/transaction';
|
||||||
import EthTx from 'ethereumjs-tx';
|
import EthTx from 'ethereumjs-tx';
|
||||||
import { getUnit } from 'selectors/transaction/meta';
|
import { getUnit } from 'selectors/transaction/meta';
|
||||||
@ -17,8 +17,12 @@ import { Wei, Address } from 'libs/units';
|
|||||||
import { getTransactionFields } from 'libs/transaction/utils/ether';
|
import { getTransactionFields } from 'libs/transaction/utils/ether';
|
||||||
import { getNetworkConfig, getLatestBlock } from 'selectors/config';
|
import { getNetworkConfig, getLatestBlock } from 'selectors/config';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import abi from 'ethereumjs-abi';
|
import {
|
||||||
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
EAC_SCHEDULING_CONFIG,
|
||||||
|
calcEACEndowment,
|
||||||
|
EAC_ADDRESSES,
|
||||||
|
getScheduleData
|
||||||
|
} from 'libs/scheduling';
|
||||||
|
|
||||||
const getTransactionState = (state: AppState) => state.transaction;
|
const getTransactionState = (state: AppState) => state.transaction;
|
||||||
|
|
||||||
@ -55,54 +59,6 @@ const getTransaction = (state: AppState): IGetTransaction => {
|
|||||||
return { transaction, isFullTransaction };
|
return { transaction, isFullTransaction };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getScheduleData = (
|
|
||||||
toAddress: string,
|
|
||||||
callData = '',
|
|
||||||
callGas: number,
|
|
||||||
callValue: BN | null,
|
|
||||||
windowSize: number,
|
|
||||||
windowStart: any,
|
|
||||||
gasPrice: BN | null,
|
|
||||||
fee: number,
|
|
||||||
payment: any,
|
|
||||||
requiredDeposit: any
|
|
||||||
) => {
|
|
||||||
if (!callValue || !gasPrice || !windowStart) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return abi.simpleEncode('schedule(address,bytes,uint[8]):(address)', toAddress, callData, [
|
|
||||||
callGas,
|
|
||||||
callValue,
|
|
||||||
windowSize,
|
|
||||||
windowStart,
|
|
||||||
gasPrice,
|
|
||||||
fee,
|
|
||||||
payment,
|
|
||||||
requiredDeposit
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const calcEACEndowment = (
|
|
||||||
callGas: number | string | BN,
|
|
||||||
callValue: number | string | BN,
|
|
||||||
gasPrice: number | string | BN,
|
|
||||||
fee: number | string | BN,
|
|
||||||
payment: number | string | BN
|
|
||||||
) => {
|
|
||||||
const callGasBN = new BN(callGas);
|
|
||||||
const callValueBN = new BN(callValue);
|
|
||||||
const gasPriceBN = new BN(gasPrice);
|
|
||||||
const feeBN = new BN(fee);
|
|
||||||
const paymentBN = new BN(payment);
|
|
||||||
|
|
||||||
return paymentBN
|
|
||||||
.add(feeBN.mul(new BN(2)))
|
|
||||||
.add(callGasBN.mul(gasPriceBN))
|
|
||||||
.add(gasPriceBN.mul(new BN(EAC_SCHEDULING_CONFIG.FUTURE_EXECUTION_COST)))
|
|
||||||
.add(callValueBN);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction => {
|
const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction => {
|
||||||
const currentTo = getCurrentTo(state);
|
const currentTo = getCurrentTo(state);
|
||||||
const currentValue = getCurrentValue(state);
|
const currentValue = getCurrentValue(state);
|
||||||
@ -115,6 +71,7 @@ const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction =>
|
|||||||
const gasLimit = getGasLimit(state);
|
const gasLimit = getGasLimit(state);
|
||||||
const nonce = getNonce(state);
|
const nonce = getNonce(state);
|
||||||
const gasPrice = getGasPrice(state);
|
const gasPrice = getGasPrice(state);
|
||||||
|
const timeBounty = getTimeBounty(state);
|
||||||
|
|
||||||
const isFullTransaction = isFullTx(
|
const isFullTransaction = isFullTx(
|
||||||
state,
|
state,
|
||||||
@ -126,43 +83,29 @@ const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction =>
|
|||||||
unit
|
unit
|
||||||
);
|
);
|
||||||
|
|
||||||
const WINDOW_SIZE_IN_BLOCKS = EAC_SCHEDULING_CONFIG.WINDOW_SIZE_IN_BLOCKS;
|
|
||||||
const SCHEDULING_GAS_LIMIT = new BN(EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT);
|
|
||||||
const EAC_FEE = 0;
|
|
||||||
const PAYMENT = EAC_SCHEDULING_CONFIG.PAYMENT;
|
|
||||||
const REQUIRED_DEPOSIT = 0;
|
|
||||||
|
|
||||||
const EAC_ADDRESSES = {
|
|
||||||
KOVAN: {
|
|
||||||
blockScheduler: '0x1afc19a7e642761ba2b55d2a45b32c7ef08269d1'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const transactionData = getScheduleData(
|
const transactionData = getScheduleData(
|
||||||
currentTo.raw,
|
currentTo.raw,
|
||||||
callData.raw,
|
callData.raw,
|
||||||
parseInt(gasLimit.raw, 10),
|
parseInt(gasLimit.raw, 10),
|
||||||
currentValue.value,
|
currentValue.value,
|
||||||
WINDOW_SIZE_IN_BLOCKS,
|
EAC_SCHEDULING_CONFIG.WINDOW_SIZE_IN_BLOCKS,
|
||||||
windowStart.value,
|
windowStart.value,
|
||||||
gasPrice.value,
|
gasPrice.value,
|
||||||
EAC_FEE,
|
timeBounty.value,
|
||||||
PAYMENT,
|
EAC_SCHEDULING_CONFIG.REQUIRED_DEPOSIT
|
||||||
REQUIRED_DEPOSIT
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const endowment = calcEACEndowment(
|
const endowment = calcEACEndowment(
|
||||||
gasLimit.value || 21000,
|
gasLimit.value || new BN(21000),
|
||||||
currentValue.value || 0,
|
currentValue.value || new BN(0),
|
||||||
gasPrice.value,
|
gasPrice.value,
|
||||||
EAC_FEE,
|
timeBounty.value
|
||||||
PAYMENT
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const transactionOptions = {
|
const transactionOptions = {
|
||||||
to: Address(EAC_ADDRESSES.KOVAN.blockScheduler),
|
to: Address(EAC_ADDRESSES.KOVAN.blockScheduler),
|
||||||
data: transactionData,
|
data: transactionData,
|
||||||
gasLimit: SCHEDULING_GAS_LIMIT,
|
gasLimit: EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT,
|
||||||
gasPrice: gasPrice.value,
|
gasPrice: gasPrice.value,
|
||||||
nonce: new BN(0),
|
nonce: new BN(0),
|
||||||
value: endowment
|
value: endowment
|
||||||
@ -229,6 +172,5 @@ export {
|
|||||||
getTransactionState,
|
getTransactionState,
|
||||||
getGasCost,
|
getGasCost,
|
||||||
nonStandardTransaction,
|
nonStandardTransaction,
|
||||||
serializedAndTransactionFieldsMatch,
|
serializedAndTransactionFieldsMatch
|
||||||
getScheduleData
|
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,7 @@ import createSagaMiddleware from 'redux-saga';
|
|||||||
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
|
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
|
||||||
import RootReducer, { AppState } from 'reducers';
|
import RootReducer, { AppState } from 'reducers';
|
||||||
import sagas from 'sagas';
|
import sagas from 'sagas';
|
||||||
import { gasPricetoBase } from 'libs/units';
|
import { gasPriceToBase } from 'libs/units';
|
||||||
import {
|
import {
|
||||||
rehydrateConfigAndCustomTokenState,
|
rehydrateConfigAndCustomTokenState,
|
||||||
getConfigAndCustomTokensStateToSubscribe
|
getConfigAndCustomTokensStateToSubscribe
|
||||||
@ -59,7 +59,7 @@ const configureStore = () => {
|
|||||||
savedTransactionState && savedTransactionState.fields.gasPrice
|
savedTransactionState && savedTransactionState.fields.gasPrice
|
||||||
? {
|
? {
|
||||||
raw: savedTransactionState.fields.gasPrice.raw,
|
raw: savedTransactionState.fields.gasPrice.raw,
|
||||||
value: gasPricetoBase(+savedTransactionState.fields.gasPrice.raw)
|
value: gasPriceToBase(+savedTransactionState.fields.gasPrice.raw)
|
||||||
}
|
}
|
||||||
: transactionInitialState.fields.gasPrice
|
: transactionInitialState.fields.gasPrice
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { TypeKeys } from 'actions/transaction/constants';
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
import { gasPricetoBase } from 'libs/units';
|
import { gasPriceToBase, timeBountyRawToValue } from 'libs/units';
|
||||||
import { fields, State } from 'reducers/transaction/fields';
|
import { fields, State } from 'reducers/transaction/fields';
|
||||||
import * as txActions from 'actions/transaction';
|
import * as txActions from 'actions/transaction';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
|
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
||||||
|
|
||||||
describe('fields reducer', () => {
|
describe('fields reducer', () => {
|
||||||
const INITIAL_STATE: State = {
|
const INITIAL_STATE: State = {
|
||||||
@ -11,7 +12,11 @@ describe('fields reducer', () => {
|
|||||||
nonce: { raw: '', value: null },
|
nonce: { raw: '', value: null },
|
||||||
value: { raw: '', value: null },
|
value: { raw: '', value: null },
|
||||||
gasLimit: { raw: '21000', value: new BN(21000) },
|
gasLimit: { raw: '21000', value: new BN(21000) },
|
||||||
gasPrice: { raw: '20', value: gasPricetoBase(20) },
|
gasPrice: { raw: '20', value: gasPriceToBase(20) },
|
||||||
|
timeBounty: {
|
||||||
|
raw: EAC_SCHEDULING_CONFIG.TIME_BOUNTY_DEFAULT.toString(),
|
||||||
|
value: timeBountyRawToValue(EAC_SCHEDULING_CONFIG.TIME_BOUNTY_DEFAULT)
|
||||||
|
},
|
||||||
windowStart: { raw: '', value: null }
|
windowStart: { raw: '', value: null }
|
||||||
};
|
};
|
||||||
const testPayload = { raw: 'test', value: null };
|
const testPayload = { raw: 'test', value: null };
|
||||||
|
@ -3,7 +3,7 @@ import { SagaIterator, delay } from 'redux-saga';
|
|||||||
import { call, put } from 'redux-saga/effects';
|
import { call, put } from 'redux-saga/effects';
|
||||||
import { setDataField, setGasLimitField, setNonceField } from 'actions/transaction/actionCreators';
|
import { setDataField, setGasLimitField, setNonceField } from 'actions/transaction/actionCreators';
|
||||||
import { isValidHex, isValidNonce, gasPriceValidator, gasLimitValidator } from 'libs/validators';
|
import { isValidHex, isValidNonce, gasPriceValidator, gasLimitValidator } from 'libs/validators';
|
||||||
import { Data, Wei, Nonce, gasPricetoBase } from 'libs/units';
|
import { Data, Wei, Nonce, gasPriceToBase } from 'libs/units';
|
||||||
import {
|
import {
|
||||||
handleDataInput,
|
handleDataInput,
|
||||||
handleGasLimitInput,
|
handleGasLimitInput,
|
||||||
@ -129,7 +129,7 @@ describe('handleGasPriceInput*', () => {
|
|||||||
put(
|
put(
|
||||||
setGasPriceField({
|
setGasPriceField({
|
||||||
raw: payload,
|
raw: payload,
|
||||||
value: gasPricetoBase(priceFloat)
|
value: gasPriceToBase(priceFloat)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -40,6 +40,10 @@ describe('fields selector', () => {
|
|||||||
raw: '1500',
|
raw: '1500',
|
||||||
value: Wei('1500')
|
value: Wei('1500')
|
||||||
},
|
},
|
||||||
|
timeBounty: {
|
||||||
|
raw: '1500',
|
||||||
|
value: Wei('1500')
|
||||||
|
},
|
||||||
windowStart: {
|
windowStart: {
|
||||||
raw: '',
|
raw: '',
|
||||||
value: null
|
value: null
|
||||||
|
@ -44,6 +44,10 @@ describe('helpers selector', () => {
|
|||||||
raw: '1500',
|
raw: '1500',
|
||||||
value: Wei('1500')
|
value: Wei('1500')
|
||||||
},
|
},
|
||||||
|
timeBounty: {
|
||||||
|
raw: '1500',
|
||||||
|
value: Wei('1500')
|
||||||
|
},
|
||||||
windowStart: {
|
windowStart: {
|
||||||
raw: '',
|
raw: '',
|
||||||
value: null
|
value: null
|
||||||
@ -59,6 +63,7 @@ describe('helpers selector', () => {
|
|||||||
nonce: new BN('0'),
|
nonce: new BN('0'),
|
||||||
to: new Buffer([0, 1, 2, 3]),
|
to: new Buffer([0, 1, 2, 3]),
|
||||||
value: Wei('1000000000'),
|
value: Wei('1000000000'),
|
||||||
|
timeBounty: Wei('1500'),
|
||||||
windowStart: null
|
windowStart: null
|
||||||
};
|
};
|
||||||
expect(reduceToValues(state.transaction.fields)).toEqual(values);
|
expect(reduceToValues(state.transaction.fields)).toEqual(values);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user