Compare commits

..

52 Commits

Author SHA1 Message Date
e2d5d704ce fix typo 2019-09-23 00:47:42 +01:00
e0372d3eb4 add kit test script 2019-09-20 09:38:53 +01:00
42c469bbc6 clean 2019-09-16 12:32:22 +01:00
d4b7dbf99d add unit tests 2019-09-13 15:01:53 +01:00
1fd40dbf84 add aragon vault app to KreditsKit 2019-08-27 15:30:35 +01:00
48ff304861 Merge pull request #166 from 67P/dev/remove_yarn_lockfile
Remove yarn lockfiles
2019-08-27 12:34:29 +02:00
1c1a318ae6 Merge pull request #165 from 67P/docs/blocktime
Document how to configure block time for Ganache
2019-08-09 22:10:06 +00:00
580d6e8f51 Remove yarn lockfiles 2019-08-09 19:03:29 +02:00
a572f02b2e Merge pull request #164 from 67P/chore/remove-cached-artifacts
Remove cached artifacts
2019-08-09 19:00:21 +02:00
abd4caa336 Document how to configure block time for Ganache 2019-08-09 18:58:20 +02:00
f1941eb6b8 Remove cached artifacts
Thos should be generated on every contract app deployment and thus don't need to
be in the repo.
We also don't have those for the other contract apps.
2019-08-09 18:46:36 +02:00
ddeeb5ffd7 Merge pull request #162 from 67P/dev/aragon_truffle
Remove Aragon CLI, document system deps
2019-08-09 18:38:40 +02:00
ae71691c5b Install Aragon CLI and Truffle on Travis 2019-08-09 18:26:38 +02:00
819fbc547a Add contract publish options
This removes most of the features we don't need/want and minimizes
prompts during the bootstrap process.
2019-08-09 18:18:36 +02:00
7236b04b4b Remove Aragon CLI, document system deps
In order to prevent regular issues with the notoriously npm-issue-ridden
Aragon CLI module, this removes it as a direct dependency and requires
it to be installed as a system dependency.

Also adds Truffle as a system dependency to the docs (which was missing
before).
2019-08-09 18:04:21 +02:00
f746470cf6 Merge pull request #161 from 67P/fix_typos
Fix a few typos in the README
2019-08-07 16:42:01 +02:00
Greg Karékinian
5452cf2dad Fix a few typos 2019-08-07 15:55:11 +02:00
3c08e3ecfc Merge pull request #160 from 67P/bugfix/packages-install-scripts
Fix package script command deploy:kit
2019-08-04 19:42:42 +02:00
6e8c994a0a Fix package script command deploy:kit 2019-08-04 19:37:31 +02:00
Haythem Sellami
fd844a00fd Test token app (#157)
* test token app
* update travis config
2019-07-31 15:17:38 +00:00
Haythem Sellami
eb4e06edf1 Contributor app tests (#143)
Adds tests for the contributor contract
2019-07-22 06:55:22 +00:00
4ae17aa36f Merge pull request #156 from haythem96/refactor-get-contract
Refactor get apps contract functions
2019-07-22 06:54:05 +00:00
e14cb0a77d refactor get apps contract functions 2019-07-20 15:06:17 +01:00
d92ad83379 Merge pull request #155 from 67P/bugfix/send-for-new-web3
Fix send-funds script to use new web3 API
2019-07-19 09:11:55 +00:00
fa3e99d404 Fix send-funds script to use new web3 API
The API changed with the recent aragon/truffle update.
2019-07-18 16:25:06 +02:00
4aa5f3aa89 Merge pull request #151 from 67P/chore/remove-ipfs-pinner
Remove IPFS pinner
2019-07-03 12:50:59 +02:00
2316e8f15a Remove IPFS pinner
The pinner now lives in its own npm package
2019-07-02 19:09:26 +02:00
87a468bc91 5.4.0 2019-07-02 16:27:26 +02:00
0734acbcbe Merge pull request #149 from 67P/feature/support-ipfs-gateway
Add support to use IPFS gateway to read ipfs data
2019-07-01 15:41:07 +00:00
a45c8d14be Downgrade IPFS package
The new version uses generators which breaks the build on kredits-web.
2019-07-01 16:12:22 +02:00
61fe9add1b Add support to use IPFS gateway to read ipfs data
This makes caching of IPFS documents easier. Browsers should cache those
by default
2019-07-01 15:53:18 +02:00
16141ed482 Merge pull request #136 from 67P/feature/ipfs-pinner
Add IPFS pinning script
2019-07-01 13:06:45 +02:00
01ef37fd39 Merge pull request #147 from 67P/bugfix/compile_all
Fix compile command
2019-07-01 10:30:41 +00:00
03b9f69d22 Fix compile command
The Aragon one is failing now, but just using the underlying Truffle
command works. So it appears to be the passing of the argument in aragon
that's broken.

Co-authored-by: Michael Bumann <hello@michaelbumann.com>
2019-07-01 12:24:56 +02:00
dd76ebdc8d Merge pull request #141 from haythem96/setup-tests
Solidity test setup
2019-06-26 15:05:23 +00:00
e485bd90c0 install packages 2019-06-19 14:34:14 +01:00
1d89759c49 merge 2019-06-19 13:47:58 +01:00
d653b3715f Update package-lock 2019-06-19 14:10:44 +02:00
a05e2c75f3 Merge pull request #142 from 67P/chore/update-dependencies-2
Chore/update aragon-cli dependencies
2019-06-19 08:39:06 +00:00
124287b977 Updated latest package-json 2019-06-19 01:00:53 +02:00
9906fde7ef Use postshrinkwrap instead of postinstall
`postinstall` is executed before package-lock.json is written to disk.

https://github.com/npm/npm/issues/18798
2019-06-19 00:52:48 +02:00
c7e1f118a6 Add postinstall lockfile fix
https://github.com/67P/kredits-contracts/pull/140
2019-06-19 00:52:47 +02:00
1702c22084 Make sure fix lockfile uses the correct file path 2019-06-19 00:52:47 +02:00
32a123a825 Default to open.aragonpm.eth
it is now also available on the devchain
2019-06-19 00:52:47 +02:00
ac83573438 I don't know why this is needed but it fixes an npm issue
if install fails node scripts/fix-package-lock.js might help
2019-06-19 00:52:47 +02:00
77c6c11800 Remove npm cache and use LTS node on travis 2019-06-19 00:52:05 +02:00
ca0a6f6ef9 user 7545 port for tests 2019-06-17 23:35:53 +01:00
4614c454a5 test setup 2019-06-17 12:13:35 +01:00
9fd9dbc1b5 Handle errors in IPFS pin script 2019-06-13 18:31:47 +02:00
6d6c6056f0 Refactor IPFS pinner 2019-06-12 01:08:07 +02:00
b09c2830c8 Make IPFS node configurable 2019-06-11 23:45:27 +02:00
fc5a41123a Add IPFS pinning script
This script loads the IPFS hashes for contributors and contributions and
pins them on the connected IPFS node.

usage:

    $ node script/ipfs-pinner.js

    $ ETH_RPC_URL=http://localhost:7547 APM_DOMAIN=aragonpm.eth node scripts/ipfs.pinner.js
2019-06-11 21:48:50 +02:00
38 changed files with 7224 additions and 73541 deletions

View File

@@ -28,5 +28,6 @@ module.exports = {
named: 'always', named: 'always',
asyncArrow: 'always', asyncArrow: 'always',
}], }],
'indent': ['error', 2]
} }
} }

