Compare commits

..

301 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
86bbe49c0b Fix seeds script to support new web3 version 2019-06-13 18:39:25 +02:00
d5322530c3 Update aragon CLI to latest version 2019-06-13 18:37:33 +02:00
011d85447f Merge pull request #138 from 67P/dev/seeds
Various small seed/script improvements
2019-06-13 16:36:38 +00:00
9fd9dbc1b5 Handle errors in IPFS pin script 2019-06-13 18:31:47 +02:00
b7d87cd8f2 Ignore scripts folder in eslint
Lots of undef etc. due to the scripts being piped through truffle
2019-06-13 17:39:03 +02:00
6c8491e67b Handle errors in seed funding 2019-06-13 17:38:34 +02:00
2623e71055 Update deprecated functions in seeds 2019-06-13 17:38:00 +02:00
ed0d420fd5 Fix linter issues in seeds 2019-06-13 17:37:36 +02:00
36666fd417 Update package lockfile 2019-06-12 16:07:38 +02:00
231d6e2477 Merge pull request #135 from 67P/feature/expose-available-networks
Expose available network IDs
2019-06-12 07:57:31 +00: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
107654ecca Expose available network IDs
This exposes the network IDs on which kredits is deployed. Helpful to
check if the used network is supported.
2019-06-11 15:45:14 +02:00
810a2eb5fd Merge pull request #134 from 67P/chore/update-dependencies
Update dependencies
2019-06-10 13:19:29 +02:00
06a4e2173a Try npm instead of yarn on travis
There is some strange error with yarn: https://travis-ci.org/67P/kredits-contracts/builds/543186831
2019-06-10 12:59:02 +02:00
e55a209343 Merge pull request #133 from 67P/feature/list-totals
Print total unconfirmed and confirmed contribution kredits
2019-06-09 13:58:42 +02:00
17bc4e7d8f Merge pull request #121 from 67P/refactor/amounts_vs_counts
Improve totalKreditsEarned
2019-06-09 13:57:44 +02:00
4919605664 Merge pull request #130 from 67P/feature/kredits-kit-wrapper
Add JS wrapper for Kit contract
2019-06-09 13:56:32 +02:00
f639e3aa19 Add pre-commit hook and setup script (#129)
Add pre-commit hook and setup script

Runs the appropriate linter on staged files before committing.
2019-06-09 13:53:40 +02:00
84b4461ba6 Update dependencies 2019-06-08 19:05:35 +02:00
c4f8e9278e Use consitently uint32 for amounts 2019-06-08 17:56:50 +02:00
00905eb269 Update ABIs 2019-06-08 17:53:26 +02:00
6a64842415 Only count not-vetoed contributions for total balances 2019-06-08 17:49:24 +02:00
055d8bc0ef Print total unconfirmed and confirmed contribution kredits 2019-06-08 17:42:20 +02:00
91779ccd03 Merge pull request #131 from 67P/feature/claim-contribution-script
Add script to claim contributions for one contributor
2019-05-21 11:29:56 +00:00
516b8b31ac Add script to claim contributions for one contributor 2019-05-20 13:48:15 +02:00
ccd52f6ee5 Cleanup 2019-05-17 18:24:55 +02:00
ffff09ab23 Add contract address accessor 2019-05-17 15:56:24 +02:00
3df0831d9b Cleanup whitespace 2019-05-17 15:56:02 +02:00
27a746261c Add JS wrapper for kredits kit
This makes it easier to deploy new DAOs and the deploy script is less
dependent on truffle
2019-05-17 15:54:52 +02:00
345b6bde82 Merge pull request #127 from 67P/feature/allow-setting-contributor-accounts
Allow setting any contributor accounts
2019-05-17 08:42:43 +00:00
a86ea08bdf Merge pull request #128 from 67P/feature/simple-init
Add helper to initialize a new instance with provider
2019-05-17 07:37:10 +00:00
e20bda73fb Remove not needed network check
We default to localhost anyway
2019-05-17 09:17:10 +02:00
4c64aa7c2a linting 2019-05-14 12:03:29 +02:00
cf43bf9487 Linting 2019-05-14 11:32:42 +02:00
1a227ba67c Linting 2019-05-14 11:31:33 +02:00
df7536589d Add helper to initialize a new instance with provider
So far we always had to initialze a provider and signer and pass those
to the kredits constructor.
This helper makes it easier to initialize a default ethers provider and
a default signer.
2019-05-14 11:25:21 +02:00
f0fe62f6d7 Apply suggestions from code review
Co-Authored-By: Sebastian Kippe <sebastian@kip.pe>
2019-05-14 09:18:23 +00:00
66fc992291 Allow setting any contributor accounts
This allows to pass in an account object when creating or updating a
contribtor.
2019-05-14 11:06:49 +02:00
2a675c9417 Merge pull request #126 from 67P/chore/update_schemas
Update kosmos-schemas
2019-05-10 16:08:30 +02:00
a3590d7c16 Update kosmos-schemas
Includes the new "special" contribution kind, as discussed in our last
call.
2019-05-10 13:14:56 +02:00
07a5ca847d Merge pull request #125 from 67P/bugfix/pagination
Fix page number calculation for zero records
2019-05-07 17:12:16 +02:00
37ce2fddde Merge pull request #124 from 67P/bugfix/fix-me-1
Fix util import
2019-05-04 08:40:58 +00:00
3a43284557 Fix page number calculation for zero records
So far it returned 0 because of those in range checks which both
applied because numberOfPages is 0 if we have no record.
2019-05-04 01:34:05 +02:00
572848c04a Fix util import 2019-05-04 01:09:22 +02:00
b6ce9dcfc8 Merge pull request #118 from 67P/deprecate/old-add-methods
Deprecate old add* methods
2019-05-01 18:12:18 +00:00
e7e8744ad2 Update lib/contracts/proposal.js
Co-Authored-By: bumi <hello@michaelbumann.com>
2019-05-01 18:06:55 +00:00
d2198dca61 Update lib/contracts/contribution.js
Co-Authored-By: bumi <hello@michaelbumann.com>
2019-05-01 18:06:43 +00:00
f9f2ef234e Merge pull request #122 from 67P/feature/veto_script
Add script for vetoing via console
2019-05-01 18:05:37 +00:00
a1f51428d0 Add script for vetoing via console 2019-04-28 15:09:18 +01:00
555cb53c78 Improve totalKreditsEarned
* Use a more reasonable size of integer
* Use better variable names (count != amount, balance != count)
2019-04-27 21:01:51 +01:00
ad74d30aa7 Contributor canPerform fix deployment 2019-04-25 22:25:38 +02:00
3568d3c141 Merge pull request #120 from 67P/bugfix/fix-core-permissions
Fix canPerform method
2019-04-25 21:17:37 +01:00
db566a581f Merge pull request #119 from 67P/bugfix/fix-kit-deployment
Fix apps lookup
2019-04-25 21:10:04 +01:00
c69ebd0a62 Fix canPerform method
Even if the variable is not used and the linter might complain we have
to have that parameter in the signature. otherwise the method is not
found and can not be called.
2019-04-25 22:06:40 +02:00
5c375f764f Update scripts/deploy-kit.js
Co-Authored-By: bumi <hello@michaelbumann.com>
2019-04-25 20:05:03 +00:00
b04d572b9a Fix apps lookup
We use the directories in ./apps to load available app names.
For this we need to make sure that we only use directories.
2019-04-25 16:45:39 +02:00
1199b053fe Add missing returns for the deprecated methods 2019-04-24 21:55:10 +02:00
f06b21dfee Deprecate old add* methods 2019-04-24 21:49:27 +02:00
d643e5842c Merge pull request #97 from 67P/chore/linter
Add linter and travis.yml
2019-04-24 18:28:32 +00:00
a87d5326bf Oh my package-lock 2019-04-24 20:17:03 +02:00
c9fed46054 Add contract test linting 2019-04-24 19:56:37 +02:00
6f2097ed46 Fix regex 2019-04-24 19:39:30 +02:00
94d342ce63 Replace console.log by deprecate function 2019-04-24 19:31:26 +02:00
f984dec95a Style fixes 2019-04-24 19:31:04 +02:00
145b3ea766 Merge branch 'master' into chore/linter
# Conflicts:
#	lib/contracts/contribution.js
#	lib/contracts/contributor.js
#	lib/contracts/proposal.js
#	lib/kredits.js
#	lib/serializers/contributor.js
#	yarn.lock
2019-04-24 19:12:18 +02:00
a80dfee5c5 Merge pull request #116 from 67P/deployments/balance-update
Release/deployment notes for latest contract updates on Rinkeby
2019-04-24 17:03:48 +01:00
4649de24c8 Deploy notes for latest contributor and contribution deployment 2019-04-24 17:32:58 +02:00
8539b56a48 5.3.0 2019-04-24 14:22:53 +01:00
f59c37827a Merge pull request #108 from 67P/feature/kredits-formatter
Add kredits-formatter and additionally format balance
2019-04-24 14:20:44 +01:00
58db57ee45 Merge branch 'master' into feature/kredits-formatter 2019-04-24 13:10:48 +00:00
b64a7ca299 Merge pull request #113 from 67P/feature/gitea_site
Add Gitea site/username to serializer and seeds
2019-04-24 12:58:44 +00:00
6f09ca8d13 Merge pull request #114 from 67P/chore/scripts
Improve/fix scripts
2019-04-24 12:57:43 +00:00
6f53c8097e Wrap anything that could break in the try/catch block 2019-04-24 14:55:35 +02:00
6b2ac15f56 Improve error handling for list-contributors script 2019-04-24 13:46:27 +01:00
359989f235 Fix function name for total kredits issued/earned 2019-04-24 13:45:56 +01:00
5894f6323b Add Gitea username to contributor seeds 2019-04-24 13:43:46 +01:00
09b78e1e8f Add Gitea site/username to contributor serializer 2019-04-23 20:28:56 +01:00
48c8f6b9b3 Merge branch 'master' into feature/kredits-formatter 2019-04-23 12:56:55 +00:00
542ebaf3f3 5.2.0 2019-04-23 13:52:46 +01:00
d82ffba75e Update ABI 2019-04-23 13:52:37 +01:00
bdb2cee0c4 Merge pull request #110 from 67P/feature/contribution-balances
Add contract calls for total contribution balances
2019-04-23 13:47:50 +01:00
cd45ce260f Merge pull request #112 from 67P/feature/update-contributor-profile
Update contributor profile
2019-04-20 09:22:31 +00:00
3a97983540 Merge pull request #111 from 67P/feature/contributor-schema-validation
Add Contributor validation against JSON schema
2019-04-20 08:47:49 +01:00
9714926e11 Add function to update contributor profile to wrapper
The function updates the contributor profile,
adds the new profile to IPFS and does the contract call to update
the profile hash
2019-04-20 02:17:38 +02:00
59614201b5 Ups... 2019-04-20 02:15:53 +02:00
e591742e40 Add Contributor validation against JSON schema
based on the Contribution validation.
2019-04-20 01:10:46 +02:00
791190f5e7 Cleanup promise call 2019-04-20 00:30:20 +02:00
24b66daf2a Update ABI 2019-04-19 14:16:40 +02:00
ad034d7712 Naming is hard 2019-04-19 14:15:30 +02:00
375d8f3275 Cleanup 2019-04-19 13:34:39 +02:00
80dc787971 Merge pull request #109 from 67P/dev/list_contributors_error_handling
Handle errors in contributor list script
2019-04-19 11:22:38 +00:00
7967dc26f2 Update ABIs 2019-04-19 13:20:25 +02:00
c248725cc1 Add balances to getContributorById call 2019-04-19 13:19:55 +02:00
59135bf312 Add contract calls for total contribution balances
Those methods return the total kredits amounts of contribtions.
2019-04-19 13:06:36 +02:00
1d771c43e8 Handle errors in contributor list script 2019-04-19 12:02:28 +01:00
3cb94fb660 Add kredits-formatter and additionally format balance
This adds a `balanceInt` value to the contributor data that has the
token balance formatted as full Kredits. (similar to Ether)
2019-04-19 11:57:35 +02:00
5820d71b2c Merge pull request #96 from 67P/feature/pagination
Add pagination for .all methods
2019-04-17 13:53:17 +00:00
4771c0c8a0 Merge branch 'master' into feature/pagination 2019-04-17 13:52:53 +00:00
2a1ae117e8 5.1.1 2019-04-16 12:50:07 +01:00
8abc7ba77f Merge pull request #104 from 67P/chore/update-kosmos-schema
Update kosmos-schema dependency
2019-04-16 11:19:03 +00:00
f696721918 Readme: add note about locally running out of funds 2019-04-16 13:17:54 +02:00
00b58dec66 Update kosmos-schema dependency 2019-04-16 13:16:05 +02:00
560315cbca Merge pull request #102 from 67P/chore/add-yarn-support
Add yarn lock files
2019-04-15 15:54:38 +00:00
24933f31a7 Add yarn lock files 2019-04-15 17:34:48 +02:00
b13bf6e8b0 Readme: add note about locally running out of funds 2019-04-15 15:59:54 +02:00
8dcad88372 Merge pull request #99 from 67P/update-seeds
Update seeds
2019-04-15 10:39:10 +00:00
dc6d2716aa Update seeds 2019-04-15 12:33:51 +02:00
80ad9db630 5.1.0 2019-04-13 12:41:49 +01:00
6f97c905d6 Add count property and DRY 2019-04-13 13:05:47 +02:00
1b5f7ff95d Merge pull request #93 from 67P/deployments/weltempfaenger-release
Production release to rinkeby
2019-04-13 11:07:58 +01:00
b5b12e22ce Readd solhint:default 2019-04-13 01:53:52 +02:00
fe811cdb12 Use solhint:recommended 2019-04-13 01:17:38 +02:00
42df6fe310 Fix solhint invocation 2019-04-13 01:10:40 +02:00
c8805be054 Switch to yarn 2019-04-13 00:19:52 +02:00
764f63fc8c Trigger build 2019-04-13 00:14:23 +02:00
f73ccedf42 Activate linting on travis 2019-04-13 00:10:21 +02:00
a9093c1c40 Fix linter errors
# Conflicts:
#	lib/contracts/contribution.js
#	lib/contracts/contributor.js
#	lib/contracts/proposal.js
#	lib/kredits.js
#	lib/utils/pagination.js
2019-04-13 00:08:12 +02:00
e405644b1d Add eslint and solhint 2019-04-13 00:03:16 +02:00
f6189bf910 Add pagination for .all methods
I removed rsvp as a dependency as we only use Promise.all
2019-04-12 21:21:19 +02:00
b6c06c289c Merge pull request #95 from 67P/cosmetics
Cosmetic cleanups
2019-04-12 18:55:59 +00:00
f405e39c04 Merge pull request #94 from 67P/bugfix/schema_changes
Refactor contribution serializer and validation
2019-04-12 18:54:56 +00:00
1dbf3b5742 Cosmetic cleanups 2019-04-12 20:16:24 +02:00
952b5153fd Validate proposed contributions 2019-04-11 13:46:42 +02:00
d953141f52 Refactor contribution serializer and validation 2019-04-11 13:05:40 +02:00
aa57d7c70b Adjust seeds for new requirements 2019-04-11 11:02:15 +02:00
4c0bb879e8 Show IPFS hash in list script output 2019-04-11 11:01:45 +02:00
9c5a517fb9 5.0.0 2019-04-11 08:45:49 +02:00
b00ddda312 Merge pull request #92 from 67P/feature/contribution_schema
Validate contribution docs against schema
2019-04-11 08:40:38 +02:00
130e2a7797 Validate contribution docs against schema
Currently requires an open PR branch for the schemas, which is adding
date and time for contributions.

refs #30
2019-04-10 18:37:02 +02:00
27e5190e29 Production release to rinkeby
Deployed all apps and created a new Kredits DAO
2019-04-10 18:28:24 +02:00
b9c171884b Merge pull request #91 from 67P/feature/store-balance-as-wei
Store kredits tokens as wei with 18 decimals
2019-04-10 15:51:36 +02:00
4d2e0ea84b Update Token symbol 2019-04-10 15:50:33 +02:00
26d12ba239 Store kredits tokens as wei with 18 decimals
This stores the tokens with 18 decimals as most other tokens and as
assumed by a potential future token standard EIP 777.
2019-04-10 13:59:00 +02:00
1aae62e139 Merge pull request #88 from 67P/bugfix/confirmed-contributions
Fix confirmed contribution check
2019-04-09 22:36:37 +02:00
f21c4cf9de Fix confirmed contribution check
If the blocknumber is higher or equal the contribution.confirmedAt block
number then the contribution is confirmed and can be claimed.
2019-04-09 22:30:17 +02:00
6778b9060f 4.0.2 2019-04-09 12:47:59 +02:00
4d36f78824 4.0.1 2019-04-09 12:47:37 +02:00
98ecf28262 Merge pull request #87 from 67P/dev/dependency_install
Rename postinstall script
2019-04-09 12:45:41 +02:00
f5564fa923 Formatting, whitespace 2019-04-09 12:45:20 +02:00
096a9f3cea Update README for install-all script 2019-04-09 12:45:09 +02:00
3d24835908 Merge pull request #86 from 67P/dev/bootstrap
Don't run `npm install` on bootstrap
2019-04-09 09:50:51 +02:00
8cbef8458d Rename postinstall script
Prevents it being run when contracts are installed as dependency.
2019-04-09 09:48:00 +02:00
9ca0580db6 Merge pull request #85 from 67P/dev/fix_seeds
Fix contributor ID in seeds
2019-04-09 07:33:42 +00:00
dfe38e7d21 Don't run npm install on bootstrap
When one wants to install, they can install. When one wants to
bootstrap, they should be able to only bootstrap.
2019-04-09 08:44:56 +02:00
377560805f Fix contributor ID in seeds
We have one contributor less, after having removed the initial dummy
account recently.
2019-04-09 08:43:13 +02:00
65d9cf2a06 Fix bootstrap
This runs npm install for every app through a postinstall hook.
2019-04-08 18:10:13 +02:00
b35dc2049b Merge pull request #82 from 67P/dev/list_contributions
Improve list-contributions script
2019-04-06 19:40:24 +00:00
26c2710149 Improve list-contributions script
* Improve sort order of table columns
* Print if the contribution is confirmed
* Log error if something goes wrong
2019-04-06 17:56:48 +02:00
cc24c27444 Merge pull request #80 from 67P/chore/rename-ipfshash-1
Rename ipfsHash to hashDigest in Contributor
2019-04-06 13:55:19 +00:00
f717968402 Better function naming to update contributor profiles 2019-04-06 15:42:16 +02:00
14d7fbd75e Rename ipfsHash to hashDigest in Contributor
naming should be consistent with the other contracts and digest is more
correct.
2019-04-06 15:24:44 +02:00
7eb1fedb42 Merge pull request #76 from 67P/features/dynamic-core-flag
Dynamic function to test for core contributor flag
2019-04-06 15:19:01 +02:00
cbfe39f804 Merge pull request #78 from 67P/feature/veto-period
Set contribution veto period to 1 week
2019-04-06 00:30:30 +02:00
a0e4f5410d Set veto period to 1 week
This makes a contribution claimable after roughly 7 days
2019-04-05 20:30:02 +02:00
766463b57b Dynamic function to test for core contributor flag
This removes the isCore flag and allows us to dynamically calculate the
core flag for contributors.

For now this is just us (the first 6 contirbutors)

Also we do not need the default contributor anymore because the deploy
user has the role to manage contributors and can create the first real
contributors.
2019-04-05 18:55:21 +02:00
93e0b30b35 4.0.0 2019-04-05 15:44:51 +02:00
6510dca4b1 Fix provider fallbacks for non dev networks
This now checks if frame or a local node is running and else uses infura
to connect to the ethereum network.
Now you can use all the helpers for the testnets/mainnet without running
anything (in readonly mode)
2019-04-05 13:51:23 +02:00
551edcfa72 Fix init kredits for readonly providers
The apm option was not passed on to kredits
2019-04-05 01:05:16 +02:00
d58e2d560a deploy to rinkeby 2019-04-05 00:38:51 +02:00
99394e7f14 Merge pull request #73 from 67P/feature/contribution_owner
Convert contribution owner to ID, use smaller number formats
2019-04-04 21:40:16 +00:00
8ceab08bfc ups 2019-04-04 23:23:02 +02:00
896db5e047 Update abi 2019-04-04 23:16:23 +02:00
d507d7b562 Enable all seeds again 2019-04-04 23:16:01 +02:00
40c5d2a275 Merge branch 'master' into feature/contribution_owner 2019-04-04 23:12:16 +02:00
a049f2eedb Adjust proposals for format changes 2019-04-04 23:11:43 +02:00
b68b037000 Merge pull request #74 from 67P/chore/npm-scripts
Add some helpers to reset a fresh DAO and upgrade an app
2019-04-04 23:11:12 +02:00
181e6f3c23 Fix/refactor contribution wrapper 2019-04-04 22:56:06 +02:00
19556349f6 Fix syntax error 2019-04-04 22:30:27 +02:00
a1a1c5ef9f Get contributor by ID
Co-Authored-By: skddc <sebastian@kip.pe>
2019-04-04 22:29:37 +02:00
afbd114a36 Add app upgrade helper script
This script deploys a new app version, upgrades the given DAO to the
latest version of that app and builds the ABI files for the wrapper.

usage:

    scripts/upgrade.sh <app name> <dao address>

e.g.

    scripts/upgrade.sh token 0xfoobar

The DAO address can also be set as environment variable
$KREDITS_DAO_ADDRESS
2019-04-04 19:51:38 +02:00
db312dafbf Add some helpers to reset a fresh DAO 2019-04-04 19:27:57 +02:00
e4c3d9a468 Update abi 2019-04-04 16:28:34 +02:00
5b49f82544 Adjust wrapper and scripts for contract changes 2019-04-04 16:24:37 +02:00
6088f30cd8 Use smaller numbers for contributor ID
2.2 billion contributors should be enough.
2019-04-04 16:01:08 +02:00
f1e2c65b9e Use smaller numbers where appropriate 2019-04-04 15:28:18 +02:00
786f38cfb7 Print errors in seed contract calls 2019-04-04 15:25:31 +02:00
197a31b9e1 Remove whitespace 2019-04-04 14:47:25 +02:00
20acfc70e3 Use ID instead of address for contribution owner 2019-04-04 14:43:38 +02:00
732dfe7b29 Merge pull request #71 from 67P/chore/update_seeds
Update seeds
2019-04-04 11:32:58 +00:00
3ce8f41d32 Merge pull request #72 from 67P/chore/whitespace
Remove unnecessary space chars
2019-04-04 11:17:35 +00:00
e0ff29d1c9 Remove unnecessary space chars 2019-04-04 11:38:18 +02:00
0ce62839e9 Update seeds
Use more realistic data, add more contributions
2019-04-04 11:32:46 +02:00
cc2c9a7368 Merge pull request #70 from 67P/feature/claim-contribution-in-seeds
Update seeds
2019-04-03 21:50:43 +02:00
1abfc5a265 Merge pull request #69 from 67P/fix/add-contributor-permissions
Fix permissions to manage contributors
2019-04-03 21:50:19 +02:00
6b9466c348 Update seeds
Claim contribution which issues Kredits to the contributor
2019-04-03 21:40:37 +02:00
9fffdbfb58 Fix permissions to manage contributors
Uses the contributor oracle to decide if somebody has the
MANAGE_CONTRIBUTOR_ROLE
2019-04-03 21:22:53 +02:00
350dadec4d Merge pull request #68 from 67P/update-ipfs-package
Update ipfs package
2019-04-03 21:16:22 +02:00
70b9edbcac Update ipfs package 2019-04-03 21:01:51 +02:00
92da07dca2 Merge pull request #67 from 67P/feature/contributor-balance-1
Add balance when loading contributor
2019-04-03 20:22:50 +02:00
6fed81c0ed Merge pull request #66 from 67P/chore/seeds
Allow seed tx to fail
2019-04-03 17:03:22 +00:00
74e61e1393 Show balance in list-contributors helper script 2019-04-03 14:05:16 +02:00
6351db3057 Add balance when loading contributor
This is a regression introduced by the latest contract updates.
Now we return the balance again when loading contributor data.
2019-04-03 13:56:52 +02:00
ed3e5dd4c4 Allow seed tx to fail
This allows for running seeds multiple times, e.g. after adding new
ones.
2019-04-03 11:41:55 +02:00
bd39d0f126 Use new address for raucao seed 2019-04-03 11:41:45 +02:00
4c8ee69664 Merge pull request #65 from 67P/fix/ethersjs-namehash
Use namehash from ethers.utils
2019-04-03 11:39:35 +02:00
eae8967322 Merge pull request #63 from 67P/fix/contriutor-permissions
Fix contributor oracle permission auth
2019-04-03 11:37:10 +02:00
9984ca66ba Use namehash from ethers.utils
no need for the additional dependency
2019-04-03 10:24:11 +02:00
1b09a30646 Fix contributor oracle permission auth
It seems that the entity is either defined by the permission or if we
want to use the oracle the permission must be defined for any_entity.
In that case the oracle does not get the msg.sender as who/entity thus
we will use tx.origin in that case.
2019-04-03 10:06:00 +02:00
f40cc1d8ff Merge pull request #62 from 67P/aragonos
Build on aragonOS
2019-04-02 21:36:36 +02:00
91135dbc82 Fix deploy-kit helper script
We no longer need the app ids as json. Those are dynamically calculated
now
2019-04-02 18:06:33 +02:00
adb7122a28 Add helper script for updating local address file
Can be run after starting the devchain, so that all local truffle
scripts work with the new network ID.
2019-04-02 17:35:28 +02:00
ce446e530d Set Kreits apm from arapp.json file in helper scripts
different networks might require different apm domains. We set those in
the arapp.json file which we can reuise to init the kredits instance in
the helper scripts.
2019-04-02 09:58:44 +02:00
fedb10c5da Dynamically get app ids from the namehash
This dynamically hashes the app id which makes it easier to manually set
contract addresses. This is useful in development environments with no
default network ids.
The used apm (which is part of the app id hash) is configurable.

usage:

new Kredits(provider, signer, { addresses: { Kernel: '0x...' }, apm: 'aragonpm.eth' })
2019-04-01 22:41:00 +02:00
a24f80d44f Change addresses 2019-04-01 14:04:11 +02:00
61fa26da7a Add more information output to the send funds helper 2019-04-01 11:53:50 +02:00
9512ba4334 Update contract addresses 2019-04-01 11:19:30 +02:00
65c129eafd Update package locks 2019-04-01 11:17:26 +02:00
c2f763bec7 Add missing variable assignment 2019-04-01 11:16:55 +02:00
c93a81808a Update package lock 2019-04-01 10:34:48 +02:00
51e5da414f Update ethers.js to latest version v4
The main change is how ethers loads the networkId which is now async.
Thus the init process had to change a bit
2019-03-29 18:13:51 +01:00
3662f1ae24 Add Operator getter for backwards compatibility 2019-03-29 15:03:37 +01:00
c568263fea update eth-provider to support different providers
Ideally eth-provider checks which connection is available and uses the
available one.
frame => local node => infura

But it seems there is still a bug and it raises an error if frame is not
available.
But at least we can use frame now for testnet/mainnet deployments
2019-03-29 12:08:07 +01:00
38079d07db remove debug console 2019-03-29 12:07:52 +01:00
0cc67c2fad Support getting the network version from different web3
version/providers
2019-03-29 12:07:09 +01:00
a45be0021e Fix old registry reference 2019-03-29 12:06:43 +01:00
4bd1aed197 Refactor kredits init in helper scripts
This now also supports readonly providers like infura
2019-03-29 12:05:51 +01:00
94832d4d07 Add ACL contract wrapper
this mainly allows us to check if an account has a certain role and thus
if the account can call specific contract functions.

At some point we might want to extend that to support the check if an
account can call the function. For that we would need to have a mapping
between function names and roles, which we have not right now.
2019-03-28 12:39:04 +01:00
4f5ae01c5a Add helper funtion to list contract entries 2019-03-28 11:16:20 +01:00
d6f99f57b7 Auto resolve promises in repl 2019-03-28 11:12:32 +01:00
901566d1ff Update network specific addresses and app ids 2019-03-28 11:11:49 +01:00
5d4be8f176 Update ABIs used by wrapper 2019-03-28 11:09:49 +01:00
f9ab8b225a Fix proposal wrapper to support the latest contracts 2019-03-28 11:08:34 +01:00
dfa55516ec Add contribution veto function
Allows anybody with the VETO_CONTRIBUTION_ROLE to veto a contribution
and thus prevent that the contribution can be claimed.
So far like the ADD_CONTRIBUTION_ROLE any contributor is allowed to
veto.
2019-03-28 11:06:19 +01:00
b6f34ac9a5 Pretty print JSON for contract addresses
This makes it easier to read the file and a git diff is more useful
2019-03-27 21:58:19 +01:00
258c6729b6 Cleanup scripts and use helper to get the networkid 2019-03-27 17:06:52 +01:00
b201642485 remove obsolete comment 2019-03-27 16:56:52 +01:00
0686c79998 Print dao address and kreditskit address 2019-03-27 16:56:24 +01:00
7e68dbf8c2 rinkeby deployment 2019-03-27 00:39:00 +01:00
f5973756c8 Dynamically set AppIds
AppIds are used to lookup the actual contract addresses of each app.
Because of different registry names (open.aragonpm.eth vs. aragonpm.eth)
we have to use different ids in the local dev chain and in the
testnet/mainnet. To allow this we need to set the appids dynamically.

There is an open aragon issue to solve this and also allow to use
open.aragonpm.eth in the devchain by default.
https://github.com/aragon/aragen/issues/10
2019-03-27 00:21:06 +01:00
9cc237fbf4 Support web3 providers that do not support sync calls
This is currently the non default web3 provider used for rinkeby etc.
2019-03-26 00:35:22 +01:00
3584a73c08 Set kredits-<name>.open.aragonpm.eth as appid hashes 2019-03-26 00:34:46 +01:00
3c2cdf4376 Deployment hacking while trying to deploy on rinkeby
This currently breaks the local usage because of the different appIds:
<name>.open.aragonpm.eth vs. <name>.aragonpm.eth (local)
2019-03-26 00:18:59 +01:00
fbda45376e cleanup contract debugging and make sure contributions are only once claimable 2019-03-24 22:33:16 +01:00
cd7df3893e readme 2019-03-24 22:18:19 +01:00
e1fea4ed97 refactor DAO deployment 2019-03-24 22:11:24 +01:00
12341d1526 Add script to print current DAO address 2019-03-24 16:09:00 +01:00
14b23ecdf1 move app bootstrap script to scripts 2019-03-24 15:45:48 +01:00
1679afb9b4 formatting 2019-03-24 14:43:43 +00:00
b03095e149 Cleanup and readme
simplify bootstrap
2019-03-24 15:40:46 +01:00
0d9b2d7d58 readme 2019-03-24 11:01:59 +01:00
e7affdb531 updated npm scripts 2019-03-24 00:58:56 +01:00
1594bf0e17 update seeds 2019-03-24 00:39:46 +01:00
203199c268 cleanup 2019-03-24 00:21:36 +01:00
116f69cb12 cleanup 2019-03-24 00:20:48 +01:00
6c569239de refactor contrats with aragonos 2019-03-23 19:15:23 +01:00
d687ff604e Merge branch 'master' into contribution-contract
* master:
  Update truffle and ganache-cli
2018-09-29 19:54:28 +02:00
c9a4b1decc Update truffle and ganache-cli 2018-09-29 19:52:14 +02:00
dae44cac70 Continue Contribution contract and JS wrapper 2018-09-29 19:46:37 +02:00
6b8f718051 Create contribution when proposal gets executed 2018-06-18 18:43:35 +02:00
6d9a54b71c Remove whitespace 2018-06-18 18:42:32 +02:00
75d426f0cc Add Contribution contract
The contribution contract implements an ERC721 interface which
represents any contribution.
The contributions are non-fungible (as opposed to the Kredits tokens)
and can be not be transferred. The contract stores the history of any
contribution.
Contributions can be claimed which will issue the Kredits tokens to the
contributor.

This is an early implementation and misses some access control and
probably more things.
2018-06-18 15:28:50 +02:00
153 changed files with 121229 additions and 5114 deletions

1
.eslintignore Normal file
View File

@@ -0,0 +1 @@
/scripts/

33
.eslintrc.js Normal file
View File

@@ -0,0 +1,33 @@
module.exports = {
'env': {
'browser': true,
'es6': true,
'node': true
},
'extends': 'eslint:recommended',
'globals': {
'Atomics': 'readonly',
'SharedArrayBuffer': 'readonly'
},
'parserOptions': {
'ecmaVersion': 2018,
'sourceType': 'module'
},
'rules': {
'comma-dangle': ['error', {
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'never',
exports: 'never',
functions: 'ignore',
}],
'eol-last': ['error', 'always'],
semi: ['error', 'always'],
'space-before-function-paren': ['error', {
anonymous: 'never',
named: 'always',
asyncArrow: 'always',
}],
'indent': ['error', 2]
}
}

4
.gitignore vendored
View File

@@ -1,4 +1,8 @@
build
flattened_contracts
node_modules
**/node_modules
.ganache-db
.tm_properties
yarn-error.log
.DS_Store

9
.solhint.json Normal file
View File

@@ -0,0 +1,9 @@
{
"extends": [
"solhint:default",
"solhint:recommended"
],
"rules": {
"indent": "2"
}
}

33
.travis.yml Normal file
View File

@@ -0,0 +1,33 @@
---
language: node_js
node_js:
- "lts/*"
sudo: false
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:
- npm install -g @aragon/cli
- npm install -g truffle
- npm install
before_script:
- npm run devchain &
script:
- npm run lint:wrapper
- npm run lint:contract-tests
- npm run test
branches:
only:
- master

231
README.md
View File

@@ -2,92 +2,102 @@
# Kredits Contracts
This repository contains the Solidity smart contracts and JavaScript API
wrapper for [Kosmos Kredits](https://wiki.kosmos.org/Kredits).
This repository contains the Solidity smart contracts organized as
[Aragon](https://hack.aragon.org/) apps and JavaScript API wrapper for [Kosmos
Kredits](https://wiki.kosmos.org/Kredits).
It uses the [Truffle framework](http://truffleframework.com/) for some things.
It is based on [aragonOS](https://hack.aragon.org/docs/aragonos-intro.html) and
follows the aragonOS conventions. Aragon itself uses the [Truffle
framework](http://truffleframework.com/) for some things.
## Development
### Installation
$ npm install
### Requirements
#### App dependencies
All requirements are defined in `package.json`.
Those can be installed globally for convenience:
$ npm install
* [truffle framework](http://truffleframework.com): `npm install -g truffle`
* [ganache](http://truffleframework.com/ganache): `npm install -g ganache-cli`
Each of the aragon apps are separate packages:
We use following solidity contract libraries:
$ cd apps/[app]
$ npm install
* [Open Zeppelin](https://github.com/OpenZeppelin/zeppelin-solidity)
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
For local development it is recommended to use
[ganache-cli](https://github.com/trufflesuite/ganache-cli) (or the [ganache
GUI](http://truffleframework.com/ganache/) to run a local development chain.
Using the ganache simulator no full Ethereum node is required.
[ganache](http://truffleframework.com/ganache/) to run a local development
chain. When using the ganache simulator, no full Ethereum node is required.
We default to:
We use the default aragon-cli devchain command to configure and run a local
development ganache.
* port 7545 for development to not get in conflict with the default Ethereum
RPC port.
* network ID 100 to stay on the same network id
* store ganache data in .ganache-db to presist the chain data across restarts
* use a fixed Mnemonic code to get the same accounts across restarts
$ npm run devchain (or aragon devchain --port 7545)
Have a look at `ganache-cli` for more configuration options.
To clear/reset the chain use (e.g. if you run out of funds on your devchain)
Run your ganache simulator before using Kredits locally:
$ npm run devchain -- --reset (or aragon devchain --port 7545 --reset)
$ npm run ganache (which is: ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits)
We default to port 7545 for development to not get in conflict with the default
Ethereum RPC port.
### Truffle console
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`.
Truffle comes with a simple REPL to interact with the Smart Contracts. Have a
look at the [documentation
here](http://truffleframework.com/docs/getting_started/console)
### Bootstrap
NOTE: There are promisses, have a look at the examples:
1. Run an Ethereum node and ipfs
```javascript
Token.deployed().then(function(token) {
token.totalSupply.call().then(function(value) {
console.log(value.toString());
})
});
```
$ npm run devchain
$ ipfs daemon
Also please be aware of the differences between web3.js 0.2x.x and
[1.x.x](https://web3js.readthedocs.io/en/1.0/) - [web3
repo](https://github.com/ethereum/web3.js/)
2. Deploy each app to the devchain
## Contract Deployment
(make sure you've run `npm install` for every app - see installation)
$ npm run deploy:apps
Truffle uses migration scripts to deploy contract to various networks. Have a
look at the `migrations` folder for those. The Ethereum nodes for the
different networks need to be configured in `truffle.js`.
3. Deploy a new KreditsKit and create a new DAO with the latest app versions
Run the truffle migration scripts:
$ npm run deploy:kit
$ npm run deploy:dao
$ truffle deploy
$ truffle deploy --network=<network config from truffle.js>
4. Execute seeds to create demo contributors, contributions, etc. (optional)
Truffle keeps track of already executed migration scripts. To reset the
migration use the `--reset` option
$ npm run seeds
$ truffle migrate --reset
**Step 2-4 is also summarized in `npm run bootstrap`**
Migration scripts can also be run from within `truffle console` or `truffle
develop`
If you want to reset your local setup:
To initially bootstrap a local development chain in ganache you can use the
bootstrap script:
$ npm run reset // deploys a new kit and a new DAO
$ npm run reset:hard // deploys all apps and does reset
## Contract architecture
Contracts are organized in independent apps (see `/apps`) and are developed and
deployed independently. Each app has a version and can be "installed" on the
Kredits DAO independently.
![](docs/kredits-diagram.png)
A DAO can be deployed using the `scripts/deploy-kit.js` script or with the
`npm run deploy:dao` command. This deploys a new Kredits DAO, installs the
latest app versions and sets the required permissions.
See each app in `/apps/*` for details.
$ npm run bootstrap
## Helper scripts
@@ -97,6 +107,8 @@ CLI. _At some point these should be moved into a real nice CLI._
To run these scripts use `truffle exec`. For example: `truffle exec
scripts/add-proposal.js`.
Some scripts are also defined as npm script, see package.json.
### cli.js
Call any function on any contract:
@@ -110,18 +122,17 @@ instance.
$ truffle exec scripts/repl.js
### add-contributor.js
### add-{contributor, contribution, proposal}.js
Adds a new core contributor, creates a proposal for the new contributor and
votes for that one.
Script to add a new entries to the contracts using the JS wrapper
$ truffle exec scripts/add-contributor.js
$ truffle exec scripts/add-{contributor, contribution, proposal}.js
### add-proposal.js
### list-{contributors, contributions, proposals}.js
Adds a new proposal for an existing contributor
List contract entries
$ truffle exec scripts/add-proposal.js
$ truffle exec scripts/list-{contributors, contributions, proposals}.js
### send-funds.js
@@ -131,48 +142,88 @@ metamask account.
$ truffle exec scripts/send-funds.js
### seeds.js
Run seeds defined in `config/seeds.js`.
$ truffle exec scripts/seeds.js
or
$ npm run seeds
### current-address.js
Prints all known DAO addresses and the DAO address for the current network
$ truffle exec scripts/current-address.js
or
$ npm run dao:address
### deploy-kit.js
Deploys a new KreditsKit that allows to create a new DAO
$ truffle exec script/deploy-kit.js
or
$ npm run deploy:kit
`ENS` address is required as environment variable.
`DAO_FACTORY` can optionally be set as environment variable. (see aragon)
### new-dao.js
Creates and configures a new DAO instance.
$ truffle exec script/new-dao.js
or
$ npm run deploy:dao
KreditsKit address is loaded from `lib/addresses/KreditsKit.json` or can be
configured through the `KREDITS_KIT` environment variable.
### deploy-apps.sh
Runs `npm install` for each app and publishes a new version.
$ ./scripts/deploy-apps.sh
or
$ npm run deploy:apps
## Deployment
### Apps deployment
To deploy a new app version run:
$ aragon apm publish major --environment=NETWORK_TO_DEPLOY
### KreditsKit
deploy the KreditsKit as Kit to create new DAOs
$ truffle exec scripts/deploy-kit.js --network=NETWORK_TO_DEPLOY
### Creating a new DAO
make sure all apps and the KreditsKit are deployed, then create a new DAO:
$ truffle exec scripts/new-dao.js --network=NETWORK_TO_DEPLOY
## ACL / Permissions
## Upgradeable contracts
Some of the contracts use upgradability ideas from
[zeppelinos](https://github.com/zeppelinos/labs) (see `contracts/upgradable`).
The basic idea is to have a Registry contract that knows about the current
implementations and a Proxy contract that uses `delegatecall` to call the
current implementation. That means the Proxy contract holds the storage and
the address of that one does not change but the actuall implemenation is
managed through the Registry.
To deploy a new version a new contract is deployed then the version is
registered (`addVersion()`) in the Registry and on the Proxy contract is
"upgraded" (`upgrade()`) to the new version.
The Registry knows about all the different contracts and implementations.
Versions are stored as uint and automatically incremented for every added
implementation.
We use aragonOS for upgradeability of the different contracts. Refer to the
[aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro)
for more details.
### Example
Deployment is best done using the truffle deployer.
1. Setup
1. Deploy the Registry
2. Deploy the contract
3. Register the contract at the Registry:
`registry.addVersion('Token', Token.address)`
4. Create the Proxy:
`registry.createProxy('Token', 1)`
1. Setup (see #Bootstrap)
1. Deploy each contract/apps (see `/apps/*`)
2. Create a new DAO (see scripts/deploy-kit.js)
2. Update
1. Deploy a new Version of the contract
2. Register the new version at the Registry:
`registry.addVersion('Token', NewToken.address)`
3. Set the new implementation address on the Proxy contract:
`registry.upgrade('Token', 2)`
1. Deploy a new Version of the contract/app (see `/apps/*`)
2. Use the `aragon dao upgrade` command to "install" the new version for the DAO
(`aragon dao upgrade <DAO address> <app name>`)
## Known Issues

12
apps/.eslintrc.js Normal file
View File

@@ -0,0 +1,12 @@
module.exports = {
'globals': {
contract: true,
describe: true,
it: true,
},
rules: {
'no-unused-vars': ['error', {
'argsIgnorePattern': '^_',
}],
}
}

4
apps/contribution/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules
build
.cache
dist

View File

@@ -0,0 +1,14 @@
# Git files
.gitignore
# Build files
.cache
node_modules
build
# Lock files
package-lock.json
yarn.lock
# Others
test

View File

@@ -0,0 +1 @@
# Kredits Contribution

View File

@@ -0,0 +1,38 @@
{
"roles": [
{
"name": "Add contributions",
"id": "ADD_CONTRIBUTION_ROLE",
"params": []
},
{
"name": "Manage token contract",
"id": "MANAGE_TOKEN_CONTRACT_ROLE",
"params": []
},
{
"name": "Veto contributions",
"id": "VETO_CONTRIBUTION_ROLE",
"params": []
}
],
"environments": {
"default": {
"network": "development",
"appName": "kredits-contribution.open.aragonpm.eth"
},
"rinkeby": {
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
"appName": "kredits-contribution.open.aragonpm.eth",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"network": "rinkeby"
},
"production": {
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
"appName": "contribution.open.aragonpm.eth",
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
"network": "mainnet"
}
},
"path": "contracts/Contribution.sol"
}

View File

@@ -0,0 +1,206 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/kernel/IKernel.sol";
interface IToken {
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public;
}
interface ContributorInterface {
function getContributorAddressById(uint32 contributorId) public view returns (address);
function getContributorIdByAddress(address contributorAccount) public view returns (uint32);
// TODO Maybe use for validation
// function exists(uint32 contributorId) public view returns (bool);
}
contract Contribution is AragonApp {
bytes32 public constant ADD_CONTRIBUTION_ROLE = keccak256("ADD_CONTRIBUTION_ROLE");
bytes32 public constant VETO_CONTRIBUTION_ROLE = keccak256("VETO_CONTRIBUTION_ROLE");
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[5] public appIds;
struct ContributionData {
uint32 contributorId;
uint32 amount;
bool claimed;
bytes32 hashDigest;
uint8 hashFunction;
uint8 hashSize;
string tokenMetadataURL;
uint256 confirmedAtBlock;
bool vetoed;
bool exists;
}
string internal name_;
string internal symbol_;
// map contribution ID to contributor
mapping(uint32 => uint32) public contributionOwner;
// map contributor to contribution IDs
mapping(uint32 => uint32[]) public ownedContributions;
mapping(uint32 => ContributionData) public contributions;
uint32 public contributionsCount;
uint32 public blocksToWait;
event ContributionAdded(uint32 id, uint32 indexed contributorId, uint32 amount);
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
event ContributionVetoed(uint32 id, address vetoedByAccount);
function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
blocksToWait = 40320; // 7 days; 15 seconds block time
initialized();
}
function getContract(uint8 appId) public view returns (address) {
IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
}
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
address contributor = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributor).getContributorIdByAddress(contributorAccount);
}
function getContributorAddressById(uint32 contributorId) public view returns (address) {
address contributor = getContract(uint8(Apps.Contributor));
return ContributorInterface(contributor).getContributorAddressById(contributorId);
}
//
// Token standard functions (ERC 721)
//
function name() external view returns (string) {
return name_;
}
function symbol() external view returns (string) {
return symbol_;
}
// Balance is amount of ERC271 tokens, not amount of kredits
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0));
uint32 contributorId = getContributorIdByAddress(owner);
return ownedContributions[contributorId].length;
}
function ownerOf(uint32 contributionId) public view returns (address) {
require(exists(contributionId));
uint32 contributorId = contributions[contributionId].contributorId;
return getContributorAddressById(contributorId);
}
function tokenOfOwnerByIndex(address owner, uint32 index) public view returns (uint32) {
uint32 contributorId = getContributorIdByAddress(owner);
return ownedContributions[contributorId][index];
}
function tokenMetadata(uint32 contributionId) public view returns (string) {
return contributions[contributionId].tokenMetadataURL;
}
//
// Custom functions
//
function totalKreditsEarned(bool confirmedOnly) public view returns (uint32 amount) {
for (uint32 i = 1; i <= contributionsCount; i++) {
ContributionData memory c = contributions[i];
if (!c.vetoed && (block.number >= c.confirmedAtBlock || !confirmedOnly)) {
amount += c.amount; // should use safemath
}
}
}
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) public view returns (uint32 amount) {
uint256 tokenCount = ownedContributions[contributorId].length;
for (uint256 i = 0; i < tokenCount; i++) {
uint32 cId = ownedContributions[contributorId][i];
ContributionData memory c = contributions[cId];
if (!c.vetoed && (block.number >= c.confirmedAtBlock || !confirmedOnly)) {
amount += c.amount; // should use safemath
}
}
}
function getContribution(uint32 contributionId) public view returns (uint32 id, uint32 contributorId, uint32 amount, bool claimed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
id = contributionId;
ContributionData storage c = contributions[id];
return (
id,
c.contributorId,
c.amount,
c.claimed,
c.hashDigest,
c.hashFunction,
c.hashSize,
c.confirmedAtBlock,
c.exists,
c.vetoed
);
}
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_CONTRIBUTION_ROLE) {
//require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint32[](0)), 'nope');
uint32 contributionId = contributionsCount + 1;
ContributionData storage c = contributions[contributionId];
c.exists = true;
c.amount = amount;
c.claimed = false;
c.contributorId = contributorId;
c.hashDigest = hashDigest;
c.hashFunction = hashFunction;
c.hashSize = hashSize;
if (contributionId < 10) {
c.confirmedAtBlock = block.number;
} else {
c.confirmedAtBlock = block.number + blocksToWait;
}
contributionsCount++;
contributionOwner[contributionId] = contributorId;
ownedContributions[contributorId].push(contributionId);
emit ContributionAdded(contributionId, contributorId, amount);
}
function veto(uint32 contributionId) public isInitialized auth(VETO_CONTRIBUTION_ROLE) {
ContributionData storage c = contributions[contributionId];
require(c.exists, 'NOT_FOUND');
require(!c.claimed, 'ALREADY_CLAIMED');
require(block.number < c.confirmedAtBlock, 'VETO_PERIOD_ENDED');
c.vetoed = true;
emit ContributionVetoed(contributionId, msg.sender);
}
function claim(uint32 contributionId) public isInitialized {
ContributionData storage c = contributions[contributionId];
require(c.exists, 'NOT_FOUND');
require(!c.claimed, 'ALREADY_CLAIMED');
require(!c.vetoed, 'VETOED');
require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE');
c.claimed = true;
address token = getContract(uint8(Apps.Token));
address contributorAccount = getContributorAddressById(c.contributorId);
uint256 amount = uint256(c.amount);
IToken(token).mintFor(contributorAccount, amount, contributionId);
emit ContributionClaimed(contributionId, c.contributorId, c.amount);
}
function exists(uint32 contributionId) public view returns (bool) {
return contributions[contributionId].exists;
}
}

View File

@@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity ^0.4.24;
contract Migrations {
address public owner;
@@ -8,7 +8,7 @@ contract Migrations {
if (msg.sender == owner) _;
}
function Migrations() public {
constructor() public {
owner = msg.sender;
}

View File

@@ -0,0 +1,4 @@
{
"name": "Contribution",
"description": "Kredits contribution app"
}

View File

@@ -0,0 +1,5 @@
var Migrations = artifacts.require('./Migrations.sol')
module.exports = function (deployer) {
deployer.deploy(Migrations)
}

View File

@@ -0,0 +1,5 @@
var Contribution = artifacts.require('Contribution.sol')
module.exports = function (deployer) {
deployer.deploy(Contribution)
}

28331
apps/contribution/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
{
"name": "kredits-contribution",
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
},
"devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11"
},
"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": "aragon contracts test"
},
"keywords": []
}

View File

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

View File

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

4
apps/contributor/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules
build
.cache
dist

View File

@@ -0,0 +1,14 @@
# Git files
.gitignore
# Build files
.cache
node_modules
build
# Lock files
package-lock.json
yarn.lock
# Others
test

View File

@@ -0,0 +1 @@
# Kredits Contributor

View File

@@ -0,0 +1,28 @@
{
"roles": [
{
"name": "Manage contributors",
"id": "MANAGE_CONTRIBUTORS_ROLE",
"params": []
}
],
"environments": {
"default": {
"network": "development",
"appName": "kredits-contributor.open.aragonpm.eth"
},
"rinkeby": {
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
"appName": "kredits-contributor.open.aragonpm.eth",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"network": "rinkeby"
},
"production": {
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
"appName": "contributor.open.aragonpm.eth",
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
"network": "mainnet"
}
},
"path": "contracts/Contributor.sol"
}

View File

@@ -0,0 +1,155 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/kernel/IKernel.sol";
interface ITokenBalance {
function balanceOf(address contributorAccount) public view returns (uint256);
}
interface IContributionBalance {
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) public view returns (uint32 amount);
function balanceOf(address owner) public view returns (uint256);
}
contract Contributor is AragonApp {
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
bytes32 public constant MANAGE_CONTRIBUTORS_ROLE = keccak256("MANAGE_CONTRIBUTORS_ROLE");
struct Contributor {
address account;
bytes32 hashDigest;
uint8 hashFunction;
uint8 hashSize;
bool exists;
}
mapping (address => uint32) public contributorIds;
mapping (uint32 => Contributor) public contributors;
uint32 public contributorsCount;
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token, Vault }
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[5] _appIds) public onlyInit {
appIds = _appIds;
initialized();
}
function getContract(uint8 appId) public view returns (address) {
IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
}
function coreContributorsCount() public view returns (uint32) {
uint32 count = 0;
for (uint32 i = 1; i <= contributorsCount; i++) {
if (isCoreTeam(i)) {
count += 1;
}
}
return count;
}
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[newAccount] = id;
contributors[id].account = newAccount;
emit ContributorAccountUpdated(id, oldAccount, newAccount);
}
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
Contributor storage c = contributors[id];
bytes32 oldHashDigest = c.hashDigest;
c.hashDigest = hashDigest;
c.hashFunction = hashFunction;
c.hashSize = hashSize;
ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
}
function addContributor(address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
require(!addressExists(account));
uint32 _id = contributorsCount + 1;
assert(!contributors[_id].exists); // this can not be acually
Contributor storage c = contributors[_id];
c.exists = true;
c.hashDigest = hashDigest;
c.hashFunction = hashFunction;
c.hashSize = hashSize;
c.account = account;
contributorIds[account] = _id;
contributorsCount += 1;
emit ContributorAdded(_id, account);
}
function isCoreTeam(uint32 id) view public returns (bool) {
// TODO: for simplicity we simply define the first contributors as core
// later this needs to be changed to something more dynamic
return id < 7;
}
function exists(uint32 id) view public returns (bool) {
return contributors[id].exists;
}
function addressIsCore(address account) view public returns (bool) {
uint32 id = getContributorIdByAddress(account);
return isCoreTeam(id);
}
function addressExists(address account) view public returns (bool) {
return getContributorByAddress(account).exists;
}
function getContributorIdByAddress(address account) view public returns (uint32) {
return contributorIds[account];
}
function getContributorAddressById(uint32 id) view public returns (address) {
return contributors[id].account;
}
function getContributorByAddress(address account) internal view returns (Contributor) {
uint32 id = contributorIds[account];
return contributors[id];
}
function getContributorById(uint32 _id) public view returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, uint32 totalKreditsEarned, uint256 contributionsCount, bool exists ) {
id = _id;
Contributor storage c = contributors[_id];
account = c.account;
hashDigest = c.hashDigest;
hashFunction = c.hashFunction;
hashSize = c.hashSize;
isCore = isCoreTeam(id);
address token = getContract(uint8(Apps.Token));
balance = ITokenBalance(token).balanceOf(c.account);
address contribution = getContract(uint8(Apps.Contribution));
totalKreditsEarned = IContributionBalance(contribution).totalKreditsEarnedByContributor(_id, true);
contributionsCount = IContributionBalance(contribution).balanceOf(c.account);
exists = c.exists;
}
function canPerform(address _who, address _where, bytes32 _what, uint256[] memory _how) public returns (bool) {
address sender = _who;
if (sender == address(-1)) {
sender = tx.origin;
}
// _what == keccak256('VOTE_PROPOSAL_ROLE')
if (_what == 0xd61216798314d2fc33e42ff2021d66707b1e38517d3f7166798a9d3a196a9c96) {
return contributorIds[sender] != uint256(0);
}
return addressIsCore(sender);
}
}

View File

@@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity ^0.4.24;
contract Migrations {
address public owner;
@@ -8,7 +8,7 @@ contract Migrations {
if (msg.sender == owner) _;
}
function Migrations() public {
constructor() public {
owner = msg.sender;
}

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

@@ -0,0 +1,4 @@
{
"name": "Contributor",
"description": "Kredits Contributor app"
}

View File

@@ -0,0 +1,5 @@
var Migrations = artifacts.require('./Migrations.sol')
module.exports = function (deployer) {
deployer.deploy(Migrations)
}

View File

@@ -0,0 +1,5 @@
var Contributor = artifacts.require('Contributor.sol')
module.exports = function (deployer) {
deployer.deploy(Contributor)
}

28331
apps/contributor/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
{
"name": "kredits-contributor",
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
},
"devDependencies": {
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11",
"@aragon/test-helpers": "^2.0.0"
},
"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": "aragon contracts test"
},
"keywords": []
}

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';
});
});
});
});

View File

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

1
apps/proposal/README.md Normal file
View File

@@ -0,0 +1 @@
# Kredits Proposal

33
apps/proposal/arapp.json Normal file
View File

@@ -0,0 +1,33 @@
{
"roles": [
{
"name": "Add proposal",
"id": "ADD_PROPOSAL_ROLE",
"params": []
},
{
"name": "Vote proposals",
"id": "VOTE_PROPOSAL_ROLE",
"params": []
}
],
"environments": {
"default": {
"network": "development",
"appName": "kredits-proposal.open.aragonpm.eth"
},
"rinkeby": {
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
"appName": "kredits-proposal.open.aragonpm.eth",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"network": "rinkeby"
},
"production": {
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
"appName": "proposal.open.aragonpm.eth",
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
"network": "mainnet"
}
},
"path": "contracts/Proposal.sol"
}

View File

@@ -0,0 +1,130 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/kernel/IKernel.sol";
interface IContributor {
function getContributorAddressById(uint32 contributorId) public view returns (address);
function getContributorIdByAddress(address contributorAccount) public view returns (uint32);
function exists(uint32 contributorId) public view returns (bool);
}
interface IContribution {
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public;
}
contract Proposal is AragonApp {
bytes32 public constant ADD_PROPOSAL_ROLE = keccak256("ADD_PROPOSAL_ROLE");
bytes32 public constant VOTE_PROPOSAL_ROLE = keccak256("VOTE_PROPOSAL_ROLE");
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[5] public appIds;
struct Proposal {
address creatorAccount;
uint32 contributorId;
uint16 votesCount;
uint16 votesNeeded;
uint32 amount;
bool executed;
bytes32 hashDigest;
uint8 hashFunction;
uint8 hashSize;
uint32[] voterIds;
mapping (uint32 => bool) votes;
bool exists;
}
mapping(uint32 => Proposal) public proposals;
uint32 public proposalsCount;
event ProposalCreated(uint32 id, address creatorAccount, uint32 contributorId, uint32 amount);
event ProposalVoted(uint32 id, uint32 voterId, uint16 totalVotes);
event ProposalExecuted(uint32 id, uint32 contributorId, uint32 amount);
function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
initialized();
}
function getContract(uint8 appId) public view returns (address) {
IKernel k = IKernel(kernel());
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
}
function addProposal(uint32 contributorId, uint32 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_PROPOSAL_ROLE) {
require(IContributor(getContract(uint8(Apps.Contributor))).exists(contributorId), 'CONTRIBUTOR_NOT_FOUND');
uint32 proposalId = proposalsCount + 1;
uint16 _votesNeeded = 1; //contributorsContract().coreContributorsCount() / 100 * 75;
Proposal storage p = proposals[proposalId];
p.creatorAccount = msg.sender;
p.contributorId = contributorId;
p.amount = amount;
p.hashDigest = hashDigest;
p.hashFunction = hashFunction;
p.hashSize = hashSize;
p.votesCount = 0;
p.votesNeeded = _votesNeeded;
p.exists = true;
proposalsCount++;
emit ProposalCreated(proposalId, msg.sender, p.contributorId, p.amount);
}
function getProposal(uint32 proposalId) public view returns (uint32 id, address creatorAccount, uint32 contributorId, uint16 votesCount, uint16 votesNeeded, uint32 amount, bool executed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint32[] voterIds, bool exists) {
id = proposalId;
Proposal storage p = proposals[id];
return (
id,
p.creatorAccount,
p.contributorId,
p.votesCount,
p.votesNeeded,
p.amount,
p.executed,
p.hashDigest,
p.hashFunction,
p.hashSize,
p.voterIds,
p.exists
);
}
function vote(uint32 proposalId) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
Proposal storage p = proposals[proposalId];
require(!p.executed, 'ALREADY_EXECUTED');
uint32 voterId = IContributor(getContract(uint8(Apps.Contributor))).getContributorIdByAddress(msg.sender);
require(p.votes[voterId] != true, 'ALREADY_VOTED');
p.voterIds.push(voterId);
p.votes[voterId] = true;
p.votesCount++;
if (p.votesCount >= p.votesNeeded) {
executeProposal(proposalId);
}
emit ProposalVoted(proposalId, voterId, p.votesCount);
}
function batchVote(uint32[] _proposalIds) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
for (uint32 i = 0; i < _proposalIds.length; i++) {
vote(_proposalIds[i]);
}
}
function executeProposal(uint32 proposalId) private {
Proposal storage p = proposals[proposalId];
require(!p.executed, 'ALREADY_EXECUTED');
require(p.votesCount >= p.votesNeeded, 'MISSING_VOTES');
p.executed = true;
IContribution(getContract(uint8(Apps.Contribution))).add(p.amount, p.contributorId, p.hashDigest, p.hashFunction, p.hashSize);
emit ProposalExecuted(proposalId, p.contributorId, p.amount);
}
}

View File

@@ -0,0 +1,23 @@
pragma solidity ^0.4.24;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "Proposal",
"description": "Kredits Proposal app"
}

View File

@@ -0,0 +1,5 @@
var Migrations = artifacts.require('./Migrations.sol')
module.exports = function (deployer) {
deployer.deploy(Migrations)
}

28331
apps/proposal/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
{
"name": "kredits-proposal",
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
},
"devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11"
},
"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": "aragon contracts test"
},
"keywords": []
}

View File

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

1
apps/proposal/truffle.js Normal file
View File

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

4
apps/token/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules
build
.cache
dist

14
apps/token/.ipfsignore Normal file
View File

@@ -0,0 +1,14 @@
# Git files
.gitignore
# Build files
.cache
node_modules
build
# Lock files
package-lock.json
yarn.lock
# Others
test

1
apps/token/README.md Normal file
View File

@@ -0,0 +1 @@
# Kredits Token

28
apps/token/arapp.json Normal file
View File

@@ -0,0 +1,28 @@
{
"roles": [
{
"name": "Mint token",
"id": "MINT_TOKEN_ROLE",
"params": []
}
],
"environments": {
"default": {
"network": "development",
"appName": "kredits-token.open.aragonpm.eth"
},
"rinkeby": {
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
"appName": "kredits-token.open.aragonpm.eth",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"network": "rinkeby"
},
"mainnet": {
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
"appName": "kredits-token.open.aragonpm.eth",
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
"network": "mainnet"
}
},
"path": "contracts/Token.sol"
}

View File

@@ -0,0 +1,173 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/lib/math/SafeMath.sol";
/**
* beause ERC20.sol conflicts with the aragon ERC20.sol this is copied and modified from:
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20.sol
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://eips.ethereum.org/EIPS/eip-20
* Originally based on code by FirstBlood:
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
* all accounts just by listening to said events. Note that this isn't required by the specification, and other
* compliant implementations may not do it.
*/
contract ERC20Token {
using SafeMath for uint256;
mapping (address => uint256) public _balances;
mapping (address => mapping (address => uint256)) private _allowed;
uint256 public _totalSupply;
string public name;
string public symbol;
uint8 public decimals;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev Gets the balance of the specified address.
* @param owner The address to query the balance of.
* @return A uint256 representing the amount owned by the passed address.
*/
function balanceOf(address owner) public view returns (uint256) {
return _balances[owner];
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param owner address The address which owns the funds.
* @param spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowed[owner][spender];
}
/**
* @dev Transfer token to a specified address
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function transfer(address to, uint256 value) public returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
*/
function approve(address spender, uint256 value) public returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
/**
* @dev Transfer tokens from one address to another.
* Note that while this function emits an Approval event, this is not required as per the specification,
* and other compliant implementations may not emit the event.
* @param from address The address which you want to send tokens from
* @param to address The address which you want to transfer to
* @param value uint256 the amount of tokens to be transferred
*/
function transferFrom(address from, address to, uint256 value) public returns (bool) {
_transfer(from, to, value);
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
return true;
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when _allowed[msg.sender][spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* Emits an Approval event.
* @param spender The address which will spend the funds.
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when _allowed[msg.sender][spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* Emits an Approval event.
* @param spender The address which will spend the funds.
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
return true;
}
/**
* @dev Transfer token for a specified addresses
* @param from The address to transfer from.
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function _transfer(address from, address to, uint256 value) internal {
require(to != address(0));
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(from, to, value);
}
/**
* @dev Internal function that mints an amount of the token and assigns it to
* an account. This encapsulates the modification of balances such that the
* proper events are emitted.
* @param account The account that will receive the created tokens.
* @param value The amount that will be created.
*/
function _mint(address account, uint256 value) internal {
require(account != address(0), 'invalid address');
_totalSupply = _totalSupply.add(value);
_balances[account] = _balances[account].add(value);
emit Transfer(address(0), account, value);
}
/**
* @dev Approve an address to spend another addresses' tokens.
* @param owner The address that owns the tokens.
* @param spender The address that will spend the tokens.
* @param value The number of tokens that can be spent.
*/
function _approve(address owner, address spender, uint256 value) internal {
require(spender != address(0));
require(owner != address(0));
_allowed[owner][spender] = value;
emit Approval(owner, spender, value);
}
}

View File

@@ -0,0 +1,31 @@
pragma solidity ^0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "./ERC20Token.sol";
contract Token is ERC20Token, AragonApp {
bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[5] public appIds;
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
function initialize(bytes32[5] _appIds) public onlyInit {
appIds = _appIds;
name = 'Kredits';
symbol = '₭S';
decimals = 18;
initialized();
}
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);
_mint(contributorAccount, amountInWei);
emit LogMint(contributorAccount, amount, contributionId);
}
}

View File

@@ -0,0 +1,23 @@
pragma solidity ^0.4.24;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}

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 {
// ...
}

4
apps/token/manifest.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "Token",
"description": "Kredits Token app"
}

View File

@@ -0,0 +1,5 @@
var Migrations = artifacts.require('./Migrations.sol')
module.exports = function (deployer) {
deployer.deploy(Migrations)
}

View File

@@ -0,0 +1,5 @@
var Token = artifacts.require('Token.sol')
module.exports = function (deployer) {
deployer.deploy(Token)
}

28331
apps/token/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

32
apps/token/package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "kredits-token",
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.2.0",
"@aragon/cli": "^5.9.6"
},
"devDependencies": {
"@aragon/test-helpers": "^2.0.0",
"eth-gas-reporter": "^0.2.0",
"ganache-cli": "^6.4.3",
"solidity-coverage": "^0.5.11"
},
"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": "aragon contracts test"
},
"keywords": []
}

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
});
});
});

