Compare commits

..

76 Commits

Author SHA1 Message Date
8b7e2da8af Merge pull request 'Export data' (#229) from legacy-export into legacy
Reviewed-on: #229
2022-11-02 16:58:38 +00:00
38893937ec Add export data from contributions and contributors 2022-10-07 18:49:39 +02:00
f17af2d0ae export scripts without truffle dependency 2022-10-07 18:48:17 +02:00
Râu Cao
1cfeaec70b Also export vetoed contributions 2022-08-23 09:50:05 +01:00
Râu Cao
44f3128f16 Add export scripts 2022-08-23 09:27:42 +01:00
c865c154a4 Merge pull request #198 from 67P/feature/expenses
Add Reimbursement app
2021-06-02 14:25:33 +02:00
a63a37c5d6 Merge pull request #212 from 67P/chore/nvmrc
Add .nvmrc
2021-05-31 11:41:45 +02:00
20879c4c08 Add .nvmrc
Configures node version to what we currently recommend/require.
2021-05-31 10:07:44 +02:00
7ab8e4e52d Merge pull request #211 from 67P/feature/find_block_by_date
Add script for finding block closest to given date
2021-05-29 16:59:38 +02:00
f11c4f7764 Add script for finding block closest to given date
Useful for manual grant cycle management.
2021-05-20 15:09:56 +02:00
44cad2d26e Fix contributorId being used in a reimbursement seed 2021-02-22 15:32:43 +01:00
357698db02 Deployment details 2021-02-19 10:24:54 +01:00
6c80179a3d Re-add veto auth
Accidentally merged during pairing with some minor changes in #210
2021-01-14 15:46:33 +01:00
c471060cfd Merge pull request #210 from 67P/chore/variable_naming
Improve variable name clarity
2021-01-14 15:43:26 +01:00
7418d33e63 Merge pull request #209 from 67P/bugfix/confirmed_at
Fix confirmations being 1 block too late
2021-01-14 15:43:07 +01:00
1cfbc09e4a Merge pull request #208 from 67P/feature/count-contributions
Add script to count contributions between a certain block timeframe
2021-01-14 15:41:41 +01:00
8984ba3802 Improve variable name clarity 2021-01-14 15:39:19 +01:00
2238ccf40e Fix confirmations being 1 block too late
block.number refers to the last mined block, so we need to add +1 to
wait from the current block on (the one in which this function is
executed).
2021-01-14 15:36:55 +01:00
0df7930e06 Get it running 2020-12-22 12:28:34 +01:00
eebc0db02b Add script to count contributions between a certain block timeframe 2020-12-16 17:19:31 +01:00
b22d16e61e We do not need the appIds in the reimbursement app
this might make it easier to deploy?
2020-12-01 13:27:39 +01:00
6bc6bcb7f6 We don't use those helpers right now. but maybe later? 2020-12-01 12:54:28 +01:00
9df58b7f9a Fix seeds 2020-12-01 12:51:33 +01:00
c83a560e3b merge master 2020-12-01 10:39:01 +01:00
eadca6904a Rename contributor to recipient
And remove addedBy entry.
2020-12-01 10:33:09 +01:00
89829ee81f Merge pull request #207 from 67P/docs/update_readme
Lock node.js to 12 on CI, add note for devs to README
2020-11-18 19:09:19 +01:00
32b212f9cf Use legacy node.js in CI
Courtesy of aragon CLI.
2020-11-18 17:31:10 +01:00
e3c03bf4a0 Update README
Add note about having to use node.js 12 for now.
2020-11-17 12:30:09 +01:00
7dba0e4501 Add missing permission assignment
Fixes reimbursement transaction failures.

Co-authored-by: Michael Bumann <hello@michaelbumann.com>
2020-10-20 10:44:29 +02:00
e6349f0594 Some minor improvements of ExpenseSerializer 2020-10-01 16:12:13 +02:00
15b47dbc42 Improve Reimbursement.add validation 2020-10-01 12:15:48 +02:00
8f0d7e5196 6.0.0 2020-07-17 13:22:59 +02:00
4add0c7d96 package-lock 2020-07-17 13:22:24 +02:00
7ad2515b67 Improve seeds 2020-07-10 00:07:06 +02:00
fbd82a442e Merge pull request #200 from 67P/ethers5
Update to ethers 5
2020-07-07 16:59:40 +02:00
c39fe406d0 Fix deprecation 2020-06-29 23:49:46 +02:00
a609d921aa Remove accidentally added local DAO addresses 2020-06-29 23:49:03 +02:00
23d3dd3a80 Adjust API for new ethers v5 API
see issue for details: https://github.com/ethers-io/ethers.js/issues/920#issuecomment-650836642
2020-06-29 17:23:08 +02:00
c63fcc002b Use new schemas release 2020-06-28 00:47:24 +02:00
bc38dcb136 Copy contract data into new object to avoid object is not extensible error
It seems the new ethers.js version returns contract data as a non-
extensible object. We have to clone it before adding the IPFS data.
2020-06-27 20:39:23 +02:00
c4e7e1259e Remove obsolete manual expense schema import 2020-06-27 16:27:11 +02:00
17cc44cb98 Use unreleased kosmos schemas fix 2020-06-27 16:23:15 +02:00
c2dcedfe58 Update to ethers 5 2020-06-24 01:20:04 +02:00
2c567fa71a Use contributorId instead or address for reimbursements 2020-06-12 00:29:59 +02:00
9b4a95f375 use const for not reassigned variable 2020-05-30 14:02:50 +02:00
687f87f43b cleanup address files 2020-05-30 14:02:29 +02:00
7fdeb78617 Support multiple expenses in one reimburesement 2020-05-29 18:47:49 +02:00
19f212f283 Cleanup
we do not support claiming/withdrawal yet.
2020-05-29 17:25:27 +02:00
1f248812a7 Reimbursement.getReimbursement vs. Reimbursement.get 2020-05-29 15:12:57 +02:00
3f8407fa02 Update apps/reimbursement/contracts/Reimbursement.sol
Co-authored-by: Sebastian Kippe <sebastian@kip.pe>
2020-05-29 11:31:51 +02:00
a0b0183beb Add Reimbursement app 2020-05-29 10:46:55 +02:00
2b99593699 Merge pull request #196 from 67P/chore/dependency-updates
Chore/dependency updates
2020-05-27 16:22:40 +02:00
606350eb5e Update solc
our contracts still use an older version, but I guess it is good to have
the latest solc package
2020-05-27 10:53:31 +02:00
a330a8eedf npm upgrade 2020-05-27 10:46:41 +02:00
3c72fa3a8b run npm upgrade in every app
are those package-lock.json there actually used?
2020-05-27 10:31:12 +02:00
a4ef2398be update dependencies 2020-05-27 10:06:06 +02:00
31c29ab6d0 Merge pull request #194 from 67P/updates
Some required dependency updates
2020-05-07 10:08:26 +02:00
ef0c0c0a39 (ci) Disable all tests 2020-05-07 09:59:27 +02:00
844bdbd681 (ci) Disable token tests
They are failing in different ways both locally and on Travis.
2020-05-07 09:51:26 +02:00
9d96824fe9 (ci) Wait a little for the devchain to start up 2020-05-07 09:41:11 +02:00
d246531cfa Update package lockfile 2020-05-07 09:40:58 +02:00
6be06b2e57 Merge branch 'master' into updates 2020-05-07 09:30:29 +02:00
c2220c3654 Fix ESLint error 2020-05-07 09:27:15 +02:00
5044d8fe41 fix syntax error 2020-04-15 20:44:13 +02:00
3c49c688d2 Add missing dev dependencies and update dependencies 2020-04-15 20:43:46 +02:00
47f59126a7 5.5.0 2020-03-01 12:46:22 +01:00
2ce5d925d0 Merge pull request #182 from 67P/chore/update_dependencies
WIP: Fix Aragon breaking changes; update dependencies
2020-02-20 11:42:04 +00:00
3db89b0fa3 Refactor kredits related configuration in arapp.json
we use an environment specific entry for the daoAddress.
Locally we deploy our own, but for rinkeby and other public networks
we use the official entries.
To make deployments easy we store the address in the arapp.json
2020-02-10 15:55:16 +01:00
190d3b77d5 Update tests
getContract now seems to return a Promise
2020-02-10 14:59:22 +01:00
b7eac4202c Adjust deploy script and readme for updates 2020-02-10 14:30:03 +01:00
93aeea69c6 Fix test commands
Aragon CLI does not come with the contracts command anymore.
2020-02-08 17:37:26 -05:00
e7700d5ec7 Remove @aragon/cli from app package configs
We're assuming a global install now.
2020-02-08 17:36:48 -05:00
c3eced5c1d Remove apm app config keys 2020-02-08 17:19:39 -05:00
4c6ed12167 Re-add fixed package lock 2020-02-08 16:41:08 -05:00
9431bc22a6 Re-add package lock fix script
m(
2020-02-08 16:36:29 -05:00
78c8052629 Update dependencies
Dance the update dance with me.
2020-02-08 16:28:13 -05:00
78 changed files with 50309 additions and 99708 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
data
build
flattened_contracts
node_modules

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
12

View File

@@ -1,7 +1,7 @@
---
language: node_js
node_js:
- "lts/*"
- "12"
sudo: false
dist: xenial
@@ -22,11 +22,16 @@ install:
before_script:
- npm run devchain &
- sleep 10
script:
- npm run lint:wrapper
- npm run lint:contract-tests
- npm run test
# FIXME Fix tests
# - npm run test:token
# - npm run test:contributor
# - npm run test:contribution
# - npm run test:proposal
branches:
only:

View File

@@ -34,6 +34,9 @@ Aragon CLI and Truffle need to be installed on your sytem as well:
npm install -g @aragon/cli
npm install -g truffle
_Note: `@aragon/cli` currently fails to install on node.js 14. Please use
node.js 12 until the issue has been resolved upstream._
### Local development chain
For local development it is recommended to use
@@ -63,21 +66,26 @@ if you want to increase the block time to 10 seconds you can add
$ npm run devchain
$ ipfs daemon
2. Deploy each app to the devchain
2. Compile contracts
(compiled contracts will be in `/build`)
$ npm run compile-contracts
3. Deploy each app to the devchain
(make sure you've run `npm install` for every app - see installation)
$ npm run deploy:apps
3. Deploy a new KreditsKit and create a new DAO with the latest app versions
4. Deploy a new KreditsKit and create a new DAO with the latest app versions
$ npm run deploy:kit
$ npm run deploy:dao
4. Execute seeds to create demo contributors, contributions, etc. (optional)
5. Execute seeds to create demo contributors, contributions, etc. (optional)
$ npm run seeds
**Step 2-4 is also summarized in `npm run bootstrap`**
**Step 2-5 is also summarized in `npm run bootstrap`**
If you want to reset your local setup:
@@ -165,8 +173,14 @@ Deploys a new KreditsKit that allows to create a new DAO
or
$ npm run deploy:kit
`ENS` address is required as environment variable.
`DAO_FACTORY` can optionally be set as environment variable. (see aragon)
#### Kredits configuration options:
Configuration options can be set in an environment specific `kredits` object in the `arapp.json` or using a CLI parameter.
* daoFactory: Ethereum address of the used DAO Factory. On public networks we use [official aragon factories](https://github.com/aragon/deployments/tree/master/environments/)
* apmDomain: the ENS domain of the aragonPM (normally `open.aragonpm.eth`)
(please also see the [arapp.json related configuration options](https://hack.aragon.org/docs/cli-global-confg#the-arappjson-file))
### new-dao.js

View File

@@ -21,8 +21,8 @@ contract Contribution is AragonApp {
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token }
bytes32[4] public appIds;
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
bytes32[5] public appIds;
struct ContributionData {
uint32 contributorId;
@@ -54,7 +54,7 @@ contract Contribution is AragonApp {
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
event ContributionVetoed(uint32 id, address vetoedByAccount);
function initialize(bytes32[4] _appIds) public onlyInit {
function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
blocksToWait = 40320; // 7 days; 15 seconds block time
initialized();
@@ -66,13 +66,13 @@ contract Contribution is AragonApp {
}
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
address contributor = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributor).getContributorIdByAddress(contributorAccount);
address contributorContract = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributorContract).getContributorIdByAddress(contributorAccount);
}
function getContributorAddressById(uint32 contributorId) public view returns (address) {
address contributor = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributor).getContributorAddressById(contributorId);
address contributorContract = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributorContract).getContributorAddressById(contributorId);
}
//
@@ -164,7 +164,7 @@ contract Contribution is AragonApp {
if (contributionId < 10) {
c.confirmedAtBlock = block.number;
} else {
c.confirmedAtBlock = block.number + blocksToWait;
c.confirmedAtBlock = block.number + 1 + blocksToWait;
}
contributionsCount++;
@@ -193,10 +193,10 @@ contract Contribution is AragonApp {
require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE');
c.claimed = true;
address token = getContract(uint8(Apps.Token));
address tokenContract = getContract(uint8(Apps.Token));
address contributorAccount = getContributorAddressById(c.contributorId);
uint256 amount = uint256(c.amount);
IToken(token).mintFor(contributorAccount, amount, contributionId);
IToken(tokenContract).mintFor(contributorAccount, amount, contributionId);
emit ContributionClaimed(contributionId, c.contributorId, c.amount);
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,12 @@
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
"@aragon/os": "^4.4.0"
},
"devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"@aragon/test-helpers": "^2.1.0",
"eth-gas-reporter": "^0.2.17",
"ganache-cli": "^6.9.1",
"solidity-coverage": "^0.5.11"
},
"scripts": {
@@ -26,7 +25,7 @@
"publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major",
"versions": "aragon apm versions",
"test": "aragon contracts test"
"test": "truffle test"
},
"keywords": []
}

View File

@@ -28,14 +28,14 @@ contract Contributor is AragonApp {
uint32 public contributorsCount;
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token }
bytes32[4] public appIds;
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
bytes32[5] public appIds;
event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
event ContributorAdded(uint32 id, address account);
function initialize(address root,bytes32[4] _appIds) public onlyInit {
function initialize(address root, bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
initialized();

File diff suppressed because it is too large Load Diff

View File

@@ -3,14 +3,13 @@
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
"@aragon/os": "^4.4.0"
},
"devDependencies": {
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11",
"@aragon/test-helpers": "^2.0.0"
"@aragon/test-helpers": "^2.1.0",
"eth-gas-reporter": "^0.2.17",
"ganache-cli": "^6.9.1",
"solidity-coverage": "^0.5.11"
},
"scripts": {
"start": "npm run start:aragon:ipfs",
@@ -26,7 +25,7 @@
"publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major",
"versions": "aragon apm versions",
"test": "aragon contracts test"
"test": "truffle test"
},
"keywords": []
}

View File

@@ -21,8 +21,8 @@ contract('Contributor app', (accounts) => {
aclBase = await getContract('ACL').new();
daoFactory = await getContract('DAOFactory').new(kernelBase.address, aclBase.address, ZERO_ADDR);
r = await daoFactory.newDAO(root);
dao = getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao);
acl = getContract('ACL').at(await dao.acl());
dao = await getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao);
acl = await getContract('ACL').at(await dao.acl());
//create dao mamnager permission for coin owner
await acl.createPermission(
@@ -63,7 +63,7 @@ contract('Contributor app', (accounts) => {
root,
{ from: root }
);
});
describe("Owner default permissions", async () => {
@@ -71,7 +71,7 @@ contract('Contributor app', (accounts) => {
let manageContributorPermission = await acl.hasPermission(root, contributor.address, await contributor.MANAGE_CONTRIBUTORS_ROLE());
// eslint-disable-next-line no-undef
assert.equal(manageContributorPermission, true);
});
});
});
describe("Add contributor", async () => {

View File

@@ -20,8 +20,8 @@ contract Proposal is AragonApp {
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token }
bytes32[4] public appIds;
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
bytes32[5] public appIds;
struct Proposal {
address creatorAccount;
@@ -46,7 +46,7 @@ contract Proposal is AragonApp {
event ProposalVoted(uint32 id, uint32 voterId, uint16 totalVotes);
event ProposalExecuted(uint32 id, uint32 contributorId, uint32 amount);
function initialize(bytes32[4] _appIds) public onlyInit {
function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
initialized();
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,12 @@
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
"@aragon/os": "^4.4.0"
},
"devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"@aragon/test-helpers": "^2.1.0",
"eth-gas-reporter": "^0.2.17",
"ganache-cli": "^6.9.1",
"solidity-coverage": "^0.5.11"
},
"scripts": {
@@ -26,7 +25,7 @@
"publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major",
"versions": "aragon apm versions",
"test": "aragon contracts test"
"test": "truffle test"
},
"keywords": []
}

1
apps/reimbursement/.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.sol linguist-language=Solidity

7
apps/reimbursement/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
node_modules
artifacts
.cache
cache
dist
ipfs.cmd
package-lock.json

View File

@@ -0,0 +1,34 @@
{
"roles": [
{
"name": "Add reimursements",
"id": "ADD_REIMBURSEMENT_ROLE",
"params": []
},
{
"name": "Veto reimbursement",
"id": "VETO_REIMBURSEMENT_ROLE",
"params": []
}
],
"environments": {
"default": {
"network": "development",
"appName": "kredits-reimbursement.open.aragonpm.eth"
},
"rinkeby": {
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
"appName": "kredits-reimbursement.open.aragonpm.eth",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"network": "rinkeby"
},
"production": {
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
"appName": "kredits-reimbursement.aragonpm.eth",
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
"network": "mainnet"
}
},
"appName": "kredits-reimbursement.aragonpm.eth",
"path": "contracts/Reimbursement.sol"
}

View File

@@ -0,0 +1,34 @@
const { usePlugin } = require('@nomiclabs/buidler/config')
const hooks = require('./scripts/buidler-hooks')
usePlugin('@aragon/buidler-aragon')
module.exports = {
// Default Buidler configurations. Read more about it at https://buidler.dev/config/
defaultNetwork: 'localhost',
networks: {
localhost: {
url: 'http://localhost:8545',
},
},
solc: {
version: '0.4.24',
optimizer: {
enabled: true,
runs: 10000,
},
},
// Etherscan plugin configuration. Learn more at https://github.com/nomiclabs/buidler/tree/master/packages/buidler-etherscan
etherscan: {
apiKey: '', // API Key for smart contract verification. Get yours at https://etherscan.io/apis
},
// Aragon plugin configuration
aragon: {
appServePort: 8001,
clientServePort: 3000,
appSrcPath: 'app/',
appBuildOutputPath: 'dist/',
appName: 'expenses',
hooks, // Path to script hooks
},
}

View File

@@ -0,0 +1,94 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/kernel/IKernel.sol";
contract Reimbursement is AragonApp {
bytes32 public constant ADD_REIMBURSEMENT_ROLE = keccak256("ADD_REIMBURSEMENT_ROLE");
bytes32 public constant VETO_REIMBURSEMENT_ROLE = keccak256("VETO_REIMBURSEMENT_ROLE");
// bytes32 public constant MANAGE_APPS_ROLE = keccak256("MANAGE_APPS_ROLE");
struct ReimbursementData {
uint32 recipientId;
uint256 amount;
address token;
bytes32 hashDigest;
uint8 hashFunction;
uint8 hashSize;
uint256 confirmedAtBlock;
bool vetoed;
bool exists;
}
mapping(uint32 => ReimbursementData) public reimbursements;
uint32 public reimbursementsCount;
uint32 public blocksToWait;
event ReimbursementAdded(uint32 id, address indexed addedByAccount, uint256 amount);
event ReimbursementVetoed(uint32 id, address vetoedByAccount);
function initialize() public onlyInit {
blocksToWait = 40320; // 7 days; 15 seconds block time
initialized();
}
// function setApps() public isInitialized auth(MANAGE_APPS_ROLE) {
// }
function totalAmount(bool confirmedOnly) public view returns (uint256 amount) {
for (uint32 i = 1; i <= reimbursementsCount; i++) {
ReimbursementData memory r = reimbursements[i];
if (!r.vetoed && (block.number >= r.confirmedAtBlock || !confirmedOnly)) {
amount += r.amount; // should use safemath
}
}
}
function get(uint32 reimbursementId) public view returns (uint32 id, uint32 recipientId, uint256 amount, address token, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
id = reimbursementId;
ReimbursementData storage r = reimbursements[id];
return (
id,
r.recipientId,
r.amount,
r.token,
r.hashDigest,
r.hashFunction,
r.hashSize,
r.confirmedAtBlock,
r.exists,
r.vetoed
);
}
function add(uint256 amount, address token, uint32 recipientId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_REIMBURSEMENT_ROLE) {
uint32 reimbursementId = reimbursementsCount + 1;
ReimbursementData storage r = reimbursements[reimbursementId];
r.exists = true;
r.amount = amount;
r.token = token;
r.recipientId = recipientId;
r.hashDigest = hashDigest;
r.hashFunction = hashFunction;
r.hashSize = hashSize;
r.confirmedAtBlock = block.number + blocksToWait;
reimbursementsCount++;
emit ReimbursementAdded(reimbursementId, msg.sender, amount);
}
function veto(uint32 reimbursementId) public isInitialized auth(VETO_REIMBURSEMENT_ROLE) {
ReimbursementData storage r = reimbursements[reimbursementId];
require(r.exists, 'NOT_FOUND');
require(block.number < r.confirmedAtBlock, 'VETO_PERIOD_ENDED');
r.vetoed = true;
emit ReimbursementVetoed(reimbursementId, msg.sender);
}
function exists(uint32 reimbursementId) public view returns (bool) {
return reimbursements[reimbursementId].exists;
}
}

View File

@@ -0,0 +1,16 @@
{
"name": "kredits Reimbursement",
"author": "Placeholder-author",
"description": "An application for Aragon",
"details_url": "/meta/details.md",
"source_url": "https://<placeholder-repository-url>",
"icons": [
{
"src": "/meta/icon.svg",
"sizes": "56x56"
}
],
"screenshots": [{ "src": "/meta/screenshot-1.png" }],
"start_url": "/index.html",
"script": "/script.js"
}

View File

@@ -0,0 +1,30 @@
{
"name": "kredits-reimbursement",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "npm run start:aragon:ipfs",
"start:aragon:ipfs": "aragon run",
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
"start:app": "",
"compile": "aragon contracts compile",
"sync-assets": "",
"build:app": "",
"build:script": "",
"build": "",
"publish:patch": "aragon apm publish patch",
"publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major",
"versions": "aragon apm versions",
"test": "truffle test"
},
"dependencies": {
"@aragon/os": "^4.4.0"
},
"devDependencies": {
"@aragon/test-helpers": "^2.1.0",
"eth-gas-reporter": "^0.2.17",
"ganache-cli": "^6.9.1",
"solidity-coverage": "^0.5.11"
}
}

View File

@@ -0,0 +1,65 @@
/*
const { hash } = require('eth-ens-namehash')
const { getEventArgument } = require('@aragon/contract-test-helpers/events')
const Kernel = artifacts.require('@aragon/os/build/contracts/kernel/Kernel')
const ACL = artifacts.require('@aragon/os/build/contracts/acl/ACL')
const EVMScriptRegistryFactory = artifacts.require(
'@aragon/os/build/contracts/factory/EVMScriptRegistryFactory'
)
const DAOFactory = artifacts.require(
'@aragon/os/build/contracts/factory/DAOFactory'
)
const newDao = async (rootAccount) => {
// Deploy a DAOFactory.
const kernelBase = await Kernel.new(true)
const aclBase = await ACL.new()
const registryFactory = await EVMScriptRegistryFactory.new()
const daoFactory = await DAOFactory.new(
kernelBase.address,
aclBase.address,
registryFactory.address
)
// Create a DAO instance.
const daoReceipt = await daoFactory.newDAO(rootAccount)
const dao = await Kernel.at(getEventArgument(daoReceipt, 'DeployDAO', 'dao'))
// Grant the rootAccount address permission to install apps in the DAO.
const acl = await ACL.at(await dao.acl())
const APP_MANAGER_ROLE = await kernelBase.APP_MANAGER_ROLE()
await acl.createPermission(
rootAccount,
dao.address,
APP_MANAGER_ROLE,
rootAccount,
{ from: rootAccount }
)
return { dao, acl }
}
const newApp = async (dao, appName, baseAppAddress, rootAccount) => {
const receipt = await dao.newAppInstance(
hash(`${appName}.aragonpm.test`), // appId - Unique identifier for each app installed in the DAO; can be any bytes32 string in the tests.
baseAppAddress, // appBase - Location of the app's base implementation.
'0x', // initializePayload - Used to instantiate and initialize the proxy in the same call (if given a non-empty bytes string).
false, // setDefault - Whether the app proxy is the default proxy.
{ from: rootAccount }
)
// Find the deployed proxy address in the tx logs.
const logs = receipt.logs
const log = logs.find((l) => l.event === 'NewAppProxy')
const proxyAddress = log.args.proxy
return proxyAddress
}
module.exports = {
newDao,
newApp,
}
*/

View File

@@ -0,0 +1,21 @@
/*
const ANY_ADDRESS = '0xffffffffffffffffffffffffffffffffffffffff'
const setOpenPermission = async (acl, appAddress, role, rootAddress) => {
// Note: Setting a permission to 0xffffffffffffffffffffffffffffffffffffffff
// is interpreted by aragonOS as allowing the role for any address.
await acl.createPermission(
ANY_ADDRESS, // entity (who?) - The entity or address that will have the permission.
appAddress, // app (where?) - The app that holds the role involved in this permission.
role, // role (what?) - The particular role that the entity is being assigned to in this permission.
rootAddress, // manager - Can grant/revoke further permissions for this role.
{ from: rootAddress}
)
}
module.exports = {
setOpenPermission
}
*/

View File

@@ -0,0 +1 @@
module.exports = require("../../truffle.js");

8716
apps/reimbursement/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,12 +7,12 @@ contract Token is ERC20Token, AragonApp {
bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token }
bytes32[4] public appIds;
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
bytes32[5] public appIds;
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
function initialize(bytes32[4] _appIds) public onlyInit {
function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
name = 'Kredits';
symbol = '₭S';

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,12 @@
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
"@aragon/os": "^4.4.0"
},
"devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"@aragon/test-helpers": "^2.1.0",
"eth-gas-reporter": "^0.2.17",
"ganache-cli": "^6.9.1",
"solidity-coverage": "^0.5.11"
},
"scripts": {
@@ -26,7 +25,7 @@
"publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major",
"versions": "aragon apm versions",
"test": "aragon contracts test"
"test": "truffle test"
},
"keywords": []
}