View File

@@ -6,13 +6,27 @@ node_js:
sudo: false sudo: false
dist: xenial dist: xenial
cache:
directories:
- node_modules
- apps/contribution/node_modules
- apps/contributor/node_modules
- apps/proposal/node_modules
- apps/token/node_modules
- apps/vault/node_modules
install: install:
- npm install -g @aragon/cli
- npm install -g truffle
- npm install - npm install
before_script:
- npm run devchain &
script: script:
- npm run lint:wrapper - npm run lint:wrapper
- npm run lint:contract-tests - npm run lint:contract-tests
# - yarn lint:contracts - npm run test
branches: branches:
only: only:

View File

@@ -14,6 +14,8 @@ framework](http://truffleframework.com/) for some things.
### Installation ### Installation
#### App dependencies
All requirements are defined in `package.json`. All requirements are defined in `package.json`.
$ npm install $ npm install
@@ -25,13 +27,20 @@ Each of the aragon apps are separate packages:
You can use `npm run install-all` to install all app dependencies at once. You can use `npm run install-all` to install all app dependencies at once.
#### Sytem dependencies
Aragon CLI and Truffle need to be installed on your sytem as well:
npm install -g @aragon/cli
npm install -g truffle
### Local development chain ### Local development chain
For local development it is recommended to use For local development it is recommended to use
[ganache](http://truffleframework.com/ganache/) to run a local development [ganache](http://truffleframework.com/ganache/) to run a local development
chain. Using the ganache simulator no full Ethereum node is required. chain. When using the ganache simulator, no full Ethereum node is required.
We use the default aragon-cli devchain command to confgure and run a local We use the default aragon-cli devchain command to configure and run a local
development ganache. development ganache.
$ npm run devchain (or aragon devchain --port 7545) $ npm run devchain (or aragon devchain --port 7545)
@@ -43,6 +52,10 @@ To clear/reset the chain use (e.g. if you run out of funds on your devchain)
We default to port 7545 for development to not get in conflict with the default We default to port 7545 for development to not get in conflict with the default
Ethereum RPC port. Ethereum RPC port.
You can also set certain ganache options to configure the devchain, for example
if you want to increase the block time to 10 seconds you can add
`--block-time=10`.
### Bootstrap ### Bootstrap
1. Run an Ethereum node and ipfs 1. Run an Ethereum node and ipfs
@@ -60,7 +73,7 @@ Ethereum RPC port.
$ npm run deploy:kit $ npm run deploy:kit
$ npm run deploy:dao $ npm run deploy:dao
4. Execute seeds to create demo contributors, contributons, etc. (optional) 4. Execute seeds to create demo contributors, contributions, etc. (optional)
$ npm run seeds $ npm run seeds
@@ -163,7 +176,7 @@ Creates and configures a new DAO instance.
or or
$ npm run deploy:dao $ npm run deploy:dao
KreditsKit address is load from `lib/addresses/KreditsKit.json` or can be KreditsKit address is loaded from `lib/addresses/KreditsKit.json` or can be
configured through the `KREDITS_KIT` environment variable. configured through the `KREDITS_KIT` environment variable.
### deploy-apps.sh ### deploy-apps.sh
@@ -198,7 +211,7 @@ make sure all apps and the KreditsKit are deployed, then create a new DAO:
## Upgradeable contracts ## Upgradeable contracts
We use aragonOS for upgradeablity of the different contracts. Refer to the We use aragonOS for upgradeability of the different contracts. Refer to the
[aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro) [aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro)
for more details. for more details.

View File

@@ -1,912 +0,0 @@
{
"roles": [
{
"name": "Add contributions",
"id": "ADD_CONTRIBUTION_ROLE",
"params": [],
"bytes": "0x493d28cd0d82bcb20db66e4f6390a00122ef772717e282b436ba3240af18bfb1"
},
{
"name": "Manage token contract",
"id": "MANAGE_TOKEN_CONTRACT_ROLE",
"params": [],
"bytes": "0xdd275187bc43df45ce7b34f6716e572716c69ad44e5e496175008950f032854b"
},
{
"name": "Veto contributions",
"id": "VETO_CONTRIBUTION_ROLE",
"params": [],
"bytes": "0x495a36de1ed34d5c1b9f8704e7d8bc8badb027221b09c79691d430bc54c4c88f"
}
],
"environments": {
"default": {
"network": "development",
"appName": "kredits-contribution.open.aragonpm.eth"
}
},
"path": "contracts/Contribution.sol",
"appName": "kredits-contribution.open.aragonpm.eth",
"appId": "0x09f5274cba299b46c5be722ef672d10eef7a2ef980b612aef529d74fb9da7643",
"abi": [
{
"constant": true,
"inputs": [],
"name": "hasInitialized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "ADD_CONTRIBUTION_ROLE",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_script",
"type": "bytes"
}
],
"name": "getEVMScriptExecutor",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getRecoveryVault",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "contributionsCount",
"outputs": [
{
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "token",
"type": "address"
}
],
"name": "allowRecoverability",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "appId",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getInitializationBlock",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "KERNEL_APP_ADDR_NAMESPACE",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "transferToVault",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_sender",
"type": "address"
},
{
"name": "_role",
"type": "bytes32"
},
{
"name": "_params",
"type": "uint256[]"
}
],
"name": "canPerform",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getEVMScriptRegistry",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint32"
}
],
"name": "contributionOwner",
"outputs": [
{
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint32"
}
],
"name": "contributions",
"outputs": [
{
"name": "contributorId",
"type": "uint32"
},
{
"name": "amount",
"type": "uint32"
},
{
"name": "claimed",
"type": "bool"
},
{
"name": "hashDigest",
"type": "bytes32"
},
{
"name": "hashFunction",
"type": "uint8"
},
{
"name": "hashSize",
"type": "uint8"
},
{
"name": "tokenMetadataURL",
"type": "string"
},
{
"name": "confirmedAtBlock",
"type": "uint256"
},
{
"name": "vetoed",
"type": "bool"
},
{
"name": "exists",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint32"
},
{
"name": "",
"type": "uint256"
}
],
"name": "ownedContributions",
"outputs": [
{
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "kernel",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "blocksToWait",
"outputs": [
{
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "isPetrified",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint256"
}
],
"name": "appIds",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "VETO_CONTRIBUTION_ROLE",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "id",
"type": "uint32"
},
{
"indexed": true,
"name": "contributorId",
"type": "uint32"
},
{
"indexed": false,
"name": "amount",
"type": "uint32"
}
],
"name": "ContributionAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "id",
"type": "uint32"
},
{
"indexed": true,
"name": "contributorId",
"type": "uint32"
},
{
"indexed": false,
"name": "amount",
"type": "uint32"
}
],
"name": "ContributionClaimed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "id",
"type": "uint32"
},
{
"indexed": false,
"name": "vetoedByAccount",
"type": "address"
}
],
"name": "ContributionVetoed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "executor",
"type": "address"
},
{
"indexed": false,
"name": "script",
"type": "bytes"
},
{
"indexed": false,
"name": "input",
"type": "bytes"
},
{
"indexed": false,
"name": "returnData",
"type": "bytes"
}
],
"name": "ScriptResult",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "vault",
"type": "address"
},
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "amount",
"type": "uint256"
}
],
"name": "RecoverToVault",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "_appIds",
"type": "bytes32[4]"
}
],
"name": "initialize",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getTokenContract",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getContributorContract",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributorAccount",
"type": "address"
}
],
"name": "getContributorIdByAddress",
"outputs": [
{
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributorId",
"type": "uint32"
}
],
"name": "getContributorAddressById",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributionId",
"type": "uint32"
}
],
"name": "ownerOf",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "index",
"type": "uint32"
}
],
"name": "tokenOfOwnerByIndex",
"outputs": [
{
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributionId",
"type": "uint32"
}
],
"name": "tokenMetadata",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "confirmedOnly",
"type": "bool"
}
],
"name": "totalKreditsEarned",
"outputs": [
{
"name": "amount",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributorId",
"type": "uint32"
},
{
"name": "confirmedOnly",
"type": "bool"
}
],
"name": "totalKreditsEarnedByContributor",
"outputs": [
{
"name": "amount",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributionId",
"type": "uint32"
}
],
"name": "getContribution",
"outputs": [
{
"name": "id",
"type": "uint32"
},
{
"name": "contributorId",
"type": "uint32"
},
{
"name": "amount",
"type": "uint32"
},
{
"name": "claimed",
"type": "bool"
},
{
"name": "hashDigest",
"type": "bytes32"
},
{
"name": "hashFunction",
"type": "uint8"
},
{
"name": "hashSize",
"type": "uint8"
},
{
"name": "confirmedAtBlock",
"type": "uint256"
},
{
"name": "exists",
"type": "bool"
},
{
"name": "vetoed",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "amount",
"type": "uint32"
},
{
"name": "contributorId",
"type": "uint32"
},
{
"name": "hashDigest",
"type": "bytes32"
},
{
"name": "hashFunction",
"type": "uint8"
},
{
"name": "hashSize",
"type": "uint8"
}
],
"name": "add",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "contributionId",
"type": "uint32"
}
],
"name": "veto",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "contributionId",
"type": "uint32"
}
],
"name": "claim",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "contributionId",
"type": "uint32"
}
],
"name": "exists",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
"deployment": {
"contractName": "Contribution",
"compiledAt": "2019-06-13T12:39:07.659Z",
"compiler": {
"name": "solc",
"version": "0.4.24+commit.e67f0147.Emscripten.clang",
"optimizer": {
"enabled": false
}
},
"flattenedCode": "./code.sol",
"transactionHash": "0x073057bb616243e415823fa9a8c8cc096b573fbd0bbf11c2f59bb75a84291689"
},
"functions": [
{
"sig": "mintFor(address,uint256,uint32)",
"roles": [],
"notice": null
},
{
"sig": "initialize(bytes32[4])",
"roles": [],
"notice": null
},
{
"sig": "add(uint32,uint32,bytes32,uint8,uint8)",
"roles": [
"ADD_CONTRIBUTION_ROLE"
],
"notice": null
},
{
"sig": "veto(uint32)",
"roles": [
"VETO_CONTRIBUTION_ROLE"
],
"notice": null
},
{
"sig": "claim(uint32)",
"roles": [],
"notice": null
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,8 @@ contract Contribution is AragonApp {
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb; bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
// ensure alphabetic order // ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token } enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[4] public appIds; bytes32[5] public appIds;
struct ContributionData { struct ContributionData {
uint32 contributorId; uint32 contributorId;
@@ -54,29 +54,24 @@ contract Contribution is AragonApp {
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount); event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
event ContributionVetoed(uint32 id, address vetoedByAccount); event ContributionVetoed(uint32 id, address vetoedByAccount);
function initialize(bytes32[4] _appIds) public onlyInit { function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds; appIds = _appIds;
blocksToWait = 40320; // 7 days; 15 seconds block time blocksToWait = 40320; // 7 days; 15 seconds block time
initialized(); initialized();
} }
// TODO refactor into a single function function getContract(uint8 appId) public view returns (address) {
function getTokenContract() public view returns (address) {
IKernel k = IKernel(kernel()); IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]); return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
}
function getContributorContract() public view returns (address) {
IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contributor)]);
} }
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) { function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
address contributor = getContributorContract(); address contributor = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributor).getContributorIdByAddress(contributorAccount); return ContributorInterface(contributor).getContributorIdByAddress(contributorAccount);
} }
function getContributorAddressById(uint32 contributorId) public view returns (address) { function getContributorAddressById(uint32 contributorId) public view returns (address) {
address contributor = getContributorContract(); address contributor = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributor).getContributorAddressById(contributorId); return ContributorInterface(contributor).getContributorAddressById(contributorId);
} }
@@ -198,14 +193,14 @@ contract Contribution is AragonApp {
require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE'); require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE');
c.claimed = true; c.claimed = true;
address token = getTokenContract(); address token = getContract(uint8(Apps.Token));
address contributorAccount = getContributorAddressById(c.contributorId); address contributorAccount = getContributorAddressById(c.contributorId);
uint256 amount = uint256(c.amount); uint256 amount = uint256(c.amount);
IToken(token).mintFor(contributorAccount, amount, contributionId); IToken(token).mintFor(contributorAccount, amount, contributionId);
emit ContributionClaimed(contributionId, c.contributorId, c.amount); emit ContributionClaimed(contributionId, c.contributorId, c.amount);
} }
function exists(uint32 contributionId) view public returns (bool) { function exists(uint32 contributionId) public view returns (bool) {
return contributions[contributionId].exists; return contributions[contributionId].exists;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,13 +6,17 @@
"@aragon/os": "^4.2.0", "@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6" "@aragon/cli": "^5.9.6"
}, },
"devDependencies": {}, "devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11"
},
"scripts": { "scripts": {
"start": "npm run start:aragon:ipfs", "start": "npm run start:aragon:ipfs",
"start:aragon:ipfs": "aragon run", "start:aragon:ipfs": "aragon run",
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist", "start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
"start:app": "", "start:app": "",
"test": "aragon contracts test",
"compile": "aragon contracts compile", "compile": "aragon contracts compile",
"sync-assets": "", "sync-assets": "",
"build:app": "", "build:app": "",
@@ -21,7 +25,8 @@
"publish:patch": "aragon apm publish patch", "publish:patch": "aragon apm publish patch",
"publish:minor": "aragon apm publish minor", "publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major", "publish:major": "aragon apm publish major",
"versions": "aragon apm versions" "versions": "aragon apm versions",
"test": "aragon contracts test"
}, },
"keywords": [] "keywords": []
} }

