Build on aragonOS #62
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
build
|
||||
flattened_contracts
|
||||
node_modules
|
||||
**/node_modules
|
||||
.ganache-db
|
||||
.tm_properties
|
||||
|
||||
4
apps/contribution/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
14
apps/contribution/.ipfsignore
Normal file
@ -0,0 +1,14 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
162
apps/contribution/README.md
Normal file
@ -0,0 +1,162 @@
|
||||
# Aragon React Boilerplate
|
||||
|
||||
> 🕵️ [Find more boilerplates using GitHub](https://github.com/search?q=topic:aragon-boilerplate) |
|
||||
> ✨ [Official boilerplates](https://github.com/search?q=topic:aragon-boilerplate+org:aragon)
|
||||
|
||||
React boilerplate for Aragon applications.
|
||||
|
||||
This boilerplate also includes a fully working example app, complete with a background worker and a front-end in React (with Aragon UI).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
aragon init app.aragonpm.eth react
|
||||
```
|
||||
|
||||
## Running your app
|
||||
|
||||
### Using HTTP
|
||||
|
||||
Running your app using HTTP will allow for a faster development process of your app's front-end, as it can be hot-reloaded without the need to execute `aragon run` every time a change is made.
|
||||
|
||||
- First start your app's development server running `npm run start:app`, and keep that process running. By default it will rebuild the app and reload the server when changes to the source are made.
|
||||
|
||||
- After that, you can run `npm run start:aragon:http` which will compile your app's contracts, publish the app locally and create a DAO. You will need to stop it and run it again after making changes to your smart contracts.
|
||||
|
||||
Changes to the app's background script (`app/script.js`) cannot be hot-reloaded, after making changes to the script, you will need to either restart the development server (`npm run start:app`) or rebuild the script `npm run build:script`.
|
||||
|
||||
### Using IPFS
|
||||
|
||||
Running your app using IPFS will mimic the production environment that will be used for running your app. `npm run start:aragon:ipfs` will run your app using IPFS. Whenever a change is made to any file in your front-end, a new version of the app needs to be published, so the command needs to be restarted.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
### npm Scripts
|
||||
|
||||
- **start** or **start:aragon:ipfs**: Runs your app inside a DAO served from IPFS
|
||||
- **start:aragon:http**: Runs your app inside a DAO served with HTTP (hot reloading)
|
||||
- **start:app**: Starts a development server for your app
|
||||
- **compile**: Compile the smart contracts
|
||||
- **build**: Builds the front-end and background script
|
||||
- **build:app**: Builds the front-end
|
||||
- **build:script**: Builds the background script
|
||||
- **test**: Runs tests for the contracts
|
||||
- **publish:patch**: Release a patch version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:minor**: Release a minor version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:major**: Release a major version to aragonPM (frontend **and** contract changes)
|
||||
- **versions**: Check the currently installed versions of the app
|
||||
|
||||
### Libraries
|
||||
|
||||
- [**@aragon/os**](https://github.com/aragon/aragonos): Aragon interfaces
|
||||
- [**@aragon/client**](https://github.com/aragon/aragon.js/tree/master/packages/aragon-client): Wrapper for Aragon application RPC
|
||||
- [**@aragon/ui**](https://github.com/aragon/aragon-ui): Aragon UI components (in React)
|
||||
|
||||
## Publish
|
||||
|
||||
This app has 3 environments defined in `arapp.json`:
|
||||
|
||||
| Environment | Network |
|
||||
|--- |--- |
|
||||
| default | localhost |
|
||||
| staging | rinkeby |
|
||||
| production | mainnet |
|
||||
|
||||
Prerequisites:
|
||||
- ENS Registry address
|
||||
|
||||
Note: the `default` environment which points to `localhost` does not have an ENS Registry address specified because the `@aragon/cli` will default the value to `0xB9462EF3441346dBc6E49236Edbb0dF207db09B7` (the ENS Registry pre-deployed on the local development chain).
|
||||
|
||||
### Introduction to environments
|
||||
|
||||
Environments are defined in `arapp.json`, for example `staging` points to:
|
||||
- an ENS registry (`0x314159265dd8dbb310642f98f50c066173c1259b`)
|
||||
- an APM registry (`open.aragonpm.eth`)
|
||||
- an APM repository (`app`)
|
||||
- an Ethereum network (`rinkeby`)
|
||||
- an Ethereum websockets provider (`wss://rinkeby.eth.aragon.network/ws` - to **read** from the blockchain)
|
||||
|
||||
The `rinkeby` network is further defined in `truffle.js`, and has:
|
||||
- an Ethereum provider (to **write** to the blockchain):
|
||||
- an address (`https://rinkeby.infura.io`)
|
||||
- an Ethereum Account (`0xb4124cEB3451635DAcedd11767f004d8a28c6eE7`)
|
||||
(which is the first account generated from the `DEFAULT_MNEMONIC` variable, to use a different account see [here](#Using-a-different-Ethereum-account))
|
||||
|
||||
### Major version: content + contract
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:major -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (the output lives in `dist`)
|
||||
2. _compile_ the app's contract (the output lives in `build`)
|
||||
3. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
> aragon apm publish major "--environment" "staging"
|
||||
|
||||
✔ Successfully published app.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
ℹ Transaction hash: 0x3d752db29cc106e9ff98b260a90615921eb32471425a29ead8cbb830fb224d8
|
||||
```
|
||||
|
||||
Note: the contract location is defined in `arapp.json` under `path`.
|
||||
Note: you can also deploy a major version with only frontend changes by passing `--only-content`.
|
||||
|
||||
### Minor/patch version: content only
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:patch -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (which lives in `dist`)
|
||||
2. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
✔ Successfully published app.open.aragonpm.eth v1.1.1:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
ℹ Transaction hash: 0x57864d8efd8d439008621b494b19a3e8f876a8a46b38475f9626802f0a1403c2
|
||||
```
|
||||
|
||||
### Check published versions
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run versions -- --environment staging
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
ℹ app.open.aragonpm.eth has 4 published versions
|
||||
✔ 1.0.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
✔ 1.1.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmSwjUZFpv2c2e9fLoxtgFrAsAmBN4DyQGJp4RcqQcW3z3
|
||||
✔ 1.1.1: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
✔ 2.0.0: 0x74CBbbC932d7C344FCd789Eba24BfD40e52980c9 ipfs:Qmadb3hzwLDKtb93fF367Vg1epkdsLZF4dhpapNYynjgZF
|
||||
```
|
||||
|
||||
### Using a different Ethereum account
|
||||
|
||||
To deploy from a different account, you can:
|
||||
- define a `~/.aragon/mnemonic.json` file
|
||||
```
|
||||
{
|
||||
"mnemonic": "explain tackle mirror kit ..."
|
||||
}
|
||||
```
|
||||
or
|
||||
- define a `~/.aragon/${network_name}_key.json` file, for example: `~/.aragon/rinkeby_key.json`
|
||||
```
|
||||
{
|
||||
"keys": [
|
||||
"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563"
|
||||
]
|
||||
}
|
||||
```
|
||||
33
apps/contribution/arapp.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"roles": [
|
||||
{
|
||||
"name": "Add contributions",
|
||||
"id": "ADD_CONTRIBUTION_ROLE",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"name": "Manage token contract",
|
||||
"id": "MANAGE_TOKEN_CONTRACT_ROLE",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"environments": {
|
||||
"default": {
|
||||
"network": "development",
|
||||
"appName": "contribution.aragonpm.eth"
|
||||
},
|
||||
"staging": {
|
||||
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
|
||||
"appName": "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"
|
||||
}
|
||||
139
apps/contribution/contracts/Contribution.sol
Normal file
@ -0,0 +1,139 @@
|
||||
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 proposalId) external;
|
||||
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 KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
||||
bytes32 public constant TOKEN_APP_ID = 0xe04a882e7a6adf5603207d545ea49aec17e6b936c4d9eae3d74dbe482264991a;
|
||||
|
||||
struct ContributionData {
|
||||
address contributor;
|
||||
uint256 amount;
|
||||
bool claimed;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
string tokenMetadataURL;
|
||||
uint claimAfterBlock;
|
||||
bool exists;
|
||||
}
|
||||
string internal name_;
|
||||
string internal symbol_;
|
||||
|
||||
address public tokenContract;
|
||||
|
||||
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);
|
||||
|
||||
function initialize() public onlyInit {
|
||||
initialized();
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
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 claim(uint256 contributionId) public isInitialized {
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
require(c.exists, 'NOT_FOUND');
|
||||
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||
require(block.number > c.claimAfterBlock, 'NOT_CLAIMABLE');
|
||||
//c.claimed = true;
|
||||
//IToken(getTokenContract()).mintFor(c.contributor, c.amount, contributionId); // somehow this does not work
|
||||
bytes4 sig = bytes4(keccak256("mintFor()"));
|
||||
address token = getTokenContract();
|
||||
//IToken token = IToken(getTokenContract());
|
||||
|
||||
//token.call(sig);
|
||||
//IToken(token).mintFor(c.contributor, c.amount, contributionId);
|
||||
IToken(token).mintFor(c.contributor, c.amount, contributionId);
|
||||
|
||||
//emit ContributionClaimed(contributionId, c.contributor, c.amount);
|
||||
}
|
||||
|
||||
function getTokenContract() public view returns (address) {
|
||||
return 0x8779fc70eeea01d00efa9044c29d3c930fdb874a;
|
||||
//IKernel k = IKernel(kernel());
|
||||
|
||||
//return k.getApp(KERNEL_APP_ADDR_NAMESPACE, TOKEN_APP_ID);
|
||||
}
|
||||
|
||||
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.4;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
@ -8,15 +8,15 @@ contract Migrations {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() public {
|
||||
function Migrations() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) public restricted {
|
||||
function setCompleted(uint completed) restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) public restricted {
|
||||
function upgrade(address new_address) restricted {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
4
apps/contribution/manifest.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Contribution",
|
||||
"description": "Kredits contribution app"
|
||||
}
|
||||
5
apps/contribution/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
5
apps/contribution/migrations/2_deploy_contracts.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Contribution = artifacts.require('Contribution.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Contribution)
|
||||
}
|
||||
21093
apps/contribution/package-lock.json
generated
Normal file
28
apps/contribution/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "app-name",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@aragon/os": "^4.1.0",
|
||||
"@aragon/cli": "^5.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
},
|
||||
"scripts": {
|
||||
"start": "npm run start:aragon:ipfs",
|
||||
"start:aragon:ipfs": "aragon run",
|
||||
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
|
||||
"start:app": "npm run sync-assets && npm run build:script -- --no-minify && parcel serve app/index.html -p 8001 --out-dir dist/ --no-cache",
|
||||
"test": "aragon contracts test",
|
||||
"compile": "aragon contracts compile",
|
||||
"sync-assets": "copy-aragon-ui-assets -n aragon-ui ./dist",
|
||||
"build:app": "",
|
||||
"build:script": "",
|
||||
"build": "",
|
||||
"publish:patch": "aragon apm publish patch",
|
||||
"publish:minor": "aragon apm publish minor",
|
||||
"publish:major": "aragon apm publish major",
|
||||
"versions": "aragon apm versions"
|
||||
},
|
||||
"keywords": []
|
||||
}
|
||||
5
apps/contribution/test/app.js
Normal file
@ -0,0 +1,5 @@
|
||||
const CounterApp = artifacts.require('Contribution.sol')
|
||||
|
||||
contract('Contribution', (accounts) => {
|
||||
it('should be tested')
|
||||
})
|
||||
63
apps/contribution/truffle.js
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* https://github.com/aragon/aragonOS/blob/v4.0.0/truffle-config.js
|
||||
*/
|
||||
const homedir = require('homedir')
|
||||
const path = require('path')
|
||||
|
||||
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||
const HDWalletProviderPrivkey = require('truffle-hdwallet-provider-privkey')
|
||||
|
||||
const DEFAULT_MNEMONIC = 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus'
|
||||
|
||||
const defaultRPC = (network) =>
|
||||
`https://${network}.infura.io`
|
||||
|
||||
const configFilePath = (filename) =>
|
||||
path.join(homedir(), `.aragon/${filename}`)
|
||||
|
||||
const mnemonic = () => {
|
||||
try {
|
||||
return require(configFilePath('mnemonic.json')).mnemonic
|
||||
} catch (e) {
|
||||
return DEFAULT_MNEMONIC
|
||||
}
|
||||
}
|
||||
|
||||
const settingsForNetwork = (network) => {
|
||||
try {
|
||||
return require(configFilePath(`${network}_key.json`))
|
||||
} catch (e) {
|
||||
return { }
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily loaded provider
|
||||
const providerForNetwork = (network) => (
|
||||
() => {
|
||||
let { rpc, keys } = settingsForNetwork(network)
|
||||
rpc = rpc || defaultRPC(network)
|
||||
|
||||
if (!keys || keys.length == 0) {
|
||||
return new HDWalletProvider(mnemonic(), rpc)
|
||||
}
|
||||
|
||||
return new HDWalletProviderPrivkey(keys, rpc)
|
||||
}
|
||||
)
|
||||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: '*'
|
||||
},
|
||||
mainnet: {
|
||||
network_id: 1,
|
||||
provider: providerForNetwork('mainnet')
|
||||
},
|
||||
rinkeby: {
|
||||
network_id: 4,
|
||||
provider: providerForNetwork('rinkeby')
|
||||
}
|
||||
}
|
||||
}
|
||||
4
apps/contributor/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
14
apps/contributor/.ipfsignore
Normal file
@ -0,0 +1,14 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
162
apps/contributor/README.md
Normal file
@ -0,0 +1,162 @@
|
||||
# Aragon React Boilerplate
|
||||
|
||||
> 🕵️ [Find more boilerplates using GitHub](https://github.com/search?q=topic:aragon-boilerplate) |
|
||||
> ✨ [Official boilerplates](https://github.com/search?q=topic:aragon-boilerplate+org:aragon)
|
||||
|
||||
React boilerplate for Aragon applications.
|
||||
|
||||
This boilerplate also includes a fully working example app, complete with a background worker and a front-end in React (with Aragon UI).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
aragon init app.aragonpm.eth react
|
||||
```
|
||||
|
||||
## Running your app
|
||||
|
||||
### Using HTTP
|
||||
|
||||
Running your app using HTTP will allow for a faster development process of your app's front-end, as it can be hot-reloaded without the need to execute `aragon run` every time a change is made.
|
||||
|
||||
- First start your app's development server running `npm run start:app`, and keep that process running. By default it will rebuild the app and reload the server when changes to the source are made.
|
||||
|
||||
- After that, you can run `npm run start:aragon:http` which will compile your app's contracts, publish the app locally and create a DAO. You will need to stop it and run it again after making changes to your smart contracts.
|
||||
|
||||
Changes to the app's background script (`app/script.js`) cannot be hot-reloaded, after making changes to the script, you will need to either restart the development server (`npm run start:app`) or rebuild the script `npm run build:script`.
|
||||
|
||||
### Using IPFS
|
||||
|
||||
Running your app using IPFS will mimic the production environment that will be used for running your app. `npm run start:aragon:ipfs` will run your app using IPFS. Whenever a change is made to any file in your front-end, a new version of the app needs to be published, so the command needs to be restarted.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
### npm Scripts
|
||||
|
||||
- **start** or **start:aragon:ipfs**: Runs your app inside a DAO served from IPFS
|
||||
- **start:aragon:http**: Runs your app inside a DAO served with HTTP (hot reloading)
|
||||
- **start:app**: Starts a development server for your app
|
||||
- **compile**: Compile the smart contracts
|
||||
- **build**: Builds the front-end and background script
|
||||
- **build:app**: Builds the front-end
|
||||
- **build:script**: Builds the background script
|
||||
- **test**: Runs tests for the contracts
|
||||
- **publish:patch**: Release a patch version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:minor**: Release a minor version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:major**: Release a major version to aragonPM (frontend **and** contract changes)
|
||||
- **versions**: Check the currently installed versions of the app
|
||||
|
||||
### Libraries
|
||||
|
||||
- [**@aragon/os**](https://github.com/aragon/aragonos): Aragon interfaces
|
||||
- [**@aragon/client**](https://github.com/aragon/aragon.js/tree/master/packages/aragon-client): Wrapper for Aragon application RPC
|
||||
- [**@aragon/ui**](https://github.com/aragon/aragon-ui): Aragon UI components (in React)
|
||||
|
||||
## Publish
|
||||
|
||||
This app has 3 environments defined in `arapp.json`:
|
||||
|
||||
| Environment | Network |
|
||||
|--- |--- |
|
||||
| default | localhost |
|
||||
| staging | rinkeby |
|
||||
| production | mainnet |
|
||||
|
||||
Prerequisites:
|
||||
- ENS Registry address
|
||||
|
||||
Note: the `default` environment which points to `localhost` does not have an ENS Registry address specified because the `@aragon/cli` will default the value to `0xB9462EF3441346dBc6E49236Edbb0dF207db09B7` (the ENS Registry pre-deployed on the local development chain).
|
||||
|
||||
### Introduction to environments
|
||||
|
||||
Environments are defined in `arapp.json`, for example `staging` points to:
|
||||
- an ENS registry (`0x314159265dd8dbb310642f98f50c066173c1259b`)
|
||||
- an APM registry (`open.aragonpm.eth`)
|
||||
- an APM repository (`app`)
|
||||
- an Ethereum network (`rinkeby`)
|
||||
- an Ethereum websockets provider (`wss://rinkeby.eth.aragon.network/ws` - to **read** from the blockchain)
|
||||
|
||||
The `rinkeby` network is further defined in `truffle.js`, and has:
|
||||
- an Ethereum provider (to **write** to the blockchain):
|
||||
- an address (`https://rinkeby.infura.io`)
|
||||
- an Ethereum Account (`0xb4124cEB3451635DAcedd11767f004d8a28c6eE7`)
|
||||
(which is the first account generated from the `DEFAULT_MNEMONIC` variable, to use a different account see [here](#Using-a-different-Ethereum-account))
|
||||
|
||||
### Major version: content + contract
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:major -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (the output lives in `dist`)
|
||||
2. _compile_ the app's contract (the output lives in `build`)
|
||||
3. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
> aragon apm publish major "--environment" "staging"
|
||||
|
||||
✔ Successfully published app.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
ℹ Transaction hash: 0x3d752db29cc106e9ff98b260a90615921eb32471425a29ead8cbb830fb224d8
|
||||
```
|
||||
|
||||
Note: the contract location is defined in `arapp.json` under `path`.
|
||||
Note: you can also deploy a major version with only frontend changes by passing `--only-content`.
|
||||
|
||||
### Minor/patch version: content only
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:patch -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (which lives in `dist`)
|
||||
2. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
✔ Successfully published app.open.aragonpm.eth v1.1.1:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
ℹ Transaction hash: 0x57864d8efd8d439008621b494b19a3e8f876a8a46b38475f9626802f0a1403c2
|
||||
```
|
||||
|
||||
### Check published versions
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run versions -- --environment staging
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
ℹ app.open.aragonpm.eth has 4 published versions
|
||||
✔ 1.0.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
✔ 1.1.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmSwjUZFpv2c2e9fLoxtgFrAsAmBN4DyQGJp4RcqQcW3z3
|
||||
✔ 1.1.1: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
✔ 2.0.0: 0x74CBbbC932d7C344FCd789Eba24BfD40e52980c9 ipfs:Qmadb3hzwLDKtb93fF367Vg1epkdsLZF4dhpapNYynjgZF
|
||||
```
|
||||
|
||||
### Using a different Ethereum account
|
||||
|
||||
To deploy from a different account, you can:
|
||||
- define a `~/.aragon/mnemonic.json` file
|
||||
```
|
||||
{
|
||||
"mnemonic": "explain tackle mirror kit ..."
|
||||
}
|
||||
```
|
||||
or
|
||||
- define a `~/.aragon/${network_name}_key.json` file, for example: `~/.aragon/rinkeby_key.json`
|
||||
```
|
||||
{
|
||||
"keys": [
|
||||
"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563"
|
||||
]
|
||||
}
|
||||
```
|
||||
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": "contributor.aragonpm.eth"
|
||||
},
|
||||
"staging": {
|
||||
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
|
||||
"appName": "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;
|
||||
@ -23,20 +22,16 @@ contract Contributors is Upgradeable {
|
||||
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) 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;
|
||||
|
||||
initialized();
|
||||
}
|
||||
|
||||
function coreContributorsCount() view public returns (uint) {
|
||||
@ -49,14 +44,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 +61,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 +75,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 +107,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 +116,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);
|
||||
}
|
||||
}
|
||||
23
apps/contributor/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 Migrations() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) restricted {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
}
|
||||
4
apps/contributor/manifest.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Contributor",
|
||||
"description": "Kredits Contributor app"
|
||||
}
|
||||
5
apps/contributor/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
5
apps/contributor/migrations/2_deploy_contracts.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Contributor = artifacts.require('Contributor.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Contributor)
|
||||
}
|
||||
13527
apps/contributor/package-lock.json
generated
Normal file
27
apps/contributor/package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "kredits-contributor",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@aragon/os": "^4.1.0",
|
||||
"@aragon/cli": "^5.5.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"start": "npm run start:aragon:ipfs",
|
||||
"start:aragon:ipfs": "aragon run",
|
||||
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
|
||||
"start:app": "",
|
||||
"test": "aragon contracts test",
|
||||
"compile": "aragon contracts compile",
|
||||
"sync-assets": "",
|
||||
"build:app": "",
|
||||
"build:script": "",
|
||||
"build": "",
|
||||
"publish:patch": "aragon apm publish patch",
|
||||
"publish:minor": "aragon apm publish minor",
|
||||
"publish:major": "aragon apm publish major",
|
||||
"versions": "aragon apm versions"
|
||||
},
|
||||
"keywords": []
|
||||
}
|
||||
5
apps/contributor/test/app.js
Normal file
@ -0,0 +1,5 @@
|
||||
const CounterApp = artifacts.require('CounterApp.sol')
|
||||
|
||||
contract('CounterApp', (accounts) => {
|
||||
it('should be tested')
|
||||
})
|
||||
63
apps/contributor/truffle.js
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* https://github.com/aragon/aragonOS/blob/v4.0.0/truffle-config.js
|
||||
*/
|
||||
const homedir = require('homedir')
|
||||
const path = require('path')
|
||||
|
||||
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||
const HDWalletProviderPrivkey = require('truffle-hdwallet-provider-privkey')
|
||||
|
||||
const DEFAULT_MNEMONIC = 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus'
|
||||
|
||||
const defaultRPC = (network) =>
|
||||
`https://${network}.infura.io`
|
||||
|
||||
const configFilePath = (filename) =>
|
||||
path.join(homedir(), `.aragon/${filename}`)
|
||||
|
||||
const mnemonic = () => {
|
||||
try {
|
||||
return require(configFilePath('mnemonic.json')).mnemonic
|
||||
} catch (e) {
|
||||
return DEFAULT_MNEMONIC
|
||||
}
|
||||
}
|
||||
|
||||
const settingsForNetwork = (network) => {
|
||||
try {
|
||||
return require(configFilePath(`${network}_key.json`))
|
||||
} catch (e) {
|
||||
return { }
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily loaded provider
|
||||
const providerForNetwork = (network) => (
|
||||
() => {
|
||||
let { rpc, keys } = settingsForNetwork(network)
|
||||
rpc = rpc || defaultRPC(network)
|
||||
|
||||
if (!keys || keys.length == 0) {
|
||||
return new HDWalletProvider(mnemonic(), rpc)
|
||||
}
|
||||
|
||||
return new HDWalletProviderPrivkey(keys, rpc)
|
||||
}
|
||||
)
|
||||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: '*'
|
||||
},
|
||||
mainnet: {
|
||||
network_id: 1,
|
||||
provider: providerForNetwork('mainnet')
|
||||
},
|
||||
rinkeby: {
|
||||
network_id: 4,
|
||||
provider: providerForNetwork('rinkeby')
|
||||
}
|
||||
}
|
||||
}
|
||||
162
apps/proposal/README.md
Normal file
@ -0,0 +1,162 @@
|
||||
# Aragon React Boilerplate
|
||||
|
||||
> 🕵️ [Find more boilerplates using GitHub](https://github.com/search?q=topic:aragon-boilerplate) |
|
||||
> ✨ [Official boilerplates](https://github.com/search?q=topic:aragon-boilerplate+org:aragon)
|
||||
|
||||
React boilerplate for Aragon applications.
|
||||
|
||||
This boilerplate also includes a fully working example app, complete with a background worker and a front-end in React (with Aragon UI).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
aragon init app.aragonpm.eth react
|
||||
```
|
||||
|
||||
## Running your app
|
||||
|
||||
### Using HTTP
|
||||
|
||||
Running your app using HTTP will allow for a faster development process of your app's front-end, as it can be hot-reloaded without the need to execute `aragon run` every time a change is made.
|
||||
|
||||
- First start your app's development server running `npm run start:app`, and keep that process running. By default it will rebuild the app and reload the server when changes to the source are made.
|
||||
|
||||
- After that, you can run `npm run start:aragon:http` which will compile your app's contracts, publish the app locally and create a DAO. You will need to stop it and run it again after making changes to your smart contracts.
|
||||
|
||||
Changes to the app's background script (`app/script.js`) cannot be hot-reloaded, after making changes to the script, you will need to either restart the development server (`npm run start:app`) or rebuild the script `npm run build:script`.
|
||||
|
||||
### Using IPFS
|
||||
|
||||
Running your app using IPFS will mimic the production environment that will be used for running your app. `npm run start:aragon:ipfs` will run your app using IPFS. Whenever a change is made to any file in your front-end, a new version of the app needs to be published, so the command needs to be restarted.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
### npm Scripts
|
||||
|
||||
- **start** or **start:aragon:ipfs**: Runs your app inside a DAO served from IPFS
|
||||
- **start:aragon:http**: Runs your app inside a DAO served with HTTP (hot reloading)
|
||||
- **start:app**: Starts a development server for your app
|
||||
- **compile**: Compile the smart contracts
|
||||
- **build**: Builds the front-end and background script
|
||||
- **build:app**: Builds the front-end
|
||||
- **build:script**: Builds the background script
|
||||
- **test**: Runs tests for the contracts
|
||||
- **publish:patch**: Release a patch version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:minor**: Release a minor version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:major**: Release a major version to aragonPM (frontend **and** contract changes)
|
||||
- **versions**: Check the currently installed versions of the app
|
||||
|
||||
### Libraries
|
||||
|
||||
- [**@aragon/os**](https://github.com/aragon/aragonos): Aragon interfaces
|
||||
- [**@aragon/client**](https://github.com/aragon/aragon.js/tree/master/packages/aragon-client): Wrapper for Aragon application RPC
|
||||
- [**@aragon/ui**](https://github.com/aragon/aragon-ui): Aragon UI components (in React)
|
||||
|
||||
## Publish
|
||||
|
||||
This app has 3 environments defined in `arapp.json`:
|
||||
|
||||
| Environment | Network |
|
||||
|--- |--- |
|
||||
| default | localhost |
|
||||
| staging | rinkeby |
|
||||
| production | mainnet |
|
||||
|
||||
Prerequisites:
|
||||
- ENS Registry address
|
||||
|
||||
Note: the `default` environment which points to `localhost` does not have an ENS Registry address specified because the `@aragon/cli` will default the value to `0xB9462EF3441346dBc6E49236Edbb0dF207db09B7` (the ENS Registry pre-deployed on the local development chain).
|
||||
|
||||
### Introduction to environments
|
||||
|
||||
Environments are defined in `arapp.json`, for example `staging` points to:
|
||||
- an ENS registry (`0x314159265dd8dbb310642f98f50c066173c1259b`)
|
||||
- an APM registry (`open.aragonpm.eth`)
|
||||
- an APM repository (`app`)
|
||||
- an Ethereum network (`rinkeby`)
|
||||
- an Ethereum websockets provider (`wss://rinkeby.eth.aragon.network/ws` - to **read** from the blockchain)
|
||||
|
||||
The `rinkeby` network is further defined in `truffle.js`, and has:
|
||||
- an Ethereum provider (to **write** to the blockchain):
|
||||
- an address (`https://rinkeby.infura.io`)
|
||||
- an Ethereum Account (`0xb4124cEB3451635DAcedd11767f004d8a28c6eE7`)
|
||||
(which is the first account generated from the `DEFAULT_MNEMONIC` variable, to use a different account see [here](#Using-a-different-Ethereum-account))
|
||||
|
||||
### Major version: content + contract
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:major -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (the output lives in `dist`)
|
||||
2. _compile_ the app's contract (the output lives in `build`)
|
||||
3. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
> aragon apm publish major "--environment" "staging"
|
||||
|
||||
✔ Successfully published app.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
ℹ Transaction hash: 0x3d752db29cc106e9ff98b260a90615921eb32471425a29ead8cbb830fb224d8
|
||||
```
|
||||
|
||||
Note: the contract location is defined in `arapp.json` under `path`.
|
||||
Note: you can also deploy a major version with only frontend changes by passing `--only-content`.
|
||||
|
||||
### Minor/patch version: content only
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:patch -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (which lives in `dist`)
|
||||
2. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
✔ Successfully published app.open.aragonpm.eth v1.1.1:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
ℹ Transaction hash: 0x57864d8efd8d439008621b494b19a3e8f876a8a46b38475f9626802f0a1403c2
|
||||
```
|
||||
|
||||
### Check published versions
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run versions -- --environment staging
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
ℹ app.open.aragonpm.eth has 4 published versions
|
||||
✔ 1.0.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
✔ 1.1.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmSwjUZFpv2c2e9fLoxtgFrAsAmBN4DyQGJp4RcqQcW3z3
|
||||
✔ 1.1.1: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
✔ 2.0.0: 0x74CBbbC932d7C344FCd789Eba24BfD40e52980c9 ipfs:Qmadb3hzwLDKtb93fF367Vg1epkdsLZF4dhpapNYynjgZF
|
||||
```
|
||||
|
||||
### Using a different Ethereum account
|
||||
|
||||
To deploy from a different account, you can:
|
||||
- define a `~/.aragon/mnemonic.json` file
|
||||
```
|
||||
{
|
||||
"mnemonic": "explain tackle mirror kit ..."
|
||||
}
|
||||
```
|
||||
or
|
||||
- define a `~/.aragon/${network_name}_key.json` file, for example: `~/.aragon/rinkeby_key.json`
|
||||
```
|
||||
{
|
||||
"keys": [
|
||||
"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563"
|
||||
]
|
||||
}
|
||||
```
|
||||
43
apps/proposal/arapp.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"roles": [
|
||||
{
|
||||
"name": "Add proposal",
|
||||
"id": "ADD_PROPOSAL_ROLE",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"name": "Vote proposals",
|
||||
"id": "VOTE_PROPOSAL_ROLE",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"name": "Add contribution",
|
||||
"id": "ADD_CONTRIBUTION_ROLE",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"name": "Manage contributors",
|
||||
"id": "MANAGE_CONTRIBUTORS_ROLE",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"environments": {
|
||||
"default": {
|
||||
"network": "development",
|
||||
"appName": "proposal.aragonpm.eth"
|
||||
},
|
||||
"staging": {
|
||||
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
|
||||
"appName": "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"
|
||||
}
|
||||
132
apps/proposal/contracts/Proposal.sol
Normal file
@ -0,0 +1,132 @@
|
||||
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;
|
||||
bytes32 public constant CONTRIBUTOR_APP_ID = 0xe9140f1e39c8a1d04167c3b710688a3eecea2976f34735c8eb98956f4764635b;
|
||||
bytes32 public constant CONTRIBUTION_APP_ID = 0x7fcf91283b719b30c2fa954ff0da021e1b91aed09d7aa13df5e8078a4a1007eb;
|
||||
|
||||
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() public onlyInit {
|
||||
initialized();
|
||||
}
|
||||
|
||||
function getContributorContract() public view returns (address) {
|
||||
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, CONTRIBUTOR_APP_ID);
|
||||
}
|
||||
|
||||
function getContributionContract() public view returns (address) {
|
||||
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, CONTRIBUTION_APP_ID);
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
address contributorAccount = IContributor(getContributorContract()).getContributorAddressById(p.contributorId);
|
||||
IContribution(getContributionContract()).add(p.amount, contributorAccount, p.hashDigest, p.hashFunction, p.hashSize);
|
||||
p.executed = true;
|
||||
emit ProposalExecuted(proposalId, p.contributorId, p.amount);
|
||||
}
|
||||
|
||||
}
|
||||
4
apps/proposal/manifest.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Proposal",
|
||||
"description": "Kredits proposal app"
|
||||
}
|
||||
5
apps/proposal/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
21093
apps/proposal/package-lock.json
generated
Normal file
28
apps/proposal/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
63
apps/proposal/truffle.js
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* https://github.com/aragon/aragonOS/blob/v4.0.0/truffle-config.js
|
||||
*/
|
||||
const homedir = require('homedir')
|
||||
const path = require('path')
|
||||
|
||||
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||
const HDWalletProviderPrivkey = require('truffle-hdwallet-provider-privkey')
|
||||
|
||||
const DEFAULT_MNEMONIC = 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus'
|
||||
|
||||
const defaultRPC = (network) =>
|
||||
`https://${network}.infura.io`
|
||||
|
||||
const configFilePath = (filename) =>
|
||||
path.join(homedir(), `.aragon/${filename}`)
|
||||
|
||||
const mnemonic = () => {
|
||||
try {
|
||||
return require(configFilePath('mnemonic.json')).mnemonic
|
||||
} catch (e) {
|
||||
return DEFAULT_MNEMONIC
|
||||
}
|
||||
}
|
||||
|
||||
const settingsForNetwork = (network) => {
|
||||
try {
|
||||
return require(configFilePath(`${network}_key.json`))
|
||||
} catch (e) {
|
||||
return { }
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily loaded provider
|
||||
const providerForNetwork = (network) => (
|
||||
() => {
|
||||
let { rpc, keys } = settingsForNetwork(network)
|
||||
rpc = rpc || defaultRPC(network)
|
||||
|
||||
if (!keys || keys.length == 0) {
|
||||
return new HDWalletProvider(mnemonic(), rpc)
|
||||
}
|
||||
|
||||
return new HDWalletProviderPrivkey(keys, rpc)
|
||||
}
|
||||
)
|
||||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: '*'
|
||||
},
|
||||
mainnet: {
|
||||
network_id: 1,
|
||||
provider: providerForNetwork('mainnet')
|
||||
},
|
||||
rinkeby: {
|
||||
network_id: 4,
|
||||
provider: providerForNetwork('rinkeby')
|
||||
}
|
||||
}
|
||||
}
|
||||
4
apps/token/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
14
apps/token/.ipfsignore
Normal file
@ -0,0 +1,14 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
162
apps/token/README.md
Normal file
@ -0,0 +1,162 @@
|
||||
# Aragon React Boilerplate
|
||||
|
||||
> 🕵️ [Find more boilerplates using GitHub](https://github.com/search?q=topic:aragon-boilerplate) |
|
||||
> ✨ [Official boilerplates](https://github.com/search?q=topic:aragon-boilerplate+org:aragon)
|
||||
|
||||
React boilerplate for Aragon applications.
|
||||
|
||||
This boilerplate also includes a fully working example app, complete with a background worker and a front-end in React (with Aragon UI).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
aragon init app.aragonpm.eth react
|
||||
```
|
||||
|
||||
## Running your app
|
||||
|
||||
### Using HTTP
|
||||
|
||||
Running your app using HTTP will allow for a faster development process of your app's front-end, as it can be hot-reloaded without the need to execute `aragon run` every time a change is made.
|
||||
|
||||
- First start your app's development server running `npm run start:app`, and keep that process running. By default it will rebuild the app and reload the server when changes to the source are made.
|
||||
|
||||
- After that, you can run `npm run start:aragon:http` which will compile your app's contracts, publish the app locally and create a DAO. You will need to stop it and run it again after making changes to your smart contracts.
|
||||
|
||||
Changes to the app's background script (`app/script.js`) cannot be hot-reloaded, after making changes to the script, you will need to either restart the development server (`npm run start:app`) or rebuild the script `npm run build:script`.
|
||||
|
||||
### Using IPFS
|
||||
|
||||
Running your app using IPFS will mimic the production environment that will be used for running your app. `npm run start:aragon:ipfs` will run your app using IPFS. Whenever a change is made to any file in your front-end, a new version of the app needs to be published, so the command needs to be restarted.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
### npm Scripts
|
||||
|
||||
- **start** or **start:aragon:ipfs**: Runs your app inside a DAO served from IPFS
|
||||
- **start:aragon:http**: Runs your app inside a DAO served with HTTP (hot reloading)
|
||||
- **start:app**: Starts a development server for your app
|
||||
- **compile**: Compile the smart contracts
|
||||
- **build**: Builds the front-end and background script
|
||||
- **build:app**: Builds the front-end
|
||||
- **build:script**: Builds the background script
|
||||
- **test**: Runs tests for the contracts
|
||||
- **publish:patch**: Release a patch version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:minor**: Release a minor version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:major**: Release a major version to aragonPM (frontend **and** contract changes)
|
||||
- **versions**: Check the currently installed versions of the app
|
||||
|
||||
### Libraries
|
||||
|
||||
- [**@aragon/os**](https://github.com/aragon/aragonos): Aragon interfaces
|
||||
- [**@aragon/client**](https://github.com/aragon/aragon.js/tree/master/packages/aragon-client): Wrapper for Aragon application RPC
|
||||
- [**@aragon/ui**](https://github.com/aragon/aragon-ui): Aragon UI components (in React)
|
||||
|
||||
## Publish
|
||||
|
||||
This app has 3 environments defined in `arapp.json`:
|
||||
|
||||
| Environment | Network |
|
||||
|--- |--- |
|
||||
| default | localhost |
|
||||
| staging | rinkeby |
|
||||
| production | mainnet |
|
||||
|
||||
Prerequisites:
|
||||
- ENS Registry address
|
||||
|
||||
Note: the `default` environment which points to `localhost` does not have an ENS Registry address specified because the `@aragon/cli` will default the value to `0xB9462EF3441346dBc6E49236Edbb0dF207db09B7` (the ENS Registry pre-deployed on the local development chain).
|
||||
|
||||
### Introduction to environments
|
||||
|
||||
Environments are defined in `arapp.json`, for example `staging` points to:
|
||||
- an ENS registry (`0x314159265dd8dbb310642f98f50c066173c1259b`)
|
||||
- an APM registry (`open.aragonpm.eth`)
|
||||
- an APM repository (`app`)
|
||||
- an Ethereum network (`rinkeby`)
|
||||
- an Ethereum websockets provider (`wss://rinkeby.eth.aragon.network/ws` - to **read** from the blockchain)
|
||||
|
||||
The `rinkeby` network is further defined in `truffle.js`, and has:
|
||||
- an Ethereum provider (to **write** to the blockchain):
|
||||
- an address (`https://rinkeby.infura.io`)
|
||||
- an Ethereum Account (`0xb4124cEB3451635DAcedd11767f004d8a28c6eE7`)
|
||||
(which is the first account generated from the `DEFAULT_MNEMONIC` variable, to use a different account see [here](#Using-a-different-Ethereum-account))
|
||||
|
||||
### Major version: content + contract
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:major -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (the output lives in `dist`)
|
||||
2. _compile_ the app's contract (the output lives in `build`)
|
||||
3. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
> aragon apm publish major "--environment" "staging"
|
||||
|
||||
✔ Successfully published app.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
ℹ Transaction hash: 0x3d752db29cc106e9ff98b260a90615921eb32471425a29ead8cbb830fb224d8
|
||||
```
|
||||
|
||||
Note: the contract location is defined in `arapp.json` under `path`.
|
||||
Note: you can also deploy a major version with only frontend changes by passing `--only-content`.
|
||||
|
||||
### Minor/patch version: content only
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:patch -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (which lives in `dist`)
|
||||
2. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
✔ Successfully published app.open.aragonpm.eth v1.1.1:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
ℹ Transaction hash: 0x57864d8efd8d439008621b494b19a3e8f876a8a46b38475f9626802f0a1403c2
|
||||
```
|
||||
|
||||
### Check published versions
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run versions -- --environment staging
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
ℹ app.open.aragonpm.eth has 4 published versions
|
||||
✔ 1.0.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
✔ 1.1.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmSwjUZFpv2c2e9fLoxtgFrAsAmBN4DyQGJp4RcqQcW3z3
|
||||
✔ 1.1.1: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
✔ 2.0.0: 0x74CBbbC932d7C344FCd789Eba24BfD40e52980c9 ipfs:Qmadb3hzwLDKtb93fF367Vg1epkdsLZF4dhpapNYynjgZF
|
||||
```
|
||||
|
||||
### Using a different Ethereum account
|
||||
|
||||
To deploy from a different account, you can:
|
||||
- define a `~/.aragon/mnemonic.json` file
|
||||
```
|
||||
{
|
||||
"mnemonic": "explain tackle mirror kit ..."
|
||||
}
|
||||
```
|
||||
or
|
||||
- define a `~/.aragon/${network_name}_key.json` file, for example: `~/.aragon/rinkeby_key.json`
|
||||
```
|
||||
{
|
||||
"keys": [
|
||||
"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563"
|
||||
]
|
||||
}
|
||||
```
|
||||
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": "token.aragonpm.eth"
|
||||
},
|
||||
"staging": {
|
||||
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
|
||||
"appName": "token.open.aragonpm.eth",
|
||||
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
|
||||
"network": "rinkeby"
|
||||
},
|
||||
"production": {
|
||||
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
|
||||
"appName": "token.open.aragonpm.eth",
|
||||
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
|
||||
"network": "mainnet"
|
||||
}
|
||||
},
|
||||
"path": "contracts/Token.sol"
|
||||
}
|
||||
173
apps/token/contracts/ERC20Token.sol
Normal file
@ -0,0 +1,173 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/lib/math/SafeMath.sol";
|
||||
|
||||
/**
|
||||
* beause ERC20.sol conflicts with the aragon ERC20.sol this is copied and modified from:
|
||||
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20.sol
|
||||
* @title Standard ERC20 token
|
||||
*
|
||||
* @dev Implementation of the basic standard token.
|
||||
* https://eips.ethereum.org/EIPS/eip-20
|
||||
* Originally based on code by FirstBlood:
|
||||
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
|
||||
*
|
||||
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
|
||||
* all accounts just by listening to said events. Note that this isn't required by the specification, and other
|
||||
* compliant implementations may not do it.
|
||||
*/
|
||||
contract ERC20Token {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping (address => uint256) public _balances;
|
||||
|
||||
mapping (address => mapping (address => uint256)) private _allowed;
|
||||
|
||||
uint256 public _totalSupply;
|
||||
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint8 public decimals;
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
|
||||
/**
|
||||
* @dev Total number of tokens in existence
|
||||
*/
|
||||
function totalSupply() public view returns (uint256) {
|
||||
return _totalSupply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the balance of the specified address.
|
||||
* @param owner The address to query the balance of.
|
||||
* @return A uint256 representing the amount owned by the passed address.
|
||||
*/
|
||||
function balanceOf(address owner) public view returns (uint256) {
|
||||
return _balances[owner];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Function to check the amount of tokens that an owner allowed to a spender.
|
||||
* @param owner address The address which owns the funds.
|
||||
* @param spender address The address which will spend the funds.
|
||||
* @return A uint256 specifying the amount of tokens still available for the spender.
|
||||
*/
|
||||
function allowance(address owner, address spender) public view returns (uint256) {
|
||||
return _allowed[owner][spender];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfer token to a specified address
|
||||
* @param to The address to transfer to.
|
||||
* @param value The amount to be transferred.
|
||||
*/
|
||||
function transfer(address to, uint256 value) public returns (bool) {
|
||||
_transfer(msg.sender, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
|
||||
* Beware that changing an allowance with this method brings the risk that someone may use both the old
|
||||
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
|
||||
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
|
||||
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
||||
* @param spender The address which will spend the funds.
|
||||
* @param value The amount of tokens to be spent.
|
||||
*/
|
||||
function approve(address spender, uint256 value) public returns (bool) {
|
||||
_approve(msg.sender, spender, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfer tokens from one address to another.
|
||||
* Note that while this function emits an Approval event, this is not required as per the specification,
|
||||
* and other compliant implementations may not emit the event.
|
||||
* @param from address The address which you want to send tokens from
|
||||
* @param to address The address which you want to transfer to
|
||||
* @param value uint256 the amount of tokens to be transferred
|
||||
*/
|
||||
function transferFrom(address from, address to, uint256 value) public returns (bool) {
|
||||
_transfer(from, to, value);
|
||||
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Increase the amount of tokens that an owner allowed to a spender.
|
||||
* approve should be called when _allowed[msg.sender][spender] == 0. To increment
|
||||
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* the first transaction is mined)
|
||||
* From MonolithDAO Token.sol
|
||||
* Emits an Approval event.
|
||||
* @param spender The address which will spend the funds.
|
||||
* @param addedValue The amount of tokens to increase the allowance by.
|
||||
*/
|
||||
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
|
||||
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decrease the amount of tokens that an owner allowed to a spender.
|
||||
* approve should be called when _allowed[msg.sender][spender] == 0. To decrement
|
||||
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* the first transaction is mined)
|
||||
* From MonolithDAO Token.sol
|
||||
* Emits an Approval event.
|
||||
* @param spender The address which will spend the funds.
|
||||
* @param subtractedValue The amount of tokens to decrease the allowance by.
|
||||
*/
|
||||
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
|
||||
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfer token for a specified addresses
|
||||
* @param from The address to transfer from.
|
||||
* @param to The address to transfer to.
|
||||
* @param value The amount to be transferred.
|
||||
*/
|
||||
function _transfer(address from, address to, uint256 value) internal {
|
||||
require(to != address(0));
|
||||
|
||||
_balances[from] = _balances[from].sub(value);
|
||||
_balances[to] = _balances[to].add(value);
|
||||
emit Transfer(from, to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function that mints an amount of the token and assigns it to
|
||||
* an account. This encapsulates the modification of balances such that the
|
||||
* proper events are emitted.
|
||||
* @param account The account that will receive the created tokens.
|
||||
* @param value The amount that will be created.
|
||||
*/
|
||||
function _mint(address account, uint256 value) internal {
|
||||
require(account != address(0), 'invalid address');
|
||||
|
||||
_totalSupply = _totalSupply.add(value);
|
||||
_balances[account] = _balances[account].add(value);
|
||||
emit Transfer(address(0), account, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Approve an address to spend another addresses' tokens.
|
||||
* @param owner The address that owns the tokens.
|
||||
* @param spender The address that will spend the tokens.
|
||||
* @param value The number of tokens that can be spent.
|
||||
*/
|
||||
function _approve(address owner, address spender, uint256 value) internal {
|
||||
require(spender != address(0));
|
||||
require(owner != address(0));
|
||||
|
||||
_allowed[owner][spender] = value;
|
||||
emit Approval(owner, spender, value);
|
||||
}
|
||||
|
||||
}
|
||||
20
apps/token/contracts/Token.sol
Normal file
@ -0,0 +1,20 @@
|
||||
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");
|
||||
|
||||
event LogMint(address indexed recipient, uint256 amount, uint256 contributionId);
|
||||
|
||||
function initialize() public onlyInit {
|
||||
initialized();
|
||||
}
|
||||
|
||||
function mintFor(address contributorAccount, uint256 amount, uint256 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) {
|
||||
_mint(contributorAccount, amount);
|
||||
emit LogMint(contributorAccount, amount, contributionId);
|
||||
}
|
||||
|
||||
}
|
||||
23
apps/token/contracts/misc/Migrations.sol
Normal file
@ -0,0 +1,23 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
uint public last_completed_migration;
|
||||
|
||||
modifier restricted() {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) restricted {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
}
|
||||
4
apps/token/manifest.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Token",
|
||||
"description": "Kredits token app"
|
||||
}
|
||||
5
apps/token/migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
5
apps/token/migrations/2_deploy_contracts.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Token = artifacts.require('Token.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Token)
|
||||
}
|
||||
13482
apps/token/package-lock.json
generated
Normal file
28
apps/token/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "kredits-token",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@aragon/os": "^4.1.0",
|
||||
"@aragon/cli": "^5.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
},
|
||||
"scripts": {
|
||||
"start": "npm run start:aragon:ipfs",
|
||||
"start:aragon:ipfs": "aragon run",
|
||||
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
|
||||
"start:app": "",
|
||||
"test": "aragon contracts test",
|
||||
"compile": "aragon contracts compile",
|
||||
"sync-assets": "",
|
||||
"build:app": "",
|
||||
"build:script": "",
|
||||
"build": "",
|
||||
"publish:patch": "aragon apm publish patch",
|
||||
"publish:minor": "aragon apm publish minor",
|
||||
"publish:major": "aragon apm publish major",
|
||||
"versions": "aragon apm versions"
|
||||
},
|
||||
"keywords": []
|
||||
}
|
||||
5
apps/token/test/app.js
Normal file
@ -0,0 +1,5 @@
|
||||
const CounterApp = artifacts.require('CounterApp.sol')
|
||||
|
||||
contract('CounterApp', (accounts) => {
|
||||
it('should be tested')
|
||||
})
|
||||
63
apps/token/truffle.js
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* https://github.com/aragon/aragonOS/blob/v4.0.0/truffle-config.js
|
||||
*/
|
||||
const homedir = require('homedir')
|
||||
const path = require('path')
|
||||
|
||||
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||
const HDWalletProviderPrivkey = require('truffle-hdwallet-provider-privkey')
|
||||
|
||||
const DEFAULT_MNEMONIC = 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus'
|
||||
|
||||
const defaultRPC = (network) =>
|
||||
`https://${network}.infura.io`
|
||||
|
||||
const configFilePath = (filename) =>
|
||||
path.join(homedir(), `.aragon/${filename}`)
|
||||
|
||||
const mnemonic = () => {
|
||||
try {
|
||||
return require(configFilePath('mnemonic.json')).mnemonic
|
||||
} catch (e) {
|
||||
return DEFAULT_MNEMONIC
|
||||
}
|
||||
}
|
||||
|
||||
const settingsForNetwork = (network) => {
|
||||
try {
|
||||
return require(configFilePath(`${network}_key.json`))
|
||||
} catch (e) {
|
||||
return { }
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily loaded provider
|
||||
const providerForNetwork = (network) => (
|
||||
() => {
|
||||
let { rpc, keys } = settingsForNetwork(network)
|
||||
rpc = rpc || defaultRPC(network)
|
||||
|
||||
if (!keys || keys.length == 0) {
|
||||
return new HDWalletProvider(mnemonic(), rpc)
|
||||
}
|
||||
|
||||
return new HDWalletProviderPrivkey(keys, rpc)
|
||||
}
|
||||
)
|
||||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: '*'
|
||||
},
|
||||
mainnet: {
|
||||
network_id: 1,
|
||||
provider: providerForNetwork('mainnet')
|
||||
},
|
||||
rinkeby: {
|
||||
network_id: 4,
|
||||
provider: providerForNetwork('rinkeby')
|
||||
}
|
||||
}
|
||||
}
|
||||
46
arapp.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"roles": [
|
||||
{
|
||||
"name": "Add contributions",
|
||||
"id": "ADD_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": {
|
||||
"rinkeby": {
|
||||
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
|
||||
"registry": "0x98Df287B6C145399Aaa709692c8D308357bC085D",
|
||||
"appName": "dummy.open.aragonpm.eth",
|
||||
"network": "rinkeby"
|
||||
},
|
||||
"rpc": {
|
||||
"network": "rpc",
|
||||
"appName": "dummy.aragonpm.eth"
|
||||
},
|
||||
"default": {
|
||||
"network": "rpc",
|
||||
"appName": "dummy.aragonpm.eth"
|
||||
}
|
||||
},
|
||||
"path": "contracts/misc/DummyApp.sol"
|
||||
}
|
||||
@ -1,126 +0,0 @@
|
||||
pragma solidity ^0.4.19;
|
||||
|
||||
import "zeppelin-solidity/contracts/token/ERC721/ERC721Token.sol";
|
||||
import './upgradeable/Upgradeable.sol';
|
||||
|
||||
// ToDo: only load interfaces
|
||||
import './Token.sol';
|
||||
import './Contributors.sol';
|
||||
|
||||
contract Contribution is Upgradeable, ERC721Token {
|
||||
|
||||
struct ContributionData {
|
||||
address contributor;
|
||||
uint amount;
|
||||
bool claimed;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
string tokenMetadataURL;
|
||||
uint claimAfterBlock;
|
||||
bool exists;
|
||||
}
|
||||
string internal name_;
|
||||
string internal symbol_;
|
||||
|
||||
mapping(uint256 => address) contributionOwner;
|
||||
mapping(address => uint256[]) ownedContributions;
|
||||
|
||||
mapping(uint256 => ContributionData) public contributions;
|
||||
uint256 public contributionsCount;
|
||||
|
||||
event ContributionAdded(uint256 id, address indexed contributor, uint256 amount);
|
||||
event ContributionClaimed(uint256 id, address indexed contributor, uint256 amount);
|
||||
|
||||
modifier coreOnly() {
|
||||
require(contributorsContract().addressIsCore(msg.sender));
|
||||
_;
|
||||
}
|
||||
modifier contributorOnly() {
|
||||
require(contributorsContract().addressExists(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
function contributorsContract() view public returns (Contributors) {
|
||||
return Contributors(registry.getProxyFor('Contributors'));
|
||||
}
|
||||
|
||||
function tokenContract() view public returns (Token) {
|
||||
return Token(registry.getProxyFor('Token'));
|
||||
}
|
||||
|
||||
function name() external view returns (string) {
|
||||
return name_;
|
||||
}
|
||||
|
||||
function symbol() external view returns (string) {
|
||||
return symbol_;
|
||||
}
|
||||
|
||||
function ownerOf(uint256 contributionId) public view returns (address) {
|
||||
require(exists(contributionId));
|
||||
return contributions[contributionId].contributor;
|
||||
}
|
||||
|
||||
function balanceOf(address contributor) public view returns (uint) {
|
||||
return ownedContributions[contributor].length;
|
||||
}
|
||||
|
||||
function tokenOfOwnerByIndex(address contributor, uint index) public view returns (uint) {
|
||||
return ownedContributions[contributor][index];
|
||||
}
|
||||
|
||||
function tokenMetadata(uint contributionId) public view returns (string) {
|
||||
return contributions[contributionId].tokenMetadataURL;
|
||||
}
|
||||
|
||||
function getContribution(uint contributionId) public view returns (uint256 id, address contributor, uint256 amount, bool claimed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint claimAfterBlock, bool exists) {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
function add(uint256 amount, address contributor, uint256 blocksToWait) public coreOnly {
|
||||
uint contributionId = contributionsCount + 1;
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
c.exists = true;
|
||||
c.amount = amount;
|
||||
c.claimed = false;
|
||||
c.contributor = contributor;
|
||||
c.claimAfterBlock = block.number + blocksToWait;
|
||||
|
||||
contributionsCount++;
|
||||
|
||||
contributionOwner[contributionId] = contributor;
|
||||
ownedContributions[contributor].push(contributionId);
|
||||
|
||||
ContributionAdded(contributionId, contributor, amount);
|
||||
}
|
||||
|
||||
function claim(uint256 contributionId) public {
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
require(c.exists);
|
||||
require(!c.claimed);
|
||||
require(block.number > c.claimAfterBlock);
|
||||
c.claimed = true;
|
||||
tokenContract().mintFor(c.contributor, c.amount, contributionId);
|
||||
|
||||
ContributionClaimed(contributionId, c.contributor, c.amount);
|
||||
}
|
||||
|
||||
function exists(uint256 contributionId) view public returns (bool) {
|
||||
return contributions[contributionId].exists;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
85
contracts/KreditsKit.sol
Normal file
@ -0,0 +1,85 @@
|
||||
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/os/contracts/acl/ACLSyntaxSugar.sol";
|
||||
|
||||
import "@aragon/kits-base/contracts/KitBase.sol";
|
||||
import "./misc/APMNamehashOpen.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, APMNamehashOpen, ACLSyntaxSugar {
|
||||
bytes32 public contributorAppId = apmNamehash("contributor"); // 0xe9140f1e39c8a1d04167c3b710688a3eecea2976f34735c8eb98956f4764635b
|
||||
bytes32 public contributionAppId = apmNamehash("contribution"); // 0x7fcf91283b719b30c2fa954ff0da021e1b91aed09d7aa13df5e8078a4a1007eb
|
||||
bytes32 public tokenAppId = apmNamehash("token"); // 0xe04a882e7a6adf5603207d545ea49aec17e6b936c4d9eae3d74dbe482264991a
|
||||
|
|
||||
bytes32 public proposalAppId = apmNamehash("proposal"); // 0xaf5fe5c3b0d9581ee88974bbc8699e6fa71efd1b321e44b2227103c9ef21dbdb
|
||||
|
||||
|
||||
event DeployInstance(address dao);
|
||||
event InstalledApp(address dao, address appProxy, bytes32 appId);
|
||||
|
||||
constructor (DAOFactory _fac, ENS _ens) public KitBase(_fac, _ens) {}
|
||||
|
||||
function newInstance() public returns (Kernel dao, ERCProxy proxy) {
|
||||
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, contributorAppId));
|
||||
contributor.initialize(root);
|
||||
acl.createPermission(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), root);
|
||||
|
||||
Token token = Token(_installApp(dao, tokenAppId));
|
||||
token.initialize();
|
||||
|
||||
Contribution contribution = Contribution(_installApp(dao, contributionAppId));
|
||||
contribution.initialize();
|
||||
|
||||
Proposal proposal = Proposal(_installApp(dao, proposalAppId));
|
||||
proposal.initialize();
|
||||
|
||||
acl.createPermission(root, contribution, contribution.ADD_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.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.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,133 +0,0 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
// ToDo: only load interfaces
|
||||
import './Token.sol';
|
||||
import './Contributors.sol';
|
||||
import './Contribution.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 contributionContract() view public returns (Contribution) {
|
||||
return Contribution(registry.getProxyFor('Contribution'));
|
||||
}
|
||||
|
||||
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);
|
||||
contributionContract().add(p.amount, recipientAddress, 0);
|
||||
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('Contribution') public {
|
||||
totalSupply_ = totalSupply_.add(amount);
|
||||
balances[contributorAccount] = balances[contributorAccount].add(amount);
|
||||
|
||||
LogMint(contributorAccount, amount, proposalId);
|
||||
}
|
||||
|
||||
}
|
||||
13
contracts/misc/APMNamehashOpen.sol
Normal file
@ -0,0 +1,13 @@
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/apm/APMNamehash.sol";
|
||||
|
||||
|
||||
contract APMNamehashOpen is APMNamehash {
|
||||
bytes32 public constant OPEN_TITLE = keccak256("open");
|
||||
bytes32 public constant OPEN_APM_NODE = keccak256(abi.encodePacked(APM_NODE, OPEN_TITLE));
|
||||
|
||||
function apmNamehashOpen(string name) internal pure returns (bytes32) {
|
||||
return keccak256(abi.encodePacked(OPEN_APM_NODE, keccak256(name)));
|
||||
}
|
||||
}
|
||||
16
contracts/misc/DummyApp.sol
Normal file
@ -0,0 +1,16 @@
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||
|
||||
|
||||
// This is a "Dummy" app which's only purpose to exist is because
|
||||
// Aragon's CLI still doesn't support running a Kit inside a project
|
||||
// which isn't considered to be a "valid" Aragon project.
|
||||
// It requires us to have an arrap.json file pointing to the contract
|
||||
// and a manifest.json file which describes the front-end structure.
|
||||
contract DummyApp is AragonApp {
|
||||
function initialize() public onlyInit {
|
||||
initialized();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
@ -8,7 +8,7 @@ contract Migrations {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() public {
|
||||
function constructor() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
1
lib/abis/Contributor.json
Normal file
@ -1 +0,0 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contributors","outputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"contributorIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldIpfsHash","type":"bytes32"},{"indexed":false,"name":"newIpfsHash","type":"bytes32"}],"name":"ContributorProfileUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldAccount","type":"address"},{"indexed":false,"name":"newAccount","type":"address"}],"name":"ContributorAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"account","type":"address"}],"name":"ContributorAdded","type":"event"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"oldAccount","type":"address"},{"name":"newAccount","type":"address"}],"name":"updateContributorAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"updateContributorIpfsHash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"}],"name":"addContributor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"isCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"exists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressIsCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"getContributorAddressById","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"getContributorById","outputs":[{"name":"id","type":"uint256"},{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"balance","type":"uint256"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]
|
||||
1
lib/abis/Kernel.json
Normal file
@ -1 +0,0 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposalsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"creatorAccount","type":"address"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"voterId","type":"uint256"},{"indexed":false,"name":"totalVotes","type":"uint256"}],"name":"ProposalVoted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalExecuted","type":"event"},{"constant":true,"inputs":[],"name":"contributorsContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributionContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"contributorId","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"addProposal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"getProposal","outputs":[{"name":"id","type":"uint256"},{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"voterIds","type":"uint256[]"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_proposalIds","type":"uint256[]"}],"name":"batchVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
|
||||
1
lib/abis/Proposal.json
Normal file
@ -1 +0,0 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"currentVersions","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"name":"versions","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"proxy","type":"address"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"},{"indexed":false,"name":"implementation","type":"address"}],"name":"VersionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"}],"name":"ProxyImplementationUpgraded","type":"event"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"implementation","type":"address"}],"name":"addVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"getVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getLatestVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getProxyFor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"upgradeToLatest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"createProxy","outputs":[{"name":"","type":"address"}],"payable":true,"stateMutability":"payable","type":"function"}]
|
||||
@ -1 +1 @@
|
||||
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"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":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"proposalId","type":"uint256"}],"name":"LogMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"contributorAccount","type":"address"},{"name":"amount","type":"uint256"},{"name":"proposalId","type":"uint256"}],"name":"mintFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
|
||||
[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_foo","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINT_TOKEN_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"contributionId","type":"uint256"}],"name":"LogMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"constant":false,"inputs":[],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"foo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"mintFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
|
||||
@ -1 +0,0 @@
|
||||
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"}
|
||||
@ -1 +0,0 @@
|
||||
{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"}
|
||||
@ -1 +0,0 @@
|
||||
{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x7458dea485d9d8301e3ce43e8a1ec1456be5ba83"}
|
||||
@ -1 +0,0 @@
|
||||
{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"}
|
||||
1
lib/addresses/dao.json
Normal file
@ -0,0 +1 @@
|
||||
|
I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
||||
{"23827572":"0xe4e0e7fe54d9189df29a80c07ab733fc9a212761","65047207":"0xdbe26ae4a434472a7474db60cc3e3c97a57bbf38"}
|
||||
|
I am wondering how I can prevent that those local address details get commited. I am wondering how I can prevent that those local address details get commited.
Those "14945560" network IDs are devchain IDs.
so far I don't think it is worth to write code for that and maybe simply try to ignore commiting those changes, but if somebody has an idea...?
Maybe a git pre commit hook would work. I have never worked with git hooks... Maybe a git pre commit hook would work. I have never worked with git hooks...
Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually. Yes, I think that could be a good solution. Git hooks are pretty easy to work with actually.
hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones. then it probably does not change that often... hmm. the issue is locally you need those addresses in the file but in the repo we only need the commonly used ones.
so what would the hook do?
then it probably does not change that often...
|
||||
@ -46,6 +46,26 @@ class Contribution extends Base {
|
||||
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,
|
||||
];
|
||||
|
||||
console.log(contribution);
|
||||
return this.functions.add(...contribution, callOptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Contribution;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
Contributors: require('./contributor'),
|
||||
Contributor: require('./contributor'),
|
||||
Contribution: require('./contribution'),
|
||||
Operator: require('./operator'),
|
||||
Proposal: require('./proposal'),
|
||||
Token: require('./token'),
|
||||
Registry: require('./registry')
|
||||
Kernel: require('./kernel')
|
||||
};
|
||||
|
||||
21
lib/contracts/kernel.js
Normal file
@ -0,0 +1,21 @@
|
||||
const Base = require('./base');
|
||||
|
||||
KERNEL_APP_ADDR_NAMESPACE = '0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb';
|
||||
|
||||
class Kernel extends Base {
|
||||
|
||||
getApp(appName) {
|
||||
return this.functions.getApp(KERNEL_APP_ADDR_NAMESPACE, this.appNamehash(appName));
|
||||
}
|
||||
|
||||
appNamehash(appName) {
|
||||
return {
|
||||
Contributor: '0xe9140f1e39c8a1d04167c3b710688a3eecea2976f34735c8eb98956f4764635b',
|
||||
Contribution: '0x7fcf91283b719b30c2fa954ff0da021e1b91aed09d7aa13df5e8078a4a1007eb',
|
||||
Token: '0xe04a882e7a6adf5603207d545ea49aec17e6b936c4d9eae3d74dbe482264991a',
|
||||
Proposal: '0xaf5fe5c3b0d9581ee88974bbc8699e6fa71efd1b321e44b2227103c9ef21dbdb'
|
||||
}[appName];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Kernel;
|
||||
@ -1,6 +0,0 @@
|
||||
const Base = require('./base');
|
||||
|
||||
class Registry extends Base {
|
||||
}
|
||||
|
||||
module.exports = Registry;
|
||||
@ -4,13 +4,19 @@ const RSVP = require('rsvp');
|
||||
const Preflight = require('./utils/preflight');
|
||||
|
||||
const ABIS = {
|
||||
Contributors: require('./abis/Contributors.json'),
|
||||
Contributor: require('./abis/Contributor.json'),
|
||||
Contribution: require('./abis/Contribution.json'),
|
||||
Operator: require('./abis/Operator.json'),
|
||||
Registry: require('./abis/Registry.json'),
|
||||
Token: require('./abis/Token.json')
|
||||
Token: require('./abis/Token.json'),
|
||||
Proposal: require('./abis/Proposal.json'),
|
||||
Kernel: require('./abis/Kernel.json')
|
||||
};
|
||||
const RegistryAddress = require('./addresses/Registry.json');
|
||||
const APP_CONTRACTS = [
|
||||
'Contributor',
|
||||
'Contribution',
|
||||
'Token',
|
||||
'Proposal'
|
||||
];
|
||||
const DaoAddresses = require('./addresses/dao.json');
|
||||
|
||||
const Contracts = require('./contracts');
|
||||
const IPFS = require('./utils/ipfs')
|
||||
@ -28,18 +34,18 @@ class Kredits {
|
||||
|
||||
this.provider = provider;
|
||||
this.signer = signer;
|
||||
// by default we only need the registry address.
|
||||
// by default we only need the DAO/Kernel 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.addresses = addresses || { Kernel: DaoAddresses[this.provider.chainId.toString()] }; // chainID must be a string
|
||||
this.abis = abis || ABIS;
|
||||
this.ipfs = new IPFS(ipfsConfig);
|
||||
this.contracts = {};
|
||||
}
|
||||
|
||||
init(names) {
|
||||
let contractsToLoad = names || Object.keys(ABIS);
|
||||
let contractsToLoad = names || APP_CONTRACTS;
|
||||
let addressPromises = contractsToLoad.map((contractName) => {
|
||||
return this.Registry.functions.getProxyFor(contractName).then((address) => {
|
||||
return this.Kernel.getApp(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}
|
||||
@ -55,13 +61,13 @@ class Kredits {
|
||||
return new Kredits(provider, signer, { ipfsConfig: ipfsConfig }).init();
|
||||
}
|
||||
|
||||
get Registry() {
|
||||
return this.contractFor('registry');
|
||||
get Kernel() {
|
||||
return this.contractFor('Kernel');
|
||||
}
|
||||
|
||||
get Contributor() {
|
||||
// TODO: rename to contributor
|
||||
return this.contractFor('contributors');
|
||||
return this.contractFor('Contributor');
|
||||
}
|
||||
|
||||
get Contributors() {
|
||||
@ -69,16 +75,16 @@ class Kredits {
|
||||
return this.Contributor;
|
||||
}
|
||||
|
||||
get Operator() {
|
||||
return this.contractFor('operator');
|
||||
get Proposal() {
|
||||
return this.contractFor('Proposal');
|
||||
}
|
||||
|
You don't need the You don't need the `()` see `get Contributors()`
ah ja... thx. ah ja... thx.
|
||||
|
||||
get Token() {
|
||||
return this.contractFor('token');
|
||||
return this.contractFor('Token');
|
||||
}
|
||||
|
||||
get Contribution() {
|
||||
return this.contractFor('contribution');
|
||||
return this.contractFor('Contribution');
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
var Registry = artifacts.require('./Registry.sol');
|
||||
var Contribution = artifacts.require('./Contribution.sol');
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Contribution).then(function(contribution) {
|
||||
console.log('Registry address: ', Registry.address);
|
||||
console.log('Contribution address: ', Contribution.address);
|
||||
Registry.deployed().then(function(registry) {
|
||||
registry.addVersion('Contribution', Contribution.address);
|
||||
registry.createProxy('Contribution', 1);
|
||||
});
|
||||
});
|
||||
};
|
||||
14329
package-lock.json
generated
10
package.json
@ -7,7 +7,7 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build-json": "truffle compile && node ./scripts/build-json.js",
|
||||
"build-json": "aragon contracts compile --all && node ./scripts/build-json.js",
|
||||
"reset": "truffle migrate --reset && npm run build-json",
|
||||
"bootstrap": "npm run reset && truffle exec scripts/seeds.js",
|
||||
"ganache": "ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits",
|
||||
@ -25,11 +25,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/67P/truffle-kredits#readme",
|
||||
"devDependencies": {
|
||||
"@aragon/cli": "^5.5.0",
|
||||
"@aragon/kits-base": "^1.0.0",
|
||||
"@aragon/os": "^4.1.0",
|
||||
"async-each-series": "^1.1.0",
|
||||
"ganache-cli": "^6.1.8",
|
||||
"openzeppelin-solidity": "^2.2.0",
|
||||
"promptly": "^3.0.3",
|
||||
"truffle": "^4.1.14",
|
||||
"zeppelin-solidity": "^1.7.0"
|
||||
"solc": "^0.4.25"
|
||||
},
|
||||
"dependencies": {
|
||||
"ethers": "3.0.15",
|
||||
|
||||
43
scripts/add-contribution.js
Normal file
@ -0,0 +1,43 @@
|
||||
const promptly = require('promptly');
|
||||
|
||||
const ethers = require('ethers');
|
||||
|
❤️ ❤️
is it actually is it actually `init_kredits.js` or initKredits.js` as file name?
I think JS folks use I think JS folks use `require('./helpers/init-kredits');` You don't need the `.js`
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
module.exports = async function(callback) {
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await new Kredits(provider, provider.getSigner()).init();
|
||||
|
||||
console.log(`Using Contributions at: ${kredits.Contribution.contract.address}`);
|
||||
|
||||
let contributor = await promptly.prompt('Contributor (address or id): ');
|
||||
let contributorId;
|
||||
if (contributor.length < 5) {
|
||||
contributorAccount = await kredits.Contributor.functions.getContributorAddressById(contributor);
|
||||
} else {
|
||||
contributorAccount = contributor;
|
||||
}
|
||||
console.log(`Creating a contribution for contributor Account #${contributorAccount}`);
|
||||
|
||||
let contributionAttributes = {
|
||||
contributorAccount,
|
||||
amount: await promptly.prompt('Amount: '),
|
||||
description: await promptly.prompt('Description: '),
|
||||
kind: await promptly.prompt('Kind: ', { default: 'dev' }),
|
||||
url: await promptly.prompt('URL: ', { default: '' })
|
||||
}
|
||||
|
||||
console.log("\nAdding contribution:");
|
||||
console.log(contributionAttributes);
|
||||
|
||||
kredits.Contribution.addContribution(contributionAttributes, { gasLimit: 300000 }).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create contribution');
|
||||
callback(error);
|
||||
});
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
const promptly = require('promptly');
|
||||
|
||||
const ethers = require('ethers');
|
||||
@ -11,39 +10,35 @@ async function prompt(message, options) {
|
||||
return await promptly.prompt(message, options);
|
||||
}
|
||||
|
||||
module.exports = function(callback) {
|
||||
Registry.deployed().then(async (registry) => {
|
||||
module.exports = async function(callback) {
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await new Kredits(provider, provider.getSigner()).init();
|
||||
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await Kredits.setup(provider, provider.getSigner());
|
||||
console.log(`Using contributors at: ${kredits.Contributor.contract.address}`);
|
||||
|
||||
console.log(`Using contributors at: ${kredits.Contributor.contract.address}`);
|
||||
let contributorAttributes = {
|
||||
account: await prompt('Contributor address: ', {}),
|
||||
name: await prompt('Name: '),
|
||||
isCore: await prompt('core? y/n') === 'y',
|
||||
kind: await prompt('Kind (default person): ', {default: 'person'}),
|
||||
url: await prompt('URL: '),
|
||||
github_username: await prompt('GitHub username: '),
|
||||
github_uid: await prompt('GitHub UID: '),
|
||||
wiki_username: await prompt('Wiki username: '),
|
||||
};
|
||||
|
||||
let contributorAttributes = {
|
||||
account: await prompt('Contributor address: ', {}),
|
||||
name: await prompt('Name: '),
|
||||
isCore: await prompt('core? y/n') === 'y',
|
||||
kind: await prompt('Kind (default person): ', {default: 'person'}),
|
||||
url: await prompt('URL: '),
|
||||
github_username: await prompt('GitHub username: '),
|
||||
github_uid: await prompt('GitHub UID: '),
|
||||
wiki_username: await prompt('Wiki username: '),
|
||||
};
|
||||
|
||||
console.log("\nAdding contributor:");
|
||||
console.log(contributorAttributes);
|
||||
|
||||
kredits.Contributor.add(contributorAttributes, { gasLimit: 250000 }).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create contributor');
|
||||
callback(error);
|
||||
});
|
||||
console.log("\nAdding contributor:");
|
||||
console.log(contributorAttributes);
|
||||
|
||||
kredits.Contributor.add(contributorAttributes, { gasLimit: 250000 }).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create contributor');
|
||||
callback(error);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,46 +1,43 @@
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
const promptly = require('promptly');
|
||||
|
||||
const ethers = require('ethers');
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
module.exports = function(callback) {
|
||||
Registry.deployed().then(async (registry) => {
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await Kredits.setup(provider, provider.getSigner());
|
||||
module.exports = async function(callback) {
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await new Kredits(provider, provider.getSigner()).init();
|
||||
|
||||
console.log(`Using operator at: ${kredits.Operator.contract.address}`);
|
||||
console.log(`Using Proposal at: ${kredits.Proposal.contract.address}`);
|
||||
|
||||
let contributor = await promptly.prompt('Contributor (address or id): ');
|
||||
let contributorId;
|
||||
if (contributor.length < 5) {
|
||||
contributorId = contributor;
|
||||
} else {
|
||||
contributorId = await kredits.Contributor.functions.getContributorIdByAddress(contributor);
|
||||
}
|
||||
console.log(`Creating a proposal for contributor ID #${contributorId}`);
|
||||
let contributor = await promptly.prompt('Contributor (address or id): ');
|
||||
let contributorId;
|
||||
if (contributor.length < 5) {
|
||||
contributorId = contributor;
|
||||
} else {
|
||||
contributorId = await kredits.Contributor.functions.getContributorIdByAddress(contributor);
|
||||
}
|
||||
console.log(`Creating a proposal for contributor ID #${contributorId}`);
|
||||
|
||||
let contributionAttributes = {
|
||||
contributorId,
|
||||
amount: await promptly.prompt('Amount: '),
|
||||
description: await promptly.prompt('Description: '),
|
||||
kind: await promptly.prompt('Kind: ', { default: 'dev' }),
|
||||
url: await promptly.prompt('URL: ', { default: '' })
|
||||
}
|
||||
let contributionAttributes = {
|
||||
contributorId,
|
||||
amount: await promptly.prompt('Amount: '),
|
||||
description: await promptly.prompt('Description: '),
|
||||
kind: await promptly.prompt('Kind: ', { default: 'dev' }),
|
||||
url: await promptly.prompt('URL: ', { default: '' })
|
||||
}
|
||||
|
||||
console.log("\nAdding proposal:");
|
||||
console.log(contributionAttributes);
|
||||
console.log("\nAdding proposal:");
|
||||
console.log(contributionAttributes);
|
||||
|
||||
kredits.Operator.addProposal(contributionAttributes, { gasLimit: 300000 }).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create proposal');
|
||||
console.log(error);
|
||||
});
|
||||
kredits.Proposal.addProposal(contributionAttributes, { gasLimit: 300000 }).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create proposal');
|
||||
callback(error);
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,13 +4,12 @@ const path = require('path');
|
||||
const contractsPath = path.join(__dirname, '..', 'build', 'contracts');
|
||||
const libPath = path.join(__dirname, '..', 'lib');
|
||||
const abisPath = path.join(libPath, 'abis');
|
||||
const addressesPath = path.join(libPath, 'addresses');
|
||||
|
||||
const files = [
|
||||
'Contributors',
|
||||
'Contributor',
|
||||
'Contribution',
|
||||
'Operator',
|
||||
'Registry',
|
||||
'Kernel',
|
||||
'Proposal',
|
||||
'Token'
|
||||
];
|
||||
|
||||
@ -18,17 +17,6 @@ files.forEach((fileName) => {
|
||||
let file = require(`${contractsPath}/${fileName}.json`);
|
||||
let abiFile = path.join(abisPath, `${fileName}.json`);
|
||||
fs.writeFileSync(abiFile, JSON.stringify(file.abi));
|
||||
|
||||
if (fileName === 'Registry') {
|
||||
let addresseFile = path.join(addressesPath, `${fileName}.json`);
|
||||
let content = fs.readFileSync(addresseFile);
|
||||
let addresses = Object.keys(file.networks)
|
||||
.reduce((addresses, key) => {
|
||||
addresses[key] = file.networks[key].address;
|
||||
return addresses;
|
||||
}, JSON.parse(content));
|
||||
fs.writeFileSync(addresseFile, JSON.stringify(addresses));
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Don't forget to reaload the JSON files from your application; i.e. restart kredits-web");
|
||||
|
||||
@ -5,14 +5,12 @@ const ethers = require('ethers');
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
module.exports = function(callback) {
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
Registry.deployed().then(async (registry) => {
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await Kredits.setup(provider, provider.getSigner());
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
|
||||
new Kredits(provider, provider.getSigner()).init().then(async function(kredits) {
|
||||
let contractName = await promptly.prompt('Contract Name: ');
|
||||
const contractWrapper = kredits[contractName];
|
||||
|
||||
|
||||
49
scripts/deploy-kit.js
Normal file
@ -0,0 +1,49 @@
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const deployDAOFactory = require('@aragon/os/scripts/deploy-daofactory.js')
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const KreditsKit = artifacts.require('KreditsKit')
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const fs = require('fs');
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const path = require('path');
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const libPath = path.join(__dirname, '..', 'lib');
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const addressesPath = path.join(libPath, 'addresses');
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const ensAddr = process.env.ENS
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
module.exports = async (callback) => {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
if (!ensAddr) {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
callback(new Error("ENS address not found in environment variable ENS"))
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
}
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
deployDAOFactory(null, { artifacts, verbose: false })
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
.catch(console.log)
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
.then((result) => {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const daoFactory = result.daoFactory
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
KreditsKit.new(daoFactory.address, ensAddr)
|
||||
|
Are you a javascript pro, now? Are you a javascript pro, now?
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
a pro in being desperate :) a pro in being desperate :)
those scripts are executed in some truffle context and debugging sometimes is a pain because truffle swallows the errors and traces... so I sometimes threw everything on it :D
Much better with a normal function! Much better with a normal function!
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
.catch(console.log)
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
.then((kreditsKit) => {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
console.log(kreditsKit.address)
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
kreditsKit.newInstance().then((ret) => {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
console.log(ret.logs);
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const installedEvents = ret.logs.filter(log => log.event === 'InstalledApp').map(log => log.args)
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const deployEvents = ret.logs.filter(log => log.event === 'DeployInstance').map(log => log.args)
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
if (deployEvents.length > 1) {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
callback(new Error("More than one DAO was deployed. Something is wrong"))
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
}
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const daoAddress = deployEvents[0].dao;
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
const networkId = parseInt(web3.version.network);
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
let addresseFile = path.join(addressesPath, `dao.json`);
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
let addresses = JSON.parse(fs.readFileSync(addresseFile));
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
addresses[networkId] = daoAddress;
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
fs.writeFileSync(addresseFile, JSON.stringify(addresses));
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
callback();
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
}).catch((e) => {
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
console.log(e);
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
})
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
})
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
})
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
}
|
||||
|
What about:
What about:
```js
const KreditsKit = artifacts.require('KreditsKit')
const kreditsKitFile = 'KreditsKit.json'
// ...
let addresseFile = path.join(addressesPath, kreditsKitFile);
```
`const networkId = await getNetworkId(web3);`
Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.) Have you tried the new suggestion feature in these comments? It's pretty useful! (And you'll be credited in the commit.)
|
||||
@ -1,18 +1,16 @@
|
||||
const REPL = require('repl');
|
||||
const promptly = require('promptly');
|
||||
|
||||
const ethers = require('ethers');
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
module.exports = function(callback) {
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
Registry.deployed().then(async (registry) => {
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await Kredits.setup(provider, provider.getSigner());
|
||||
console.log(`defined variables: kredits, web3`);
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
|
||||
new Kredits(provider, provider.getSigner()).init().then((kredits) => {
|
||||
console.log(`Defined variables: kredits, web3`);
|
||||
let r = REPL.start();
|
||||
r.context.kredits = kredits;
|
||||
r.context.web3 = web3;
|
||||
|
||||
73
truffle.js
@ -1,15 +1,68 @@
|
||||
/**
|
||||
* https://github.com/aragon/aragonOS/blob/v4.0.0/truffle-config.js
|
||||
*/
|
||||
const homedir = require('homedir')
|
||||
const path = require('path')
|
||||
|
||||
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||
const HDWalletProviderPrivkey = require('truffle-hdwallet-provider-privkey')
|
||||
|
||||
const DEFAULT_MNEMONIC = 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus'
|
||||
|
||||
const defaultRPC = (network) =>
|
||||
`https://${network}.infura.io`
|
||||
|
||||
const configFilePath = (filename) =>
|
||||
path.join(homedir(), `.aragon/${filename}`)
|
||||
|
||||
const mnemonic = () => {
|
||||
try {
|
||||
return require(configFilePath('mnemonic.json')).mnemonic
|
||||
} catch (e) {
|
||||
return DEFAULT_MNEMONIC
|
||||
}
|
||||
}
|
||||
|
||||
const settingsForNetwork = (network) => {
|
||||
try {
|
||||
return require(configFilePath(`${network}_key.json`))
|
||||
} catch (e) {
|
||||
return { }
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily loaded provider
|
||||
const providerForNetwork = (network) => (
|
||||
() => {
|
||||
let { rpc, keys } = settingsForNetwork(network)
|
||||
rpc = rpc || defaultRPC(network)
|
||||
|
||||
if (!keys || keys.length == 0) {
|
||||
return new HDWalletProvider(mnemonic(), rpc)
|
||||
}
|
||||
|
||||
return new HDWalletProviderPrivkey(keys, rpc)
|
||||
}
|
||||
)
|
||||
module.exports = {
|
||||
// See <http://truffleframework.com/docs/advanced/configuration>
|
||||
networks: {
|
||||
development: {
|
||||
host: "127.0.0.1",
|
||||
port: 7545,
|
||||
network_id: "*" // Match any network id
|
||||
},
|
||||
kovan: {
|
||||
host: "127.0.0.1",
|
||||
rpc: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: "42"
|
||||
network_id: '*'
|
||||
},
|
||||
development: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: '*'
|
||||
},
|
||||
mainnet: {
|
||||
network_id: 1,
|
||||
provider: providerForNetwork('mainnet')
|
||||
},
|
||||
rinkeby: {
|
||||
network_id: 4,
|
||||
provider: providerForNetwork('rinkeby')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
❤️