mirror of https://github.com/embarklabs/embark.git
refactor(@embark/embark-deploy-tracker): Add back contract tracking
Add back contract tracking to the refactored code. Deployment checks are added as plugins to the `embark-deployment` module. Adds ability to track if a contract has already been deployed, and skips deployment if so. Updates error handling flow for deployment process. Adds a contract class to the `embark-contracts-manager`, to add a `log` function for the contract. This `log` function can be called from any module that has the contract instance. Adds TS interfaces for contracts configuration. Handles the following cases: 1. Contract already deployed 2. Contract not deployed 3. Contract is configured with `{track: false}` (deploy if not deployed, and don't track) 5. Contract is configured with an `address` in the config 6. `trackContracts` set to `false` from `engine` (always deploy but don't track contracts). Currently used for the tests. 7. Contract deployment produces an error 8. Interface deployment shows warning. PR with unit tests and documenation to follow.
This commit is contained in:
parent
57b3b8d131
commit
59a0eea295
|
@ -26,21 +26,20 @@
|
|||
},
|
||||
"main": "./dist/index.js",
|
||||
"scripts": {
|
||||
"build": "cross-env BABEL_ENV=node babel src --extensions \".js\" --out-dir dist --root-mode upward --source-maps",
|
||||
"build": "cross-env BABEL_ENV=node babel src --extensions \".js,.ts\" --out-dir dist --root-mode upward --source-maps",
|
||||
"ci": "npm run qa",
|
||||
"clean": "npm run reset",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:js": "eslint src/",
|
||||
"// lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
|
||||
"lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
|
||||
"package": "npm pack",
|
||||
"// qa": "npm-run-all lint typecheck build package",
|
||||
"qa": "npm-run-all lint build package",
|
||||
"qa": "npm-run-all lint typecheck build package",
|
||||
"reset": "npx rimraf dist embark-*.tgz package",
|
||||
"start": "npm run watch",
|
||||
"// typecheck": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"watch": "run-p watch:*",
|
||||
"watch:build": "npm run build -- --verbose --watch",
|
||||
"// watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
|
||||
"watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "../../.eslintrc.json"
|
||||
|
@ -68,4 +67,4 @@
|
|||
"npm": ">=6.4.1",
|
||||
"yarn": ">=1.12.3"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { ContractConfig, Logger } from "embark";
|
||||
const { sha3 } = require("embark-utils");
|
||||
import { ABIDefinition } from "web3/eth/abi";
|
||||
|
||||
export default class Contract {
|
||||
private logger: Logger;
|
||||
public abiDefinition?: ABIDefinition[];
|
||||
public deployedAddress?: string;
|
||||
public className: string = "";
|
||||
public address?: string;
|
||||
public args?: any[] = [];
|
||||
public instanceOf?: string;
|
||||
public gas?: number;
|
||||
public gasPrice?: number;
|
||||
public silent?: boolean = false;
|
||||
public track?: boolean = true;
|
||||
public deploy?: boolean = true;
|
||||
public realRuntimeBytecode: string = "";
|
||||
public realArgs: any[] = [];
|
||||
constructor(logger: Logger, contractConfig: ContractConfig) {
|
||||
this.logger = logger;
|
||||
this.address = contractConfig.address;
|
||||
this.args = contractConfig.args;
|
||||
this.instanceOf = contractConfig.instanceOf;
|
||||
this.gas = contractConfig.gas;
|
||||
this.gasPrice = contractConfig.gasPrice;
|
||||
this.silent = contractConfig.silent;
|
||||
this.track = contractConfig.track;
|
||||
this.deploy = contractConfig.deploy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a hash from runtime bytecode, classname, and deploy arguments.
|
||||
* Used for uniquely identifying a contract, ie in chains.json.
|
||||
*/
|
||||
get hash() {
|
||||
return sha3(this.realRuntimeBytecode + this.className + (this.realArgs || this.args).join(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message to the console. Logs with loglevel trace if contract has it's silent
|
||||
* property set (in the config or internally, ie ENS contracts). Otherwise, logs with
|
||||
* info log level.
|
||||
* @param {string} message message to log to the console
|
||||
*/
|
||||
public log(message: string) {
|
||||
this.silent ? this.logger.trace(message) : this.logger.info(message);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
import {__} from 'embark-i18n';
|
||||
import Contract from './contract';
|
||||
const async = require('async');
|
||||
const constants = require('embark-core/constants');
|
||||
const { dappPath, proposeAlternative, toposort } = require('embark-utils');
|
||||
const {dappPath, proposeAlternative, toposort} = require('embark-utils');
|
||||
|
||||
class ContractsManager {
|
||||
constructor(embark, options) {
|
||||
|
@ -123,7 +124,7 @@ class ContractsManager {
|
|||
self.events.request("blockchain:contract:create", {abi: contract.abiDefinition, address: contract.deployedAddress}, async (contractObj) => {
|
||||
try {
|
||||
let value = typeof req.body.value === "number" ? req.body.value.toString() : req.body.value;
|
||||
const gas = await contractObj.methods[req.body.method].apply(this, req.body.inputs).estimateGas({ value });
|
||||
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,
|
||||
|
@ -148,7 +149,7 @@ class ContractsManager {
|
|||
return res.send({result: error.message});
|
||||
}
|
||||
|
||||
if(funcCall === 'call') {
|
||||
if (funcCall === 'call') {
|
||||
contractLog.status = '0x1';
|
||||
return res.send({result});
|
||||
}
|
||||
|
@ -223,13 +224,13 @@ class ContractsManager {
|
|||
'/embark-api/contract/deploy',
|
||||
(req, res) => {
|
||||
this.logger.trace(`POST request /embark-api/contract/deploy:\n ${JSON.stringify(req.body)}`);
|
||||
if(typeof req.body.compiledContract !== 'object'){
|
||||
if (typeof req.body.compiledContract !== 'object') {
|
||||
return res.send({error: 'Body parameter \'compiledContract\' must be an object'});
|
||||
}
|
||||
self.compiledContracts = Object.assign(self.compiledContracts, req.body.compiledContract);
|
||||
const contractNames = Object.keys(req.body.compiledContract);
|
||||
self.build((err, _mgr) => {
|
||||
if(err){
|
||||
if (err) {
|
||||
return res.send({error: err.message});
|
||||
}
|
||||
|
||||
|
@ -243,12 +244,12 @@ class ContractsManager {
|
|||
});
|
||||
}, (err) => {
|
||||
let responseData = {};
|
||||
if(err){
|
||||
if (err) {
|
||||
responseData.error = err.message;
|
||||
}
|
||||
else responseData.result = contractNames;
|
||||
this.logger.trace(`POST response /embark-api/contract/deploy:\n ${JSON.stringify(responseData)}`);
|
||||
res.send(responseData);
|
||||
this.logger.trace(`POST response /embark-api/contract/deploy:\n ${JSON.stringify(responseData)}`);
|
||||
res.send(responseData);
|
||||
});
|
||||
}, false, false);
|
||||
}
|
||||
|
@ -263,6 +264,7 @@ class ContractsManager {
|
|||
self.events.emit("status", __("Building..."));
|
||||
|
||||
async.eachOf(contractsConfig.contracts, (contract, className, eachCb) => {
|
||||
contract = new Contract(self.logger, contract);
|
||||
if (!contract.artifact) {
|
||||
contract.className = className;
|
||||
contract.args = contract.args || [];
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import {__} from 'embark-i18n';
|
||||
import {toChecksumAddress} from 'embark-utils';
|
||||
import Web3 from "web3";
|
||||
|
||||
export default class DeploymentChecks {
|
||||
constructor({trackingFunctions, logger, events, plugins}) {
|
||||
this.trackingFunctions = trackingFunctions;
|
||||
this.logger = logger;
|
||||
this.events = events;
|
||||
this.plugins = plugins;
|
||||
this._web3 = null;
|
||||
}
|
||||
|
||||
get web3() {
|
||||
return (async () => {
|
||||
if (!this._web3) {
|
||||
const provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||
this._web3 = new Web3(provider);
|
||||
}
|
||||
return this._web3;
|
||||
})();
|
||||
}
|
||||
|
||||
async checkContractConfig(params, cb) {
|
||||
const {contract} = params;
|
||||
|
||||
// previous event action check
|
||||
if (!params.shouldDeploy) {
|
||||
return cb(null, params);
|
||||
}
|
||||
|
||||
// contract config address field set - do not deploy
|
||||
if (contract.address !== undefined) {
|
||||
try {
|
||||
toChecksumAddress(contract.address);
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
contract.deployedAddress = contract.address;
|
||||
contract.log(contract.className.bold.cyan + __(" already deployed at ").green + contract.deployedAddress.bold.cyan);
|
||||
params.shouldDeploy = false;
|
||||
return cb(null, params);
|
||||
}
|
||||
|
||||
cb(null, params);
|
||||
}
|
||||
|
||||
async checkIfAlreadyDeployed(params, cb) {
|
||||
const {contract} = params;
|
||||
const trackedContract = this.trackingFunctions.getContract(contract);
|
||||
|
||||
// previous event action check
|
||||
if (!params.shouldDeploy) {
|
||||
return cb(null, params);
|
||||
}
|
||||
|
||||
// contract is not already tracked - deploy
|
||||
if (!trackedContract || !trackedContract.address) {
|
||||
return cb(null, params);
|
||||
}
|
||||
|
||||
// tracked contract has track field set - deploy anyway, but tell user
|
||||
if (trackedContract.track === false || this.trackingFunctions.trackContracts === false) {
|
||||
contract.log(contract.className.bold.cyan + __(" will be redeployed").green);
|
||||
return cb(null, params);
|
||||
}
|
||||
|
||||
// if bytecode for the contract in chains.json exists on chain - don't deploy
|
||||
const web3 = await this.web3;
|
||||
let codeInChain = "";
|
||||
try {
|
||||
codeInChain = await web3.eth.getCode(trackedContract.address);
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (codeInChain.length > 3) { // it is "0x" or "0x0" for empty code, depending on web3 version
|
||||
contract.deployedAddress = trackedContract.address;
|
||||
contract.log(contract.className.bold.cyan + __(" already deployed at ").green + contract.deployedAddress.bold.cyan);
|
||||
params.shouldDeploy = false;
|
||||
}
|
||||
cb(null, params);
|
||||
}
|
||||
}
|
|
@ -1,130 +1,24 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
import { dappPath, sha3 } from 'embark-utils';
|
||||
const Web3 = require('web3');
|
||||
import DeploymentChecks from "./deploymentChecks";
|
||||
import TrackingFunctions from "./trackingFunctions";
|
||||
|
||||
class DeployTracker {
|
||||
|
||||
constructor(embark, options) {
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
this.fs = embark.fs;
|
||||
constructor(embark, {trackContracts, env, plugins}) {
|
||||
const {logger, events, fs, config} = embark;
|
||||
this.embark = embark;
|
||||
this.trackContracts = (options.trackContracts !== false);
|
||||
|
||||
// TODO: unclear where env comes from
|
||||
// TODO: we should be getting the env from a request to the config
|
||||
this.env = options.env;
|
||||
this.chainConfig = {};
|
||||
this.chainFile = embark.config.contractsConfig.tracking;
|
||||
|
||||
this.events.on("blockchain:started", this.loadChainTrackerFile.bind(this));
|
||||
this.embark.registerActionForEvent('deployment:deployContracts:beforeAll', this.setCurrentChain.bind(this));
|
||||
this.embark.registerActionForEvent("deployment:contract:deployed", this.trackAndSaveContract.bind(this));
|
||||
this.embark.registerActionForEvent("deploy:contract:shouldDeploy", this.checkIfDeploymentIsNeeded.bind(this));
|
||||
const trackingFunctions = new TrackingFunctions({config, fs, logger, events, env, trackContracts});
|
||||
const deploymentChecks = new DeploymentChecks({trackingFunctions, logger, events, plugins});
|
||||
|
||||
this.embark.events.on("blockchain:started", trackingFunctions.loadChainTrackerFile.bind(trackingFunctions));
|
||||
this.embark.registerActionForEvent('deployment:deployContracts:beforeAll', trackingFunctions.setCurrentChain.bind(trackingFunctions));
|
||||
this.embark.registerActionForEvent("deployment:contract:deployed", trackingFunctions.trackAndSaveContract.bind(trackingFunctions));
|
||||
this.embark.registerActionForEvent("deployment:contract:shouldDeploy", deploymentChecks.checkContractConfig.bind(deploymentChecks));
|
||||
this.embark.registerActionForEvent("deployment:contract:shouldDeploy", deploymentChecks.checkIfAlreadyDeployed.bind(deploymentChecks));
|
||||
}
|
||||
|
||||
trackAndSaveContract(params, cb) {
|
||||
if (!this.embark.config.contractsConfig.tracking) return cb();
|
||||
let contract = params.contract;
|
||||
this.trackContract(contract.className, contract.realRuntimeBytecode, contract.realArgs, contract.deployedAddress);
|
||||
this.save();
|
||||
cb();
|
||||
}
|
||||
|
||||
checkIfDeploymentIsNeeded(params, cb) {
|
||||
if (!this.embark.config.contractsConfig.tracking) return;
|
||||
if (!this.trackContracts) {
|
||||
return cb(null, params);
|
||||
}
|
||||
|
||||
let contract = params.contract;
|
||||
let trackedContract = this.getContract(contract.className, contract.realRuntimeBytecode, contract.realArgs);
|
||||
if (trackedContract) {
|
||||
params.contract.address = trackedContract.address;
|
||||
}
|
||||
if (params.shouldDeploy && trackedContract) {
|
||||
params.shouldDeploy = true;
|
||||
}
|
||||
cb(null, params);
|
||||
}
|
||||
|
||||
loadChainTrackerFile() {
|
||||
if (this.chainFile === false) return;
|
||||
if (this.chainFile === undefined) this.chainFile = ".embark/chains.json";
|
||||
this.chainFile = dappPath(this.chainFile);
|
||||
if (!this.fs.existsSync(this.chainFile)) {
|
||||
this.logger.info(this.chainFile + ' ' + __('file not found, creating it...'));
|
||||
this.fs.outputJSONSync(this.chainFile, {});
|
||||
}
|
||||
|
||||
this.chainConfig = this.fs.readJSONSync(this.chainFile);
|
||||
}
|
||||
|
||||
setCurrentChain(_params, callback) {
|
||||
if (!this.embark.config.contractsConfig.tracking) return callback();
|
||||
if (this.chainFile === false) return callback();
|
||||
if (this.chainConfig === false) {
|
||||
this.currentChain = {contracts: []};
|
||||
return callback();
|
||||
}
|
||||
|
||||
this.getBlock(0, (err) => {
|
||||
if (err) {
|
||||
// Retry with block 1 (Block 0 fails with Ganache-cli using the --fork option)
|
||||
return this.getBlock(1, callback);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
async getBlock(blockNum, cb) {
|
||||
let provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||
var web3 = new Web3(provider);
|
||||
|
||||
try {
|
||||
let block = await web3.eth.getBlock(blockNum, true);
|
||||
let chainId = block.hash;
|
||||
|
||||
if (self.chainConfig[chainId] === undefined) {
|
||||
self.chainConfig[chainId] = { contracts: {} };
|
||||
}
|
||||
|
||||
self.currentChain = self.chainConfig[chainId];
|
||||
|
||||
self.currentChain.name = self.env;
|
||||
cb();
|
||||
} catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
|
||||
loadConfig(config) {
|
||||
this.chainConfig = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
trackContract(name, code, args, address) {
|
||||
if (!this.currentChain) return false;
|
||||
this.currentChain.contracts[sha3(code + name + args.join(','))] = { name, address };
|
||||
}
|
||||
|
||||
getContract(name, code, args) {
|
||||
if (!this.currentChain) return false;
|
||||
let contract = this.currentChain.contracts[sha3(code + name + args.join(','))];
|
||||
if (contract && contract.address === undefined) {
|
||||
return false;
|
||||
}
|
||||
return contract;
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.chainConfig === false) {
|
||||
return;
|
||||
}
|
||||
this.fs.writeJSONSync(this.chainFile, this.chainConfig, {spaces: 2});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DeployTracker;
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import {__} from 'embark-i18n';
|
||||
import {dappPath} from 'embark-utils';
|
||||
import Web3 from 'web3';
|
||||
|
||||
export default class TrackingFunctions {
|
||||
constructor({config, env, fs, events, logger, trackContracts}) {
|
||||
this.config = config;
|
||||
this.chainConfig = {};
|
||||
this.chainFile = config.contractsConfig.tracking;
|
||||
this.currentChain = null;
|
||||
this.env = env;
|
||||
this.fs = fs;
|
||||
this.events = events;
|
||||
this.logger = logger;
|
||||
this._web3 = null;
|
||||
this.trackContracts = (trackContracts !== false);
|
||||
}
|
||||
|
||||
get web3() {
|
||||
return (async () => {
|
||||
if (!this._web3) {
|
||||
const provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||
this._web3 = new Web3(provider);
|
||||
}
|
||||
return this._web3;
|
||||
})();
|
||||
}
|
||||
|
||||
getContract(contract) {
|
||||
if (!this.currentChain) return false;
|
||||
let contractInFile = this.currentChain.contracts[contract.hash];
|
||||
if (contractInFile && contractInFile.address === undefined) {
|
||||
return false;
|
||||
}
|
||||
return contractInFile;
|
||||
}
|
||||
|
||||
trackAndSaveContract(params, cb) {
|
||||
const {contract} = params;
|
||||
if (!this.chainFile || !this.trackContracts || contract.track === false) return cb();
|
||||
this.trackContract(contract);
|
||||
this.save();
|
||||
cb();
|
||||
}
|
||||
|
||||
loadChainTrackerFile() {
|
||||
if (this.chainFile === false) return;
|
||||
if (this.chainFile === undefined) this.chainFile = ".embark/chains.json";
|
||||
this.chainFile = dappPath(this.chainFile);
|
||||
if (!this.fs.existsSync(this.chainFile)) {
|
||||
this.logger.info(this.chainFile + ' ' + __('file not found, creating it...'));
|
||||
this.fs.outputJSONSync(this.chainFile, {});
|
||||
this.chainConfig = {};
|
||||
return;
|
||||
}
|
||||
|
||||
this.chainConfig = this.fs.readJSONSync(this.chainFile);
|
||||
}
|
||||
|
||||
setCurrentChain(_params, callback) {
|
||||
if (this.chainFile === false) return callback();
|
||||
if (this.chainConfig === false) {
|
||||
this.currentChain = {contracts: []};
|
||||
return callback();
|
||||
}
|
||||
|
||||
this.getBlock(0, (err) => {
|
||||
if (err) {
|
||||
// Retry with block 1 (Block 0 fails with Ganache-cli using the --fork option)
|
||||
return this.getBlock(1, callback);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
async getBlock(blockNum, cb) {
|
||||
try {
|
||||
const web3 = await this.web3;
|
||||
let block = await web3.eth.getBlock(blockNum, true);
|
||||
let chainId = block.hash;
|
||||
|
||||
if (this.chainConfig[chainId] === undefined) {
|
||||
this.chainConfig[chainId] = {contracts: {}};
|
||||
}
|
||||
|
||||
this.currentChain = this.chainConfig[chainId];
|
||||
|
||||
this.currentChain.name = this.env;
|
||||
cb();
|
||||
} catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
|
||||
loadConfig(config) {
|
||||
this.chainConfig = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
trackContract(contract) {
|
||||
if (!this.currentChain) return false;
|
||||
this.currentChain.contracts[contract.hash] = {name: contract.className, address: contract.deployedAddress};
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.chainConfig === false) {
|
||||
return;
|
||||
}
|
||||
this.fs.writeJSONSync(this.chainFile, this.chainConfig, {spaces: 2});
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
import {__} from 'embark-i18n';
|
||||
const async = require('async');
|
||||
|
||||
class ContractDeployer {
|
||||
|
@ -8,7 +8,7 @@ class ContractDeployer {
|
|||
this.plugins = options.plugins;
|
||||
this.deployer = {};
|
||||
this.events.setCommandHandler("deployment:deployer:register", (blockchainType, deployerCb) => {
|
||||
this.deployer[blockchainType] = deployerCb
|
||||
this.deployer[blockchainType] = deployerCb;
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('deployment:contract:deploy', this.deployContract.bind(this));
|
||||
|
@ -28,33 +28,33 @@ class ContractDeployer {
|
|||
},
|
||||
(next) => {
|
||||
// self.plugins.emitAndRunActionsForEvent('deployment:contract:arguments', {contract: contract}, (_params) => {
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, (_params) => {
|
||||
next();
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, (err, params) => {
|
||||
next(err, params);
|
||||
});
|
||||
},
|
||||
(next) => {
|
||||
if (contract.deploy === false) {
|
||||
(params, next) => {
|
||||
|
||||
if (!params.shouldDeploy) {
|
||||
this.events.emit("deployment:contract:undeployed", contract);
|
||||
return next();
|
||||
return next(null, null);
|
||||
}
|
||||
|
||||
console.dir("deploying contract");
|
||||
console.dir(contract.className);
|
||||
// this.deployer[contract.blockchainType].apply(this.deployer, [contract, next])
|
||||
this.deployer["ethereum"].apply(this.deployer, [contract, next])
|
||||
// next();
|
||||
// TODO: implement `blockchainType` a la `this.deployer[contract.blockchainType].apply(this.deployer, [contract, next])`
|
||||
this.deployer["ethereum"].apply(this.deployer, [contract, next]);
|
||||
},
|
||||
(next) => {
|
||||
console.dir("-------> contract deployed")
|
||||
if (contract.deploy === false) return next();
|
||||
console.dir("-------> contract deployed 2")
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:deployed', {contract: contract}, (_params) => {
|
||||
next();
|
||||
(receipt, next) => {
|
||||
if (!receipt) return next();
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:deployed', {contract, receipt}, (err, _params) => {
|
||||
next(err);
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
], (err) => {
|
||||
if (err) {
|
||||
this.events.emit("deploy:contract:error", contract);
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ContractDeployer;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
import {__} from 'embark-i18n';
|
||||
const async = require('async');
|
||||
|
||||
const ContractDeployer = require('./contract_deployer.js');
|
||||
|
@ -15,7 +15,8 @@ class Deployment {
|
|||
|
||||
this.contractDeployer = new ContractDeployer({
|
||||
events: this.events,
|
||||
plugins: this.plugins
|
||||
plugins: this.plugins,
|
||||
logger: this.logger
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('deployment:contracts:deploy', (contractsList, contractDependencies, cb) => {
|
||||
|
@ -27,17 +28,17 @@ class Deployment {
|
|||
this.logger.info(__("deploying contracts"));
|
||||
async.waterfall([
|
||||
// TODO used to be called this.plugins.emitAndRunActionsForEvent("deploy:beforeAll", (err) => {
|
||||
(next) => { this.plugins.emitAndRunActionsForEvent('deployment:deployContracts:beforeAll', {}, () => { next() }); },
|
||||
(next) => { this.deployAll(contracts, contractDependencies, () => { next() }); },
|
||||
(next) => {this.plugins.emitAndRunActionsForEvent('deployment:deployContracts:beforeAll', {}, () => {next()});},
|
||||
(next) => {this.deployAll(contracts, contractDependencies, next);},
|
||||
(next) => {
|
||||
this.events.emit('contractsDeployed');
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:deployContracts:afterAll', {}, () => { next() });
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:deployContracts:afterAll', {}, () => {next()});
|
||||
console.dir("==== finished deploying");
|
||||
}
|
||||
], done);
|
||||
}
|
||||
|
||||
deployContract(contract, callback) {
|
||||
deployContract(contract, errors, callback) {
|
||||
console.dir("requesting to deploy contract")
|
||||
this.events.request('deployment:contract:deploy', contract, (err) => {
|
||||
if (err) {
|
||||
|
@ -63,7 +64,7 @@ class Deployment {
|
|||
function deploy(result, callback) {
|
||||
console.dir("== deploy")
|
||||
if (typeof result === 'function') callback = result;
|
||||
self.deployContract(contract, callback);
|
||||
self.deployContract(contract, errors, callback);
|
||||
}
|
||||
|
||||
const className = contract.className;
|
||||
|
@ -75,23 +76,22 @@ class Deployment {
|
|||
contractDeploys[className].push(deploy);
|
||||
})
|
||||
|
||||
async.auto(contractDeploys, (_err, _results) => {
|
||||
if (_err) {
|
||||
async.auto(contractDeploys, (err, _results) => {
|
||||
if (err) {
|
||||
console.dir("error deploying contracts")
|
||||
console.dir(_err)
|
||||
console.dir(err)
|
||||
}
|
||||
if (errors.length) {
|
||||
_err = __("Error deploying contracts. Please fix errors to continue.");
|
||||
this.logger.error(_err);
|
||||
err = __("Error deploying contracts. Please fix errors to continue.");
|
||||
this.events.emit("outputError", __("Error deploying contracts, please check console"));
|
||||
return done(_err);
|
||||
return done(err);
|
||||
}
|
||||
if (contracts.length === 0) {
|
||||
this.logger.info(__("no contracts found"));
|
||||
return done();
|
||||
}
|
||||
this.logger.info(__("finished deploying contracts"));
|
||||
done(_err);
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import "./src/remix-debug-debugtest";
|
|||
export * from "./src/callbacks";
|
||||
export * from "./src/contract";
|
||||
export * from "./src/embark";
|
||||
export * from "./src/contractsConfig";
|
||||
export * from "./src/embarkConfig";
|
||||
export * from "./src/logger";
|
||||
export * from "./src/maybe";
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
export interface ContractsConfig {
|
||||
deploy: { [name: string]: ContractConfig }
|
||||
gas: string | number;
|
||||
tracking: boolean | string;
|
||||
}
|
||||
|
||||
export interface ContractConfig {
|
||||
address?: string;
|
||||
args?: Array<any>;
|
||||
instanceOf?: string;
|
||||
gas?: number;
|
||||
gasPrice?: number;
|
||||
silent?: boolean;
|
||||
track?: boolean;
|
||||
deploy?: boolean;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
export interface Logger {
|
||||
info(text: string): void;
|
||||
warn(text: string): void;
|
||||
error(text: string, ...args: Array<string|Error>): void;
|
||||
trace(text: string): void;
|
||||
error(text: string, ...args: Array<string | Error>): void;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BlockchainClient, Simulator } from 'embark-blockchain-process';
|
||||
import { __ } from 'embark-i18n';
|
||||
import { dappPath, embarkPath } from 'embark-utils';
|
||||
import {BlockchainClient, Simulator} from 'embark-blockchain-process';
|
||||
import {__} from 'embark-i18n';
|
||||
import {dappPath, embarkPath} from 'embark-utils';
|
||||
import findUp from 'find-up';
|
||||
let async = require('async');
|
||||
const constants = require('embark-core/constants');
|
||||
|
@ -209,7 +209,7 @@ class EmbarkController {
|
|||
engine.events.emit("status", __("Ready").green);
|
||||
});
|
||||
|
||||
engine.events.on('file-event', async ({ fileType, path }) => {
|
||||
engine.events.on('file-event', async ({fileType, path}) => {
|
||||
// TODO: re-add async.cargo / or use rxjs to use latest request in the queue
|
||||
console.dir("-- before timeout - file changed")
|
||||
|
||||
|
@ -219,7 +219,12 @@ class EmbarkController {
|
|||
let _contractsConfig = await engine.events.request2("config:contractsConfig");
|
||||
let contractsConfig = cloneDeep(_contractsConfig);
|
||||
let [contractsList, contractDependencies] = await engine.events.request2("contracts:build", contractsConfig, compiledContracts);
|
||||
await engine.events.request2("deployment:contracts:deploy", contractsList, contractDependencies);
|
||||
try {
|
||||
await engine.events.request2("deployment:contracts:deploy", contractsList, contractDependencies);
|
||||
}
|
||||
catch (err) {
|
||||
engine.logger.error(err);
|
||||
}
|
||||
} else if (fileType === 'asset') {
|
||||
engine.events.request('pipeline:generateAll', () => {
|
||||
console.dir("outputDone")
|
||||
|
@ -238,7 +243,12 @@ class EmbarkController {
|
|||
let _contractsConfig = await engine.events.request2("config:contractsConfig");
|
||||
let contractsConfig = cloneDeep(_contractsConfig);
|
||||
let [contractsList, contractDependencies] = await engine.events.request2("contracts:build", contractsConfig, compiledContracts);
|
||||
await engine.events.request2("deployment:contracts:deploy", contractsList, contractDependencies);
|
||||
try {
|
||||
await engine.events.request2("deployment:contracts:deploy", contractsList, contractDependencies);
|
||||
}
|
||||
catch (err) {
|
||||
engine.logger.error(err);
|
||||
}
|
||||
console.dir("deployment done")
|
||||
|
||||
await engine.events.request2("watcher:start")
|
||||
|
@ -470,7 +480,7 @@ class EmbarkController {
|
|||
});
|
||||
}
|
||||
], function (err, canExit) {
|
||||
if(err) {
|
||||
if (err) {
|
||||
engine.logger.error(err.message || err);
|
||||
}
|
||||
// TODO: this should be moved out and determined somewhere else
|
||||
|
@ -499,7 +509,7 @@ class EmbarkController {
|
|||
webpackConfigName: options.webpackConfigName
|
||||
});
|
||||
|
||||
const isSecondaryProcess = (engine) => { return engine.ipc.connected && engine.ipc.isClient(); };
|
||||
const isSecondaryProcess = (engine) => {return engine.ipc.connected && engine.ipc.isClient();};
|
||||
|
||||
async.waterfall([
|
||||
function initEngine(callback) {
|
||||
|
@ -537,7 +547,7 @@ class EmbarkController {
|
|||
},
|
||||
function deploy(callback) {
|
||||
// Skip if we are connected to a websocket, the server will do it
|
||||
if(isSecondaryProcess(engine)) {
|
||||
if (isSecondaryProcess(engine)) {
|
||||
return callback();
|
||||
}
|
||||
engine.config.reloadConfig();
|
||||
|
@ -547,7 +557,7 @@ class EmbarkController {
|
|||
},
|
||||
function waitForWriteFinish(callback) {
|
||||
// Skip if we are connected to a websocket, the server will do it
|
||||
if(isSecondaryProcess(engine)) {
|
||||
if (isSecondaryProcess(engine)) {
|
||||
return callback();
|
||||
}
|
||||
engine.logger.info("Finished deploying".underline);
|
||||
|
@ -695,7 +705,7 @@ class EmbarkController {
|
|||
callback();
|
||||
},
|
||||
function generateContract(callback) {
|
||||
engine.events.request('scaffolding:generate:contract', options, function(files) {
|
||||
engine.events.request('scaffolding:generate:contract', options, function (files) {
|
||||
files.forEach(file => engine.events.request('config:contractsFiles:add', file));
|
||||
callback();
|
||||
});
|
||||
|
@ -714,7 +724,7 @@ class EmbarkController {
|
|||
callback();
|
||||
},
|
||||
function deploy(callback) {
|
||||
engine.events.request('deploy:contracts', function(err) {
|
||||
engine.events.request('deploy:contracts', function (err) {
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
|
@ -723,7 +733,7 @@ class EmbarkController {
|
|||
callback();
|
||||
});
|
||||
}
|
||||
], function(err) {
|
||||
], function (err) {
|
||||
if (err) {
|
||||
engine.logger.error(__("Error generating the UI: "));
|
||||
engine.logger.error(err.message || err);
|
||||
|
@ -805,7 +815,12 @@ class EmbarkController {
|
|||
let _contractsConfig = await engine.events.request2("config:contractsConfig");
|
||||
let contractsConfig = cloneDeep(_contractsConfig);
|
||||
let [contractsList, contractDependencies] = await engine.events.request2("contracts:build", contractsConfig, compiledContracts);
|
||||
await engine.events.request2("deployment:contracts:deploy", contractsList, contractDependencies);
|
||||
try {
|
||||
await engine.events.request2("deployment:contracts:deploy", contractsList, contractDependencies);
|
||||
}
|
||||
catch (err) {
|
||||
engine.logger.error(err);
|
||||
}
|
||||
console.dir("deployment done")
|
||||
|
||||
await engine.events.request2('pipeline:generateAll');
|
||||
|
@ -831,17 +846,17 @@ class EmbarkController {
|
|||
// });
|
||||
}
|
||||
// function associateToENS(hash, callback) {
|
||||
// if(!options.ensDomain) {
|
||||
// return callback(null, hash);
|
||||
// }
|
||||
// engine.events.request("storage:ens:associate",
|
||||
// {name: options.ensDomain, storageHash: hash}, (err) => {
|
||||
// if (err) {
|
||||
// return callback(err);
|
||||
// }
|
||||
// engine.logger.info(__('ENS association completed for {{hash}} at {{domain}}', {hash, domain: options.ensDomain}));
|
||||
// callback();
|
||||
// });
|
||||
// if(!options.ensDomain) {
|
||||
// return callback(null, hash);
|
||||
// }
|
||||
// engine.events.request("storage:ens:associate",
|
||||
// {name: options.ensDomain, storageHash: hash}, (err) => {
|
||||
// if (err) {
|
||||
// return callback(err);
|
||||
// }
|
||||
// engine.logger.info(__('ENS association completed for {{hash}} at {{domain}}', {hash, domain: options.ensDomain}));
|
||||
// callback();
|
||||
// });
|
||||
// }
|
||||
], function (err) {
|
||||
if (err) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {__} from 'embark-i18n';
|
||||
|
||||
const async = require('async');
|
||||
const Web3 = require('web3');
|
||||
const embarkJsUtils = require('embarkjs').Utils;
|
||||
|
@ -7,6 +9,7 @@ class EthereumBlockchainClient {
|
|||
constructor(embark, options) {
|
||||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
this.logger = embark.logger;
|
||||
|
||||
this.embark.registerActionForEvent("deployment:contract:deployed", this.addContractJSONToPipeline.bind(this));
|
||||
this.embark.registerActionForEvent('deployment:contract:beforeDeploy', this.determineArguments.bind(this));
|
||||
|
@ -30,7 +33,7 @@ class EthereumBlockchainClient {
|
|||
console.dir("== ethereum contract deployer")
|
||||
let contractObj = new web3.eth.Contract(contract.abiDefinition, contract.address);
|
||||
// let deployObject = this.blockchain.deployContractObject(contractObject, {arguments: contractParams, data: dataCode});
|
||||
let contractObject = contractObj.deploy({ arguments: (contract.args || []), data: ("0x" + contract.code) });
|
||||
let contractObject = contractObj.deploy({arguments: (contract.args || []), data: ("0x" + contract.code)});
|
||||
|
||||
if (contract.gas === 'auto' || !contract.gas) {
|
||||
let gasValue = await contractObject.estimateGas();
|
||||
|
@ -44,7 +47,7 @@ class EthereumBlockchainClient {
|
|||
}
|
||||
|
||||
// this.blockchain.deployContractFromObject(deployObject,
|
||||
console.dir({ arguments: contract.args, data: ("0x" + contract.code) });
|
||||
console.dir({arguments: contract.args, data: ("0x" + contract.code)});
|
||||
console.dir("------- send")
|
||||
|
||||
embarkJsUtils.secureSend(web3, contractObject, {
|
||||
|
@ -52,7 +55,8 @@ class EthereumBlockchainClient {
|
|||
}, true, (err, receipt) => {
|
||||
contract.deployedAddress = receipt.contractAddress;
|
||||
contract.transactionHash = receipt.transactionHash;
|
||||
done();
|
||||
contract.log(`${contract.className.bold.cyan} ${__('deployed at').green} ${receipt.contractAddress.bold.cyan} ${__("using").green} ${receipt.gasUsed} ${__("gas").green} (txHash: ${receipt.transactionHash.bold.cyan})`);
|
||||
done(err, receipt);
|
||||
}, (hash) => {
|
||||
console.dir('hash is ' + hash);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue