mirror of https://github.com/embarklabs/embark.git
Merge branch 'beforeDeploy' into develop
This commit is contained in:
commit
ffe9af74bb
|
@ -29,6 +29,7 @@ The ``embark`` object then provides an api to extend different functionality of
|
||||||
* plugin to add standard contracts or a contract framework (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
* plugin to add standard contracts or a contract framework (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
||||||
* plugin to make some contracts available in all environments for use by other contracts or the dapp itself e.g a Token, a DAO, ENS, etc.. (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
* plugin to make some contracts available in all environments for use by other contracts or the dapp itself e.g a Token, a DAO, ENS, etc.. (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
||||||
* plugin to add a libraries such as react or boostrap (``embark.addFileToPipeline``)
|
* plugin to add a libraries such as react or boostrap (``embark.addFileToPipeline``)
|
||||||
|
* plugin to process contract's binary code before deployment (``embark.beforeDeploy``)
|
||||||
* plugin to specify a particular web3 initialization for special provider uses (``embark.registerClientWeb3Provider``)
|
* plugin to specify a particular web3 initialization for special provider uses (``embark.registerClientWeb3Provider``)
|
||||||
* plugin to create a different contract wrapper (``embark.registerContractsGeneration``)
|
* plugin to create a different contract wrapper (``embark.registerContractsGeneration``)
|
||||||
* plugin to add new console commands (``embark.registerConsoleCommand``)
|
* plugin to add new console commands (``embark.registerConsoleCommand``)
|
||||||
|
@ -137,6 +138,30 @@ This call is used to add a file to the pipeline so it's included with the dapp o
|
||||||
embark.addFileToPipeline("./jquery.js", {skipPipeline: true});
|
embark.addFileToPipeline("./jquery.js", {skipPipeline: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
**embark.registerBeforeDeploy(callback(options))**
|
||||||
|
|
||||||
|
This call can be used to add handler to process contract code after it was generated, but immediately before it is going to be deployed.
|
||||||
|
It is useful to replace placeholders with dynamic values.
|
||||||
|
|
||||||
|
options available:
|
||||||
|
* embarkDeploy - instance of Deploy class. Has following fields: web3, contractsManager, logger, env, chainConfig, gasLimit.
|
||||||
|
* pluginConfig - plugin configuration object from embark.json
|
||||||
|
* deploymentAccount - address of account which will be used to deploy this contract
|
||||||
|
* contract - contract object.
|
||||||
|
* callback - callback function that handler must call with result object as the only argument. Result object must have field contractCode with (un)modified code from contract.code
|
||||||
|
|
||||||
|
expected return: ignored
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
|
.. code:: javascript
|
||||||
|
|
||||||
|
module.exports = function(embark) {
|
||||||
|
embark.registerBeforeDeploy(function(options) {
|
||||||
|
return options.contract.code.replace(/deaddeaddeaddeaddeaddeaddeaddeaddeaddead/ig, 'c0dec0dec0dec0dec0dec0dec0dec0dec0dec0de');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
**embark.registerClientWeb3Provider(callback(options))**
|
**embark.registerClientWeb3Provider(callback(options))**
|
||||||
|
|
||||||
|
@ -165,7 +190,7 @@ example:
|
||||||
By default Embark will use EmbarkJS to declare contracts in the dapp. You can override and use your own client side library.
|
By default Embark will use EmbarkJS to declare contracts in the dapp. You can override and use your own client side library.
|
||||||
|
|
||||||
options available:
|
options available:
|
||||||
* contracts - Hash of objects containing all the deployed contracts. (key: contractName, value: contract object)
|
* contracts - Hash of objects containing all the deployed contracts. (key: contractName, value: contract object)
|
||||||
* abiDefinition
|
* abiDefinition
|
||||||
* code
|
* code
|
||||||
* deployedAddress
|
* deployedAddress
|
||||||
|
@ -210,18 +235,15 @@ expected return: ``string`` (output to print in console) or ``boolean`` (skip co
|
||||||
|
|
||||||
expected doneCallback arguments: ``err`` and ``hash`` of compiled contracts
|
expected doneCallback arguments: ``err`` and ``hash`` of compiled contracts
|
||||||
|
|
||||||
* Hash of objects containing the compiled contracts. (key: contractName, value: contract object)
|
* Hash of objects containing the compiled contracts. (key: contractName, value: contract object)
|
||||||
|
|
||||||
* code - contract bytecode (string)
|
* code - contract bytecode (string)
|
||||||
|
|
||||||
* runtimeBytecode - contract runtimeBytecode (string)
|
* runtimeBytecode - contract runtimeBytecode (string)
|
||||||
|
|
||||||
* gasEstimates - gas estimates for constructor and methods (hash)
|
* gasEstimates - gas estimates for constructor and methods (hash)
|
||||||
* e.g ``{"creation":[20131,38200],"external":{"get()":269,"set(uint256)":20163,"storedData()":224},"internal":{}}``
|
* e.g ``{"creation":[20131,38200],"external":{"get()":269,"set(uint256)":20163,"storedData()":224},"internal":{}}``
|
||||||
* functionHashes - object with methods and their corresponding hash identifier (hash)
|
* functionHashes - object with methods and their corresponding hash identifier (hash)
|
||||||
* e.g ``{"get()":"6d4ce63c","set(uint256)":"60fe47b1","storedData()":"2a1afcd9"}``
|
* e.g ``{"get()":"6d4ce63c","set(uint256)":"60fe47b1","storedData()":"2a1afcd9"}``
|
||||||
* abiDefinition - contract abi (array of objects)
|
* abiDefinition - contract abi (array of objects)
|
||||||
* e.g ``[{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}, etc...``
|
* e.g ``[{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}, etc...``
|
||||||
|
|
||||||
below a possible implementation of a solcjs plugin:
|
below a possible implementation of a solcjs plugin:
|
||||||
|
|
||||||
|
@ -271,15 +293,12 @@ e.g ``embark.logger.info("hello")``
|
||||||
This call is used to listen and react to events that happen in Embark such as contract deployment
|
This call is used to listen and react to events that happen in Embark such as contract deployment
|
||||||
|
|
||||||
* eventName - name of event to listen to
|
* eventName - name of event to listen to
|
||||||
* available events:
|
* available events:
|
||||||
* "contractsDeployed" - triggered when contracts have been deployed
|
* "contractsDeployed" - triggered when contracts have been deployed
|
||||||
* "file-add", "file-change", "file-remove", "file-event" - triggered on
|
* "file-add", "file-change", "file-remove", "file-event" - triggered on a file change, args is (filetype, path)
|
||||||
a file change, args is (filetype, path)
|
* "abi", "abi-vanila", "abi-contracts-vanila" - triggered when contracts have been deployed and returns the generated JS code
|
||||||
* "abi", "abi-vanila", "abi-contracts-vanila" - triggered when contracts
|
* "outputDone" - triggered when dapp is (re)generated
|
||||||
have been deployed and returns the generated JS code
|
* "firstDeploymentDone" - triggered when the dapp is deployed and generated for the first time
|
||||||
* "outputDone" - triggered when dapp is (re)generated
|
|
||||||
* "firstDeploymentDone" - triggered when the dapp is deployed and generated
|
|
||||||
for the first time
|
|
||||||
|
|
||||||
.. code:: javascript
|
.. code:: javascript
|
||||||
|
|
||||||
|
@ -293,4 +312,3 @@ This call is used to listen and react to events that happen in Embark such as co
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Deploy {
|
||||||
this.logger = options.logger;
|
this.logger = options.logger;
|
||||||
this.env = options.env;
|
this.env = options.env;
|
||||||
this.chainConfig = options.chainConfig;
|
this.chainConfig = options.chainConfig;
|
||||||
|
this.plugins = options.plugins;
|
||||||
this.gasLimit = options.gasLimit;
|
this.gasLimit = options.gasLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +183,8 @@ class Deploy {
|
||||||
}
|
}
|
||||||
|
|
||||||
let contractCode = contract.code;
|
let contractCode = contract.code;
|
||||||
|
|
||||||
|
// Applying linked contracts
|
||||||
let contractsList = self.contractsManager.listContracts();
|
let contractsList = self.contractsManager.listContracts();
|
||||||
for (let contractObj of contractsList) {
|
for (let contractObj of contractsList) {
|
||||||
let filename = contractObj.filename;
|
let filename = contractObj.filename;
|
||||||
|
@ -204,47 +207,88 @@ class Deploy {
|
||||||
contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress);
|
contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
let contractObject = new self.web3.eth.Contract(contract.abiDefinition);
|
// saving code changes back to contract object
|
||||||
let deployObject;
|
contract.code = contractCode;
|
||||||
|
|
||||||
try {
|
// selected in deploy_manager
|
||||||
deployObject = contractObject.deploy({arguments: contractParams, data: "0x" + contractCode});
|
let deploymentAccount = self.web3.eth.defaultAccount || accounts[0];
|
||||||
} catch(e) {
|
let beforeDeployPlugins = self.plugins.getPluginsFor('beforeDeploy');
|
||||||
if (e.indexOf('Invalid number of parameters for "undefined"') >= 0) {
|
|
||||||
return callback(new Error("attempted to deploy " + contractObject.className + " without specifying parameters"));
|
|
||||||
} else {
|
|
||||||
return callback(new Error(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.logger.info("deploying " + contract.className.bold.cyan + " with ".green + contract.gas + " gas".green);
|
async.waterfall([
|
||||||
|
(asyncCallback)=>{
|
||||||
|
//self.logger.info("applying beforeDeploy plugins...", beforeDeployPlugins.length);
|
||||||
|
async.eachSeries(beforeDeployPlugins, (plugin, eachPluginCb)=>{
|
||||||
|
self.logger.info("running beforeDeploy plugin " + plugin.name + " .");
|
||||||
|
|
||||||
deployObject.send({
|
// calling each beforeDeploy handler declared by the plugin
|
||||||
from: accounts[0],
|
async.eachSeries(plugin.beforeDeploy, (beforeDeployFn, eachCb)=>{
|
||||||
gas: contract.gas,
|
beforeDeployFn({
|
||||||
gasPrice: contract.gasPrice
|
embarkDeploy: self,
|
||||||
}).on('receipt', function(receipt) {
|
pluginConfig: plugin.pluginConfig,
|
||||||
if (err) {
|
deploymentAccount: deploymentAccount,
|
||||||
self.logger.error("error deploying contract: " + contract.className.cyan);
|
contract: contract,
|
||||||
let errMsg = err.toString();
|
callback:
|
||||||
if (errMsg === 'Error: The contract code couldn\'t be stored, please check your gas amount.') {
|
(function(resObj){
|
||||||
errMsg = 'The contract code couldn\'t be stored, out of gas or constructor error';
|
contract.code = resObj.contractCode;
|
||||||
|
eachCb();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}, ()=>{
|
||||||
|
//self.logger.info('All beforeDeploy handlers of the plugin has processed.');
|
||||||
|
eachPluginCb();
|
||||||
|
});
|
||||||
|
}, ()=>{
|
||||||
|
//self.logger.info('All beforeDeploy plugins has been processed.');
|
||||||
|
contractCode = contract.code;
|
||||||
|
asyncCallback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(asyncCallback)=>{
|
||||||
|
let contractObject = new self.web3.eth.Contract(contract.abiDefinition);
|
||||||
|
let deployObject;
|
||||||
|
|
||||||
|
try {
|
||||||
|
deployObject = contractObject.deploy({arguments: contractParams, data: "0x" + contractCode});
|
||||||
|
} catch(e) {
|
||||||
|
if (e.indexOf('Invalid number of parameters for "undefined"') >= 0) {
|
||||||
|
return callback(new Error("attempted to deploy " + contractObject.className + " without specifying parameters"));
|
||||||
|
} else {
|
||||||
|
return callback(new Error(e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.logger.error(errMsg);
|
|
||||||
contract.error = errMsg;
|
self.logger.info("deploying " + contract.className.bold.cyan + " with ".green + contract.gas + " gas".green);
|
||||||
self.logger.contractsState(self.contractsManager.contractsState());
|
|
||||||
return callback(new Error(err));
|
deployObject.send({
|
||||||
} else if (receipt.contractAddress !== undefined) {
|
from: deploymentAccount,
|
||||||
self.logger.info(contract.className.bold.cyan + " deployed at ".green + receipt.contractAddress.bold.cyan);
|
gas: contract.gas,
|
||||||
contract.deployedAddress = receipt.contractAddress;
|
gasPrice: contract.gasPrice
|
||||||
contract.transactionHash = receipt.transactionHash;
|
}).on('receipt', function(receipt) {
|
||||||
self.logger.contractsState(self.contractsManager.contractsState());
|
if (err) {
|
||||||
return callback(null, receipt.contractAddress);
|
self.logger.error("error deploying contract: " + contract.className.cyan);
|
||||||
|
let errMsg = err.toString();
|
||||||
|
if (errMsg === 'Error: The contract code couldn\'t be stored, please check your gas amount.') {
|
||||||
|
errMsg = 'The contract code couldn\'t be stored, out of gas or constructor error';
|
||||||
|
}
|
||||||
|
self.logger.error(errMsg);
|
||||||
|
contract.error = errMsg;
|
||||||
|
self.logger.contractsState(self.contractsManager.contractsState());
|
||||||
|
return callback(new Error(err));
|
||||||
|
} else if (receipt.contractAddress !== undefined) {
|
||||||
|
self.logger.info(contract.className.bold.cyan + " deployed at ".green + receipt.contractAddress.bold.cyan);
|
||||||
|
contract.deployedAddress = receipt.contractAddress;
|
||||||
|
contract.transactionHash = receipt.transactionHash;
|
||||||
|
self.logger.contractsState(self.contractsManager.contractsState());
|
||||||
|
return callback(null, receipt.contractAddress);
|
||||||
|
}
|
||||||
|
self.logger.contractsState(self.contractsManager.contractsState());
|
||||||
|
}).on('error', function(error) {
|
||||||
|
return callback(new Error("error deploying =" + contract.className + "= due to error: " + error.message));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self.logger.contractsState(self.contractsManager.contractsState());
|
]); // end of async.waterfall
|
||||||
}).on('error', function(error) {
|
|
||||||
return callback(new Error("error deploying =" + contract.className + "= due to error: " + error.message));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@ class DeployManager {
|
||||||
logger: self.logger,
|
logger: self.logger,
|
||||||
chainConfig: self.chainConfig,
|
chainConfig: self.chainConfig,
|
||||||
env: self.config.env,
|
env: self.config.env,
|
||||||
|
plugins: self.plugins,
|
||||||
gasLimit: self.gasLimit
|
gasLimit: self.gasLimit
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ var Plugin = function(options) {
|
||||||
this.pluginConfig = options.pluginConfig;
|
this.pluginConfig = options.pluginConfig;
|
||||||
this.shouldInterceptLogs = options.interceptLogs;
|
this.shouldInterceptLogs = options.interceptLogs;
|
||||||
this.clientWeb3Providers = [];
|
this.clientWeb3Providers = [];
|
||||||
|
this.beforeDeploy = [];
|
||||||
this.contractsGenerators = [];
|
this.contractsGenerators = [];
|
||||||
this.pipeline = [];
|
this.pipeline = [];
|
||||||
this.pipelineFiles = [];
|
this.pipelineFiles = [];
|
||||||
|
@ -85,6 +86,11 @@ Plugin.prototype.registerClientWeb3Provider = function(cb) {
|
||||||
this.pluginTypes.push('clientWeb3Provider');
|
this.pluginTypes.push('clientWeb3Provider');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Plugin.prototype.registerBeforeDeploy = function(cb) {
|
||||||
|
this.beforeDeploy.push(cb);
|
||||||
|
this.pluginTypes.push('beforeDeploy');
|
||||||
|
};
|
||||||
|
|
||||||
Plugin.prototype.registerContractsGeneration = function(cb) {
|
Plugin.prototype.registerContractsGeneration = function(cb) {
|
||||||
this.contractsGenerators.push(cb);
|
this.contractsGenerators.push(cb);
|
||||||
this.pluginTypes.push('contractGeneration');
|
this.pluginTypes.push('contractGeneration');
|
||||||
|
|
Loading…
Reference in New Issue