1
apps/token/truffle.js Normal file
View File

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

60
arapp.json Normal file
View File

@@ -0,0 +1,60 @@
{
"roles": [
{
"name": "Add contributions",
"id": "ADD_CONTRIBUTION_ROLE",
"params": []
},
{
"name": "Veto contributions",
"id": "VETO_CONTRIBUTION_ROLE",
"params": []
},
{
"name": "Manage contributors",
"id": "MANAGE_CONTRIBUTORS_ROLE",
"params": []
},
{
"name": "Mint token",
"id": "MINT_TOKEN_ROLE",
"params": []
},
{
"name": "Add proposal",
"id": "ADD_PROPOSAL_ROLE",
"params": []
},
{
"name": "Vote proposal",
"id": "VOTE_PROPOSAL_ROLE",
"params": []
}
],
"environments": {
"development": {
"network": "development",
"apm": "open.aragonpm.eth",
"registry": "0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1",
"appName": "dummy.open.aragonpm.eth"
},
"rinkeby": {
"network": "rinkeby",
"registry": "0x98Df287B6C145399Aaa709692c8D308357bC085D",
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
"daoFactory": "0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d",
"appName": "dummy.open.aragonpm.eth",
"apm": "open.aragonpm.eth"
},
"kovan": {
"network": "kovan",
"appName": "dummy.aragonpm.eth"
},
"default": {
"network": "development",
"appName": "dummy.aragonpm.eth",
"apm": "open.aragonpm.eth"
}
},
"path": "contracts/misc/DummyApp.sol"
}