View File

@@ -21,8 +21,8 @@ contract('Token app', (accounts) => {
aclBase = await getContract('ACL').new();
daoFactory = await getContract('DAOFactory').new(kernelBase.address, aclBase.address, ZERO_ADDR);
r = await daoFactory.newDAO(root);
dao = getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao);
acl = getContract('ACL').at(await dao.acl());
dao = await getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao);
acl = await getContract('ACL').at(await dao.acl());
//create dao mamnager permission for coin owner
await acl.createPermission(
@@ -63,7 +63,7 @@ contract('Token app', (accounts) => {
root,
{ from: root }
);
});
describe("Owner default space permissions", async () => {
@@ -71,7 +71,7 @@ contract('Token app', (accounts) => {
let tokenIssuerPermission = await acl.hasPermission(root, token.address, await token.MINT_TOKEN_ROLE());
// eslint-disable-next-line no-undef
assert.equal(tokenIssuerPermission, true);
});
});
});
describe("Token issuing", async () => {

View File

@@ -34,7 +34,6 @@
"environments": {
"development": {
"network": "development",
"apm": "open.aragonpm.eth",
"registry": "0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1",
"appName": "dummy.open.aragonpm.eth"
},
@@ -42,9 +41,10 @@
"network": "rinkeby",
"registry": "0x98Df287B6C145399Aaa709692c8D308357bC085D",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"daoFactory": "0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d",
"appName": "dummy.open.aragonpm.eth",
"apm": "open.aragonpm.eth"
"kredits": {
"daoFactory": "0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d"
}
},
"kovan": {
"network": "kovan",
@@ -52,8 +52,7 @@
},
"default": {
"network": "development",
"appName": "dummy.aragonpm.eth",
"apm": "open.aragonpm.eth"
"appName": "dummy.aragonpm.eth"
}
},
"path": "contracts/misc/DummyApp.sol"

View File

@@ -31,13 +31,19 @@ const contractCalls = [
wiki_username: 'Manuel',
}, { gasLimit: 200000 }]],
['Proposal', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-09', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
['Proposal', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-10', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
['Proposal', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Hacked on kredits', url: '' }, { gasLimit: 350000 }]],
['Proposal', 'vote', [1, { gasLimit: 550000 }]],
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 5000, kind: 'dev', description: '[67P/kredits-contracts] Introduce contribution token', url: '' }, { gasLimit: 350000 }]],
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Test this thing', url: '' }, { gasLimit: 350000 }]],
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-web] Reviewed stuff', url: '' }, { gasLimit: 350000 }]],
['Contribution', 'claim', [1, { gasLimit: 300000 }]],
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-contracts] Add tests', url: '' }, { gasLimit: 350000 }]],
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-contracts] Introduce contribution token', url: '' }, { gasLimit: 350000 }]],
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 5000, kind: 'dev', description: '[67P/kredits-web] Expense UI, first draft', url: '' }, { gasLimit: 350000 }]],
['Reimbursement', 'add', [{amount: 1116000, recipientId: 1, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
{ title: 'Server rent', description: 'Dedicated server: andromeda.kosmos.org, April 2020', amount: 61, currency: 'EUR', date: '2020-05-28' },
{ title: 'Server rent', description: 'Dedicated server: centaurus.kosmos.org, April 2020', amount: 32, currency: 'EUR', date: '2020-05-28' }
]}, { gasLimit: 300000 }]],
['Reimbursement', 'add', [{amount: 166800, recipientId: 2, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
{ title: 'Domain kosmos.chat', description: 'Yearly registration fee for domain kosmos.chat', amount: 13.90, currency: 'EUR', date: '2020-05-30' }
]}, { gasLimit: 300000 }]],
];
const funds = [

View File

@@ -10,17 +10,18 @@ import "../apps/contribution/contracts/Contribution.sol";
import "../apps/contributor/contracts/Contributor.sol";
import "../apps/token/contracts/Token.sol";
import "../apps/proposal/contracts/Proposal.sol";
import "../apps/reimbursement/contracts/Reimbursement.sol";
contract KreditsKit is KitBase {
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token }
bytes32[4] public appIds;
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
bytes32[5] public appIds;
event DeployInstance(address dao);
event InstalledApp(address dao, address appProxy, bytes32 appId);
constructor (DAOFactory _fac, ENS _ens, bytes32[4] _appIds) public KitBase(_fac, _ens) {
constructor (DAOFactory _fac, ENS _ens, bytes32[5] _appIds) public KitBase(_fac, _ens) {
appIds = _appIds;
}
@@ -41,18 +42,24 @@ contract KreditsKit is KitBase {
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());
Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)]));
proposal.initialize(appIds);
Reimbursement reimbursement = Reimbursement(_installApp(dao, appIds[uint8(Apps.Reimbursement)]));
reimbursement.initialize();
acl.createPermission(root, reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE(), this);
acl.createPermission(root, reimbursement, reimbursement.VETO_REIMBURSEMENT_ROLE(), this);
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);
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.VETO_CONTRIBUTION_ROLE(), params);
acl.grantPermissionP(acl.ANY_ENTITY(), contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), params);
acl.grantPermissionP(acl.ANY_ENTITY(), reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE(), params);
//acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE();
acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this);
@@ -67,6 +74,8 @@ 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.setPermissionManager(root, reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE());
acl.setPermissionManager(root, reimbursement, reimbursement.VETO_REIMBURSEMENT_ROLE());
acl.createPermission(root, token, token.MINT_TOKEN_ROLE(), this);
acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE());

