Merge pull request #166 from status-im/features/improve-gas-estimator
Add gas estimator to the functions that need it
This commit is contained in:
commit
87dfffef4d
|
@ -0,0 +1,21 @@
|
|||
.contract-function-container .collapse.show .card-body {
|
||||
min-height: 65px;
|
||||
}
|
||||
|
||||
.contract-function-container .contract-function-button {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.contract-function-container .gas-price-form #gasPrice {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.contract-function-container .gas-price-form button {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border: 0;
|
||||
box-shadow: none !important;
|
||||
}
|
|
@ -17,12 +17,16 @@ import {
|
|||
ListGroup,
|
||||
ListGroupItem
|
||||
} from "reactstrap";
|
||||
import GasStationContainer from "../containers/GasStationContainer";
|
||||
import {formatContractForDisplay} from '../utils/presentation';
|
||||
import FontAwesome from 'react-fontawesome';
|
||||
|
||||
import "./ContractOverview.css";
|
||||
|
||||
class ContractFunction extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {inputs: {}, optionsCollapse: false, functionCollapse: false};
|
||||
this.state = {inputs: {}, optionsCollapse: false, functionCollapse: false, gasPriceCollapse: false};
|
||||
}
|
||||
|
||||
static isPureCall(method) {
|
||||
|
@ -49,11 +53,18 @@ class ContractFunction extends Component {
|
|||
}
|
||||
|
||||
handleChange(e, name) {
|
||||
let newInputs = this.state.inputs;
|
||||
const newInputs = this.state.inputs;
|
||||
newInputs[name] = e.target.value;
|
||||
this.setState({inputs: newInputs});
|
||||
}
|
||||
|
||||
autoSetGasPrice(e) {
|
||||
e.preventDefault();
|
||||
const newInputs = this.state.inputs;
|
||||
newInputs.gasPrice = this.gasStation.getCurrentGas();
|
||||
this.setState({inputs: newInputs});
|
||||
}
|
||||
|
||||
handleCall(e) {
|
||||
e.preventDefault();
|
||||
this.props.postContractFunction(this.props.contractProfile.name, this.props.method.name, this.inputsAsArray(), this.state.inputs.gasPrice * 1000000000);
|
||||
|
@ -65,66 +76,85 @@ class ContractFunction extends Component {
|
|||
|
||||
toggleOptions() {
|
||||
this.setState({
|
||||
optionsCollapse: !this.state.optionsCollapse,
|
||||
optionsCollapse: !this.state.optionsCollapse
|
||||
});
|
||||
}
|
||||
|
||||
toggleGasPrice() {
|
||||
this.setState({
|
||||
gasPriceCollapse: !this.state.gasPriceCollapse
|
||||
});
|
||||
}
|
||||
|
||||
toggleFunction() {
|
||||
this.setState({
|
||||
functionCollapse: !this.state.functionCollapse,
|
||||
functionCollapse: !this.state.functionCollapse
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Card>
|
||||
<Card className="contract-function-container">
|
||||
<CardHeader>
|
||||
<CardTitle className="collapsable" onClick={() => this.toggleFunction()}>
|
||||
{ContractFunction.isPureCall(this.props.method) &&
|
||||
<button className="btn btn-warning btn-sm float-right">call</button>
|
||||
<button className="btn btn-warning btn-sm float-right" onClick={(e) => this.handleCall(e)}>call</button>
|
||||
}
|
||||
{ContractFunction.isEvent(this.props.method) &&
|
||||
<button className="btn btn-info btn-sm float-right">event</button>
|
||||
<button className="btn btn-info btn-sm float-right">event</button>
|
||||
}
|
||||
{this.props.method.name}({this.props.method.inputs.map(input => input.name).join(', ')})
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<Collapse isOpen={this.state.functionCollapse}>
|
||||
<Collapse isOpen={this.state.functionCollapse} className="relative">
|
||||
<CardBody>
|
||||
<Form action="" method="post" inline>
|
||||
{this.props.method.inputs.map(input => (
|
||||
<FormGroup key={input.name} className="pr-1">
|
||||
<Label for={input.name} className="pr-1">{input.name}: </Label>
|
||||
<Input name={input.name} id={input.name} placeholder={input.type} onChange={(e) => this.handleChange(e, input.name)}/>
|
||||
</FormGroup>
|
||||
))}
|
||||
<Form method="post" inline>
|
||||
{this.props.method.inputs.map(input => (
|
||||
<FormGroup key={input.name}>
|
||||
<Label for={input.name} className="mr-2 font-weight-bold">{input.name}</Label>
|
||||
<Input name={input.name} id={input.name} placeholder={input.type}
|
||||
onChange={(e) => this.handleChange(e, input.name)}/>
|
||||
</FormGroup>
|
||||
))}
|
||||
</Form>
|
||||
{!ContractFunction.isPureCall(this.props.method) &&
|
||||
<Col xs={12} className="my-2">
|
||||
<Row>
|
||||
<strong className="collapsable" onClick={() => this.toggleOptions()}>
|
||||
<i className={this.state.optionsCollapse ? 'fa fa-caret-down' : 'fa fa-caret-right'}/>Advanced Options
|
||||
</strong>
|
||||
<Col xs={12} className="my-2">
|
||||
<Row>
|
||||
<Collapse isOpen={this.state.optionsCollapse}>
|
||||
<Form action="" method="post" inline>
|
||||
<FormGroup key="gasPrice" className="pr-1">
|
||||
<Label for="gasPrice" className="pr-1">Gas Price (in GWei)(optional)</Label>
|
||||
<Input name="gasPrice" id="gasPrice" onChange={(e) => this.handleChange(e, 'gasPrice')}/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</Collapse>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col xs={12} className="mt-3">
|
||||
<Row>
|
||||
<strong className="collapsable" onClick={() => this.toggleOptions()}>
|
||||
<FontAwesome name={this.state.optionsCollapse ? 'caret-down' : 'caret-right'} className="mr-2"/>
|
||||
Advanced Options
|
||||
</strong>
|
||||
</Row>
|
||||
<Row>
|
||||
<Collapse isOpen={this.state.optionsCollapse} className="pl-3">
|
||||
<Form method="post" inline className="gas-price-form ">
|
||||
<FormGroup key="gasPrice">
|
||||
<Label for="gasPrice" className="mr-2">Gas Price (in GWei)(optional)</Label>
|
||||
<Input name="gasPrice" id="gasPrice" placeholder="uint256"
|
||||
value={this.state.inputs.gasPrice || ''}
|
||||
onChange={(e) => this.handleChange(e, 'gasPrice')}/>
|
||||
<Button onClick={(e) => this.autoSetGasPrice(e)} title="Automatically set the gas price to what is currently in the estimator (default: safe low)">
|
||||
Auto-set
|
||||
</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
<p className="collapsable mb-2" onClick={() => this.toggleGasPrice()}>
|
||||
<FontAwesome name={this.state.gasPriceCollapse ? 'caret-down' : 'caret-right'} className="mr-2"/>
|
||||
Gas price estimator
|
||||
</p>
|
||||
<Collapse isOpen={this.state.gasPriceCollapse}>
|
||||
<GasStationContainer ref={instance => {
|
||||
if (instance) this.gasStation = instance.getWrappedInstance();
|
||||
}}/>
|
||||
</Collapse>
|
||||
</Collapse>
|
||||
</Row>
|
||||
</Col>
|
||||
}
|
||||
<div align="right">
|
||||
<Button color="primary" disabled={this.callDisabled()} onClick={(e) => this.handleCall(e)}>
|
||||
{this.buttonTitle()}
|
||||
</Button>
|
||||
</div>
|
||||
<Button className="contract-function-button" color="primary" disabled={this.callDisabled()}
|
||||
onClick={(e) => this.handleCall(e)}>
|
||||
{this.buttonTitle()}
|
||||
</Button>
|
||||
</CardBody>
|
||||
</Collapse>
|
||||
{this.props.contractFunctions && this.props.contractFunctions.length > 0 && <CardFooter>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.copy-to-clipboard {
|
||||
#root .copy-to-clipboard {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
|
|
@ -49,6 +49,10 @@ class GasStation extends Component {
|
|||
return formattedStats;
|
||||
}
|
||||
|
||||
getCurrentGas() {
|
||||
return this.getGasOracleFormatted()[this.state.gasOracleSliderIndex].gasPrice / this.PRICE_UNIT_DIVIDER;
|
||||
}
|
||||
|
||||
gasSliderChange(e, name) {
|
||||
this.setState({
|
||||
[name]: e.target.value
|
||||
|
@ -91,7 +95,7 @@ class GasStation extends Component {
|
|||
}
|
||||
return <Row>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card className="mb-0">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Gas Price Estimator
|
||||
|
|
|
@ -5,7 +5,6 @@ import PropTypes from 'prop-types';
|
|||
import {contractProfile as contractProfileAction, contractFunction as contractFunctionAction} from '../actions';
|
||||
import ContractOverview from '../components/ContractOverview';
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
import GasStationContainer from "../containers/GasStationContainer";
|
||||
import {getContractProfile, getContractFunctions} from "../reducers/selectors";
|
||||
|
||||
class ContractOverviewContainer extends Component {
|
||||
|
@ -18,14 +17,10 @@ class ContractOverviewContainer extends Component {
|
|||
<DataWrapper shouldRender={this.props.contractProfile !== undefined}
|
||||
{...this.props}
|
||||
render={({contractProfile, contractFunctions, postContractFunction}) => (
|
||||
<React.Fragment>
|
||||
<ContractOverview contractProfile={contractProfile}
|
||||
contractFunctions={contractFunctions}
|
||||
contract={this.props.contract}
|
||||
postContractFunction={postContractFunction}/>
|
||||
|
||||
<GasStationContainer/>
|
||||
</React.Fragment>
|
||||
<ContractOverview contractProfile={contractProfile}
|
||||
contractFunctions={contractFunctions}
|
||||
contract={this.props.contract}
|
||||
postContractFunction={postContractFunction}/>
|
||||
)}/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import PropTypes from "prop-types";
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {withRouter} from "react-router-dom";
|
||||
import GasStation from '../components/GasStation';
|
||||
import {stopGasOracle, listenToGasOracle, gasOracle as ethGasAction, blocks as blocksAction} from "../actions";
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
|
@ -18,10 +17,14 @@ class GasStationContainer extends Component {
|
|||
this.props.stopGasOracle();
|
||||
}
|
||||
|
||||
getCurrentGas() {
|
||||
return this.gasStation.getCurrentGas();
|
||||
}
|
||||
|
||||
render() {
|
||||
return <DataWrapper shouldRender={Boolean(this.props.gasOracleStats && Object.keys(this.props.gasOracleStats).length && this.props.lastBlock)}
|
||||
{...this.props} render={({lastBlock, gasOracleStats}) => (
|
||||
<GasStation gasOracleStats={gasOracleStats} lastBlock={lastBlock}/>
|
||||
<GasStation gasOracleStats={gasOracleStats} lastBlock={lastBlock} ref={instance => { this.gasStation = instance; }}/>
|
||||
)}/>;
|
||||
|
||||
}
|
||||
|
@ -43,12 +46,14 @@ function mapStateToProps(state, _props) {
|
|||
};
|
||||
}
|
||||
|
||||
export default withRouter(connect(
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
fetchEthGas: ethGasAction.request,
|
||||
fetchBlocks: blocksAction.request,
|
||||
listenToGasOracle,
|
||||
stopGasOracle
|
||||
}
|
||||
)(GasStationContainer));
|
||||
},
|
||||
null,
|
||||
{ withRef: true }
|
||||
)(GasStationContainer);
|
||||
|
|
Loading…
Reference in New Issue