View File

@@ -1,13 +1,48 @@
let contractCalls = [
['Contributor', 'add', [{ account: '0x7e8f313c56f809188313aa274fa67ee58c31515d', name: 'bumi', isCore: true, kind: 'preson', url: '', github_username: 'bumi', github_uid: 318, wiki_username: 'bumi' }, {gasLimit: 200000}]],
['Contributor', 'add', [{ account: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', name: 'raucau', isCore: true, kind: 'person', url: '', github_username: 'skddc', github_uid: 842, wiki_username: 'raucau' }, {gasLimit: 200000}]],
['Operator', 'addProposal', [{ contributorId: 2, amount: 42, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
['Operator', 'addProposal', [{ contributorId: 3, amount: 23, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
['Operator', 'addProposal', [{contributorId: 3, amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
['Operator', 'vote', ['1', {gasLimit: 250000}]]
const contractCalls = [
['Contributor', 'add', [{
account: '0x7e8f313c56f809188313aa274fa67ee58c31515d',
name: 'bumi',
kind: 'person',
url: '',
github_username: 'bumi',
github_uid: 318,
gitea_username: 'bumi',
wiki_username: 'Bumi',
}, { gasLimit: 200000 }]],
['Contributor', 'add', [{
account: '0x49575f3DD9a0d60aE661BC992f72D837A77f05Bc',
name: 'raucao',
kind: 'person',
url: '',
github_username: 'skddc',
github_uid: 842,
gitea_username: 'raucao',
wiki_username: 'Basti',
}, { gasLimit: 200000 }]],
['Contributor', 'add', [{
account: '0xF722709ECC3B05c19d02E82a2a4A4021B8F48C62',
name: 'Manuel',
kind: 'person',
url: '',
github_username: 'fsmanuel',
github_uid: 54812,
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: 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 }]],
];
let funds = [
const funds = [
'0x7e8f313c56f809188313aa274fa67ee58c31515d',
'0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827'
'0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827',
];
module.exports = { contractCalls, funds };

View File

@@ -1,128 +0,0 @@
pragma solidity ^0.4.18;
// import basic ERC20 details to be able to call balanceOf
import 'zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol';
import './upgradeable/Upgradeable.sol';
contract Contributors is Upgradeable {
struct Contributor {
address account;
bytes32 ipfsHash;
uint8 hashFunction;
uint8 hashSize;
bool isCore;
bool exists;
}
mapping (address => uint) public contributorIds;
mapping (uint => Contributor) public contributors;
uint256 public contributorsCount;
event ContributorProfileUpdated(uint id, bytes32 oldIpfsHash, bytes32 newIpfsHash);
event ContributorAccountUpdated(uint id, address oldAccount, address newAccount);
event ContributorAdded(uint id, address account);
modifier onlyCoreOrOperator() {
require(msg.sender == registry.getProxyFor('Operator') || addressIsCore(msg.sender));
_;
}
function initialize(address sender) public payable {
require(msg.sender == address(registry));
uint _id = 1;
Contributor storage c = contributors[_id];
c.exists = true;
c.isCore = true;
c.account = sender;
contributorIds[sender] = _id;
contributorsCount += 1;
}
function coreContributorsCount() view public returns (uint) {
uint count = 0;
for (uint256 i = 1; i <= contributorsCount; i++) {
if (contributors[i].isCore) {
count += 1;
}
}
return count;
}
function updateContributorAccount(uint id, address oldAccount, address newAccount) public onlyCoreOrOperator {
contributorIds[oldAccount] = 0;
contributorIds[newAccount] = id;
contributors[id].account = newAccount;
ContributorAccountUpdated(id, oldAccount, newAccount);
}
function updateContributorIpfsHash(uint id, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public onlyCoreOrOperator {
Contributor storage c = contributors[id];
bytes32 oldIpfsHash = c.ipfsHash;
c.ipfsHash = ipfsHash;
c.hashFunction = hashFunction;
c.hashSize = hashSize;
ContributorProfileUpdated(id, oldIpfsHash, c.ipfsHash);
}
function addContributor(address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore) public onlyCoreOrOperator {
require(!addressExists(account));
uint _id = contributorsCount + 1;
assert(!contributors[_id].exists); // this can not be acually
Contributor storage c = contributors[_id];
c.exists = true;
c.isCore = isCore;
c.ipfsHash = ipfsHash;
c.hashFunction = hashFunction;
c.hashSize = hashSize;
c.account = account;
contributorIds[account] = _id;
contributorsCount += 1;
ContributorAdded(_id, account);
}
function isCore(uint id) view public returns (bool) {
return contributors[id].isCore;
}
function exists(uint id) view public returns (bool) {
return contributors[id].exists;
}
function addressIsCore(address account) view public returns (bool) {
return getContributorByAddress(account).isCore;
}
function addressExists(address account) view public returns (bool) {
return getContributorByAddress(account).exists;
}
function getContributorIdByAddress(address account) view public returns (uint) {
return contributorIds[account];
}
function getContributorAddressById(uint id) view public returns (address) {
return contributors[id].account;
}
function getContributorByAddress(address account) internal view returns (Contributor) {
uint id = contributorIds[account];
return contributors[id];
}
function getContributorById(uint _id) public view returns (uint id, address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore, uint balance, bool exists ) {
id = _id;
Contributor storage c = contributors[_id];
account = c.account;
ipfsHash = c.ipfsHash;
hashFunction = c.hashFunction;
hashSize = c.hashSize;
isCore = c.isCore;
exists = c.exists;
ERC20Basic token = ERC20Basic(registry.getProxyFor('Token'));
balance = token.balanceOf(account);
}
}

99
contracts/KreditsKit.sol Normal file
View File

@@ -0,0 +1,99 @@
pragma solidity 0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/kernel/Kernel.sol";
import "@aragon/os/contracts/acl/ACL.sol";
import "@aragon/kits-base/contracts/KitBase.sol";
import "@aragon/apps-vault/contracts/Vault.sol";
import "../apps/contribution/contracts/Contribution.sol";
import "../apps/contributor/contracts/Contributor.sol";
import "../apps/token/contracts/Token.sol";
import "../apps/proposal/contracts/Proposal.sol";
contract KreditsKit is KitBase {
// ensure alphabetic order
enum Apps { Contribution, Contributor, Proposal, Token, Vault }
bytes32[5] public appIds;
event DeployInstance(address dao);
event InstalledApp(address dao, address appProxy, bytes32 appId);
constructor (DAOFactory _fac, ENS _ens, bytes32[5] _appIds) public KitBase(_fac, _ens) {
appIds = _appIds;
}
function newInstance() public returns (Kernel dao) {
address root = msg.sender;
dao = fac.newDAO(this);
ACL acl = ACL(dao.acl());
acl.createPermission(this, dao, dao.APP_MANAGER_ROLE(), this);
Contributor contributor = Contributor(_installApp(dao, appIds[uint8(Apps.Contributor)]));
contributor.initialize(root, appIds);
acl.createPermission(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), this);
Token token = Token(_installApp(dao, appIds[uint8(Apps.Token)]));
token.initialize(appIds);
Contribution contribution = Contribution(_installApp(dao, appIds[uint8(Apps.Contribution)]));
contribution.initialize(appIds);
Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)]));
proposal.initialize(appIds);
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.VETO_CONTRIBUTION_ROLE(), this);
acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE());
uint256[] memory params = new uint256[](1);
params[0] = uint256(203) << 248 | uint256(1) << 240 | uint240(contributor);
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.ADD_CONTRIBUTION_ROLE(), params);
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.VETO_CONTRIBUTION_ROLE(), params);
acl.grantPermissionP(acl.ANY_ENTITY(), contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), params);
//acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE();
acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this);
acl.grantPermissionP(acl.ANY_ENTITY(), proposal, proposal.VOTE_PROPOSAL_ROLE(), params);
acl.createPermission(root, proposal, proposal.ADD_PROPOSAL_ROLE(), this);
//acl.grantPermissionP(address(-1), proposal, proposal.ADD_PROPOSAL_ROLE(), params);
acl.grantPermission(acl.ANY_ENTITY(), proposal, proposal.ADD_PROPOSAL_ROLE());
acl.setPermissionManager(root, proposal, proposal.VOTE_PROPOSAL_ROLE());
acl.setPermissionManager(root, proposal, proposal.ADD_PROPOSAL_ROLE());
acl.setPermissionManager(root, contribution, contribution.ADD_CONTRIBUTION_ROLE());
acl.setPermissionManager(root, contribution, contribution.VETO_CONTRIBUTION_ROLE());
acl.setPermissionManager(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE());
acl.createPermission(root, token, token.MINT_TOKEN_ROLE(), this);
acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE());
acl.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);
emit DeployInstance(dao);
return dao;
}
function _installApp(Kernel _dao, bytes32 _appId) internal returns (AragonApp) {
address baseAppAddress = latestVersionAppBase(_appId);
require(baseAppAddress != address(0), "App should be deployed");
AragonApp appProxy = AragonApp(_dao.newAppInstance(_appId, baseAppAddress, new bytes(0), true));
emit InstalledApp(_dao, appProxy, _appId);
return appProxy;
}
}

View File

@@ -1,130 +0,0 @@
pragma solidity ^0.4.18;
// ToDo: only load interfaces
import './Token.sol';
import './Contributors.sol';
contract Operator is Upgradeable {
struct Proposal {
address creatorAccount;
uint contributorId;
uint votesCount;
uint votesNeeded;
uint256 amount;
bool executed;
bytes32 ipfsHash;
uint8 hashFunction;
uint8 hashSize;
uint256[] voterIds;
mapping (uint256 => bool) votes;
bool exists;
}
mapping(uint256 => Proposal) public proposals;
uint256 public proposalsCount;
event ProposalCreated(uint256 id, address creatorAccount, uint256 contributorId, uint256 amount);
event ProposalVoted(uint256 id, uint256 voterId, uint256 totalVotes);
event ProposalExecuted(uint256 id, uint256 contributorId, uint256 amount);
modifier coreOnly() {
require(contributorsContract().addressIsCore(msg.sender));
_;
}
modifier contributorOnly() {
require(contributorsContract().addressExists(msg.sender));
_;
}
modifier noEther() {
require(msg.value == 0);
_;
}
function contributorsContract() view public returns (Contributors) {
return Contributors(registry.getProxyFor('Contributors'));
}
function tokenContract() view public returns (Token) {
return Token(registry.getProxyFor('Token'));
}
function contributorsCount() view public returns (uint) {
return contributorsContract().contributorsCount();
}
function coreContributorsCount() view public returns (uint) {
return contributorsContract().coreContributorsCount();
}
function addProposal(uint contributorId, uint256 amount, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public {
require(contributorsContract().exists(contributorId));
uint256 proposalId = proposalsCount + 1;
uint256 _votesNeeded = contributorsContract().coreContributorsCount() / 100 * 75;
var p = proposals[proposalId];
p.creatorAccount = msg.sender;
p.contributorId = contributorId;
p.amount = amount;
p.ipfsHash = ipfsHash;
p.hashFunction = hashFunction;
p.hashSize = hashSize;
p.votesCount = 0;
p.votesNeeded = _votesNeeded;
p.exists = true;
proposalsCount++;
ProposalCreated(proposalId, msg.sender, p.contributorId, p.amount);
}
function getProposal(uint proposalId) public view returns (uint256 id, address creatorAccount, uint256 contributorId, uint256 votesCount, uint256 votesNeeded, uint256 amount, bool executed, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, uint256[] voterIds, bool exists) {
id = proposalId;
Proposal storage p = proposals[id];
return (
id,
p.creatorAccount,
p.contributorId,
p.votesCount,
p.votesNeeded,
p.amount,
p.executed,
p.ipfsHash,
p.hashFunction,
p.hashSize,
p.voterIds,
p.exists
);
}
function vote(uint256 proposalId) public coreOnly {
var p = proposals[proposalId];
require(!p.executed);
uint256 voterId = contributorsContract().getContributorIdByAddress(msg.sender);
require(p.votes[voterId] != true);
p.voterIds.push(voterId);
p.votes[voterId] = true;
p.votesCount++;
if (p.votesCount >= p.votesNeeded) {
executeProposal(proposalId);
}
ProposalVoted(proposalId, voterId, p.votesCount);
}
function batchVote(uint256[] _proposalIds) public coreOnly {
for (uint256 i = 0; i < _proposalIds.length; i++) {
vote(_proposalIds[i]);
}
}
function executeProposal(uint proposalId) private {
var p = proposals[proposalId];
require(!p.executed);
require(p.votesCount >= p.votesNeeded);
address recipientAddress = contributorsContract().getContributorAddressById(p.contributorId);
tokenContract().mintFor(recipientAddress, p.amount, proposalId);
p.executed = true;
ProposalExecuted(proposalId, p.contributorId, p.amount);
}
}

View File

@@ -1,27 +0,0 @@
pragma solidity ^0.4.18;
import 'zeppelin-solidity/contracts/token/ERC20/BasicToken.sol';
import './upgradeable/Upgradeable.sol';
contract Token is Upgradeable, BasicToken {
string public name;
string public symbol;
uint8 public decimals;
event LogMint(address indexed recipient, uint256 amount, uint256 proposalId);
function initialize(address sender) public payable {
require(msg.sender == address(registry));
name = 'Kredits';
symbol = 'K';
decimals = 18;
}
function mintFor(address contributorAccount, uint256 amount, uint proposalId) onlyRegistryContractFor('Operator') public {
totalSupply_ = totalSupply_.add(amount);
balances[contributorAccount] = balances[contributorAccount].add(amount);
LogMint(contributorAccount, amount, proposalId);
}
}

View File

@@ -0,0 +1,13 @@
pragma solidity 0.4.24;
import "@aragon/os/contracts/apm/APMNamehash.sol";
contract APMNamehashOpen is APMNamehash {
bytes32 public constant OPEN_TITLE = keccak256("open");
bytes32 public constant OPEN_APM_NODE = keccak256(abi.encodePacked(APM_NODE, OPEN_TITLE));
function apmNamehashOpen(string name) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(OPEN_APM_NODE, keccak256(name)));
}
}

View File

@@ -0,0 +1,16 @@
pragma solidity 0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
// This is a "Dummy" app which's only purpose to exist is because
// Aragon's CLI still doesn't support running a Kit inside a project
// which isn't considered to be a "valid" Aragon project.
// It requires us to have an arrap.json file pointing to the contract
// and a manifest.json file which describes the front-end structure.
contract DummyApp is AragonApp {
function initialize() public onlyInit {
initialized();
}
}

View File

@@ -0,0 +1,23 @@
pragma solidity ^0.4.4;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
function constructor() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}

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