File diff suppressed because it is too large Load Diff

View File

@@ -28,32 +28,25 @@ contract Contributor is AragonApp {
uint32 public contributorsCount; uint32 public contributorsCount;
// ensure alphabetic order // ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token } enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[4] public appIds; bytes32[5] public appIds;
event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount); event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
event ContributorAdded(uint32 id, address account); 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; appIds = _appIds;
initialized(); initialized();
} }
function getTokenContract() public view returns (address) { function getContract(uint8 appId) public view returns (address) {
IKernel k = IKernel(kernel()); IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]);
} }
function getContributionContract() public view returns (address) { function coreContributorsCount() public view returns (uint32) {
IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contribution)]);
}
function coreContributorsCount() view public returns (uint32) {
uint32 count = 0; uint32 count = 0;
for (uint32 i = 1; i <= contributorsCount; i++) { for (uint32 i = 1; i <= contributorsCount; i++) {
if (isCoreTeam(i)) { if (isCoreTeam(i)) {
@@ -64,10 +57,13 @@ contract Contributor is AragonApp {
} }
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public auth(MANAGE_CONTRIBUTORS_ROLE) { function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public auth(MANAGE_CONTRIBUTORS_ROLE) {
require(newAccount != address(0), "invalid new account address");
require(getContributorAddressById(id) == oldAccount, "contributor does not exist");
contributorIds[oldAccount] = 0; contributorIds[oldAccount] = 0;
contributorIds[newAccount] = id; contributorIds[newAccount] = id;
contributors[id].account = newAccount; contributors[id].account = newAccount;
ContributorAccountUpdated(id, oldAccount, newAccount); emit ContributorAccountUpdated(id, oldAccount, newAccount);
} }
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) { function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
@@ -136,9 +132,9 @@ contract Contributor is AragonApp {
hashFunction = c.hashFunction; hashFunction = c.hashFunction;
hashSize = c.hashSize; hashSize = c.hashSize;
isCore = isCoreTeam(id); isCore = isCoreTeam(id);
address token = getTokenContract(); address token = getContract(uint8(Apps.Token));
balance = ITokenBalance(token).balanceOf(c.account); balance = ITokenBalance(token).balanceOf(c.account);
address contribution = getContributionContract(); address contribution = getContract(uint8(Apps.Contribution));
totalKreditsEarned = IContributionBalance(contribution).totalKreditsEarnedByContributor(_id, true); totalKreditsEarned = IContributionBalance(contribution).totalKreditsEarnedByContributor(_id, true);
contributionsCount = IContributionBalance(contribution).balanceOf(c.account); contributionsCount = IContributionBalance(contribution).balanceOf(c.account);
exists = c.exists; exists = c.exists;

View File

@@ -0,0 +1,16 @@
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 {
// ...
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,13 +6,17 @@
"@aragon/os": "^4.2.0", "@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6" "@aragon/cli": "^5.9.6"
}, },
"devDependencies": {}, "devDependencies": {
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11",
"@aragon/test-helpers": "^2.0.0"
},
"scripts": { "scripts": {
"start": "npm run start:aragon:ipfs", "start": "npm run start:aragon:ipfs",
"start:aragon:ipfs": "aragon run", "start:aragon:ipfs": "aragon run",
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist", "start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
"start:app": "", "start:app": "",
"test": "aragon contracts test",
"compile": "aragon contracts compile", "compile": "aragon contracts compile",
"sync-assets": "", "sync-assets": "",
"build:app": "", "build:app": "",
@@ -21,7 +25,8 @@
"publish:patch": "aragon apm publish patch", "publish:patch": "aragon apm publish patch",
"publish:minor": "aragon apm publish minor", "publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major", "publish:major": "aragon apm publish major",
"versions": "aragon apm versions" "versions": "aragon apm versions",
"test": "aragon contracts test"
}, },
"keywords": [] "keywords": []
} }

View File

@@ -1,5 +0,0 @@
// const Contributor = artifacts.require('Contributor.sol');
contract('Contributor', (_accounts) => {
it('should be tested');
});

View File

@@ -0,0 +1,170 @@
const namehash = require('ethers').utils.namehash;
// eslint-disable-next-line no-undef
const Contributor = artifacts.require("Contributor.sol");
// eslint-disable-next-line no-undef
const getContract = name => artifacts.require(name);
const { assertRevert } = require('@aragon/test-helpers/assertThrow');
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
contract('Contributor app', (accounts) => {
let kernelBase, aclBase, daoFactory, r, dao, acl, contributor;
const root = accounts[0];
const member1 = accounts[1];
// eslint-disable-next-line no-undef
before(async () => {
kernelBase = await getContract('Kernel').new(true); // petrify immediately
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());
//create dao mamnager permission for coin owner
await acl.createPermission(
root,
dao.address,
await dao.APP_MANAGER_ROLE(),
root,
{ from: root }
);
//get new app instance from DAO
const receipt = await dao.newAppInstance(
'0x1234',
(await Contributor.new()).address,
0x0,
false,
{ from: root }
);
contributor = Contributor.at(
receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
);
//apps id
let appsId = [];
appsId[0] = namehash("kredits-contribution");
appsId[1] = namehash("kredits-contributor");
appsId[2] = namehash("kredits-proposal");
appsId[3] = namehash("kredits-token");
//init contributor (app)
await contributor.initialize(root, appsId);
//create manage contributors role
await acl.createPermission(
root,
contributor.address,
await contributor.MANAGE_CONTRIBUTORS_ROLE(),
root,
{ from: root }
);
});
describe("Owner default permissions", async () => {
it('check owner is contributors manager', async () => {
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 () => {
let account = root;
let hashDigest = '0x0';
let hashFunction = 0;
let hashSize = 0;
it("should revert when add contributor from an address that does not have permission", async () => {
return assertRevert(async () => {
await contributor.addContributor(account, hashDigest, hashFunction, hashSize, { from: member1});
'sender does not have permission';
});
});
it('add contributor', async () => {
let contributorCount = await contributor.coreContributorsCount();
await contributor.addContributor(account, hashDigest, hashFunction, hashSize);
// eslint-disable-next-line no-undef
assert.equal(await contributor.addressExists(account), true);
let contributorCountAfter = await contributor.coreContributorsCount();
// eslint-disable-next-line no-undef
assert.equal(await contributorCountAfter.toNumber(), parseInt(contributorCount)+1);
});
it("should revert when add contributor with an address that already exist", async () => {
return assertRevert(async () => {
await contributor.addContributor(account, hashDigest, hashFunction, hashSize, { from: member1});
'address already exist';
});
});
});
describe("Update contributor", async () => {
let id;
let oldAccount;
let newAccount;
let hashDigest;
let hashFunction;
let hashSize;
// eslint-disable-next-line no-undef
before(async () => {
id = await contributor.coreContributorsCount();
oldAccount = root;
newAccount = member1;
hashDigest = '0x1000000000000000000000000000000000000000000000000000000000000000';
hashFunction = 1;
hashSize = 1;
});
it('update contributor account', async () => {
await contributor.updateContributorAccount(id.toNumber(), oldAccount, newAccount);
let contributorId = await contributor.getContributorIdByAddress(oldAccount);
// eslint-disable-next-line no-undef
assert.equal(contributorId.toNumber(), 0);
});
it("should revert when update contributor account from address that does not have permission", async () => {
return assertRevert(async () => {
await contributor.updateContributorAccount(id.toNumber(), oldAccount, newAccount, {from: member1});
'sender does not have permission';
});
});
it("should revert when update contributor account that does not exist", async () => {
return assertRevert(async () => {
await contributor.updateContributorAccount(id.toNumber(), accounts[3], newAccount);
'contributor does not exist';
});
});
it("should revert when update contributor account with address(0)", async () => {
return assertRevert(async () => {
await contributor.updateContributorAccount(id.toNumber(), oldAccount, ZERO_ADDR);
'contributor does not exist';
});
});
it('update contributor profile hash', async () => {
await contributor.updateContributorProfileHash(id.toNumber(), hashDigest, hashFunction, hashSize);
let contributorProfile = await contributor.contributors(id.toNumber());
assert.equal(hashDigest, contributorProfile[1]); // eslint-disable-line no-undef
assert.equal(hashFunction, contributorProfile[2].toNumber()); // eslint-disable-line no-undef
assert.equal(hashSize, contributorProfile[3].toNumber()); // eslint-disable-line no-undef
});
it("should revert when update contributor profile hash from address that does not have permission", async () => {
return assertRevert(async () => {
await contributor.updateContributorProfileHash(id.toNumber(), hashDigest, hashFunction, hashSize, {from: member1});
'sender does not have permission';
});
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,8 @@ contract Proposal is AragonApp {
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb; bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
// ensure alphabetic order // ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token } enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[4] public appIds; bytes32[5] public appIds;
struct Proposal { struct Proposal {
address creatorAccount; address creatorAccount;
@@ -46,21 +46,18 @@ contract Proposal is AragonApp {
event ProposalVoted(uint32 id, uint32 voterId, uint16 totalVotes); event ProposalVoted(uint32 id, uint32 voterId, uint16 totalVotes);
event ProposalExecuted(uint32 id, uint32 contributorId, uint32 amount); event ProposalExecuted(uint32 id, uint32 contributorId, uint32 amount);
function initialize(bytes32[4] _appIds) public onlyInit { function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds; appIds = _appIds;
initialized(); initialized();
} }
function getContributorContract() public view returns (address) { function getContract(uint8 appId) public view returns (address) {
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contributor)]); IKernel k = IKernel(kernel());
} return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
function getContributionContract() public view returns (address) {
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contribution)]);
} }
function addProposal(uint32 contributorId, uint32 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_PROPOSAL_ROLE) { function addProposal(uint32 contributorId, uint32 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_PROPOSAL_ROLE) {
require(IContributor(getContributorContract()).exists(contributorId), 'CONTRIBUTOR_NOT_FOUND'); require(IContributor(getContract(uint8(Apps.Contributor))).exists(contributorId), 'CONTRIBUTOR_NOT_FOUND');
uint32 proposalId = proposalsCount + 1; uint32 proposalId = proposalsCount + 1;
uint16 _votesNeeded = 1; //contributorsContract().coreContributorsCount() / 100 * 75; uint16 _votesNeeded = 1; //contributorsContract().coreContributorsCount() / 100 * 75;
@@ -69,10 +66,10 @@ contract Proposal is AragonApp {
p.creatorAccount = msg.sender; p.creatorAccount = msg.sender;
p.contributorId = contributorId; p.contributorId = contributorId;
p.amount = amount; p.amount = amount;
p.hashDigest = hashDigest; p.hashDigest = hashDigest;
p.hashFunction = hashFunction; p.hashFunction = hashFunction;
p.hashSize = hashSize; p.hashSize = hashSize;
p.votesCount = 0; p.votesCount = 0;
p.votesNeeded = _votesNeeded; p.votesNeeded = _votesNeeded;
p.exists = true; p.exists = true;
@@ -102,7 +99,7 @@ contract Proposal is AragonApp {
function vote(uint32 proposalId) public isInitialized auth(VOTE_PROPOSAL_ROLE) { function vote(uint32 proposalId) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
Proposal storage p = proposals[proposalId]; Proposal storage p = proposals[proposalId];
require(!p.executed, 'ALREADY_EXECUTED'); require(!p.executed, 'ALREADY_EXECUTED');
uint32 voterId = IContributor(getContributorContract()).getContributorIdByAddress(msg.sender); uint32 voterId = IContributor(getContract(uint8(Apps.Contributor))).getContributorIdByAddress(msg.sender);
require(p.votes[voterId] != true, 'ALREADY_VOTED'); require(p.votes[voterId] != true, 'ALREADY_VOTED');
p.voterIds.push(voterId); p.voterIds.push(voterId);
p.votes[voterId] = true; p.votes[voterId] = true;
@@ -126,7 +123,7 @@ contract Proposal is AragonApp {
require(p.votesCount >= p.votesNeeded, 'MISSING_VOTES'); require(p.votesCount >= p.votesNeeded, 'MISSING_VOTES');
p.executed = true; p.executed = true;
IContribution(getContributionContract()).add(p.amount, p.contributorId, p.hashDigest, p.hashFunction, p.hashSize); IContribution(getContract(uint8(Apps.Contribution))).add(p.amount, p.contributorId, p.hashDigest, p.hashFunction, p.hashSize);
emit ProposalExecuted(proposalId, p.contributorId, p.amount); emit ProposalExecuted(proposalId, p.contributorId, p.amount);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,13 +6,17 @@
"@aragon/os": "^4.2.0", "@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6" "@aragon/cli": "^5.9.6"
}, },
"devDependencies": {}, "devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11"
},
"scripts": { "scripts": {
"start": "npm run start:aragon:ipfs", "start": "npm run start:aragon:ipfs",
"start:aragon:ipfs": "aragon run", "start:aragon:ipfs": "aragon run",
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist", "start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
"start:app": "", "start:app": "",
"test": "aragon contracts test",
"compile": "aragon contracts compile", "compile": "aragon contracts compile",
"sync-assets": "", "sync-assets": "",
"build:app": "", "build:app": "",
@@ -21,7 +25,8 @@
"publish:patch": "aragon apm publish patch", "publish:patch": "aragon apm publish patch",
"publish:minor": "aragon apm publish minor", "publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major", "publish:major": "aragon apm publish major",
"versions": "aragon apm versions" "versions": "aragon apm versions",
"test": "aragon contracts test"
}, },
"keywords": [] "keywords": []
} }

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"); bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
// ensure alphabetic order // ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token } enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[4] public appIds; bytes32[5] public appIds;
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId); 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; appIds = _appIds;
name = 'Kredits'; name = 'Kredits';
symbol = '₭S'; symbol = '₭S';
@@ -21,6 +21,8 @@ contract Token is ERC20Token, AragonApp {
} }
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) { function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) {
require(amount > 0, "INVALID_AMOUNT");
uint256 amountInWei = amount.mul(1 ether); uint256 amountInWei = amount.mul(1 ether);
_mint(contributorAccount, amountInWei); _mint(contributorAccount, amountInWei);
emit LogMint(contributorAccount, amount, contributionId); emit LogMint(contributorAccount, amount, contributionId);

View File

@@ -0,0 +1,16 @@
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 {
// ...
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,13 +6,17 @@
"@aragon/os": "^4.2.0", "@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6" "@aragon/cli": "^5.9.6"
}, },
"devDependencies": {}, "devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11"
},
"scripts": { "scripts": {
"start": "npm run start:aragon:ipfs", "start": "npm run start:aragon:ipfs",
"start:aragon:ipfs": "aragon run", "start:aragon:ipfs": "aragon run",
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist", "start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
"start:app": "", "start:app": "",
"test": "aragon contracts test",
"compile": "aragon contracts compile", "compile": "aragon contracts compile",
"sync-assets": "", "sync-assets": "",
"build:app": "", "build:app": "",
@@ -21,7 +25,8 @@
"publish:patch": "aragon apm publish patch", "publish:patch": "aragon apm publish patch",
"publish:minor": "aragon apm publish minor", "publish:minor": "aragon apm publish minor",
"publish:major": "aragon apm publish major", "publish:major": "aragon apm publish major",
"versions": "aragon apm versions" "versions": "aragon apm versions",
"test": "aragon contracts test"
}, },
"keywords": [] "keywords": []
} }

View File

@@ -1,5 +0,0 @@
// const Token = artifacts.require('Token.sol');
contract('Token', (_accounts) => {
it('should be tested');
});

123
apps/token/test/token.js Normal file
View File

@@ -0,0 +1,123 @@
const namehash = require('ethers').utils.namehash;
// eslint-disable-next-line no-undef
const Token = artifacts.require("Token.sol");
// eslint-disable-next-line no-undef
const getContract = name => artifacts.require(name);
const { assertRevert } = require('@aragon/test-helpers/assertThrow');
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
contract('Token app', (accounts) => {
let kernelBase, aclBase, daoFactory, dao, r, acl, token;
const root = accounts[0];
const member1 = accounts[1];
// eslint-disable-next-line no-undef
before(async () => {
kernelBase = await getContract('Kernel').new(true); // petrify immediately
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());
//create dao mamnager permission for coin owner
await acl.createPermission(
root,
dao.address,
await dao.APP_MANAGER_ROLE(),
root,
{ from: root }
);
//get new app instance from DAO
const receipt = await dao.newAppInstance(
'0x1234',
(await Token.new()).address,
0x0,
false,
{ from: root }
);
token = Token.at(
receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
);
//apps id
let appsId = [];
appsId[0] = namehash("kredits-contribution");
appsId[1] = namehash("kredits-contributor");
appsId[2] = namehash("kredits-proposal");
appsId[3] = namehash("kredits-token");
//init token (app)
await token.initialize(appsId);
//create token mint permission for coin owner
await acl.createPermission(
root,
token.address,
await token.MINT_TOKEN_ROLE(),
root,
{ from: root }
);
});
describe("Owner default space permissions", async () => {
it('check owner is token issuer', async () => {
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 () => {
let name = "Kredits";
let symbol = "₭S";
let decimals = 18;
it("check token properties", async () => {
assert.equal(await token.name(), name); // eslint-disable-line no-undef
assert.equal(await token.symbol(), symbol); // eslint-disable-line no-undef
assert.equal(await token.decimals(), decimals); // eslint-disable-line no-undef
});
});
describe("Token minting", async () => {
let tokenToMint = 250;
let ether = 1000000000000000000;
it("should revert when mint tokens from an address that does not have minting permission", async () => {
return assertRevert(async () => {
await token.mintFor(root, tokenToMint, 1, { from: member1});
'address does not have permission to mint tokens';
});
});
it("should revert when mint tokens to address(0)", async () => {
return assertRevert(async () => {
await token.mintFor(ZERO_ADDR, tokenToMint, 1, { from: root});
'invalid contributor address';
});
});
it("should revert when mint amount of tokens equal to 0", async () => {
return assertRevert(async () => {
await token.mintFor(root, 0, 1, { from: root});
'amount to mint should be greater than zero';
});
});
it("mint tokens", async () => {
await token.mintFor(root, tokenToMint, 1, { from: root });
let ownerBalance = await token.balanceOf(root);
let totalSupply = await token.totalSupply();
assert.equal(ownerBalance.toNumber(), tokenToMint*ether); // eslint-disable-line no-undef
assert.equal(totalSupply.toNumber(), tokenToMint*ether); // eslint-disable-line no-undef
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,8 @@ import "@aragon/os/contracts/acl/ACL.sol";
import "@aragon/kits-base/contracts/KitBase.sol"; import "@aragon/kits-base/contracts/KitBase.sol";
import "@aragon/apps-vault/contracts/Vault.sol";
import "../apps/contribution/contracts/Contribution.sol"; import "../apps/contribution/contracts/Contribution.sol";
import "../apps/contributor/contracts/Contributor.sol"; import "../apps/contributor/contracts/Contributor.sol";
import "../apps/token/contracts/Token.sol"; import "../apps/token/contracts/Token.sol";
@@ -14,13 +16,13 @@ import "../apps/proposal/contracts/Proposal.sol";
contract KreditsKit is KitBase { contract KreditsKit is KitBase {
// ensure alphabetic order // ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token } enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[4] public appIds; bytes32[5] public appIds;
event DeployInstance(address dao); event DeployInstance(address dao);
event InstalledApp(address dao, address appProxy, bytes32 appId); 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; appIds = _appIds;
} }
@@ -44,6 +46,9 @@ contract KreditsKit is KitBase {
Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)])); Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)]));
proposal.initialize(appIds); proposal.initialize(appIds);
Vault vault = Vault(_installApp(dao, appIds[uint8(Apps.Vault)]));
vault.initialize();
acl.createPermission(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), this); acl.createPermission(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), this);
acl.createPermission(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), this); acl.createPermission(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), this);
acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE()); acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE());
@@ -72,6 +77,10 @@ contract KreditsKit is KitBase {
acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE()); acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE());
acl.setPermissionManager(root, token, token.MINT_TOKEN_ROLE()); acl.setPermissionManager(root, token, token.MINT_TOKEN_ROLE());
// Vault permissions
acl.createPermission(root, vault, vault.TRANSFER_ROLE(), this);
//TODO: grant rewards app permission to transfer funds
//acl.grantPermission(rewards, vault, vault.TRANSFER_ROLE());
cleanupDAOPermissions(dao, acl, root); cleanupDAOPermissions(dao, acl, root);

