Compare commits
1 Commits
tests/cont
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
| 759436f870 |
@@ -1 +0,0 @@
|
||||
/scripts/
|
||||
33
.eslintrc.js
33
.eslintrc.js
@@ -1,33 +0,0 @@
|
||||
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
.github/release-drafter.yml
vendored
4
.github/release-drafter.yml
vendored
@@ -1,4 +0,0 @@
|
||||
template: |
|
||||
## Changes
|
||||
|
||||
$CHANGES
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,8 +1,3 @@
|
||||
build
|
||||
flattened_contracts
|
||||
node_modules
|
||||
**/node_modules
|
||||
.ganache-db
|
||||
.tm_properties
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
.ganache-db
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"solhint:default",
|
||||
"solhint:recommended"
|
||||
],
|
||||
"rules": {
|
||||
"indent": "2"
|
||||
}
|
||||
}
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,33 +0,0 @@
|
||||
---
|
||||
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
|
||||
234
README.md
234
README.md
@@ -1,234 +0,0 @@
|
||||
[](https://www.npmjs.com/package/kredits-contracts)
|
||||
|
||||
# Kredits Contracts
|
||||
|
||||
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 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
|
||||
|
||||
#### App dependencies
|
||||
|
||||
All requirements are defined in `package.json`.
|
||||
|
||||
$ npm install
|
||||
|
||||
Each of the aragon apps are separate packages:
|
||||
|
||||
$ cd apps/[app]
|
||||
$ npm install
|
||||
|
||||
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](http://truffleframework.com/ganache/) to run a local development
|
||||
chain. When using the ganache simulator, no full Ethereum node is required.
|
||||
|
||||
We use the default aragon-cli devchain command to configure and run a local
|
||||
development ganache.
|
||||
|
||||
$ npm run devchain (or aragon devchain --port 7545)
|
||||
|
||||
To clear/reset the chain use (e.g. if you run out of funds on your devchain)
|
||||
|
||||
$ npm run devchain -- --reset (or aragon devchain --port 7545 --reset)
|
||||
|
||||
We default to port 7545 for development to not get in conflict with the default
|
||||
Ethereum RPC port.
|
||||
|
||||
You can also set certain ganache options to configure the devchain, for example
|
||||
if you want to increase the block time to 10 seconds you can add
|
||||
`--block-time=10`.
|
||||
|
||||
### Bootstrap
|
||||
|
||||
1. Run an Ethereum node and ipfs
|
||||
|
||||
$ npm run devchain
|
||||
$ ipfs daemon
|
||||
|
||||
2. Deploy each app to the devchain
|
||||
|
||||
(make sure you've run `npm install` for every app - see installation)
|
||||
$ npm run deploy:apps
|
||||
|
||||
3. Deploy a new KreditsKit and create a new DAO with the latest app versions
|
||||
|
||||
$ npm run deploy:kit
|
||||
$ npm run deploy:dao
|
||||
|
||||
4. Execute seeds to create demo contributors, contributions, etc. (optional)
|
||||
|
||||
$ npm run seeds
|
||||
|
||||
**Step 2-4 is also summarized in `npm run bootstrap`**
|
||||
|
||||
If you want to reset your local setup:
|
||||
|
||||
$ 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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Helper scripts
|
||||
|
||||
`scripts/` contains some helper scripts to interact with the contracts from the
|
||||
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:
|
||||
|
||||
$ truffle exec scripts/cli.js
|
||||
|
||||
### repl.js
|
||||
|
||||
Similar to cli.js but only provides a REPL with an initialized `kredits`
|
||||
instance.
|
||||
|
||||
$ truffle exec scripts/repl.js
|
||||
|
||||
### add-{contributor, contribution, proposal}.js
|
||||
|
||||
Script to add a new entries to the contracts using the JS wrapper
|
||||
|
||||
$ truffle exec scripts/add-{contributor, contribution, proposal}.js
|
||||
|
||||
### list-{contributors, contributions, proposals}.js
|
||||
|
||||
List contract entries
|
||||
|
||||
$ truffle exec scripts/list-{contributors, contributions, proposals}.js
|
||||
|
||||
### send-funds.js
|
||||
|
||||
Sends funds to an address. Helpful in development mode to for example fund a
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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/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
|
||||
|
||||
When resetting ganache Metamask might have an invalid transaction nonce and
|
||||
transactions get rejected. Nonces in Ethereum must be incrementing and have no
|
||||
gap.
|
||||
|
||||
To solve this reset the metamask account (Account -> Settings -> Reset Account)
|
||||
153
README.mdown
Normal file
153
README.mdown
Normal file
@@ -0,0 +1,153 @@
|
||||
# Kredits
|
||||
|
||||
This repository contains all the contracts for Kredits as a [truffle framework](http://truffleframework.com/) project.
|
||||
|
||||
## Development
|
||||
|
||||
### Installation
|
||||
|
||||
$ npm install
|
||||
|
||||
### Requirements
|
||||
|
||||
All requirements are defined in `package.json`.
|
||||
|
||||
Those can be installed globally for convenience:
|
||||
* [truffle framework](http://truffleframework.com): `npm install -g truffle`
|
||||
* [ganache](http://truffleframework.com/ganache): `npm install -g ganache-cli`
|
||||
|
||||
We use following solidity contract libraries:
|
||||
* [Open Zeppelin](https://github.com/OpenZeppelin/zeppelin-solidity)
|
||||
|
||||
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.
|
||||
|
||||
We default to:
|
||||
|
||||
* 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
|
||||
|
||||
Have a look at `ganache-cli` for more configuration options.
|
||||
|
||||
Run your ganache simulator before using Kredits locally:
|
||||
|
||||
$ npm run ganache (which is: ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits)
|
||||
|
||||
### Truffle console
|
||||
|
||||
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)
|
||||
|
||||
NOTE: There are promisses, have a look at the examples:
|
||||
|
||||
```javascript
|
||||
Token.deployed().then(function(token) {
|
||||
token.totalSupply.call().then(function(value) {
|
||||
console.log(value.toString());
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
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/)
|
||||
|
||||
|
||||
## Contract Deployment
|
||||
|
||||
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`.
|
||||
|
||||
Run the truffle migration scripts:
|
||||
|
||||
$ truffle deploy
|
||||
$ truffle deploy --network=<network config from truffle.js>
|
||||
|
||||
Truffle keeps track of already executed migration scripts. To reset the migration use the `--reset` option
|
||||
|
||||
$ truffle migrate --reset
|
||||
|
||||
Migration scripts can also be run from within `truffle console` or `truffle develop`
|
||||
|
||||
To initially bootstrap a local development chain in ganache you can use the bootstrap script:
|
||||
|
||||
$ npm run bootstrap (= `truffle migrate --reset && truffle exec scripts/seeds.js && npm run build-json`)
|
||||
|
||||
|
||||
## Helper scripts
|
||||
|
||||
`scripts/` contains some helper scripts to interact with the contracts from the 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`
|
||||
|
||||
### cli.js
|
||||
|
||||
Call any function on any contract:
|
||||
|
||||
$ truffle exec scripts/cli.js <Contract Name> <Function> [<optional> <arguments>]
|
||||
|
||||
For example:
|
||||
$ truffle exec scripts/cli.js Operator proposalsCount
|
||||
|
||||
Please note that the contract name and the function are case sensitive.
|
||||
|
||||
### add-contributor.js
|
||||
Adds a new core contributor, creates a proposal for the new contributor and votes for that one.
|
||||
|
||||
$ truffle exec scripts/add-contributor.js <ethereum address> [<profile IPFS hash>]
|
||||
|
||||
### add-proposal.js
|
||||
Adds a new proposal for an existing contributor
|
||||
|
||||
$ truffle exec scripts/add-proposal.js <ethereum address> [<proposal IPFS hash>]
|
||||
|
||||
### send-funds.js
|
||||
Sends funds to an address. Helpful in development mode to for example fund a metamask account.
|
||||
|
||||
$ truffle exec scripts/send-funds.js <ethereum address>
|
||||
|
||||
### seeds.js
|
||||
Run seeds defined in `config/seeds.js`.
|
||||
|
||||
$ truffle exec scripts/seeds.js
|
||||
or
|
||||
$ npm run seeds
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
### 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)`
|
||||
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)`
|
||||
|
||||
|
||||
## Known Issues
|
||||
|
||||
When resetting ganache Metamask might have an invalid transaction nonce and transactions get rejected.
|
||||
Nonces in Ethereum must be incrementing and have no gap.
|
||||
|
||||
To solve this reset the metamask account (Account -> Settings -> Reset Account)
|
||||
@@ -1,12 +0,0 @@
|
||||
module.exports = {
|
||||
'globals': {
|
||||
contract: true,
|
||||
describe: true,
|
||||
it: true,
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', {
|
||||
'argsIgnorePattern': '^_',
|
||||
}],
|
||||
}
|
||||
}
|
||||
4
apps/contribution/.gitignore
vendored
4
apps/contribution/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
@@ -1,14 +0,0 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
@@ -1 +0,0 @@
|
||||
# Kredits Contribution
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
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 }
|
||||
bytes32[4] 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[4] _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;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Contribution",
|
||||
"description": "Kredits contribution app"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Contribution = artifacts.require('Contribution.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Contribution)
|
||||
}
|
||||
28331
apps/contribution/package-lock.json
generated
28331
apps/contribution/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// const Contribution = artifacts.require('Contribution.sol');
|
||||
|
||||
contract('Contribution', (_accounts) => {
|
||||
it('should be tested');
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require("../../truffle.js");
|
||||
4
apps/contributor/.gitignore
vendored
4
apps/contributor/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
@@ -1,14 +0,0 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
@@ -1 +0,0 @@
|
||||
# Kredits Contributor
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
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 }
|
||||
bytes32[4] public appIds;
|
||||
|
||||
event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged
|
||||
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
|
||||
event ContributorAdded(uint32 id, address account);
|
||||
|
||||
function initialize(address root,bytes32[4] _appIds) public onlyInit {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/acl/ACL.sol";
|
||||
import "@aragon/os/contracts/kernel/Kernel.sol";
|
||||
import "@aragon/os/contracts/factory/DAOFactory.sol";
|
||||
|
||||
// You might think this file is a bit odd, but let me explain.
|
||||
// We only use for now those imported contracts in our tests, which
|
||||
// means Truffle will not compile them for us, because they are from
|
||||
// an external dependency.
|
||||
|
||||
|
||||
// solium-disable-next-line no-empty-blocks
|
||||
contract Spoof {
|
||||
// ...
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Contributor",
|
||||
"description": "Kredits Contributor app"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Contributor = artifacts.require('Contributor.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Contributor)
|
||||
}
|
||||
28331
apps/contributor/package-lock.json
generated
28331
apps/contributor/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
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';
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require("../../truffle.js");
|
||||
@@ -1 +0,0 @@
|
||||
# Kredits Proposal
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
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 }
|
||||
bytes32[4] 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[4] _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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Proposal",
|
||||
"description": "Kredits Proposal app"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
28331
apps/proposal/package-lock.json
generated
28331
apps/proposal/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// const Proposal = artifacts.require('Proposal.sol');
|
||||
|
||||
contract('Proposal', (_accounts) => {
|
||||
it('should be tested');
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require("../../truffle.js");
|
||||
4
apps/token/.gitignore
vendored
4
apps/token/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
@@ -1,14 +0,0 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
@@ -1 +0,0 @@
|
||||
# Kredits Token
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
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 }
|
||||
bytes32[4] public appIds;
|
||||
|
||||
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
||||
|
||||
function initialize(bytes32[4] _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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/acl/ACL.sol";
|
||||
import "@aragon/os/contracts/kernel/Kernel.sol";
|
||||
import "@aragon/os/contracts/factory/DAOFactory.sol";
|
||||
|
||||
// You might think this file is a bit odd, but let me explain.
|
||||
// We only use for now those imported contracts in our tests, which
|
||||
// means Truffle will not compile them for us, because they are from
|
||||
// an external dependency.
|
||||
|
||||
|
||||
// solium-disable-next-line no-empty-blocks
|
||||
contract Spoof {
|
||||
// ...
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Token",
|
||||
"description": "Kredits Token app"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
var Token = artifacts.require('Token.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Token)
|
||||
}
|
||||
28331
apps/token/package-lock.json
generated
28331
apps/token/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
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 +0,0 @@
|
||||
module.exports = require("../../truffle.js");
|
||||
60
arapp.json
60
arapp.json
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,48 +1,9 @@
|
||||
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 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 funds = [
|
||||
'0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
||||
'0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827',
|
||||
];
|
||||
|
||||
module.exports = { contractCalls, funds };
|
||||
module.exports = { contractCalls };
|
||||
|
||||
128
contracts/Contributors.sol
Normal file
128
contracts/Contributors.sol
Normal file
@@ -0,0 +1,128 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
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 "../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 }
|
||||
bytes32[4] public appIds;
|
||||
|
||||
event DeployInstance(address dao);
|
||||
event InstalledApp(address dao, address appProxy, bytes32 appId);
|
||||
|
||||
constructor (DAOFactory _fac, ENS _ens, bytes32[4] _appIds) public KitBase(_fac, _ens) {
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma solidity ^0.4.17;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
@@ -8,7 +8,7 @@ contract Migrations {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
constructor() public {
|
||||
function Migrations() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
123
contracts/Operator.sol
Normal file
123
contracts/Operator.sol
Normal file
@@ -0,0 +1,123 @@
|
||||
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 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);
|
||||
}
|
||||
|
||||
}
|
||||
27
contracts/Token.sol
Normal file
27
contracts/Token.sol
Normal file
@@ -0,0 +1,27 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/acl/ACL.sol";
|
||||
import "@aragon/os/contracts/kernel/Kernel.sol";
|
||||
import "@aragon/os/contracts/factory/DAOFactory.sol";
|
||||
|
||||
// You might think this file is a bit odd, but let me explain.
|
||||
// We only use for now those imported contracts in our tests, which
|
||||
// means Truffle will not compile them for us, because they are from
|
||||
// an external dependency.
|
||||
|
||||
|
||||
// solium-disable-next-line no-empty-blocks
|
||||
contract Spoof {
|
||||
// ...
|
||||
}
|
||||
53
contracts/upgradeable/IRegistry.sol
Normal file
53
contracts/upgradeable/IRegistry.sol
Normal file
@@ -0,0 +1,53 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma solidity ^0.4.17;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
@@ -8,7 +8,7 @@ contract Migrations {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
constructor() public {
|
||||
function Migrations() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
36
contracts/upgradeable/Proxy.sol
Normal file
36
contracts/upgradeable/Proxy.sol
Normal file
@@ -0,0 +1,36 @@
|
||||
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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
86
contracts/upgradeable/Registry.sol
Normal file
86
contracts/upgradeable/Registry.sol
Normal file
@@ -0,0 +1,86 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
28
contracts/upgradeable/UpgradeabilityProxy.sol
Normal file
28
contracts/upgradeable/UpgradeabilityProxy.sol
Normal file
@@ -0,0 +1,28 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
37
contracts/upgradeable/UpgradeabilityStorage.sol
Normal file
37
contracts/upgradeable/UpgradeabilityStorage.sol
Normal file
@@ -0,0 +1,37 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
19
contracts/upgradeable/Upgradeable.sol
Normal file
19
contracts/upgradeable/Upgradeable.sol
Normal file
@@ -0,0 +1,19 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
# 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
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# 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
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# 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
|
||||
@@ -1,62 +0,0 @@
|
||||
# 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"
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# 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
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
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
1
lib/abis/Contributors.json
Normal file
1
lib/abis/Contributors.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"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"}]
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
[{"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"}]
|
||||
1
lib/abis/Operator.json
Normal file
1
lib/abis/Operator.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"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"}]
|
||||
File diff suppressed because one or more lines are too long
1
lib/abis/Registry.json
Normal file
1
lib/abis/Registry.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"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
1
lib/addresses/Contributors.json
Normal file
1
lib/addresses/Contributors.json
Normal file
@@ -0,0 +1 @@
|
||||
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"4": "0x76e069b47b79442657eaf0555a32c6b16fa1b8b4"
|
||||
}
|
||||
1
lib/addresses/Operator.json
Normal file
1
lib/addresses/Operator.json
Normal file
@@ -0,0 +1 @@
|
||||
{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"}
|
||||
1
lib/addresses/Registry.json
Normal file
1
lib/addresses/Registry.json
Normal file
@@ -0,0 +1 @@
|
||||
{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x7458dea485d9d8301e3ce43e8a1ec1456be5ba83"}
|
||||
1
lib/addresses/Token.json
Normal file
1
lib/addresses/Token.json
Normal file
@@ -0,0 +1 @@
|
||||
{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"4": "0xc34edf7d11b7f8433d597f0bb0697acdff55ef14"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user