@@ -1,53 +0,0 @@
pragma solidity ^0.4.18;
/**
* @title IRegistry
* @dev This contract represents the interface of a registry contract
*/
interface IRegistry {
/**
* @dev This event will be emitted every time a new proxy is created
* @param name of the contract, as specified in the registry
* @param proxy representing the address of the proxy created
*/
event ProxyCreated(string name, address proxy);
/**
* @dev This event will be emitted every time a new implementation is registered
* @param name of the contract, as specified in the registry
* @param version representing the version name of the registered implementation
* @param implementation representing the address of the registered implementation
*/
event VersionAdded(string name, uint version, address implementation);
/**
* @dev This event will be emitted every time a proxy is upgraded to a new version
* @param name of the contract, as specified in the registry
* @param version representing the version name of the registered implementation
*/
event ProxyImplementationUpgraded(string name, uint version);
/**
* @dev Registers a new version with its implementation address
* @param name of the contract, as specified in the registry
* @param implementation representing the address of the new implementation to be registered
*/
function addVersion(string name, address implementation) public;
/**
* @dev Tells the address of the implementation for a given version
* @param name of the contract, as specified in the registry
* @param version to query the implementation of
* @return address of the implementation registered for the given version
*/
function getVersion(string name, uint version) public view returns (address);
/**
* @dev Tells the latest address of the implementation
* @param name of the contract, as specified in the registry
* @return address of the implementation registered for the latest version
*/
function getLatestVersion(string name) public view returns (address);
function getProxyFor(string name) public view returns (address);
}

