Use prompt instead of argv arguments in scripts #32

Closed
bumi wants to merge 3 commits from feature/multi-network-support-for-scripts into master
17 changed files with 165 additions and 73 deletions

View File

@ -1 +1 @@
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"} {"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0x6ebe4c6a39216e37f5efafd9ce89e2bed293270e"}

View File

@ -1 +1 @@
{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"} {"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x38062ac7ac5f910471ce490eabf0af1c4ac92c5f"}

View File

@ -1 +1 @@
{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x513f8e80a8fbb9fa188320ecf231efcf2f6da9c5"} {"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x2cf47d9c33590ade7261bba063082e5ee1469911"}

View File

@ -1 +1 @@
{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"} {"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x98547fe20531018a2fd5e4a70be11c4ecbeb0520"}

View File

@ -3,6 +3,10 @@ class Base {
this.contract = contract; this.contract = contract;
} }
get address() {
return this.contract.address;
}
get functions() { get functions() {
return this.contract.functions; return this.contract.functions;
} }

View File

@ -42,13 +42,14 @@ class Contributor extends Base {
.add(json) .add(json)
.then((ipfsHashAttr) => { .then((ipfsHashAttr) => {
let contributor = [ let contributor = [
contributorAttr.address, contributorAttr.account,
ipfsHashAttr.hashDigest, ipfsHashAttr.hashDigest,
ipfsHashAttr.hashFunction, ipfsHashAttr.hashFunction,
ipfsHashAttr.hashSize, ipfsHashAttr.hashSize,
contributorAttr.isCore, contributorAttr.isCore,
]; ];
console.log(contributor);
return this.functions.addContributor(...contributor); return this.functions.addContributor(...contributor);
}); });
} }

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
Contributors: require('./contributor'), Contributors: require('./contributor'),
Operator: require('./operator'), Operator: require('./operator'),
Token: require('./token') Token: require('./token'),
Registry: require('./registry')
} }

View File

@ -0,0 +1,8 @@
const Base = require('./base');
class Registry extends Base {
}
module.exports = Registry;

24
lib/healthcheck.js Normal file
View File

@ -0,0 +1,24 @@
class Healthcheck {
constructor(kredits) {
this.kredits = kredits;
}
check() {
return this.kredits.ipfs._ipfsAPI.id()
.catch((error) => {
throw new Error(`IPFS node not available; config: ${JSON.stringify(this.kredits.ipfs.config)} - ${error.message}`);
})
.then(() => {
return Object.keys(this.kredits.contracts).map((name) => {
let contract = this.kredits.contracts[name];
this.kredits.provider.getCode(contract.address).then((code) => {
// not sure if we always get the same return value of the code is not available
// that's why checking if it is < 5 long
if (code === '0x00' || code.length < 5) {
throw new Error(`Registry not found at ${contract.address} on network ${this.kredits.provider.chainId}`);
}
});
});
});
}
}

View File