View File

@@ -1,16 +0,0 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/acl/ACL.sol";
import "@aragon/os/contracts/kernel/Kernel.sol";
import "@aragon/os/contracts/factory/DAOFactory.sol";
// You might think this file is a bit odd, but let me explain.
// We only use for now those imported contracts in our tests, which
// means Truffle will not compile them for us, because they are from
// an external dependency.
// solium-disable-next-line no-empty-blocks
contract Spoof {
// ...
}

19000
data/contributions.json Normal file

File diff suppressed because it is too large Load Diff

121
data/contributors.json Normal file
View File

@@ -0,0 +1,121 @@
{
"1": {
"account": "0x7E8f313C56F809188313aa274Fa67EE58c31515d",
"hashDigest": "0x99b8afd7b266e19990924a8be9099e81054b70c36b20937228a77a5cf75723b8",
"hashFunction": 18,
"hashSize": 32,
"id": 1
},
"2": {
"account": "0x49575f3DD9a0d60aE661BC992f72D837A77f05Bc",
"hashDigest": "0xeb78574922d8606419b714174b31961007afefe313111c9db817aa9d3f82e157",
"hashFunction": 18,
"hashSize": 32,
"id": 2
},
"3": {
"account": "0xF722709ECC3B05c19d02E82a2a4A4021B8F48C62",
"hashDigest": "0x7acd73632c7cc8d317fa9e72e925eaef1d700e69f185b84e3f0168471e17cf2d",
"hashFunction": 18,
"hashSize": 32,
"id": 3
},
"4": {
"account": "0xD4a64570B12dA659Ee4BBd41c3509B7b1F9c51AC",
"hashDigest": "0x4d394c58e4b0534446be10a9b7f8b50e5478258719c23a3e158a5ea9fca14bdd",
"hashFunction": 18,
"hashSize": 32,
"id": 4
},
"5": {
"account": "0x35d9e68a5F7A935C64b08221d5DC7f161a415184",
"hashDigest": "0xd6f726f37ad52998b8341b7021cb5d9f4dcf7ce09af575358505a2a7c2f81edb",
"hashFunction": 18,
"hashSize": 32,
"id": 5
},
"6": {
"account": "0x8345E84D848792bf750A1d032d76f20f00aeC1a7",
"hashDigest": "0x1acdc784e20f62c44ec222552531bf89daafaaca1893a68057a9ada920ea0984",
"hashFunction": 18,
"hashSize": 32,
"id": 6
},
"7": {
"account": "0x4D99d767477Fbb2B47EFeb17E2a78970AD22CCc1",
"hashDigest": "0xd6d16bde5ee3d3374dd5981dab0296938b24e3c812e72ba4fa3d38011b6fab24",
"hashFunction": 18,
"hashSize": 32,
"id": 7
},
"8": {
"account": "0x6a6cD99ab0335C92E55fbb4403D67A4f4B52AfEc",
"hashDigest": "0xec30c91b31a85eef2af7afce0ba66b0636f1d61a75a12d8ca188a2d9e1626cf2",
"hashFunction": 18,
"hashSize": 32,
"id": 8
},
"9": {
"account": "0x21aB0B3527326dcA4467245654Cf881F5F7a8c5e",
"hashDigest": "0xd6c8b0f285e614b12f700d6e66e2e67901c16c420308625f844357283bd555ba",
"hashFunction": 18,
"hashSize": 32,
"id": 9
},
"10": {
"account": "0x150A69bAfA216FD55C7CeF8eA2002cd582dc5982",
"hashDigest": "0x7490aabadf995751211686b3b9f4b8cfee3354947df23cec043c15bfb519c817",
"hashFunction": 18,
"hashSize": 32,
"id": 10
},
"11": {
"account": "0x2f65679cAf0c3abCbF77fC68fA56759f4D96C73c",
"hashDigest": "0xd147d2d26f7eb1cbe1c5da53c345565df2d3c6c33a8a3e3331952d4b878b2bb0",
"hashFunction": 18,
"hashSize": 32,
"id": 11
},
"12": {
"account": "0x13a24319Abb4e00c383D8a80dACb20690699Ac8C",
"hashDigest": "0x84c63c2d3f9510f87717e54a2cecb41f88dce6a41ae6392480ebf6561e30670e",
"hashFunction": 18,
"hashSize": 32,
"id": 12
},
"13": {
"account": "0x0e0F02508b80e401C26F584fF02eE80Ab094CdF9",
"hashDigest": "0xe4c34e15b87114e9edd599fa1bbd6d4b1bf45c3b0163d0772158fb93503c1fe1",
"hashFunction": 18,
"hashSize": 32,
"id": 13
},
"14": {
"account": "0x49750D74930b20b2937DDF77A6C30d81882d888E",
"hashDigest": "0xa1f18c54e77d1e8f0fa106463b3f66a34a6287bcd9b643febea0ab2e97009665",
"hashFunction": 18,
"hashSize": 32,
"id": 14
},
"15": {
"account": "0x608FD4b95116Ea616990Aaeb1d4f1ce07612f261",
"hashDigest": "0x1d9de6de5c72eedca6d7a5e8a9159e2f5fe676506aece3000acefcc821723429",
"hashFunction": 18,
"hashSize": 32,
"id": 15
},
"16": {
"account": "0xCaBba4560c96FADe3Dd6C29cF24Cfb16a228bC1c",
"hashDigest": "0x0c81914b8a332808879b06b1a68398edccea7e7facb50767e4116c33914d2c64",
"hashFunction": 18,
"hashSize": 32,
"id": 16
},
"17": {
"account": "0x765E88b4F9a59C3a3b300C6eFF9E6E9fDDf9FbD9",
"hashDigest": "0xcfbeeadc244dfdc55bbad50d431871439df067970db84c73023956c96a6f5df2",
"hashFunction": 18,
"hashSize": 32,
"id": 17
}
}

