mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-11 03:26:14 +00:00
[FEATURE] Redirection to the DApp for details.
This commit is contained in:
parent
e3884fc5ae
commit
9a70d776b4
@ -4,7 +4,7 @@ import { withRouter, Switch, Redirect, HashRouter, Route, BrowserRouter } from '
|
|||||||
// Components
|
// Components
|
||||||
import Contracts from 'containers/Tabs/Contracts';
|
import Contracts from 'containers/Tabs/Contracts';
|
||||||
import ENS from 'containers/Tabs/ENS';
|
import ENS from 'containers/Tabs/ENS';
|
||||||
import Schedule from 'containers/Tabs/Schedule';
|
import ScheduleTransaction from 'containers/Tabs/ScheduleTransaction';
|
||||||
import GenerateWallet from 'containers/Tabs/GenerateWallet';
|
import GenerateWallet from 'containers/Tabs/GenerateWallet';
|
||||||
import SendTransaction from 'containers/Tabs/SendTransaction';
|
import SendTransaction from 'containers/Tabs/SendTransaction';
|
||||||
import Swap from 'containers/Tabs/Swap';
|
import Swap from 'containers/Tabs/Swap';
|
||||||
@ -82,7 +82,7 @@ class RootClass extends Component<Props, State> {
|
|||||||
<Route path="/swap" component={Swap} />
|
<Route path="/swap" component={Swap} />
|
||||||
<Route path="/contracts" component={Contracts} />
|
<Route path="/contracts" component={Contracts} />
|
||||||
<Route path="/ens" component={ENS} exact={true} />
|
<Route path="/ens" component={ENS} exact={true} />
|
||||||
<Route path="/schedule" component={Schedule} exact={true} />
|
<Route path="/schedule" component={ScheduleTransaction} exact={true} />
|
||||||
<Route path="/sign-and-verify-message" component={SignAndVerifyMessage} />
|
<Route path="/sign-and-verify-message" component={SignAndVerifyMessage} />
|
||||||
<Route path="/tx-status" component={CheckTransaction} exact={true} />
|
<Route path="/tx-status" component={CheckTransaction} exact={true} />
|
||||||
<Route path="/pushTx" component={BroadcastTx} />
|
<Route path="/pushTx" component={BroadcastTx} />
|
||||||
|
@ -3,13 +3,15 @@ import { Link } from 'react-router-dom';
|
|||||||
import translate from 'translations';
|
import translate from 'translations';
|
||||||
import { NewTabLink } from 'components/ui';
|
import { NewTabLink } from 'components/ui';
|
||||||
import { BlockExplorerConfig } from 'types/network';
|
import { BlockExplorerConfig } from 'types/network';
|
||||||
|
import { getTXDetailsCheckURL } from 'libs/scheduling';
|
||||||
|
|
||||||
export interface TransactionSucceededProps {
|
export interface TransactionSucceededProps {
|
||||||
txHash: string;
|
txHash: string;
|
||||||
blockExplorer?: BlockExplorerConfig;
|
blockExplorer?: BlockExplorerConfig;
|
||||||
|
scheduling?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TransactionSucceeded = ({ txHash, blockExplorer }: TransactionSucceededProps) => {
|
const TransactionSucceeded = ({ txHash, blockExplorer, scheduling }: TransactionSucceededProps) => {
|
||||||
let verifyBtn: React.ReactElement<string> | undefined;
|
let verifyBtn: React.ReactElement<string> | undefined;
|
||||||
if (blockExplorer) {
|
if (blockExplorer) {
|
||||||
verifyBtn = (
|
verifyBtn = (
|
||||||
@ -19,11 +21,21 @@ const TransactionSucceeded = ({ txHash, blockExplorer }: TransactionSucceededPro
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let scheduleDetailsBtn: React.ReactElement<string> | undefined;
|
||||||
|
if (scheduling) {
|
||||||
|
scheduleDetailsBtn = (
|
||||||
|
<a href={getTXDetailsCheckURL(txHash)} className="btn btn-xs">
|
||||||
|
{translate('SCHEDULE_check')}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{translate('SUCCESS_3')} {txHash}
|
{translate('SUCCESS_3')} {txHash}
|
||||||
</p>
|
</p>
|
||||||
|
{scheduleDetailsBtn}
|
||||||
{verifyBtn}
|
{verifyBtn}
|
||||||
<Link to={`/tx-status?txHash=${txHash}`} className="btn btn-xs">
|
<Link to={`/tx-status?txHash=${txHash}`} className="btn btn-xs">
|
||||||
{translate('NAV_CHECKTXSTATUS')}
|
{translate('NAV_CHECKTXSTATUS')}
|
||||||
|
@ -1,25 +1,8 @@
|
|||||||
import { GenerateTransactionFactory } from './GenerateTransactionFactory';
|
import { GenerateTransactionFactory } from './GenerateTransactionFactory';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import translate from 'translations';
|
import translate from 'translations';
|
||||||
import { ScheduleTransactionFactory } from './ScheduleTransactionFactory';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
scheduling?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GenerateTransaction: React.SFC<Props> = props => {
|
|
||||||
if (props.scheduling) {
|
|
||||||
return (
|
|
||||||
<ScheduleTransactionFactory
|
|
||||||
withProps={({ disabled, isWeb3Wallet, onClick }) => (
|
|
||||||
<button disabled={disabled} className="btn btn-info btn-block" onClick={onClick}>
|
|
||||||
{isWeb3Wallet ? translate('SCHEDULE_schedule') : translate('DEP_signtx')}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export const GenerateTransaction: React.SFC<{}> = () => {
|
||||||
return (
|
return (
|
||||||
<GenerateTransactionFactory
|
<GenerateTransactionFactory
|
||||||
withProps={({ disabled, isWeb3Wallet, onClick }) => (
|
withProps={({ disabled, isWeb3Wallet, onClick }) => (
|
||||||
|
@ -42,7 +42,7 @@ interface OwnProps {
|
|||||||
|
|
||||||
type Props = OwnProps & StateProps;
|
type Props = OwnProps & StateProps;
|
||||||
|
|
||||||
class GenerateTransactionFactoryClass extends Component<Props> {
|
export class GenerateTransactionFactoryClass extends Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
walletType,
|
walletType,
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { signTransactionRequested, TSignTransactionRequested } from 'actions/transaction';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
interface DispatchProps {
|
|
||||||
signTransactionRequested: TSignTransactionRequested;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OwnProps {
|
|
||||||
isWeb3: boolean;
|
|
||||||
withSigner(signer: TSignTransactionRequested): React.ReactElement<any> | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Container extends Component<DispatchProps & OwnProps, {}> {
|
|
||||||
public render() {
|
|
||||||
return this.props.withSigner(this.props.signTransactionRequested);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WithSigner = connect(null, { signTransactionRequested })(Container);
|
|
@ -1,88 +0,0 @@
|
|||||||
import { WithSigner } from './Container';
|
|
||||||
import EthTx from 'ethereumjs-tx';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { AppState } from 'reducers';
|
|
||||||
import {
|
|
||||||
getSchedulingTransaction,
|
|
||||||
isNetworkRequestPending,
|
|
||||||
isValidGasPrice,
|
|
||||||
isValidGasLimit,
|
|
||||||
getGasPrice,
|
|
||||||
getCurrentTo,
|
|
||||||
getCurrentValue
|
|
||||||
} from 'selectors/transaction';
|
|
||||||
import { getWalletType } from 'selectors/wallet';
|
|
||||||
import { getWindowStart } from '../../selectors/transaction/fields';
|
|
||||||
|
|
||||||
export interface CallbackProps {
|
|
||||||
disabled: boolean;
|
|
||||||
isWeb3Wallet: boolean;
|
|
||||||
onClick(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StateProps {
|
|
||||||
transaction: EthTx;
|
|
||||||
networkRequestPending: boolean;
|
|
||||||
isFullTransaction: boolean;
|
|
||||||
isWeb3Wallet: boolean;
|
|
||||||
validGasPrice: boolean;
|
|
||||||
validGasLimit: boolean;
|
|
||||||
isWindowStartValid: boolean;
|
|
||||||
windowStart: any;
|
|
||||||
gasPrice: any;
|
|
||||||
currentTo: any;
|
|
||||||
currentValue: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OwnProps {
|
|
||||||
withProps(props: CallbackProps): React.ReactElement<any> | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = OwnProps & StateProps;
|
|
||||||
|
|
||||||
class ScheduleTransactionFactoryClass extends Component<Props> {
|
|
||||||
public render() {
|
|
||||||
const {
|
|
||||||
isFullTransaction,
|
|
||||||
isWeb3Wallet,
|
|
||||||
networkRequestPending,
|
|
||||||
validGasPrice,
|
|
||||||
validGasLimit,
|
|
||||||
isWindowStartValid,
|
|
||||||
transaction
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const isButtonDisabled =
|
|
||||||
!isWindowStartValid ||
|
|
||||||
!isFullTransaction ||
|
|
||||||
networkRequestPending ||
|
|
||||||
!validGasPrice ||
|
|
||||||
!validGasLimit;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<WithSigner
|
|
||||||
isWeb3={isWeb3Wallet}
|
|
||||||
withSigner={signer =>
|
|
||||||
this.props.withProps({
|
|
||||||
disabled: isButtonDisabled,
|
|
||||||
isWeb3Wallet,
|
|
||||||
onClick: () => signer(transaction)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ScheduleTransactionFactory = connect((state: AppState) => ({
|
|
||||||
...getSchedulingTransaction(state),
|
|
||||||
networkRequestPending: isNetworkRequestPending(state),
|
|
||||||
isWeb3Wallet: getWalletType(state).isWeb3Wallet,
|
|
||||||
validGasPrice: isValidGasPrice(state),
|
|
||||||
validGasLimit: isValidGasLimit(state),
|
|
||||||
windowStart: getWindowStart(state),
|
|
||||||
gasPrice: getGasPrice(state),
|
|
||||||
currentTo: getCurrentTo(state),
|
|
||||||
currentValue: getCurrentValue(state)
|
|
||||||
}))(ScheduleTransactionFactoryClass);
|
|
@ -1 +0,0 @@
|
|||||||
export * from './ScheduleTransactionFactory';
|
|
@ -41,7 +41,7 @@ interface OwnProps {
|
|||||||
|
|
||||||
type Props = StateProps & OwnProps;
|
type Props = StateProps & OwnProps;
|
||||||
|
|
||||||
class SendButtonFactoryClass extends Component<Props> {
|
export class SendButtonFactoryClass extends Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
signing,
|
signing,
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import translate from 'translations';
|
||||||
|
import { ScheduleTransactionFactory } from './ScheduleTransactionFactory';
|
||||||
|
|
||||||
|
export const GenerateScheduleTransactionButton: React.SFC<{}> = () => {
|
||||||
|
return (
|
||||||
|
<ScheduleTransactionFactory
|
||||||
|
withProps={({ disabled, isWeb3Wallet, onClick }) => (
|
||||||
|
<button disabled={disabled} className="btn btn-info btn-block" onClick={onClick}>
|
||||||
|
{isWeb3Wallet ? translate('SCHEDULE_schedule') : translate('DEP_signtx')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { AppState } from 'reducers';
|
||||||
|
import {
|
||||||
|
getSchedulingTransaction,
|
||||||
|
isNetworkRequestPending,
|
||||||
|
isValidGasPrice,
|
||||||
|
isValidGasLimit,
|
||||||
|
getSerializedTransaction,
|
||||||
|
getSignedTx
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { getWalletType } from 'selectors/wallet';
|
||||||
|
import { GenerateTransactionFactoryClass } from 'components/GenerateTransactionFactory';
|
||||||
|
|
||||||
|
export const ScheduleTransactionFactory = connect((state: AppState) => ({
|
||||||
|
...getSchedulingTransaction(state),
|
||||||
|
walletType: getWalletType(state),
|
||||||
|
serializedTransaction: getSerializedTransaction(state),
|
||||||
|
networkRequestPending: isNetworkRequestPending(state),
|
||||||
|
isWeb3Wallet: getWalletType(state).isWeb3Wallet,
|
||||||
|
validGasPrice: isValidGasPrice(state),
|
||||||
|
validGasLimit: isValidGasLimit(state),
|
||||||
|
signedTx: !!getSignedTx(state)
|
||||||
|
}))(GenerateTransactionFactoryClass);
|
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import translate from 'translations';
|
||||||
|
import { ConfirmationModal } from 'components/ConfirmationModal';
|
||||||
|
import { SigningStatus } from 'components';
|
||||||
|
import { SendScheduleTransactionButtonFactory } from 'containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButtonFactory';
|
||||||
|
|
||||||
|
export const SendScheduleTransactionButton: React.SFC<{
|
||||||
|
className?: string;
|
||||||
|
signing?: boolean;
|
||||||
|
customModal?: typeof ConfirmationModal;
|
||||||
|
}> = ({ signing, customModal, className }) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<SendScheduleTransactionButtonFactory
|
||||||
|
signing={signing}
|
||||||
|
Modal={customModal ? customModal : ConfirmationModal}
|
||||||
|
withProps={({ disabled, openModal, signTx }) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<button
|
||||||
|
disabled={disabled}
|
||||||
|
className={`SendButton btn btn-primary btn-block ${className}`}
|
||||||
|
onClick={() => {
|
||||||
|
!!signing ? (signTx(), openModal()) : openModal();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{translate('SCHEDULE_schedule')}
|
||||||
|
</button>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<SigningStatus />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
@ -0,0 +1,29 @@
|
|||||||
|
import { getWalletType } from 'selectors/wallet';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { AppState } from 'reducers';
|
||||||
|
import {
|
||||||
|
getSerializedTransaction,
|
||||||
|
isNetworkRequestPending,
|
||||||
|
isValidGasPrice,
|
||||||
|
isValidGasLimit,
|
||||||
|
getSignedTx,
|
||||||
|
getWeb3Tx,
|
||||||
|
getSchedulingTransaction
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { SendButtonFactoryClass } from 'components/SendButtonFactory';
|
||||||
|
|
||||||
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
walletType: getWalletType(state),
|
||||||
|
serializedTransaction: getSerializedTransaction(state),
|
||||||
|
...getSchedulingTransaction(state),
|
||||||
|
networkRequestPending: isNetworkRequestPending(state),
|
||||||
|
validGasPrice: isValidGasPrice(state),
|
||||||
|
validGasLimit: isValidGasLimit(state),
|
||||||
|
signedTx: !!getSignedTx(state) || !!getWeb3Tx(state)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SendScheduleTransactionButtonFactory = connect(mapStateToProps)(
|
||||||
|
SendButtonFactoryClass
|
||||||
|
);
|
@ -7,8 +7,8 @@ import { getWalletInst } from 'selectors/wallet';
|
|||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { RouteComponentProps, Redirect } from 'react-router';
|
import { RouteComponentProps, Redirect } from 'react-router';
|
||||||
import { UnavailableWallets, SchedulingFields } from 'containers/Tabs/SendTransaction/components';
|
import { UnavailableWallets, SchedulingFields } from 'containers/Tabs/SendTransaction/components';
|
||||||
import { isNetworkUnit } from 'selectors/config/wallet';
|
|
||||||
import { SideBar } from '../SendTransaction/components/SideBar';
|
import { SideBar } from '../SendTransaction/components/SideBar';
|
||||||
|
import { getNetworkConfig } from 'selectors/config';
|
||||||
|
|
||||||
const ScheduleMain = () => (
|
const ScheduleMain = () => (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@ -18,16 +18,19 @@ const ScheduleMain = () => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
|
schedulingDisabled: boolean;
|
||||||
wallet: AppState['wallet']['inst'];
|
wallet: AppState['wallet']['inst'];
|
||||||
requestDisabled: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = StateProps & RouteComponentProps<{}>;
|
type Props = StateProps & RouteComponentProps<{}>;
|
||||||
|
|
||||||
class Schedule extends React.Component<Props> {
|
class Schedule extends React.Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const { wallet, match } = this.props;
|
const { schedulingDisabled, wallet } = this.props;
|
||||||
const currentPath = match.url;
|
|
||||||
|
if (schedulingDisabled && wallet) {
|
||||||
|
return <Redirect to="account/info" />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabSection>
|
<TabSection>
|
||||||
@ -36,7 +39,7 @@ class Schedule extends React.Component<Props> {
|
|||||||
{wallet && (
|
{wallet && (
|
||||||
<div className="SubTabs row">
|
<div className="SubTabs row">
|
||||||
<div className="col-sm-8">
|
<div className="col-sm-8">
|
||||||
{wallet.isReadOnly ? <Redirect to={`${currentPath}/info`} /> : <ScheduleMain />};
|
{wallet.isReadOnly ? <Redirect to="schedule/info" /> : <ScheduleMain />};
|
||||||
</div>
|
</div>
|
||||||
<SideBar />
|
<SideBar />
|
||||||
</div>
|
</div>
|
||||||
@ -49,5 +52,5 @@ class Schedule extends React.Component<Props> {
|
|||||||
|
|
||||||
export default connect((state: AppState) => ({
|
export default connect((state: AppState) => ({
|
||||||
wallet: getWalletInst(state),
|
wallet: getWalletInst(state),
|
||||||
requestDisabled: !isNetworkUnit(state, 'ETH')
|
schedulingDisabled: getNetworkConfig(state).name !== 'Kovan'
|
||||||
}))(Schedule);
|
}))(Schedule);
|
@ -8,16 +8,23 @@ import {
|
|||||||
CurrentCustomMessage,
|
CurrentCustomMessage,
|
||||||
GenerateTransaction,
|
GenerateTransaction,
|
||||||
SendButton,
|
SendButton,
|
||||||
SigningStatus,
|
WindowStartField,
|
||||||
WindowStartField
|
ScheduleTimestampField,
|
||||||
|
ScheduleTimezoneDropDown,
|
||||||
|
TimeBountyField,
|
||||||
|
ScheduleType,
|
||||||
|
WindowSizeField,
|
||||||
|
ScheduleGasPriceField
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { OnlyUnlocked, WhenQueryExists } from 'components/renderCbs';
|
import { OnlyUnlocked, WhenQueryExists } from 'components/renderCbs';
|
||||||
import translate from 'translations';
|
import translate from 'translations';
|
||||||
|
|
||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { NonStandardTransaction } from './components';
|
import { NonStandardTransaction } from './components';
|
||||||
import { getCurrentWindowStart, ICurrentWindowStart } from 'selectors/transaction';
|
import { getOffline } from 'selectors/config';
|
||||||
import { getNetworkConfig } from 'selectors/config';
|
import { SendScheduleTransactionButton } from 'containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButton';
|
||||||
|
import { GenerateScheduleTransactionButton } from 'containers/Tabs/ScheduleTransaction/components/GenerateScheduleTransactionButton';
|
||||||
|
import { getCurrentScheduleType, ICurrentScheduleType } from 'selectors/transaction';
|
||||||
|
|
||||||
const QueryWarning: React.SFC<{}> = () => (
|
const QueryWarning: React.SFC<{}> = () => (
|
||||||
<WhenQueryExists
|
<WhenQueryExists
|
||||||
@ -30,56 +37,15 @@ const QueryWarning: React.SFC<{}> = () => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
schedulingDisabled: boolean;
|
scheduling: boolean;
|
||||||
shouldDisplay: boolean;
|
shouldDisplay: boolean;
|
||||||
offline: boolean;
|
offline: boolean;
|
||||||
windowStart: ICurrentWindowStart;
|
schedulingType: ICurrentScheduleType;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldsClass extends Component<StateProps> {
|
class FieldsClass extends Component<StateProps> {
|
||||||
public render() {
|
public render() {
|
||||||
const { schedulingDisabled, shouldDisplay, windowStart } = this.props;
|
const { shouldDisplay, scheduling, schedulingType } = this.props;
|
||||||
|
|
||||||
const scheduling = Boolean(windowStart.value);
|
|
||||||
|
|
||||||
const content = (
|
|
||||||
<div className="Tab-content-pane">
|
|
||||||
<AddressField />
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<AmountField hasUnitDropdown={true} />
|
|
||||||
<SendEverything />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!schedulingDisabled && (
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<WindowStartField />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<TXMetaDataPanel scheduling={scheduling} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CurrentCustomMessage />
|
|
||||||
<NonStandardTransaction />
|
|
||||||
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12 clearfix">
|
|
||||||
<GenerateTransaction scheduling={scheduling} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<SigningStatus />
|
|
||||||
<div className="row form-group">
|
|
||||||
<SendButton />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OnlyUnlocked
|
<OnlyUnlocked
|
||||||
@ -95,16 +61,61 @@ class FieldsClass extends Component<StateProps> {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{scheduling && (
|
||||||
|
<div className="scheduled-tx-settings">
|
||||||
|
<h6>Scheduled Transaction Settings</h6>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-3">
|
||||||
|
<ScheduleType />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{schedulingType.value === 'time' && (
|
||||||
|
<div>
|
||||||
|
<div className="col-xs-12 col-md-3">
|
||||||
|
<ScheduleTimestampField />
|
||||||
|
</div>
|
||||||
|
<div className="col-xs-12 col-md-3">
|
||||||
|
<ScheduleTimezoneDropDown />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{schedulingType.value === 'block' && (
|
||||||
|
<div>
|
||||||
|
<div className="col-xs-12 col-md-6">
|
||||||
|
<WindowStartField />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="col-xs-12 col-md-3">
|
||||||
|
<WindowSizeField />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-6">
|
||||||
|
<ScheduleGasPriceField />
|
||||||
|
</div>
|
||||||
|
<div className="col-xs-6">
|
||||||
|
<TimeBountyField />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="row form-group">
|
<div className="row form-group">
|
||||||
<div className="col-xs-12">
|
<div className="col-xs-12">
|
||||||
<TXMetaDataPanel />
|
<TXMetaDataPanel scheduling={scheduling} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CurrentCustomMessage />
|
<CurrentCustomMessage />
|
||||||
<NonStandardTransaction />
|
<NonStandardTransaction />
|
||||||
|
|
||||||
{offline ? <GenerateTransaction /> : <SendButton signing={true} />}
|
{this.getTxButton()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@ -112,11 +123,29 @@ class FieldsClass extends Component<StateProps> {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTxButton() {
|
||||||
|
const { offline, scheduling } = this.props;
|
||||||
|
|
||||||
|
if (scheduling) {
|
||||||
|
if (offline) {
|
||||||
|
return <GenerateScheduleTransactionButton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SendScheduleTransactionButton signing={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offline) {
|
||||||
|
return <GenerateTransaction />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SendButton signing={true} />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Fields = connect((state: AppState) => ({
|
export const Fields = connect((state: AppState) => ({
|
||||||
|
scheduling: true,
|
||||||
shouldDisplay: !isAnyOfflineWithWeb3(state),
|
shouldDisplay: !isAnyOfflineWithWeb3(state),
|
||||||
offline: getOffline(state),
|
offline: getOffline(state),
|
||||||
windowStart: getCurrentWindowStart(state),
|
schedulingType: getCurrentScheduleType(state)
|
||||||
schedulingDisabled: getNetworkConfig(state).name !== 'Kovan'
|
|
||||||
}))(FieldsClass);
|
}))(FieldsClass);
|
||||||
|
@ -5,11 +5,7 @@ import {
|
|||||||
AddressField,
|
AddressField,
|
||||||
AmountField,
|
AmountField,
|
||||||
TXMetaDataPanel,
|
TXMetaDataPanel,
|
||||||
SendEverything,
|
|
||||||
CurrentCustomMessage,
|
CurrentCustomMessage,
|
||||||
GenerateTransaction,
|
|
||||||
SendButton,
|
|
||||||
SigningStatus,
|
|
||||||
WindowStartField
|
WindowStartField
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { OnlyUnlocked, WhenQueryExists } from 'components/renderCbs';
|
import { OnlyUnlocked, WhenQueryExists } from 'components/renderCbs';
|
||||||
@ -18,6 +14,9 @@ import translate from 'translations';
|
|||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { NonStandardTransaction } from './components';
|
import { NonStandardTransaction } from './components';
|
||||||
import { NewTabLink } from 'components/ui';
|
import { NewTabLink } from 'components/ui';
|
||||||
|
import { getOffline } from 'selectors/config';
|
||||||
|
import { SendScheduleTransactionButton } from 'containers/Tabs/ScheduleTransaction/components/SendScheduleTransactionButton';
|
||||||
|
import { GenerateScheduleTransactionButton } from 'containers/Tabs/ScheduleTransaction/components/GenerateScheduleTransactionButton';
|
||||||
|
|
||||||
const EACLink = () => (
|
const EACLink = () => (
|
||||||
<NewTabLink href="https://chronologic.network" content="Ethereum Alarm Clock" />
|
<NewTabLink href="https://chronologic.network" content="Ethereum Alarm Clock" />
|
||||||
@ -35,64 +34,62 @@ const QueryWarning: React.SFC<{}> = () => (
|
|||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
shouldDisplay: boolean;
|
shouldDisplay: boolean;
|
||||||
|
offline: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SchedulingFieldsClass extends Component<StateProps> {
|
class SchedulingFieldsClass extends Component<StateProps> {
|
||||||
public render() {
|
public render() {
|
||||||
const { shouldDisplay } = this.props;
|
const { shouldDisplay, offline } = this.props;
|
||||||
|
|
||||||
const content = (
|
|
||||||
<div className="Tab-content-pane">
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<h3>ChronoLogic Scheduler</h3>
|
|
||||||
Powered by the <EACLink />, ChronoLogic Scheduler is a decentralized scheduling protocol
|
|
||||||
based on the Ethereum blockchain.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="row form-group" />
|
|
||||||
|
|
||||||
<AddressField />
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<AmountField hasUnitDropdown={true} />
|
|
||||||
<SendEverything />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<WindowStartField />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<TXMetaDataPanel scheduling={true} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CurrentCustomMessage />
|
|
||||||
<NonStandardTransaction />
|
|
||||||
|
|
||||||
<div className="row form-group">
|
|
||||||
<div className="col-xs-12 clearfix">
|
|
||||||
<GenerateTransaction scheduling={true} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<SigningStatus />
|
|
||||||
<div className="row form-group">
|
|
||||||
<SendButton />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OnlyUnlocked
|
<OnlyUnlocked
|
||||||
whenUnlocked={
|
whenUnlocked={
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<QueryWarning />
|
<QueryWarning />
|
||||||
{shouldDisplay ? content : null}
|
{shouldDisplay && (
|
||||||
|
<div className="Tab-content-pane">
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-12">
|
||||||
|
<h3>ChronoLogic Scheduler</h3>
|
||||||
|
Powered by the <EACLink />, ChronoLogic Scheduler is a decentralized scheduling
|
||||||
|
protocol based on the Ethereum blockchain.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row form-group" />
|
||||||
|
|
||||||
|
<AddressField />
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-12">
|
||||||
|
<AmountField hasUnitDropdown={true} hasSendEverything={true} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-12">
|
||||||
|
<WindowStartField />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-12">
|
||||||
|
<TXMetaDataPanel scheduling={true} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CurrentCustomMessage />
|
||||||
|
<NonStandardTransaction />
|
||||||
|
|
||||||
|
<div className="row form-group">
|
||||||
|
<div className="col-xs-12 clearfix">
|
||||||
|
{offline ? (
|
||||||
|
<GenerateScheduleTransactionButton />
|
||||||
|
) : (
|
||||||
|
<SendScheduleTransactionButton signing={true} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -101,5 +98,6 @@ class SchedulingFieldsClass extends Component<StateProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SchedulingFields = connect((state: AppState) => ({
|
export const SchedulingFields = connect((state: AppState) => ({
|
||||||
shouldDisplay: !isAnyOfflineWithWeb3(state)
|
shouldDisplay: !isAnyOfflineWithWeb3(state),
|
||||||
|
offline: getOffline(state)
|
||||||
}))(SchedulingFieldsClass);
|
}))(SchedulingFieldsClass);
|
||||||
|
@ -2,6 +2,7 @@ import BN from 'bn.js';
|
|||||||
import abi from 'ethereumjs-abi';
|
import abi from 'ethereumjs-abi';
|
||||||
|
|
||||||
export const EAC_SCHEDULING_CONFIG = {
|
export const EAC_SCHEDULING_CONFIG = {
|
||||||
|
DAPP_ADDRESS: 'https://app.chronologic.network',
|
||||||
FEE: new BN('2242000000000000'), // $2
|
FEE: new BN('2242000000000000'), // $2
|
||||||
FEE_MULTIPLIER: new BN('2'),
|
FEE_MULTIPLIER: new BN('2'),
|
||||||
FUTURE_EXECUTION_COST: new BN('180000'),
|
FUTURE_EXECUTION_COST: new BN('180000'),
|
||||||
@ -65,3 +66,7 @@ export const getScheduleData = (
|
|||||||
requiredDeposit
|
requiredDeposit
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getTXDetailsCheckURL = (txHash: string) => {
|
||||||
|
return `${EAC_SCHEDULING_CONFIG.DAPP_ADDRESS}/awaiting/scheduler/${txHash}`;
|
||||||
|
};
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { SagaIterator } from 'redux-saga';
|
import { SagaIterator } from 'redux-saga';
|
||||||
import { getWeb3Tx, getSignedTx, getTransactionStatus } from 'selectors/transaction';
|
import {
|
||||||
|
getWeb3Tx,
|
||||||
|
getSignedTx,
|
||||||
|
getTransactionStatus,
|
||||||
|
getWindowStart,
|
||||||
|
ICurrentWindowStart
|
||||||
|
} from 'selectors/transaction';
|
||||||
import { select, call, put } from 'redux-saga/effects';
|
import { select, call, put } from 'redux-saga/effects';
|
||||||
import {
|
import {
|
||||||
broadcastTransactionFailed,
|
broadcastTransactionFailed,
|
||||||
@ -50,14 +56,18 @@ export const broadcastTransactionWrapper = (func: (serializedTx: string) => Saga
|
|||||||
const broadcastedHash: string = yield call(func, stringTx); // convert to string because node / web3 doesnt support buffers
|
const broadcastedHash: string = yield call(func, stringTx); // convert to string because node / web3 doesnt support buffers
|
||||||
yield put(broadcastTransactionSucceeded({ indexingHash, broadcastedHash }));
|
yield put(broadcastTransactionSucceeded({ indexingHash, broadcastedHash }));
|
||||||
|
|
||||||
|
const windowStart: ICurrentWindowStart = yield select(getWindowStart);
|
||||||
const network: NetworkConfig = yield select(getNetworkConfig);
|
const network: NetworkConfig = yield select(getNetworkConfig);
|
||||||
|
|
||||||
|
const scheduling = Boolean(windowStart && windowStart.value);
|
||||||
|
|
||||||
yield put(
|
yield put(
|
||||||
showNotification(
|
showNotification(
|
||||||
'success',
|
'success',
|
||||||
<TransactionSucceeded
|
<TransactionSucceeded
|
||||||
txHash={broadcastedHash}
|
txHash={broadcastedHash}
|
||||||
blockExplorer={network.isCustom ? undefined : network.blockExplorer}
|
blockExplorer={network.isCustom ? undefined : network.blockExplorer}
|
||||||
|
scheduling={scheduling}
|
||||||
/>,
|
/>,
|
||||||
Infinity
|
Infinity
|
||||||
)
|
)
|
||||||
|
@ -31,12 +31,6 @@ export interface IGetTransaction {
|
|||||||
isFullTransaction: boolean; //if the user has filled all the fields
|
isFullTransaction: boolean; //if the user has filled all the fields
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGetSchedulingTransaction {
|
|
||||||
transaction: EthTx;
|
|
||||||
isFullTransaction: boolean;
|
|
||||||
isWindowStartValid: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTransaction = (state: AppState): IGetTransaction => {
|
const getTransaction = (state: AppState): IGetTransaction => {
|
||||||
const currentTo = getCurrentTo(state);
|
const currentTo = getCurrentTo(state);
|
||||||
const currentValue = getCurrentValue(state);
|
const currentValue = getCurrentValue(state);
|
||||||
@ -59,7 +53,7 @@ const getTransaction = (state: AppState): IGetTransaction => {
|
|||||||
return { transaction, isFullTransaction };
|
return { transaction, isFullTransaction };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction => {
|
const getSchedulingTransaction = (state: AppState): IGetTransaction => {
|
||||||
const currentTo = getCurrentTo(state);
|
const currentTo = getCurrentTo(state);
|
||||||
const currentValue = getCurrentValue(state);
|
const currentValue = getCurrentValue(state);
|
||||||
const transactionFields = getFields(state);
|
const transactionFields = getFields(state);
|
||||||
@ -72,16 +66,11 @@ const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction =>
|
|||||||
const nonce = getNonce(state);
|
const nonce = getNonce(state);
|
||||||
const gasPrice = getGasPrice(state);
|
const gasPrice = getGasPrice(state);
|
||||||
const timeBounty = getTimeBounty(state);
|
const timeBounty = getTimeBounty(state);
|
||||||
|
const windowStartValid = isWindowStartValid(transactionFields, getLatestBlock(state));
|
||||||
|
|
||||||
const isFullTransaction = isFullTx(
|
const isFullTransaction =
|
||||||
state,
|
isFullTx(state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit) &&
|
||||||
transactionFields,
|
windowStartValid;
|
||||||
currentTo,
|
|
||||||
currentValue,
|
|
||||||
dataExists,
|
|
||||||
validGasCost,
|
|
||||||
unit
|
|
||||||
);
|
|
||||||
|
|
||||||
const transactionData = getScheduleData(
|
const transactionData = getScheduleData(
|
||||||
currentTo.raw,
|
currentTo.raw,
|
||||||
@ -119,8 +108,7 @@ const getSchedulingTransaction = (state: AppState): IGetSchedulingTransaction =>
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
transaction,
|
transaction,
|
||||||
isFullTransaction,
|
isFullTransaction
|
||||||
isWindowStartValid: isWindowStartValid(transactionFields, getLatestBlock(state))
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,9 @@
|
|||||||
"ledgerco": "1.2.1",
|
"ledgerco": "1.2.1",
|
||||||
"lodash": "4.17.5",
|
"lodash": "4.17.5",
|
||||||
"moment": "2.22.0",
|
"moment": "2.22.0",
|
||||||
|
"moment-timezone": "0.5.14",
|
||||||
"normalizr": "3.2.4",
|
"normalizr": "3.2.4",
|
||||||
|
"pikaday-time": "1.6.1",
|
||||||
"qrcode": "1.2.0",
|
"qrcode": "1.2.0",
|
||||||
"qrcode.react": "0.8.0",
|
"qrcode.react": "0.8.0",
|
||||||
"query-string": "6.0.0",
|
"query-string": "6.0.0",
|
||||||
@ -60,6 +62,7 @@
|
|||||||
"@types/history": "4.6.2",
|
"@types/history": "4.6.2",
|
||||||
"@types/jest": "22.2.2",
|
"@types/jest": "22.2.2",
|
||||||
"@types/lodash": "4.14.106",
|
"@types/lodash": "4.14.106",
|
||||||
|
"@types/moment-timezone": "0.5.4",
|
||||||
"@types/qrcode": "0.8.0",
|
"@types/qrcode": "0.8.0",
|
||||||
"@types/qrcode.react": "0.6.3",
|
"@types/qrcode.react": "0.6.3",
|
||||||
"@types/query-string": "5.1.0",
|
"@types/query-string": "5.1.0",
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { getWeb3Tx, getSignedTx, getTransactionStatus } from 'selectors/transaction';
|
import {
|
||||||
|
getWeb3Tx,
|
||||||
|
getSignedTx,
|
||||||
|
getTransactionStatus,
|
||||||
|
getWindowStart
|
||||||
|
} from 'selectors/transaction';
|
||||||
import { select, call, put } from 'redux-saga/effects';
|
import { select, call, put } from 'redux-saga/effects';
|
||||||
import {
|
import {
|
||||||
broadcastTransactionFailed,
|
broadcastTransactionFailed,
|
||||||
@ -118,6 +123,10 @@ describe('broadcastTransactionWrapper*', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('select getWindowStart', () => {
|
||||||
|
expect(gens.gen.next().value).toEqual(select(getWindowStart));
|
||||||
|
});
|
||||||
|
|
||||||
it('select getNetworkConfig', () => {
|
it('select getNetworkConfig', () => {
|
||||||
expect(gens.gen.next().value).toEqual(select(getNetworkConfig));
|
expect(gens.gen.next().value).toEqual(select(getNetworkConfig));
|
||||||
});
|
});
|
||||||
@ -127,7 +136,11 @@ describe('broadcastTransactionWrapper*', () => {
|
|||||||
put(
|
put(
|
||||||
showNotification(
|
showNotification(
|
||||||
'success',
|
'success',
|
||||||
<TransactionSucceeded txHash={broadcastedHash} blockExplorer={network.blockExplorer} />,
|
<TransactionSucceeded
|
||||||
|
txHash={broadcastedHash}
|
||||||
|
blockExplorer={network.blockExplorer}
|
||||||
|
scheduling={false}
|
||||||
|
/>,
|
||||||
Infinity
|
Infinity
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user