From 6038da4339443f707550270d6e4330480d2f576c Mon Sep 17 00:00:00 2001 From: Anthony Laibe Date: Thu, 16 Aug 2018 16:18:07 +0100 Subject: [PATCH] Deploy contract --- embark-ui/src/actions/index.js | 7 +++ embark-ui/src/api/index.js | 4 ++ embark-ui/src/components/ContractLayout.js | 2 + .../containers/ContractDeploymentContainer.js | 54 +++++++++++++++++++ .../containers/ContractFunctionsContainer.js | 1 - embark-ui/src/reducers/index.js | 1 + embark-ui/src/reducers/selectors.js | 4 ++ embark-ui/src/sagas/index.js | 8 ++- lib/modules/contracts_manager/index.js | 34 ++++++++++-- 9 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 embark-ui/src/containers/ContractDeploymentContainer.js diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 174a0b35..c839e103 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -118,6 +118,13 @@ export const contractFunction = { failure: (error) => action(CONTRACT_FUNCTION[FAILURE], {error}) }; +export const CONTRACT_DEPLOY = createRequestTypes('CONTRACT_DEPLOY'); +export const contractDeploy = { + post: (contractName, method, inputs) => action(CONTRACT_DEPLOY[REQUEST], {contractName, method, inputs}), + success: (result, payload) => action(CONTRACT_DEPLOY[SUCCESS], {contractDeploys: [{...result, ...payload}]}), + failure: (error) => action(CONTRACT_DEPLOY[FAILURE], {error}) +}; + export const VERSIONS = createRequestTypes('VERSIONS'); export const versions = { request: () => action(VERSIONS[REQUEST]), diff --git a/embark-ui/src/api/index.js b/embark-ui/src/api/index.js index 07925650..3718d061 100644 --- a/embark-ui/src/api/index.js +++ b/embark-ui/src/api/index.js @@ -72,6 +72,10 @@ export function postContractFunction(payload) { return post(`/contract/${payload.contractName}/function`, payload); } +export function postContractDeploy(payload) { + return post(`/contract/${payload.contractName}/deploy`, payload); +} + export function fetchVersions() { return get('/versions'); } diff --git a/embark-ui/src/components/ContractLayout.js b/embark-ui/src/components/ContractLayout.js index edd8882f..b9950471 100644 --- a/embark-ui/src/components/ContractLayout.js +++ b/embark-ui/src/components/ContractLayout.js @@ -10,6 +10,7 @@ import { import ContractContainer from '../containers/ContractContainer'; import ContractLoggerContainer from '../containers/ContractLoggerContainer'; import ContractFunctionsContainer from '../containers/ContractFunctionsContainer'; +import ContractDeploymentContainer from '../containers/ContractDeploymentContainer'; import ContractProfileContainer from '../containers/ContractProfileContainer'; import ContractSourceContainer from '../containers/ContractSourceContainer'; @@ -73,6 +74,7 @@ const ContractLayout = ({match}) => ( + diff --git a/embark-ui/src/containers/ContractDeploymentContainer.js b/embark-ui/src/containers/ContractDeploymentContainer.js new file mode 100644 index 00000000..b1bf2741 --- /dev/null +++ b/embark-ui/src/containers/ContractDeploymentContainer.js @@ -0,0 +1,54 @@ +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; +import {withRouter} from 'react-router-dom'; + +import {contractProfile as contractProfileAction, contractDeploy as contractDeployAction} from '../actions'; +import ContractFunctions from '../components/ContractFunctions'; +import DataWrapper from "../components/DataWrapper"; +import {getContractProfile, getContractDeploys} from "../reducers/selectors"; + +class ContractDeploymentContainer extends Component { + componentDidMount() { + this.props.fetchContractProfile(this.props.match.params.contractName); + } + + render() { + return ( + ( + + )} /> + ); + } +} + +function mapStateToProps(state, props) { + return { + contractProfile: getContractProfile(state, props.match.params.contractName), + contractDeploys: getContractDeploys(state, props.match.params.contractName), + error: state.errorMessage, + loading: state.loading + }; +} + +ContractDeploymentContainer.propTypes = { + match: PropTypes.object, + contractProfile: PropTypes.object, + contractFunctions: PropTypes.arrayOf(PropTypes.object), + postContractDeploy: PropTypes.func, + fetchContractProfile: PropTypes.func, + error: PropTypes.string +}; + +export default withRouter(connect( + mapStateToProps, + { + fetchContractProfile: contractProfileAction.request, + postContractDeploy: contractDeployAction.post + } +)(ContractDeploymentContainer)); diff --git a/embark-ui/src/containers/ContractFunctionsContainer.js b/embark-ui/src/containers/ContractFunctionsContainer.js index a5296193..cf273c99 100644 --- a/embark-ui/src/containers/ContractFunctionsContainer.js +++ b/embark-ui/src/containers/ContractFunctionsContainer.js @@ -20,7 +20,6 @@ class ContractFunctionsContainer extends Component { render={({contractProfile, contractFunctions, postContractFunction}) => ( )} /> ); diff --git a/embark-ui/src/reducers/index.js b/embark-ui/src/reducers/index.js index fe4c7c11..c3d7f283 100644 --- a/embark-ui/src/reducers/index.js +++ b/embark-ui/src/reducers/index.js @@ -14,6 +14,7 @@ const entitiesDefaultState = { contractProfiles: [], contractFiles: [], contractFunctions: [], + contractDeploys: [], contractLogs: [], commands: [], messages: [], diff --git a/embark-ui/src/reducers/selectors.js b/embark-ui/src/reducers/selectors.js index 4928df8a..b7ef021a 100644 --- a/embark-ui/src/reducers/selectors.js +++ b/embark-ui/src/reducers/selectors.js @@ -70,6 +70,10 @@ export function getContractFunctions(state, contractName) { return state.entities.contractFunctions.filter((contractFunction => contractFunction.contractName === contractName)); } +export function getContractDeploys(state, contractName) { + return state.entities.contractDeploys.filter((contractDeploy => contractDeploy.contractName === contractName)); +} + export function getVersions(state) { return state.entities.versions; } diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index 45aa793c..668767a1 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -5,7 +5,7 @@ import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects'; const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs, contracts, contract, contractProfile, messageSend, versions, plugins, messageListen, fiddle, - ensRecord, ensRecords, contractLogs, contractFile, contractFunction} = actions; + ensRecord, ensRecords, contractLogs, contractFile, contractFunction, contractDeploy} = actions; function *doRequest(entity, apiFn, payload) { const {response, error} = yield call(apiFn, payload); @@ -33,6 +33,7 @@ export const fetchContract = doRequest.bind(null, contract, api.fetchContract); export const fetchContractProfile = doRequest.bind(null, contractProfile, api.fetchContractProfile); export const fetchContractFile = doRequest.bind(null, contractFile, api.fetchContractFile); export const postContractFunction = doRequest.bind(null, contractFunction, api.postContractFunction); +export const postContractDeploy = doRequest.bind(null, contractDeploy, api.postContractDeploy); export const fetchFiddle = doRequest.bind(null, fiddle, api.fetchFiddle); export const sendMessage = doRequest.bind(null, messageSend, api.sendMessage); export const fetchEnsRecord = doRequest.bind(null, ensRecord, api.fetchEnsRecord); @@ -98,6 +99,10 @@ export function *watchPostContractFunction() { yield takeEvery(actions.CONTRACT_FUNCTION[actions.REQUEST], postContractFunction); } +export function *watchPostContractDeploy() { + yield takeEvery(actions.CONTRACT_DEPLOY[actions.REQUEST], postContractDeploy); +} + export function *watchFetchVersions() { yield takeEvery(actions.VERSIONS[actions.REQUEST], fetchVersions); } @@ -206,6 +211,7 @@ export default function *root() { fork(watchFetchContractProfile), fork(watchFetchContractFile), fork(watchPostContractFunction), + fork(watchPostContractDeploy), fork(watchListenToMessages), fork(watchSendMessage), fork(watchFetchContract), diff --git a/lib/modules/contracts_manager/index.js b/lib/modules/contracts_manager/index.js index cc3cbcae..b19a9897 100644 --- a/lib/modules/contracts_manager/index.js +++ b/lib/modules/contracts_manager/index.js @@ -103,7 +103,7 @@ class ContractsManager { account: (callback) => { self.events.request("blockchain:defaultAccount:get", (account) => callback(null, account)); } - }, function (error, result) { + }, (error, result) => { if (error) { return res.send({error: error.message}); } @@ -117,10 +117,38 @@ class ContractsManager { return res.send({result: error.message}); } - return res.send({result}); + res.send({result}); }); } catch (e) { - return res.send({result: e.message}); + res.send({result: e.message}); + } + }); + } + ); + + plugin.registerAPICall( + 'post', + '/embark-api/contract/:contractName/deploy', + (req, res) => { + async.parallel({ + contract: (callback) => { + self.events.request('contracts:contract', req.body.contractName, (contract) => callback(null, contract)); + }, + account: (callback) => { + self.events.request("blockchain:defaultAccount:get", (account) => callback(null, account)); + } + }, async (error, result) => { + if (error) { + return res.send({error: error.message}); + } + const {account, contract} = result; + const contractObj = new web3.eth.Contract(contract.abiDefinition); + try { + let gas = await contractObj.deploy({data: `0x${contract.code}`, arguments: req.body.inputs}).estimateGas(); + let newContract = await contractObj.deploy({data: `0x${contract.code}`, arguments: req.body.inputs}).send({from: account, gas}); + res.send({result: newContract._address}); + } catch (e) { + res.send({result: e.message}); } }); }