View File

@@ -2,6 +2,36 @@
aragon apm publish major --environment=rinkeby"
## 20212-01-14
apps/contribution@master » aragon apm publish major --environment=rinkeby
eth-provider | Invalid provider preset/location: "local"
✔ Start IPFS
✔ Applying version bump (major)
↓ Building frontend [skipped]
→ build script not defined in package.json
✔ Deploy contract
✔ Determine contract address for version
✔ Prepare files for publishing
✔ Generate application artifact
✔ Publish intent
⚠ Publishing files from the project's root folder is not recommended. Consider using the distribution folder of your project: "--files <folder>".
The following information will be published:
Contract address: 0x914Da982ef17B56D2e868E3a67E923EbED1aE017
Content (ipfs): QmdVrY2R48NFqwLopd8ix1anAK1d6WafDGauou3ZJrB9gf
? Publish to kredits-contribution.open.aragonpm.eth repo Yes
✔ Publish kredits-contribution.open.aragonpm.eth
Successfully published kredits-contribution.open.aragonpm.eth v7.0.0 :
Transaction hash: 0xb817b2e80e90a6be60b45dd39987498e3132c9962c0501feb7549ad30186c6d5
## 2019-04-24 update balances
✔ Successfully published kredits-contribution.open.aragonpm.eth v6.0.0:

