mirror of https://github.com/embarklabs/embark.git
refactor contracts manager; deployment; blockchain client
This commit is contained in:
parent
d80f04850a
commit
261dee8ad0
|
@ -1,170 +1,176 @@
|
|||
/*global web3*/
|
||||
import React from 'react';
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import {SimpleStorage, Test, SimpleStorageTest} from '../../embarkArtifacts/contracts';
|
||||
|
||||
window.SimpleStorageTest = SimpleStorageTest;
|
||||
import {SimpleStorage} from '../../embarkArtifacts/contracts';
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import $ from 'jquery';
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import 'bootstrap/dist/css/bootstrap-theme.css';
|
||||
import 'bootstrap/dist/js/bootstrap.min.js';
|
||||
|
||||
window.EmbarkJS = EmbarkJS;
|
||||
window.SimpleStorage = SimpleStorage;
|
||||
window.Test = Test;
|
||||
//window.Assert = Assert;
|
||||
|
||||
window.React = React;
|
||||
|
||||
import './foo.css';
|
||||
|
||||
import App from './app.js';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
|
||||
var addToLog = function(id, txt) {
|
||||
$(id + " .logs").append("<br>" + txt);
|
||||
};
|
||||
|
||||
// ===========================
|
||||
// Blockchain example
|
||||
// ===========================
|
||||
$(document).ready(function() {
|
||||
EmbarkJS.onReady((err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
console.log([1,2,3].map(v => v + 1));
|
||||
|
||||
$("#blockchain button.set").click(function() {
|
||||
var value = parseInt($("#blockchain input.text").val(), 10);
|
||||
|
||||
SimpleStorage.methods.set(value).send({from: web3.eth.defaultAccount, gas: 5300000});
|
||||
addToLog("#blockchain", "SimpleStorage.methods.set(value).send({from: web3.eth.defaultAccount, gas: 5300000})");
|
||||
});
|
||||
|
||||
$("#blockchain button.get").click(function() {
|
||||
SimpleStorage.methods.get().call(function(err, value) {
|
||||
$("#blockchain .value").html(value);
|
||||
});
|
||||
addToLog("#blockchain", "SimpleStorage.methods.get(console.log)");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ===========================
|
||||
// Storage (IPFS) example
|
||||
// ===========================
|
||||
$(document).ready(function() {
|
||||
// automatic set if config/storage.json has "enabled": true and "provider": "ipfs"
|
||||
//EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'});
|
||||
|
||||
$("#storage .error").hide();
|
||||
//EmbarkJS.Storage.ipfsConnection.version()
|
||||
// .then(function(){
|
||||
$("#status-storage").addClass('status-online');
|
||||
$("#storage-controls").show();
|
||||
// })
|
||||
// .catch(function(err) {
|
||||
// if(err){
|
||||
// console.log("IPFS Connection Error => " + err.message);
|
||||
// $("#storage .error").show();
|
||||
// $("#status-storage").addClass('status-offline');
|
||||
// $("#storage-controls").hide();
|
||||
// }
|
||||
// });
|
||||
|
||||
$("#storage button.setIpfsText").click(function() {
|
||||
var value = $("#storage input.ipfsText").val();
|
||||
EmbarkJS.Storage.saveText(value).then(function(hash) {
|
||||
$("span.textHash").html(hash);
|
||||
$("input.textHash").val(hash);
|
||||
addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
|
||||
})
|
||||
.catch(function(err) {
|
||||
if(err){
|
||||
console.log("IPFS saveText Error => " + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#storage button.loadIpfsHash").click(function() {
|
||||
var value = $("#storage input.textHash").val();
|
||||
EmbarkJS.Storage.get(value).then(function(content) {
|
||||
$("span.ipfsText").html(content);
|
||||
addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
|
||||
})
|
||||
.catch(function(err) {
|
||||
if(err){
|
||||
console.log("IPFS get Error => " + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#storage button.uploadFile").click(function() {
|
||||
var input = $("#storage input[type=file]");
|
||||
EmbarkJS.Storage.uploadFile(input).then(function(hash) {
|
||||
$("span.fileIpfsHash").html(hash);
|
||||
$("input.fileIpfsHash").val(hash);
|
||||
addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
|
||||
})
|
||||
.catch(function(err) {
|
||||
if(err){
|
||||
console.log("IPFS uploadFile Error => " + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#storage button.loadIpfsFile").click(function() {
|
||||
var hash = $("#storage input.fileIpfsHash").val();
|
||||
var url = EmbarkJS.Storage.getUrl(hash);
|
||||
var link = '<a href="' + url + '" target="_blank">' + url + '</a>';
|
||||
$("span.ipfsFileUrl").html(link);
|
||||
$(".ipfsImage").attr('src', url);
|
||||
addToLog("#storage", "EmbarkJS.Storage.getUrl('" + hash + "')");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ===========================
|
||||
// Communication (Whisper) example
|
||||
// ===========================
|
||||
$(document).ready(function() {
|
||||
|
||||
$("#communication .error").hide();
|
||||
$("#communication .errorVersion").hide();
|
||||
if (EmbarkJS.Messages.providerName === 'whisper') {
|
||||
EmbarkJS.Messages.getWhisperVersion(function(err, _version) {
|
||||
if (err) {
|
||||
$("#communication .error").show();
|
||||
$("#communication-controls").hide();
|
||||
$("#status-communication").addClass('status-offline');
|
||||
} else {
|
||||
EmbarkJS.Messages.setProvider('whisper');
|
||||
$("#status-communication").addClass('status-online');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$("#communication button.listenToChannel").click(function() {
|
||||
var channel = $("#communication .listen input.channel").val();
|
||||
$("#communication #subscribeList").append("<br> subscribed to " + channel + " now try sending a message");
|
||||
EmbarkJS.Messages.listenTo({topic: [channel]}).subscribe(function({data: message}) {
|
||||
$("#communication #messagesList").append("<br> channel: " + channel + " message: " + message);
|
||||
});
|
||||
addToLog("#communication", "EmbarkJS.Messages.listenTo({topic: ['" + channel + "']}).then(function(message) {})");
|
||||
});
|
||||
|
||||
$("#communication button.sendMessage").click(function() {
|
||||
var channel = $("#communication .send input.channel").val();
|
||||
var message = $("#communication .send input.message").val();
|
||||
EmbarkJS.Messages.sendMessage({topic: channel, data: message});
|
||||
addToLog("#communication", "EmbarkJS.Messages.sendMessage({topic: '" + channel + "', data: '" + message + "'})");
|
||||
});
|
||||
|
||||
});
|
||||
// /*global web3*/
|
||||
// import React from 'react';
|
||||
// import EmbarkJS from 'Embark/EmbarkJS';
|
||||
// import {SimpleStorage, Test, SimpleStorageTest} from '../../embarkArtifacts/contracts';
|
||||
//
|
||||
// window.SimpleStorageTest = SimpleStorageTest;
|
||||
//
|
||||
// import ReactDOM from 'react-dom';
|
||||
//
|
||||
// import $ from 'jquery';
|
||||
// import 'bootstrap/dist/css/bootstrap.css';
|
||||
// import 'bootstrap/dist/css/bootstrap-theme.css';
|
||||
// import 'bootstrap/dist/js/bootstrap.min.js';
|
||||
//
|
||||
// window.EmbarkJS = EmbarkJS;
|
||||
// window.SimpleStorage = SimpleStorage;
|
||||
// window.Test = Test;
|
||||
// //window.Assert = Assert;
|
||||
//
|
||||
// window.React = React;
|
||||
//
|
||||
// import './foo.css';
|
||||
//
|
||||
// import App from './app.js';
|
||||
//
|
||||
// ReactDOM.render(<App />, document.getElementById('root'));
|
||||
//
|
||||
// var addToLog = function(id, txt) {
|
||||
// $(id + " .logs").append("<br>" + txt);
|
||||
// };
|
||||
//
|
||||
// // ===========================
|
||||
// // Blockchain example
|
||||
// // ===========================
|
||||
// $(document).ready(function() {
|
||||
// EmbarkJS.onReady((err) => {
|
||||
// if (err) {
|
||||
// console.error(err);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// console.log([1,2,3].map(v => v + 1));
|
||||
//
|
||||
// $("#blockchain button.set").click(function() {
|
||||
// var value = parseInt($("#blockchain input.text").val(), 10);
|
||||
//
|
||||
// SimpleStorage.methods.set(value).send({from: web3.eth.defaultAccount, gas: 5300000});
|
||||
// addToLog("#blockchain", "SimpleStorage.methods.set(value).send({from: web3.eth.defaultAccount, gas: 5300000})");
|
||||
// });
|
||||
//
|
||||
// $("#blockchain button.get").click(function() {
|
||||
// SimpleStorage.methods.get().call(function(err, value) {
|
||||
// $("#blockchain .value").html(value);
|
||||
// });
|
||||
// addToLog("#blockchain", "SimpleStorage.methods.get(console.log)");
|
||||
// });
|
||||
//
|
||||
// });
|
||||
//
|
||||
// // ===========================
|
||||
// // Storage (IPFS) example
|
||||
// // ===========================
|
||||
// $(document).ready(function() {
|
||||
// // automatic set if config/storage.json has "enabled": true and "provider": "ipfs"
|
||||
// //EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'});
|
||||
//
|
||||
// $("#storage .error").hide();
|
||||
// //EmbarkJS.Storage.ipfsConnection.version()
|
||||
// // .then(function(){
|
||||
// $("#status-storage").addClass('status-online');
|
||||
// $("#storage-controls").show();
|
||||
// // })
|
||||
// // .catch(function(err) {
|
||||
// // if(err){
|
||||
// // console.log("IPFS Connection Error => " + err.message);
|
||||
// // $("#storage .error").show();
|
||||
// // $("#status-storage").addClass('status-offline');
|
||||
// // $("#storage-controls").hide();
|
||||
// // }
|
||||
// // });
|
||||
//
|
||||
// $("#storage button.setIpfsText").click(function() {
|
||||
// var value = $("#storage input.ipfsText").val();
|
||||
// EmbarkJS.Storage.saveText(value).then(function(hash) {
|
||||
// $("span.textHash").html(hash);
|
||||
// $("input.textHash").val(hash);
|
||||
// addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
|
||||
// })
|
||||
// .catch(function(err) {
|
||||
// if(err){
|
||||
// console.log("IPFS saveText Error => " + err.message);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// $("#storage button.loadIpfsHash").click(function() {
|
||||
// var value = $("#storage input.textHash").val();
|
||||
// EmbarkJS.Storage.get(value).then(function(content) {
|
||||
// $("span.ipfsText").html(content);
|
||||
// addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
|
||||
// })
|
||||
// .catch(function(err) {
|
||||
// if(err){
|
||||
// console.log("IPFS get Error => " + err.message);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// $("#storage button.uploadFile").click(function() {
|
||||
// var input = $("#storage input[type=file]");
|
||||
// EmbarkJS.Storage.uploadFile(input).then(function(hash) {
|
||||
// $("span.fileIpfsHash").html(hash);
|
||||
// $("input.fileIpfsHash").val(hash);
|
||||
// addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
|
||||
// })
|
||||
// .catch(function(err) {
|
||||
// if(err){
|
||||
// console.log("IPFS uploadFile Error => " + err.message);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// $("#storage button.loadIpfsFile").click(function() {
|
||||
// var hash = $("#storage input.fileIpfsHash").val();
|
||||
// var url = EmbarkJS.Storage.getUrl(hash);
|
||||
// var link = '<a href="' + url + '" target="_blank">' + url + '</a>';
|
||||
// $("span.ipfsFileUrl").html(link);
|
||||
// $(".ipfsImage").attr('src', url);
|
||||
// addToLog("#storage", "EmbarkJS.Storage.getUrl('" + hash + "')");
|
||||
// });
|
||||
//
|
||||
// });
|
||||
//
|
||||
// // ===========================
|
||||
// // Communication (Whisper) example
|
||||
// // ===========================
|
||||
// $(document).ready(function() {
|
||||
//
|
||||
// $("#communication .error").hide();
|
||||
// $("#communication .errorVersion").hide();
|
||||
// if (EmbarkJS.Messages.providerName === 'whisper') {
|
||||
// EmbarkJS.Messages.getWhisperVersion(function(err, _version) {
|
||||
// if (err) {
|
||||
// $("#communication .error").show();
|
||||
// $("#communication-controls").hide();
|
||||
// $("#status-communication").addClass('status-offline');
|
||||
// } else {
|
||||
// EmbarkJS.Messages.setProvider('whisper');
|
||||
// $("#status-communication").addClass('status-online');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// $("#communication button.listenToChannel").click(function() {
|
||||
// var channel = $("#communication .listen input.channel").val();
|
||||
// $("#communication #subscribeList").append("<br> subscribed to " + channel + " now try sending a message");
|
||||
// EmbarkJS.Messages.listenTo({topic: [channel]}).subscribe(function({data: message}) {
|
||||
// $("#communication #messagesList").append("<br> channel: " + channel + " message: " + message);
|
||||
// });
|
||||
// addToLog("#communication", "EmbarkJS.Messages.listenTo({topic: ['" + channel + "']}).then(function(message) {})");
|
||||
// });
|
||||
//
|
||||
// $("#communication button.sendMessage").click(function() {
|
||||
// var channel = $("#communication .send input.channel").val();
|
||||
// var message = $("#communication .send input.message").val();
|
||||
// EmbarkJS.Messages.sendMessage({topic: channel, data: message});
|
||||
// addToLog("#communication", "EmbarkJS.Messages.sendMessage({topic: '" + channel + "', data: '" + message + "'})");
|
||||
// });
|
||||
//
|
||||
// });
|
||||
//
|
||||
|
|
|
@ -1,60 +1,61 @@
|
|||
import $ from 'jquery';
|
||||
|
||||
import {AlreadyDeployedToken, AnotherStorage, MyToken, MyToken2, SimpleStorage, Token} from '../../embarkArtifacts/contracts';
|
||||
import async from 'async';
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
document.getElementById("runTests").onclick = function() {
|
||||
async.waterfall([
|
||||
function test1(callback) {
|
||||
AnotherStorage.methods.simpleStorageAddress().call().then(function(simpleStorageAddress) {
|
||||
$("#tests").append("<br>test 1: " + (simpleStorageAddress === SimpleStorage._address));
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function test2(callback) {
|
||||
SimpleStorage.methods.storedData().call().then(function(result) {
|
||||
$("#tests").append("<br>test 2 (true first time): " + (result === "100"));
|
||||
$("#tests").append("<br>test 2 (true after): " + (result === "150"));
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function test3(callback) {
|
||||
SimpleStorage.methods.set(150).send({from: web3.eth.defaultAccount}).then(function() {
|
||||
SimpleStorage.methods.get().call().then(function(result) {
|
||||
$("#tests").append("<br>test 3: " + (result === "150"));
|
||||
callback();
|
||||
});
|
||||
});
|
||||
},
|
||||
function test4(callback) {
|
||||
$("#tests").append("<br>test 4: " + (Token._address === null));
|
||||
$("#tests").append("<br>test 4: " + (MyToken._address !== undefined));
|
||||
$("#tests").append("<br>test 4: " + (MyToken2._address !== undefined));
|
||||
callback();
|
||||
},
|
||||
function test5(callback) {
|
||||
MyToken.methods._supply().call().then(function(result) {
|
||||
$("#tests").append("<br>test 5: " + (result === "1000"));
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function test6(callback) {
|
||||
MyToken2.methods._supply().call().then(function(result) {
|
||||
$("#tests").append("<br>test 6: " + (result === "2000"));
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function test7(callback) {
|
||||
$("#tests").append("<br>test 7: " + (AlreadyDeployedToken._address === "0xeCE374063fE5Cc7EFbACA0a498477CaDA94E5AD6"));
|
||||
callback();
|
||||
}
|
||||
], function (err, result) {
|
||||
$("#tests").append("<br>done");
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
/// import $ from 'jquery';
|
||||
///
|
||||
/// import {AlreadyDeployedToken, AnotherStorage, MyToken, MyToken2, SimpleStorage, Token} from '../../embarkArtifacts/contracts';
|
||||
/// import async from 'async';
|
||||
///
|
||||
/// $(document).ready(function() {
|
||||
///
|
||||
/// document.getElementById("runTests").onclick = function() {
|
||||
/// async.waterfall([
|
||||
/// function test1(callback) {
|
||||
/// AnotherStorage.methods.simpleStorageAddress().call().then(function(simpleStorageAddress) {
|
||||
/// $("#tests").append("<br>test 1: " + (simpleStorageAddress === SimpleStorage._address));
|
||||
/// callback();
|
||||
/// });
|
||||
/// },
|
||||
/// function test2(callback) {
|
||||
/// SimpleStorage.methods.storedData().call().then(function(result) {
|
||||
/// $("#tests").append("<br>test 2 (true first time): " + (result === "100"));
|
||||
/// $("#tests").append("<br>test 2 (true after): " + (result === "150"));
|
||||
/// callback();
|
||||
/// });
|
||||
/// },
|
||||
/// function test3(callback) {
|
||||
/// SimpleStorage.methods.set(150).send({from: web3.eth.defaultAccount}).then(function() {
|
||||
/// SimpleStorage.methods.get().call().then(function(result) {
|
||||
/// $("#tests").append("<br>test 3: " + (result === "150"));
|
||||
/// callback();
|
||||
/// });
|
||||
/// });
|
||||
/// },
|
||||
/// function test4(callback) {
|
||||
/// $("#tests").append("<br>test 4: " + (Token._address === null));
|
||||
/// $("#tests").append("<br>test 4: " + (MyToken._address !== undefined));
|
||||
/// $("#tests").append("<br>test 4: " + (MyToken2._address !== undefined));
|
||||
/// callback();
|
||||
/// },
|
||||
/// function test5(callback) {
|
||||
/// MyToken.methods._supply().call().then(function(result) {
|
||||
/// $("#tests").append("<br>test 5: " + (result === "1000"));
|
||||
/// callback();
|
||||
/// });
|
||||
/// },
|
||||
/// function test6(callback) {
|
||||
/// MyToken2.methods._supply().call().then(function(result) {
|
||||
/// $("#tests").append("<br>test 6: " + (result === "2000"));
|
||||
/// callback();
|
||||
/// });
|
||||
/// },
|
||||
/// function test7(callback) {
|
||||
/// $("#tests").append("<br>test 7: " + (AlreadyDeployedToken._address === "0xeCE374063fE5Cc7EFbACA0a498477CaDA94E5AD6"));
|
||||
/// callback();
|
||||
/// }
|
||||
/// ], function (err, result) {
|
||||
/// $("#tests").append("<br>done");
|
||||
/// });
|
||||
///
|
||||
/// };
|
||||
///
|
||||
/// });
|
||||
///
|
||||
///
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
pragma solidity ^0.4.25;
|
||||
|
||||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
address public registar;
|
||||
address owner;
|
||||
event EventOnSet2(bool passed, string message);
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function set(uint x) public {
|
||||
storedData = x;
|
||||
//require(msg.sender == owner);
|
||||
//require(msg.sender == 0x0);
|
||||
//storedData = x + 2;
|
||||
}
|
||||
|
||||
function set2(uint x) public {
|
||||
storedData = x;
|
||||
emit EventOnSet2(true, "hi");
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
|
||||
function getS() public pure returns (string d) {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
function setRegistar(address x) public {
|
||||
registar = x;
|
||||
}
|
||||
|
||||
}
|
|
@ -9,79 +9,23 @@ module.exports = {
|
|||
],
|
||||
gas: "auto",
|
||||
deploy: {
|
||||
Ownable: {
|
||||
deploy: false
|
||||
},
|
||||
SimpleStorage: {
|
||||
fromIndex: 0,
|
||||
args: [100],
|
||||
onDeploy: ["SimpleStorage.methods.setRegistar(web3.eth.defaultAccount).send()"]
|
||||
},
|
||||
AnotherStorage: {
|
||||
args: ["$SimpleStorage"]
|
||||
},
|
||||
Token: {
|
||||
deploy: false,
|
||||
args: [1000]
|
||||
},
|
||||
Test: {
|
||||
onDeploy: ["Test.methods.changeAddress('$MyToken')", "Test.methods.changeENS('embark.eth')"]
|
||||
},
|
||||
MyToken: {
|
||||
instanceOf: "Token"
|
||||
},
|
||||
MyToken2: {
|
||||
instanceOf: "Token",
|
||||
args: [200]
|
||||
},
|
||||
AlreadyDeployedToken: {
|
||||
address: "0xece374063fe5cc7efbaca0a498477cada94e5ad6",
|
||||
instanceOf: "Token"
|
||||
},
|
||||
MyToken3: {
|
||||
instanceOf: "Tokn"
|
||||
},
|
||||
ContractArgs: {
|
||||
args: {
|
||||
initialValue: 123,
|
||||
"_addresses": ["$MyToken2", "$SimpleStorage"]
|
||||
}
|
||||
},
|
||||
SomeContract: {
|
||||
deployIf: 'await MyToken.methods.isAvailable().call()',
|
||||
deps: ['MyToken'],
|
||||
args: [
|
||||
["$MyToken2", "$SimpleStorage"],
|
||||
100
|
||||
]
|
||||
},
|
||||
ERC20: {
|
||||
file: "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"
|
||||
},
|
||||
SimpleStorageTest: {
|
||||
file: "./some_folder/test_contract.sol",
|
||||
args: [1000]
|
||||
},
|
||||
StandardToken: {
|
||||
file: "https://github.com/status-im/contracts/blob/151-embark31/contracts/token/StandardToken.sol",
|
||||
deploy: false
|
||||
},
|
||||
SimpleStorageWithHttpImport: {
|
||||
fromIndex: 0,
|
||||
args: [100]
|
||||
}
|
||||
},
|
||||
},
|
||||
afterDeploy: [
|
||||
"Test.methods.changeAddress('$MyToken')",
|
||||
"web3.eth.getAccounts((err, accounts) => Test.methods.changeAddress(accounts[0]))"
|
||||
//"Test.methods.changeAddress('$MyToken')",
|
||||
//"web3.eth.getAccounts((err, accounts) => Test.methods.changeAddress(accounts[0]))"
|
||||
]
|
||||
},
|
||||
development: {
|
||||
deploy: {
|
||||
MyToken2: {
|
||||
instanceOf: "Token",
|
||||
args: [2000]
|
||||
}
|
||||
// MyToken2: {
|
||||
// instanceOf: "Token",
|
||||
// args: [2000]
|
||||
// }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
module.exports = {
|
||||
default: {
|
||||
dappConnection: [
|
||||
"ws://localhost:8546",
|
||||
"http://localhost:8550",
|
||||
"http://localhost:8545",
|
||||
"http://localhost:8550",
|
||||
"$WEB3"
|
||||
],
|
||||
gas: "auto",
|
||||
deploy: {
|
||||
Ownable: {
|
||||
deploy: false
|
||||
},
|
||||
SimpleStorage: {
|
||||
fromIndex: 0,
|
||||
args: [100],
|
||||
onDeploy: ["SimpleStorage.methods.setRegistar(web3.eth.defaultAccount).send()"]
|
||||
},
|
||||
AnotherStorage: {
|
||||
args: ["$SimpleStorage"]
|
||||
},
|
||||
Token: {
|
||||
deploy: false,
|
||||
args: [1000]
|
||||
},
|
||||
Test: {
|
||||
onDeploy: ["Test.methods.changeAddress('$MyToken')", "Test.methods.changeENS('embark.eth')"]
|
||||
},
|
||||
MyToken: {
|
||||
instanceOf: "Token"
|
||||
},
|
||||
MyToken2: {
|
||||
instanceOf: "Token",
|
||||
args: [200]
|
||||
},
|
||||
AlreadyDeployedToken: {
|
||||
address: "0xece374063fe5cc7efbaca0a498477cada94e5ad6",
|
||||
instanceOf: "Token"
|
||||
},
|
||||
MyToken3: {
|
||||
instanceOf: "Tokn"
|
||||
},
|
||||
ContractArgs: {
|
||||
args: {
|
||||
initialValue: 123,
|
||||
"_addresses": ["$MyToken2", "$SimpleStorage"]
|
||||
}
|
||||
},
|
||||
SomeContract: {
|
||||
deployIf: 'await MyToken.methods.isAvailable().call()',
|
||||
deps: ['MyToken'],
|
||||
args: [
|
||||
["$MyToken2", "$SimpleStorage"],
|
||||
100
|
||||
]
|
||||
},
|
||||
ERC20: {
|
||||
file: "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"
|
||||
},
|
||||
SimpleStorageTest: {
|
||||
file: "./some_folder/test_contract.sol",
|
||||
args: [1000]
|
||||
},
|
||||
StandardToken: {
|
||||
file: "https://github.com/status-im/contracts/blob/151-embark31/contracts/token/StandardToken.sol",
|
||||
deploy: false
|
||||
},
|
||||
SimpleStorageWithHttpImport: {
|
||||
fromIndex: 0,
|
||||
args: [100]
|
||||
}
|
||||
},
|
||||
afterDeploy: [
|
||||
"Test.methods.changeAddress('$MyToken')",
|
||||
"web3.eth.getAccounts((err, accounts) => Test.methods.changeAddress(accounts[0]))"
|
||||
]
|
||||
},
|
||||
development: {
|
||||
deploy: {
|
||||
MyToken2: {
|
||||
instanceOf: "Token",
|
||||
args: [2000]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"contracts": ["app/contracts/**", "contracts/**"],
|
||||
"contracts": ["app/contracts/**"],
|
||||
"app": {
|
||||
"js/jquery.js": "app/js/_vendor/jquery.min.js",
|
||||
"js/bootstrap.js": "app/js/_vendor/bootstrap.min.js",
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"contracts": ["app/contracts/**", "contracts/**"],
|
||||
"app": {
|
||||
"js/jquery.js": "app/js/_vendor/jquery.min.js",
|
||||
"js/bootstrap.js": "app/js/_vendor/bootstrap.min.js",
|
||||
"css/app.css": ["app/css/**"],
|
||||
"images/": ["app/images/**"],
|
||||
"js/app.js": ["app/js/index.js"],
|
||||
"js/test.js": ["app/js/_vendor/jquery.min.js", "app/js/_vendor/async.min.js", "app/js/test.js"],
|
||||
"index.html": "app/index.html",
|
||||
"test.html": "app/test.html",
|
||||
"test2.html": "app/test2.html",
|
||||
"test3.html": "app/test3.haml"
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/",
|
||||
"versions": {
|
||||
"solc": "0.4.25",
|
||||
"web3": "1.0.0-beta",
|
||||
"ipfs-api": "17.2.7"
|
||||
},
|
||||
"plugins": {
|
||||
"embarkjs-connector-web3": {}
|
||||
},
|
||||
"options": {
|
||||
"solc": {
|
||||
"optimize": true,
|
||||
"optimize-runs": 200
|
||||
}
|
||||
},
|
||||
"generationDir": "embarkArtifacts"
|
||||
}
|
|
@ -47,11 +47,11 @@ class BlockchainConnector {
|
|||
});
|
||||
});
|
||||
|
||||
self.events.setCommandHandler("blockchain:ready", self.onReady.bind(this));
|
||||
// self.events.setCommandHandler("blockchain:ready", self.onReady.bind(this));
|
||||
|
||||
self.events.setCommandHandler("blockchain:web3:isReady", (cb) => {
|
||||
cb(self.isWeb3Ready);
|
||||
});
|
||||
// self.events.setCommandHandler("blockchain:web3:isReady", (cb) => {
|
||||
// cb(self.isWeb3Ready);
|
||||
// });
|
||||
|
||||
self.events.setCommandHandler("blockchain:object", (cb) => {
|
||||
cb(self);
|
||||
|
@ -127,10 +127,11 @@ class BlockchainConnector {
|
|||
};
|
||||
this.provider = new Provider(providerOptions);
|
||||
|
||||
self.events.request("processes:launch", "blockchain", (err) => {
|
||||
if (err) {
|
||||
return self.logger.error(err);
|
||||
}
|
||||
// self.events.request("processes:launch", "blockchain", (err) => {
|
||||
// if (err) {
|
||||
// return self.logger.error(err);
|
||||
// }
|
||||
// setTimeout(() => {
|
||||
self.provider.startWeb3Provider(async () => {
|
||||
try {
|
||||
const blockNumber = await self.web3.eth.getBlockNumber();
|
||||
|
@ -165,7 +166,7 @@ class BlockchainConnector {
|
|||
console.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
_setupVM(cb) {
|
||||
|
|
|
@ -37,6 +37,14 @@ class ContractsManager {
|
|||
|
||||
this.events.setCommandHandler("contracts:build", this.buildContracts.bind(this));
|
||||
|
||||
this.events.setCommandHandler('contracts:list', (cb) => {
|
||||
cb(this.compileError, this.listContracts());
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('contracts:state', (cb) => {
|
||||
cb(this.compileError, this.contractsState());
|
||||
});
|
||||
|
||||
console.dir("---- contracts manager---- ")
|
||||
// this.registerCommands()
|
||||
// this.registerAPIs()
|
||||
|
@ -52,10 +60,6 @@ class ContractsManager {
|
|||
// });
|
||||
// });
|
||||
|
||||
self.events.setCommandHandler('contracts:list', (cb) => {
|
||||
cb(self.compileError, self.listContracts());
|
||||
});
|
||||
|
||||
self.events.setCommandHandler('contracts:add', (contract) => {
|
||||
this.contracts[contract.className] = contract;
|
||||
});
|
||||
|
@ -81,18 +85,6 @@ class ContractsManager {
|
|||
cb();
|
||||
});
|
||||
|
||||
self.events.on("deploy:contract:error", (_contract) => {
|
||||
self.events.emit('contractsState', self.contractsState());
|
||||
});
|
||||
|
||||
self.events.on("deploy:contract:deployed", (_contract) => {
|
||||
self.events.emit('contractsState', self.contractsState());
|
||||
});
|
||||
|
||||
self.events.on("deploy:contract:undeployed", (_contract) => {
|
||||
self.events.emit('contractsState', self.contractsState());
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('setDashboardState', () => {
|
||||
self.events.emit('contractsState', self.contractsState());
|
||||
});
|
||||
|
@ -558,7 +550,7 @@ class ContractsManager {
|
|||
self.logger.trace("finished".underline);
|
||||
console.dir("done!!")
|
||||
|
||||
done(err, self.contracts);
|
||||
done(err, self.contracts, self.contractDependencies);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,398 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
const async = require('async');
|
||||
|
||||
import {AddressUtils, toChecksumAddress} from 'embark-utils';
|
||||
const {ZERO_ADDRESS} = AddressUtils;
|
||||
|
||||
// Check out definition 97 of the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||
const MAX_CONTRACT_BYTECODE_LENGTH = 24576;
|
||||
const GANACHE_CLIENT_VERSION_NAME = "EthereumJS TestRPC";
|
||||
|
||||
class ContractDeployer {
|
||||
constructor(options) {
|
||||
this.logger = options.logger;
|
||||
this.events = options.events;
|
||||
this.plugins = options.plugins;
|
||||
|
||||
this.events.setCommandHandler('deploy:contract', (contract, cb) => {
|
||||
this.checkAndDeployContract(contract, null, cb);
|
||||
});
|
||||
this.events.setCommandHandler('deploy:contract:object', (contract, cb) => {
|
||||
this.checkAndDeployContract(contract, null, cb, true);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: determining the arguments could also be in a module since it's not
|
||||
// part of a 'normal' contract deployment
|
||||
determineArguments(suppliedArgs, contract, accounts, callback) {
|
||||
const self = this;
|
||||
|
||||
let args = suppliedArgs;
|
||||
if (!Array.isArray(args)) {
|
||||
args = [];
|
||||
let abi = contract.abiDefinition.find((abi) => abi.type === 'constructor');
|
||||
|
||||
for (let input of abi.inputs) {
|
||||
let inputValue = suppliedArgs[input.name];
|
||||
if (!inputValue) {
|
||||
this.logger.error(__("{{inputName}} has not been defined for {{className}} constructor", {inputName: input.name, className: contract.className}));
|
||||
}
|
||||
args.push(inputValue || "");
|
||||
}
|
||||
}
|
||||
|
||||
function parseArg(arg, cb) {
|
||||
const match = arg.match(/\$accounts\[([0-9]+)]/);
|
||||
if (match) {
|
||||
if (!accounts[match[1]]) {
|
||||
return cb(__('No corresponding account at index %d', match[1]));
|
||||
}
|
||||
return cb(null, accounts[match[1]]);
|
||||
}
|
||||
let contractName = arg.substr(1);
|
||||
self.events.request('contracts:contract', contractName, (referedContract) => {
|
||||
// Because we're referring to a contract that is not being deployed (ie. an interface),
|
||||
// we still need to provide a valid address so that the ABI checker won't fail.
|
||||
cb(null, (referedContract.deployedAddress || ZERO_ADDRESS));
|
||||
});
|
||||
}
|
||||
|
||||
function checkArgs(argus, cb) {
|
||||
async.map(argus, (arg, nextEachCb) => {
|
||||
if (arg[0] === "$") {
|
||||
return parseArg(arg, nextEachCb);
|
||||
}
|
||||
|
||||
if (Array.isArray(arg)) {
|
||||
return checkArgs(arg, nextEachCb);
|
||||
}
|
||||
|
||||
self.events.request('ens:isENSName', arg, (isENSName) => {
|
||||
if (isENSName) {
|
||||
return self.events.request("ens:resolve", arg, (err, address) => {
|
||||
if (err) {
|
||||
return nextEachCb(err);
|
||||
}
|
||||
nextEachCb(err, address);
|
||||
});
|
||||
}
|
||||
|
||||
nextEachCb(null, arg);
|
||||
});
|
||||
}, cb);
|
||||
}
|
||||
|
||||
checkArgs(args, callback);
|
||||
}
|
||||
|
||||
checkAndDeployContract(contract, params, callback, returnObject) {
|
||||
console.dir("= checkAndDeployContract: " + contract.className);
|
||||
let self = this;
|
||||
contract.error = false;
|
||||
let accounts = [];
|
||||
let deploymentAccount;
|
||||
|
||||
if (contract.deploy === false) {
|
||||
self.events.emit("deploy:contract:undeployed", contract);
|
||||
return callback();
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function checkContractBytesize(next) {
|
||||
if (!contract.code) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const code = (contract.code.indexOf('0x') === 0) ? contract.code.substr(2) : contract.code;
|
||||
const contractCodeLength = Buffer.from(code, 'hex').toString().length;
|
||||
if(contractCodeLength > MAX_CONTRACT_BYTECODE_LENGTH) {
|
||||
return next(new Error(`Bytecode for ${contract.className} contract is too large. Not deploying.`));
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
// TODO: it should just ask blockchain client to deploy contract X but shouldn't
|
||||
// know details how this contract is deployed
|
||||
|
||||
|
||||
// function requestBlockchainConnector(next) {
|
||||
// self.events.request("blockchain:object", (blockchain) => {
|
||||
// self.blockchain = blockchain;
|
||||
// next();
|
||||
// });
|
||||
// },
|
||||
|
||||
// TODO: can potentially go to a beforeDeploy plugin
|
||||
function getAccounts(next) {
|
||||
deploymentAccount = self.blockchain.defaultAccount();
|
||||
self.events.request('blockchain:provider:contract:accounts:get', (_err, blockchainAccounts) => {
|
||||
accounts = blockchainAccounts;
|
||||
|
||||
// applying deployer account configuration, if any
|
||||
if (typeof contract.fromIndex === 'number') {
|
||||
deploymentAccount = accounts[contract.fromIndex];
|
||||
if (deploymentAccount === undefined) {
|
||||
return next(__("error deploying") + " " + contract.className + ": " + __("no account found at index") + " " + contract.fromIndex + __(" check the config"));
|
||||
}
|
||||
}
|
||||
if (typeof contract.from === 'string' && typeof contract.fromIndex !== 'undefined') {
|
||||
self.logger.warn(__('Both "from" and "fromIndex" are defined for contract') + ' "' + contract.className + '". ' + __('Using "from" as deployer account.'));
|
||||
}
|
||||
if (typeof contract.from === 'string') {
|
||||
deploymentAccount = contract.from;
|
||||
}
|
||||
|
||||
deploymentAccount = deploymentAccount || accounts[0];
|
||||
contract.deploymentAccount = deploymentAccount;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function applyArgumentPlugins(next) {
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:arguments', {contract: contract}, (_params) => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
function _determineArguments(next) {
|
||||
self.determineArguments(params || contract.args, contract, accounts, (err, realArgs) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
contract.realArgs = realArgs;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function deployIt(next) {
|
||||
let skipBytecodeCheck = false;
|
||||
if (contract.address !== undefined) {
|
||||
try {
|
||||
toChecksumAddress(contract.address);
|
||||
} catch(e) {
|
||||
self.logger.error(__("error deploying %s", contract.className));
|
||||
self.logger.error(e.message);
|
||||
contract.error = e.message;
|
||||
self.events.emit("deploy:contract:error", contract);
|
||||
return next(e.message);
|
||||
}
|
||||
contract.deployedAddress = contract.address;
|
||||
skipBytecodeCheck = true;
|
||||
}
|
||||
|
||||
if (returnObject) {
|
||||
return self.deployContract(contract, next, returnObject);
|
||||
}
|
||||
|
||||
console.dir("== emitAndRunActionsForEvent / should Deploy");
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, function(_err, params) {
|
||||
let trackedContract = params.contract;
|
||||
if (!params.shouldDeploy) {
|
||||
return self.willNotDeployContract(contract, trackedContract, next);
|
||||
}
|
||||
if (!trackedContract.address) {
|
||||
return self.deployContract(contract, next);
|
||||
}
|
||||
// deploy the contract regardless if track field is defined and set to false
|
||||
if (trackedContract.track === false) {
|
||||
self.logFunction(contract)(contract.className.bold.cyan + __(" will be redeployed").green);
|
||||
return self.deployContract(contract, next);
|
||||
}
|
||||
|
||||
self.blockchain.getCode(trackedContract.address, function(getCodeErr, codeInChain) {
|
||||
if (getCodeErr) {
|
||||
return next(getCodeErr);
|
||||
}
|
||||
if (codeInChain.length > 3 || skipBytecodeCheck) { // it is "0x" or "0x0" for empty code, depending on web3 version
|
||||
self.contractAlreadyDeployed(contract, trackedContract, next);
|
||||
} else {
|
||||
self.deployContract(contract, next);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
], (err,results) => {
|
||||
callback(err, results);
|
||||
});
|
||||
}
|
||||
|
||||
willNotDeployContract(contract, trackedContract, callback) {
|
||||
contract.deploy = false;
|
||||
this.events.emit("deploy:contract:undeployed", contract);
|
||||
callback();
|
||||
}
|
||||
|
||||
contractAlreadyDeployed(contract, trackedContract, callback) {
|
||||
console.dir("--> contractAlreadyDeployed")
|
||||
this.logFunction(contract)(contract.className.bold.cyan + __(" already deployed at ").green + trackedContract.address.bold.cyan);
|
||||
contract.deployedAddress = trackedContract.address;
|
||||
this.events.emit("deploy:contract:deployed", contract);
|
||||
|
||||
this.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, (err) => {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
logFunction(contract) {
|
||||
return contract.silent ? this.logger.trace.bind(this.logger) : this.logger.info.bind(this.logger);
|
||||
}
|
||||
|
||||
deployContract(contract, callback, returnObject) {
|
||||
console.dir("deployContract")
|
||||
let self = this;
|
||||
let deployObject;
|
||||
|
||||
async.waterfall([
|
||||
function doLinking(next) {
|
||||
console.dir("= doLinking")
|
||||
|
||||
if (!contract.linkReferences || !Object.keys(contract.linkReferences).length) {
|
||||
return next();
|
||||
}
|
||||
let contractCode = contract.code;
|
||||
let offset = 0;
|
||||
|
||||
// TODO: linking can/should be done differently
|
||||
async.eachLimit(contract.linkReferences, 1, (fileReference, eachCb1) => {
|
||||
async.eachOfLimit(fileReference, 1, (references, libName, eachCb2) => {
|
||||
self.events.request("contracts:contract", libName, (libContract) => {
|
||||
async.eachLimit(references, 1, (reference, eachCb3) => {
|
||||
if (!libContract) {
|
||||
return eachCb3(new Error(__('{{contractName}} has a link to the library {{libraryName}}, but it was not found. Is it in your contract folder?'), {
|
||||
contractName: contract.className,
|
||||
libraryName: libName
|
||||
}));
|
||||
}
|
||||
|
||||
let libAddress = libContract.deployedAddress;
|
||||
if (!libAddress) {
|
||||
return eachCb3(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {
|
||||
contractName: contract.className,
|
||||
libraryName: libName
|
||||
})));
|
||||
}
|
||||
|
||||
libAddress = libAddress.substr(2).toLowerCase();
|
||||
|
||||
// Multiplying by two because the original pos and length are in bytes, but we have an hex string
|
||||
contractCode = contractCode.substring(0, (reference.start * 2) + offset) + libAddress + contractCode.substring((reference.start * 2) + offset + (reference.length * 2));
|
||||
// Calculating an offset in case the length is at some point different than the address length
|
||||
offset += libAddress.length - (reference.length * 2);
|
||||
|
||||
eachCb3();
|
||||
}, eachCb2);
|
||||
});
|
||||
}, eachCb1);
|
||||
}, (err) => {
|
||||
contract.code = contractCode;
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function applyBeforeDeploy(next) {
|
||||
console.dir("= applyBeforeDeploy")
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:beforeDeploy', {contract: contract}, (_params) => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
function getGasPriceForNetwork(next) {
|
||||
console.dir("= getGasPriceForNetwork")
|
||||
self.events.request("blockchain:gasPrice", (err, gasPrice) => {
|
||||
if (err) {
|
||||
return next(new Error(__("could not get the gas price")));
|
||||
}
|
||||
contract.gasPrice = contract.gasPrice || gasPrice;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function createDeployObject(next) {
|
||||
console.dir("= createDeployObject")
|
||||
let contractCode = contract.code;
|
||||
let contractObject = self.blockchain.ContractObject({abi: contract.abiDefinition});
|
||||
let contractParams = (contract.realArgs || contract.args).slice();
|
||||
|
||||
try {
|
||||
const dataCode = contractCode.startsWith('0x') ? contractCode : "0x" + contractCode;
|
||||
deployObject = self.blockchain.deployContractObject(contractObject, {arguments: contractParams, data: dataCode});
|
||||
if (returnObject) {
|
||||
return callback(null, deployObject);
|
||||
}
|
||||
} catch(e) {
|
||||
if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) {
|
||||
return next(new Error(__("attempted to deploy %s without specifying parameters", contract.className)) + ". " + __("check if there are any params defined for this contract in this environment in the contracts configuration file"));
|
||||
}
|
||||
return next(new Error(e));
|
||||
}
|
||||
next();
|
||||
},
|
||||
function estimateCorrectGas(next) {
|
||||
self.blockchain.getClientVersion((err, version) => {
|
||||
if (version.split('/')[0] === GANACHE_CLIENT_VERSION_NAME) {
|
||||
// This is Ganache's gas limit. We subtract 1 so we don't reach the limit.
|
||||
//
|
||||
// We do this because Ganache's gas estimates are wrong (contract creation
|
||||
// has a base cost of 53k, not 21k, so it sometimes results in out of gas
|
||||
// errors.)
|
||||
contract.gas = 6721975 - 1;
|
||||
} else if (contract.gas === 'auto' || !contract.gas) {
|
||||
return self.blockchain.estimateDeployContractGas(deployObject, (err, gasValue) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
let increase_per = 1 + (Math.random() / 10.0);
|
||||
contract.gas = Math.floor(gasValue * increase_per);
|
||||
next();
|
||||
});
|
||||
}
|
||||
next();
|
||||
});
|
||||
},
|
||||
function deployTheContract(next) {
|
||||
console.dir("= deployTheContract " + contract.className)
|
||||
let estimatedCost = contract.gas * contract.gasPrice;
|
||||
|
||||
self.blockchain.deployContractFromObject(deployObject, {
|
||||
from: contract.deploymentAccount,
|
||||
gas: contract.gas,
|
||||
gasPrice: contract.gasPrice
|
||||
}, function(error, receipt) {
|
||||
console.dir("--> contract deployed")
|
||||
console.dir(error)
|
||||
console.dir(receipt)
|
||||
if (error) {
|
||||
contract.error = error.message;
|
||||
self.events.emit("deploy:contract:error", contract);
|
||||
if (error.message && error.message.indexOf('replacement transaction underpriced') !== -1) {
|
||||
self.logger.warn("replacement transaction underpriced: This warning typically means a transaction exactly like this one is still pending on the blockchain");
|
||||
}
|
||||
return next(new Error("error deploying =" + contract.className + "= due to error: " + error.message));
|
||||
}
|
||||
self.logFunction(contract)(`${contract.className.bold.cyan} ${__('deployed at').green} ${receipt.contractAddress.bold.cyan} ${__("using").green} ${receipt.gasUsed} ${__("gas").green} (txHash: ${receipt.transactionHash.bold.cyan})`);
|
||||
contract.deployedAddress = receipt.contractAddress;
|
||||
contract.transactionHash = receipt.transactionHash;
|
||||
receipt.className = contract.className;
|
||||
|
||||
if(receipt) self.events.emit("deploy:contract:receipt", receipt);
|
||||
self.events.emit("deploy:contract:deployed", contract);
|
||||
|
||||
// console.dir("__registerContract")
|
||||
// self.registerContract(contract, () => {
|
||||
console.dir("__runActionsForEvent deploy:contract:deployed")
|
||||
self.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, (err) => {
|
||||
console.dir("result __runActionsForEvent deploy:contract:deployed")
|
||||
if (err) {
|
||||
console.dir(err)
|
||||
return next(err);
|
||||
}
|
||||
next(null, receipt);
|
||||
});
|
||||
}, hash => {
|
||||
self.logFunction(contract)(__("deploying") + " " + contract.className.bold.cyan + " " + __("with").green + " " + contract.gas + " " + __("gas at the price of").green + " " + contract.gasPrice + " " + __("Wei, estimated cost:").green + " " + estimatedCost + " Wei".green + " (txHash: " + hash.bold.cyan + ")");
|
||||
});
|
||||
}
|
||||
], (__err, __results) => {
|
||||
console.dir("--- deployed Contract")
|
||||
callback(__err, __results)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ContractDeployer;
|
|
@ -0,0 +1,222 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
const async = require('async');
|
||||
// async._waterfall = async.waterfall;
|
||||
// let filename = "index.js";
|
||||
// async.waterfall = function (_tasks, callback) {
|
||||
// let tasks = _tasks.map(function (t) {
|
||||
// let fn = function () {
|
||||
// console.log("async " + (new Error()).stack.split("\n")[1] + ": " + t.name);
|
||||
// t.apply(t, arguments);
|
||||
// };
|
||||
// return fn;
|
||||
// });
|
||||
// async._waterfall(tasks, callback);
|
||||
// };
|
||||
|
||||
const ContractDeployer = require('./contract_deployer.js');
|
||||
const cloneDeep = require('clone-deep');
|
||||
const constants = require('embark-core/constants');
|
||||
|
||||
class DeployManager {
|
||||
constructor(embark, options) {
|
||||
const self = this;
|
||||
this.config = embark.config;
|
||||
this.logger = embark.logger;
|
||||
this.blockchainConfig = this.config.blockchainConfig;
|
||||
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
// this.blockchain = options.blockchain;
|
||||
// this.gasLimit = 6000000;
|
||||
this.fatalErrors = false;
|
||||
this.deployOnlyOnConfig = false;
|
||||
this.onlyCompile = options.onlyCompile !== undefined ? options.onlyCompile : false;
|
||||
|
||||
this.contractDeployer = new ContractDeployer({
|
||||
logger: this.logger,
|
||||
events: this.events,
|
||||
plugins: this.plugins
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('deployment:contracts:deploy', (contractsList, contractDependencies, cb) => {
|
||||
self.deployContracts(contractsList, contractDependencies, cb);
|
||||
});
|
||||
|
||||
// this.events.setCommandHandler('deploy:setGasLimit', (gasLimit) => {
|
||||
// self.gasLimit = gasLimit;
|
||||
// });
|
||||
|
||||
// this.events.setCommandHandler('deploy:contracts', (cb) => {
|
||||
// self.deployContracts(cb);
|
||||
// });
|
||||
|
||||
// this.events.setCommandHandler('deploy:contracts:test', (cb) => {
|
||||
// self.fatalErrors = true;
|
||||
// self.deployOnlyOnConfig = true;
|
||||
// self.deployContracts(cb);
|
||||
// });
|
||||
}
|
||||
|
||||
deployAll(contracts, contractDependencies, done) {
|
||||
let self = this;
|
||||
|
||||
// self.events.request('contracts:dependencies', (err, contractDependencies) => {
|
||||
// self.events.request('contracts:list', (err, contracts) => {
|
||||
// if (err) {
|
||||
// return done(err);
|
||||
// }
|
||||
|
||||
self.logger.info(__("deploying contracts"));
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
self.logger.info(__('Executing pre-deploy actions...'));
|
||||
self.plugins.emitAndRunActionsForEvent("deploy:beforeAll", (err) => {
|
||||
// console.dir("== err")
|
||||
// console.dir(err)
|
||||
// TODO: err is a function for some reason
|
||||
// if (err) {
|
||||
// return next(err);
|
||||
// }
|
||||
self.logger.info(__('Pre-deploy actions done. Deploying contracts'));
|
||||
next();
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
const contractDeploys = {};
|
||||
const errors = [];
|
||||
console.dir("=== contracts")
|
||||
console.dir(contracts.map((x) => x.className))
|
||||
contracts.forEach(contract => {
|
||||
function deploy(result, callback) {
|
||||
if (typeof result === 'function') {
|
||||
callback = result;
|
||||
}
|
||||
// contract._gasLimit = self.gasLimit;
|
||||
self.events.request('deploy:contract', contract, (err) => {
|
||||
console.dir("contract deployed " + contract.className)
|
||||
if (err) {
|
||||
console.dir("== err deploying contract");
|
||||
console.dir(err);
|
||||
contract.error = err.message || err;
|
||||
if (contract.error === constants.blockchain.gasAllowanceError) {
|
||||
self.logger.error(`[${contract.className}]: ${constants.blockchain.gasAllowanceErrorMessage}`);
|
||||
} else {
|
||||
self.logger.error(`[${contract.className}]: ${err.message || err}`);
|
||||
}
|
||||
errors.push(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
const className = contract.className;
|
||||
if (!contractDependencies[className] || contractDependencies[className].length === 0) {
|
||||
contractDeploys[className] = deploy;
|
||||
return;
|
||||
}
|
||||
contractDeploys[className] = cloneDeep(contractDependencies[className]);
|
||||
contractDeploys[className].push(deploy);
|
||||
});
|
||||
|
||||
console.dir("== async.auto");
|
||||
console.dir(Object.keys(contractDeploys));
|
||||
console.dir(contractDeploys);
|
||||
async.auto(contractDeploys, function (_err, _results) {
|
||||
if (_err) {
|
||||
console.dir("error deploying contracts")
|
||||
console.dir(_err)
|
||||
}
|
||||
if (errors.length) {
|
||||
_err = __("Error deploying contracts. Please fix errors to continue.");
|
||||
self.logger.error(_err);
|
||||
self.events.emit("outputError", __("Error deploying contracts, please check console"));
|
||||
return next(_err);
|
||||
}
|
||||
if (contracts.length === 0) {
|
||||
self.logger.info(__("no contracts found"));
|
||||
return next();
|
||||
}
|
||||
self.logger.info(__("finished deploying contracts"));
|
||||
next(err);
|
||||
});
|
||||
}
|
||||
], (err) => {
|
||||
console.dir("==== finished deploying")
|
||||
if (err) {
|
||||
self.logger.error(err);
|
||||
}
|
||||
done(err);
|
||||
});
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
// TODO: can be merged into deployAll
|
||||
deployContracts(contractsList, contractDependencies, done) {
|
||||
let self = this;
|
||||
|
||||
// if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
|
||||
// self.logger.info(__("Blockchain component is disabled in the config").underline);
|
||||
// this.events.emit('blockchainDisabled', {});
|
||||
// return done();
|
||||
// }
|
||||
|
||||
async.waterfall([
|
||||
// function requestBlockchainConnector(callback) {
|
||||
// self.events.request("blockchain:object", (blockchain) => {
|
||||
// self.blockchain = blockchain;
|
||||
// callback();
|
||||
// });
|
||||
// },
|
||||
|
||||
// function buildContracts(callback) {
|
||||
// self.events.request("contracts:build", self.deployOnlyOnConfig, (err) => {
|
||||
// callback(err);
|
||||
// });
|
||||
// },
|
||||
|
||||
// // TODO: shouldn't be necessary
|
||||
// function checkCompileOnly(callback) {
|
||||
// if (self.onlyCompile) {
|
||||
// self.events.emit('contractsDeployed');
|
||||
// return done();
|
||||
// }
|
||||
// return callback();
|
||||
// },
|
||||
|
||||
// // TODO: could be implemented as an event (beforeDeployAll)
|
||||
// function checkIsConnectedToBlockchain(callback) {
|
||||
// self.blockchain.onReady((err) => {
|
||||
// callback(err);
|
||||
// });
|
||||
// },
|
||||
|
||||
// // TODO: this can be done on the fly or as part of the initialization
|
||||
// function determineDefaultAccount(callback) {
|
||||
// self.blockchain.determineDefaultAccount((err) => {
|
||||
// callback(err);
|
||||
// });
|
||||
// },
|
||||
|
||||
function deployAllContracts(callback) {
|
||||
self.deployAll(contractsList, contractDependencies, function (err) {
|
||||
if (!err) {
|
||||
self.events.emit('contractsDeployed');
|
||||
}
|
||||
if (err && self.fatalErrors) {
|
||||
return callback(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function runAfterDeploy(callback) {
|
||||
self.plugins.emitAndRunActionsForEvent('contracts:deploy:afterAll', callback);
|
||||
}
|
||||
], function (err, _result) {
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DeployManager;
|
|
@ -1,391 +1,53 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
const async = require('async');
|
||||
|
||||
import {AddressUtils, toChecksumAddress} from 'embark-utils';
|
||||
const {ZERO_ADDRESS} = AddressUtils;
|
||||
|
||||
// Check out definition 97 of the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||
const MAX_CONTRACT_BYTECODE_LENGTH = 24576;
|
||||
const GANACHE_CLIENT_VERSION_NAME = "EthereumJS TestRPC";
|
||||
|
||||
class ContractDeployer {
|
||||
constructor(options) {
|
||||
this.logger = options.logger;
|
||||
this.events = options.events;
|
||||
this.plugins = options.plugins;
|
||||
this.deployer = {};
|
||||
this.events.setCommandHandler("deployment:deployer:register", (blockchainType, deployerCb) => {
|
||||
this.deployer[blockchainType] = deployerCb
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('deploy:contract', (contract, cb) => {
|
||||
this.checkAndDeployContract(contract, null, cb);
|
||||
});
|
||||
this.events.setCommandHandler('deploy:contract:object', (contract, cb) => {
|
||||
this.checkAndDeployContract(contract, null, cb, true);
|
||||
});
|
||||
this.events.setCommandHandler('deployment:contract:deploy', this.deployContract.bind(this));
|
||||
}
|
||||
|
||||
// TODO: determining the arguments could also be in a module since it's not
|
||||
// part of a 'normal' contract deployment
|
||||
determineArguments(suppliedArgs, contract, accounts, callback) {
|
||||
const self = this;
|
||||
|
||||
let args = suppliedArgs;
|
||||
if (!Array.isArray(args)) {
|
||||
args = [];
|
||||
let abi = contract.abiDefinition.find((abi) => abi.type === 'constructor');
|
||||
|
||||
for (let input of abi.inputs) {
|
||||
let inputValue = suppliedArgs[input.name];
|
||||
if (!inputValue) {
|
||||
this.logger.error(__("{{inputName}} has not been defined for {{className}} constructor", {inputName: input.name, className: contract.className}));
|
||||
}
|
||||
args.push(inputValue || "");
|
||||
}
|
||||
}
|
||||
|
||||
function parseArg(arg, cb) {
|
||||
const match = arg.match(/\$accounts\[([0-9]+)]/);
|
||||
if (match) {
|
||||
if (!accounts[match[1]]) {
|
||||
return cb(__('No corresponding account at index %d', match[1]));
|
||||
}
|
||||
return cb(null, accounts[match[1]]);
|
||||
}
|
||||
let contractName = arg.substr(1);
|
||||
self.events.request('contracts:contract', contractName, (referedContract) => {
|
||||
// Because we're referring to a contract that is not being deployed (ie. an interface),
|
||||
// we still need to provide a valid address so that the ABI checker won't fail.
|
||||
cb(null, (referedContract.deployedAddress || ZERO_ADDRESS));
|
||||
});
|
||||
}
|
||||
|
||||
function checkArgs(argus, cb) {
|
||||
async.map(argus, (arg, nextEachCb) => {
|
||||
if (arg[0] === "$") {
|
||||
return parseArg(arg, nextEachCb);
|
||||
}
|
||||
|
||||
if (Array.isArray(arg)) {
|
||||
return checkArgs(arg, nextEachCb);
|
||||
}
|
||||
|
||||
self.events.request('ens:isENSName', arg, (isENSName) => {
|
||||
if (isENSName) {
|
||||
return self.events.request("ens:resolve", arg, (err, address) => {
|
||||
if (err) {
|
||||
return nextEachCb(err);
|
||||
}
|
||||
nextEachCb(err, address);
|
||||
});
|
||||
}
|
||||
|
||||
nextEachCb(null, arg);
|
||||
});
|
||||
}, cb);
|
||||
}
|
||||
|
||||
checkArgs(args, callback);
|
||||
}
|
||||
|
||||
checkAndDeployContract(contract, params, callback, returnObject) {
|
||||
console.dir("= checkAndDeployContract: " + contract.className);
|
||||
let self = this;
|
||||
contract.error = false;
|
||||
let accounts = [];
|
||||
let deploymentAccount;
|
||||
|
||||
deployContract(contract, callback) {
|
||||
if (contract.deploy === false) {
|
||||
self.events.emit("deploy:contract:undeployed", contract);
|
||||
this.events.emit("deployment:contract:undeployed", contract);
|
||||
return callback();
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function checkContractBytesize(next) {
|
||||
if (!contract.code) {
|
||||
(next) => {
|
||||
// self.plugins.emitAndRunActionsForEvent('deployment:contract:arguments', {contract: contract}, (_params) => {
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, (_params) => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
(next) => {
|
||||
if (contract.deploy === false) {
|
||||
this.events.emit("deployment:contract:undeployed", contract);
|
||||
return next();
|
||||
}
|
||||
|
||||
const code = (contract.code.indexOf('0x') === 0) ? contract.code.substr(2) : contract.code;
|
||||
const contractCodeLength = Buffer.from(code, 'hex').toString().length;
|
||||
if(contractCodeLength > MAX_CONTRACT_BYTECODE_LENGTH) {
|
||||
return next(new Error(`Bytecode for ${contract.className} contract is too large. Not deploying.`));
|
||||
}
|
||||
|
||||
next();
|
||||
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();
|
||||
},
|
||||
|
||||
function requestBlockchainConnector(next) {
|
||||
self.events.request("blockchain:object", (blockchain) => {
|
||||
self.blockchain = blockchain;
|
||||
(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();
|
||||
});
|
||||
},
|
||||
|
||||
// TODO: can potentially go to a beforeDeploy plugin
|
||||
function getAccounts(next) {
|
||||
deploymentAccount = self.blockchain.defaultAccount();
|
||||
self.events.request('blockchain:provider:contract:accounts:get', (_err, blockchainAccounts) => {
|
||||
accounts = blockchainAccounts;
|
||||
|
||||
// applying deployer account configuration, if any
|
||||
if (typeof contract.fromIndex === 'number') {
|
||||
deploymentAccount = accounts[contract.fromIndex];
|
||||
if (deploymentAccount === undefined) {
|
||||
return next(__("error deploying") + " " + contract.className + ": " + __("no account found at index") + " " + contract.fromIndex + __(" check the config"));
|
||||
}
|
||||
}
|
||||
if (typeof contract.from === 'string' && typeof contract.fromIndex !== 'undefined') {
|
||||
self.logger.warn(__('Both "from" and "fromIndex" are defined for contract') + ' "' + contract.className + '". ' + __('Using "from" as deployer account.'));
|
||||
}
|
||||
if (typeof contract.from === 'string') {
|
||||
deploymentAccount = contract.from;
|
||||
}
|
||||
|
||||
deploymentAccount = deploymentAccount || accounts[0];
|
||||
contract.deploymentAccount = deploymentAccount;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function applyArgumentPlugins(next) {
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:arguments', {contract: contract}, (_params) => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
function _determineArguments(next) {
|
||||
self.determineArguments(params || contract.args, contract, accounts, (err, realArgs) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
contract.realArgs = realArgs;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function deployIt(next) {
|
||||
let skipBytecodeCheck = false;
|
||||
if (contract.address !== undefined) {
|
||||
try {
|
||||
toChecksumAddress(contract.address);
|
||||
} catch(e) {
|
||||
self.logger.error(__("error deploying %s", contract.className));
|
||||
self.logger.error(e.message);
|
||||
contract.error = e.message;
|
||||
self.events.emit("deploy:contract:error", contract);
|
||||
return next(e.message);
|
||||
}
|
||||
contract.deployedAddress = contract.address;
|
||||
skipBytecodeCheck = true;
|
||||
}
|
||||
|
||||
if (returnObject) {
|
||||
return self.deployContract(contract, next, returnObject);
|
||||
}
|
||||
|
||||
console.dir("== emitAndRunActionsForEvent / should Deploy");
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, function(_err, params) {
|
||||
let trackedContract = params.contract;
|
||||
if (!params.shouldDeploy) {
|
||||
return self.willNotDeployContract(contract, trackedContract, next);
|
||||
}
|
||||
if (!trackedContract.address) {
|
||||
return self.deployContract(contract, next);
|
||||
}
|
||||
// deploy the contract regardless if track field is defined and set to false
|
||||
if (trackedContract.track === false) {
|
||||
self.logFunction(contract)(contract.className.bold.cyan + __(" will be redeployed").green);
|
||||
return self.deployContract(contract, next);
|
||||
}
|
||||
|
||||
self.blockchain.getCode(trackedContract.address, function(getCodeErr, codeInChain) {
|
||||
if (getCodeErr) {
|
||||
return next(getCodeErr);
|
||||
}
|
||||
if (codeInChain.length > 3 || skipBytecodeCheck) { // it is "0x" or "0x0" for empty code, depending on web3 version
|
||||
self.contractAlreadyDeployed(contract, trackedContract, next);
|
||||
} else {
|
||||
self.deployContract(contract, next);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
], (err,results) => {
|
||||
callback(err, results);
|
||||
});
|
||||
}
|
||||
|
||||
willNotDeployContract(contract, trackedContract, callback) {
|
||||
contract.deploy = false;
|
||||
this.events.emit("deploy:contract:undeployed", contract);
|
||||
callback();
|
||||
}
|
||||
|
||||
contractAlreadyDeployed(contract, trackedContract, callback) {
|
||||
console.dir("--> contractAlreadyDeployed")
|
||||
this.logFunction(contract)(contract.className.bold.cyan + __(" already deployed at ").green + trackedContract.address.bold.cyan);
|
||||
contract.deployedAddress = trackedContract.address;
|
||||
this.events.emit("deploy:contract:deployed", contract);
|
||||
|
||||
this.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, (err) => {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
logFunction(contract) {
|
||||
return contract.silent ? this.logger.trace.bind(this.logger) : this.logger.info.bind(this.logger);
|
||||
}
|
||||
|
||||
deployContract(contract, callback, returnObject) {
|
||||
console.dir("deployContract")
|
||||
let self = this;
|
||||
let deployObject;
|
||||
|
||||
async.waterfall([
|
||||
function doLinking(next) {
|
||||
console.dir("= doLinking")
|
||||
|
||||
if (!contract.linkReferences || !Object.keys(contract.linkReferences).length) {
|
||||
return next();
|
||||
}
|
||||
let contractCode = contract.code;
|
||||
let offset = 0;
|
||||
|
||||
async.eachLimit(contract.linkReferences, 1, (fileReference, eachCb1) => {
|
||||
async.eachOfLimit(fileReference, 1, (references, libName, eachCb2) => {
|
||||
self.events.request("contracts:contract", libName, (libContract) => {
|
||||
async.eachLimit(references, 1, (reference, eachCb3) => {
|
||||
if (!libContract) {
|
||||
return eachCb3(new Error(__('{{contractName}} has a link to the library {{libraryName}}, but it was not found. Is it in your contract folder?'), {
|
||||
contractName: contract.className,
|
||||
libraryName: libName
|
||||
}));
|
||||
}
|
||||
|
||||
let libAddress = libContract.deployedAddress;
|
||||
if (!libAddress) {
|
||||
return eachCb3(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {
|
||||
contractName: contract.className,
|
||||
libraryName: libName
|
||||
})));
|
||||
}
|
||||
|
||||
libAddress = libAddress.substr(2).toLowerCase();
|
||||
|
||||
// Multiplying by two because the original pos and length are in bytes, but we have an hex string
|
||||
contractCode = contractCode.substring(0, (reference.start * 2) + offset) + libAddress + contractCode.substring((reference.start * 2) + offset + (reference.length * 2));
|
||||
// Calculating an offset in case the length is at some point different than the address length
|
||||
offset += libAddress.length - (reference.length * 2);
|
||||
|
||||
eachCb3();
|
||||
}, eachCb2);
|
||||
});
|
||||
}, eachCb1);
|
||||
}, (err) => {
|
||||
contract.code = contractCode;
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function applyBeforeDeploy(next) {
|
||||
console.dir("= applyBeforeDeploy")
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:beforeDeploy', {contract: contract}, (_params) => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
function getGasPriceForNetwork(next) {
|
||||
console.dir("= getGasPriceForNetwork")
|
||||
self.events.request("blockchain:gasPrice", (err, gasPrice) => {
|
||||
if (err) {
|
||||
return next(new Error(__("could not get the gas price")));
|
||||
}
|
||||
contract.gasPrice = contract.gasPrice || gasPrice;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function createDeployObject(next) {
|
||||
console.dir("= createDeployObject")
|
||||
let contractCode = contract.code;
|
||||
let contractObject = self.blockchain.ContractObject({abi: contract.abiDefinition});
|
||||
let contractParams = (contract.realArgs || contract.args).slice();
|
||||
|
||||
try {
|
||||
const dataCode = contractCode.startsWith('0x') ? contractCode : "0x" + contractCode;
|
||||
deployObject = self.blockchain.deployContractObject(contractObject, {arguments: contractParams, data: dataCode});
|
||||
if (returnObject) {
|
||||
return callback(null, deployObject);
|
||||
}
|
||||
} catch(e) {
|
||||
if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) {
|
||||
return next(new Error(__("attempted to deploy %s without specifying parameters", contract.className)) + ". " + __("check if there are any params defined for this contract in this environment in the contracts configuration file"));
|
||||
}
|
||||
return next(new Error(e));
|
||||
}
|
||||
next();
|
||||
},
|
||||
function estimateCorrectGas(next) {
|
||||
self.blockchain.getClientVersion((err, version) => {
|
||||
if (version.split('/')[0] === GANACHE_CLIENT_VERSION_NAME) {
|
||||
// This is Ganache's gas limit. We subtract 1 so we don't reach the limit.
|
||||
//
|
||||
// We do this because Ganache's gas estimates are wrong (contract creation
|
||||
// has a base cost of 53k, not 21k, so it sometimes results in out of gas
|
||||
// errors.)
|
||||
contract.gas = 6721975 - 1;
|
||||
} else if (contract.gas === 'auto' || !contract.gas) {
|
||||
return self.blockchain.estimateDeployContractGas(deployObject, (err, gasValue) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
let increase_per = 1 + (Math.random() / 10.0);
|
||||
contract.gas = Math.floor(gasValue * increase_per);
|
||||
next();
|
||||
});
|
||||
}
|
||||
next();
|
||||
});
|
||||
},
|
||||
function deployTheContract(next) {
|
||||
console.dir("= deployTheContract " + contract.className)
|
||||
let estimatedCost = contract.gas * contract.gasPrice;
|
||||
|
||||
self.blockchain.deployContractFromObject(deployObject, {
|
||||
from: contract.deploymentAccount,
|
||||
gas: contract.gas,
|
||||
gasPrice: contract.gasPrice
|
||||
}, function(error, receipt) {
|
||||
console.dir("--> contract deployed")
|
||||
console.dir(error)
|
||||
console.dir(receipt)
|
||||
if (error) {
|
||||
contract.error = error.message;
|
||||
self.events.emit("deploy:contract:error", contract);
|
||||
if (error.message && error.message.indexOf('replacement transaction underpriced') !== -1) {
|
||||
self.logger.warn("replacement transaction underpriced: This warning typically means a transaction exactly like this one is still pending on the blockchain");
|
||||
}
|
||||
return next(new Error("error deploying =" + contract.className + "= due to error: " + error.message));
|
||||
}
|
||||
self.logFunction(contract)(`${contract.className.bold.cyan} ${__('deployed at').green} ${receipt.contractAddress.bold.cyan} ${__("using").green} ${receipt.gasUsed} ${__("gas").green} (txHash: ${receipt.transactionHash.bold.cyan})`);
|
||||
contract.deployedAddress = receipt.contractAddress;
|
||||
contract.transactionHash = receipt.transactionHash;
|
||||
receipt.className = contract.className;
|
||||
|
||||
if(receipt) self.events.emit("deploy:contract:receipt", receipt);
|
||||
self.events.emit("deploy:contract:deployed", contract);
|
||||
|
||||
// console.dir("__registerContract")
|
||||
// self.registerContract(contract, () => {
|
||||
console.dir("__runActionsForEvent deploy:contract:deployed")
|
||||
self.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, (err) => {
|
||||
console.dir("result __runActionsForEvent deploy:contract:deployed")
|
||||
if (err) {
|
||||
console.dir(err)
|
||||
return next(err);
|
||||
}
|
||||
next(null, receipt);
|
||||
});
|
||||
}, hash => {
|
||||
self.logFunction(contract)(__("deploying") + " " + contract.className.bold.cyan + " " + __("with").green + " " + contract.gas + " " + __("gas at the price of").green + " " + contract.gasPrice + " " + __("Wei, estimated cost:").green + " " + estimatedCost + " Wei".green + " (txHash: " + hash.bold.cyan + ")");
|
||||
});
|
||||
}
|
||||
], (__err, __results) => {
|
||||
console.dir("--- deployed Contract")
|
||||
callback(__err, __results)
|
||||
});
|
||||
], callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,221 +1,100 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
const async = require('async');
|
||||
// async._waterfall = async.waterfall;
|
||||
// let filename = "index.js";
|
||||
// async.waterfall = function (_tasks, callback) {
|
||||
// let tasks = _tasks.map(function (t) {
|
||||
// let fn = function () {
|
||||
// console.log("async " + (new Error()).stack.split("\n")[1] + ": " + t.name);
|
||||
// t.apply(t, arguments);
|
||||
// };
|
||||
// return fn;
|
||||
// });
|
||||
// async._waterfall(tasks, callback);
|
||||
// };
|
||||
|
||||
const ContractDeployer = require('./contract_deployer.js');
|
||||
const cloneDeep = require('clone-deep');
|
||||
const constants = require('embark-core/constants');
|
||||
|
||||
class DeployManager {
|
||||
class Deployment {
|
||||
constructor(embark, options) {
|
||||
const self = this;
|
||||
this.config = embark.config;
|
||||
this.events = embark.events;
|
||||
this.logger = embark.logger;
|
||||
this.plugins = options.plugins;
|
||||
this.blockchainConfig = this.config.blockchainConfig;
|
||||
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
this.blockchain = options.blockchain;
|
||||
this.gasLimit = 6000000;
|
||||
this.fatalErrors = false;
|
||||
this.deployOnlyOnConfig = false;
|
||||
this.onlyCompile = options.onlyCompile !== undefined ? options.onlyCompile : false;
|
||||
|
||||
this.contractDeployer = new ContractDeployer({
|
||||
logger: this.logger,
|
||||
events: this.events,
|
||||
plugins: this.plugins
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('deployment:contracts:deploy', (contractsList, contractDependencies, cb) => {
|
||||
self.deployContracts(contractsList, contractDependencies, cb);
|
||||
this.deployContracts(contractsList, contractDependencies, cb);
|
||||
});
|
||||
}
|
||||
|
||||
// this.events.setCommandHandler('deploy:setGasLimit', (gasLimit) => {
|
||||
// self.gasLimit = gasLimit;
|
||||
// });
|
||||
deployContracts(contracts, contractDependencies, done) {
|
||||
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.events.emit('contractsDeployed');
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:deployContracts:afterAll', () => { next() });
|
||||
console.dir("==== finished deploying");
|
||||
}
|
||||
], done);
|
||||
}
|
||||
|
||||
// this.events.setCommandHandler('deploy:contracts', (cb) => {
|
||||
// self.deployContracts(cb);
|
||||
// });
|
||||
|
||||
// this.events.setCommandHandler('deploy:contracts:test', (cb) => {
|
||||
// self.fatalErrors = true;
|
||||
// self.deployOnlyOnConfig = true;
|
||||
// self.deployContracts(cb);
|
||||
// });
|
||||
deployContract(contract, callback) {
|
||||
console.dir("requesting to deploy contract")
|
||||
this.events.request('deployment:contract:deploy', contract, (err) => {
|
||||
if (err) {
|
||||
contract.error = err.message || err;
|
||||
if (contract.error === constants.blockchain.gasAllowanceError) {
|
||||
this.logger.error(`[${contract.className}]: ${constants.blockchain.gasAllowanceErrorMessage}`);
|
||||
} else {
|
||||
this.logger.error(`[${contract.className}]: ${err.message || err}`);
|
||||
}
|
||||
errors.push(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
deployAll(contracts, contractDependencies, done) {
|
||||
let self = this;
|
||||
const self = this;
|
||||
console.dir("doing deployAll")
|
||||
const contractDeploys = {};
|
||||
const errors = [];
|
||||
|
||||
// self.events.request('contracts:dependencies', (err, contractDependencies) => {
|
||||
// self.events.request('contracts:list', (err, contracts) => {
|
||||
// if (err) {
|
||||
// return done(err);
|
||||
// }
|
||||
|
||||
self.logger.info(__("deploying contracts"));
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
self.logger.info(__('Executing pre-deploy actions...'));
|
||||
self.plugins.emitAndRunActionsForEvent("deploy:beforeAll", (err) => {
|
||||
// console.dir("== err")
|
||||
// console.dir(err)
|
||||
// TODO: err is a function for some reason
|
||||
// if (err) {
|
||||
// return next(err);
|
||||
// }
|
||||
self.logger.info(__('Pre-deploy actions done. Deploying contracts'));
|
||||
next();
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
const contractDeploys = {};
|
||||
const errors = [];
|
||||
console.dir("=== contracts")
|
||||
console.dir(contracts.map((x) => x.className))
|
||||
contracts.forEach(contract => {
|
||||
function deploy(result, callback) {
|
||||
if (typeof result === 'function') {
|
||||
callback = result;
|
||||
}
|
||||
contract._gasLimit = self.gasLimit;
|
||||
self.events.request('deploy:contract', contract, (err) => {
|
||||
console.dir("contract deployed " + contract.className)
|
||||
if (err) {
|
||||
console.dir("== err deploying contract");
|
||||
console.dir(err);
|
||||
contract.error = err.message || err;
|
||||
if (contract.error === constants.blockchain.gasAllowanceError) {
|
||||
self.logger.error(`[${contract.className}]: ${constants.blockchain.gasAllowanceErrorMessage}`);
|
||||
} else {
|
||||
self.logger.error(`[${contract.className}]: ${err.message || err}`);
|
||||
}
|
||||
errors.push(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
const className = contract.className;
|
||||
if (!contractDependencies[className] || contractDependencies[className].length === 0) {
|
||||
contractDeploys[className] = deploy;
|
||||
return;
|
||||
}
|
||||
contractDeploys[className] = cloneDeep(contractDependencies[className]);
|
||||
contractDeploys[className].push(deploy);
|
||||
});
|
||||
|
||||
console.dir("== async.auto");
|
||||
console.dir(Object.keys(contractDeploys));
|
||||
console.dir(contractDeploys);
|
||||
async.auto(contractDeploys, function (_err, _results) {
|
||||
if (_err) {
|
||||
console.dir("error deploying contracts")
|
||||
console.dir(_err)
|
||||
}
|
||||
if (errors.length) {
|
||||
_err = __("Error deploying contracts. Please fix errors to continue.");
|
||||
self.logger.error(_err);
|
||||
self.events.emit("outputError", __("Error deploying contracts, please check console"));
|
||||
return next(_err);
|
||||
}
|
||||
if (contracts.length === 0) {
|
||||
self.logger.info(__("no contracts found"));
|
||||
return next();
|
||||
}
|
||||
self.logger.info(__("finished deploying contracts"));
|
||||
next(err);
|
||||
});
|
||||
Object.values(contracts).forEach((contract) => {
|
||||
function deploy(result, callback) {
|
||||
console.dir("== deploy")
|
||||
if (typeof result === 'function') callback = result;
|
||||
self.deployContract(contract, callback);
|
||||
}
|
||||
], (err) => {
|
||||
console.dir("==== finished deploying")
|
||||
if (err) {
|
||||
self.logger.error(err);
|
||||
|
||||
const className = contract.className;
|
||||
if (!contractDependencies[className] || contractDependencies[className].length === 0) {
|
||||
contractDeploys[className] = deploy;
|
||||
return;
|
||||
}
|
||||
done(err);
|
||||
});
|
||||
// });
|
||||
// });
|
||||
}
|
||||
contractDeploys[className] = cloneDeep(contractDependencies[className]);
|
||||
contractDeploys[className].push(deploy);
|
||||
})
|
||||
|
||||
deployContracts(contractsList, contractDependencies, done) {
|
||||
let self = this;
|
||||
|
||||
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
|
||||
self.logger.info(__("Blockchain component is disabled in the config").underline);
|
||||
this.events.emit('blockchainDisabled', {});
|
||||
return done();
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function requestBlockchainConnector(callback) {
|
||||
self.events.request("blockchain:object", (blockchain) => {
|
||||
self.blockchain = blockchain;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
function buildContracts(callback) {
|
||||
self.events.request("contracts:build", self.deployOnlyOnConfig, (err) => {
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
|
||||
// TODO: shouldn't be necessary
|
||||
function checkCompileOnly(callback) {
|
||||
if (self.onlyCompile) {
|
||||
self.events.emit('contractsDeployed');
|
||||
return done();
|
||||
}
|
||||
return callback();
|
||||
},
|
||||
|
||||
// TODO: could be implemented as an event (beforeDeployAll)
|
||||
function checkIsConnectedToBlockchain(callback) {
|
||||
self.blockchain.onReady((err) => {
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
|
||||
// TODO: this can be done on the fly or as part of the initialization
|
||||
function determineDefaultAccount(callback) {
|
||||
self.blockchain.determineDefaultAccount((err) => {
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
|
||||
function deployAllContracts(callback) {
|
||||
self.deployAll(contractsList, contractDependencies, function (err) {
|
||||
if (!err) {
|
||||
self.events.emit('contractsDeployed');
|
||||
}
|
||||
if (err && self.fatalErrors) {
|
||||
return callback(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function runAfterDeploy(callback) {
|
||||
self.plugins.emitAndRunActionsForEvent('contracts:deploy:afterAll', callback);
|
||||
async.auto(contractDeploys, (_err, _results) => {
|
||||
if (_err) {
|
||||
console.dir("error deploying contracts")
|
||||
console.dir(_err)
|
||||
}
|
||||
], function (err, _result) {
|
||||
done(err);
|
||||
if (errors.length) {
|
||||
_err = __("Error deploying contracts. Please fix errors to continue.");
|
||||
this.logger.error(_err);
|
||||
this.events.emit("outputError", __("Error deploying contracts, please check console"));
|
||||
return done(_err);
|
||||
}
|
||||
if (contracts.length === 0) {
|
||||
this.logger.info(__("no contracts found"));
|
||||
return done();
|
||||
}
|
||||
this.logger.info(__("finished deploying contracts"));
|
||||
done(_err);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DeployManager;
|
||||
module.exports = Deployment;
|
||||
|
|
|
@ -14,7 +14,7 @@ class EmbarkWeb3 {
|
|||
this.config = embark.config;
|
||||
this.modulesPath = dappPath(embark.config.embarkConfig.generationDir, constants.dappArtifacts.symlinkDir);
|
||||
|
||||
this.addWeb3ToEmbarkJS();
|
||||
// this.addWeb3ToEmbarkJS();
|
||||
}
|
||||
|
||||
async addWeb3ToEmbarkJS() {
|
||||
|
|
|
@ -163,10 +163,22 @@ class EmbarkController {
|
|||
}
|
||||
|
||||
engine.registerModuleGroup("coreComponents");
|
||||
|
||||
engine.registerModuleGroup("blockchain");
|
||||
engine.registerModuleGroup("compiler");
|
||||
engine.registerModuleGroup("contracts");
|
||||
engine.registerModuleGroup("pipeline");
|
||||
engine.registerModuleGroup("webserver");
|
||||
engine.registerModuleGroup("filewatcher");
|
||||
|
||||
engine.events.on('deployment:deployContracts:afterAll', () => {
|
||||
console.dir("--- generating files...")
|
||||
engine.events.request('pipeline:generateAll', () => {
|
||||
console.dir("outputDone")
|
||||
engine.events.emit('outputDone');
|
||||
});
|
||||
})
|
||||
|
||||
// this.events.request('watcher:start');
|
||||
|
||||
// engine.startService("processManager");
|
||||
// engine.startService("web3");
|
||||
|
|
|
@ -35,16 +35,17 @@ class Dashboard {
|
|||
(ws, _req) => {
|
||||
let dashboardState = {contractsState: [], environment: "", status: "", availableServices: []};
|
||||
|
||||
self.events.request('setDashboardState');
|
||||
|
||||
self.events.on('contractsState', (contracts) => {
|
||||
dashboardState.contractsState = [];
|
||||
|
||||
contracts.forEach(function (row) {
|
||||
dashboardState.contractsState.push({contractName: row[0], address: row[1], status: row[2]});
|
||||
});
|
||||
ws.send(JSON.stringify(dashboardState));
|
||||
});
|
||||
// self.events.request('setDashboardState');
|
||||
// self.events.on('contractsState', (contracts) => {
|
||||
// dashboardState.contractsState = [];
|
||||
|
||||
// contracts.forEach(function (row) {
|
||||
// dashboardState.contractsState.push({contractName: row[0], address: row[1], status: row[2]});
|
||||
// });
|
||||
// ws.send(JSON.stringify(dashboardState));
|
||||
// });
|
||||
self.events.on('status', (status) => {
|
||||
dashboardState.status = status;
|
||||
ws.send(JSON.stringify(dashboardState));
|
||||
|
@ -56,7 +57,32 @@ class Dashboard {
|
|||
}
|
||||
);
|
||||
|
||||
this.events.on('contractsState', monitor.setContracts);
|
||||
// this.events.on('contractsState', monitor.setContracts);
|
||||
|
||||
this.events.on("deployment:contract:error", (_contract) => {
|
||||
console.dir("---- contract error event")
|
||||
this.events.request("contracts:state", (err, contracts) => {
|
||||
monitor.setContracts(contracts)
|
||||
});
|
||||
// self.events.emit('contractsState', self.contractsState());
|
||||
});
|
||||
|
||||
this.events.on("deployment:contract:deployed", (_contract) => {
|
||||
console.dir("---- contract deployed event")
|
||||
// self.events.emit('contractsState', self.contractsState());
|
||||
this.events.request("contracts:state", (err, contracts) => {
|
||||
monitor.setContracts(contracts)
|
||||
});
|
||||
});
|
||||
|
||||
this.events.on("deployment:contract:undeployed", (_contract) => {
|
||||
console.dir("---- contract undeployed event")
|
||||
// self.events.emit('contractsState', self.contractsState());
|
||||
this.events.request("contracts:state", (err, contracts) => {
|
||||
monitor.setContracts(contracts)
|
||||
});
|
||||
});
|
||||
|
||||
this.events.on('status', monitor.setStatus.bind(monitor));
|
||||
this.events.on('servicesState', monitor.availableServices.bind(monitor));
|
||||
|
||||
|
|
|
@ -79,7 +79,10 @@ class Engine {
|
|||
"blockchain": this.blockchainComponents,
|
||||
"coreComponents": this.coreComponents,
|
||||
"compiler": this.compilerComponents,
|
||||
"contracts": this.contractsComponents
|
||||
"contracts": this.contractsComponents,
|
||||
"pipeline": this.pipelineService,
|
||||
"webserver": this.webserverService,
|
||||
"filewatcher": this.filewatcherService
|
||||
};
|
||||
|
||||
let group = groups[groupName];
|
||||
|
@ -93,6 +96,23 @@ class Engine {
|
|||
return group.apply(this, [options]);
|
||||
}
|
||||
|
||||
webserverService(_options) {
|
||||
this.registerModulePackage('embark-webserver');
|
||||
}
|
||||
|
||||
filewatcherService(_options) {
|
||||
this.registerModulePackage('embark-watcher');
|
||||
}
|
||||
|
||||
pipelineService(_options) {
|
||||
this.registerModulePackage('embark-pipeline', { plugins: this.plugins });
|
||||
this.registerModule('basic-pipeline', {
|
||||
plugins: this.plugins,
|
||||
webpackConfigName: this.webpackConfigName,
|
||||
useDashboard: this.useDashboard
|
||||
});
|
||||
}
|
||||
|
||||
coreComponents() {
|
||||
// TODO: should be made into a component
|
||||
this.processManager = new ProcessManager({
|
||||
|
@ -155,6 +175,19 @@ class Engine {
|
|||
contractsComponents(options) {
|
||||
this.registerModulePackage('embark-contracts-manager', {plugins: this.plugins, compileOnceOnly: options.compileOnceOnly});
|
||||
this.registerModulePackage('embark-deployment', {plugins: this.plugins, onlyCompile: options.onlyCompile});
|
||||
|
||||
// this.registerModulePackage('embark-blockchain-connector', {
|
||||
// isDev: this.isDev,
|
||||
// locale: this.locale,
|
||||
// plugins: this.plugins,
|
||||
// web3: options.web3,
|
||||
// wait: options.wait
|
||||
// });
|
||||
|
||||
this.registerModule('blockchain-client');
|
||||
this.registerModule('ethereum-blockchain-client');
|
||||
this.registerModule('web3', { plugins: this.plugins });
|
||||
this.registerModulePackage('embark-web3');
|
||||
}
|
||||
|
||||
startService(serviceName, _options) {
|
||||
|
@ -230,31 +263,6 @@ class Engine {
|
|||
this.registerModulePackage('embark-scaffolding', {plugins: this.plugins});
|
||||
}
|
||||
|
||||
pipelineService(_options) {
|
||||
const self = this;
|
||||
this.registerModulePackage('embark-pipeline', { plugins: this.plugins });
|
||||
this.registerModule('basic-pipeline', {
|
||||
plugins: this.plugins,
|
||||
webpackConfigName: this.webpackConfigName,
|
||||
useDashboard: this.useDashboard
|
||||
});
|
||||
// this.events.on('code-generator-ready', function (modifiedAssets) {
|
||||
// self.events.request('code', function (abi, contractsJSON) {
|
||||
// self.events.request('pipeline:build', {abi, contractsJSON, modifiedAssets}, () => {
|
||||
// self.events.emit('outputDone');
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
// TODO: move this to cmd_controller and define all such behaviour there
|
||||
this.events.on('contracts:deploy:afterAll', () => {
|
||||
self.events.request('pipeline:generateAll', () => {
|
||||
console.dir("outputDone")
|
||||
self.events.emit('outputDone');
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
serviceMonitor() {
|
||||
const ServicesMonitor = require('./services_monitor.js');
|
||||
this.servicesMonitor = new ServicesMonitor({events: this.events, logger: this.logger, plugins: this.plugins});
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
class BlockchainClient {
|
||||
|
||||
constructor(embark, options) {
|
||||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
|
||||
this.blockchainClients = {};
|
||||
this.client = null;
|
||||
this.events.setCommandHandler("blockchain:client:register", (clientName, blockchainClient) => {
|
||||
this.blockchainClients[clientName] = blockchainClient;
|
||||
this.client = blockchainClient;
|
||||
})
|
||||
|
||||
// TODO: maybe not the ideal event to listen to?
|
||||
// for e.g, could wait for all stack components to be ready
|
||||
// TODO: probably better to have 2 stages in engine, services start, then connections, etc..
|
||||
this.events.on("blockchain:started", (clientName) => {
|
||||
// make connections
|
||||
// this.client.initAndConnect(); // and config options
|
||||
// should do stuff like
|
||||
// connect to endpoint given
|
||||
// set default account
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BlockchainClient;
|
|
@ -22,7 +22,12 @@ class Blockchain {
|
|||
const client = this.blockchainNodes[clientName];
|
||||
if (!client) return cb("client " + clientName + " not found");
|
||||
|
||||
client.apply(client, [cb]);
|
||||
let onStart = () => {
|
||||
this.events.emit("blockchain:started", clientName);
|
||||
cb();
|
||||
}
|
||||
|
||||
client.apply(client, [onStart]);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
const Web3 = require('web3');
|
||||
const embarkJsUtils = require('embarkjs').Utils;
|
||||
|
||||
class EthereumBlockchainClient {
|
||||
|
||||
constructor(embark, options) {
|
||||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
|
||||
this.events.request("blockchain:client:register", "ethereum", this.getClient.bind(this));
|
||||
this.events.request("deployment:deployer:register", "ethereum", this.deployer.bind(this));
|
||||
}
|
||||
|
||||
getClient() {
|
||||
return {};
|
||||
}
|
||||
|
||||
deployer(contract, done) {
|
||||
var web3 = new Web3("ws://localhost:8556")
|
||||
web3.eth.getAccounts().then((accounts) => {
|
||||
let account = accounts[0];
|
||||
// let contractObject = this.blockchain.ContractObject({abi: contract.abiDefinition});
|
||||
console.dir("== ethereum contract deployer")
|
||||
console.dir(contract)
|
||||
console.dir("-------")
|
||||
console.dir("------- new web3")
|
||||
let contractObj = new web3.eth.Contract(contract.abiDefinition, contract.address);
|
||||
// let deployObject = this.blockchain.deployContractObject(contractObject, {arguments: contractParams, data: dataCode});
|
||||
console.dir("------- deploy")
|
||||
let contractObject = contractObj.deploy({ arguments: (contract.args || []), data: ("0x" + contract.code) });
|
||||
// this.blockchain.deployContractFromObject(deployObject,
|
||||
console.dir({ arguments: contract.args, data: ("0x" + contract.code) });
|
||||
console.dir("------- send")
|
||||
|
||||
embarkJsUtils.secureSend(web3, contractObject, {
|
||||
from: account, gas: 800000
|
||||
}, true, (err, receipt) => {
|
||||
contract.deployedAddress = receipt.contractAddress;
|
||||
contract.transactionHash = receipt.transactionHash;
|
||||
done();
|
||||
}, (hash) => {
|
||||
console.dir('hash is ' + hash);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = EthereumBlockchainClient;
|
|
@ -16,14 +16,15 @@ class Web3Plugin {
|
|||
this.plugins = options.plugins;
|
||||
let plugin = this.plugins.createPlugin('web3plugin', {});
|
||||
|
||||
plugin.registerActionForEvent("deploy:contract:deployed", this.registerInVm.bind(this));
|
||||
plugin.registerActionForEvent("deploy:contract:deployed", this.addContractJSONToPipeline.bind(this));
|
||||
plugin.registerActionForEvent("deploy:contract:deployed", this.addContractFileToPipeline.bind(this));
|
||||
// plugin.registerActionForEvent("deployment:contract:deployed", this.registerInVm.bind(this));
|
||||
plugin.registerActionForEvent("deployment:contract:deployed", this.addContractJSONToPipeline.bind(this));
|
||||
plugin.registerActionForEvent("deployment:contract:deployed", this.addContractFileToPipeline.bind(this));
|
||||
plugin.registerActionForEvent("pipeline:generateAll:before", this.addEmbarkJSNode.bind(this));
|
||||
plugin.registerActionForEvent("pipeline:generateAll:before", this.addContractIndexToPipeline.bind(this));
|
||||
}
|
||||
|
||||
registerInVm(params, cb) {
|
||||
console.dir("-- registerInVm")
|
||||
let contract = params.contract;
|
||||
let abi = JSON.stringify(contract.abiDefinition);
|
||||
let gasLimit = 6000000;
|
||||
|
@ -31,10 +32,14 @@ class Web3Plugin {
|
|||
|
||||
this.events.request('runcode:eval', contractCode, (err) => {
|
||||
if (err) {
|
||||
console.dir("error!!!")
|
||||
console.dir(err)
|
||||
return cb(err);
|
||||
}
|
||||
this.events.request('runcode:eval', contract.className, (err, result) => {
|
||||
if (err) {
|
||||
console.dir("error!!!")
|
||||
console.dir(err)
|
||||
return cb(err);
|
||||
}
|
||||
this.events.emit("runcode:register", contract.className, result, () => { cb() });
|
||||
|
@ -43,6 +48,7 @@ class Web3Plugin {
|
|||
}
|
||||
|
||||
addContractJSONToPipeline(params, cb) {
|
||||
console.dir("-- addContractJSONToPipeline")
|
||||
// TODO: check if this is correct json object to generate
|
||||
const contract = params.contract;
|
||||
|
||||
|
@ -55,6 +61,7 @@ class Web3Plugin {
|
|||
}
|
||||
|
||||
addContractFileToPipeline(params, cb) {
|
||||
console.dir("-- addContractFileToPipeline")
|
||||
const contract = params.contract;
|
||||
const contractName = contract.className;
|
||||
console.dir("--------------");
|
||||
|
|
Loading…
Reference in New Issue