Build on aragonOS #62
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
build
|
build
|
||||||
|
flattened_contracts
|
||||||
node_modules
|
node_modules
|
||||||
|
**/node_modules
|
||||||
.ganache-db
|
.ganache-db
|
||||||
.tm_properties
|
.tm_properties
|
||||||
|
193
README.md
@ -2,92 +2,82 @@
|
|||||||
|
|
||||||
# Kredits Contracts
|
# Kredits Contracts
|
||||||
|
|
||||||
This repository contains the Solidity smart contracts and JavaScript API
|
This repository contains the Solidity smart contracts organized as [Aragon](https://hack.aragon.org/)
|
||||||
wrapper for [Kosmos Kredits](https://wiki.kosmos.org/Kredits).
|
apps and JavaScript API wrapper for [Kosmos Kredits](https://wiki.kosmos.org/Kredits).
|
||||||
|
|
||||||
It uses the [Truffle framework](http://truffleframework.com/) for some things.
|
It is based on [aragonOS](https://hack.aragon.org/docs/aragonos-intro.html) and
|
||||||
|
follows the aragonOS conventions.
|
||||||
|
Aragon itself uses the [Truffle framework](http://truffleframework.com/) for some things.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
$ npm install
|
|
||||||
|
|
||||||
### Requirements
|
|
||||||
|
|
||||||
All requirements are defined in `package.json`.
|
All requirements are defined in `package.json`.
|
||||||
|
|
||||||
Those can be installed globally for convenience:
|
$ npm install
|
||||||
|
|
||||||
* [truffle framework](http://truffleframework.com): `npm install -g truffle`
|
Each of the aragon apps are separate packages:
|
||||||
* [ganache](http://truffleframework.com/ganache): `npm install -g ganache-cli`
|
|
||||||
|
|
||||||
We use following solidity contract libraries:
|
$ cd apps/[app]
|
||||||
|
$ npm install
|
||||||
|
|
||||||
* [Open Zeppelin](https://github.com/OpenZeppelin/zeppelin-solidity)
|
or use the bootstrap command (see below)
|
||||||
|
|
||||||
|
### Local development chain
|
||||||
|
|
||||||
For local development it is recommended to use
|
For local development it is recommended to use
|
||||||
[ganache-cli](https://github.com/trufflesuite/ganache-cli) (or the [ganache
|
[ganache](http://truffleframework.com/ganache/) to run a local development
|
||||||
GUI](http://truffleframework.com/ganache/) to run a local development chain.
|
chain. Using the ganache simulator no full Ethereum node is required.
|
||||||
Using the ganache simulator no full Ethereum node is required.
|
|
||||||
|
|
||||||
We default to:
|
We use the default aragon-cli devchain command to confgure and run a local
|
||||||
|
development ganache.
|
||||||
|
|
||||||
* port 7545 for development to not get in conflict with the default Ethereum
|
$ npm run devchain (or aragon devchain --port 7545)
|
||||||
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.
|
To clear/reset the chain use:
|
||||||
|
|
||||||
Run your ganache simulator before using Kredits locally:
|
$ npm run devchain -- --reset (or aragon devchain --port 7545 --reset)
|
||||||
|
|
||||||
$ npm run ganache (which is: ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits)
|
We default to port 7545 for development to not get in conflict with the default
|
||||||
|
Ethereum RPC port.
|
||||||
|
|
||||||
### Truffle console
|
### Bootstrap
|
||||||
|
|
||||||
Truffle comes with a simple REPL to interact with the Smart Contracts. Have a
|
1. Run an Ethereum node and ipfs
|
||||||
look at the [documentation
|
|
||||||
here](http://truffleframework.com/docs/getting_started/console)
|
|
||||||
|
|
||||||
NOTE: There are promisses, have a look at the examples:
|
$ npm run devchain
|
||||||
|
$ ipfs daemon
|
||||||
|
|
||||||
```javascript
|
2. Deploy each app to the devchain
|
||||||
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
|
$ npm run deploy:apps
|
||||||
[1.x.x](https://web3js.readthedocs.io/en/1.0/) - [web3
|
|
||||||
repo](https://github.com/ethereum/web3.js/)
|
|
||||||
|
|
||||||
## Contract Deployment
|
3. Deploy a new KreditsKit and create a new DAO with the latest app versions
|
||||||
|
|
||||||
Truffle uses migration scripts to deploy contract to various networks. Have a
|
$ npm run deploy:kit
|
||||||
look at the `migrations` folder for those. The Ethereum nodes for the
|
$ npm run deploy:dao
|
||||||
different networks need to be configured in `truffle.js`.
|
|
||||||
|
|
||||||
Run the truffle migration scripts:
|
4. Execute seeds to create demo contributors, contributons, etc. (optional)
|
||||||
|
|
||||||
$ truffle deploy
|
$ npm run seeds
|
||||||
$ truffle deploy --network=<network config from truffle.js>
|
|
||||||
|
|
||||||
Truffle keeps track of already executed migration scripts. To reset the
|
**Step 2-4 is also summarized in `npm run bootstrap`**
|
||||||
migration use the `--reset` option
|
|
||||||
|
|
||||||
$ truffle migrate --reset
|
## Contract architecture
|
||||||
|
|
||||||
Migration scripts can also be run from within `truffle console` or `truffle
|
Contracts are organized in independent apps (see `/apps`) and are developed
|
||||||
develop`
|
and deployed independently. Each app has a version and can be "installed"
|
||||||
|
on the Kredits DAO independently.
|
||||||
|
|
||||||
To initially bootstrap a local development chain in ganache you can use the
|

|
||||||
bootstrap script:
|
|
||||||
|
A DAO can be deployed using the `scripts/deploy-kit.js` script or with the
|
||||||
|
`npm run deploy:dao` command. This deploys a new Kredits DAO, installs
|
||||||
|
the latest app versions and sets the required permissions.
|
||||||
|
|
||||||
|
See each app in `/apps/*` for details.
|
||||||
|
|
||||||
$ npm run bootstrap
|
|
||||||
|
|
||||||
## Helper scripts
|
## Helper scripts
|
||||||
|
|
||||||
@ -110,18 +100,17 @@ instance.
|
|||||||
|
|
||||||
$ truffle exec scripts/repl.js
|
$ truffle exec scripts/repl.js
|
||||||
|
|
||||||
### add-contributor.js
|
### add-{contributor, contribution, proposal}.js
|
||||||
|
|
||||||
Adds a new core contributor, creates a proposal for the new contributor and
|
Script to add a new entries to the contracts using the JS wrapper
|
||||||
votes for that one.
|
|
||||||
|
|
||||||
$ truffle exec scripts/add-contributor.js
|
$ truffle exec scripts/add-{contributor, contribution, proposal}.js
|
||||||
|
|
||||||
### add-proposal.js
|
### list-{contributor, contribution, proposal}.js
|
||||||
|
|
||||||
Adds a new proposal for an existing contributor
|
List contract entries
|
||||||
|
|
||||||
$ truffle exec scripts/add-proposal.js
|
$ truffle exec scripts/list-{contributor, contribution, proposal}.js
|
||||||
|
|
||||||
### send-funds.js
|
### send-funds.js
|
||||||
|
|
||||||
@ -131,48 +120,70 @@ metamask account.
|
|||||||
$ truffle exec scripts/send-funds.js
|
$ truffle exec scripts/send-funds.js
|
||||||
|
|
||||||
### seeds.js
|
### seeds.js
|
||||||
|
|
||||||
Run seeds defined in `config/seeds.js`.
|
Run seeds defined in `config/seeds.js`.
|
||||||
|
|
||||||
$ truffle exec scripts/seeds.js
|
$ truffle exec scripts/seeds.js
|
||||||
or
|
or
|
||||||
$ npm run seeds
|
$ 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 load 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
|
||||||
|
|
||||||
|
|
||||||
|
## ACL / Permissions
|
||||||
|
|
||||||
|
|
||||||
## Upgradeable contracts
|
## Upgradeable contracts
|
||||||
|
|
||||||
Some of the contracts use upgradability ideas from
|
We use aragonOS for upgradeablity of the different contracts.
|
||||||
[zeppelinos](https://github.com/zeppelinos/labs) (see `contracts/upgradable`).
|
Refer to the [aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro)
|
||||||
|
for more details.
|
||||||
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
|
### Example
|
||||||
|
|
||||||
Deployment is best done using the truffle deployer.
|
1. Setup (see #Bootstrap)
|
||||||
|
1. Deploy each contract/apps (see `/apps/*`)
|
||||||
1. Setup
|
2. Create a new DAO (see scripts/deploy-kit.js)
|
||||||
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
|
2. Update
|
||||||
1. Deploy a new Version of the contract
|
1. Deploy a new Version of the contract/app (see `/apps/*`)
|
||||||
2. Register the new version at the Registry:
|
2. Use the `aragon dao upgrade` command to "install" the new version for the DAO
|
||||||
`registry.addVersion('Token', NewToken.address)`
|
(`aragon dao upgrade <DAO address> <app name>`)
|
||||||
3. Set the new implementation address on the Proxy contract:
|
|
||||||
`registry.upgrade('Token', 2)`
|
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
|
4
apps/contribution/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
.cache
|
||||||
|
dist
|
14
apps/contribution/.ipfsignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Git files
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Build files
|
||||||
|
.cache
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
|
||||||
|
# Lock files
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# Others
|
||||||
|
test
|
1
apps/contribution/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Kredits Contribution
|
38
apps/contribution/arapp.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "Add contributions",
|
||||||
|
"id": "ADD_CONTRIBUTION_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Manage token contract",
|
||||||
|
"id": "MANAGE_TOKEN_CONTRACT_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Veto contributions",
|
||||||
|
"id": "VETO_CONTRIBUTION_ROLE",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environments": {
|
||||||
|
"default": {
|
||||||
|
"network": "development",
|
||||||
|
"appName": "kredits-contribution.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"
|
||||||
|
}
|
146
apps/contribution/contracts/Contribution.sol
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
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, uint256 contributionId) public;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
address contributor;
|
||||||
|
uint256 amount;
|
||||||
|
bool claimed;
|
||||||
|
bytes32 hashDigest;
|
||||||
|
uint8 hashFunction;
|
||||||
|
uint8 hashSize;
|
||||||
|
string tokenMetadataURL;
|
||||||
|
uint claimAfterBlock;
|
||||||
|
bool vetoed;
|
||||||
|
bool exists;
|
||||||
|
}
|
||||||
|
string internal name_;
|
||||||
|
string internal symbol_;
|
||||||
|
|
||||||
|
mapping(uint256 => address) contributionOwner;
|
||||||
|
mapping(address => uint256[]) ownedContributions;
|
||||||
|
|
||||||
|
mapping(uint256 => ContributionData) public contributions;
|
||||||
|
uint256 public contributionsCount;
|
||||||
|
|
||||||
|
uint256 public blocksToWait = 0;
|
||||||
|
|
||||||
|
event ContributionAdded(uint256 id, address indexed contributor, uint256 amount);
|
||||||
|
event ContributionClaimed(uint256 id, address indexed contributor, uint256 amount);
|
||||||
|
event ContributionVetoed(uint256 id, address vetoedByAccount);
|
||||||
|
|
||||||
|
function initialize(bytes32[4] _appIds) public onlyInit {
|
||||||
|
appIds = _appIds;
|
||||||
|
initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTokenContract() public view returns (address) {
|
||||||
|
IKernel k = IKernel(kernel());
|
||||||
|
|
||||||
|
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function name() external view returns (string) {
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function symbol() external view returns (string) {
|
||||||
|
return symbol_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function balanceOf(address owner) public view returns (uint256) {
|
||||||
|
require(owner != address(0));
|
||||||
|
return ownedContributions[owner].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ownerOf(uint256 contributionId) public view returns (address) {
|
||||||
|
require(exists(contributionId));
|
||||||
|
return contributions[contributionId].contributor;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenOfOwnerByIndex(address contributor, uint256 index) public view returns (uint256) {
|
||||||
|
return ownedContributions[contributor][index];
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenMetadata(uint256 contributionId) public view returns (string) {
|
||||||
|
return contributions[contributionId].tokenMetadataURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContribution(uint256 contributionId) public view returns (uint256 id, address contributor, uint256 amount, bool claimed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint claimAfterBlock, bool exists, bool vetoed) {
|
||||||
|
id = contributionId;
|
||||||
|
ContributionData storage c = contributions[id];
|
||||||
|
return (
|
||||||
|
id,
|
||||||
|
c.contributor,
|
||||||
|
c.amount,
|
||||||
|
c.claimed,
|
||||||
|
c.hashDigest,
|
||||||
|
c.hashFunction,
|
||||||
|
c.hashSize,
|
||||||
|
c.claimAfterBlock,
|
||||||
|
c.exists,
|
||||||
|
c.vetoed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(uint256 amount, address contributorAccount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_CONTRIBUTION_ROLE) {
|
||||||
|
//require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint256[](0)), 'nope');
|
||||||
|
uint256 contributionId = contributionsCount + 1;
|
||||||
|
ContributionData storage c = contributions[contributionId];
|
||||||
|
c.exists = true;
|
||||||
|
c.amount = amount;
|
||||||
|
c.claimed = false;
|
||||||
|
c.contributor = contributorAccount;
|
||||||
|
c.hashDigest = hashDigest;
|
||||||
|
c.hashFunction = hashFunction;
|
||||||
|
c.hashSize = hashSize;
|
||||||
|
c.claimAfterBlock = block.number; // + blocksToWait;
|
||||||
|
|
||||||
|
contributionsCount++;
|
||||||
|
|
||||||
|
contributionOwner[contributionId] = contributorAccount;
|
||||||
|
ownedContributions[contributorAccount].push(contributionId);
|
||||||
|
|
||||||
|
emit ContributionAdded(contributionId, contributorAccount, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function veto(uint256 contributionId) public isInitialized auth(VETO_CONTRIBUTION_ROLE) {
|
||||||
|
ContributionData storage c = contributions[contributionId];
|
||||||
|
require(c.exists, 'NOT_FOUND');
|
||||||
|
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||||
|
c.vetoed = true;
|
||||||
|
|
||||||
|
emit ContributionVetoed(contributionId, msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
function claim(uint256 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.claimAfterBlock, 'NOT_CLAIMABLE');
|
||||||
|
|
||||||
|
c.claimed = true;
|
||||||
|
address token = getTokenContract();
|
||||||
|
IToken(token).mintFor(c.contributor, c.amount, contributionId);
|
||||||
|
emit ContributionClaimed(contributionId, c.contributor, c.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(uint256 contributionId) view public returns (bool) {
|
||||||
|
return contributions[contributionId].exists;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
pragma solidity ^0.4.17;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
contract Migrations {
|
contract Migrations {
|
||||||
address public owner;
|
address public owner;
|
||||||
@ -8,7 +8,7 @@ contract Migrations {
|
|||||||
if (msg.sender == owner) _;
|
if (msg.sender == owner) _;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Migrations() public {
|
constructor() public {
|
||||||
owner = msg.sender;
|
owner = msg.sender;
|
||||||
}
|
}
|
||||||
|
|
4
apps/contribution/manifest.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "Contribution",
|
||||||
|
"description": "Kredits contribution app"
|
||||||
|
}
|
5
apps/contribution/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Migrations = artifacts.require('./Migrations.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Migrations)
|
||||||
|
}
|
5
apps/contribution/migrations/2_deploy_contracts.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Contribution = artifacts.require('Contribution.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Contribution)
|
||||||
|
}
|
13977
apps/contribution/package-lock.json
generated
Normal file
27
apps/contribution/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "kredits-contribution",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@aragon/os": "^4.1.0",
|
||||||
|
"@aragon/cli": "^5.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"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": "npm run sync-assets && npm run build:script -- --no-minify && parcel serve app/index.html -p 8001 --out-dir dist/ --no-cache",
|
||||||
|
"test": "aragon contracts test",
|
||||||
|
"compile": "aragon contracts compile",
|
||||||
|
"sync-assets": "copy-aragon-ui-assets -n aragon-ui ./dist",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"keywords": []
|
||||||
|
}
|
5
apps/contribution/test/app.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const CounterApp = artifacts.require('Contribution.sol')
|
||||||
|
|
||||||
|
contract('Contribution', (accounts) => {
|
||||||
|
it('should be tested')
|
||||||
|
})
|
1
apps/contribution/truffle.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("../../truffle.js");
|
4
apps/contributor/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
.cache
|
||||||
|
dist
|
14
apps/contributor/.ipfsignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Git files
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Build files
|
||||||
|
.cache
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
|
||||||
|
# Lock files
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# Others
|
||||||
|
test
|
1
apps/contributor/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Kredits Contributor
|
28
apps/contributor/arapp.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "Manage contributors",
|
||||||
|
"id": "MANAGE_CONTRIBUTORS_ROLE",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environments": {
|
||||||
|
"default": {
|
||||||
|
"network": "development",
|
||||||
|
"appName": "kredits-contributor.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,10 +1,9 @@
|
|||||||
pragma solidity ^0.4.18;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
// import basic ERC20 details to be able to call balanceOf
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
import 'zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol';
|
|
||||||
import './upgradeable/Upgradeable.sol';
|
|
||||||
|
|
||||||
contract Contributors is Upgradeable {
|
contract Contributor is AragonApp {
|
||||||
|
bytes32 public constant MANAGE_CONTRIBUTORS_ROLE = keccak256("MANAGE_CONTRIBUTORS_ROLE");
|
||||||
|
|
||||||
struct Contributor {
|
struct Contributor {
|
||||||
address account;
|
address account;
|
||||||
@ -19,24 +18,26 @@ contract Contributors is Upgradeable {
|
|||||||
mapping (uint => Contributor) public contributors;
|
mapping (uint => Contributor) public contributors;
|
||||||
uint256 public contributorsCount;
|
uint256 public contributorsCount;
|
||||||
|
|
||||||
|
// ensure alphabetic order
|
||||||
|
enum Apps { Contribution, Contributor, Proposal, Token }
|
||||||
|
bytes32[4] public appIds;
|
||||||
|
|
||||||
event ContributorProfileUpdated(uint id, bytes32 oldIpfsHash, bytes32 newIpfsHash);
|
event ContributorProfileUpdated(uint id, bytes32 oldIpfsHash, bytes32 newIpfsHash);
|
||||||
event ContributorAccountUpdated(uint id, address oldAccount, address newAccount);
|
event ContributorAccountUpdated(uint id, address oldAccount, address newAccount);
|
||||||
event ContributorAdded(uint id, address account);
|
event ContributorAdded(uint id, address account);
|
||||||
|
|
||||||
modifier onlyCoreOrOperator() {
|
function initialize(address root,bytes32[4] _appIds) public onlyInit {
|
||||||
require(msg.sender == registry.getProxyFor('Operator') || addressIsCore(msg.sender));
|
uint _id = contributorsCount + 1;
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initialize(address sender) public payable {
|
|
||||||
require(msg.sender == address(registry));
|
|
||||||
uint _id = 1;
|
|
||||||
Contributor storage c = contributors[_id];
|
Contributor storage c = contributors[_id];
|
||||||
c.exists = true;
|
c.exists = true;
|
||||||
c.isCore = true;
|
c.isCore = true;
|
||||||
c.account = sender;
|
c.account = root;
|
||||||
contributorIds[sender] = _id;
|
contributorIds[root] = _id;
|
||||||
contributorsCount += 1;
|
contributorsCount += 1;
|
||||||
|
|
||||||
|
appIds = _appIds;
|
||||||
|
|
||||||
|
initialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function coreContributorsCount() view public returns (uint) {
|
function coreContributorsCount() view public returns (uint) {
|
||||||
@ -49,14 +50,14 @@ contract Contributors is Upgradeable {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContributorAccount(uint id, address oldAccount, address newAccount) public onlyCoreOrOperator {
|
function updateContributorAccount(uint id, address oldAccount, address newAccount) public auth(MANAGE_CONTRIBUTORS_ROLE) {
|
||||||
contributorIds[oldAccount] = 0;
|
contributorIds[oldAccount] = 0;
|
||||||
contributorIds[newAccount] = id;
|
contributorIds[newAccount] = id;
|
||||||
contributors[id].account = newAccount;
|
contributors[id].account = newAccount;
|
||||||
ContributorAccountUpdated(id, oldAccount, newAccount);
|
ContributorAccountUpdated(id, oldAccount, newAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContributorIpfsHash(uint id, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public onlyCoreOrOperator {
|
function updateContributorIpfsHash(uint id, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
|
||||||
Contributor storage c = contributors[id];
|
Contributor storage c = contributors[id];
|
||||||
bytes32 oldIpfsHash = c.ipfsHash;
|
bytes32 oldIpfsHash = c.ipfsHash;
|
||||||
c.ipfsHash = ipfsHash;
|
c.ipfsHash = ipfsHash;
|
||||||
@ -66,7 +67,7 @@ contract Contributors is Upgradeable {
|
|||||||
ContributorProfileUpdated(id, oldIpfsHash, c.ipfsHash);
|
ContributorProfileUpdated(id, oldIpfsHash, c.ipfsHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addContributor(address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore) public onlyCoreOrOperator {
|
function addContributor(address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
|
||||||
require(!addressExists(account));
|
require(!addressExists(account));
|
||||||
uint _id = contributorsCount + 1;
|
uint _id = contributorsCount + 1;
|
||||||
assert(!contributors[_id].exists); // this can not be acually
|
assert(!contributors[_id].exists); // this can not be acually
|
||||||
@ -80,7 +81,7 @@ contract Contributors is Upgradeable {
|
|||||||
contributorIds[account] = _id;
|
contributorIds[account] = _id;
|
||||||
|
|
||||||
contributorsCount += 1;
|
contributorsCount += 1;
|
||||||
ContributorAdded(_id, account);
|
emit ContributorAdded(_id, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCore(uint id) view public returns (bool) {
|
function isCore(uint id) view public returns (bool) {
|
||||||
@ -112,7 +113,7 @@ contract Contributors is Upgradeable {
|
|||||||
return contributors[id];
|
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 ) {
|
function getContributorById(uint _id) public view returns (uint id, address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore, bool exists ) {
|
||||||
id = _id;
|
id = _id;
|
||||||
Contributor storage c = contributors[_id];
|
Contributor storage c = contributors[_id];
|
||||||
account = c.account;
|
account = c.account;
|
||||||
@ -121,8 +122,9 @@ contract Contributors is Upgradeable {
|
|||||||
hashSize = c.hashSize;
|
hashSize = c.hashSize;
|
||||||
isCore = c.isCore;
|
isCore = c.isCore;
|
||||||
exists = c.exists;
|
exists = c.exists;
|
||||||
|
}
|
||||||
|
|
||||||
ERC20Basic token = ERC20Basic(registry.getProxyFor('Token'));
|
function canPerform(address _who, address _where, bytes32 _what, uint256[] _how) public view returns (bool) {
|
||||||
balance = token.balanceOf(account);
|
return addressExists(_who);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
pragma solidity ^0.4.17;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
contract Migrations {
|
contract Migrations {
|
||||||
address public owner;
|
address public owner;
|
||||||
@ -8,7 +8,7 @@ contract Migrations {
|
|||||||
if (msg.sender == owner) _;
|
if (msg.sender == owner) _;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Migrations() public {
|
constructor() public {
|
||||||
owner = msg.sender;
|
owner = msg.sender;
|
||||||
}
|
}
|
||||||
|
|
4
apps/contributor/manifest.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "Contributor",
|
||||||
|
"description": "Kredits Contributor app"
|
||||||
|
}
|
5
apps/contributor/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Migrations = artifacts.require('./Migrations.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Migrations)
|
||||||
|
}
|
5
apps/contributor/migrations/2_deploy_contracts.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Contributor = artifacts.require('Contributor.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Contributor)
|
||||||
|
}
|
13977
apps/contributor/package-lock.json
generated
Normal file
27
apps/contributor/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "kredits-contributor",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@aragon/os": "^4.1.0",
|
||||||
|
"@aragon/cli": "^5.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"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": "",
|
||||||
|
"test": "aragon contracts test",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"keywords": []
|
||||||
|
}
|
5
apps/contributor/test/app.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const CounterApp = artifacts.require('CounterApp.sol')
|
||||||
|
|
||||||
|
contract('CounterApp', (accounts) => {
|
||||||
|
it('should be tested')
|
||||||
|
})
|
1
apps/contributor/truffle.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("../../truffle.js");
|
1
apps/proposal/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Kredits Proposal
|
33
apps/proposal/arapp.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "Add proposal",
|
||||||
|
"id": "ADD_PROPOSAL_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vote proposals",
|
||||||
|
"id": "VOTE_PROPOSAL_ROLE",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environments": {
|
||||||
|
"default": {
|
||||||
|
"network": "development",
|
||||||
|
"appName": "kredits-proposal.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"
|
||||||
|
}
|
134
apps/proposal/contracts/Proposal.sol
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
|
import "@aragon/os/contracts/kernel/IKernel.sol";
|
||||||
|
|
||||||
|
interface IContributor {
|
||||||
|
function getContributorAddressById(uint256 contributorId) public view returns (address);
|
||||||
|
function getContributorIdByAddress(address contributorAccount) public view returns (uint256);
|
||||||
|
function exists(uint256 contributorId) public view returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IContribution {
|
||||||
|
function add(uint256 amount, address contributor, 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;
|
||||||
|
uint contributorId;
|
||||||
|
uint votesCount;
|
||||||
|
uint votesNeeded;
|
||||||
|
uint256 amount;
|
||||||
|
bool executed;
|
||||||
|
bytes32 hashDigest;
|
||||||
|
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);
|
||||||
|
|
||||||
|
function initialize(bytes32[4] _appIds) public onlyInit {
|
||||||
|
appIds = _appIds;
|
||||||
|
initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorContract() public view returns (address) {
|
||||||
|
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contributor)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributionContract() public view returns (address) {
|
||||||
|
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contribution)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addProposal(uint contributorId, uint256 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_PROPOSAL_ROLE) {
|
||||||
|
require(IContributor(getContributorContract()).exists(contributorId), 'CONTRIBUTOR_NOT_FOUND');
|
||||||
|
|
||||||
|
uint256 proposalId = proposalsCount + 1;
|
||||||
|
uint256 _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(uint proposalId) public view returns (uint256 id, address creatorAccount, uint256 contributorId, uint256 votesCount, uint256 votesNeeded, uint256 amount, bool executed, bytes32 hashDigest, 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.hashDigest,
|
||||||
|
p.hashFunction,
|
||||||
|
p.hashSize,
|
||||||
|
p.voterIds,
|
||||||
|
p.exists
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function vote(uint256 proposalId) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
|
||||||
|
Proposal storage p = proposals[proposalId];
|
||||||
|
require(!p.executed, 'ALREADY_EXECUTED');
|
||||||
|
uint256 voterId = IContributor(getContributorContract()).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(uint256[] _proposalIds) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
|
||||||
|
for (uint256 i = 0; i < _proposalIds.length; i++) {
|
||||||
|
vote(_proposalIds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeProposal(uint proposalId) private {
|
||||||
|
Proposal storage p = proposals[proposalId];
|
||||||
|
require(!p.executed, 'ALREADY_EXECUTED');
|
||||||
|
require(p.votesCount >= p.votesNeeded, 'MISSING_VOTES');
|
||||||
|
|
||||||
|
p.executed = true;
|
||||||
|
address contributorAccount = IContributor(getContributorContract()).getContributorAddressById(p.contributorId);
|
||||||
|
IContribution(getContributionContract()).add(p.amount, contributorAccount, p.hashDigest, p.hashFunction, p.hashSize);
|
||||||
|
emit ProposalExecuted(proposalId, p.contributorId, p.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
apps/proposal/contracts/misc/Migrations.sol
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
contract Migrations {
|
||||||
|
address public owner;
|
||||||
|
uint public last_completed_migration;
|
||||||
|
|
||||||
|
modifier restricted() {
|
||||||
|
if (msg.sender == owner) _;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() public {
|
||||||
|
owner = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCompleted(uint completed) public restricted {
|
||||||
|
last_completed_migration = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade(address new_address) public restricted {
|
||||||
|
Migrations upgraded = Migrations(new_address);
|
||||||
|
upgraded.setCompleted(last_completed_migration);
|
||||||
|
}
|
||||||
|
}
|
4
apps/proposal/manifest.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "Proposal",
|
||||||
|
"description": "Kredits proposal app"
|
||||||
|
}
|
5
apps/proposal/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Migrations = artifacts.require('./Migrations.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Migrations)
|
||||||
|
}
|
13977
apps/proposal/package-lock.json
generated
Normal file
27
apps/proposal/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "kredits-proposal",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@aragon/os": "^4.1.0",
|
||||||
|
"@aragon/cli": "^5.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"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": "",
|
||||||
|
"test": "aragon contracts test",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"keywords": []
|
||||||
|
}
|
1
apps/proposal/truffle.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("../../truffle.js");
|
4
apps/token/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
.cache
|
||||||
|
dist
|
14
apps/token/.ipfsignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Git files
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Build files
|
||||||
|
.cache
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
|
||||||
|
# Lock files
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# Others
|
||||||
|
test
|
1
apps/token/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Kredits Token
|
28
apps/token/arapp.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "Mint token",
|
||||||
|
"id": "MINT_TOKEN_ROLE",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environments": {
|
||||||
|
"default": {
|
||||||
|
"network": "development",
|
||||||
|
"appName": "kredits-token.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"
|
||||||
|
}
|
173
apps/token/contracts/ERC20Token.sol
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/lib/math/SafeMath.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* beause ERC20.sol conflicts with the aragon ERC20.sol this is copied and modified from:
|
||||||
|
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20.sol
|
||||||
|
* @title Standard ERC20 token
|
||||||
|
*
|
||||||
|
* @dev Implementation of the basic standard token.
|
||||||
|
* https://eips.ethereum.org/EIPS/eip-20
|
||||||
|
* Originally based on code by FirstBlood:
|
||||||
|
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
|
||||||
|
*
|
||||||
|
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
|
||||||
|
* all accounts just by listening to said events. Note that this isn't required by the specification, and other
|
||||||
|
* compliant implementations may not do it.
|
||||||
|
*/
|
||||||
|
contract ERC20Token {
|
||||||
|
using SafeMath for uint256;
|
||||||
|
|
||||||
|
mapping (address => uint256) public _balances;
|
||||||
|
|
||||||
|
mapping (address => mapping (address => uint256)) private _allowed;
|
||||||
|
|
||||||
|
uint256 public _totalSupply;
|
||||||
|
|
||||||
|
string public name;
|
||||||
|
string public symbol;
|
||||||
|
uint8 public decimals;
|
||||||
|
|
||||||
|
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||||
|
|
||||||
|
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Total number of tokens in existence
|
||||||
|
*/
|
||||||
|
function totalSupply() public view returns (uint256) {
|
||||||
|
return _totalSupply;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Gets the balance of the specified address.
|
||||||
|
* @param owner The address to query the balance of.
|
||||||
|
* @return A uint256 representing the amount owned by the passed address.
|
||||||
|
*/
|
||||||
|
function balanceOf(address owner) public view returns (uint256) {
|
||||||
|
return _balances[owner];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Function to check the amount of tokens that an owner allowed to a spender.
|
||||||
|
* @param owner address The address which owns the funds.
|
||||||
|
* @param spender address The address which will spend the funds.
|
||||||
|
* @return A uint256 specifying the amount of tokens still available for the spender.
|
||||||
|
*/
|
||||||
|
function allowance(address owner, address spender) public view returns (uint256) {
|
||||||
|
return _allowed[owner][spender];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfer token to a specified address
|
||||||
|
* @param to The address to transfer to.
|
||||||
|
* @param value The amount to be transferred.
|
||||||
|
*/
|
||||||
|
function transfer(address to, uint256 value) public returns (bool) {
|
||||||
|
_transfer(msg.sender, to, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
|
||||||
|
* Beware that changing an allowance with this method brings the risk that someone may use both the old
|
||||||
|
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
|
||||||
|
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
|
||||||
|
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
||||||
|
* @param spender The address which will spend the funds.
|
||||||
|
* @param value The amount of tokens to be spent.
|
||||||
|
*/
|
||||||
|
function approve(address spender, uint256 value) public returns (bool) {
|
||||||
|
_approve(msg.sender, spender, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfer tokens from one address to another.
|
||||||
|
* Note that while this function emits an Approval event, this is not required as per the specification,
|
||||||
|
* and other compliant implementations may not emit the event.
|
||||||
|
* @param from address The address which you want to send tokens from
|
||||||
|
* @param to address The address which you want to transfer to
|
||||||
|
* @param value uint256 the amount of tokens to be transferred
|
||||||
|
*/
|
||||||
|
function transferFrom(address from, address to, uint256 value) public returns (bool) {
|
||||||
|
_transfer(from, to, value);
|
||||||
|
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Increase the amount of tokens that an owner allowed to a spender.
|
||||||
|
* approve should be called when _allowed[msg.sender][spender] == 0. To increment
|
||||||
|
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||||
|
* the first transaction is mined)
|
||||||
|
* From MonolithDAO Token.sol
|
||||||
|
* Emits an Approval event.
|
||||||
|
* @param spender The address which will spend the funds.
|
||||||
|
* @param addedValue The amount of tokens to increase the allowance by.
|
||||||
|
*/
|
||||||
|
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
|
||||||
|
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Decrease the amount of tokens that an owner allowed to a spender.
|
||||||
|
* approve should be called when _allowed[msg.sender][spender] == 0. To decrement
|
||||||
|
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||||
|
* the first transaction is mined)
|
||||||
|
* From MonolithDAO Token.sol
|
||||||
|
* Emits an Approval event.
|
||||||
|
* @param spender The address which will spend the funds.
|
||||||
|
* @param subtractedValue The amount of tokens to decrease the allowance by.
|
||||||
|
*/
|
||||||
|
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
|
||||||
|
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfer token for a specified addresses
|
||||||
|
* @param from The address to transfer from.
|
||||||
|
* @param to The address to transfer to.
|
||||||
|
* @param value The amount to be transferred.
|
||||||
|
*/
|
||||||
|
function _transfer(address from, address to, uint256 value) internal {
|
||||||
|
require(to != address(0));
|
||||||
|
|
||||||
|
_balances[from] = _balances[from].sub(value);
|
||||||
|
_balances[to] = _balances[to].add(value);
|
||||||
|
emit Transfer(from, to, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Internal function that mints an amount of the token and assigns it to
|
||||||
|
* an account. This encapsulates the modification of balances such that the
|
||||||
|
* proper events are emitted.
|
||||||
|
* @param account The account that will receive the created tokens.
|
||||||
|
* @param value The amount that will be created.
|
||||||
|
*/
|
||||||
|
function _mint(address account, uint256 value) internal {
|
||||||
|
require(account != address(0), 'invalid address');
|
||||||
|
|
||||||
|
_totalSupply = _totalSupply.add(value);
|
||||||
|
_balances[account] = _balances[account].add(value);
|
||||||
|
emit Transfer(address(0), account, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Approve an address to spend another addresses' tokens.
|
||||||
|
* @param owner The address that owns the tokens.
|
||||||
|
* @param spender The address that will spend the tokens.
|
||||||
|
* @param value The number of tokens that can be spent.
|
||||||
|
*/
|
||||||
|
function _approve(address owner, address spender, uint256 value) internal {
|
||||||
|
require(spender != address(0));
|
||||||
|
require(owner != address(0));
|
||||||
|
|
||||||
|
_allowed[owner][spender] = value;
|
||||||
|
emit Approval(owner, spender, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
apps/token/contracts/Token.sol
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
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, uint256 contributionId);
|
||||||
|
|
||||||
|
function initialize(bytes32[4] _appIds) public onlyInit {
|
||||||
|
appIds = _appIds;
|
||||||
|
initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mintFor(address contributorAccount, uint256 amount, uint256 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) {
|
||||||
|
_mint(contributorAccount, amount);
|
||||||
|
emit LogMint(contributorAccount, amount, contributionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
apps/token/contracts/misc/Migrations.sol
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
contract Migrations {
|
||||||
|
address public owner;
|
||||||
|
uint public last_completed_migration;
|
||||||
|
|
||||||
|
modifier restricted() {
|
||||||
|
if (msg.sender == owner) _;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() public {
|
||||||
|
owner = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCompleted(uint completed) public restricted {
|
||||||
|
last_completed_migration = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade(address new_address) public restricted {
|
||||||
|
Migrations upgraded = Migrations(new_address);
|
||||||
|
upgraded.setCompleted(last_completed_migration);
|
||||||
|
}
|
||||||
|
}
|
4
apps/token/manifest.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "Token",
|
||||||
|
"description": "Kredits token app"
|
||||||
|
}
|
5
apps/token/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Migrations = artifacts.require('./Migrations.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Migrations)
|
||||||
|
}
|
5
apps/token/migrations/2_deploy_contracts.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Token = artifacts.require('Token.sol')
|
||||||
|
|
||||||
|
module.exports = function (deployer) {
|
||||||
|
deployer.deploy(Token)
|
||||||
|
}
|
13977
apps/token/package-lock.json
generated
Normal file
27
apps/token/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "kredits-token",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@aragon/os": "^4.1.0",
|
||||||
|
"@aragon/cli": "^5.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"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": "",
|
||||||
|
"test": "aragon contracts test",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"keywords": []
|
||||||
|
}
|
5
apps/token/test/app.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const CounterApp = artifacts.require('CounterApp.sol')
|
||||||
|
|
||||||
|
contract('CounterApp', (accounts) => {
|
||||||
|
it('should be tested')
|
||||||
|
})
|
1
apps/token/truffle.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("../../truffle.js");
|
60
arapp.json
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "Add contributions",
|
||||||
|
"id": "ADD_CONTRIBUTION_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Veto contributions",
|
||||||
|
"id": "VETO_CONTRIBUTION_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Manage contributors",
|
||||||
|
"id": "MANAGE_CONTRIBUTORS_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mint token",
|
||||||
|
"id": "MINT_TOKEN_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Add proposal",
|
||||||
|
"id": "ADD_PROPOSAL_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vote proposal",
|
||||||
|
"id": "VOTE_PROPOSAL_ROLE",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environments": {
|
||||||
|
"development": {
|
||||||
|
"network": "development",
|
||||||
|
"apm": "aragonpm.eth",
|
||||||
|
"registry": "0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1",
|
||||||
|
"appName": "dummy.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,10 +1,11 @@
|
|||||||
let contractCalls = [
|
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: '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}]],
|
['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}]],
|
['Proposal', '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}]],
|
['Proposal', '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}]],
|
['Proposal', 'addProposal', [{contributorId: 3, amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
|
||||||
['Operator', 'vote', ['1', {gasLimit: 250000}]]
|
['Proposal', 'vote', [1, {gasLimit: 550000}]],
|
||||||
|
['Contribution', 'addContribution', [{contributorAccount: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
|
||||||
];
|
];
|
||||||
let funds = [
|
let funds = [
|
||||||
'0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
'0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
||||||
|
87
contracts/KreditsKit.sol
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
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(), root);
|
||||||
|
|
||||||
|
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(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), params);
|
||||||
|
acl.grantPermissionP(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), params);
|
||||||
|
|
||||||
|
//acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE();
|
||||||
|
acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this);
|
||||||
|
acl.grantPermissionP(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), params);
|
||||||
|
|
||||||
|
acl.createPermission(root, proposal, proposal.ADD_PROPOSAL_ROLE(), this);
|
||||||
|
acl.grantPermissionP(root, proposal, proposal.ADD_PROPOSAL_ROLE(), params);
|
||||||
|
|
||||||
|
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.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,130 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
// ToDo: only load interfaces
|
|
||||||
import './Token.sol';
|
|
||||||
import './Contributors.sol';
|
|
||||||
|
|
||||||
contract Operator is Upgradeable {
|
|
||||||
|
|
||||||
struct Proposal {
|
|
||||||
address creatorAccount;
|
|
||||||
uint contributorId;
|
|
||||||
uint votesCount;
|
|
||||||
uint votesNeeded;
|
|
||||||
uint256 amount;
|
|
||||||
bool executed;
|
|
||||||
bytes32 ipfsHash;
|
|
||||||
uint8 hashFunction;
|
|
||||||
uint8 hashSize;
|
|
||||||
uint256[] voterIds;
|
|
||||||
mapping (uint256 => bool) votes;
|
|
||||||
bool exists;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping(uint256 => Proposal) public proposals;
|
|
||||||
uint256 public proposalsCount;
|
|
||||||
|
|
||||||
event ProposalCreated(uint256 id, address creatorAccount, uint256 contributorId, uint256 amount);
|
|
||||||
event ProposalVoted(uint256 id, uint256 voterId, uint256 totalVotes);
|
|
||||||
event ProposalExecuted(uint256 id, uint256 contributorId, uint256 amount);
|
|
||||||
|
|
||||||
modifier coreOnly() {
|
|
||||||
require(contributorsContract().addressIsCore(msg.sender));
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
modifier contributorOnly() {
|
|
||||||
require(contributorsContract().addressExists(msg.sender));
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
modifier noEther() {
|
|
||||||
require(msg.value == 0);
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function contributorsContract() view public returns (Contributors) {
|
|
||||||
return Contributors(registry.getProxyFor('Contributors'));
|
|
||||||
}
|
|
||||||
function tokenContract() view public returns (Token) {
|
|
||||||
return Token(registry.getProxyFor('Token'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function contributorsCount() view public returns (uint) {
|
|
||||||
return contributorsContract().contributorsCount();
|
|
||||||
}
|
|
||||||
function coreContributorsCount() view public returns (uint) {
|
|
||||||
return contributorsContract().coreContributorsCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addProposal(uint contributorId, uint256 amount, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public {
|
|
||||||
require(contributorsContract().exists(contributorId));
|
|
||||||
|
|
||||||
uint256 proposalId = proposalsCount + 1;
|
|
||||||
uint256 _votesNeeded = contributorsContract().coreContributorsCount() / 100 * 75;
|
|
||||||
|
|
||||||
var p = proposals[proposalId];
|
|
||||||
p.creatorAccount = msg.sender;
|
|
||||||
p.contributorId = contributorId;
|
|
||||||
p.amount = amount;
|
|
||||||
p.ipfsHash = ipfsHash;
|
|
||||||
p.hashFunction = hashFunction;
|
|
||||||
p.hashSize = hashSize;
|
|
||||||
p.votesCount = 0;
|
|
||||||
p.votesNeeded = _votesNeeded;
|
|
||||||
p.exists = true;
|
|
||||||
|
|
||||||
proposalsCount++;
|
|
||||||
ProposalCreated(proposalId, msg.sender, p.contributorId, p.amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getProposal(uint proposalId) public view returns (uint256 id, address creatorAccount, uint256 contributorId, uint256 votesCount, uint256 votesNeeded, uint256 amount, bool executed, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, uint256[] voterIds, bool exists) {
|
|
||||||
id = proposalId;
|
|
||||||
Proposal storage p = proposals[id];
|
|
||||||
return (
|
|
||||||
id,
|
|
||||||
p.creatorAccount,
|
|
||||||
p.contributorId,
|
|
||||||
p.votesCount,
|
|
||||||
p.votesNeeded,
|
|
||||||
p.amount,
|
|
||||||
p.executed,
|
|
||||||
p.ipfsHash,
|
|
||||||
p.hashFunction,
|
|
||||||
p.hashSize,
|
|
||||||
p.voterIds,
|
|
||||||
p.exists
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function vote(uint256 proposalId) public coreOnly {
|
|
||||||
var p = proposals[proposalId];
|
|
||||||
require(!p.executed);
|
|
||||||
uint256 voterId = contributorsContract().getContributorIdByAddress(msg.sender);
|
|
||||||
require(p.votes[voterId] != true);
|
|
||||||
p.voterIds.push(voterId);
|
|
||||||
p.votes[voterId] = true;
|
|
||||||
|
|
||||||
p.votesCount++;
|
|
||||||
if (p.votesCount >= p.votesNeeded) {
|
|
||||||
executeProposal(proposalId);
|
|
||||||
}
|
|
||||||
ProposalVoted(proposalId, voterId, p.votesCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
function batchVote(uint256[] _proposalIds) public coreOnly {
|
|
||||||
for (uint256 i = 0; i < _proposalIds.length; i++) {
|
|
||||||
vote(_proposalIds[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeProposal(uint proposalId) private {
|
|
||||||
|
|
||||||
var p = proposals[proposalId];
|
|
||||||
require(!p.executed);
|
|
||||||
require(p.votesCount >= p.votesNeeded);
|
|
||||||
address recipientAddress = contributorsContract().getContributorAddressById(p.contributorId);
|
|
||||||
tokenContract().mintFor(recipientAddress, p.amount, proposalId);
|
|
||||||
p.executed = true;
|
|
||||||
ProposalExecuted(proposalId, p.contributorId, p.amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
import 'zeppelin-solidity/contracts/token/ERC20/BasicToken.sol';
|
|
||||||
import './upgradeable/Upgradeable.sol';
|
|
||||||
|
|
||||||
contract Token is Upgradeable, BasicToken {
|
|
||||||
string public name;
|
|
||||||
string public symbol;
|
|
||||||
uint8 public decimals;
|
|
||||||
|
|
||||||
event LogMint(address indexed recipient, uint256 amount, uint256 proposalId);
|
|
||||||
|
|
||||||
function initialize(address sender) public payable {
|
|
||||||
require(msg.sender == address(registry));
|
|
||||||
name = 'Kredits';
|
|
||||||
symbol = 'K';
|
|
||||||
decimals = 18;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mintFor(address contributorAccount, uint256 amount, uint proposalId) onlyRegistryContractFor('Operator') public {
|
|
||||||
totalSupply_ = totalSupply_.add(amount);
|
|
||||||
balances[contributorAccount] = balances[contributorAccount].add(amount);
|
|
||||||
|
|
||||||
LogMint(contributorAccount, amount, proposalId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
13
contracts/misc/APMNamehashOpen.sol
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
pragma solidity 0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/apm/APMNamehash.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract APMNamehashOpen is APMNamehash {
|
||||||
|
bytes32 public constant OPEN_TITLE = keccak256("open");
|
||||||
|
bytes32 public constant OPEN_APM_NODE = keccak256(abi.encodePacked(APM_NODE, OPEN_TITLE));
|
||||||
|
|
||||||
|
function apmNamehashOpen(string name) internal pure returns (bytes32) {
|
||||||
|
return keccak256(abi.encodePacked(OPEN_APM_NODE, keccak256(name)));
|
||||||
|
}
|
||||||
|
}
|
16
contracts/misc/DummyApp.sol
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
pragma solidity 0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// This is a "Dummy" app which's only purpose to exist is because
|
||||||
|
// Aragon's CLI still doesn't support running a Kit inside a project
|
||||||
|
// which isn't considered to be a "valid" Aragon project.
|
||||||
|
// It requires us to have an arrap.json file pointing to the contract
|
||||||
|
// and a manifest.json file which describes the front-end structure.
|
||||||
|
contract DummyApp is AragonApp {
|
||||||
|
function initialize() public onlyInit {
|
||||||
|
initialized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
23
contracts/misc/Migrations.sol
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
pragma solidity ^0.4.4;
|
||||||
|
|
||||||
|
contract Migrations {
|
||||||
|
address public owner;
|
||||||
|
uint public last_completed_migration;
|
||||||
|
|
||||||
|
modifier restricted() {
|
||||||
|
if (msg.sender == owner) _;
|
||||||
|
}
|
||||||
|
|
||||||
|
function constructor() public {
|
||||||
|
owner = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCompleted(uint completed) public restricted {
|
||||||
|
last_completed_migration = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade(address new_address) public restricted {
|
||||||
|
Migrations upgraded = Migrations(new_address);
|
||||||
|
upgraded.setCompleted(last_completed_migration);
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title IRegistry
|
|
||||||
* @dev This contract represents the interface of a registry contract
|
|
||||||
*/
|
|
||||||
interface IRegistry {
|
|
||||||
/**
|
|
||||||
* @dev This event will be emitted every time a new proxy is created
|
|
||||||
* @param name of the contract, as specified in the registry
|
|
||||||
* @param proxy representing the address of the proxy created
|
|
||||||
*/
|
|
||||||
event ProxyCreated(string name, address proxy);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev This event will be emitted every time a new implementation is registered
|
|
||||||
* @param name of the contract, as specified in the registry
|
|
||||||
* @param version representing the version name of the registered implementation
|
|
||||||
* @param implementation representing the address of the registered implementation
|
|
||||||
*/
|
|
||||||
event VersionAdded(string name, uint version, address implementation);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev This event will be emitted every time a proxy is upgraded to a new version
|
|
||||||
* @param name of the contract, as specified in the registry
|
|
||||||
* @param version representing the version name of the registered implementation
|
|
||||||
*/
|
|
||||||
event ProxyImplementationUpgraded(string name, uint version);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Registers a new version with its implementation address
|
|
||||||
* @param name of the contract, as specified in the registry
|
|
||||||
* @param implementation representing the address of the new implementation to be registered
|
|
||||||
*/
|
|
||||||
function addVersion(string name, address implementation) public;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Tells the address of the implementation for a given version
|
|
||||||
* @param name of the contract, as specified in the registry
|
|
||||||
* @param version to query the implementation of
|
|
||||||
* @return address of the implementation registered for the given version
|
|
||||||
*/
|
|
||||||
function getVersion(string name, uint version) public view returns (address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Tells the latest address of the implementation
|
|
||||||
* @param name of the contract, as specified in the registry
|
|
||||||
* @return address of the implementation registered for the latest version
|
|
||||||
*/
|
|
||||||
function getLatestVersion(string name) public view returns (address);
|
|
||||||
|
|
||||||
function getProxyFor(string name) public view returns (address);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Proxy
|
|
||||||
* @dev Gives the possibility to delegate any call to a foreign implementation.
|
|
||||||
*/
|
|
||||||
contract Proxy {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Tells the address of the implementation where every call will be delegated.
|
|
||||||
* @return address of the implementation to which it will be delegated
|
|
||||||
*/
|
|
||||||
function implementation() public view returns (address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
|
|
||||||
* This function will return whatever the implementation call returns
|
|
||||||
*/
|
|
||||||
function () payable public {
|
|
||||||
address _impl = implementation();
|
|
||||||
require(_impl != address(0));
|
|
||||||
bytes memory data = msg.data;
|
|
||||||
|
|
||||||
assembly {
|
|
||||||
let result := delegatecall(gas, _impl, add(data, 0x20), mload(data), 0, 0)
|
|
||||||
let size := returndatasize
|
|
||||||
|
|
||||||
let ptr := mload(0x40)
|
|
||||||
returndatacopy(ptr, 0, size)
|
|
||||||
|
|
||||||
switch result
|
|
||||||
case 0 { revert(ptr, size) }
|
|
||||||
default { return(ptr, size) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
import './IRegistry.sol';
|
|
||||||
import './Upgradeable.sol';
|
|
||||||
import './UpgradeabilityProxy.sol';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Registry
|
|
||||||
* @dev This contract works as a registry of versions, it holds the implementations for the registered versions.
|
|
||||||
*/
|
|
||||||
contract Registry is IRegistry {
|
|
||||||
// mapping of contract names to versions to implementation
|
|
||||||
// "Token" => "1.0.0" => "0x123"
|
|
||||||
mapping(bytes32 => mapping(uint => address)) public versions;
|
|
||||||
|
|
||||||
// current version for a certain contract
|
|
||||||
mapping(bytes32 => uint) public currentVersions;
|
|
||||||
|
|
||||||
// mapping of the contract names to the proxy addresses
|
|
||||||
mapping(bytes32 => address) public proxies;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Registers a new version with its implementation address
|
|
||||||
* @param name of the contract
|
|
||||||
* @param implementation representing the address of the new implementation to be registered
|
|
||||||
*/
|
|
||||||
function addVersion(string name, address implementation) public {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
currentVersions[key] = currentVersions[key] + 1;
|
|
||||||
uint version = currentVersions[key];
|
|
||||||
require(versions[key][version] == 0x0);
|
|
||||||
versions[key][version] = implementation;
|
|
||||||
VersionAdded(name, version, implementation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Tells the address of the implementation for a given version
|
|
||||||
* @param name of the contract
|
|
||||||
* @param version to query the implementation of
|
|
||||||
* @return address of the implementation registered for the given version
|
|
||||||
*/
|
|
||||||
function getVersion(string name, uint version) public view returns (address) {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
return versions[key][version];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLatestVersion(string name) public view returns (address) {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
uint current = currentVersions[key];
|
|
||||||
return getVersion(name, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getProxyFor(string name) public view returns (address) {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
return proxies[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgrade(string name, uint version) public {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
UpgradeabilityProxy(proxies[key]).upgradeTo(version);
|
|
||||||
ProxyImplementationUpgraded(name, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgradeToLatest(string name) public {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
uint current = currentVersions[key];
|
|
||||||
upgrade(name, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Creates an upgradeable proxy
|
|
||||||
* @param name of the contract
|
|
||||||
* @param version representing the first version to be set for the proxy
|
|
||||||
* @return address of the new proxy created
|
|
||||||
*/
|
|
||||||
function createProxy(string name, uint version) public payable returns (UpgradeabilityProxy) {
|
|
||||||
bytes32 key = keccak256(name);
|
|
||||||
require(proxies[key] == 0x0);
|
|
||||||
UpgradeabilityProxy proxy = new UpgradeabilityProxy(name, version);
|
|
||||||
proxies[key] = address(proxy);
|
|
||||||
Upgradeable(proxy).initialize.value(msg.value)(msg.sender);
|
|
||||||
ProxyCreated(name, proxy);
|
|
||||||
return proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
import './Proxy.sol';
|
|
||||||
import './IRegistry.sol';
|
|
||||||
import './UpgradeabilityStorage.sol';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title UpgradeabilityProxy
|
|
||||||
* @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
|
|
||||||
*/
|
|
||||||
contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
|
|
||||||
|
|
||||||
function UpgradeabilityProxy(string _name, uint _version) public {
|
|
||||||
_proxiedContractName = _name;
|
|
||||||
registry = IRegistry(msg.sender);
|
|
||||||
upgradeTo(_version);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Upgrades the implementation to the requested version
|
|
||||||
* @param _version representing the version name of the new implementation to be set
|
|
||||||
*/
|
|
||||||
function upgradeTo(uint _version) public {
|
|
||||||
require(msg.sender == address(registry));
|
|
||||||
_implementation = registry.getVersion(_proxiedContractName, _version);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
import './IRegistry.sol';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title UpgradeabilityStorage
|
|
||||||
* @dev This contract holds all the necessary state variables to support the upgrade functionality
|
|
||||||
*/
|
|
||||||
contract UpgradeabilityStorage {
|
|
||||||
// Versions registry
|
|
||||||
IRegistry internal registry;
|
|
||||||
|
|
||||||
// Address of the current implementation
|
|
||||||
address internal _implementation;
|
|
||||||
|
|
||||||
// contract name
|
|
||||||
string public _proxiedContractName;
|
|
||||||
|
|
||||||
|
|
||||||
modifier requireRegistry() {
|
|
||||||
require(address(registry) != 0x0);
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
modifier onlyRegistryContractFor(string name) {
|
|
||||||
require(address(registry) != 0x0);
|
|
||||||
require(msg.sender == registry.getProxyFor(name));
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Tells the address of the current implementation
|
|
||||||
* @return address of the current implementation
|
|
||||||
*/
|
|
||||||
function implementation() public view returns (address) {
|
|
||||||
return _implementation;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
pragma solidity ^0.4.18;
|
|
||||||
|
|
||||||
import './UpgradeabilityStorage.sol';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Upgradeable
|
|
||||||
* @dev This contract holds all the minimum required functionality for a behavior to be upgradeable.
|
|
||||||
* This means, required state variables for owned upgradeability purpose and simple initialization validation.
|
|
||||||
*/
|
|
||||||
contract Upgradeable is UpgradeabilityStorage {
|
|
||||||
/**
|
|
||||||
* @dev Validates the caller is the versions registry.
|
|
||||||
* THIS FUNCTION SHOULD BE OVERRIDDEN CALLING SUPER
|
|
||||||
* @param sender representing the address deploying the initial behavior of the contract
|
|
||||||
*/
|
|
||||||
function initialize(address sender) public payable {
|
|
||||||
require(msg.sender == address(registry));
|
|
||||||
}
|
|
||||||
}
|
|
28
deployments/rinkeby/contribution.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Contribution deployments
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
19
deployments/rinkeby/contributor.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Contributor deployments
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
27
deployments/rinkeby/dao.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Kredits deployment
|
||||||
|
|
||||||
|
### 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
|
54
deployments/rinkeby/kreditskit.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# KreditsKit deployments
|
||||||
|
|
||||||
|
## 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"
|
||||||
|
|
27
deployments/rinkeby/proposal.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Proposal deployments
|
||||||
|
|
||||||
|
## 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
|
18
deployments/rinkeby/token.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Token deployments
|
||||||
|
|
||||||
|
## 2019-03-26
|
||||||
|
|
||||||
|
### v2.0.0 support for appIds
|
||||||
|
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||||
|
✔ Successfully published kredits-token.open.aragonpm.eth v2.0.0:
|
||||||
|
ℹ Contract address: 0xc126919B3b30F14b848c2cc66Ec21A1e85a7c621
|
||||||
|
ℹ Content (ipfs): QmWB9JrWa93vtdv5VG2yohiWTbDiuzbz9P58apJdP3FnNP
|
||||||
|
ℹ Transaction hash: 0xa5ccd532a91d67b0616ee5505144988be4360440daf70dc2f5108dd2a59f3d68
|
||||||
|
|
||||||
|
|
||||||
|
## 2019-03-25
|
||||||
|
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||||
|
✔ Successfully published kredits-token.open.aragonpm.eth v1.0.0:
|
||||||
|
ℹ Contract address: 0xB4147Be6d4bcC790c6CbD3d508354DDfd3EbC8e6
|
||||||
|
ℹ Content (ipfs): QmQPue7WzQhaXbTLJwyZXSHaRY1u5ezWxyVmBP8bEgGoTE
|
||||||
|
ℹ Transaction hash: 0xa7866d81e236adfeaff6bf2d5dbc9f9757fbc1b0ce689357901194913fe93a3b"
|
BIN
docs/kredits-diagram.png
Normal file
After Width: | Height: | Size: 15 KiB |
1
lib/abis/ACL.json
Normal file
1
lib/abis/Contribution.json
Normal file
1
lib/abis/Contributor.json
Normal file
@ -1 +0,0 @@
|
|||||||
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contributors","outputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"contributorIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldIpfsHash","type":"bytes32"},{"indexed":false,"name":"newIpfsHash","type":"bytes32"}],"name":"ContributorProfileUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldAccount","type":"address"},{"indexed":false,"name":"newAccount","type":"address"}],"name":"ContributorAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"account","type":"address"}],"name":"ContributorAdded","type":"event"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"oldAccount","type":"address"},{"name":"newAccount","type":"address"}],"name":"updateContributorAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"updateContributorIpfsHash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"}],"name":"addContributor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"isCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"exists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressIsCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"getContributorAddressById","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"getContributorById","outputs":[{"name":"id","type":"uint256"},{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"balance","type":"uint256"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]
|
|
1
lib/abis/Kernel.json
Normal file
@ -1 +0,0 @@
|
|||||||
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposalsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"creatorAccount","type":"address"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"voterId","type":"uint256"},{"indexed":false,"name":"totalVotes","type":"uint256"}],"name":"ProposalVoted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalExecuted","type":"event"},{"constant":true,"inputs":[],"name":"contributorsContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"contributorId","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"addProposal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"getProposal","outputs":[{"name":"id","type":"uint256"},{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"voterIds","type":"uint256[]"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_proposalIds","type":"uint256[]"}],"name":"batchVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
|
|
1
lib/abis/Proposal.json
Normal file
@ -1 +0,0 @@
|
|||||||
[{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"currentVersions","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"name":"versions","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"proxy","type":"address"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"},{"indexed":false,"name":"implementation","type":"address"}],"name":"VersionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"}],"name":"ProxyImplementationUpgraded","type":"event"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"implementation","type":"address"}],"name":"addVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"getVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getLatestVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getProxyFor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"upgradeToLatest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"createProxy","outputs":[{"name":"","type":"address"}],"payable":true,"stateMutability":"payable","type":"function"}]
|
|
@ -1 +0,0 @@
|
|||||||
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"}
|
|
4
lib/addresses/KreditsKit.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"4": "0x1d6a9c2146a330575ee860eef9a012b5ff7caa68",
|
||||||
|
"41787949": "0xa35aacdfccac54d3d96e0d29050c773b251c2c83"
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"}
|
|
@ -1 +0,0 @@
|
|||||||
{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x7458dea485d9d8301e3ce43e8a1ec1456be5ba83"}
|
|
@ -1 +0,0 @@
|
|||||||
{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"}
|
|
4
lib/addresses/dao.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
![]() I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
![]() I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
![]() Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
![]() Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
![]() Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
![]() Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
![]() hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
![]() hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
|||||||
|
{
|
||||||
![]() I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
![]() Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
![]() Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
![]() hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
|||||||
|
"4": "0x95a7ce185efc2d1f13efd2a00ee9247c51ea7009",
|
||||||
![]() I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
![]() Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
![]() Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
![]() hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
|||||||
|
"41787949": "0x183af3950364390a266edff2a0e7c4c2f95c0691"
|
||||||
![]() I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
![]() Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
![]() Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
![]() hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
|||||||
|
}
|
||||||
![]() I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
![]() Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
![]() Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
![]() hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
13
lib/contracts/acl.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const Base = require('./base');
|
||||||
|
const EthersUtils = require('ethers').utils;
|
||||||
|
|
||||||
|
class Acl extends Base {
|
||||||
|
|
||||||
|
hasPermission(fromAddress, contractAddress, roleID, params = null) {
|
||||||
|
let roleHash = EthersUtils.keccak256(EthersUtils.toUtf8Bytes(roleID));
|
||||||
|
console.log(roleHash)
|
||||||
|
return this.functions.hasPermission(fromAddress, contractAddress, roleHash, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Acl;
|
@ -17,11 +17,7 @@ class Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
on(type, callback) {
|
on(type, callback) {
|
||||||
let eventMethod = `on${type.toLowerCase()}`;
|
return this.contract.on(type, callback);
|
||||||
// Don't use this.contract.events here. Seems to be a bug in ethers.js
|
|
||||||
this.contract[eventMethod] = callback;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Base;
|
module.exports = Base;
|
||||||
|
70
lib/contracts/contribution.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const ethers = require('ethers');
|
||||||
|
const RSVP = require('rsvp');
|
||||||
|
|
||||||
|
const ContributionSerializer = require('../serializers/contribution');
|
||||||
|
const Base = require('./base');
|
||||||
|
|
||||||
|
class Contribution extends Base {
|
||||||
|
all() {
|
||||||
|
return this.functions.contributionsCount()
|
||||||
|
.then((count) => {
|
||||||
|
count = count.toNumber();
|
||||||
|
let contributions = [];
|
||||||
|
|
||||||
|
for (let id = 1; id <= count; id++) {
|
||||||
|
contributions.push(this.getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSVP.all(contributions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getById(id) {
|
||||||
|
id = ethers.utils.bigNumberify(id);
|
||||||
|
|
||||||
|
return this.functions.getContribution(id)
|
||||||
|
.then((data) => {
|
||||||
|
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getByContributor(contributor) {
|
||||||
|
return this.functions.balanceOf(contributor)
|
||||||
|
then((balance) => {
|
||||||
|
count = balance.toNumber();
|
||||||
|
|
||||||
|
let contributions = [];
|
||||||
|
|
||||||
|
for (let index = 0; index <= count; index++) {
|
||||||
|
this.functions.tokenOfOwnerByIndex(contributor, index)
|
||||||
|
.then((id) => {
|
||||||
|
contributions.push(this.getById(id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSVP.all(contributions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addContribution(contributionAttr, callOptions = {}) {
|
||||||
|
let json = ContributionSerializer.serialize(contributionAttr);
|
||||||
|
// TODO: validate against schema
|
||||||
|
|
||||||
|
return this.ipfs
|
||||||
|
.add(json)
|
||||||
|
.then((ipfsHashAttr) => {
|
||||||
|
let contribution = [
|
||||||
|
contributionAttr.amount,
|
||||||
|
contributionAttr.contributorAccount,
|
||||||
|
ipfsHashAttr.hashDigest,
|
||||||
|
ipfsHashAttr.hashFunction,
|
||||||
|
ipfsHashAttr.hashSize,
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.functions.add(...contribution, callOptions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Contribution;
|
@ -1,6 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
Contributors: require('./contributor'),
|
Contributor: require('./contributor'),
|
||||||
Operator: require('./operator'),
|
Contribution: require('./contribution'),
|
||||||
|
Proposal: require('./proposal'),
|
||||||
Token: require('./token'),
|
Token: require('./token'),
|
||||||
Registry: require('./registry')
|
Kernel: require('./kernel'),
|
||||||
|
Acl: require('./acl')
|
||||||
};
|
};
|
||||||
|
24
lib/contracts/kernel.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const namehash = require('eth-ens-namehash').hash;
|
||||||
|
const Base = require('./base');
|
||||||
|
|
||||||
|
const KERNEL_APP_ADDR_NAMESPACE = '0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb';
|
||||||
|
|
||||||
|
class Kernel extends Base {
|
||||||
|
constructor(contract) {
|
||||||
|
super(contract);
|
||||||
|
this.apm = 'aragonpm.eth'; // can be overwritten if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
getApp(appName) {
|
||||||
|
if (appName === 'Acl') {
|
||||||
|
return this.functions.acl();
|
||||||
|
}
|
||||||
|
return this.functions.getApp(KERNEL_APP_ADDR_NAMESPACE, this.appNamehash(appName));
|
||||||
|
}
|
||||||
|
|
||||||
|
appNamehash(appName) {
|
||||||
|
return namehash(`kredits-${appName.toLowerCase()}.${this.apm}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Kernel;
|
@ -4,7 +4,7 @@ const RSVP = require('rsvp');
|
|||||||
const ContributionSerializer = require('../serializers/contribution');
|
const ContributionSerializer = require('../serializers/contribution');
|
||||||
const Base = require('./base');
|
const Base = require('./base');
|
||||||
|
|
||||||
class Operator extends Base {
|
class Proposal extends Base {
|
||||||
all() {
|
all() {
|
||||||
return this.functions.proposalsCount()
|
return this.functions.proposalsCount()
|
||||||
.then((count) => {
|
.then((count) => {
|
||||||
@ -23,12 +23,6 @@ class Operator extends Base {
|
|||||||
id = ethers.utils.bigNumberify(id);
|
id = ethers.utils.bigNumberify(id);
|
||||||
|
|
||||||
return this.functions.getProposal(id)
|
return this.functions.getProposal(id)
|
||||||
.then((data) => {
|
|
||||||
// TODO: remove when naming updated on the contract
|
|
||||||
data.hashDigest = data.ipfsHash;
|
|
||||||
return data;
|
|
||||||
})
|
|
||||||
// Fetch IPFS data if available
|
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||||
});
|
});
|
||||||
@ -54,4 +48,4 @@ class Operator extends Base {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Operator;
|
module.exports = Proposal
|
@ -1,6 +0,0 @@
|
|||||||
const Base = require('./base');
|
|
||||||
|
|
||||||
class Registry extends Base {
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Registry;
|
|
@ -4,12 +4,21 @@ const RSVP = require('rsvp');
|
|||||||
const Preflight = require('./utils/preflight');
|
const Preflight = require('./utils/preflight');
|
||||||
|
|
||||||
const ABIS = {
|
const ABIS = {
|
||||||
Contributors: require('./abis/Contributors.json'),
|
Contributor: require('./abis/Contributor.json'),
|
||||||
Operator: require('./abis/Operator.json'),
|
Contribution: require('./abis/Contribution.json'),
|
||||||
Registry: require('./abis/Registry.json'),
|
Token: require('./abis/Token.json'),
|
||||||
Token: require('./abis/Token.json')
|
Proposal: require('./abis/Proposal.json'),
|
||||||
|
Kernel: require('./abis/Kernel.json'),
|
||||||
|
Acl: require('./abis/ACL.json')
|
||||||
};
|
};
|
||||||
const RegistryAddress = require('./addresses/Registry.json');
|
const APP_CONTRACTS = [
|
||||||
|
'Contributor',
|
||||||
|
'Contribution',
|
||||||
|
'Token',
|
||||||
|
'Proposal',
|
||||||
|
'Acl'
|
||||||
|
];
|
||||||
|
const DaoAddresses = require('./addresses/dao.json');
|
||||||
|
|
||||||
const Contracts = require('./contracts');
|
const Contracts = require('./contracts');
|
||||||
const IPFS = require('./utils/ipfs')
|
const IPFS = require('./utils/ipfs')
|
||||||
@ -27,26 +36,29 @@ class Kredits {
|
|||||||
|
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.signer = signer;
|
this.signer = signer;
|
||||||
// by default we only need the registry address.
|
this.options = options;
|
||||||
// the rest is loaded from there in the init() function
|
this.addresses = addresses || {};
|
||||||
this.addresses = addresses || { Registry: RegistryAddress[this.provider.chainId.toString()] }; // chainID must be a string
|
|
||||||
this.abis = abis || ABIS;
|
this.abis = abis || ABIS;
|
||||||
this.ipfs = new IPFS(ipfsConfig);
|
this.ipfs = new IPFS(ipfsConfig);
|
||||||
this.contracts = {};
|
this.contracts = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
init(names) {
|
init(names) {
|
||||||
let contractsToLoad = names || Object.keys(ABIS);
|
let contractsToLoad = names || APP_CONTRACTS;
|
||||||
|
return this.provider.getNetwork().then(network => {
|
||||||
|
this.addresses['Kernel'] = this.addresses['Kernel'] || DaoAddresses[network.chainId.toString()];
|
||||||
let addressPromises = contractsToLoad.map((contractName) => {
|
let addressPromises = contractsToLoad.map((contractName) => {
|
||||||
return this.Registry.functions.getProxyFor(contractName).then((address) => {
|
return this.Kernel.getApp(contractName).then((address) => {
|
||||||
this.addresses[contractName] = address;
|
this.addresses[contractName] = address;
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
throw new Error(`Failed to get address for ${contractName} from registry at ${this.Registry.contract.address}
|
console.log(error);
|
||||||
- correct registry? does it have version entry? - ${error.message}`
|
throw new Error(`Failed to get address for ${contractName} from DAO at ${this.Kernel.contract.address}
|
||||||
|
- ${error.message}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return RSVP.all(addressPromises).then(() => { return this });
|
return RSVP.all(addressPromises).then(() => { return this });
|
||||||
![]() Can be removed Can be removed
|
|||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static setup(provider, signer, ipfsConfig = null) {
|
static setup(provider, signer, ipfsConfig = null) {
|
||||||
@ -54,13 +66,17 @@ class Kredits {
|
|||||||
return new Kredits(provider, signer, { ipfsConfig: ipfsConfig }).init();
|
return new Kredits(provider, signer, { ipfsConfig: ipfsConfig }).init();
|
||||||
}
|
}
|
||||||
|
|
||||||
get Registry() {
|
get Kernel() {
|
||||||
return this.contractFor('registry');
|
let k = this.contractFor('Kernel');
|
||||||
|
// in case we want to use a special apm (e.g. development vs. production)
|
||||||
|
if (this.options.apm) {
|
||||||
|
k.apm = this.options.apm;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
get Contributor() {
|
get Contributor() {
|
||||||
// TODO: rename to contributor
|
return this.contractFor('Contributor');
|
||||||
return this.contractFor('contributors');
|
|
||||||
}
|
}
|
||||||
![]() You don't need the You don't need the `()` see `get Contributors()`
![]() ah ja... thx. ah ja... thx.
|
|||||||
|
|
||||||
get Contributors() {
|
get Contributors() {
|
||||||
@ -68,12 +84,24 @@ class Kredits {
|
|||||||
return this.Contributor;
|
return this.Contributor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get Proposal() {
|
||||||
|
return this.contractFor('Proposal');
|
||||||
|
}
|
||||||
|
|
||||||
get Operator() {
|
get Operator() {
|
||||||
return this.contractFor('operator');
|
return this.Proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
get Token() {
|
get Token() {
|
||||||
return this.contractFor('token');
|
return this.contractFor('Token');
|
||||||
|
}
|
||||||
|
|
||||||
|
get Contribution() {
|
||||||
|
return this.contractFor('Contribution');
|
||||||
|
}
|
||||||
|
|
||||||
|
get Acl() {
|
||||||
|
return this.contractFor('Acl');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be private
|
// Should be private
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
var Registry = artifacts.require('./upgradeable/Registry.sol');
|
|
||||||
|
|
||||||
module.exports = function(deployer) {
|
|
||||||
deployer.deploy(Registry);
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
var Registry = artifacts.require('./Registry.sol');
|
|
||||||
var Token = artifacts.require('./Token.sol');
|
|
||||||
|
|
||||||
module.exports = function(deployer) {
|
|
||||||
deployer.deploy(Token).then(function(token) {
|
|
||||||
console.log('Registry address: ', Registry.address);
|
|
||||||
console.log('Token address: ', Token.address);
|
|
||||||
Registry.deployed().then(function(registry) {
|
|
||||||
registry.addVersion('Token', Token.address);
|
|
||||||
registry.createProxy('Token', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
var Registry = artifacts.require('./Registry.sol');
|
|
||||||
var Contributors = artifacts.require('./Contributors.sol');
|
|
||||||
|
|
||||||
module.exports = function(deployer) {
|
|
||||||
deployer.deploy(Contributors).then(function(contributors) {
|
|
||||||
console.log('Registry address: ', Registry.address);
|
|
||||||
console.log('Contributors address: ', Contributors.address);
|
|
||||||
Registry.deployed().then(function(registry) {
|
|
||||||
registry.addVersion('Contributors', Contributors.address);
|
|
||||||
registry.createProxy('Contributors', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,13 +0,0 @@
|
|||||||
var Registry = artifacts.require('./Registry.sol');
|
|
||||||
var Operator = artifacts.require('./Operator.sol');
|
|
||||||
|
|
||||||
module.exports = function(deployer) {
|
|
||||||
deployer.deploy(Operator).then(function(operator) {
|
|
||||||
console.log('Registry address: ', Registry.address);
|
|
||||||
console.log('Operator address: ', Operator.address);
|
|
||||||
Registry.deployed().then(function(registry) {
|
|
||||||
registry.addVersion('Operator', Operator.address);
|
|
||||||
registry.createProxy('Operator', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
❤️