commit
1762cd480e
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"accounts": [
|
||||
{
|
||||
"mnemonic": "add mnemonic here"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -44,6 +44,7 @@
|
|||
"homepage": ".",
|
||||
"dependencies": {
|
||||
"@aragon/os": "3.1.9",
|
||||
"async": "^3.0.0",
|
||||
"clear": "^0.1.0",
|
||||
"cli-spinner": "^0.2.10",
|
||||
"cli-table": "^0.3.1",
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
var inquirer = require('inquirer');
|
||||
const Web3 = require("web3");
|
||||
const PledgeAdminUtils = require('./pledgeadmin-utils');
|
||||
const PledgeUtils = require('./pledge-utils');
|
||||
const TrxUtils = require('./trx-utils');
|
||||
const Contracts = require("./contracts.js");
|
||||
|
||||
const web3 = new Web3();
|
||||
const Provider = require("./provider.js");
|
||||
const Web3 = require('web3');
|
||||
|
||||
function doAction(actionText, action) {
|
||||
console.dir(actionText)
|
||||
|
@ -34,21 +33,36 @@ function doAction(actionText, action) {
|
|||
|
||||
class Actions {
|
||||
|
||||
constructor(chain) {
|
||||
constructor(chain, accounts) {
|
||||
this.chain = chain || "development";
|
||||
this.accounts = accounts || [];
|
||||
}
|
||||
|
||||
connect(url, cb) {
|
||||
connect(options, cb) {
|
||||
const url = options.url;
|
||||
|
||||
console.dir("connecting to: " + url);
|
||||
web3.setProvider(url);
|
||||
|
||||
if (this.accounts.length > 0) {
|
||||
this.provider = new Provider();
|
||||
this.provider.initAccounts(this.accounts);
|
||||
this.provider.startWeb3Provider("ws", url)
|
||||
} else {
|
||||
this.web3 = new Web3();
|
||||
this.web3.setProvider(url);
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
let accounts = await web3.eth.getAccounts();
|
||||
if (this.accounts.length > 0) {
|
||||
this.web3 = this.provider.web3;
|
||||
}
|
||||
|
||||
let accounts = await this.web3.eth.getAccounts();
|
||||
console.dir("== accounts");
|
||||
console.dir(accounts);
|
||||
web3.eth.defaultAccount = accounts[0]
|
||||
this.web3.eth.defaultAccount = accounts[0]
|
||||
|
||||
let contracts = new Contracts(this.chain, web3);
|
||||
let contracts = new Contracts(this.chain, this.web3);
|
||||
contracts.loadContracts();
|
||||
this.contracts = contracts.contracts;
|
||||
|
||||
|
@ -56,15 +70,15 @@ class Actions {
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
web3() {
|
||||
return web3;
|
||||
web3Object() {
|
||||
return this.web3;
|
||||
}
|
||||
|
||||
async addProject(params) {
|
||||
let text = `await LiquidPledging.methods.addProject(\"${params.name}\", \"${params.url}\", \"${params.account}\", ${params.parentProject}, ${params.commitTime}, \"${params.plugin}\").send({from: \"${web3.eth.defaultAccount}\", gas: 2000000})`
|
||||
let text = `await LiquidPledging.methods.addProject(\"${params.name}\", \"${params.url}\", \"${params.account}\", ${params.parentProject}, ${params.commitTime}, \"${params.plugin}\").send({gas: 2000000})`
|
||||
return doAction(text, async () => {
|
||||
const toSend = this.contracts.LiquidPledging.methods.addProject(params.name, params.url, params.account, params.parentProject, params.commitTime, params.plugin);
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, web3.eth.defaultAccount);
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, this.web3.eth.defaultAccount);
|
||||
console.dir("txHash: " + receipt.transactionHash);
|
||||
const projectId = receipt.events.ProjectAdded.returnValues.idProject;
|
||||
console.log("Project ID: " , projectId);
|
||||
|
@ -100,8 +114,8 @@ class Actions {
|
|||
async withdraw(params) {
|
||||
let text = `await LiquidPledging.methods.withdraw(\"${params.id}\", web3.utils.toWei(\"${params.amount}\", "ether")).send({gas: 2000000})`;
|
||||
return doAction(text, async () => {
|
||||
const toSend = this.contracts.LiquidPledging.methods.withdraw(params.id.toString(), web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, web3.eth.defaultAccount);
|
||||
const toSend = this.contracts.LiquidPledging.methods.withdraw(params.id.toString(), this.web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, this.web3.eth.defaultAccount);
|
||||
console.dir("txHash: " + receipt.transactionHash);
|
||||
const paymentId = receipt.events.AuthorizePayment.returnValues.idPayment;
|
||||
console.log("Payment ID: " , paymentId);
|
||||
|
@ -112,7 +126,7 @@ class Actions {
|
|||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const pledges = await PledgeUtils.getPledges(this.contracts.LiquidPledging);
|
||||
PledgeUtils.printTable(pledges, web3);
|
||||
PledgeUtils.printTable(pledges, this.web3);
|
||||
} catch(error){
|
||||
console.log(error);
|
||||
console.log("Couldn't obtain the list of pledges: ", error.message);
|
||||
|
@ -135,10 +149,10 @@ class Actions {
|
|||
}
|
||||
|
||||
async addGiver(params) {
|
||||
let text = `await LiquidPledging.methods.addGiver(\"${params.name}\", \"${params.url}\", ${params.commitTime}, \"${params.plugin}\").send({from: \"${web3.eth.defaultAccount}\", gas: 2000000})`
|
||||
let text = `await LiquidPledging.methods.addGiver(\"${params.name}\", \"${params.url}\", ${params.commitTime}, \"${params.plugin}\").send({gas: 2000000})`
|
||||
return doAction(text, async () => {
|
||||
const toSend = this.contracts.LiquidPledging.methods.addGiver(params.name, params.url, params.commitTime, params.plugin);
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, web3.eth.defaultAccount);
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, this.web3.eth.defaultAccount);
|
||||
console.dir("txHash: " + receipt.transactionHash);
|
||||
const funderId = receipt.events.GiverAdded.returnValues.idGiver;
|
||||
console.log("Funder ID: " , funderId);
|
||||
|
@ -148,8 +162,8 @@ class Actions {
|
|||
async mintToken(params) {
|
||||
let text = `await StandardToken.methods.mint(\"${params.account}\", web3.utils.toWei(\"${params.amount}\", \"ether\")).send({gas: 2000000})`
|
||||
return doAction(text, async () => {
|
||||
const toSend = this.contracts.StandardToken.methods.mint(params.account, web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, web3.eth.defaultAccount);
|
||||
const toSend = this.contracts.StandardToken.methods.mint(params.account, this.web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, this.web3.eth.defaultAccount);
|
||||
console.dir("txHash: " + receipt.transactionHash);
|
||||
});
|
||||
}
|
||||
|
@ -157,8 +171,8 @@ class Actions {
|
|||
async approveToken(params) {
|
||||
let text = `await StandardToken.methods.approve(\"${this.contracts.LiquidPledging.options.address}\", web3.utils.toWei(\"${params.amount}\", \"ether\")).send({gas: 2000000})`
|
||||
return doAction(text, async () => {
|
||||
const toSend = this.contracts.StandardToken.methods.approve(this.contracts.LiquidPledging.options.address, web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, web3.eth.defaultAccount);
|
||||
const toSend = this.contracts.StandardToken.methods.approve(this.contracts.LiquidPledging.options.address, this.web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, this.web3.eth.defaultAccount);
|
||||
console.dir("txHash: " + receipt.transactionHash);
|
||||
});
|
||||
}
|
||||
|
@ -166,8 +180,8 @@ class Actions {
|
|||
async donate(params) {
|
||||
let text = `await LiquidPledging.methods.donate(${params.funderId}, ${params.projectId}, \"${params.tokenAddress}\", web3.utils.toWei(\"${params.amount}\", \"ether\")).send({gas: 2000000});`
|
||||
return doAction(text, async () => {
|
||||
const toSend = this.contracts.LiquidPledging.methods.donate(params.funderId, params.projectId, params.tokenAddress, web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, web3.eth.defaultAccount);
|
||||
const toSend = this.contracts.LiquidPledging.methods.donate(params.funderId, params.projectId, params.tokenAddress, this.web3.utils.toWei(params.amount.toString(), "ether"));
|
||||
const receipt = await TrxUtils.executeAndWait(toSend, this.web3.eth.defaultAccount);
|
||||
console.dir("txHash: " + receipt.transactionHash);
|
||||
});
|
||||
}
|
||||
|
|
16
src/cmd.js
16
src/cmd.js
|
@ -11,18 +11,18 @@ function mainMenu(actions) {
|
|||
|
||||
if (subAction === 'List Projects') {
|
||||
await actions.listProjects();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (subAction === 'Create Project') {
|
||||
let params = (await menus.createProject(actions.web3().eth.defaultAccount))
|
||||
let params = (await menus.createProject(actions.web3Object().eth.defaultAccount))
|
||||
await actions.addProject(params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (subAction === 'View Project') {
|
||||
let params = (await menus.viewProject())
|
||||
await actions.viewProject(params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (subAction === 'Fund a Project') {
|
||||
let params = (await menus.donate())
|
||||
await actions.donate(params);
|
||||
|
@ -37,7 +37,7 @@ function mainMenu(actions) {
|
|||
if (subAction === 'Withdraw') {
|
||||
let params = (await menus.withdraw())
|
||||
await actions.withdraw(params);
|
||||
}
|
||||
}
|
||||
} else if (action === 'Funders') {
|
||||
subAction = (await menus.funders()).action
|
||||
|
||||
|
|
12
src/index.js
12
src/index.js
|
@ -5,12 +5,20 @@ const Actions = require('./actions.js');
|
|||
program
|
||||
.version('0.1.0')
|
||||
.option('-u, --url [url]', "host to connect to (default: ws://localhost:8556)")
|
||||
.option('-a, --accounts [accounts]', "accounts file, if not defined uses accounts in the connecting node")
|
||||
.option('-c, --chain [chain]', "environment to run, can be mainnet, ropsten, development (default: development)")
|
||||
.parse(process.argv);
|
||||
|
||||
const actions = new Actions(program.chain || "development");
|
||||
let accounts = [];
|
||||
if (program.accounts) {
|
||||
accounts = require(process.cwd() + "/" + program.accounts).accounts;
|
||||
}
|
||||
|
||||
actions.connect(program.url || "ws://localhost:8556", async () => {
|
||||
const actions = new Actions(program.chain || "development", accounts || []);
|
||||
|
||||
actions.connect({
|
||||
url: (program.url || "ws://localhost:8556")
|
||||
}, async () => {
|
||||
cmd(actions)
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
const async = require('async');
|
||||
const Web3 = require('web3');
|
||||
const bip39 = require("bip39");
|
||||
const hdkey = require('ethereumjs-wallet/hdkey');
|
||||
const ethUtil = require('ethereumjs-util');
|
||||
const Transaction = require('ethereumjs-tx');
|
||||
|
||||
class Provider {
|
||||
|
||||
constructor() {
|
||||
this.accounts = []
|
||||
this.addresses = []
|
||||
this.nonceCache = {};
|
||||
this.web3 = new Web3();
|
||||
}
|
||||
|
||||
initAccounts(accounts) {
|
||||
for (let accountConfig of accounts) {
|
||||
if (accountConfig.mnemonic) {
|
||||
const hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(accountConfig.mnemonic.trim()));
|
||||
|
||||
const addressIndex = accountConfig.addressIndex || 0;
|
||||
const numAddresses = accountConfig.numAddresses || 1;
|
||||
const wallet_hdpath = accountConfig.hdpath || "m/44'/60'/0'/0/";
|
||||
|
||||
for (let i = addressIndex; i < addressIndex + numAddresses; i++) {
|
||||
const wallet = hdwallet.derivePath(wallet_hdpath + i).getWallet();
|
||||
//if (returnAddress) {
|
||||
// this.accounts.push(wallet.getAddressString());
|
||||
//} else {
|
||||
this.accounts.push(this.web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex')));
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startWeb3Provider(type, web3Endpoint) {
|
||||
const self = this;
|
||||
|
||||
if (type === 'rpc') {
|
||||
self.provider = new this.web3.providers.HttpProvider(web3Endpoint);
|
||||
} else if (type === 'ws') {
|
||||
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
||||
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
||||
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the following error:
|
||||
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
||||
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
||||
self.provider = new this.web3.providers.WebsocketProvider(web3Endpoint, {
|
||||
headers: {Origin: "http://embark"},
|
||||
// TODO remove this when Geth fixes this: https://github.com/ethereum/go-ethereum/issues/16846
|
||||
clientConfig: {
|
||||
fragmentationThreshold: 81920
|
||||
}
|
||||
});
|
||||
self.provider.on('error', () => console.error('Websocket Error'));
|
||||
self.provider.on('end', () => console.error('Websocket connection ended'));
|
||||
} else {
|
||||
}
|
||||
|
||||
self.web3.setProvider(self.provider);
|
||||
|
||||
self.accounts.forEach(account => {
|
||||
self.addresses.push(account.address || account);
|
||||
if (account.privateKey) {
|
||||
self.web3.eth.accounts.wallet.add(account);
|
||||
}
|
||||
});
|
||||
self.addresses = [...new Set(self.addresses)]; // Remove duplicates
|
||||
|
||||
if (self.accounts.length) {
|
||||
self.web3.eth.defaultAccount = self.addresses[0];
|
||||
}
|
||||
|
||||
const realSend = self.provider.send.bind(self.provider);
|
||||
|
||||
self.runTransaction = async.queue(({payload}, callback) => {
|
||||
const rawTx = payload.params[0];
|
||||
const rawData = Buffer.from(ethUtil.stripHexPrefix(rawTx), 'hex');
|
||||
const tx = new Transaction(rawData, 'hex');
|
||||
const address = '0x' + tx.getSenderAddress().toString('hex').toLowerCase();
|
||||
|
||||
self.getNonce(address, (newNonce) => {
|
||||
tx.nonce = newNonce;
|
||||
const key = ethUtil.stripHexPrefix(self.web3.eth.accounts.wallet[address].privateKey);
|
||||
const privKey = Buffer.from(key, 'hex');
|
||||
tx.sign(privKey);
|
||||
payload.params[0] = '0x' + tx.serialize().toString('hex');
|
||||
return realSend(payload, (error, result) => {
|
||||
self.web3.eth.getTransaction(result.result, () => {
|
||||
callback(error, result);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 1);
|
||||
|
||||
self.provider.send = function(payload, cb) {
|
||||
if (payload.method === 'eth_accounts') {
|
||||
return realSend(payload, function(err, result) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (self.accounts.length) {
|
||||
result.result = self.addresses;
|
||||
}
|
||||
cb(null, result);
|
||||
});
|
||||
} else if (payload.method === "eth_sendRawTransaction") {
|
||||
return self.runTransaction.push({payload}, cb);
|
||||
}
|
||||
|
||||
realSend(payload, cb);
|
||||
};
|
||||
}
|
||||
|
||||
getNonce(address, callback) {
|
||||
this.web3.eth.getTransactionCount(address, (_error, transactionCount) => {
|
||||
if(this.nonceCache[address] === undefined) {
|
||||
this.nonceCache[address] = -1;
|
||||
}
|
||||
|
||||
if (transactionCount > this.nonceCache[address]) {
|
||||
this.nonceCache[address] = transactionCount;
|
||||
return callback(this.nonceCache[address]);
|
||||
}
|
||||
|
||||
this.nonceCache[address]++;
|
||||
callback(this.nonceCache[address]);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Provider;
|
|
@ -1,20 +1,23 @@
|
|||
const Spinner = require('cli-spinner').Spinner;
|
||||
|
||||
const executeAndWait = async (toSend, account) => {
|
||||
const spinner = new Spinner('%s');
|
||||
spinner.setSpinnerString(18);
|
||||
spinner.start();
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const spinner = new Spinner('%s');
|
||||
spinner.setSpinnerString(18);
|
||||
spinner.start();
|
||||
|
||||
try {
|
||||
const estimatedGas = await toSend.estimateGas({from: account});
|
||||
const receipt = await toSend.send({from: account, gas: estimatedGas + 10000});
|
||||
try {
|
||||
const estimatedGas = await toSend.estimateGas({from: account});
|
||||
const receipt = await toSend.send({from: account, gas: estimatedGas + 10000});
|
||||
|
||||
spinner.stop(true);
|
||||
return receipt;
|
||||
} catch(error) {
|
||||
console.log("Error minting tokens: ", error.message);
|
||||
spinner.stop(true);
|
||||
}
|
||||
spinner.stop(true);
|
||||
return resolve(receipt);
|
||||
} catch(error) {
|
||||
console.log("Error: ", error.message);
|
||||
spinner.stop(true);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -1351,6 +1351,11 @@ async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0, async@^2.6.0, async@^2.6
|
|||
dependencies:
|
||||
lodash "^4.17.11"
|
||||
|
||||
async@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.0.0.tgz#4c959b37d8c477dc189f2efb9340847f7ad7f785"
|
||||
integrity sha512-LNZ6JSpKraIia6VZKKbKxmX6nWIdfsG7WqrOvKpCuDjH7BnGyQRFMTSXEe8to2WF/rqoAKgZvj+L5nnxe0suAg==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
|
Loading…
Reference in New Issue