diff --git a/contracts/KreditsKit.sol b/contracts/KreditsKit.sol index 3e82052..19fe2b8 100644 --- a/contracts/KreditsKit.sol +++ b/contracts/KreditsKit.sol @@ -34,20 +34,20 @@ contract KreditsKit is KitBase { Contributor contributor = Contributor(_installApp(dao, appIds[uint8(Apps.Contributor)])); contributor.initialize(root, appIds); acl.createPermission(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), this); - + Token token = Token(_installApp(dao, appIds[uint8(Apps.Token)])); token.initialize(appIds); - + Contribution contribution = Contribution(_installApp(dao, appIds[uint8(Apps.Contribution)])); contribution.initialize(appIds); - + Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)])); proposal.initialize(appIds); acl.createPermission(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), this); acl.createPermission(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), this); acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE()); - + uint256[] memory params = new uint256[](1); params[0] = uint256(203) << 248 | uint256(1) << 240 | uint240(contributor); acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.ADD_CONTRIBUTION_ROLE(), params); @@ -57,7 +57,7 @@ contract KreditsKit is KitBase { //acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE(); acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this); acl.grantPermissionP(acl.ANY_ENTITY(), proposal, proposal.VOTE_PROPOSAL_ROLE(), params); - + acl.createPermission(root, proposal, proposal.ADD_PROPOSAL_ROLE(), this); //acl.grantPermissionP(address(-1), proposal, proposal.ADD_PROPOSAL_ROLE(), params); acl.grantPermission(acl.ANY_ENTITY(), proposal, proposal.ADD_PROPOSAL_ROLE()); @@ -67,9 +67,9 @@ contract KreditsKit is KitBase { acl.setPermissionManager(root, contribution, contribution.ADD_CONTRIBUTION_ROLE()); acl.setPermissionManager(root, contribution, contribution.VETO_CONTRIBUTION_ROLE()); acl.setPermissionManager(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE()); - + acl.createPermission(root, token, token.MINT_TOKEN_ROLE(), this); - acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE()); + acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE()); acl.setPermissionManager(root, token, token.MINT_TOKEN_ROLE()); diff --git a/lib/abis/KreditsKit.json b/lib/abis/KreditsKit.json new file mode 100644 index 0000000..8202592 --- /dev/null +++ b/lib/abis/KreditsKit.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"ens","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fac","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"appId","type":"bytes32"}],"name":"latestVersionAppBase","outputs":[{"name":"base","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"appIds","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_fac","type":"address"},{"name":"_ens","type":"address"},{"name":"_appIds","type":"bytes32[4]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"dao","type":"address"}],"name":"DeployInstance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"dao","type":"address"},{"indexed":false,"name":"appProxy","type":"address"},{"indexed":false,"name":"appId","type":"bytes32"}],"name":"InstalledApp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"appProxy","type":"address"},{"indexed":false,"name":"appId","type":"bytes32"}],"name":"InstalledApp","type":"event"},{"constant":false,"inputs":[],"name":"newInstance","outputs":[{"name":"dao","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/contracts/base.js b/lib/contracts/base.js index 8d9d189..9cbcb7a 100644 --- a/lib/contracts/base.js +++ b/lib/contracts/base.js @@ -7,6 +7,10 @@ class Base { return this.contract.functions; } + get address () { + return this.contract.address; + } + get ipfs () { if (!this._ipfsAPI) { throw new Error('IPFS API not configured; please set an ipfs instance'); } return this._ipfsAPI; diff --git a/lib/kreditskit.js b/lib/kreditskit.js new file mode 100644 index 0000000..bc08763 --- /dev/null +++ b/lib/kreditskit.js @@ -0,0 +1,49 @@ +const ethers = require('ethers'); + +const ABI = require('./abis/KreditsKit.json'); +const Addresses = require('./addresses/KreditsKit.json'); + +class KreditsKit { + + constructor (provider, signer, options = {}) { + let { address, abi } = options; + + this.provider = provider; + this.signer = signer; + this.options = options; + this.address = address; + this.abi = abi || ABI; + } + + init () { + return this.provider.getNetwork().then((network) => { + this.address = this.address || Addresses[network.chainId.toString()]; + this.contract = new ethers.Contract( + this.address, + this.abi, + (this.signer || this.provider) + ); + return this; + }); + } + + appIdFor (contractName) { + // see appIds in KreditsKit.sol for more details + const knownContracts = ['Contribution', 'Contributor', 'Proposal', 'Token']; + return this.contract.functions.appIds(knownContracts.indexOf(contractName)); + } + + newDAO (options = {}) { + return this.contract.functions.newInstance(options).then(transaction => { + return transaction.wait().then(result => { + const deployEvent = result.events.find(e => e.event === 'DeployInstance'); + return { + daoAddress: deployEvent.args.dao, + transactionHash: transaction.hash, + }; + }); + }); + } +} + +module.exports = KreditsKit; diff --git a/scripts/new-dao.js b/scripts/new-dao.js index 4694c48..8601034 100644 --- a/scripts/new-dao.js +++ b/scripts/new-dao.js @@ -1,13 +1,13 @@ const fs = require('fs'); const path = require('path'); +const ethers = require('ethers'); const fileInject = require('./helpers/file_inject.js'); const getNetworkId = require('./helpers/networkid.js'); +const KreditsKit = require('../lib/kreditskit'); const addressesPath = path.join(__dirname, '..', 'lib/addresses'); -const KreditsKit = artifacts.require('KreditsKit') - module.exports = async function(callback) { const networkId = await getNetworkId(web3) console.log(`Deploying to networkId: ${networkId}`) @@ -20,25 +20,21 @@ module.exports = async function(callback) { } console.log(`Using KreditsKit at: ${kreditsKitAddress}`); - let kreditsKit = KreditsKit.at(kreditsKitAddress) + const provider = new ethers.providers.Web3Provider(web3.currentProvider); + let signer = provider.getSigner(); - kreditsKit.newInstance().then((ret) => { - console.log(ret.logs); - const installedEvents = ret.logs.filter(log => log.event === 'InstalledApp').map(log => log.args) - const deployEvents = ret.logs.filter(log => log.event === 'DeployInstance').map(log => log.args) + let kit = await new KreditsKit(provider, signer).init() - if (deployEvents.length > 1) { - callback(new Error("More than one DAO was deployed. Something is wrong")) - } - const daoAddress = deployEvents[0].dao; + // TODO: get rid of the hard coded gas limit + kit.newDAO({ gasLimit: 10000000 }).then(result => { + console.log(result); + fileInject(path.join(addressesPath, 'dao.json'), networkId, result.daoAddress) - fileInject(path.join(addressesPath, 'dao.json'), networkId, daoAddress) - - console.log(`\n\nCreated new DAO at: ${daoAddress}`) + console.log(`\n\nCreated new DAO at: ${result.daoAddress}`) callback(); }).catch((err) => { - console.log('failed to create a new instance') + console.log('failed to create a new DAO') callback(err) }) }