commit
f40cc1d8ff
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
build
|
||||
flattened_contracts
|
||||
node_modules
|
||||
**/node_modules
|
||||
.ganache-db
|
||||
.tm_properties
|
||||
|
193
README.md
193
README.md
@ -2,92 +2,82 @@
|
||||
|
||||
# Kredits Contracts
|
||||
|
||||
This repository contains the Solidity smart contracts and JavaScript API
|
||||
wrapper for [Kosmos Kredits](https://wiki.kosmos.org/Kredits).
|
||||
This repository contains the Solidity smart contracts organized as [Aragon](https://hack.aragon.org/)
|
||||
apps and JavaScript API wrapper for [Kosmos Kredits](https://wiki.kosmos.org/Kredits).
|
||||
|
||||
It uses the [Truffle framework](http://truffleframework.com/) for some things.
|
||||
It is based on [aragonOS](https://hack.aragon.org/docs/aragonos-intro.html) and
|
||||
follows the aragonOS conventions.
|
||||
Aragon itself uses the [Truffle framework](http://truffleframework.com/) for some things.
|
||||
|
||||
## Development
|
||||
|
||||
### Installation
|
||||
|
||||
$ npm install
|
||||
|
||||
### Requirements
|
||||
|
||||
All requirements are defined in `package.json`.
|
||||
|
||||
Those can be installed globally for convenience:
|
||||
$ npm install
|
||||
|
||||
* [truffle framework](http://truffleframework.com): `npm install -g truffle`
|
||||
* [ganache](http://truffleframework.com/ganache): `npm install -g ganache-cli`
|
||||
Each of the aragon apps are separate packages:
|
||||
|
||||
We use following solidity contract libraries:
|
||||
$ cd apps/[app]
|
||||
$ npm install
|
||||
|
||||
* [Open Zeppelin](https://github.com/OpenZeppelin/zeppelin-solidity)
|
||||
or use the bootstrap command (see below)
|
||||
|
||||
### Local development chain
|
||||
|
||||
For local development it is recommended to use
|
||||
[ganache-cli](https://github.com/trufflesuite/ganache-cli) (or the [ganache
|
||||
GUI](http://truffleframework.com/ganache/) to run a local development chain.
|
||||
Using the ganache simulator no full Ethereum node is required.
|
||||
[ganache](http://truffleframework.com/ganache/) to run a local development
|
||||
chain. 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
|
||||
RPC port.
|
||||
* network ID 100 to stay on the same network id
|
||||
* store ganache data in .ganache-db to presist the chain data across restarts
|
||||
* use a fixed Mnemonic code to get the same accounts across restarts
|
||||
$ npm run devchain (or aragon devchain --port 7545)
|
||||
|
||||
Have a look at `ganache-cli` for more configuration options.
|
||||
To clear/reset the chain use:
|
||||
|
||||
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
|
||||
look at the [documentation
|
||||
here](http://truffleframework.com/docs/getting_started/console)
|
||||
1. Run an Ethereum node and ipfs
|
||||
|
||||
NOTE: There are promisses, have a look at the examples:
|
||||
$ npm run devchain
|
||||
$ ipfs daemon
|
||||
|
||||
```javascript
|
||||
Token.deployed().then(function(token) {
|
||||
token.totalSupply.call().then(function(value) {
|
||||
console.log(value.toString());
|
||||
})
|
||||
});
|
||||
```
|
||||
2. Deploy each app to the devchain
|
||||
|
||||
Also please be aware of the differences between web3.js 0.2x.x and
|
||||
[1.x.x](https://web3js.readthedocs.io/en/1.0/) - [web3
|
||||
repo](https://github.com/ethereum/web3.js/)
|
||||
$ npm run deploy:apps
|
||||
|
||||
## 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
|
||||
look at the `migrations` folder for those. The Ethereum nodes for the
|
||||
different networks need to be configured in `truffle.js`.
|
||||
$ npm run deploy:kit
|
||||
$ npm run deploy:dao
|
||||
|
||||
Run the truffle migration scripts:
|
||||
4. Execute seeds to create demo contributors, contributons, etc. (optional)
|
||||
|
||||
$ truffle deploy
|
||||
$ truffle deploy --network=<network config from truffle.js>
|
||||
$ npm run seeds
|
||||
|
||||
Truffle keeps track of already executed migration scripts. To reset the
|
||||
migration use the `--reset` option
|
||||
**Step 2-4 is also summarized in `npm run bootstrap`**
|
||||
|
||||
$ truffle migrate --reset
|
||||
## Contract architecture
|
||||
|
||||
Migration scripts can also be run from within `truffle console` or `truffle
|
||||
develop`
|
||||
Contracts are organized in independent apps (see `/apps`) and are developed
|
||||
and deployed independently. Each app has a version and can be "installed"
|
||||
on the Kredits DAO independently.
|
||||
|
||||
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
|
||||
|
||||
@ -110,18 +100,17 @@ instance.
|
||||
|
||||
$ truffle exec scripts/repl.js
|
||||
|
||||
### add-contributor.js
|
||||
### add-{contributor, contribution, proposal}.js
|
||||
|
||||
Adds a new core contributor, creates a proposal for the new contributor and
|
||||
votes for that one.
|
||||
Script to add a new entries to the contracts using the JS wrapper
|
||||
|
||||
$ truffle exec scripts/add-contributor.js
|
||||
$ truffle exec scripts/add-{contributor, contribution, proposal}.js
|
||||
|
||||
### add-proposal.js
|
||||
### list-{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
|
||||
|
||||
@ -131,48 +120,70 @@ metamask account.
|
||||
$ truffle exec scripts/send-funds.js
|
||||
|
||||
### seeds.js
|
||||
|
||||
Run seeds defined in `config/seeds.js`.
|
||||
|
||||
$ truffle exec scripts/seeds.js
|
||||
or
|
||||
$ npm run seeds
|
||||
|
||||
### current-address.js
|
||||
|
||||
Prints all known DAO addresses and the DAO address for the current network
|
||||
|
||||
$ truffle exec scripts/current-address.js
|
||||
or
|
||||
$ npm run dao:address
|
||||
|
||||
### deploy-kit.js
|
||||
|
||||
Deploys a new KreditsKit that allows to create a new DAO
|
||||
|
||||
$ truffle exec script/deploy-kit.js
|
||||
or
|
||||
$ npm run deploy:kit
|
||||
|
||||
`ENS` address is required as environment variable.
|
||||
`DAO_FACTORY` can optionally be set as environment variable. (see aragon)
|
||||
|
||||
### new-dao.js
|
||||
|
||||
Creates and configures a new DAO instance.
|
||||
|
||||
$ truffle exec script/new-dao.js
|
||||
or
|
||||
$ npm run deploy:dao
|
||||
|
||||
KreditsKit address is 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
|
||||
|
||||
Some of the contracts use upgradability ideas from
|
||||
[zeppelinos](https://github.com/zeppelinos/labs) (see `contracts/upgradable`).
|
||||
|
||||
The basic idea is to have a Registry contract that knows about the current
|
||||
implementations and a Proxy contract that uses `delegatecall` to call the
|
||||
current implementation. That means the Proxy contract holds the storage and
|
||||
the address of that one does not change but the actuall implemenation is
|
||||
managed through the Registry.
|
||||
|
||||
To deploy a new version a new contract is deployed then the version is
|
||||
registered (`addVersion()`) in the Registry and on the Proxy contract is
|
||||
"upgraded" (`upgrade()`) to the new version.
|
||||
|
||||
The Registry knows about all the different contracts and implementations.
|
||||
Versions are stored as uint and automatically incremented for every added
|
||||
implementation.
|
||||
We use aragonOS for upgradeablity of the different contracts.
|
||||
Refer to the [aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro)
|
||||
for more details.
|
||||
|
||||
### Example
|
||||
|
||||
Deployment is best done using the truffle deployer.
|
||||
|
||||
1. Setup
|
||||
1. Deploy the Registry
|
||||
2. Deploy the contract
|
||||
3. Register the contract at the Registry:
|
||||
`registry.addVersion('Token', Token.address)`
|
||||
4. Create the Proxy:
|
||||
`registry.createProxy('Token', 1)`
|
||||
1. Setup (see #Bootstrap)
|
||||
1. Deploy each contract/apps (see `/apps/*`)
|
||||
2. Create a new DAO (see scripts/deploy-kit.js)
|
||||
2. Update
|
||||
1. Deploy a new Version of the contract
|
||||
2. Register the new version at the Registry:
|
||||
`registry.addVersion('Token', NewToken.address)`
|
||||
3. Set the new implementation address on the Proxy contract:
|
||||
`registry.upgrade('Token', 2)`
|
||||
1. Deploy a new Version of the contract/app (see `/apps/*`)
|
||||
2. Use the `aragon dao upgrade` command to "install" the new version for the DAO
|
||||
(`aragon dao upgrade <DAO address> <app name>`)
|
||||
|
||||
## Known Issues
|
||||
|
||||
|
4
apps/contribution/.gitignore
vendored
Normal file
4
apps/contribution/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
14
apps/contribution/.ipfsignore
Normal file
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
1
apps/contribution/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Kredits Contribution
|
38
apps/contribution/arapp.json
Normal file
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
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 {
|
||||
address public owner;
|
||||
@ -8,7 +8,7 @@ contract Migrations {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() public {
|
||||
constructor() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
4
apps/contribution/manifest.json
Normal file
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
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
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
13977
apps/contribution/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
apps/contribution/package.json
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
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
1
apps/contribution/truffle.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require("../../truffle.js");
|
4
apps/contributor/.gitignore
vendored
Normal file
4
apps/contributor/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
14
apps/contributor/.ipfsignore
Normal file
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
1
apps/contributor/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Kredits Contributor
|
28
apps/contributor/arapp.json
Normal file
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 'zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol';
|
||||
import './upgradeable/Upgradeable.sol';
|
||||
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||
|
||||
contract Contributors is Upgradeable {
|
||||
contract Contributor is AragonApp {
|
||||
bytes32 public constant MANAGE_CONTRIBUTORS_ROLE = keccak256("MANAGE_CONTRIBUTORS_ROLE");
|
||||
|
||||
struct Contributor {
|
||||
address account;
|
||||
@ -19,24 +18,26 @@ contract Contributors is Upgradeable {
|
||||
mapping (uint => Contributor) public contributors;
|
||||
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 ContributorAccountUpdated(uint id, address oldAccount, address newAccount);
|
||||
event ContributorAdded(uint id, address account);
|
||||
|
||||
modifier onlyCoreOrOperator() {
|
||||
require(msg.sender == registry.getProxyFor('Operator') || addressIsCore(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(address sender) public payable {
|
||||
require(msg.sender == address(registry));
|
||||
uint _id = 1;
|
||||
function initialize(address root,bytes32[4] _appIds) public onlyInit {
|
||||
uint _id = contributorsCount + 1;
|
||||
Contributor storage c = contributors[_id];
|
||||
c.exists = true;
|
||||
c.isCore = true;
|
||||
c.account = sender;
|
||||
contributorIds[sender] = _id;
|
||||
c.account = root;
|
||||
contributorIds[root] = _id;
|
||||
contributorsCount += 1;
|
||||
|
||||
appIds = _appIds;
|
||||
|
||||
initialized();
|
||||
}
|
||||
|
||||
function coreContributorsCount() view public returns (uint) {
|
||||
@ -49,14 +50,14 @@ contract Contributors is Upgradeable {
|
||||
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[newAccount] = id;
|
||||
contributors[id].account = 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];
|
||||
bytes32 oldIpfsHash = c.ipfsHash;
|
||||
c.ipfsHash = ipfsHash;
|
||||
@ -66,7 +67,7 @@ contract Contributors is Upgradeable {
|
||||
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));
|
||||
uint _id = contributorsCount + 1;
|
||||
assert(!contributors[_id].exists); // this can not be acually
|
||||
@ -80,7 +81,7 @@ contract Contributors is Upgradeable {
|
||||
contributorIds[account] = _id;
|
||||
|
||||
contributorsCount += 1;
|
||||
ContributorAdded(_id, account);
|
||||
emit ContributorAdded(_id, account);
|
||||
}
|
||||
|
||||
function isCore(uint id) view public returns (bool) {
|
||||
@ -112,7 +113,7 @@ contract Contributors is Upgradeable {
|
||||
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;
|
||||
Contributor storage c = contributors[_id];
|
||||
account = c.account;
|
||||
@ -121,8 +122,9 @@ contract Contributors is Upgradeable {
|
||||
hashSize = c.hashSize;
|
||||
isCore = c.isCore;
|
||||
exists = c.exists;
|
||||
}
|
||||
|
||||
ERC20Basic token = ERC20Basic(registry.getProxyFor('Token'));
|
||||
balance = token.balanceOf(account);
|
||||
function canPerform(address _who, address _where, bytes32 _what, uint256[] _how) public view returns (bool) {
|
||||
return addressExists(_who);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
@ -8,7 +8,7 @@ contract Migrations {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() public {
|
||||
constructor() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
4
apps/contributor/manifest.json
Normal file
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
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
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
13977
apps/contributor/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
apps/contributor/package.json
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
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
1
apps/contributor/truffle.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require("../../truffle.js");
|
1
apps/proposal/README.md
Normal file
1
apps/proposal/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Kredits Proposal
|
33
apps/proposal/arapp.json
Normal file
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
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
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
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
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
13977
apps/proposal/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
apps/proposal/package.json
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
1
apps/proposal/truffle.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require("../../truffle.js");
|
4
apps/token/.gitignore
vendored
Normal file
4
apps/token/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
14
apps/token/.ipfsignore
Normal file
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
1
apps/token/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Kredits Token
|
28
apps/token/arapp.json
Normal file
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
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
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
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
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
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
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
13977
apps/token/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
apps/token/package.json
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
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
1
apps/token/truffle.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require("../../truffle.js");
|
60
arapp.json
Normal file
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 = [
|
||||
['Contributor', 'add', [{ account: '0x7e8f313c56f809188313aa274fa67ee58c31515d', name: 'bumi', isCore: true, kind: 'preson', url: '', github_username: 'bumi', github_uid: 318, wiki_username: 'bumi' }, {gasLimit: 200000}]],
|
||||
['Contributor', 'add', [{ account: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', name: 'raucau', isCore: true, kind: 'person', url: '', github_username: 'skddc', github_uid: 842, wiki_username: 'raucau' }, {gasLimit: 200000}]],
|
||||
['Operator', 'addProposal', [{ contributorId: 2, amount: 42, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
|
||||
['Operator', 'addProposal', [{ contributorId: 3, amount: 23, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
|
||||
['Operator', 'addProposal', [{contributorId: 3, amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
|
||||
['Operator', 'vote', ['1', {gasLimit: 250000}]]
|
||||
['Proposal', 'addProposal', [{ contributorId: 2, amount: 42, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
|
||||
['Proposal', 'addProposal', [{ contributorId: 3, amount: 23, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
|
||||
['Proposal', 'addProposal', [{contributorId: 3, amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
|
||||
['Proposal', 'vote', [1, {gasLimit: 550000}]],
|
||||
['Contribution', 'addContribution', [{contributorAccount: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
|
||||
];
|
||||
let funds = [
|
||||
'0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
||||
|
87
contracts/KreditsKit.sol
Normal file
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
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
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
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
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
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
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
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
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
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
BIN
docs/kredits-diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
1
lib/abis/ACL.json
Normal file
1
lib/abis/ACL.json
Normal file
File diff suppressed because one or more lines are too long
1
lib/abis/Contribution.json
Normal file
1
lib/abis/Contribution.json
Normal file
File diff suppressed because one or more lines are too long
1
lib/abis/Contributor.json
Normal file
1
lib/abis/Contributor.json
Normal file
File diff suppressed because one or more lines are too long
@ -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
lib/abis/Kernel.json
Normal file
File diff suppressed because one or more lines are too long
@ -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
lib/abis/Proposal.json
Normal file
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"currentVersions","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"name":"versions","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"proxy","type":"address"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"},{"indexed":false,"name":"implementation","type":"address"}],"name":"VersionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"}],"name":"ProxyImplementationUpgraded","type":"event"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"implementation","type":"address"}],"name":"addVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"getVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getLatestVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getProxyFor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"upgradeToLatest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"createProxy","outputs":[{"name":"","type":"address"}],"payable":true,"stateMutability":"payable","type":"function"}]
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"}
|
4
lib/addresses/KreditsKit.json
Normal file
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
4
lib/addresses/dao.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"4": "0x95a7ce185efc2d1f13efd2a00ee9247c51ea7009",
|
||||
"41787949": "0x183af3950364390a266edff2a0e7c4c2f95c0691"
|
||||
}
|
13
lib/contracts/acl.js
Normal file
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) {
|
||||
let eventMethod = `on${type.toLowerCase()}`;
|
||||
// Don't use this.contract.events here. Seems to be a bug in ethers.js
|
||||
this.contract[eventMethod] = callback;
|
||||
|
||||
return this;
|
||||
return this.contract.on(type, callback);
|
||||
}
|
||||
}
|
||||
module.exports = Base;
|
||||
|
70
lib/contracts/contribution.js
Normal file
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 = {
|
||||
Contributors: require('./contributor'),
|
||||
Operator: require('./operator'),
|
||||
Contributor: require('./contributor'),
|
||||
Contribution: require('./contribution'),
|
||||
Proposal: require('./proposal'),
|
||||
Token: require('./token'),
|
||||
Registry: require('./registry')
|
||||
Kernel: require('./kernel'),
|
||||
Acl: require('./acl')
|
||||
};
|
||||
|
24
lib/contracts/kernel.js
Normal file
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 Base = require('./base');
|
||||
|
||||
class Operator extends Base {
|
||||
class Proposal extends Base {
|
||||
all() {
|
||||
return this.functions.proposalsCount()
|
||||
.then((count) => {
|
||||
@ -23,12 +23,6 @@ class Operator extends Base {
|
||||
id = ethers.utils.bigNumberify(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) => {
|
||||
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 ABIS = {
|
||||
Contributors: require('./abis/Contributors.json'),
|
||||
Operator: require('./abis/Operator.json'),
|
||||
Registry: require('./abis/Registry.json'),
|
||||
Token: require('./abis/Token.json')
|
||||
Contributor: require('./abis/Contributor.json'),
|
||||
Contribution: require('./abis/Contribution.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 IPFS = require('./utils/ipfs')
|
||||
@ -27,26 +36,29 @@ class Kredits {
|
||||
|
||||
this.provider = provider;
|
||||
this.signer = signer;
|
||||
// by default we only need the registry address.
|
||||
// the rest is loaded from there in the init() function
|
||||
this.addresses = addresses || { Registry: RegistryAddress[this.provider.chainId.toString()] }; // chainID must be a string
|
||||
this.options = options;
|
||||
this.addresses = addresses || {};
|
||||
this.abis = abis || ABIS;
|
||||
this.ipfs = new IPFS(ipfsConfig);
|
||||
this.contracts = {};
|
||||
}
|
||||
|
||||
init(names) {
|
||||
let contractsToLoad = names || Object.keys(ABIS);
|
||||
let addressPromises = contractsToLoad.map((contractName) => {
|
||||
return this.Registry.functions.getProxyFor(contractName).then((address) => {
|
||||
this.addresses[contractName] = address;
|
||||
}).catch((error) => {
|
||||
throw new Error(`Failed to get address for ${contractName} from registry at ${this.Registry.contract.address}
|
||||
- correct registry? does it have version entry? - ${error.message}`
|
||||
);
|
||||
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) => {
|
||||
return this.Kernel.getApp(contractName).then((address) => {
|
||||
this.addresses[contractName] = address;
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
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 });
|
||||
}
|
||||
|
||||
static setup(provider, signer, ipfsConfig = null) {
|
||||
@ -54,13 +66,17 @@ class Kredits {
|
||||
return new Kredits(provider, signer, { ipfsConfig: ipfsConfig }).init();
|
||||
}
|
||||
|
||||
get Registry() {
|
||||
return this.contractFor('registry');
|
||||
get Kernel() {
|
||||
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() {
|
||||
// TODO: rename to contributor
|
||||
return this.contractFor('contributors');
|
||||
return this.contractFor('Contributor');
|
||||
}
|
||||
|
||||
get Contributors() {
|
||||
@ -68,12 +84,24 @@ class Kredits {
|
||||
return this.Contributor;
|
||||
}
|
||||
|
||||
get Proposal() {
|
||||
return this.contractFor('Proposal');
|
||||
}
|
||||
|
||||
get Operator() {
|
||||
return this.contractFor('operator');
|
||||
return this.Proposal;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
};
|
14849
package-lock.json
generated
14849
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user