View File

@@ -1,36 +0,0 @@
pragma solidity ^0.4.18;
/**
* @title Proxy
* @dev Gives the possibility to delegate any call to a foreign implementation.
*/
contract Proxy {
/**
* @dev Tells the address of the implementation where every call will be delegated.
* @return address of the implementation to which it will be delegated
*/
function implementation() public view returns (address);
/**
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
* This function will return whatever the implementation call returns
*/
function () payable public {
address _impl = implementation();
require(_impl != address(0));
bytes memory data = msg.data;
assembly {
let result := delegatecall(gas, _impl, add(data, 0x20), mload(data), 0, 0)
let size := returndatasize
let ptr := mload(0x40)
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}

View File

@@ -1,86 +0,0 @@
pragma solidity ^0.4.18;
import './IRegistry.sol';
import './Upgradeable.sol';
import './UpgradeabilityProxy.sol';
/**
* @title Registry
* @dev This contract works as a registry of versions, it holds the implementations for the registered versions.
*/
contract Registry is IRegistry {
// mapping of contract names to versions to implementation
// "Token" => "1.0.0" => "0x123"
mapping(bytes32 => mapping(uint => address)) public versions;
// current version for a certain contract
mapping(bytes32 => uint) public currentVersions;
// mapping of the contract names to the proxy addresses
mapping(bytes32 => address) public proxies;
/**
* @dev Registers a new version with its implementation address
* @param name of the contract
* @param implementation representing the address of the new implementation to be registered
*/
function addVersion(string name, address implementation) public {
bytes32 key = keccak256(name);
currentVersions[key] = currentVersions[key] + 1;
uint version = currentVersions[key];
require(versions[key][version] == 0x0);
versions[key][version] = implementation;
VersionAdded(name, version, implementation);
}
/**
* @dev Tells the address of the implementation for a given version
* @param name of the contract
* @param version to query the implementation of
* @return address of the implementation registered for the given version
*/
function getVersion(string name, uint version) public view returns (address) {
bytes32 key = keccak256(name);
return versions[key][version];
}
function getLatestVersion(string name) public view returns (address) {
bytes32 key = keccak256(name);
uint current = currentVersions[key];
return getVersion(name, current);
}
function getProxyFor(string name) public view returns (address) {
bytes32 key = keccak256(name);
return proxies[key];
}
function upgrade(string name, uint version) public {
bytes32 key = keccak256(name);
UpgradeabilityProxy(proxies[key]).upgradeTo(version);
ProxyImplementationUpgraded(name, version);
}
function upgradeToLatest(string name) public {
bytes32 key = keccak256(name);
uint current = currentVersions[key];
upgrade(name, current);
}
/**
* @dev Creates an upgradeable proxy
* @param name of the contract
* @param version representing the first version to be set for the proxy
* @return address of the new proxy created
*/
function createProxy(string name, uint version) public payable returns (UpgradeabilityProxy) {
bytes32 key = keccak256(name);
require(proxies[key] == 0x0);
UpgradeabilityProxy proxy = new UpgradeabilityProxy(name, version);
proxies[key] = address(proxy);
Upgradeable(proxy).initialize.value(msg.value)(msg.sender);
ProxyCreated(name, proxy);
return proxy;
}
}

View File

@@ -1,28 +0,0 @@
pragma solidity ^0.4.18;
import './Proxy.sol';
import './IRegistry.sol';
import './UpgradeabilityStorage.sol';
/**
* @title UpgradeabilityProxy
* @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
*/
contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
function UpgradeabilityProxy(string _name, uint _version) public {
_proxiedContractName = _name;
registry = IRegistry(msg.sender);
upgradeTo(_version);
}
/**
* @dev Upgrades the implementation to the requested version
* @param _version representing the version name of the new implementation to be set
*/
function upgradeTo(uint _version) public {
require(msg.sender == address(registry));
_implementation = registry.getVersion(_proxiedContractName, _version);
}
}

View File

@@ -1,37 +0,0 @@
pragma solidity ^0.4.18;
import './IRegistry.sol';
/**
* @title UpgradeabilityStorage
* @dev This contract holds all the necessary state variables to support the upgrade functionality
*/
contract UpgradeabilityStorage {
// Versions registry
IRegistry internal registry;
// Address of the current implementation
address internal _implementation;
// contract name
string public _proxiedContractName;
modifier requireRegistry() {
require(address(registry) != 0x0);
_;
}
modifier onlyRegistryContractFor(string name) {
require(address(registry) != 0x0);
require(msg.sender == registry.getProxyFor(name));
_;
}
/**
* @dev Tells the address of the current implementation
* @return address of the current implementation
*/
function implementation() public view returns (address) {
return _implementation;
}
}

View File

@@ -1,19 +0,0 @@
pragma solidity ^0.4.18;
import './UpgradeabilityStorage.sol';
/**
* @title Upgradeable
* @dev This contract holds all the minimum required functionality for a behavior to be upgradeable.
* This means, required state variables for owned upgradeability purpose and simple initialization validation.
*/
contract Upgradeable is UpgradeabilityStorage {
/**
* @dev Validates the caller is the versions registry.
* THIS FUNCTION SHOULD BE OVERRIDDEN CALLING SUPER
* @param sender representing the address deploying the initial behavior of the contract
*/
function initialize(address sender) public payable {
require(msg.sender == address(registry));
}
}

View File

@@ -0,0 +1,53 @@
# Contribution deployments
aragon apm publish major --environment=rinkeby"
## 2019-04-24 update balances
✔ Successfully published kredits-contribution.open.aragonpm.eth v6.0.0:
Contract address: 0x2c083EEA83fd3a99C93759D97D0317A43261c758
Content (ipfs): QmULpSqz7BgTFmDu8AL7YZZEz525xkcEzf3dPKtbRdUtFs
Transaction hash: 0x8b01c4c00162e918659d267a2beaf33b578e2aaf9f427f1aa9a43029333c5cd7
## 2019-04-10 - Weltempfänger release
✔ Successfully published kredits-contribution.open.aragonpm.eth v5.0.0:
Contract address: 0xe0f7dB486321b917e3A986Bdb2F2b9d51BA98fa9
Content (ipfs): QmU3XEBb4f5jU8MFFEpwaa95C1mhc82UeYLRWLrKsvcQNw
Transaction hash: 0xd736ff5f79f8142be3fad1a50580fb40aa468838da397f8630285fd91a445af3
## 2019-04-04
✔ Successfully published kredits-contribution.open.aragonpm.eth v4.0.0:
Contract address: 0x7485e8fbde0112C53587079db450Eb002D359372
Content (ipfs): QmZKxYPm8wz4phgL4428Gh7MjmbyFFDMP2st7qhNL9qGDQ
Transaction hash: 0x7d9be7920db675be88e8f60ebf08dc62ee77c4e6e454c5fbf0f91f6ac97e4c26
## 2019-03-26
### v3.0.0 appids
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-contribution.open.aragonpm.eth v3.0.0:
Contract address: 0x9b4954834f070380faf9B6CB3794C7eA92d3B506
Content (ipfs): Qma3yvT5AmBbJHL8WkpXHs7aCFqpGd9ZaMpbiz3cT6Un59
Transaction hash: 0xc2b2d19e1b6d68ba50ed051a35c22eac74c69bd50665aed65488f9209171d382
## 2019-03-25
### v2.0.0 updated appid hashes
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-contribution.open.aragonpm.eth v2.0.0:
Contract address: 0x2765F13d82B83C0C9d770715e1fB376ab01C0361
Content (ipfs): QmYiv1cMh6cj8pcbmaTUAWxf93k4UhN8mPJWeqEo7BEkMx
Transaction hash: 0xe4841a6552527c8fbeb6aa44769f95ce60d99413958c6289f67e8ec83823ee96
### v1.0.0
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-contribution.open.aragonpm.eth v1.0.0:
Contract address: 0x1F460107361047064d982f61002D1BdEb02Ce705
Content (ipfs): QmQ6rTWCGcseCmGb6thYG2kwijHk6W84qaFPeftZ4bUY2k
Transaction hash: 0xeee90c5d18a8cb8ac845f52a4202cd62b27c23b4251b69c3681a854786b6e336

View File

@@ -0,0 +1,51 @@
# Contributor deployments
aragon apm publish major --environment=rinkeby
## 2019-04-25 canPerform fix
✔ Successfully published kredits-contributor.open.aragonpm.eth v6.0.0:
Contract address: 0xA5379D49C718845A1BD7720c6BE3872bA69906cc
Content (ipfs): QmdennNV6s2FNpe6QNYxrUsUXPVdnQGvh1vCi22Tqs8ojq
Transaction hash: 0x51077afeff70a24e87c78bb23ea13bdb9b4445bd43ea7a74a4178fadfeeb6c35
## 2019-04-24 update balances
✔ Successfully published kredits-contributor.open.aragonpm.eth v5.0.0:
Contract address: 0xadefa3b66b68a127Fe38bEa1813b844EE69CFD86
Content (ipfs): QmeygbQgoj2McLWzo9hJayLWuBZqFaK4HTpa5qLeQdkn5K
Transaction hash: 0x4237a9636f6e4a8190e0d5bcfa85a452da097bf654a173a88e0e1de3d078f08d
## 2019-04-10 - Weltempfänger release
✔ Successfully published kredits-contributor.open.aragonpm.eth v4.0.0:
Contract address: 0x08a6D4D915FCAA5524F05F5F715a6C17cB6eeA6B
Content (ipfs): QmR62PWwe1EzommfkhJDYcTvHoZjbXuv9dTG6vCn5dWCsb
Transaction hash: 0xd5317c9e207a413485c55ec3046b09d467d978443680304737a6d7d3db0c90e1
## 2019-04-04
✔ Successfully published kredits-contributor.open.aragonpm.eth v3.0.0:
Contract address: 0x95D8458E28C8de7216279512601A3B9Dc512D70B
Content (ipfs): QmSpHnmsf8FybvqfD49kwxvDixwiBUR7D5yG4BWSnnwCPS
Transaction hash: 0x736f9751b07a91178f453c279ecb57604b3b5686ae5d7115880f3b27fbeb50f2
## 2019-03-26
### v2.0.0 support for appids
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-contributor.open.aragonpm.eth v2.0.0:
Contract address: 0xf8e7B45b3c5A98dbE3D69C6828052dfD9fe2dc69
Content (ipfs): QmTDduMJVUVcqz5SgVEns1xwY9LqYrMoAyYcx3pMrPxn6i
Transaction hash: 0x48b38f32f5dcb52a0a8603743b66a7ca490fec04ccb1888dcfd37106bbd3b886
## 2019-03-25
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-contributor.open.aragonpm.eth v1.0.0:
Contract address: 0x6D80EFEE6F9A40AA86Ef7c4C95c8b2e453d260fb
Content (ipfs): QmbGSQPwi3AXHjDFG2fkMpJrBJLtyuaA6DVPMkFTfMpksn
Transaction hash: 0x26376c59dfdb617c35b740a0f110bf3040cdad0103593cdc788267a84d9847b9

View File

@@ -0,0 +1,57 @@
# Kredits deployment
## 2019-04-25 canPerfom fix
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
✔ Fetching kredits-contributor.open.aragonpm.eth@latest
✔ Upgrading app
✔ Successfully executed: "Set the resolving address of 'kredits-contributor.open.aragonpm.eth' in namespace 'App code' to 0xA5379D49C718845A1BD7720c6BE3872bA69906cc"
## 2019-04-24 upgrade contributor and contribution
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
eth-provider | Invalid provider preset/location: "local"
✔ Fetching kredits-contributor.open.aragonpm.eth@latest
✔ Upgrading app
✔ Successfully executed: "Set the resolving address of 'kredits-contributor.open.aragonpm.eth' in namespace 'App code' to 0xadefa3b66b68a127Fe38bEa1813b844EE69CFD86"
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contribution.open.aragonpm.eth --environment=rinkeby
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
✔ Upgrading app
✔ Successfully executed: "Set the resolving address of 'kredits-contribution.open.aragonpm.eth' in namespace 'App code' to 0x2c083EEA83fd3a99C93759D97D0317A43261c758"
## 2019-04-10 - Weltempfänger release
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
Created new DAO at: 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14
## 2019-04-04
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
Created new DAO at: 0xcd75458fbc4aa2231252d5b21f1391fd031e5cb2
### 2019-03-26
kredits/truffle-kredits@aragonos » truffle exec scripts/new-dao.js --network=rinkeby
Using network 'rinkeby'.
Deploying to networkId: 4
Using KreditsKit at: 0x1d6a9c2146a330575ee860eef9a012b5ff7caa68
Created new DAO at: 0x95a7ce185efc2d1f13efd2a00ee9247c51ea7009"
### 2019-03-25
kredits/truffle-kredits@aragonos » aragon contracts exec scripts/new-dao.js --network=rinkeby
Use of `--network` is deprecated and has been replaced with `--environment`. You may need to update your arapp.json
Passing the command to Truffle
Using network 'rinkeby'.
Deploying to networkId: 4
Using KreditsKit at: 0xf4f3963718e5c2b426dd5c3ef0ab4b31ffb7a318
Created new DAO at: 0x8b7c0bec9476ce08d9769a87d272b03b350712e2
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
https://rinkeby.etherscan.io/tx/0x4deb02b3740b3baa7735097d57c1456a5cb329ee741d123478fdb5114e2c305b

View File

@@ -0,0 +1,62 @@
# KreditsKit deployments
## 2019-04-04
Deploying to networkId: 4
Using ENS at: 0x98Df287B6C145399Aaa709692c8D308357bC085D
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
Found apps: [contribution,contributor,proposal,token].open.aragonpm.eth
Deployed KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
## 2019-03-26
Using network 'rinkeby'.
Deploying to networkId: 4
Using ENS at: 0x98Df287B6C145399Aaa709692c8D308357bC085D
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
Found apps: [contribution,contributor,proposal,token].open.aragonpm.eth
Deployed KreditsKit at: 0x1d6a9c2146a330575ee860eef9a012b5ff7caa68
### fails
a few deployments to fix the deploy script
## 2019-03-25
### fixed kit with correct appids
kredits/truffle-kredits@aragonos » aragon contracts exec scripts/deploy-kit.js --debug --network=rinkeby
Use of `--network` is deprecated and has been replaced with `--environment`. You may need to update your arapp.json
Passing the command to Truffle
Using network 'rinkeby'.
Deploying to networkId: 4
Using ENS at: 0x98Df287B6C145399Aaa709692c8D308357bC085D
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
Found apps: [contribution,contributor,proposal,token].open.aragonpm.eth
Deployed KreditsKit at: 0xf4f3963718e5c2b426dd5c3ef0ab4b31ffb7a318
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
### test with fixed deploy script
kredits/truffle-kredits@aragonos » ENS=0x98df287b6c145399aaa709692c8d308357bc085d DAO_FACTORY=0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d truffle exec scripts/deploy-kit.js --network=rinkeby
Using network 'rinkeby'.
Deploying to networkId: 4
Using ENS at: 0x98df287b6c145399aaa709692c8d308357bc085d
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
Deployed KreditsKit at: 0x83afd3c99563fc467aec69e0187ffd53fc8faa76
### success
kredits/truffle-kredits@aragonos » ENS=0x98df287b6c145399aaa709692c8d308357bc085d DAO_FACTORY=0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d truffle exec scripts/deploy-kit.js --network=rinkeby
Using network 'rinkeby'.
Using ENS at: 0x98df287b6c145399aaa709692c8d308357bc085d
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
Deployed KreditsKit at: 0x1fd2f9206addaf86f3ef921a3b7c84400374ba68
### deployment script error:
deployment script failure at: https://rinkeby.etherscan.io/tx/0x3571b889b6b9b2b3f26dd0ee7fb82c7ece90b28d910078f2e06753d878832af4"

View File

@@ -0,0 +1,43 @@
# Proposal deployments
## 2019-04-10 - Weltempfänger release
✔ Successfully published kredits-proposal.open.aragonpm.eth v5.0.0:
Contract address: 0x4ce5b0286483c66b861e5599a199054687434552
Content (ipfs): QmNYXEcmvKTGxYiob7WUf85oZhdmFDCuGiA6TsRrDE9TYb
Transaction hash: 0x0482b58a1ba87d494c6391026399d0ac41b45384330d916f3f99ba70e501584b
## 2019-04-04
✔ Successfully published kredits-proposal.open.aragonpm.eth v4.0.0:
Contract address: 0x4993275362Ba50D76f349A262B7b842e7FbD7490
Content (ipfs): QmesCPKLapASPTB3rnPpSdD7ULkg8BQwRcpdE1B8WwfSh7
Transaction hash: 0xe4be7b1a75b663eb345b957b216a8476b0f75e2bbfc5880943b05c82fab15dff
## 2019-03-26
### v3.0.0 appids
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-proposal.open.aragonpm.eth v3.0.0:
Contract address: 0x9f47c31aBB6F53ff2fec09C0bF79c3337C20f5AA
Content (ipfs): Qmdxg33FxAQSH7U8oTApaM5SgUUC9btiA6tu5Hystzp5tV
Transaction hash: 0xceb572f3fff368b9f07fc835577529a113e2de8ff7972a51ffaf4c63acbda9eb
## 2019-03-25
### v2.0.0 updated appid hashes
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-proposal.open.aragonpm.eth v2.0.0:
Contract address: 0x0a48dc5415f4d7A3B2B4a9aaD4A7a8775f923ce3
Content (ipfs): QmZej9xPJN7aTiQ7SzWziRuzEjjfMzjPakcGYcoN8QQBMH
Transaction hash: 0xf14c308b9f92b43a719fab2602c624dc2e11d0f629a0be9a6ec8ac47719ee9ca
### v1.0.0
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-proposal.open.aragonpm.eth v1.0.0:
Contract address: 0xFc04eB3eF666507F96A22d330d8a852d8eC996EA
Content (ipfs): QmRTzoYr7B5f8gDGY8RmoodJkMm59D4jSJLZNRnhAd4wCg
Transaction hash: 0xce419d9d555551eefc624a7ac87c19b5d660eb9c4fe0da611cd5e28e3ee6844f

View File

@@ -0,0 +1,34 @@
# Token deployments
## 2019-04-10 - Weltempfänger release
✔ Successfully published kredits-token.open.aragonpm.eth v4.0.0:
Contract address: 0x05E0C2bbdA8e5BeE22AC1E20C1457dA4de63aE26
Content (ipfs): QmUuYLRMRNZcundUk2pxVaSjMNvtB7hzdf3eyoaUNqDPow
Transaction hash: 0x98c28b5ca645904d56eb83c4783682f018c0fcee015b3a3d5fa8bd609223fb89
## 2019-04-04
✔ Successfully published kredits-token.open.aragonpm.eth v3.0.0:
Contract address: 0xd9913A96e087f50E71BF14c62cBCa3b9635392A9
Content (ipfs): QmfZ7LwjkQRuLsEnVjrEF3ryTaHsL6YTxffiiDS5KWmHQG
Transaction hash: 0x102b27e154d1e144ec084f5e8dc78e1626fda9f26c20db3e3b230fac381c317a
## 2019-03-26
### v2.0.0 support for appIds
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-token.open.aragonpm.eth v2.0.0:
Contract address: 0xc126919B3b30F14b848c2cc66Ec21A1e85a7c621
Content (ipfs): QmWB9JrWa93vtdv5VG2yohiWTbDiuzbz9P58apJdP3FnNP
Transaction hash: 0xa5ccd532a91d67b0616ee5505144988be4360440daf70dc2f5108dd2a59f3d68
## 2019-03-25
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
✔ Successfully published kredits-token.open.aragonpm.eth v1.0.0:
Contract address: 0xB4147Be6d4bcC790c6CbD3d508354DDfd3EbC8e6
Content (ipfs): QmQPue7WzQhaXbTLJwyZXSHaRY1u5ezWxyVmBP8bEgGoTE
Transaction hash: 0xa7866d81e236adfeaff6bf2d5dbc9f9757fbc1b0ce689357901194913fe93a3b"

BIN
docs/kredits-diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1
lib/abis/ACL.json Normal file

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

@@ -1 +0,0 @@
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contributors","outputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"contributorIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldIpfsHash","type":"bytes32"},{"indexed":false,"name":"newIpfsHash","type":"bytes32"}],"name":"ContributorProfileUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldAccount","type":"address"},{"indexed":false,"name":"newAccount","type":"address"}],"name":"ContributorAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"account","type":"address"}],"name":"ContributorAdded","type":"event"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"oldAccount","type":"address"},{"name":"newAccount","type":"address"}],"name":"updateContributorAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"updateContributorIpfsHash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"}],"name":"addContributor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"isCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"exists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressIsCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"getContributorAddressById","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"getContributorById","outputs":[{"name":"id","type":"uint256"},{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"balance","type":"uint256"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]

1
lib/abis/Kernel.json Normal file

File diff suppressed because one or more lines are too long

1
lib/abis/KreditsKit.json Normal file
View File

@@ -0,0 +1 @@
[{"constant":true,"inputs":[],"name":"ens","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fac","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"appId","type":"bytes32"}],"name":"latestVersionAppBase","outputs":[{"name":"base","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"appIds","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_fac","type":"address"},{"name":"_ens","type":"address"},{"name":"_appIds","type":"bytes32[4]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"dao","type":"address"}],"name":"DeployInstance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"dao","type":"address"},{"indexed":false,"name":"appProxy","type":"address"},{"indexed":false,"name":"appId","type":"bytes32"}],"name":"InstalledApp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"appProxy","type":"address"},{"indexed":false,"name":"appId","type":"bytes32"}],"name":"InstalledApp","type":"event"},{"constant":false,"inputs":[],"name":"newInstance","outputs":[{"name":"dao","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

View File

@@ -1 +0,0 @@
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposalsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"creatorAccount","type":"address"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"voterId","type":"uint256"},{"indexed":false,"name":"totalVotes","type":"uint256"}],"name":"ProposalVoted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalExecuted","type":"event"},{"constant":true,"inputs":[],"name":"contributorsContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"contributorId","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"addProposal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"getProposal","outputs":[{"name":"id","type":"uint256"},{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"voterIds","type":"uint256[]"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_proposalIds","type":"uint256[]"}],"name":"batchVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]

