diff --git a/lib/addresses/Contributors.json b/lib/addresses/Contributors.json index 7c8cb62..9b722e1 100644 --- a/lib/addresses/Contributors.json +++ b/lib/addresses/Contributors.json @@ -1 +1 @@ -{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"} \ No newline at end of file +{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0x6ebe4c6a39216e37f5efafd9ce89e2bed293270e"} \ No newline at end of file diff --git a/lib/addresses/Operator.json b/lib/addresses/Operator.json index b865526..0298bb1 100644 --- a/lib/addresses/Operator.json +++ b/lib/addresses/Operator.json @@ -1 +1 @@ -{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"} \ No newline at end of file +{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x38062ac7ac5f910471ce490eabf0af1c4ac92c5f"} \ No newline at end of file diff --git a/lib/addresses/Registry.json b/lib/addresses/Registry.json index 8bdcb57..2e23736 100644 --- a/lib/addresses/Registry.json +++ b/lib/addresses/Registry.json @@ -1 +1 @@ -{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x513f8e80a8fbb9fa188320ecf231efcf2f6da9c5"} \ No newline at end of file +{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x2cf47d9c33590ade7261bba063082e5ee1469911"} \ No newline at end of file diff --git a/lib/addresses/Token.json b/lib/addresses/Token.json index 9242b73..ecb7bba 100644 --- a/lib/addresses/Token.json +++ b/lib/addresses/Token.json @@ -1 +1 @@ -{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"} \ No newline at end of file +{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x98547fe20531018a2fd5e4a70be11c4ecbeb0520"} \ No newline at end of file diff --git a/lib/contracts/base.js b/lib/contracts/base.js index de43c19..ba113b5 100644 --- a/lib/contracts/base.js +++ b/lib/contracts/base.js @@ -3,6 +3,10 @@ class Base { this.contract = contract; } + get address() { + return this.contract.address; + } + get functions() { return this.contract.functions; } diff --git a/lib/contracts/contributor.js b/lib/contracts/contributor.js index 127e2dc..a112f2c 100644 --- a/lib/contracts/contributor.js +++ b/lib/contracts/contributor.js @@ -42,13 +42,14 @@ class Contributor extends Base { .add(json) .then((ipfsHashAttr) => { let contributor = [ - contributorAttr.address, + contributorAttr.account, ipfsHashAttr.hashDigest, ipfsHashAttr.hashFunction, ipfsHashAttr.hashSize, contributorAttr.isCore, ]; + console.log(contributor); return this.functions.addContributor(...contributor); }); } diff --git a/lib/contracts/index.js b/lib/contracts/index.js index 9fd06ae..f9f209b 100644 --- a/lib/contracts/index.js +++ b/lib/contracts/index.js @@ -1,5 +1,6 @@ module.exports = { Contributors: require('./contributor'), Operator: require('./operator'), - Token: require('./token') + Token: require('./token'), + Registry: require('./registry') } diff --git a/lib/contracts/registry.js b/lib/contracts/registry.js new file mode 100644 index 0000000..3ff8562 --- /dev/null +++ b/lib/contracts/registry.js @@ -0,0 +1,8 @@ +const Base = require('./base'); + +class Registry extends Base { +} + +module.exports = Registry; + + diff --git a/lib/healthcheck.js b/lib/healthcheck.js new file mode 100644 index 0000000..b440d5e --- /dev/null +++ b/lib/healthcheck.js @@ -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}`); + } + }); + }); + }); + } +} diff --git a/lib/kredits.js b/lib/kredits.js index 8182137..e7eefc5 100644 --- a/lib/kredits.js +++ b/lib/kredits.js @@ -1,13 +1,13 @@ const ethers = require('ethers'); const RSVP = require('rsvp'); -const abis = { +const ABIs = { Contributors: require('./abis/Contributors.json'), Operator: require('./abis/Operator.json'), Registry: require('./abis/Registry.json'), Token: require('./abis/Token.json') }; -const addresses = { +const ADDRESSES = { Registry: require('./addresses/Registry.json') }; @@ -22,7 +22,7 @@ function capitalize(word) { class Kredits { static get contractNames() { - return Object.keys(abis); + return Object.keys(ABIs); } constructor(provider, signer, addresses) { @@ -30,11 +30,26 @@ class Kredits { this.signer = signer; // Initialize our registry contract - this.addresses = addresses; + this.addresses = addresses || ADDRESSES[this.provider.chainId]; + this.abis = ABIs; this.contracts = {}; 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) { let ipfsAPI = new IPFS(ipfsConfig); @@ -64,11 +79,11 @@ class Kredits { } static initRegistryContract(provider) { - let address = addresses['Registry'][provider.chainId]; + let address = ADDRESSES['Registry'][provider.chainId]; if (!address) { throw new Error(`Registry address not found; invalid network? requested network: ${provider.chainId} - supported networks: ${Object.keys(addresses['Registry'])} + supported networks: ${Object.keys(ADDRESSES['Registry'])} `); } provider.getCode(address).then((code) => { @@ -78,10 +93,14 @@ class Kredits { 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); } + get Registry() { + return this.contractFor('registry'); + } + get Contributor() { // TODO: rename to contributor return this.contractFor('contributors'); @@ -103,10 +122,11 @@ class Kredits { let contractName = capitalize(name); 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}`); } - 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].ipfs = this.ipfs; diff --git a/package-lock.json b/package-lock.json index e3024a1..473e969 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4230,6 +4230,16 @@ "resolved": "https://registry.npmjs.org/promisify-es6/-/promisify-es6-1.0.3.tgz", "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": { "version": "3.3.2", "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": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", diff --git a/package.json b/package.json index b2e9257..9cf8786 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "homepage": "https://github.com/67P/truffle-kredits#readme", "devDependencies": { "ganache-cli": "^6.0.3", + "promptly": "^3.0.3", "truffle": "^4.1.3", "zeppelin-solidity": "^1.7.0" }, diff --git a/scripts/add-contributor.js b/scripts/add-contributor.js index e003bd9..6f5f043 100644 --- a/scripts/add-contributor.js +++ b/scripts/add-contributor.js @@ -1,47 +1,65 @@ const Registry = artifacts.require('./Registry.sol'); const Operator = artifacts.require('./Operator.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 decoded = bs58.decode(multihash); +const ethers = require('ethers'); +const Kredits = require('../lib/kredits'); - return { - digest: `0x${decoded.slice(2).toString('hex')}`, - hashFunction: decoded[0], - size: decoded[1], - }; +async function prompt(message, options) { + if (!options) { + options = {default: ''} + } + return await promptly.prompt(message, options); } - module.exports = function(callback) { Registry.deployed().then(async (registry) => { - var operatorAddress = await registry.getProxyFor('Operator'); - var contributorsAddress = await registry.getProxyFor('Contributors'); - var operator = await Operator.at(operatorAddress); - var contributors = await Contributors.at(contributorsAddress); - - let contributorToAddAddress = process.argv[4]; - if(!contributorToAddAddress) { - console.log('please provide an address'); - proxess.exit(); + console.log(`Using registry at: ${registry.address}`); + let networkId = parseInt(web3.version.network); + console.log(web3.currentProvider); + let provider = new ethers.providers.Web3Provider( + web3.currentProvider, + { chainId: networkId } + ) + 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); - let proposalMultihash = getBytes32FromMultiash('QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs'); - let proposalResult = await operator.addProposal(contributorId, 23, proposalMultihash.digest, proposalMultihash.hashFunction, proposalMultihash.size); - console.log('Proposal added, tx: ', proposalResult.tx); - - let proposalId = await operator.proposalsCount(); - let votingResult = await operator.vote(proposalId.toNumber()-1); - console.log('Voted for proposal', proposalId.toString(), votingResult.tx); - - callback(); + contributorAttributes = { + account: '0x398ac9cdb122e6f526c8bf8dd80eeeb18fce8821', + name: 'bumi', + isCore: '1' + } + console.log("\nCreating new contributor with following attributes:"); + console.log(contributorAttributes); + kredits.Contributor.functions.addContributor('0x398ac9cdb122e6f526c8bf8dd80eeeb18fce8821', + '0x272bbfc66166f26cae9c9b96b7f9590e095f02edf342ac2dd71e1667a12116ca', 18, 32, true).then((r) => { + 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); + }); + */ }); } diff --git a/scripts/add-proposal.js b/scripts/add-proposal.js index 35a8c55..6dbe117 100644 --- a/scripts/add-proposal.js +++ b/scripts/add-proposal.js @@ -1,8 +1,9 @@ const Registry = artifacts.require('./Registry.sol'); const Operator = artifacts.require('./Operator.sol'); const Contributors = artifacts.require('./Contributors.sol'); +const promptly = require('promptly'); -var bs58 = require('bs58'); +const bs58 = require('bs58'); function getBytes32FromMultiash(multihash) { const decoded = bs58.decode(multihash); @@ -22,12 +23,9 @@ module.exports = function(callback) { var operator = await Operator.at(operatorAddress); var contributors = await Contributors.at(contributorsAddress); - let recipientAddress = process.argv[4]; - if(!recipientAddress) { - console.log('please provide an address'); - process.exit(); - } - let ipfsHash = process.argv[5] || 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs'; + let recipientAddress = await promptly.prompt('Contributor address: '); + let ipfsHash = await promptly.prompt('IPFS hash (blank for default): ', { default: 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs' }); + let multihash = getBytes32FromMultiash(ipfsHash); let contributorId = await contributors.getContributorIdByAddress(recipientAddress); diff --git a/scripts/cli.js b/scripts/cli.js index 20ac150..ca0b005 100644 --- a/scripts/cli.js +++ b/scripts/cli.js @@ -1,17 +1,15 @@ const REPL = require('repl'); +const promptly = require('promptly'); module.exports = function(callback) { const Registry = artifacts.require('./Registry.sol'); Registry.deployed().then(async (registry) => { - let contractName = process.argv[4]; - let method = process.argv[5]; - let args = process.argv.slice(6); - - if (!contractName) { - console.log("Usage:"); - console.log(" truffle exec scripts/cli.js [ ]"); - callback(); - return; + let contractName = await promptly.prompt('Contract Name: '); + let method = await promptly.prompt('Function: '); + let argumentInput = await promptly.prompt('Arguments (comma separated): ', { default: '' }); + let args = []; + if (argumentInput !== '') { + args = argumentInput.split(',').map(a => a.trim()); } let contractAddress = await registry.getProxyFor(contractName); diff --git a/scripts/multihash.js b/scripts/multihash.js index bf59b2f..e80719c 100644 --- a/scripts/multihash.js +++ b/scripts/multihash.js @@ -1,4 +1,4 @@ -var bs58 = require('bs58'); +const bs58 = require('bs58'); function getBytes32FromMultiash(multihash) { const decoded = bs58.decode(multihash); diff --git a/scripts/send-funds.js b/scripts/send-funds.js index 262e286..eff869a 100644 --- a/scripts/send-funds.js +++ b/scripts/send-funds.js @@ -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); callback();