16
contracts/test/Spoof.sol Normal file
View File

@@ -0,0 +1,16 @@
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 {
// ...
}

View File

@@ -14,6 +14,10 @@ class Contribution extends Record {
}); });
} }
getData (id) {
return this.functions.getContribution(id);
}
getByContributorId (contributorId) { getByContributorId (contributorId) {
return this.functions.getContributorAddressById(contributorId) return this.functions.getContributorAddressById(contributorId)
.then(address => this.getByContributorAddress(address)); .then(address => this.getByContributorAddress(address));
@@ -62,6 +66,7 @@ class Contribution extends Record {
deprecate('The function `addContribution()` is deprecated and will be removed in the next major version. Use `add()` instead'); deprecate('The function `addContribution()` is deprecated and will be removed in the next major version. Use `add()` instead');
return this.add(...arguments); return this.add(...arguments);
} }
} }
module.exports = Contribution; module.exports = Contribution;

View File

@@ -15,6 +15,10 @@ class Contributor extends Record {
}); });
} }
getData (id) {
return this.functions.getContributorById(id);
}
filterByAccount (search) { filterByAccount (search) {
return this._byAccount(search, 'filter'); return this._byAccount(search, 'filter');
} }
@@ -84,6 +88,7 @@ class Contributor extends Record {
}); });
}); });
} }
} }
module.exports = Contributor; module.exports = Contributor;