1
lib/abis/Proposal.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"currentVersions","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"name":"versions","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"proxy","type":"address"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"},{"indexed":false,"name":"implementation","type":"address"}],"name":"VersionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"}],"name":"ProxyImplementationUpgraded","type":"event"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"implementation","type":"address"}],"name":"addVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"getVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getLatestVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getProxyFor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"upgradeToLatest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"createProxy","outputs":[{"name":"","type":"address"}],"payable":true,"stateMutability":"payable","type":"function"}]

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"}

View File

@@ -0,0 +1,3 @@
{
"4": "0x76e069b47b79442657eaf0555a32c6b16fa1b8b4"
}

View File

@@ -1 +0,0 @@
{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"}

View File

@@ -1 +0,0 @@
{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x7458dea485d9d8301e3ce43e8a1ec1456be5ba83"}

View File

@@ -1 +0,0 @@
{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"}

3
lib/addresses/dao.json Normal file
View File

@@ -0,0 +1,3 @@
{
"4": "0xc34edf7d11b7f8433d597f0bb0697acdff55ef14"
}

17
lib/contracts/acl.js Normal file
View File

@@ -0,0 +1,17 @@
const Base = require('./base');
const EthersUtils = require('ethers').utils;
class Acl extends Base {
hasPermission (fromAddress, contractAddress, roleID, params = null) {
let roleHash = EthersUtils.keccak256(EthersUtils.toUtf8Bytes(roleID));
return this.functions.hasPermission(
fromAddress,
contractAddress,
roleHash,
params
);
}
}
module.exports = Acl;

View File

@@ -1,27 +1,28 @@
class Base {
constructor(contract) {
constructor (contract) {
this.contract = contract;
}
get functions() {
get functions () {
return this.contract.functions;
}
get ipfs() {
get address () {
return this.contract.address;
}
get ipfs () {
if (!this._ipfsAPI) { throw new Error('IPFS API not configured; please set an ipfs instance'); }
return this._ipfsAPI;
}
set ipfs(ipfsAPI) {
set ipfs (ipfsAPI) {
this._ipfsAPI = ipfsAPI;
}
on(type, callback) {
let eventMethod = `on${type.toLowerCase()}`;
// Don't use this.contract.events here. Seems to be a bug in ethers.js
this.contract[eventMethod] = callback;
return this;
on (type, callback) {
return this.contract.on(type, callback);
}
}
module.exports = Base;

Some files were not shown because too many files have changed in this diff Show More