View File

@@ -1,5 +1,16 @@
# Kredits deployment
## 2021-01-14
apps/contribution@master » aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contribution.open.aragonpm.eth --environment=rinkeby
eth-provider | Invalid provider preset/location: "local"
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
✔ Upgrading app
✔ Successfully executed: "Upgrade 'kredits-contribution.open.aragonpm.eth' app instances to v7.0.0"
## 2019-04-25 canPerfom fix
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@ class Acl extends Base {
hasPermission (fromAddress, contractAddress, roleID, params = null) {
let roleHash = EthersUtils.keccak256(EthersUtils.toUtf8Bytes(roleID));
return this.functions.hasPermission(
return this.hasPermission(
fromAddress,
contractAddress,
roleHash,

View File

@@ -1,10 +1,13 @@
const deprecate = require('../utils/deprecate');
class Base {
constructor (contract) {
this.contract = contract;
}
get functions () {
return this.contract.functions;
deprecate('The property `functions` is deprecated. contract functions are now directly defined on the ethers contract object. https://github.com/ethers-io/ethers.js/issues/920#issuecomment-650836642');
return this.contract;
}
get address () {

View File

@@ -4,33 +4,33 @@ const deprecate = require('../utils/deprecate');
class Contribution extends Record {
get count () {
return this.functions.contributionsCount();
return this.contract.contributionsCount();
}
getById (id) {
return this.functions.getContribution(id)
return this.contract.getContribution(id)
.then(data => {
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
});
}
getData (id) {
return this.functions.getContribution(id);
return this.contract.getContribution(id);
}
getByContributorId (contributorId) {
return this.functions.getContributorAddressById(contributorId)
return this.contract.getContributorAddressById(contributorId)
.then(address => this.getByContributorAddress(address));
}
getByContributorAddress (address) {
return this.functions.balanceOf(address)
return this.contract.balanceOf(address)
.then(async (balance) => {
const count = balance.toNumber();
const contributions = [];
for (let index = 0; index < count; index++) {
const id = await this.functions.tokenOfOwnerByIndex(address, index);
const id = await this.contract.tokenOfOwnerByIndex(address, index);
const contribution = await this.getById(id);
contributions.push(contribution);
}
@@ -58,7 +58,7 @@ class Contribution extends Record {
ipfsHashAttr.hashSize,
];
return this.functions.add(...contribution, callOptions);
return this.contract.add(...contribution, callOptions);
});
}

View File

@@ -4,19 +4,20 @@ const formatKredits = require('../utils/format-kredits');
class Contributor extends Record {
get count () {
return this.functions.contributorsCount();
return this.contract.contributorsCount();
}
getById (id) {
return this.functions.getContributorById(id)
.then(data => {
return this.contract.getContributorById(id)
.then(contractData => {
let data = {...contractData};
data.balanceInt = formatKredits(data.balance);
return this.ipfs.catAndMerge(data, ContributorSerializer.deserialize);
});
}
getData (id) {
return this.functions.getContributorById(id);
return this.contract.getContributorById(id);
}
filterByAccount (search) {
@@ -61,7 +62,7 @@ class Contributor extends Record {
ipfsHashAttr.hashSize,
];
return this.functions.addContributor(...contributor, callOptions);
return this.contract.addContributor(...contributor, callOptions);
});
}
@@ -78,7 +79,7 @@ class Contributor extends Record {
return this.ipfs
.add(jsonStr)
.then(ipfsHashAttr => {
return this.functions.updateContributorProfileHash(
return this.contract.updateContributorProfileHash(
contributorId,
ipfsHashAttr.hashDigest,
ipfsHashAttr.hashFunction,

View File

@@ -3,6 +3,7 @@ module.exports = {
Contribution: require('./contribution'),
Proposal: require('./proposal'),
Token: require('./token'),
Reimbursement: require('./reimbursement'),
Kernel: require('./kernel'),
Acl: require('./acl'),
};

View File

@@ -11,9 +11,9 @@ class Kernel extends Base {
getApp (appName) {
if (appName === 'Acl') {
return this.functions.acl();
return this.contract.acl();
}
return this.functions.getApp(KERNEL_APP_ADDR_NAMESPACE, this.appNamehash(appName));
return this.contract.getApp(KERNEL_APP_ADDR_NAMESPACE, this.appNamehash(appName));
}
appNamehash (appName) {

View File

@@ -4,11 +4,11 @@ const deprecate = require('../utils/deprecate');
class Proposal extends Record {
get count () {
return this.functions.proposalsCount();
return this.contract.proposalsCount();
}
getById (id) {
return this.functions.getProposal(id)
return this.contract.getProposal(id)
.then(data => {
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
});
@@ -33,7 +33,7 @@ class Proposal extends Record {
ipfsHashAttr.hashSize,
];
return this.functions.addProposal(...proposal, callOptions);
return this.contract.addProposal(...proposal, callOptions);
});
}

View File

@@ -0,0 +1,65 @@
const Record = require('./record');
const ExpenseSerializer = require('../serializers/expense');
class Reimbursement extends Record {
get count () {
return this.functions.reimbursementsCount();
}
getById (id) {
return this.functions.get(id)
.then(data => {
return this.ipfs.catAndMerge(data, (ipfsDocument) => {
const expenses = JSON.parse(ipfsDocument);
return { expenses };
});
});
}
getData (id) {
return this.functions.getReimbursement(id);
}
async add (attrs, callOptions = {}) {
const amount = parseInt(attrs.amount);
const token = attrs.token;
const recipientId = attrs.recipientId;
const expenses = attrs.expenses.map( e => new ExpenseSerializer(e) );
let errorMessage;
if (typeof amount !== 'number' || amount <= 0) {
errorMessage = 'Invalid data: amount must be a positive number.';
}
if (!token || token === '') {
errorMessage = 'Invalid data: token must be a token address.';
}
if (!recipientId || recipientId === '') {
errorMessage = 'Invalid data: recipientId is required.';
}
if (expenses.length === 0) {
errorMessage = 'Invalid data: at least one expense item is required.';
}
if (errorMessage) { return Promise.reject(new Error(errorMessage)); }
return Promise.all(expenses.map(e => e.validate()))
.then(() => {
const jsonStr = JSON.stringify(expenses.map(e => e.data), null, 2);
return this.ipfs
.add(jsonStr)
.then(ipfsHashAttr => {
const reimbursement = [
amount,
token,
parseInt(recipientId),
ipfsHashAttr.hashDigest,
ipfsHashAttr.hashFunction,
ipfsHashAttr.hashSize,
];
return this.functions.add(...reimbursement, callOptions);
});
});
}
}
module.exports = Reimbursement;

View File

@@ -6,6 +6,7 @@ const deprecate = require('./utils/deprecate');
const ABIS = {
Contributor: require('./abis/Contributor.json'),
Contribution: require('./abis/Contribution.json'),
Reimbursement: require('./abis/Reimbursement.json'),
Token: require('./abis/Token.json'),
Proposal: require('./abis/Proposal.json'),
Kernel: require('./abis/Kernel.json'),
@@ -16,6 +17,7 @@ const APP_CONTRACTS = [
'Contribution',
'Token',
'Proposal',
'Reimbursement',
'Acl',
];
const DaoAddresses = require('./addresses/dao.json');
@@ -121,6 +123,10 @@ class Kredits {
return this.contractFor('Contribution');
}
get Reimbursement () {
return this.contractFor('Reimbursement');
}
get Acl () {
return this.contractFor('Acl');
}

View File

@@ -29,12 +29,12 @@ class KreditsKit {
appIdFor (contractName) {
// see appIds in KreditsKit.sol for more details
const knownContracts = ['Contribution', 'Contributor', 'Proposal', 'Token'];
return this.contract.functions.appIds(knownContracts.indexOf(contractName));
const knownContracts = ['Contribution', 'Contributor', 'Proposal', 'Reimbursement', 'Token'];
return this.contract.appIds(knownContracts.indexOf(contractName));
}
newDAO (options = {}) {
return this.contract.functions.newInstance(options).then(transaction => {
return this.contract.newInstance(options).then(transaction => {
return transaction.wait().then(result => {
const deployEvent = result.events.find(e => e.event === 'DeployInstance');
return {

View File

@@ -1,4 +1,4 @@
const schemas = require('kosmos-schemas');
const schemas = require('@kosmos/schemas');
const validator = require('../utils/validator');
/**

View File

@@ -1,4 +1,4 @@
const schemas = require('kosmos-schemas');
const schemas = require('@kosmos/schemas');
const validator = require('../utils/validator');
/**
* Handle serialization for JSON-LD object of the contributor, according to

100
lib/serializers/expense.js Normal file
View File

@@ -0,0 +1,100 @@
const schemas = require('@kosmos/schemas');
const validator = require('../utils/validator');
/**
* Serialization and validation for JSON-LD document of the Expense
*
* @class
* @public
*/
class ExpenseSerializer {
constructor (attrs) {
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
}
/**
* Serialize object to JSON
*
* @public
*/
serialize () {
// Write it pretty to ipfs
return JSON.stringify(this.data, null, 2);
}
get data () {
const {
title,
description,
currency,
amount,
date,
url,
tags,
details,
} = this;
const data = {
'@context': 'https://schema.kosmos.org',
'@type': 'Expense',
title,
description,
currency,
amount,
date,
'tags': tags || [],
'details': details || {},
};
if (url) {
data['url'] = url;
}
return data;
}
/**
* Validate serialized data against schema
*
* @public
*/
validate () {
const serialized = JSON.parse(this.serialize());
const valid = validator.validate(serialized, schemas['expense']);
return valid ? Promise.resolve() : Promise.reject(validator.error);
}
/**
* Deserialize JSON to object
*
* @public
*/
static deserialize (serialized) {
const {
title,
description,
currency,
amount,
date,
url,
tags,
details,
} = JSON.parse(serialized.toString('utf8'));
return {
title,
description,
currency,
amount,
date,
url,
tags,
details,
ipfsData: serialized,
};
}
}
module.exports = ExpenseSerializer;

View File

@@ -11,7 +11,8 @@ class IPFS {
this._ipfsAPI = ipfsClient(config);
}
catAndMerge (data, deserialize) {
catAndMerge (contractData, deserialize) {
let data = {...contractData}; // data from ethers.js is not extensible. this copy the attributes in a new object
// if no hash details are found simply return the data; nothing to merge
if (!data.hashSize || data.hashSize === 0) {
return data;
@@ -36,7 +37,7 @@ class IPFS {
cat (hashData) {
let ipfsHash = hashData; // default - if it is a string
if (hashData.hasOwnProperty('hashSize')) {
if (Object.prototype.hasOwnProperty.call(hashData, 'hashSize')) {
ipfsHash = this.encodeHash(hashData);
}
if (this._config['gatewayUrl']) {
@@ -48,7 +49,7 @@ class IPFS {
pin (hashData) {
let ipfsHash = hashData; // default - if it is a string
if (hashData.hasOwnProperty('hashSize')) {
if (Object.prototype.hasOwnProperty.call(hashData, 'hashSize')) {
ipfsHash = this.encodeHash(hashData);
}
return this._ipfsAPI.pin.add(multihashes.toB58String(ipfsHash));

6215
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "kredits-contracts",
"version": "5.4.0",
"version": "6.0.0",
"description": "Ethereum contracts and npm wrapper for Kredits",
"main": "./lib/kredits.js",
"directories": {
@@ -15,21 +15,20 @@
"compile-contracts": "truffle compile --all",
"bootstrap": "npm run reset:hard && npm run seeds",
"reset": "npm run deploy:kit && npm run deploy:dao",
"reset:hard": "npm run deploy:apps && npm run reset",
"deploy:kit": "aragon contracts exec scripts/deploy-kit.js",
"deploy:dao": "aragon contracts exec scripts/new-dao.js",
"reset:hard": "npm run compile-contracts && npm run deploy:apps && npm run reset",
"deploy:kit": "truffle exec scripts/deploy-kit.js",
"deploy:dao": "truffle exec scripts/new-dao.js",
"deploy:apps": "./scripts/every-app.sh \"aragon apm publish major --propagate-content=false --build=false --prepublish=false --skip-confirmation\"",
"devchain": "aragon devchain --port 7545",
"dao:address": "truffle exec scripts/current-address.js",
"lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"",
"lint:contract-tests": "eslint apps/*/test",
"lint:wrapper": "eslint lib/",
"test": "npm run test:token && npm run test:contributor && npm run test:contribution && npm run test:proposal && npm run test:kit",
"test": "npm run test:token && npm run test:contributor && npm run test:contribution && npm run test:proposal",
"test:token": "cd apps/token && npm run test",
"test:contributor": "cd apps/contributor && npm run test",
"test:contribution": "cd apps/contribution && npm run test",
"test:proposal": "cd apps/proposal && npm run test",
"test:kit": "aragon contracts test",
"setup-git-hooks": "sh scripts/git-hooks/install"
},
"repository": {
@@ -44,23 +43,27 @@
"homepage": "https://github.com/67P/truffle-kredits#readme",
"devDependencies": {
"@aragon/kits-base": "^1.0.0",
"@aragon/os": "^4.2.0",
"@aragon/os": "^4.4.0",
"async-each-series": "^1.1.0",
"cli-table": "^0.3.1",
"eslint": "^5.16.0",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.1.1",
"eth-provider": "^0.2.2",
"eslint": "^7.1.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eth-provider": "^0.2.5",
"ethereum-block-by-date": "^1.4.0",
"homedir": "^0.6.0",
"promptly": "^3.0.3",
"solc": "^0.4.26",
"solhint": "^2.1.0",
"yargs": "^12.0.0"
"solc": "^0.6.8",
"solhint": "^2.3.1",
"truffle-hdwallet-provider": "^1.0.17",
"truffle-hdwallet-provider-privkey": "^0.3.0",
"yargs": "^15.0.0"
},
"dependencies": {
"ethers": "^4.0.29",
"ipfs-http-client": "^30.1.3",
"kosmos-schemas": "^2.1.0",
"ethers": "^5.0.2",
"ipfs-http-client": "^41.0.1",
"@kosmos/schemas": "^3.0.0",
"node-fetch": "^2.6.0",
"tv4": "^1.3.0"
},

View File

@@ -19,10 +19,10 @@ module.exports = async function(callback) {
let contributorAccount;
if (contributor.length < 5) {
contributorId = contributor;
contributorAccount = await kredits.Contributor.functions.getContributorAddressById(contributor);
contributorAccount = await kredits.Contributor.contract.getContributorAddressById(contributor);
} else {
contributorAccount = contributor;
contributorId = await kredits.Contributor.functions.getContributorIdByAddress(contributor);
contributorId = await kredits.Contributor.contract.getContributorIdByAddress(contributor);
}
console.log(`Creating a contribution for contributor account ${contributorAccount} ID: ${contributorId}`);
@@ -45,7 +45,7 @@ module.exports = async function(callback) {
console.log("\nAdding contribution:");
console.log(contributionAttributes);
kredits.Contribution.addContribution(contributionAttributes, { gasLimit: 300000 })
kredits.Contribution.add(contributionAttributes, { gasLimit: 300000 })
.then(result => {
console.log("\n\nResult:");
console.log(result);

View File

@@ -19,10 +19,10 @@ module.exports = async function(callback) {
let contributorAccount;
if (contributor.length < 5) {
contributorId = contributor;
contributorAccount = await kredits.Contributor.functions.getContributorAddressById(contributor);
contributorAccount = await kredits.Contributor.contract.getContributorAddressById(contributor);
} else {
contributorAccount = contributor;
contributorId = await kredits.Contributor.functions.getContributorIdByAddress(contributor);
contributorId = await kredits.Contributor.contract.getContributorIdByAddress(contributor);
}
console.log(`Creating a proposal for contributor ID #${contributorId} account: ${contributorAccount}`);

View File

@@ -11,6 +11,7 @@ const files = [
'Kernel',
'Proposal',
'Token',
'Reimbursement',
'ACL'
];

View File

@@ -31,7 +31,7 @@ module.exports = async function(callback) {
if (c.contributorId === recipient && confirmed && !c.vetoed && !c.claimed) {
console.log(`Claiming contribution ID=${c.id}`);
return kredits.Contribution.functions.claim(c.id, { gasLimit: 500000 }).then(tx => {
return kredits.Contribution.contract.claim(c.id, { gasLimit: 500000 }).then(tx => {
table.push([
c.id.toString(),
`${c.description}`,

View File

@@ -17,7 +17,7 @@ module.exports = async function(callback) {
method = await promptly.prompt('Function: ');
}
if (!contractWrapper[method] && !contractWrapper.functions[method]) {
if (!contractWrapper[method] && !contractWrapper.contract[method]) {
callback(new Error(`Method ${method} is not defined on ${contractName}`));
return;
}
@@ -33,7 +33,7 @@ module.exports = async function(callback) {
if (contractWrapper[method]) {
func = contractWrapper[method];
} else {
func = contractWrapper.functions[method];
func = contractWrapper.contract[method];
}
func.apply(contractWrapper, args).then((result) => {
console.log("\nResult:");

View File

@@ -1,9 +1,12 @@
const knownDAOAddresses = require('../lib/addresses/dao.json');
const knownKreditsKitAddresses = require('../lib/addresses/KreditsKit.json');
const getNetworkId = require('./helpers/networkid.js')
const ethers = require('ethers');
module.exports = async function(callback) {
const networkId = await getNetworkId(web3)
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
let network = await provider.getNetwork();
let networkId = network.chainId;
console.log('# All known DAO addresses');
Object.keys(knownDAOAddresses).forEach((networkId) => {

View File

@@ -3,23 +3,33 @@ const deployDAOFactory = require('@aragon/os/scripts/deploy-daofactory.js')
const fs = require('fs');
const path = require('path');
const argv = require('yargs').argv
const namehash = require('ethers').utils.namehash;
const ethers = require('ethers');
const namehash = ethers.utils.namehash;
const fileInject = require('./helpers/file_inject.js')
const getNetworkId = require('./helpers/networkid.js')
const DAOFactory = artifacts.require('DAOFactory')
const KreditsKit = artifacts.require('KreditsKit')
const arapp = require('../arapp.json')
const environment = argv['network'] || argv['environment'] || 'development'
const apm = arapp.environments[environment].apm
const ensAddr = arapp.environments[environment].registry || process.env.ENS
const daoFactoryAddress = arapp.environments[environment].daoFactory || process.env.DAO_FACTORY
const kreditsArappConfig = arapp.environments[environment].kredits || {}
// typically we use the open.aragonpm.eth aragonpm.
const apm = kreditsArappConfig.apmDomain || argv['apmDomain'] || 'open.aragonpm.eth'
// daoFactory is environment specific.
// See https://github.com/aragon/deployments/tree/master/environments/ for the official daoFactory
// Locally we deploy our own daoFactory and no daoFactory is required (`daoFactoryAddress` is null).
const daoFactoryAddress = kreditsArappConfig.daoFactory || argv['daoFactory']
const ensAddr = arapp.environments[environment].registry || argv['ensAddress']
module.exports = async function(callback) {
const networkId = await getNetworkId(web3)
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
const network = await provider.getNetwork();
const networkId = network.chainId;
console.log(`Deploying to networkId: ${networkId}`)
if (!ensAddr) {

View File

@@ -0,0 +1,49 @@
const fs = require('fs');
const ethers = require('ethers');
const Kredits = require('../../lib/kredits');
const provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_rinkeby');
const arapp = require('../../arapp.json');
const apm = arapp.environments['rinkeby'].apm;
async function main() {
const kredits = await new Kredits(provider, null, { apm });
//kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
await kredits.init();
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
const count = await kredits.Contribution.count;
const currentBlockHeight = await provider.getBlockNumber();
const backup = {};
const promises = [];
for (let i = 1; i <= count; i++) {
promises.push(new Promise((resolve, reject) => {
setTimeout(async () => {
console.log(`Loading contribution #${i}`);
await kredits.Contribution.contract.getContribution(i).then(contractData => {
backup[i] = {
amount: contractData.amount,
contributorId: contractData.contributorId,
hashDigest: contractData.hashDigest,
hashFunction: contractData.hashFunction,
hashSize: contractData.hashSize,
confirmedAtBlock: contractData.confirmedAtBlock,
confirmed: contractData.confirmedAtBlock <= currentBlockHeight,
vetoed: contractData.vetoed,
id: contractData.id,
}
resolve();
});
}, 100 * i);
}));
}
await Promise.all(promises).then(() => {
fs.writeFileSync("./data/contributions.json", JSON.stringify(backup, null, 2));
console.log("Exported");
});
}
main();

View File

@@ -0,0 +1,44 @@
const fs = require('fs');
const ethers = require('ethers');
const Kredits = require('../../lib/kredits');
const provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_rinkeby');
const arapp = require('../../arapp.json');
const apm = arapp.environments['rinkeby'].apm;
async function main() {
const kredits = await new Kredits(provider, null, { apm });
//kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
await kredits.init();
console.log(`Using Contributor at: ${kredits.Contributor.contract.address}`);
const count = await kredits.Contributor.count;
const backup = {};
const promises = [];
for (let i = 1; i <= count; i++) {
promises.push(new Promise((resolve, reject) => {
setTimeout(async () => {
console.log(`Loading contributor #${i}`);
await kredits.Contributor.contract.getContributorById(i).then(contractData => {
backup[i] = {
account: contractData.account,
hashDigest: contractData.hashDigest,
hashFunction: contractData.hashFunction,
hashSize: contractData.hashSize,
id: contractData.id,
}
resolve();
});
}, 100 * i);
}));
}
await Promise.all(promises).then(() => {
fs.writeFileSync("./data/contributors.json", JSON.stringify(backup, null, 2));
console.log("Exported");
});
}
main();

View File

@@ -0,0 +1,19 @@
const promptly = require('promptly');
const EthDater = require('ethereum-block-by-date');
const initKredits = require('./helpers/init_kredits.js');
module.exports = async function(callback) {
let kredits;
try { kredits = await initKredits(web3); } catch(e) { callback(e); return; }
const dater = new EthDater(kredits.provider);
const dateStr = await promptly.prompt('Specify a date and time (e.g. 2021-05-07T14:00:40Z): ');
const blockData = await dater.getDate(dateStr, true);
console.log(`
The closest block is #${blockData.block}:
https://rinkeby.etherscan.io/block/${blockData.block}
`);
callback();
}

View File

@@ -1,6 +1,5 @@
const argv = require('yargs').argv;
const ethers = require('ethers');
const getNetworkId = require('./networkid.js');
const Kredits = require('../../lib/kredits');
const arapp = require('../../arapp.json');
@@ -10,7 +9,7 @@ const apm = arapp.environments[environment].apm;
module.exports = async function(web3) {
return new Promise((resolve, reject) => {
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
let signer = provider.getSigner();
const signer = provider.getSigner();
// checking if siner supports signing transactions
signer.getAddress().then(_ => {
new Kredits(provider, signer, { apm }).init().then(kredits => {

View File

@@ -1,17 +0,0 @@
module.exports = function(web3) {
return new Promise((resolve, reject) => {
let func;
if (web3.version.getNetwork) {
func = web3.version.getNetwork;
} else {
func = web3.eth.net.getId;
}
func((err, network) => {
if (err) {
reject(err);
} else {
resolve(network);
}
})
})
}

View File

@@ -1,12 +1,14 @@
const fs = require('fs');
const getNetworkId = require('./networkid.js');
const ethers = require('ethers');
module.exports = async function(callback) {
const daoAddressPath = 'lib/addresses/dao.json';
// TODO maybe do the same for KreditsKit address file
try {
const networkId = await getNetworkId(web3);
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
const network = await provider.getNetwork();
const networkId = network.chainId;
const daoAddresses = JSON.parse(fs.readFileSync(daoAddressPath));
const oldNetworkId = Math.max(...Object.keys(daoAddresses).map(a => parseInt(a)));
const localDaoAddress = daoAddresses[oldNetworkId];

View File

@@ -0,0 +1,76 @@
const promptly = require('promptly');
const Table = require('cli-table');
const initKredits = require('./helpers/init_kredits.js');
module.exports = async function(callback) {
let kredits;
try {
kredits = await initKredits(web3);
} catch(e) {
callback(e);
return;
}
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
const table = new Table({
head: ['ID', 'Name', 'Kredits']
})
try {
let currentBlockNumber = await kredits.provider.getBlockNumber();
console.log(`Current block number: ${currentBlockNumber}`);
let confirmedBeforeBlock = await promptly.prompt('Before block: ');
let confirmedAfterBlock = await promptly.prompt('After block: ');
let tokens = {};
let contributors = await kredits.Contributor.all();
contributors.forEach(c => {
tokens[c.id] = { amount: 0, contributor: c };
});
let contributionId = await kredits.Contribution.contract.contributionsCount();
let nextContribution = true;
while (nextContribution) {
console.log(`Getting contribution: ${contributionId}`);
let contribution = await kredits.Contribution.getById(contributionId);
contributionId = contributionId - 1;
// if no conribution is found
if (!contribution.exists) {
nextContribution = false;
break;
}
// check if the contribution is older
// in that case we assume all other contributions now are older
if (contribution.confirmedAtBlock < confirmedAfterBlock) {
nextContribution = false;
}
// if the contribution is within the range count it
if (!contribution.vetoed && contribution.confirmedAtBlock < confirmedBeforeBlock && contribution.confirmedAtBlock > confirmedAfterBlock) {
// init
tokens[contribution.contributorId].amount = tokens[contribution.contributorId].amount + contribution.amount;
}
}
Object.keys(tokens).forEach((contributorId) => {
table.push([
contributorId,
`${tokens[contributorId].contributor.name}`,
`${tokens[contributorId].amount}`
]);
});
const total = Object.keys(tokens).map(cid => { return tokens[cid].amount}).reduce((a,b) => { return a+b }, 0);
console.log(`Total confirmed Kredits: ${total} between block ${confirmedAfterBlock} and ${confirmedBeforeBlock}`);
console.log(table.toString());
} catch (err) {
console.log(err);
}
callback();
}

View File

@@ -41,8 +41,8 @@ module.exports = async function(callback) {
console.log(table.toString());
let totalKreditsEarnedUnConfirmed = await kredits.Contribution.functions.totalKreditsEarned(false);
let totalKreditsEarnedConfirmed = await kredits.Contribution.functions.totalKreditsEarned(true);
let totalKreditsEarnedUnConfirmed = await kredits.Contribution.contract.totalKreditsEarned(false);
let totalKreditsEarnedConfirmed = await kredits.Contribution.contract.totalKreditsEarned(true);
console.log(`Total Kredits: ${totalKreditsEarnedConfirmed} (confirmed) | ${totalKreditsEarnedUnConfirmed} (including unconfirmed)`);
} catch (err) {
console.log(err);

View File

@@ -0,0 +1,52 @@
const promptly = require('promptly');
const Table = require('cli-table');
const initKredits = require('./helpers/init_kredits.js');
module.exports = async function(callback) {
let kredits;
try {
kredits = await initKredits(web3);
} catch(e) {
callback(e);
return;
}
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
const table = new Table({
head: ['ID', 'Amount', 'Token', 'recipientId', 'Confirmed?', 'Vetoed?', 'IPFS', 'Expenses']
})
try {
let blockNumber = await kredits.provider.getBlockNumber();
let reimbursements = await kredits.Reimbursement.all({page: {size: 1000}});
let kreditsSum = 0;
console.log(`Current block number: ${blockNumber}`);
reimbursements.forEach(r => {
const confirmed = r.confirmedAtBlock <= blockNumber;
table.push([
r.id.toString(),
r.amount.toString(),
`${r.token}`,
`${r.recipientId}`,
`${confirmed}`,
`${r.vetoed}`,
`${r.ipfsHash}`,
`${r.expenses.length}`
]);
});
console.log(table.toString());
let totalAmountUnconfirmed = await kredits.Reimbursement.functions.totalAmount(false);
let totalAmountConfirmed = await kredits.Reimbursement.functions.totalAmount(true);
console.log(`Total: ${totalAmountConfirmed} (confirmed) | ${totalAmountUnconfirmed} (including unconfirmed)`);
} catch (err) {
console.log(err);
}
callback();
}

View File

@@ -3,13 +3,15 @@ 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');
module.exports = async function(callback) {
const networkId = await getNetworkId(web3)
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
const signer = provider.getSigner();
const network = await provider.getNetwork();
const networkId = network.chainId;
console.log(`Deploying to networkId: ${networkId}`)
let kitAddresseFile = path.join(addressesPath, 'KreditsKit.json');
@@ -20,9 +22,6 @@ module.exports = async function(callback) {
}
console.log(`Using KreditsKit at: ${kreditsKitAddress}`);
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
let signer = provider.getSigner();
let kit = await new KreditsKit(provider, signer).init()
// TODO: get rid of the hard coded gas limit

View File

@@ -38,7 +38,7 @@ module.exports = async function(callback) {
if (contractWrapper[method]) {
func = contractWrapper[method];
} else {
func = contractWrapper.functions[method];
func = contractWrapper.contract[method];
}
func.apply(contractWrapper, args).then((result) => {
console.log(`[OK] kredits.${contractName}.${method}(${JSON.stringify(args)}) => ${result.hash}`);

View File

@@ -15,7 +15,7 @@ module.exports = async function(callback) {
console.log(`Recording a veto for contribution #${contributionId}`);
try {
kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
kredits.Contribution.contract.veto(contributionId, { gasLimit: 300000 })
.then(result => {
console.log("\n\nResult:");
console.log(result);

View File

@@ -1,88 +0,0 @@
/* eslint-disable no-undef */
const namehash = require('ethers').utils.namehash;
const KreditsKit = artifacts.require("KreditsKit.sol");
const getContract = name => artifacts.require(name);
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
const arapp = require('../arapp.json');
const ENS_ADDRESS = arapp.environments.development.registry;
contract('DAO bare kit', (accounts) => {
let kreditsKit;
let address;
let apps;
let kernel;
let contribution;
let contributor;
let proposal;
let token;
before(async () => {
//apps id
const appsId = [];
appsId[0] = namehash("kredits-contribution");
appsId[1] = namehash("kredits-contributor");
appsId[2] = namehash("kredits-proposal");
appsId[3] = namehash("kredits-token");
const kernelBase = await getContract('Kernel').new(true); // petrify immediately
const aclBase = await getContract('ACL').new();
const daoFactory = await getContract('DAOFactory').new(kernelBase.address, aclBase.address, ZERO_ADDR);
kreditsKit = await KreditsKit.new(daoFactory.address, ENS_ADDRESS, appsId, { from: accounts[0] });
});
describe("New DAO instance", () => {
it("kit should be defined", async () => {
assert.notEqual(kreditsKit, undefined);
});
it('it should deploy DAO', async () => {
const receipt = await kreditsKit.newInstance({ from: accounts[0] });
address = receipt.logs.filter(l => l.event === 'DeployInstance')[0].args.dao;
apps = receipt.logs
.filter(l => l.event === 'InstalledApp')
.map(event => {
return { id: event.args.appId, proxy: event.args.appProxy };
});
address.should.not.equal(ZERO_ADDR);
});
it('it should install apps', async () => {
apps[0].id.should.equal(namehash('kredits-contribution'));
apps[1].id.should.equal(namehash('kredits-contributor'));
apps[2].id.should.equal(namehash('kredits-proposal'));
apps[3].id.should.equal(namehash('kredits-token'));
});
it('it should initialize apps', async () => {
contribution = await getContract('Contribution').at(apps[0].proxy);
contributor = await getContract('Contributor').at(apps[1].proxy);
proposal = await getContract('Proposal').at(apps[2].proxy);
token = await getContract('Token').at(apps[3].proxy);
(await Promise.all([
contribution.hasInitialized(),
contributor.hasInitialized(),
proposal.hasInitialized(),
token.hasInitialized(),
])).should.deep.equal([true, true, true, true]);
});
it('it should set permissions', async () => {
kernel = await getContract('Kernel').at(address);
(await Promise.all([
//check contribution app roles
kernel.hasPermission(accounts[0], contribution.address, await space.ADD_CONTRIBUTION_ROLE(), '0x0'),
kernel.hasPermission(accounts[0], contribution.address, await space.VETO_CONTRIBUTION_ROLE(), '0x0'),
kernel.hasPermission(proposal.address, contribution.address, await space.ADD_CONTRIBUTION_ROLE(), '0x0'),
//proposal app roles
kernel.hasPermission(accounts[0], proposal.address, await proposal.VOTE_PROPOSAL_ROLE(), '0x0'),
//token app roles
kernel.hasPermission(accounts[0], token.address, await token.MINT_TOKEN_ROLE(), '0x0'),
kernel.hasPermission(contribution.address, token.address, await token.MINT_TOKEN_ROLE(), '0x0'),
])).should.deep.equal([true, true, true, true, true, true]);
});
});
});