View File

@@ -13,7 +13,7 @@ class Contributor {
Object.keys(attrs).forEach(a => this[a] = attrs[a]); Object.keys(attrs).forEach(a => this[a] = attrs[a]);
} }
/** /**
* Serialize object to JSON * Serialize object to JSON
* *
* @method * @method

View File

@@ -1,13 +1,14 @@
const ipfsClient = require('ipfs-http-client'); const ipfsClient = require('ipfs-http-client');
const multihashes = require('multihashes'); const multihashes = require('multihashes');
const fetch = require('node-fetch');
class IPFS { class IPFS {
constructor (config) { constructor (config) {
if (!config) { if (!config) {
config = { host: 'localhost', port: '5001', protocol: 'http' }; config = { host: 'localhost', port: '5001', protocol: 'http' };
} }
this._ipfsAPI = ipfsClient(config);
this._config = config; this._config = config;
this._ipfsAPI = ipfsClient(config);
} }
catAndMerge (data, deserialize) { catAndMerge (data, deserialize) {
@@ -38,7 +39,19 @@ class IPFS {
if (hashData.hasOwnProperty('hashSize')) { if (hashData.hasOwnProperty('hashSize')) {
ipfsHash = this.encodeHash(hashData); ipfsHash = this.encodeHash(hashData);
} }
return this._ipfsAPI.cat(ipfsHash); if (this._config['gatewayUrl']) {
return fetch(`${this._config['gatewayUrl']}/${ipfsHash}`).then(r => r.text());
} else {
return this._ipfsAPI.cat(ipfsHash);
}
}
pin (hashData) {
let ipfsHash = hashData; // default - if it is a string
if (hashData.hasOwnProperty('hashSize')) {
ipfsHash = this.encodeHash(hashData);
}
return this._ipfsAPI.pin.add(multihashes.toB58String(ipfsHash));
} }
decodeHash (ipfsHash) { decodeHash (ipfsHash) {

26528
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "kredits-contracts", "name": "kredits-contracts",
"version": "5.3.0", "version": "5.4.0",
"description": "Ethereum contracts and npm wrapper for Kredits", "description": "Ethereum contracts and npm wrapper for Kredits",
"main": "./lib/kredits.js", "main": "./lib/kredits.js",
"directories": { "directories": {
@@ -12,19 +12,24 @@
"build-json": "npm run compile-contracts && node ./scripts/build-json.js", "build-json": "npm run compile-contracts && node ./scripts/build-json.js",
"repl": "truffle exec scripts/repl.js", "repl": "truffle exec scripts/repl.js",
"seeds": "truffle exec scripts/seeds.js", "seeds": "truffle exec scripts/seeds.js",
"compile-contracts": "aragon contracts compile --all", "compile-contracts": "truffle compile --all",
"bootstrap": "npm run reset:hard && npm run seeds", "bootstrap": "npm run reset:hard && npm run seeds",
"reset": "npm run deploy:kit && npm run deploy:dao", "reset": "npm run deploy:kit && npm run deploy:dao",
"reset:hard": "npm run deploy:apps && npm run reset", "reset:hard": "npm run deploy:apps && npm run reset",
"deploy:kit": "npm run compile-contracts && aragon contracts exec scripts/deploy-kit.js", "deploy:kit": "aragon contracts exec scripts/deploy-kit.js",
"deploy:dao": "aragon contracts exec scripts/new-dao.js", "deploy:dao": "aragon contracts exec scripts/new-dao.js",
"deploy:apps": "./scripts/every-app.sh \"aragon apm publish major\"", "deploy:apps": "./scripts/every-app.sh \"aragon apm publish major --propagate-content=false --build=false --prepublish=false --skip-confirmation\"",
"devchain": "aragon devchain --port 7545", "devchain": "aragon devchain --port 7545",
"dao:address": "truffle exec scripts/current-address.js", "dao:address": "truffle exec scripts/current-address.js",
"lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"", "lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"",
"lint:contract-tests": "eslint apps/*/test", "lint:contract-tests": "eslint apps/*/test",
"lint:wrapper": "eslint lib/", "lint:wrapper": "eslint lib/",
"test": "echo \"Error: no test specified\" && exit 1", "test": "npm run test:token && npm run test:contributor && npm run test:contribution && npm run test:proposal && npm run test:kit",
"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" "setup-git-hooks": "sh scripts/git-hooks/install"
}, },
"repository": { "repository": {
@@ -38,7 +43,6 @@
}, },
"homepage": "https://github.com/67P/truffle-kredits#readme", "homepage": "https://github.com/67P/truffle-kredits#readme",
"devDependencies": { "devDependencies": {
"@aragon/cli": "^5.9.6",
"@aragon/kits-base": "^1.0.0", "@aragon/kits-base": "^1.0.0",
"@aragon/os": "^4.2.0", "@aragon/os": "^4.2.0",
"async-each-series": "^1.1.0", "async-each-series": "^1.1.0",
@@ -54,9 +58,11 @@
"yargs": "^12.0.0" "yargs": "^12.0.0"
}, },
"dependencies": { "dependencies": {
"@aragon/apps-vault": "^4.1.0",
"ethers": "^4.0.29", "ethers": "^4.0.29",
"ipfs-http-client": "^32.0.1", "ipfs-http-client": "^30.1.3",
"kosmos-schemas": "^2.1.0", "kosmos-schemas": "^2.1.0",
"node-fetch": "^2.6.0",
"tv4": "^1.3.0" "tv4": "^1.3.0"
}, },
"keywords": [ "keywords": [

View File

@@ -5,7 +5,8 @@ module.exports = async function(callback) {
let amount = await promptly.prompt('Amount: ', {default: '1'}); let amount = await promptly.prompt('Amount: ', {default: '1'});
amount = parseInt(amount); amount = parseInt(amount);
let fromAccount = web3.eth.accounts[0]; const accounts = await web3.eth.personal.getAccounts();
let fromAccount = accounts[0];
let fromBalance = await web3.eth.getBalance(fromAccount); let fromBalance = await web3.eth.getBalance(fromAccount);
let recipientBalance = await web3.eth.getBalance(recipient); let recipientBalance = await web3.eth.getBalance(recipient);
@@ -13,11 +14,11 @@ module.exports = async function(callback) {
console.log(`sender account balance ${fromAccount}: ${fromBalance}`); console.log(`sender account balance ${fromAccount}: ${fromBalance}`);
console.log(`recipient account balance ${recipient}: ${recipientBalance}`); console.log(`recipient account balance ${recipient}: ${recipientBalance}`);
console.log(`\nsending ${amount} ETH from ${web3.eth.accounts[0]} to ${recipient}`); console.log(`\nsending ${amount} ETH from ${accounts[0]} to ${recipient}`);
let transaction = await web3.eth.sendTransaction({to: recipient, value: web3.toWei(amount), from: web3.eth.accounts[0]}); let transaction = await web3.eth.sendTransaction({to: recipient, value: web3.utils.toWei(new web3.utils.BN(amount)), from: accounts[0]});
console.log(`transaction id: ${transaction}`); console.log(`transaction id: ${transaction.transactionHash}`);
recipientBalance = await web3.eth.getBalance(recipient); recipientBalance = await web3.eth.getBalance(recipient);
console.log(`\nnew recipient account balance ${recipient}: ${recipientBalance}`); console.log(`\nnew recipient account balance ${recipient}: ${recipientBalance}`);

95
test/kreditskit.js Normal file
View File

@@ -0,0 +1,95 @@
/* 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;
let vault;
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");
appsId[4] = namehash("vault");
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(ZERO_ADDR, 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[0].id.should.equal(namehash('kredits-proposal'));
apps[1].id.should.equal(namehash('kredits-token'));
apps[0].id.should.equal(namehash('vault'));
});
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);
vault = await getContract('Vault').at(apps[4].proxy);
(await Promise.all([
contribution.hasInitialized(),
contributor.hasInitialized(),
proposal.hasInitialized(),
token.hasInitialized(),
vault.hasInitialized(),
])).should.deep.equal([true, 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'),
//vaul app roles
kernel.hasPermission(accounts[0], vault.address, await vault.TRANSFER_ROLE(), '0x0'),
])).should.deep.equal([true, true, true, true, true, true, true]);
});
});
});

8836
yarn.lock

File diff suppressed because it is too large Load Diff