@ -1,13 +1,13 @@
const ethers = require('ethers'); const ethers = require('ethers');
const RSVP = require('rsvp'); const RSVP = require('rsvp');
const abis = { const ABIs = {
Contributors: require('./abis/Contributors.json'), Contributors: require('./abis/Contributors.json'),
Operator: require('./abis/Operator.json'), Operator: require('./abis/Operator.json'),
Registry: require('./abis/Registry.json'), Registry: require('./abis/Registry.json'),
Token: require('./abis/Token.json') Token: require('./abis/Token.json')
}; };
const addresses = { const ADDRESSES = {
Registry: require('./addresses/Registry.json') Registry: require('./addresses/Registry.json')
}; };
@ -22,7 +22,7 @@ function capitalize(word) {
class Kredits { class Kredits {
static get contractNames() { static get contractNames() {
return Object.keys(abis); return Object.keys(ABIs);
} }
constructor(provider, signer, addresses) { constructor(provider, signer, addresses) {
@ -30,11 +30,26 @@ class Kredits {
this.signer = signer; this.signer = signer;
// Initialize our registry contract // Initialize our registry contract
this.addresses = addresses; this.addresses = addresses || ADDRESSES[this.provider.chainId];
this.abis = ABIs;
this.contracts = {}; this.contracts = {};
this.ipfs = new IPFS(); this.ipfs = new IPFS();
} }
init(names) {
let contractsToLoad = names || Kredits.contractNames;
let addressPromises = contractsToLoad.map((contractName) => {
return this.Registry.functions.getProxyFor(contractName).then((address) => {
this.addresses[contractName] = address;
}).catch((error) => {
throw new Error(`Failed to get address for ${contractName} from registry at ${this.Registry.address}
- correct registry? does it have version entry? - ${error.message}`
);
});
});
return RSVP.all(addressPromises).then(() => { return this });
}
static setup(provider, signer, ipfsConfig = null) { static setup(provider, signer, ipfsConfig = null) {
let ipfsAPI = new IPFS(ipfsConfig); let ipfsAPI = new IPFS(ipfsConfig);
@ -64,11 +79,11 @@ class Kredits {
} }
static initRegistryContract(provider) { static initRegistryContract(provider) {
let address = addresses['Registry'][provider.chainId]; let address = ADDRESSES['Registry'][provider.chainId];
if (!address) { if (!address) {
throw new Error(`Registry address not found; invalid network? throw new Error(`Registry address not found; invalid network?
requested network: ${provider.chainId} requested network: ${provider.chainId}
supported networks: ${Object.keys(addresses['Registry'])} supported networks: ${Object.keys(ADDRESSES['Registry'])}
`); `);
} }
provider.getCode(address).then((code) => { provider.getCode(address).then((code) => {
@ -78,10 +93,14 @@ class Kredits {
throw new Error(`Registry not found at ${address} on network ${provider.chainId}`); throw new Error(`Registry not found at ${address} on network ${provider.chainId}`);
} }
}); });
let abi = abis['Registry']; let abi = ABIs['Registry'];
return new ethers.Contract(address, abi, provider); return new ethers.Contract(address, abi, provider);
} }
get Registry() {
return this.contractFor('registry');
}
get Contributor() { get Contributor() {
// TODO: rename to contributor // TODO: rename to contributor
return this.contractFor('contributors'); return this.contractFor('contributors');
@ -103,10 +122,11 @@ class Kredits {
let contractName = capitalize(name); let contractName = capitalize(name);
let address = this.addresses[contractName]; let address = this.addresses[contractName];
if (!address || !abis[contractName]) { let abi = this.abis[contractName];
if (!address || !abi) {
throw new Error(`Address or ABI not found for ${contractName}`); throw new Error(`Address or ABI not found for ${contractName}`);
} }
let contract = new ethers.Contract(address, abis[contractName], this.signer); let contract = new ethers.Contract(address, abi, this.signer);
this.contracts[name] = new contracts[contractName](contract); this.contracts[name] = new contracts[contractName](contract);
this.contracts[name].ipfs = this.ipfs; this.contracts[name].ipfs = this.ipfs;

19
package-lock.json generated
View File

@ -4230,6 +4230,16 @@
"resolved": "https://registry.npmjs.org/promisify-es6/-/promisify-es6-1.0.3.tgz", "resolved": "https://registry.npmjs.org/promisify-es6/-/promisify-es6-1.0.3.tgz",
"integrity": "sha512-N9iVG+CGJsI4b4ZGazjwLnxErD2d9Pe4DPvvXSxYA9tFNu8ymXME4Qs5HIQ0LMJpNM7zj+m0NlNnNeqFpKzqnA==" "integrity": "sha512-N9iVG+CGJsI4b4ZGazjwLnxErD2d9Pe4DPvvXSxYA9tFNu8ymXME4Qs5HIQ0LMJpNM7zj+m0NlNnNeqFpKzqnA=="
}, },
"promptly": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/promptly/-/promptly-3.0.3.tgz",
"integrity": "sha512-EWnzOsxVKUjqKeE6SStH1/cO4+DE44QolaoJ4ojGd9z6pcNkpgfJKr1ncwxrOFHSTIzoudo7jG8y0re30/LO1g==",
"dev": true,
"requires": {
"pify": "3.0.0",
"read": "1.0.7"
}
},
"protocol-buffers-schema": { "protocol-buffers-schema": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz",
@ -4343,6 +4353,15 @@
} }
} }
}, },
"read": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
"dev": true,
"requires": {
"mute-stream": "0.0.7"
}
},
"read-chunk": { "read-chunk": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz",

View File

@ -25,6 +25,7 @@
"homepage": "https://github.com/67P/truffle-kredits#readme", "homepage": "https://github.com/67P/truffle-kredits#readme",
"devDependencies": { "devDependencies": {
"ganache-cli": "^6.0.3", "ganache-cli": "^6.0.3",
"promptly": "^3.0.3",
"truffle": "^4.1.3", "truffle": "^4.1.3",
"zeppelin-solidity": "^1.7.0" "zeppelin-solidity": "^1.7.0"
}, },

View File

@ -1,47 +1,65 @@
const Registry = artifacts.require('./Registry.sol'); const Registry = artifacts.require('./Registry.sol');
const Operator = artifacts.require('./Operator.sol'); const Operator = artifacts.require('./Operator.sol');
const Contributors = artifacts.require('./Contributors.sol'); const Contributors = artifacts.require('./Contributors.sol');
const promptly = require('promptly');
var bs58 = require('bs58'); const IPFS = require('../lib/utils/ipfs');
const ipfs = new IPFS();
const bs58 = require('bs58');
function getBytes32FromMultiash(multihash) { const ethers = require('ethers');
const decoded = bs58.decode(multihash); const Kredits = require('../lib/kredits');
return { async function prompt(message, options) {
digest: `0x${decoded.slice(2).toString('hex')}`, if (!options) {
hashFunction: decoded[0], options = {default: ''}
size: decoded[1], }
}; return await promptly.prompt(message, options);
} }
module.exports = function(callback) { module.exports = function(callback) {
Registry.deployed().then(async (registry) => { Registry.deployed().then(async (registry) => {
var operatorAddress = await registry.getProxyFor('Operator');
var contributorsAddress = await registry.getProxyFor('Contributors');
var operator = await Operator.at(operatorAddress); console.log(`Using registry at: ${registry.address}`);
var contributors = await Contributors.at(contributorsAddress); let networkId = parseInt(web3.version.network);
console.log(web3.currentProvider);
let contributorToAddAddress = process.argv[4]; let provider = new ethers.providers.Web3Provider(
if(!contributorToAddAddress) { web3.currentProvider,
console.log('please provide an address'); { chainId: networkId }
proxess.exit(); )
console.log(provider.getSigner());
const kredits = await new Kredits(provider, provider.getSigner(), {Registry: registry.address}).init();
console.log(`Using contributors at: ${kredits.Contributor.address}`);
let contributorAttributes = {
account: await prompt('Contributor address: ', {}),
name: await prompt('Name: '),
isCore: await prompt('core? y/n') === 'y',
kind: await prompt('Kind (default person): ', {default: 'person'}),
url: await prompt('URL: '),
github_username: await prompt('GitHub username: '),
github_uid: await prompt('GitHub UID: '),
wiki_username: await prompt('Wiki username: '),
} }
let ipfsHash = process.argv[5] || 'QmQyZJT9uikzDYTZLhhyVZ5ReZVCoMucYzyvDokDJsijhj';
let contributorMultihash = getBytes32FromMultiash(ipfsHash);
let isCore = true;
let contributorResult = await contributors.addContributor(contributorToAddAddress, contributorMultihash.digest, contributorMultihash.hashFunction, contributorMultihash.size, isCore);
console.log('Contributor added, tx: ', contributorResult.tx);
let contributorId = await contributors.getContributorIdByAddress(contributorToAddAddress); contributorAttributes = {
let proposalMultihash = getBytes32FromMultiash('QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs'); account: '0x398ac9cdb122e6f526c8bf8dd80eeeb18fce8821',
let proposalResult = await operator.addProposal(contributorId, 23, proposalMultihash.digest, proposalMultihash.hashFunction, proposalMultihash.size); name: 'bumi',
console.log('Proposal added, tx: ', proposalResult.tx); isCore: '1'
}
let proposalId = await operator.proposalsCount(); console.log("\nCreating new contributor with following attributes:");
let votingResult = await operator.vote(proposalId.toNumber()-1); console.log(contributorAttributes);
console.log('Voted for proposal', proposalId.toString(), votingResult.tx); kredits.Contributor.functions.addContributor('0x398ac9cdb122e6f526c8bf8dd80eeeb18fce8821',
'0x272bbfc66166f26cae9c9b96b7f9590e095f02edf342ac2dd71e1667a12116ca', 18, 32, true).then((r) => {
callback(); console.log(r);
process.exit();
});
/*
kredits.Contributor.add(contributorAttributes).then((result) => {
console.log(result);
callback();
}).catch((error) => {
console.log('Failed to create contributor');
callback(error);
});
*/
}); });
} }

View File

@ -1,8 +1,9 @@
const Registry = artifacts.require('./Registry.sol'); const Registry = artifacts.require('./Registry.sol');
const Operator = artifacts.require('./Operator.sol'); const Operator = artifacts.require('./Operator.sol');
const Contributors = artifacts.require('./Contributors.sol'); const Contributors = artifacts.require('./Contributors.sol');
const promptly = require('promptly');
var bs58 = require('bs58'); const bs58 = require('bs58');
function getBytes32FromMultiash(multihash) { function getBytes32FromMultiash(multihash) {
const decoded = bs58.decode(multihash); const decoded = bs58.decode(multihash);
@ -22,12 +23,9 @@ module.exports = function(callback) {
var operator = await Operator.at(operatorAddress); var operator = await Operator.at(operatorAddress);
var contributors = await Contributors.at(contributorsAddress); var contributors = await Contributors.at(contributorsAddress);
let recipientAddress = process.argv[4]; let recipientAddress = await promptly.prompt('Contributor address: ');
if(!recipientAddress) { let ipfsHash = await promptly.prompt('IPFS hash (blank for default): ', { default: 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs' });
console.log('please provide an address');
process.exit();
}
let ipfsHash = process.argv[5] || 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs';
let multihash = getBytes32FromMultiash(ipfsHash); let multihash = getBytes32FromMultiash(ipfsHash);
let contributorId = await contributors.getContributorIdByAddress(recipientAddress); let contributorId = await contributors.getContributorIdByAddress(recipientAddress);

View File

@ -1,17 +1,15 @@
const REPL = require('repl'); const REPL = require('repl');
const promptly = require('promptly');
module.exports = function(callback) { module.exports = function(callback) {
const Registry = artifacts.require('./Registry.sol'); const Registry = artifacts.require('./Registry.sol');
Registry.deployed().then(async (registry) => { Registry.deployed().then(async (registry) => {
let contractName = process.argv[4]; let contractName = await promptly.prompt('Contract Name: ');
let method = process.argv[5]; let method = await promptly.prompt('Function: ');
let args = process.argv.slice(6); let argumentInput = await promptly.prompt('Arguments (comma separated): ', { default: '' });
let args = [];
if (!contractName) { if (argumentInput !== '') {
console.log("Usage:"); args = argumentInput.split(',').map(a => a.trim());
console.log(" truffle exec scripts/cli.js <Contract name> <method to call> [<optional> <arguments>]");
callback();
return;
} }
let contractAddress = await registry.getProxyFor(contractName); let contractAddress = await registry.getProxyFor(contractName);

View File

@ -1,4 +1,4 @@
var bs58 = require('bs58'); const bs58 = require('bs58');
function getBytes32FromMultiash(multihash) { function getBytes32FromMultiash(multihash) {
const decoded = bs58.decode(multihash); const decoded = bs58.decode(multihash);

View File

@ -1,12 +1,12 @@
const promptly = require('promptly');
module.exports = async function(callback) {
let recipient = await promptly.prompt('Recipient address: ');
let amount = await promptly.prompt('Amount: ', {default: '1'});
amount = parseInt(amount);
console.log(`sending ${amount} ETH from ${web3.eth.accounts[0]} to ${recipient}`);
module.exports = function(callback) {
let recipient = process.argv[4];
if (!recipient) {
console.log('Please provide a recipient address');
process.exit();
}
let amount = parseInt(process.argv[5]) || 1;
console.log(recipient);
web3.eth.sendTransaction({to: recipient, value: web3.toWei(amount), from: web3.eth.accounts[0]}, console.log); web3.eth.sendTransaction({to: recipient, value: web3.toWei(amount), from: web3.eth.accounts[0]}, console.log);
callback(); callback();