From 3ad9835f7996299e8e0e6633d8a04d43e04cb2b8 Mon Sep 17 00:00:00 2001 From: bumi Date: Thu, 19 Apr 2018 15:02:40 +0200 Subject: [PATCH 01/11] Add kovan deployment --- lib/addresses/Contributors.json | 2 +- lib/addresses/Operator.json | 2 +- lib/addresses/Registry.json | 2 +- lib/addresses/Token.json | 2 +- truffle.js | 5 +++++ 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/addresses/Contributors.json b/lib/addresses/Contributors.json index 2ccea3a..7c8cb62 100644 --- a/lib/addresses/Contributors.json +++ b/lib/addresses/Contributors.json @@ -1 +1 @@ -{"100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"} \ No newline at end of file +{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"} \ No newline at end of file diff --git a/lib/addresses/Operator.json b/lib/addresses/Operator.json index 0ef267e..b865526 100644 --- a/lib/addresses/Operator.json +++ b/lib/addresses/Operator.json @@ -1 +1 @@ -{"100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"} \ No newline at end of file +{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"} \ No newline at end of file diff --git a/lib/addresses/Registry.json b/lib/addresses/Registry.json index 8a5492a..8bdcb57 100644 --- a/lib/addresses/Registry.json +++ b/lib/addresses/Registry.json @@ -1 +1 @@ -{"100":"0x513f8e80a8fbb9fa188320ecf231efcf2f6da9c5"} \ No newline at end of file +{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x513f8e80a8fbb9fa188320ecf231efcf2f6da9c5"} \ No newline at end of file diff --git a/lib/addresses/Token.json b/lib/addresses/Token.json index 658df01..9242b73 100644 --- a/lib/addresses/Token.json +++ b/lib/addresses/Token.json @@ -1 +1 @@ -{"100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"} \ No newline at end of file +{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"} \ No newline at end of file diff --git a/truffle.js b/truffle.js index f591088..77e88c5 100644 --- a/truffle.js +++ b/truffle.js @@ -5,6 +5,11 @@ module.exports = { host: "127.0.0.1", port: 7545, network_id: "*" // Match any network id + }, + kovan: { + host: "127.0.0.1", + port: 8545, + network_id: "42" } } }; From 7f56e1163a2f2d4718214964fbb35b059eac07f1 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 19 Apr 2018 15:23:15 +0200 Subject: [PATCH 02/11] Add accounts to contributor serialization --- lib/serializers/contributor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/serializers/contributor.js b/lib/serializers/contributor.js index 985641d..d426370 100644 --- a/lib/serializers/contributor.js +++ b/lib/serializers/contributor.js @@ -35,6 +35,7 @@ class Contributor { name, kind, url, + accounts, github_uid, github_username, wiki_username, From b6bc5af7bf4c9b7aded6a032bd7acb0bd57e475d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 19 Apr 2018 15:39:00 +0200 Subject: [PATCH 03/11] Serialize details in contributions --- lib/serializers/contribution.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/serializers/contribution.js b/lib/serializers/contribution.js index e57365c..149b077 100644 --- a/lib/serializers/contribution.js +++ b/lib/serializers/contribution.js @@ -41,6 +41,7 @@ class Contribution { kind, description, url, + details } = deserialized; let data = { @@ -51,7 +52,7 @@ class Contribution { }, kind, description, - "details": {} + "details": details || {} }; if (url) { From fbd15953abc095ec04a71924bc3fccb2a74b2b81 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Fri, 20 Apr 2018 00:16:14 +0200 Subject: [PATCH 04/11] Rename contributorAttr address -> account --- lib/contracts/contributor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/contracts/contributor.js b/lib/contracts/contributor.js index 127e2dc..94d4921 100644 --- a/lib/contracts/contributor.js +++ b/lib/contracts/contributor.js @@ -42,7 +42,7 @@ class Contributor extends Base { .add(json) .then((ipfsHashAttr) => { let contributor = [ - contributorAttr.address, + contributorAttr.account, ipfsHashAttr.hashDigest, ipfsHashAttr.hashFunction, ipfsHashAttr.hashSize, From fba767cd40ce26c59034a2d7fc58e1d589a91e12 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Fri, 20 Apr 2018 00:18:06 +0200 Subject: [PATCH 05/11] Only create only registry addresses --- scripts/build-json.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/build-json.js b/scripts/build-json.js index 2a426e5..3bc2855 100644 --- a/scripts/build-json.js +++ b/scripts/build-json.js @@ -18,14 +18,15 @@ files.forEach((fileName) => { let abiFile = path.join(abisPath, `${fileName}.json`); fs.writeFileSync(abiFile, JSON.stringify(file.abi)); - let addresseFile = path.join(addressesPath, `${fileName}.json`); - let addresses = Object.keys(file.networks) - .reduce((addresses, key) => { - addresses[key] = file.networks[key].address; - return addresses; - }, {}); - fs.writeFileSync(addresseFile, JSON.stringify(addresses)); - + if (fileName === 'Registry') { + let addresseFile = path.join(addressesPath, `${fileName}.json`); + let addresses = Object.keys(file.networks) + .reduce((addresses, key) => { + addresses[key] = file.networks[key].address; + return addresses; + }, {}); + fs.writeFileSync(addresseFile, JSON.stringify(addresses)); + } }); console.log("Don't forget to reaload the JSON files from your application; i.e. restart kredits-web"); From 9669f0137ba7cc70bd3fadd47ee926c214882779 Mon Sep 17 00:00:00 2001 From: bumi Date: Thu, 19 Apr 2018 15:59:40 +0200 Subject: [PATCH 06/11] Use prompt instead of argv arguments in scripts This makes it easier to handle truffle arguments which we for example need to specify the network. So we ask the user for input instead on using the argv array which might change. --- package-lock.json | 19 +++++++++++++++++++ package.json | 1 + scripts/add-contributor.js | 12 +++++------- scripts/add-proposal.js | 12 +++++------- scripts/cli.js | 16 +++++++--------- scripts/multihash.js | 2 +- scripts/send-funds.js | 16 ++++++++-------- 7 files changed, 46 insertions(+), 32 deletions(-) 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..2636c2a 100644 --- a/scripts/add-contributor.js +++ b/scripts/add-contributor.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 contributorToAddAddress = process.argv[4]; - if(!contributorToAddAddress) { - console.log('please provide an address'); - proxess.exit(); - } - let ipfsHash = process.argv[5] || 'QmQyZJT9uikzDYTZLhhyVZ5ReZVCoMucYzyvDokDJsijhj'; + let contributorToAddAddress = await promptly.prompt('Contributor address: '); + let ipfsHash = await promptly.prompt('IPFS hash (blank for default): ', { default: 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs' }); + let contributorMultihash = getBytes32FromMultiash(ipfsHash); let isCore = true; let contributorResult = await contributors.addContributor(contributorToAddAddress, contributorMultihash.digest, contributorMultihash.hashFunction, contributorMultihash.size, isCore); 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(); From 6738abd0b3e0cfec231f025d2cd091bd4bfec4fa Mon Sep 17 00:00:00 2001 From: bumi Date: Fri, 20 Apr 2018 02:09:30 +0200 Subject: [PATCH 07/11] Add support for contract tx call options This allows to provide options like gas price/limit settings for the state changing contract calls. These options are simply passed to the ethers contract instance. We need to provide the gas limit when using the jsonrpc provider. (ganache failed with revert if not enought gas was provider) --- lib/contracts/contributor.js | 4 ++-- lib/contracts/operator.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/contracts/contributor.js b/lib/contracts/contributor.js index 94d4921..1845730 100644 --- a/lib/contracts/contributor.js +++ b/lib/contracts/contributor.js @@ -34,7 +34,7 @@ class Contributor extends Base { }); } - add(contributorAttr) { + add(contributorAttr, callOptions = {}) { let json = ContributorSerializer.serialize(contributorAttr); // TODO: validate against schema @@ -49,7 +49,7 @@ class Contributor extends Base { contributorAttr.isCore, ]; - return this.functions.addContributor(...contributor); + return this.functions.addContributor(...contributor, callOptions); }); } } diff --git a/lib/contracts/operator.js b/lib/contracts/operator.js index bcb31b8..83a5eae 100644 --- a/lib/contracts/operator.js +++ b/lib/contracts/operator.js @@ -34,7 +34,7 @@ class Operator extends Base { }); } - addProposal(proposalAttr) { + addProposal(proposalAttr, callOptions = {}) { let json = ContributionSerializer.serialize(proposalAttr); // TODO: validate against schema @@ -49,7 +49,7 @@ class Operator extends Base { ipfsHashAttr.hashSize, ]; - return this.functions.addProposal(...proposal); + return this.functions.addProposal(...proposal, callOptions); }); } } From 3da3e22214cd9b1ad603229281b8472fee8db17e Mon Sep 17 00:00:00 2001 From: bumi Date: Fri, 20 Apr 2018 03:08:18 +0200 Subject: [PATCH 08/11] Refactor kredits address initialization This moves the Kredits initialization to the instance which allows us to be more flexible with handling contract addresses. Example: var k = new Kredits(provider, signer, {Registry: '0xabc'}); k.init().then((kredits) { ...}); var k = new Kredits(provider, signer, {Contributors: '0xabc'}) k.Contributor.add(...); --- lib/contracts/index.js | 5 ++- lib/contracts/registry.js | 6 +++ lib/kredits.js | 89 +++++++++++++++++---------------------- 3 files changed, 47 insertions(+), 53 deletions(-) create mode 100644 lib/contracts/registry.js diff --git a/lib/contracts/index.js b/lib/contracts/index.js index 9fd06ae..a4a1792 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..a3af768 --- /dev/null +++ b/lib/contracts/registry.js @@ -0,0 +1,6 @@ +const Base = require('./base'); + +class Registry extends Base { +} + +module.exports = Registry; diff --git a/lib/kredits.js b/lib/kredits.js index 8182137..8cb0075 100644 --- a/lib/kredits.js +++ b/lib/kredits.js @@ -1,17 +1,15 @@ 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 = { - Registry: require('./addresses/Registry.json') -}; +const RegistryAddress = require('./addresses/Registry.json'); -const contracts = require('./contracts'); +const Contracts = require('./contracts'); const IPFS = require('./utils/ipfs') // Helpers @@ -22,64 +20,52 @@ function capitalize(word) { class Kredits { static get contractNames() { - return Object.keys(abis); + return Object.keys(ABIS); } constructor(provider, signer, addresses) { this.provider = provider; this.signer = signer; - // Initialize our registry contract - this.addresses = addresses; + // by default we only need the registry address. + // the rest is loaded from there in the init() function + this.addresses = addresses || {Registry: RegistryAddress[this.provider.chainId.toString()]}; // chaiID must be a string + this.abis = ABIS; this.contracts = {}; this.ipfs = new IPFS(); } - static setup(provider, signer, ipfsConfig = null) { - let ipfsAPI = new IPFS(ipfsConfig); + 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.contract.address} + - correct registry? does it have version entry? - ${error.message}` + ); + }); + }); + return RSVP.all(addressPromises).then(() => { return this }); + } - return ipfsAPI._ipfsAPI.id().catch((error) => { + static setup(provider, signer, ipfsConfig = null) { + console.log('Kredits.setup() is deprecated use new Kredits().init() instead'); + let ipfs = new IPFS(ipfsConfig); + + return ipfs._ipfsAPI.id().catch((error) => { throw new Error(`IPFS node not available; config: ${JSON.stringify(ipfsConfig)} - ${error.message}`); }).then(() => { - let registryContract = this.initRegistryContract(provider); - - let addresses = Kredits.contractNames.reduce((mem, name) => { - let contractName = capitalize(name); - mem[contractName] = registryContract.functions.getProxyFor(contractName).catch((error) => { - throw new Error(`Failed to get address for ${contractName} from registry at ${registryContract.address} - - correct registry? does it have version entry? - ${error.message}` - ); - }); - return mem; - }, {}); - - return RSVP.hash(addresses) - .then((addresses) => { - let kredits = new Kredits(provider, signer, addresses); - kredits.ipfs = ipfsAPI; - return kredits; - }); + return new Kredits(provider, signer).init().then((kredits) => { + kredits.ipfs = ipfs; + return kredits; + }); }); } - static initRegistryContract(provider) { - 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'])} - `); - } - provider.getCode(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 ${address} on network ${provider.chainId}`); - } - }); - let abi = abis['Registry']; - return new ethers.Contract(address, abi, provider); + get Registry() { + return this.contractFor('registry'); } get Contributor() { @@ -101,13 +87,14 @@ class Kredits { return this.contracts[name]; } - let contractName = capitalize(name); - let address = this.addresses[contractName]; - if (!address || !abis[contractName]) { + const contractName = capitalize(name); + const address = this.addresses[contractName]; + const 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); - this.contracts[name] = new contracts[contractName](contract); + let contract = new ethers.Contract(address, abi, this.signer); + this.contracts[name] = new Contracts[contractName](contract); this.contracts[name].ipfs = this.ipfs; return this.contracts[name]; From 2503ac7c73774ae97d8629294732ac7b2f4feee2 Mon Sep 17 00:00:00 2001 From: bumi Date: Fri, 20 Apr 2018 12:56:09 +0200 Subject: [PATCH 09/11] Refactor helper scripts to use kredits module This reuses the kredits library functions in the helper scripts and seeds. We no longer need to add IPFS hashes manually but simply can provider contributor/proposal data. --- config/seeds.js | 74 +++++--------------------------------- package-lock.json | 16 ++++++--- package.json | 3 +- scripts/add-contributor.js | 61 ++++++++++++++++--------------- scripts/cli.js | 20 +++++++---- scripts/multihash.js | 35 ------------------ scripts/seeds.js | 51 ++++++++++++++------------ 7 files changed, 98 insertions(+), 162 deletions(-) delete mode 100644 scripts/multihash.js diff --git a/config/seeds.js b/config/seeds.js index ae3403a..d8b84e5 100644 --- a/config/seeds.js +++ b/config/seeds.js @@ -1,65 +1,9 @@ -let contractCalls = { - Contributors: { - addContributor: [ - // make sure to use an IPFS hash of one of the objects in ipfsContent - ['0x24dd2aedd8a9fe52ac071b3a23b2fc8f225c185e', '0x272bbfc66166f26cae9c9b96b7f9590e095f02edf342ac2dd71e1667a12116ca', 18, 32, true], // QmQyZJT9uikzDYTZLhhyVZ5ReZVCoMucYzyvDokDJsijhj - ['0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', '0x9569ed44826286597982e40bbdff919c6b7752e29d13250efca452644e6b4b25', 18, 32, true] // QmYPu8zvtfDy18ZqHCviVxnKtxycw5UTJLJyk9oAEjWfnL - ] - }, - Operator: { - addProposal: [ - [2, 23, '0x1e1a168d736fc825213144973a8fd5b3cc9f37ad821a8b3d9c3488034bbf69d8', 18, 32], // QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs" - [3, 42, '0x1e1a168d736fc825213144973a8fd5b3cc9f37ad821a8b3d9c3488034bbf69d8', 18, 32], // QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs" - [3, 100, '0x1e1a168d736fc825213144973a8fd5b3cc9f37ad821a8b3d9c3488034bbf69d8', 18, 32] // QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs" - ], - vote: [ - [1] - ] - } -}; -let ipfsContent = [ - { - "@context": "https://schema.kosmos.org", - "@type": "Contributor", - "kind": "person", - "name": "Râu Cao", - "url": "https://sebastian.kip.pe", - "accounts": [ - { - "site": "github.com", - "username": "skddc", - "uid": 842, - "url": "https://github.com/skddc/" - }, - ] - }, - { - "@context": "https://schema.kosmos.org", - "@type": "Contributor", - "kind": "person", - "name": "Bumi", - "url": "https://michaelbumann.com", - "accounts": [ - { - "site": "github.com", - "username": "bumi", - "uid": 318, - "url": "https://github.com/bumi/" - }, - ] - }, - { - "@context": "https://schema.kosmos.org", - "@type": "Contribution", - "contributor": { - "ipfs": "QmQ2ZZS2bXgneQfKtVTVxe6dV7pcJuXnTeZJQtoVUFsAtJ" - }, - "kind": "dev", - "description": "hacking hacking on kredits", - "url": "https://github.com/67P/kredits-web/pull/11", - "details": {} - } - -] - -module.exports = { contractCalls, ipfsContent }; +let contractCalls = [ + ['Contributor', 'add', [{ account: '0x7e8f313c56f809188313aa274fa67ee58c31515d', name: 'bumi', isCore: true, kind: 'preson', url: '', github_username: 'bumi', github_uid: 318, wiki_username: 'bumi' }, {gasLimit: 200000}]], + ['Contributor', 'add', [{ account: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', name: 'raucau', isCore: true, kind: 'person', url: '', github_username: 'skddc', github_uid: 842, wiki_username: 'raucau' }, {gasLimit: 200000}]], + ['Operator', 'addProposal', [{ contributorId: 2, amount: 42, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]], + ['Operator', 'addProposal', [{ contributorId: 3, amount: 23, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]], + ['Operator', 'addProposal', [{contributorId: 3, amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]], + ['Operator', 'vote', ['1', {gasLimit: 250000}]] +]; +module.exports = { contractCalls }; diff --git a/package-lock.json b/package-lock.json index 473e969..070e4e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -106,10 +106,10 @@ "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "async-each-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-1.1.0.tgz", + "integrity": "sha1-9C/YFV048hpbjqB8KOBj7RcAsTg=", "dev": true }, "babel-code-frame": { @@ -5420,6 +5420,14 @@ "recast": "0.12.9", "temp": "0.8.3", "write-file-atomic": "1.3.4" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } } }, "recast": { diff --git a/package.json b/package.json index 9cf8786..36784fd 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "build-json": "truffle compile && node ./scripts/build-json.js", - "bootstrap": "truffle migrate --reset && truffle exec scripts/seeds.js && npm run build-json", + "bootstrap": "truffle migrate --reset && npm run build-json && truffle exec scripts/seeds.js", "ganache": "ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits", "dev": "truffle migrate && npm run build-json", "test": "echo \"Error: no test specified\" && exit 1" @@ -24,6 +24,7 @@ }, "homepage": "https://github.com/67P/truffle-kredits#readme", "devDependencies": { + "async-each-series": "^1.1.0", "ganache-cli": "^6.0.3", "promptly": "^3.0.3", "truffle": "^4.1.3", diff --git a/scripts/add-contributor.js b/scripts/add-contributor.js index 2636c2a..34bb282 100644 --- a/scripts/add-contributor.js +++ b/scripts/add-contributor.js @@ -1,45 +1,50 @@ const Registry = artifacts.require('./Registry.sol'); -const Operator = artifacts.require('./Operator.sol'); -const Contributors = artifacts.require('./Contributors.sol'); const promptly = require('promptly'); - 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); + const networkId = parseInt(web3.version.network); + const provider = new ethers.providers.Web3Provider( + web3.currentProvider, { chainId: networkId } + ); + const kredits = await Kredits.setup(provider, provider.getSigner()); - let contributorToAddAddress = await promptly.prompt('Contributor address: '); - let ipfsHash = await promptly.prompt('IPFS hash (blank for default): ', { default: 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs' }); + console.log(`Using contributors at: ${kredits.Contributor.contract.address}`); - 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 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 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); + console.log("\nAdding contributor:"); + console.log(contributorAttributes); - let proposalId = await operator.proposalsCount(); - let votingResult = await operator.vote(proposalId.toNumber()-1); - console.log('Voted for proposal', proposalId.toString(), votingResult.tx); + kredits.Contributor.add(contributorAttributes, {gasLimit: 250000}).then((result) => { + console.log("\n\nResult:"); + console.log(result); + callback(); + }).catch((error) => { + console.log('Failed to create contributor'); + callback(error); + }); - callback(); }); } diff --git a/scripts/cli.js b/scripts/cli.js index ca0b005..f1c733f 100644 --- a/scripts/cli.js +++ b/scripts/cli.js @@ -1,6 +1,9 @@ const REPL = require('repl'); const promptly = require('promptly'); +const ethers = require('ethers'); +const Kredits = require('../lib/kredits'); + module.exports = function(callback) { const Registry = artifacts.require('./Registry.sol'); Registry.deployed().then(async (registry) => { @@ -12,26 +15,31 @@ module.exports = function(callback) { args = argumentInput.split(',').map(a => a.trim()); } - let contractAddress = await registry.getProxyFor(contractName); - console.log(`Using ${contractName} at ${contractAddress}`); - let contract = await artifacts.require(`./${contractName}`).at(contractAddress); + const networkId = parseInt(web3.version.network); + const provider = new ethers.providers.Web3Provider( + web3.currentProvider, { chainId: networkId } + ); + const kredits = await Kredits.setup(provider, provider.getSigner()); + + const contract = kredits[contractName].contract; + console.log(`Using ${contractName} at ${contract.address}`); + console.log(`Calling ${method} with ${JSON.stringify(args)}`); if (!contract[method]) { callback(new Error(`Method ${method} is not defined on ${contractName}`)); return; } - console.log(`Calling ${method} with ${JSON.stringify(args)}`); contract[method](...args).then((result) => { console.log("\nResult:"); console.log(result); console.log("\nStartig a REPL. (type .exit to exit)"); - console.log(`defined variables: result, ${contractName}, web3`); + console.log(`defined variables: result, ${contractName}, kredis`); let r = REPL.start(); r.context.result = result; r.context[contractName] = contract; - r.context.web3 = web3; + r.context.kredits = kredits; r.on('exit', () => { console.log('Bye'); diff --git a/scripts/multihash.js b/scripts/multihash.js deleted file mode 100644 index e80719c..0000000 --- a/scripts/multihash.js +++ /dev/null @@ -1,35 +0,0 @@ -const bs58 = require('bs58'); - -function getBytes32FromMultiash(multihash) { - const decoded = bs58.decode(multihash); - - return { - digest: `0x${decoded.slice(2).toString('hex')}`, - hashFunction: decoded[0], - size: decoded[1], - }; -} - - -function getMultihashFromBytes32(multihash) { - const { digest, hashFunction, size } = multihash; - if (size === 0) return null; - - // cut off leading "0x" - const hashBytes = Buffer.from(digest.slice(2), 'hex'); - - // prepend hashFunction and digest size - //const multihashBytes = new (hashBytes.constructor)(2 + hashBytes.length); - const multihashBytes = new Buffer(2 + hashBytes.length); - - console.log(hashBytes.constructor); - - multihashBytes[0] = hashFunction; - multihashBytes[1] = size; - multihashBytes.set(hashBytes, 2); - - return bs58.encode(multihashBytes); -} - -var m = getBytes32FromMultiash(process.argv[2]); -console.log(m) diff --git a/scripts/seeds.js b/scripts/seeds.js index 69d79fa..7e9fd9a 100644 --- a/scripts/seeds.js +++ b/scripts/seeds.js @@ -1,34 +1,39 @@ const path = require('path'); const seeds = require(path.join(__dirname, '..', '/config/seeds.js')); -const IPFS = require('ipfs-api'); -var ipfs = IPFS({host: 'localhost', port: '5001', protocol: 'http'}) +const ethers = require('ethers'); +const Kredits = require('../lib/kredits'); + +const each = require('async-each-series'); module.exports = function(callback) { const Registry = artifacts.require('./Registry.sol'); - const contracts = {}; - Registry.deployed().then((registry) => { - Object.keys(seeds.contractCalls).forEach(async (contract) => { - var address = await registry.getProxyFor(contract); - console.log(`Using ${contract} at ${address}`); - contracts[contract] = await artifacts.require(contract).at(address); + Registry.deployed().then(async (registry) => { - Object.keys(seeds.contractCalls[contract]).forEach((method) => { - seeds.contractCalls[contract][method].forEach((args) => { - console.log(`[Sending] ${contract}.#${method}(${JSON.stringify(args)})`); - contracts[contract][method](...args).then((result) => { - console.log(`[Result] ${contract}.${method}(${JSON.stringify(args)}) => ${result.tx}`); - }); - }); + const networkId = parseInt(web3.version.network); + const provider = new ethers.providers.Web3Provider( + web3.currentProvider, { chainId: networkId } + ); + const kredits = await Kredits.setup(provider, provider.getSigner()); + + each(seeds.contractCalls, (call, next) => { + let [contractName, method, args] = call; + let contractWrapper = kredits[contractName]; + let func; + if (contractWrapper[method]) { + func = contractWrapper[method]; + } else { + func = contractWrapper.functions[method]; + } + func.apply(contractWrapper, args).then((result) => { + console.log(`[OK] kredits.${contractName}.${method}(${JSON.stringify(args)}) => ${result.hash}`); + next(); + }).catch((error) => { + console.log(`[FAILD] kredits.${contractName}.${method}(${JSON.stringify(args)})`); + callback(error) }); - }); + }, () => { console.log("\nDone!") }); + }); - - - seeds.ipfsContent.forEach((content) => { - ipfs.add(new ipfs.Buffer(JSON.stringify(content))).then((result) => { console.log(`[IPFS] added ${result[0].hash}`) }); - }); - - callback(); } From 92f3963c5aff73af70a4d14866e7b6216a8ed8ef Mon Sep 17 00:00:00 2001 From: bumi Date: Fri, 20 Apr 2018 13:01:44 +0200 Subject: [PATCH 10/11] Remove not needed static contractNames function --- lib/kredits.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/kredits.js b/lib/kredits.js index 8cb0075..f4a065d 100644 --- a/lib/kredits.js +++ b/lib/kredits.js @@ -19,9 +19,6 @@ function capitalize(word) { } class Kredits { - static get contractNames() { - return Object.keys(ABIS); - } constructor(provider, signer, addresses) { this.provider = provider; @@ -36,7 +33,7 @@ class Kredits { } init(names) { - let contractsToLoad = names || Kredits.contractNames; + let contractsToLoad = names || Object.keys(ABIS); let addressPromises = contractsToLoad.map((contractName) => { return this.Registry.functions.getProxyFor(contractName).then((address) => { this.addresses[contractName] = address; From 6ca23de343efbcd4fa359a16ff3401632c4e4819 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Sat, 21 Apr 2018 10:44:09 +0200 Subject: [PATCH 11/11] Lock ethers.js at 3.0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36784fd..84ad412 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "zeppelin-solidity": "^1.7.0" }, "dependencies": { - "ethers": "^3.0.15", + "ethers": "3.0.15", "ipfs-api": "^19.0.0", "rsvp": "^4.8.2" }