mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-13 23:35:46 +00:00
feat(@cockpit/explorer): enable users to send ether through payable methods (#1649)
This commit is contained in:
parent
ed65b066e7
commit
d10c0b7951
@ -107,6 +107,9 @@ class ContractsManager {
|
||||
contract: (callback) => {
|
||||
self.events.request('contracts:contract', req.body.contractName, (contract) => callback(null, contract));
|
||||
},
|
||||
web3: (callback) => {
|
||||
self.events.request("blockchain:get", web3 => callback(null, web3));
|
||||
},
|
||||
account: (callback) => {
|
||||
self.events.request("blockchain:defaultAccount:get", (account) => callback(null, account));
|
||||
}
|
||||
@ -114,14 +117,20 @@ class ContractsManager {
|
||||
if (error) {
|
||||
return res.send({error: error.message});
|
||||
}
|
||||
const {account, contract} = result;
|
||||
const {account, contract, web3} = result;
|
||||
const abi = contract.abiDefinition.find(definition => definition.name === req.body.method);
|
||||
const funcCall = (abi.constant === true || abi.stateMutability === 'view' || abi.stateMutability === 'pure') ? 'call' : 'send';
|
||||
|
||||
self.events.request("blockchain:contract:create", {abi: contract.abiDefinition, address: contract.deployedAddress}, async (contractObj) => {
|
||||
try {
|
||||
const gas = await contractObj.methods[req.body.method].apply(this, req.body.inputs).estimateGas();
|
||||
contractObj.methods[req.body.method].apply(this, req.body.inputs)[funcCall]({from: account, gasPrice: req.body.gasPrice, gas: Math.floor(gas)}, (error, result) => {
|
||||
const value = req.body.value !== undefined ? web3.utils.toWei(req.body.value, 'ether') : 0
|
||||
const gas = await contractObj.methods[req.body.method].apply(this, req.body.inputs).estimateGas({ value });
|
||||
contractObj.methods[req.body.method].apply(this, req.body.inputs)[funcCall]({
|
||||
from: account,
|
||||
gasPrice: req.body.gasPrice,
|
||||
gas: Math.floor(gas),
|
||||
value
|
||||
}, (error, result) => {
|
||||
const paramString = abi.inputs.map((input, idx) => {
|
||||
const quote = input.type.indexOf("int") === -1 ? '"' : '';
|
||||
return quote + req.body.inputs[idx] + quote;
|
||||
|
@ -214,7 +214,7 @@ export const contractFile = {
|
||||
|
||||
export const CONTRACT_FUNCTION = createRequestTypes('CONTRACT_FUNCTION');
|
||||
export const contractFunction = {
|
||||
post: (contractName, method, inputs, gasPrice) => action(CONTRACT_FUNCTION[REQUEST], {contractName, method, inputs, gasPrice}),
|
||||
post: (contractName, method, inputs, gasPrice, value) => action(CONTRACT_FUNCTION[REQUEST], {contractName, method, inputs, gasPrice, value}),
|
||||
success: (result, payload) => action(CONTRACT_FUNCTION[SUCCESS], {contractFunctions: [{...result, ...payload}]}),
|
||||
failure: (error) => action(CONTRACT_FUNCTION[FAILURE], {error})
|
||||
};
|
||||
|
@ -28,13 +28,23 @@ import "./ContractOverview.scss";
|
||||
class ContractFunction extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {inputs: {}, optionsCollapse: false, functionCollapse: false, gasPriceCollapse: false};
|
||||
this.state = {
|
||||
inputs: {},
|
||||
optionsCollapse: false,
|
||||
functionCollapse: false,
|
||||
gasPriceCollapse: false,
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
|
||||
static isPureCall(method) {
|
||||
return (method.stateMutability === 'view' || method.stateMutability === 'pure');
|
||||
}
|
||||
|
||||
static isPayable(method) {
|
||||
return method.payable;
|
||||
}
|
||||
|
||||
static isEvent(method) {
|
||||
return !this.isPureCall(method) && (method.type === 'event');
|
||||
}
|
||||
@ -59,9 +69,13 @@ class ContractFunction extends Component {
|
||||
}
|
||||
|
||||
handleChange(e, name) {
|
||||
const newInputs = this.state.inputs;
|
||||
newInputs[name] = e.target.value;
|
||||
this.setState({inputs: newInputs});
|
||||
if (name === `${this.props.method.name}-value`) {
|
||||
this.setState({ value: e.target.value });
|
||||
} else {
|
||||
const newInputs = this.state.inputs;
|
||||
newInputs[name] = e.target.value;
|
||||
this.setState({inputs: newInputs});
|
||||
}
|
||||
}
|
||||
|
||||
autoSetGasPrice(e) {
|
||||
@ -78,7 +92,8 @@ class ContractFunction extends Component {
|
||||
this.props.contractName,
|
||||
this.props.method.name,
|
||||
this.inputsAsArray(),
|
||||
this.state.inputs.gasPrice * 1000000000
|
||||
this.state.inputs.gasPrice * 1000000000,
|
||||
this.state.value
|
||||
);
|
||||
}
|
||||
|
||||
@ -171,12 +186,25 @@ class ContractFunction extends Component {
|
||||
: (ContractFunction.isPureCall(this.props.method) &&
|
||||
this.makeBadge('success', 'white', 'call')) ||
|
||||
this.makeBadge('warning', 'black', 'send')}
|
||||
{ContractFunction.isPayable(this.props.method) &&
|
||||
this.makeBadge('light', 'black', 'payable')
|
||||
}
|
||||
</div>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
{!ContractFunction.isFallback(this.props.method) &&
|
||||
<Collapse isOpen={this.state.functionCollapse} className="relative">
|
||||
<CardBody>
|
||||
{ContractFunction.isPayable(this.props.method) &&
|
||||
<Form inline>
|
||||
<Label for={this.props.method.name + '-value'} className="mr-2 font-weight-bold contract-function-input">ETH</Label>
|
||||
<Input name={this.props.method.name}
|
||||
id={this.props.method.name + '-value'}
|
||||
onChange={(e) => this.handleChange(e, this.props.method.name + '-value')}
|
||||
onKeyPress={(e) => this.handleKeyPress(e)}
|
||||
/>
|
||||
</Form>
|
||||
}
|
||||
<Form inline>
|
||||
{this.props.method.inputs.map((input, idx) => (
|
||||
<FormGroup key={idx}>
|
||||
|
@ -1,5 +1,6 @@
|
||||
.contract-function-badge {
|
||||
cursor: default;
|
||||
margin-left: 1em;
|
||||
|
||||
code {
|
||||
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
||||
|
Loading…
x
Reference in New Issue
Block a user