Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b7e2da8af | |||
| 38893937ec | |||
| f17af2d0ae | |||
|
|
1cfeaec70b
|
||
|
|
44f3128f16
|
||
| c865c154a4 | |||
| a63a37c5d6 | |||
|
20879c4c08
|
|||
| 7ab8e4e52d | |||
|
f11c4f7764
|
|||
|
44cad2d26e
|
|||
| 357698db02 | |||
|
6c80179a3d
|
|||
| c471060cfd | |||
| 7418d33e63 | |||
| 1cfbc09e4a | |||
|
8984ba3802
|
|||
|
2238ccf40e
|
|||
| 0df7930e06 | |||
| eebc0db02b | |||
| b22d16e61e | |||
| 6bc6bcb7f6 | |||
| 9df58b7f9a | |||
| c83a560e3b | |||
| eadca6904a | |||
| 89829ee81f | |||
|
32b212f9cf
|
|||
|
e3c03bf4a0
|
|||
|
7dba0e4501
|
|||
|
e6349f0594
|
|||
|
15b47dbc42
|
|||
| 8f0d7e5196 | |||
| 4add0c7d96 | |||
|
7ad2515b67
|
|||
| fbd82a442e | |||
| c39fe406d0 | |||
| a609d921aa | |||
| 23d3dd3a80 | |||
|
c63fcc002b
|
|||
| bc38dcb136 | |||
|
c4e7e1259e
|
|||
|
17cc44cb98
|
|||
| c2dcedfe58 | |||
| 2c567fa71a | |||
| 9b4a95f375 | |||
| 687f87f43b | |||
| 7fdeb78617 | |||
| 19f212f283 | |||
| 1f248812a7 | |||
| 3f8407fa02 | |||
| a0b0183beb | |||
| 2b99593699 | |||
| 606350eb5e | |||
| a330a8eedf | |||
| 3c72fa3a8b | |||
| a4ef2398be | |||
| 31c29ab6d0 | |||
| ef0c0c0a39 | |||
| 844bdbd681 | |||
| 9d96824fe9 | |||
| d246531cfa | |||
| 6be06b2e57 | |||
| c2220c3654 | |||
| 5044d8fe41 | |||
| 3c49c688d2 | |||
| 47f59126a7 | |||
| 2ce5d925d0 | |||
| 3db89b0fa3 | |||
| 190d3b77d5 | |||
| b7eac4202c | |||
| 93aeea69c6 | |||
| e7700d5ec7 | |||
| c3eced5c1d | |||
| 4c6ed12167 | |||
| 9431bc22a6 | |||
| 78c8052629 | |||
| a318fe8374 | |||
| eded4a811f | |||
| 66a37a1e74 | |||
| aba4a23104 | |||
| 13ed02e134 | |||
| 48ff304861 | |||
| 1c1a318ae6 | |||
| 580d6e8f51 | |||
| a572f02b2e | |||
| abd4caa336 | |||
| f1941eb6b8 | |||
| ddeeb5ffd7 | |||
| ae71691c5b | |||
| 819fbc547a | |||
| 7236b04b4b | |||
| f746470cf6 | |||
|
|
5452cf2dad | ||
| 3c08e3ecfc | |||
| 6e8c994a0a | |||
|
|
fd844a00fd | ||
|
|
eb4e06edf1 | ||
| 4ae17aa36f | |||
| e14cb0a77d | |||
| d92ad83379 | |||
| fa3e99d404 | |||
| 4aa5f3aa89 | |||
| 2316e8f15a |
@@ -28,5 +28,6 @@ module.exports = {
|
|||||||
named: 'always',
|
named: 'always',
|
||||||
asyncArrow: 'always',
|
asyncArrow: 'always',
|
||||||
}],
|
}],
|
||||||
|
'indent': ['error', 2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
.github/release-drafter.yml
vendored
Normal file
4
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
template: |
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
$CHANGES
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
data
|
||||||
build
|
build
|
||||||
flattened_contracts
|
flattened_contracts
|
||||||
node_modules
|
node_modules
|
||||||
|
|||||||
23
.travis.yml
23
.travis.yml
@@ -1,18 +1,37 @@
|
|||||||
---
|
---
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "lts/*"
|
- "12"
|
||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
dist: xenial
|
dist: xenial
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
- apps/contribution/node_modules
|
||||||
|
- apps/contributor/node_modules
|
||||||
|
- apps/proposal/node_modules
|
||||||
|
- apps/token/node_modules
|
||||||
|
- apps/vault/node_modules
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- npm install -g @aragon/cli
|
||||||
|
- npm install -g truffle
|
||||||
- npm install
|
- npm install
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- npm run devchain &
|
||||||
|
- sleep 10
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- npm run lint:wrapper
|
- npm run lint:wrapper
|
||||||
- npm run lint:contract-tests
|
- npm run lint:contract-tests
|
||||||
# - yarn lint:contracts
|
# FIXME Fix tests
|
||||||
|
# - npm run test:token
|
||||||
|
# - npm run test:contributor
|
||||||
|
# - npm run test:contribution
|
||||||
|
# - npm run test:proposal
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
|||||||
47
README.md
47
README.md
@@ -14,6 +14,8 @@ framework](http://truffleframework.com/) for some things.
|
|||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
|
#### App dependencies
|
||||||
|
|
||||||
All requirements are defined in `package.json`.
|
All requirements are defined in `package.json`.
|
||||||
|
|
||||||
$ npm install
|
$ npm install
|
||||||
@@ -25,13 +27,23 @@ Each of the aragon apps are separate packages:
|
|||||||
|
|
||||||
You can use `npm run install-all` to install all app dependencies at once.
|
You can use `npm run install-all` to install all app dependencies at once.
|
||||||
|
|
||||||
|
#### Sytem dependencies
|
||||||
|
|
||||||
|
Aragon CLI and Truffle need to be installed on your sytem as well:
|
||||||
|
|
||||||
|
npm install -g @aragon/cli
|
||||||
|
npm install -g truffle
|
||||||
|
|
||||||
|
_Note: `@aragon/cli` currently fails to install on node.js 14. Please use
|
||||||
|
node.js 12 until the issue has been resolved upstream._
|
||||||
|
|
||||||
### Local development chain
|
### Local development chain
|
||||||
|
|
||||||
For local development it is recommended to use
|
For local development it is recommended to use
|
||||||
[ganache](http://truffleframework.com/ganache/) to run a local development
|
[ganache](http://truffleframework.com/ganache/) to run a local development
|
||||||
chain. Using the ganache simulator no full Ethereum node is required.
|
chain. When using the ganache simulator, no full Ethereum node is required.
|
||||||
|
|
||||||
We use the default aragon-cli devchain command to confgure and run a local
|
We use the default aragon-cli devchain command to configure and run a local
|
||||||
development ganache.
|
development ganache.
|
||||||
|
|
||||||
$ npm run devchain (or aragon devchain --port 7545)
|
$ npm run devchain (or aragon devchain --port 7545)
|
||||||
@@ -43,6 +55,10 @@ To clear/reset the chain use (e.g. if you run out of funds on your devchain)
|
|||||||
We default to port 7545 for development to not get in conflict with the default
|
We default to port 7545 for development to not get in conflict with the default
|
||||||
Ethereum RPC port.
|
Ethereum RPC port.
|
||||||
|
|
||||||
|
You can also set certain ganache options to configure the devchain, for example
|
||||||
|
if you want to increase the block time to 10 seconds you can add
|
||||||
|
`--block-time=10`.
|
||||||
|
|
||||||
### Bootstrap
|
### Bootstrap
|
||||||
|
|
||||||
1. Run an Ethereum node and ipfs
|
1. Run an Ethereum node and ipfs
|
||||||
@@ -50,21 +66,26 @@ Ethereum RPC port.
|
|||||||
$ npm run devchain
|
$ npm run devchain
|
||||||
$ ipfs daemon
|
$ ipfs daemon
|
||||||
|
|
||||||
2. Deploy each app to the devchain
|
2. Compile contracts
|
||||||
|
|
||||||
|
(compiled contracts will be in `/build`)
|
||||||
|
$ npm run compile-contracts
|
||||||
|
|
||||||
|
3. Deploy each app to the devchain
|
||||||
|
|
||||||
(make sure you've run `npm install` for every app - see installation)
|
(make sure you've run `npm install` for every app - see installation)
|
||||||
$ npm run deploy:apps
|
$ npm run deploy:apps
|
||||||
|
|
||||||
3. Deploy a new KreditsKit and create a new DAO with the latest app versions
|
4. Deploy a new KreditsKit and create a new DAO with the latest app versions
|
||||||
|
|
||||||
$ npm run deploy:kit
|
$ npm run deploy:kit
|
||||||
$ npm run deploy:dao
|
$ npm run deploy:dao
|
||||||
|
|
||||||
4. Execute seeds to create demo contributors, contributons, etc. (optional)
|
5. Execute seeds to create demo contributors, contributions, etc. (optional)
|
||||||
|
|
||||||
$ npm run seeds
|
$ npm run seeds
|
||||||
|
|
||||||
**Step 2-4 is also summarized in `npm run bootstrap`**
|
**Step 2-5 is also summarized in `npm run bootstrap`**
|
||||||
|
|
||||||
If you want to reset your local setup:
|
If you want to reset your local setup:
|
||||||
|
|
||||||
@@ -152,8 +173,14 @@ Deploys a new KreditsKit that allows to create a new DAO
|
|||||||
or
|
or
|
||||||
$ npm run deploy:kit
|
$ npm run deploy:kit
|
||||||
|
|
||||||
`ENS` address is required as environment variable.
|
#### Kredits configuration options:
|
||||||
`DAO_FACTORY` can optionally be set as environment variable. (see aragon)
|
|
||||||
|
Configuration options can be set in an environment specific `kredits` object in the `arapp.json` or using a CLI parameter.
|
||||||
|
|
||||||
|
* daoFactory: Ethereum address of the used DAO Factory. On public networks we use [official aragon factories](https://github.com/aragon/deployments/tree/master/environments/)
|
||||||
|
* apmDomain: the ENS domain of the aragonPM (normally `open.aragonpm.eth`)
|
||||||
|
|
||||||
|
(please also see the [arapp.json related configuration options](https://hack.aragon.org/docs/cli-global-confg#the-arappjson-file))
|
||||||
|
|
||||||
### new-dao.js
|
### new-dao.js
|
||||||
|
|
||||||
@@ -163,7 +190,7 @@ Creates and configures a new DAO instance.
|
|||||||
or
|
or
|
||||||
$ npm run deploy:dao
|
$ npm run deploy:dao
|
||||||
|
|
||||||
KreditsKit address is load from `lib/addresses/KreditsKit.json` or can be
|
KreditsKit address is loaded from `lib/addresses/KreditsKit.json` or can be
|
||||||
configured through the `KREDITS_KIT` environment variable.
|
configured through the `KREDITS_KIT` environment variable.
|
||||||
|
|
||||||
### deploy-apps.sh
|
### deploy-apps.sh
|
||||||
@@ -198,7 +225,7 @@ make sure all apps and the KreditsKit are deployed, then create a new DAO:
|
|||||||
|
|
||||||
## Upgradeable contracts
|
## Upgradeable contracts
|
||||||
|
|
||||||
We use aragonOS for upgradeablity of the different contracts. Refer to the
|
We use aragonOS for upgradeability of the different contracts. Refer to the
|
||||||
[aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro)
|
[aragonOS upgradeablity documentation](https://hack.aragon.org/docs/upgradeability-intro)
|
||||||
for more details.
|
for more details.
|
||||||
|
|
||||||
|
|||||||
@@ -1,912 +0,0 @@
|
|||||||
{
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"name": "Add contributions",
|
|
||||||
"id": "ADD_CONTRIBUTION_ROLE",
|
|
||||||
"params": [],
|
|
||||||
"bytes": "0x493d28cd0d82bcb20db66e4f6390a00122ef772717e282b436ba3240af18bfb1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Manage token contract",
|
|
||||||
"id": "MANAGE_TOKEN_CONTRACT_ROLE",
|
|
||||||
"params": [],
|
|
||||||
"bytes": "0xdd275187bc43df45ce7b34f6716e572716c69ad44e5e496175008950f032854b"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Veto contributions",
|
|
||||||
"id": "VETO_CONTRIBUTION_ROLE",
|
|
||||||
"params": [],
|
|
||||||
"bytes": "0x495a36de1ed34d5c1b9f8704e7d8bc8badb027221b09c79691d430bc54c4c88f"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"environments": {
|
|
||||||
"default": {
|
|
||||||
"network": "development",
|
|
||||||
"appName": "kredits-contribution.open.aragonpm.eth"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path": "contracts/Contribution.sol",
|
|
||||||
"appName": "kredits-contribution.open.aragonpm.eth",
|
|
||||||
"appId": "0x09f5274cba299b46c5be722ef672d10eef7a2ef980b612aef529d74fb9da7643",
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "hasInitialized",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "ADD_CONTRIBUTION_ROLE",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"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": "contributionsCount",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"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": "getInitializationBlock",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "KERNEL_APP_ADDR_NAMESPACE",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"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": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "contributionOwner",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "contributions",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "claimed",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashDigest",
|
|
||||||
"type": "bytes32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashFunction",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashSize",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tokenMetadataURL",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "confirmedAtBlock",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "vetoed",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ownedContributions",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"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": "blocksToWait",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "isPetrified",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "appIds",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "VETO_CONTRIBUTION_ROLE",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "id",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ContributionAdded",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "id",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ContributionClaimed",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "id",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "vetoedByAccount",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ContributionVetoed",
|
|
||||||
"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": "_appIds",
|
|
||||||
"type": "bytes32[4]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "initialize",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "getTokenContract",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "getContributorContract",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributorAccount",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "getContributorIdByAddress",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "getContributorAddressById",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "name",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "symbol",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "balanceOf",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributionId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ownerOf",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "tokenOfOwnerByIndex",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributionId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "tokenMetadata",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "confirmedOnly",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "totalKreditsEarned",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "confirmedOnly",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "totalKreditsEarnedByContributor",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributionId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "getContribution",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "id",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "claimed",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashDigest",
|
|
||||||
"type": "bytes32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashFunction",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashSize",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "confirmedAtBlock",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "vetoed",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "contributorId",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashDigest",
|
|
||||||
"type": "bytes32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashFunction",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hashSize",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "add",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributionId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "veto",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributionId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "claim",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "contributionId",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "exists",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"deployment": {
|
|
||||||
"contractName": "Contribution",
|
|
||||||
"compiledAt": "2019-06-13T12:39:07.659Z",
|
|
||||||
"compiler": {
|
|
||||||
"name": "solc",
|
|
||||||
"version": "0.4.24+commit.e67f0147.Emscripten.clang",
|
|
||||||
"optimizer": {
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flattenedCode": "./code.sol",
|
|
||||||
"transactionHash": "0x073057bb616243e415823fa9a8c8cc096b573fbd0bbf11c2f59bb75a84291689"
|
|
||||||
},
|
|
||||||
"functions": [
|
|
||||||
{
|
|
||||||
"sig": "mintFor(address,uint256,uint32)",
|
|
||||||
"roles": [],
|
|
||||||
"notice": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sig": "initialize(bytes32[4])",
|
|
||||||
"roles": [],
|
|
||||||
"notice": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sig": "add(uint32,uint32,bytes32,uint8,uint8)",
|
|
||||||
"roles": [
|
|
||||||
"ADD_CONTRIBUTION_ROLE"
|
|
||||||
],
|
|
||||||
"notice": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sig": "veto(uint32)",
|
|
||||||
"roles": [
|
|
||||||
"VETO_CONTRIBUTION_ROLE"
|
|
||||||
],
|
|
||||||
"notice": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sig": "claim(uint32)",
|
|
||||||
"roles": [],
|
|
||||||
"notice": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -21,8 +21,8 @@ contract Contribution is AragonApp {
|
|||||||
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
||||||
|
|
||||||
// ensure alphabetic order
|
// ensure alphabetic order
|
||||||
enum Apps { Contribution, Contributor, Proposal, Token }
|
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
|
||||||
bytes32[4] public appIds;
|
bytes32[5] public appIds;
|
||||||
|
|
||||||
struct ContributionData {
|
struct ContributionData {
|
||||||
uint32 contributorId;
|
uint32 contributorId;
|
||||||
@@ -54,30 +54,25 @@ contract Contribution is AragonApp {
|
|||||||
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
|
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
|
||||||
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
||||||
|
|
||||||
function initialize(bytes32[4] _appIds) public onlyInit {
|
function initialize(bytes32[5] _appIds) public onlyInit {
|
||||||
appIds = _appIds;
|
appIds = _appIds;
|
||||||
blocksToWait = 40320; // 7 days; 15 seconds block time
|
blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||||
initialized();
|
initialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO refactor into a single function
|
function getContract(uint8 appId) public view returns (address) {
|
||||||
function getTokenContract() public view returns (address) {
|
|
||||||
IKernel k = IKernel(kernel());
|
IKernel k = IKernel(kernel());
|
||||||
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]);
|
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
|
||||||
}
|
|
||||||
function getContributorContract() public view returns (address) {
|
|
||||||
IKernel k = IKernel(kernel());
|
|
||||||
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contributor)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
|
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
|
||||||
address contributor = getContributorContract();
|
address contributorContract = getContract(uint8(Apps.Contributor));
|
||||||
return ContributorInterface(contributor).getContributorIdByAddress(contributorAccount);
|
return ContributorInterface(contributorContract).getContributorIdByAddress(contributorAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContributorAddressById(uint32 contributorId) public view returns (address) {
|
function getContributorAddressById(uint32 contributorId) public view returns (address) {
|
||||||
address contributor = getContributorContract();
|
address contributorContract = getContract(uint8(Apps.Contributor));
|
||||||
return ContributorInterface(contributor).getContributorAddressById(contributorId);
|
return ContributorInterface(contributorContract).getContributorAddressById(contributorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -169,7 +164,7 @@ contract Contribution is AragonApp {
|
|||||||
if (contributionId < 10) {
|
if (contributionId < 10) {
|
||||||
c.confirmedAtBlock = block.number;
|
c.confirmedAtBlock = block.number;
|
||||||
} else {
|
} else {
|
||||||
c.confirmedAtBlock = block.number + blocksToWait;
|
c.confirmedAtBlock = block.number + 1 + blocksToWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
contributionsCount++;
|
contributionsCount++;
|
||||||
@@ -198,14 +193,14 @@ contract Contribution is AragonApp {
|
|||||||
require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE');
|
require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE');
|
||||||
|
|
||||||
c.claimed = true;
|
c.claimed = true;
|
||||||
address token = getTokenContract();
|
address tokenContract = getContract(uint8(Apps.Token));
|
||||||
address contributorAccount = getContributorAddressById(c.contributorId);
|
address contributorAccount = getContributorAddressById(c.contributorId);
|
||||||
uint256 amount = uint256(c.amount);
|
uint256 amount = uint256(c.amount);
|
||||||
IToken(token).mintFor(contributorAccount, amount, contributionId);
|
IToken(tokenContract).mintFor(contributorAccount, amount, contributionId);
|
||||||
emit ContributionClaimed(contributionId, c.contributorId, c.amount);
|
emit ContributionClaimed(contributionId, c.contributorId, c.amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function exists(uint32 contributionId) view public returns (bool) {
|
function exists(uint32 contributionId) public view returns (bool) {
|
||||||
return contributions[contributionId].exists;
|
return contributions[contributionId].exists;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28809
apps/contribution/package-lock.json
generated
28809
apps/contribution/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,12 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aragon/os": "^4.2.0",
|
"@aragon/os": "^4.4.0"
|
||||||
"@aragon/cli": "^5.9.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aragon/test-helpers": "^1.1.0",
|
"@aragon/test-helpers": "^2.1.0",
|
||||||
"eth-gas-reporter": "^0.2.0",
|
"eth-gas-reporter": "^0.2.17",
|
||||||
"ganache-cli": "^6.4.3",
|
"ganache-cli": "^6.9.1",
|
||||||
"solidity-coverage": "^0.5.11"
|
"solidity-coverage": "^0.5.11"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,10 +25,7 @@
|
|||||||
"publish:minor": "aragon apm publish minor",
|
"publish:minor": "aragon apm publish minor",
|
||||||
"publish:major": "aragon apm publish major",
|
"publish:major": "aragon apm publish major",
|
||||||
"versions": "aragon apm versions",
|
"versions": "aragon apm versions",
|
||||||
"test": "TRUFFLE_TEST=true PORT=7545 npm run ganache-cli:test",
|
"test": "truffle test"
|
||||||
"test:gas": "GAS_REPORTER=true npm test",
|
|
||||||
"coverage": "SOLIDITY_COVERAGE=true npm run ganache-cli:test",
|
|
||||||
"ganache-cli:test": "./node_modules/@aragon/test-helpers/ganache-cli.sh"
|
|
||||||
},
|
},
|
||||||
"keywords": []
|
"keywords": []
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -28,32 +28,25 @@ contract Contributor is AragonApp {
|
|||||||
uint32 public contributorsCount;
|
uint32 public contributorsCount;
|
||||||
|
|
||||||
// ensure alphabetic order
|
// ensure alphabetic order
|
||||||
enum Apps { Contribution, Contributor, Proposal, Token }
|
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
|
||||||
bytes32[4] public appIds;
|
bytes32[5] public appIds;
|
||||||
|
|
||||||
event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged
|
event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged
|
||||||
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
|
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
|
||||||
event ContributorAdded(uint32 id, address account);
|
event ContributorAdded(uint32 id, address account);
|
||||||
|
|
||||||
function initialize(address root,bytes32[4] _appIds) public onlyInit {
|
function initialize(address root, bytes32[5] _appIds) public onlyInit {
|
||||||
appIds = _appIds;
|
appIds = _appIds;
|
||||||
|
|
||||||
initialized();
|
initialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTokenContract() public view returns (address) {
|
function getContract(uint8 appId) public view returns (address) {
|
||||||
IKernel k = IKernel(kernel());
|
IKernel k = IKernel(kernel());
|
||||||
|
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
|
||||||
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContributionContract() public view returns (address) {
|
function coreContributorsCount() public view returns (uint32) {
|
||||||
IKernel k = IKernel(kernel());
|
|
||||||
|
|
||||||
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contribution)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function coreContributorsCount() view public returns (uint32) {
|
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
for (uint32 i = 1; i <= contributorsCount; i++) {
|
for (uint32 i = 1; i <= contributorsCount; i++) {
|
||||||
if (isCoreTeam(i)) {
|
if (isCoreTeam(i)) {
|
||||||
@@ -64,10 +57,13 @@ contract Contributor is AragonApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public auth(MANAGE_CONTRIBUTORS_ROLE) {
|
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public auth(MANAGE_CONTRIBUTORS_ROLE) {
|
||||||
|
require(newAccount != address(0), "invalid new account address");
|
||||||
|
require(getContributorAddressById(id) == oldAccount, "contributor does not exist");
|
||||||
|
|
||||||
contributorIds[oldAccount] = 0;
|
contributorIds[oldAccount] = 0;
|
||||||
contributorIds[newAccount] = id;
|
contributorIds[newAccount] = id;
|
||||||
contributors[id].account = newAccount;
|
contributors[id].account = newAccount;
|
||||||
ContributorAccountUpdated(id, oldAccount, newAccount);
|
emit ContributorAccountUpdated(id, oldAccount, newAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
|
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(MANAGE_CONTRIBUTORS_ROLE) {
|
||||||
@@ -136,9 +132,9 @@ contract Contributor is AragonApp {
|
|||||||
hashFunction = c.hashFunction;
|
hashFunction = c.hashFunction;
|
||||||
hashSize = c.hashSize;
|
hashSize = c.hashSize;
|
||||||
isCore = isCoreTeam(id);
|
isCore = isCoreTeam(id);
|
||||||
address token = getTokenContract();
|
address token = getContract(uint8(Apps.Token));
|
||||||
balance = ITokenBalance(token).balanceOf(c.account);
|
balance = ITokenBalance(token).balanceOf(c.account);
|
||||||
address contribution = getContributionContract();
|
address contribution = getContract(uint8(Apps.Contribution));
|
||||||
totalKreditsEarned = IContributionBalance(contribution).totalKreditsEarnedByContributor(_id, true);
|
totalKreditsEarned = IContributionBalance(contribution).totalKreditsEarnedByContributor(_id, true);
|
||||||
contributionsCount = IContributionBalance(contribution).balanceOf(c.account);
|
contributionsCount = IContributionBalance(contribution).balanceOf(c.account);
|
||||||
exists = c.exists;
|
exists = c.exists;
|
||||||
|
|||||||
16
apps/contributor/contracts/test/Spoof.sol
Normal file
16
apps/contributor/contracts/test/Spoof.sol
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/acl/ACL.sol";
|
||||||
|
import "@aragon/os/contracts/kernel/Kernel.sol";
|
||||||
|
import "@aragon/os/contracts/factory/DAOFactory.sol";
|
||||||
|
|
||||||
|
// You might think this file is a bit odd, but let me explain.
|
||||||
|
// We only use for now those imported contracts in our tests, which
|
||||||
|
// means Truffle will not compile them for us, because they are from
|
||||||
|
// an external dependency.
|
||||||
|
|
||||||
|
|
||||||
|
// solium-disable-next-line no-empty-blocks
|
||||||
|
contract Spoof {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
28809
apps/contributor/package-lock.json
generated
28809
apps/contributor/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,12 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aragon/os": "^4.2.0",
|
"@aragon/os": "^4.4.0"
|
||||||
"@aragon/cli": "^5.9.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aragon/test-helpers": "^1.1.0",
|
"@aragon/test-helpers": "^2.1.0",
|
||||||
"eth-gas-reporter": "^0.2.0",
|
"eth-gas-reporter": "^0.2.17",
|
||||||
"ganache-cli": "^6.4.3",
|
"ganache-cli": "^6.9.1",
|
||||||
"solidity-coverage": "^0.5.11"
|
"solidity-coverage": "^0.5.11"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,10 +25,7 @@
|
|||||||
"publish:minor": "aragon apm publish minor",
|
"publish:minor": "aragon apm publish minor",
|
||||||
"publish:major": "aragon apm publish major",
|
"publish:major": "aragon apm publish major",
|
||||||
"versions": "aragon apm versions",
|
"versions": "aragon apm versions",
|
||||||
"test": "TRUFFLE_TEST=true PORT=7545 npm run ganache-cli:test",
|
"test": "truffle test"
|
||||||
"test:gas": "GAS_REPORTER=true npm test",
|
|
||||||
"coverage": "SOLIDITY_COVERAGE=true npm run ganache-cli:test",
|
|
||||||
"ganache-cli:test": "./node_modules/@aragon/test-helpers/ganache-cli.sh"
|
|
||||||
},
|
},
|
||||||
"keywords": []
|
"keywords": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
// const Contributor = artifacts.require('Contributor.sol');
|
|
||||||
|
|
||||||
contract('Contributor', (_accounts) => {
|
|
||||||
it('should be tested');
|
|
||||||
});
|
|
||||||
170
apps/contributor/test/contributor.js
Normal file
170
apps/contributor/test/contributor.js
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
const namehash = require('ethers').utils.namehash;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const Contributor = artifacts.require("Contributor.sol");
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const getContract = name => artifacts.require(name);
|
||||||
|
const { assertRevert } = require('@aragon/test-helpers/assertThrow');
|
||||||
|
|
||||||
|
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
|
||||||
|
|
||||||
|
contract('Contributor app', (accounts) => {
|
||||||
|
let kernelBase, aclBase, daoFactory, r, dao, acl, contributor;
|
||||||
|
|
||||||
|
const root = accounts[0];
|
||||||
|
const member1 = accounts[1];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
before(async () => {
|
||||||
|
kernelBase = await getContract('Kernel').new(true); // petrify immediately
|
||||||
|
aclBase = await getContract('ACL').new();
|
||||||
|
daoFactory = await getContract('DAOFactory').new(kernelBase.address, aclBase.address, ZERO_ADDR);
|
||||||
|
r = await daoFactory.newDAO(root);
|
||||||
|
dao = await getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao);
|
||||||
|
acl = await getContract('ACL').at(await dao.acl());
|
||||||
|
|
||||||
|
//create dao mamnager permission for coin owner
|
||||||
|
await acl.createPermission(
|
||||||
|
root,
|
||||||
|
dao.address,
|
||||||
|
await dao.APP_MANAGER_ROLE(),
|
||||||
|
root,
|
||||||
|
{ from: root }
|
||||||
|
);
|
||||||
|
|
||||||
|
//get new app instance from DAO
|
||||||
|
const receipt = await dao.newAppInstance(
|
||||||
|
'0x1234',
|
||||||
|
(await Contributor.new()).address,
|
||||||
|
0x0,
|
||||||
|
false,
|
||||||
|
{ from: root }
|
||||||
|
);
|
||||||
|
contributor = Contributor.at(
|
||||||
|
receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
|
||||||
|
);
|
||||||
|
|
||||||
|
//apps id
|
||||||
|
let appsId = [];
|
||||||
|
appsId[0] = namehash("kredits-contribution");
|
||||||
|
appsId[1] = namehash("kredits-contributor");
|
||||||
|
appsId[2] = namehash("kredits-proposal");
|
||||||
|
appsId[3] = namehash("kredits-token");
|
||||||
|
|
||||||
|
//init contributor (app)
|
||||||
|
await contributor.initialize(root, appsId);
|
||||||
|
|
||||||
|
//create manage contributors role
|
||||||
|
await acl.createPermission(
|
||||||
|
root,
|
||||||
|
contributor.address,
|
||||||
|
await contributor.MANAGE_CONTRIBUTORS_ROLE(),
|
||||||
|
root,
|
||||||
|
{ from: root }
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Owner default permissions", async () => {
|
||||||
|
it('check owner is contributors manager', async () => {
|
||||||
|
let manageContributorPermission = await acl.hasPermission(root, contributor.address, await contributor.MANAGE_CONTRIBUTORS_ROLE());
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
assert.equal(manageContributorPermission, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Add contributor", async () => {
|
||||||
|
let account = root;
|
||||||
|
let hashDigest = '0x0';
|
||||||
|
let hashFunction = 0;
|
||||||
|
let hashSize = 0;
|
||||||
|
|
||||||
|
it("should revert when add contributor from an address that does not have permission", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await contributor.addContributor(account, hashDigest, hashFunction, hashSize, { from: member1});
|
||||||
|
'sender does not have permission';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('add contributor', async () => {
|
||||||
|
let contributorCount = await contributor.coreContributorsCount();
|
||||||
|
await contributor.addContributor(account, hashDigest, hashFunction, hashSize);
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
assert.equal(await contributor.addressExists(account), true);
|
||||||
|
let contributorCountAfter = await contributor.coreContributorsCount();
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
assert.equal(await contributorCountAfter.toNumber(), parseInt(contributorCount)+1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when add contributor with an address that already exist", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await contributor.addContributor(account, hashDigest, hashFunction, hashSize, { from: member1});
|
||||||
|
'address already exist';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Update contributor", async () => {
|
||||||
|
let id;
|
||||||
|
let oldAccount;
|
||||||
|
let newAccount;
|
||||||
|
let hashDigest;
|
||||||
|
let hashFunction;
|
||||||
|
let hashSize;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
before(async () => {
|
||||||
|
id = await contributor.coreContributorsCount();
|
||||||
|
oldAccount = root;
|
||||||
|
newAccount = member1;
|
||||||
|
hashDigest = '0x1000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
hashFunction = 1;
|
||||||
|
hashSize = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('update contributor account', async () => {
|
||||||
|
await contributor.updateContributorAccount(id.toNumber(), oldAccount, newAccount);
|
||||||
|
let contributorId = await contributor.getContributorIdByAddress(oldAccount);
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
assert.equal(contributorId.toNumber(), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when update contributor account from address that does not have permission", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await contributor.updateContributorAccount(id.toNumber(), oldAccount, newAccount, {from: member1});
|
||||||
|
'sender does not have permission';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when update contributor account that does not exist", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await contributor.updateContributorAccount(id.toNumber(), accounts[3], newAccount);
|
||||||
|
'contributor does not exist';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when update contributor account with address(0)", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await contributor.updateContributorAccount(id.toNumber(), oldAccount, ZERO_ADDR);
|
||||||
|
'contributor does not exist';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('update contributor profile hash', async () => {
|
||||||
|
await contributor.updateContributorProfileHash(id.toNumber(), hashDigest, hashFunction, hashSize);
|
||||||
|
let contributorProfile = await contributor.contributors(id.toNumber());
|
||||||
|
assert.equal(hashDigest, contributorProfile[1]); // eslint-disable-line no-undef
|
||||||
|
assert.equal(hashFunction, contributorProfile[2].toNumber()); // eslint-disable-line no-undef
|
||||||
|
assert.equal(hashSize, contributorProfile[3].toNumber()); // eslint-disable-line no-undef
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when update contributor profile hash from address that does not have permission", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await contributor.updateContributorProfileHash(id.toNumber(), hashDigest, hashFunction, hashSize, {from: member1});
|
||||||
|
'sender does not have permission';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,8 @@ contract Proposal is AragonApp {
|
|||||||
|
|
||||||
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
||||||
// ensure alphabetic order
|
// ensure alphabetic order
|
||||||
enum Apps { Contribution, Contributor, Proposal, Token }
|
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
|
||||||
bytes32[4] public appIds;
|
bytes32[5] public appIds;
|
||||||
|
|
||||||
struct Proposal {
|
struct Proposal {
|
||||||
address creatorAccount;
|
address creatorAccount;
|
||||||
@@ -46,21 +46,18 @@ contract Proposal is AragonApp {
|
|||||||
event ProposalVoted(uint32 id, uint32 voterId, uint16 totalVotes);
|
event ProposalVoted(uint32 id, uint32 voterId, uint16 totalVotes);
|
||||||
event ProposalExecuted(uint32 id, uint32 contributorId, uint32 amount);
|
event ProposalExecuted(uint32 id, uint32 contributorId, uint32 amount);
|
||||||
|
|
||||||
function initialize(bytes32[4] _appIds) public onlyInit {
|
function initialize(bytes32[5] _appIds) public onlyInit {
|
||||||
appIds = _appIds;
|
appIds = _appIds;
|
||||||
initialized();
|
initialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContributorContract() public view returns (address) {
|
function getContract(uint8 appId) public view returns (address) {
|
||||||
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contributor)]);
|
IKernel k = IKernel(kernel());
|
||||||
}
|
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[appId]);
|
||||||
|
|
||||||
function getContributionContract() public view returns (address) {
|
|
||||||
return IKernel(kernel()).getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contribution)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addProposal(uint32 contributorId, uint32 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_PROPOSAL_ROLE) {
|
function addProposal(uint32 contributorId, uint32 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_PROPOSAL_ROLE) {
|
||||||
require(IContributor(getContributorContract()).exists(contributorId), 'CONTRIBUTOR_NOT_FOUND');
|
require(IContributor(getContract(uint8(Apps.Contributor))).exists(contributorId), 'CONTRIBUTOR_NOT_FOUND');
|
||||||
|
|
||||||
uint32 proposalId = proposalsCount + 1;
|
uint32 proposalId = proposalsCount + 1;
|
||||||
uint16 _votesNeeded = 1; //contributorsContract().coreContributorsCount() / 100 * 75;
|
uint16 _votesNeeded = 1; //contributorsContract().coreContributorsCount() / 100 * 75;
|
||||||
@@ -69,10 +66,10 @@ contract Proposal is AragonApp {
|
|||||||
p.creatorAccount = msg.sender;
|
p.creatorAccount = msg.sender;
|
||||||
p.contributorId = contributorId;
|
p.contributorId = contributorId;
|
||||||
p.amount = amount;
|
p.amount = amount;
|
||||||
p.hashDigest = hashDigest;
|
p.hashDigest = hashDigest;
|
||||||
p.hashFunction = hashFunction;
|
p.hashFunction = hashFunction;
|
||||||
p.hashSize = hashSize;
|
p.hashSize = hashSize;
|
||||||
p.votesCount = 0;
|
p.votesCount = 0;
|
||||||
p.votesNeeded = _votesNeeded;
|
p.votesNeeded = _votesNeeded;
|
||||||
p.exists = true;
|
p.exists = true;
|
||||||
|
|
||||||
@@ -102,7 +99,7 @@ contract Proposal is AragonApp {
|
|||||||
function vote(uint32 proposalId) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
|
function vote(uint32 proposalId) public isInitialized auth(VOTE_PROPOSAL_ROLE) {
|
||||||
Proposal storage p = proposals[proposalId];
|
Proposal storage p = proposals[proposalId];
|
||||||
require(!p.executed, 'ALREADY_EXECUTED');
|
require(!p.executed, 'ALREADY_EXECUTED');
|
||||||
uint32 voterId = IContributor(getContributorContract()).getContributorIdByAddress(msg.sender);
|
uint32 voterId = IContributor(getContract(uint8(Apps.Contributor))).getContributorIdByAddress(msg.sender);
|
||||||
require(p.votes[voterId] != true, 'ALREADY_VOTED');
|
require(p.votes[voterId] != true, 'ALREADY_VOTED');
|
||||||
p.voterIds.push(voterId);
|
p.voterIds.push(voterId);
|
||||||
p.votes[voterId] = true;
|
p.votes[voterId] = true;
|
||||||
@@ -126,7 +123,7 @@ contract Proposal is AragonApp {
|
|||||||
require(p.votesCount >= p.votesNeeded, 'MISSING_VOTES');
|
require(p.votesCount >= p.votesNeeded, 'MISSING_VOTES');
|
||||||
|
|
||||||
p.executed = true;
|
p.executed = true;
|
||||||
IContribution(getContributionContract()).add(p.amount, p.contributorId, p.hashDigest, p.hashFunction, p.hashSize);
|
IContribution(getContract(uint8(Apps.Contribution))).add(p.amount, p.contributorId, p.hashDigest, p.hashFunction, p.hashSize);
|
||||||
emit ProposalExecuted(proposalId, p.contributorId, p.amount);
|
emit ProposalExecuted(proposalId, p.contributorId, p.amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28809
apps/proposal/package-lock.json
generated
28809
apps/proposal/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,12 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aragon/os": "^4.2.0",
|
"@aragon/os": "^4.4.0"
|
||||||
"@aragon/cli": "^5.9.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aragon/test-helpers": "^1.1.0",
|
"@aragon/test-helpers": "^2.1.0",
|
||||||
"eth-gas-reporter": "^0.2.0",
|
"eth-gas-reporter": "^0.2.17",
|
||||||
"ganache-cli": "^6.4.3",
|
"ganache-cli": "^6.9.1",
|
||||||
"solidity-coverage": "^0.5.11"
|
"solidity-coverage": "^0.5.11"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,10 +25,7 @@
|
|||||||
"publish:minor": "aragon apm publish minor",
|
"publish:minor": "aragon apm publish minor",
|
||||||
"publish:major": "aragon apm publish major",
|
"publish:major": "aragon apm publish major",
|
||||||
"versions": "aragon apm versions",
|
"versions": "aragon apm versions",
|
||||||
"test": "TRUFFLE_TEST=true PORT=7545 npm run ganache-cli:test",
|
"test": "truffle test"
|
||||||
"test:gas": "GAS_REPORTER=true npm test",
|
|
||||||
"coverage": "SOLIDITY_COVERAGE=true npm run ganache-cli:test",
|
|
||||||
"ganache-cli:test": "./node_modules/@aragon/test-helpers/ganache-cli.sh"
|
|
||||||
},
|
},
|
||||||
"keywords": []
|
"keywords": []
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1
apps/reimbursement/.gitattributes
vendored
Normal file
1
apps/reimbursement/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.sol linguist-language=Solidity
|
||||||
7
apps/reimbursement/.gitignore
vendored
Normal file
7
apps/reimbursement/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
artifacts
|
||||||
|
.cache
|
||||||
|
cache
|
||||||
|
dist
|
||||||
|
ipfs.cmd
|
||||||
|
package-lock.json
|
||||||
34
apps/reimbursement/arapp.json
Normal file
34
apps/reimbursement/arapp.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "Add reimursements",
|
||||||
|
"id": "ADD_REIMBURSEMENT_ROLE",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Veto reimbursement",
|
||||||
|
"id": "VETO_REIMBURSEMENT_ROLE",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environments": {
|
||||||
|
"default": {
|
||||||
|
"network": "development",
|
||||||
|
"appName": "kredits-reimbursement.open.aragonpm.eth"
|
||||||
|
},
|
||||||
|
"rinkeby": {
|
||||||
|
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
|
||||||
|
"appName": "kredits-reimbursement.open.aragonpm.eth",
|
||||||
|
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
|
||||||
|
"network": "rinkeby"
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
|
||||||
|
"appName": "kredits-reimbursement.aragonpm.eth",
|
||||||
|
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
|
||||||
|
"network": "mainnet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"appName": "kredits-reimbursement.aragonpm.eth",
|
||||||
|
"path": "contracts/Reimbursement.sol"
|
||||||
|
}
|
||||||
34
apps/reimbursement/buidler.config.js
Normal file
34
apps/reimbursement/buidler.config.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
const { usePlugin } = require('@nomiclabs/buidler/config')
|
||||||
|
const hooks = require('./scripts/buidler-hooks')
|
||||||
|
|
||||||
|
usePlugin('@aragon/buidler-aragon')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Default Buidler configurations. Read more about it at https://buidler.dev/config/
|
||||||
|
defaultNetwork: 'localhost',
|
||||||
|
networks: {
|
||||||
|
localhost: {
|
||||||
|
url: 'http://localhost:8545',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
solc: {
|
||||||
|
version: '0.4.24',
|
||||||
|
optimizer: {
|
||||||
|
enabled: true,
|
||||||
|
runs: 10000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Etherscan plugin configuration. Learn more at https://github.com/nomiclabs/buidler/tree/master/packages/buidler-etherscan
|
||||||
|
etherscan: {
|
||||||
|
apiKey: '', // API Key for smart contract verification. Get yours at https://etherscan.io/apis
|
||||||
|
},
|
||||||
|
// Aragon plugin configuration
|
||||||
|
aragon: {
|
||||||
|
appServePort: 8001,
|
||||||
|
clientServePort: 3000,
|
||||||
|
appSrcPath: 'app/',
|
||||||
|
appBuildOutputPath: 'dist/',
|
||||||
|
appName: 'expenses',
|
||||||
|
hooks, // Path to script hooks
|
||||||
|
},
|
||||||
|
}
|
||||||
94
apps/reimbursement/contracts/Reimbursement.sol
Normal file
94
apps/reimbursement/contracts/Reimbursement.sol
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
|
import "@aragon/os/contracts/kernel/IKernel.sol";
|
||||||
|
|
||||||
|
contract Reimbursement is AragonApp {
|
||||||
|
bytes32 public constant ADD_REIMBURSEMENT_ROLE = keccak256("ADD_REIMBURSEMENT_ROLE");
|
||||||
|
bytes32 public constant VETO_REIMBURSEMENT_ROLE = keccak256("VETO_REIMBURSEMENT_ROLE");
|
||||||
|
// bytes32 public constant MANAGE_APPS_ROLE = keccak256("MANAGE_APPS_ROLE");
|
||||||
|
|
||||||
|
struct ReimbursementData {
|
||||||
|
uint32 recipientId;
|
||||||
|
uint256 amount;
|
||||||
|
address token;
|
||||||
|
bytes32 hashDigest;
|
||||||
|
uint8 hashFunction;
|
||||||
|
uint8 hashSize;
|
||||||
|
uint256 confirmedAtBlock;
|
||||||
|
bool vetoed;
|
||||||
|
bool exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping(uint32 => ReimbursementData) public reimbursements;
|
||||||
|
uint32 public reimbursementsCount;
|
||||||
|
|
||||||
|
uint32 public blocksToWait;
|
||||||
|
|
||||||
|
event ReimbursementAdded(uint32 id, address indexed addedByAccount, uint256 amount);
|
||||||
|
event ReimbursementVetoed(uint32 id, address vetoedByAccount);
|
||||||
|
|
||||||
|
function initialize() public onlyInit {
|
||||||
|
blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||||
|
initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
// function setApps() public isInitialized auth(MANAGE_APPS_ROLE) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
function totalAmount(bool confirmedOnly) public view returns (uint256 amount) {
|
||||||
|
for (uint32 i = 1; i <= reimbursementsCount; i++) {
|
||||||
|
ReimbursementData memory r = reimbursements[i];
|
||||||
|
if (!r.vetoed && (block.number >= r.confirmedAtBlock || !confirmedOnly)) {
|
||||||
|
amount += r.amount; // should use safemath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(uint32 reimbursementId) public view returns (uint32 id, uint32 recipientId, uint256 amount, address token, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
|
||||||
|
id = reimbursementId;
|
||||||
|
ReimbursementData storage r = reimbursements[id];
|
||||||
|
return (
|
||||||
|
id,
|
||||||
|
r.recipientId,
|
||||||
|
r.amount,
|
||||||
|
r.token,
|
||||||
|
r.hashDigest,
|
||||||
|
r.hashFunction,
|
||||||
|
r.hashSize,
|
||||||
|
r.confirmedAtBlock,
|
||||||
|
r.exists,
|
||||||
|
r.vetoed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(uint256 amount, address token, uint32 recipientId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_REIMBURSEMENT_ROLE) {
|
||||||
|
uint32 reimbursementId = reimbursementsCount + 1;
|
||||||
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
|
r.exists = true;
|
||||||
|
r.amount = amount;
|
||||||
|
r.token = token;
|
||||||
|
r.recipientId = recipientId;
|
||||||
|
r.hashDigest = hashDigest;
|
||||||
|
r.hashFunction = hashFunction;
|
||||||
|
r.hashSize = hashSize;
|
||||||
|
r.confirmedAtBlock = block.number + blocksToWait;
|
||||||
|
|
||||||
|
reimbursementsCount++;
|
||||||
|
|
||||||
|
emit ReimbursementAdded(reimbursementId, msg.sender, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function veto(uint32 reimbursementId) public isInitialized auth(VETO_REIMBURSEMENT_ROLE) {
|
||||||
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
|
require(r.exists, 'NOT_FOUND');
|
||||||
|
require(block.number < r.confirmedAtBlock, 'VETO_PERIOD_ENDED');
|
||||||
|
r.vetoed = true;
|
||||||
|
|
||||||
|
emit ReimbursementVetoed(reimbursementId, msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(uint32 reimbursementId) public view returns (bool) {
|
||||||
|
return reimbursements[reimbursementId].exists;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
apps/reimbursement/manifest.json
Normal file
16
apps/reimbursement/manifest.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "kredits Reimbursement",
|
||||||
|
"author": "Placeholder-author",
|
||||||
|
"description": "An application for Aragon",
|
||||||
|
"details_url": "/meta/details.md",
|
||||||
|
"source_url": "https://<placeholder-repository-url>",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/meta/icon.svg",
|
||||||
|
"sizes": "56x56"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"screenshots": [{ "src": "/meta/screenshot-1.png" }],
|
||||||
|
"start_url": "/index.html",
|
||||||
|
"script": "/script.js"
|
||||||
|
}
|
||||||
30
apps/reimbursement/package.json
Normal file
30
apps/reimbursement/package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "kredits-reimbursement",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"scripts": {
|
||||||
|
"start": "npm run start:aragon:ipfs",
|
||||||
|
"start:aragon:ipfs": "aragon run",
|
||||||
|
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
|
||||||
|
"start:app": "",
|
||||||
|
"compile": "aragon contracts compile",
|
||||||
|
"sync-assets": "",
|
||||||
|
"build:app": "",
|
||||||
|
"build:script": "",
|
||||||
|
"build": "",
|
||||||
|
"publish:patch": "aragon apm publish patch",
|
||||||
|
"publish:minor": "aragon apm publish minor",
|
||||||
|
"publish:major": "aragon apm publish major",
|
||||||
|
"versions": "aragon apm versions",
|
||||||
|
"test": "truffle test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@aragon/os": "^4.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@aragon/test-helpers": "^2.1.0",
|
||||||
|
"eth-gas-reporter": "^0.2.17",
|
||||||
|
"ganache-cli": "^6.9.1",
|
||||||
|
"solidity-coverage": "^0.5.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
65
apps/reimbursement/test/helpers/dao.js
Normal file
65
apps/reimbursement/test/helpers/dao.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
const { hash } = require('eth-ens-namehash')
|
||||||
|
const { getEventArgument } = require('@aragon/contract-test-helpers/events')
|
||||||
|
const Kernel = artifacts.require('@aragon/os/build/contracts/kernel/Kernel')
|
||||||
|
const ACL = artifacts.require('@aragon/os/build/contracts/acl/ACL')
|
||||||
|
const EVMScriptRegistryFactory = artifacts.require(
|
||||||
|
'@aragon/os/build/contracts/factory/EVMScriptRegistryFactory'
|
||||||
|
)
|
||||||
|
const DAOFactory = artifacts.require(
|
||||||
|
'@aragon/os/build/contracts/factory/DAOFactory'
|
||||||
|
)
|
||||||
|
|
||||||
|
const newDao = async (rootAccount) => {
|
||||||
|
// Deploy a DAOFactory.
|
||||||
|
const kernelBase = await Kernel.new(true)
|
||||||
|
const aclBase = await ACL.new()
|
||||||
|
const registryFactory = await EVMScriptRegistryFactory.new()
|
||||||
|
const daoFactory = await DAOFactory.new(
|
||||||
|
kernelBase.address,
|
||||||
|
aclBase.address,
|
||||||
|
registryFactory.address
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a DAO instance.
|
||||||
|
const daoReceipt = await daoFactory.newDAO(rootAccount)
|
||||||
|
const dao = await Kernel.at(getEventArgument(daoReceipt, 'DeployDAO', 'dao'))
|
||||||
|
|
||||||
|
// Grant the rootAccount address permission to install apps in the DAO.
|
||||||
|
const acl = await ACL.at(await dao.acl())
|
||||||
|
const APP_MANAGER_ROLE = await kernelBase.APP_MANAGER_ROLE()
|
||||||
|
await acl.createPermission(
|
||||||
|
rootAccount,
|
||||||
|
dao.address,
|
||||||
|
APP_MANAGER_ROLE,
|
||||||
|
rootAccount,
|
||||||
|
{ from: rootAccount }
|
||||||
|
)
|
||||||
|
|
||||||
|
return { dao, acl }
|
||||||
|
}
|
||||||
|
|
||||||
|
const newApp = async (dao, appName, baseAppAddress, rootAccount) => {
|
||||||
|
const receipt = await dao.newAppInstance(
|
||||||
|
hash(`${appName}.aragonpm.test`), // appId - Unique identifier for each app installed in the DAO; can be any bytes32 string in the tests.
|
||||||
|
baseAppAddress, // appBase - Location of the app's base implementation.
|
||||||
|
'0x', // initializePayload - Used to instantiate and initialize the proxy in the same call (if given a non-empty bytes string).
|
||||||
|
false, // setDefault - Whether the app proxy is the default proxy.
|
||||||
|
{ from: rootAccount }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Find the deployed proxy address in the tx logs.
|
||||||
|
const logs = receipt.logs
|
||||||
|
const log = logs.find((l) => l.event === 'NewAppProxy')
|
||||||
|
const proxyAddress = log.args.proxy
|
||||||
|
|
||||||
|
return proxyAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
newDao,
|
||||||
|
newApp,
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
21
apps/reimbursement/test/helpers/permissions.js
Normal file
21
apps/reimbursement/test/helpers/permissions.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
const ANY_ADDRESS = '0xffffffffffffffffffffffffffffffffffffffff'
|
||||||
|
|
||||||
|
const setOpenPermission = async (acl, appAddress, role, rootAddress) => {
|
||||||
|
// Note: Setting a permission to 0xffffffffffffffffffffffffffffffffffffffff
|
||||||
|
// is interpreted by aragonOS as allowing the role for any address.
|
||||||
|
await acl.createPermission(
|
||||||
|
ANY_ADDRESS, // entity (who?) - The entity or address that will have the permission.
|
||||||
|
appAddress, // app (where?) - The app that holds the role involved in this permission.
|
||||||
|
role, // role (what?) - The particular role that the entity is being assigned to in this permission.
|
||||||
|
rootAddress, // manager - Can grant/revoke further permissions for this role.
|
||||||
|
{ from: rootAddress}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setOpenPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
1
apps/reimbursement/truffle.js
Normal file
1
apps/reimbursement/truffle.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = require("../../truffle.js");
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,12 @@ contract Token is ERC20Token, AragonApp {
|
|||||||
bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
|
bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
|
||||||
|
|
||||||
// ensure alphabetic order
|
// ensure alphabetic order
|
||||||
enum Apps { Contribution, Contributor, Proposal, Token }
|
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
|
||||||
bytes32[4] public appIds;
|
bytes32[5] public appIds;
|
||||||
|
|
||||||
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
||||||
|
|
||||||
function initialize(bytes32[4] _appIds) public onlyInit {
|
function initialize(bytes32[5] _appIds) public onlyInit {
|
||||||
appIds = _appIds;
|
appIds = _appIds;
|
||||||
name = 'Kredits';
|
name = 'Kredits';
|
||||||
symbol = '₭S';
|
symbol = '₭S';
|
||||||
@@ -21,6 +21,8 @@ contract Token is ERC20Token, AragonApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) {
|
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) {
|
||||||
|
require(amount > 0, "INVALID_AMOUNT");
|
||||||
|
|
||||||
uint256 amountInWei = amount.mul(1 ether);
|
uint256 amountInWei = amount.mul(1 ether);
|
||||||
_mint(contributorAccount, amountInWei);
|
_mint(contributorAccount, amountInWei);
|
||||||
emit LogMint(contributorAccount, amount, contributionId);
|
emit LogMint(contributorAccount, amount, contributionId);
|
||||||
|
|||||||
16
apps/token/contracts/test/Spoof.sol
Normal file
16
apps/token/contracts/test/Spoof.sol
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/acl/ACL.sol";
|
||||||
|
import "@aragon/os/contracts/kernel/Kernel.sol";
|
||||||
|
import "@aragon/os/contracts/factory/DAOFactory.sol";
|
||||||
|
|
||||||
|
// You might think this file is a bit odd, but let me explain.
|
||||||
|
// We only use for now those imported contracts in our tests, which
|
||||||
|
// means Truffle will not compile them for us, because they are from
|
||||||
|
// an external dependency.
|
||||||
|
|
||||||
|
|
||||||
|
// solium-disable-next-line no-empty-blocks
|
||||||
|
contract Spoof {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
28809
apps/token/package-lock.json
generated
28809
apps/token/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,12 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aragon/os": "^4.2.0",
|
"@aragon/os": "^4.4.0"
|
||||||
"@aragon/cli": "^5.9.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aragon/test-helpers": "^1.1.0",
|
"@aragon/test-helpers": "^2.1.0",
|
||||||
"eth-gas-reporter": "^0.2.0",
|
"eth-gas-reporter": "^0.2.17",
|
||||||
"ganache-cli": "^6.4.3",
|
"ganache-cli": "^6.9.1",
|
||||||
"solidity-coverage": "^0.5.11"
|
"solidity-coverage": "^0.5.11"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,10 +25,7 @@
|
|||||||
"publish:minor": "aragon apm publish minor",
|
"publish:minor": "aragon apm publish minor",
|
||||||
"publish:major": "aragon apm publish major",
|
"publish:major": "aragon apm publish major",
|
||||||
"versions": "aragon apm versions",
|
"versions": "aragon apm versions",
|
||||||
"test": "TRUFFLE_TEST=true PORT=7545 npm run ganache-cli:test",
|
"test": "truffle test"
|
||||||
"test:gas": "GAS_REPORTER=true npm test",
|
|
||||||
"coverage": "SOLIDITY_COVERAGE=true npm run ganache-cli:test",
|
|
||||||
"ganache-cli:test": "./node_modules/@aragon/test-helpers/ganache-cli.sh"
|
|
||||||
},
|
},
|
||||||
"keywords": []
|
"keywords": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
// const Token = artifacts.require('Token.sol');
|
|
||||||
|
|
||||||
contract('Token', (_accounts) => {
|
|
||||||
it('should be tested');
|
|
||||||
});
|
|
||||||
123
apps/token/test/token.js
Normal file
123
apps/token/test/token.js
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
const namehash = require('ethers').utils.namehash;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const Token = artifacts.require("Token.sol");
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const getContract = name => artifacts.require(name);
|
||||||
|
const { assertRevert } = require('@aragon/test-helpers/assertThrow');
|
||||||
|
|
||||||
|
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
|
||||||
|
|
||||||
|
contract('Token app', (accounts) => {
|
||||||
|
let kernelBase, aclBase, daoFactory, dao, r, acl, token;
|
||||||
|
|
||||||
|
const root = accounts[0];
|
||||||
|
const member1 = accounts[1];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
before(async () => {
|
||||||
|
kernelBase = await getContract('Kernel').new(true); // petrify immediately
|
||||||
|
aclBase = await getContract('ACL').new();
|
||||||
|
daoFactory = await getContract('DAOFactory').new(kernelBase.address, aclBase.address, ZERO_ADDR);
|
||||||
|
r = await daoFactory.newDAO(root);
|
||||||
|
dao = await getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao);
|
||||||
|
acl = await getContract('ACL').at(await dao.acl());
|
||||||
|
|
||||||
|
//create dao mamnager permission for coin owner
|
||||||
|
await acl.createPermission(
|
||||||
|
root,
|
||||||
|
dao.address,
|
||||||
|
await dao.APP_MANAGER_ROLE(),
|
||||||
|
root,
|
||||||
|
{ from: root }
|
||||||
|
);
|
||||||
|
|
||||||
|
//get new app instance from DAO
|
||||||
|
const receipt = await dao.newAppInstance(
|
||||||
|
'0x1234',
|
||||||
|
(await Token.new()).address,
|
||||||
|
0x0,
|
||||||
|
false,
|
||||||
|
{ from: root }
|
||||||
|
);
|
||||||
|
token = Token.at(
|
||||||
|
receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
|
||||||
|
);
|
||||||
|
|
||||||
|
//apps id
|
||||||
|
let appsId = [];
|
||||||
|
appsId[0] = namehash("kredits-contribution");
|
||||||
|
appsId[1] = namehash("kredits-contributor");
|
||||||
|
appsId[2] = namehash("kredits-proposal");
|
||||||
|
appsId[3] = namehash("kredits-token");
|
||||||
|
|
||||||
|
//init token (app)
|
||||||
|
await token.initialize(appsId);
|
||||||
|
|
||||||
|
//create token mint permission for coin owner
|
||||||
|
await acl.createPermission(
|
||||||
|
root,
|
||||||
|
token.address,
|
||||||
|
await token.MINT_TOKEN_ROLE(),
|
||||||
|
root,
|
||||||
|
{ from: root }
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Owner default space permissions", async () => {
|
||||||
|
it('check owner is token issuer', async () => {
|
||||||
|
let tokenIssuerPermission = await acl.hasPermission(root, token.address, await token.MINT_TOKEN_ROLE());
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
assert.equal(tokenIssuerPermission, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Token issuing", async () => {
|
||||||
|
let name = "Kredits";
|
||||||
|
let symbol = "₭S";
|
||||||
|
let decimals = 18;
|
||||||
|
|
||||||
|
it("check token properties", async () => {
|
||||||
|
assert.equal(await token.name(), name); // eslint-disable-line no-undef
|
||||||
|
assert.equal(await token.symbol(), symbol); // eslint-disable-line no-undef
|
||||||
|
assert.equal(await token.decimals(), decimals); // eslint-disable-line no-undef
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Token minting", async () => {
|
||||||
|
let tokenToMint = 250;
|
||||||
|
let ether = 1000000000000000000;
|
||||||
|
|
||||||
|
it("should revert when mint tokens from an address that does not have minting permission", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await token.mintFor(root, tokenToMint, 1, { from: member1});
|
||||||
|
'address does not have permission to mint tokens';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when mint tokens to address(0)", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await token.mintFor(ZERO_ADDR, tokenToMint, 1, { from: root});
|
||||||
|
'invalid contributor address';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revert when mint amount of tokens equal to 0", async () => {
|
||||||
|
return assertRevert(async () => {
|
||||||
|
await token.mintFor(root, 0, 1, { from: root});
|
||||||
|
'amount to mint should be greater than zero';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mint tokens", async () => {
|
||||||
|
await token.mintFor(root, tokenToMint, 1, { from: root });
|
||||||
|
let ownerBalance = await token.balanceOf(root);
|
||||||
|
let totalSupply = await token.totalSupply();
|
||||||
|
assert.equal(ownerBalance.toNumber(), tokenToMint*ether); // eslint-disable-line no-undef
|
||||||
|
assert.equal(totalSupply.toNumber(), tokenToMint*ether); // eslint-disable-line no-undef
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
8145
apps/token/yarn.lock
8145
apps/token/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,6 @@
|
|||||||
"environments": {
|
"environments": {
|
||||||
"development": {
|
"development": {
|
||||||
"network": "development",
|
"network": "development",
|
||||||
"apm": "open.aragonpm.eth",
|
|
||||||
"registry": "0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1",
|
"registry": "0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1",
|
||||||
"appName": "dummy.open.aragonpm.eth"
|
"appName": "dummy.open.aragonpm.eth"
|
||||||
},
|
},
|
||||||
@@ -42,9 +41,10 @@
|
|||||||
"network": "rinkeby",
|
"network": "rinkeby",
|
||||||
"registry": "0x98Df287B6C145399Aaa709692c8D308357bC085D",
|
"registry": "0x98Df287B6C145399Aaa709692c8D308357bC085D",
|
||||||
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
|
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
|
||||||
"daoFactory": "0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d",
|
|
||||||
"appName": "dummy.open.aragonpm.eth",
|
"appName": "dummy.open.aragonpm.eth",
|
||||||
"apm": "open.aragonpm.eth"
|
"kredits": {
|
||||||
|
"daoFactory": "0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"kovan": {
|
"kovan": {
|
||||||
"network": "kovan",
|
"network": "kovan",
|
||||||
@@ -52,8 +52,7 @@
|
|||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"network": "development",
|
"network": "development",
|
||||||
"appName": "dummy.aragonpm.eth",
|
"appName": "dummy.aragonpm.eth"
|
||||||
"apm": "open.aragonpm.eth"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"path": "contracts/misc/DummyApp.sol"
|
"path": "contracts/misc/DummyApp.sol"
|
||||||
|
|||||||
@@ -31,13 +31,19 @@ const contractCalls = [
|
|||||||
wiki_username: 'Manuel',
|
wiki_username: 'Manuel',
|
||||||
}, { gasLimit: 200000 }]],
|
}, { gasLimit: 200000 }]],
|
||||||
|
|
||||||
['Proposal', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-09', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
|
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Test this thing', url: '' }, { gasLimit: 350000 }]],
|
||||||
['Proposal', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-10', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
|
|
||||||
['Proposal', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Hacked on kredits', url: '' }, { gasLimit: 350000 }]],
|
|
||||||
['Proposal', 'vote', [1, { gasLimit: 550000 }]],
|
|
||||||
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 5000, kind: 'dev', description: '[67P/kredits-contracts] Introduce contribution token', url: '' }, { gasLimit: 350000 }]],
|
|
||||||
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-web] Reviewed stuff', url: '' }, { gasLimit: 350000 }]],
|
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-web] Reviewed stuff', url: '' }, { gasLimit: 350000 }]],
|
||||||
['Contribution', 'claim', [1, { gasLimit: 300000 }]],
|
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-contracts] Add tests', url: '' }, { gasLimit: 350000 }]],
|
||||||
|
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-contracts] Introduce contribution token', url: '' }, { gasLimit: 350000 }]],
|
||||||
|
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 5000, kind: 'dev', description: '[67P/kredits-web] Expense UI, first draft', url: '' }, { gasLimit: 350000 }]],
|
||||||
|
|
||||||
|
['Reimbursement', 'add', [{amount: 1116000, recipientId: 1, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
|
||||||
|
{ title: 'Server rent', description: 'Dedicated server: andromeda.kosmos.org, April 2020', amount: 61, currency: 'EUR', date: '2020-05-28' },
|
||||||
|
{ title: 'Server rent', description: 'Dedicated server: centaurus.kosmos.org, April 2020', amount: 32, currency: 'EUR', date: '2020-05-28' }
|
||||||
|
]}, { gasLimit: 300000 }]],
|
||||||
|
['Reimbursement', 'add', [{amount: 166800, recipientId: 2, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
|
||||||
|
{ title: 'Domain kosmos.chat', description: 'Yearly registration fee for domain kosmos.chat', amount: 13.90, currency: 'EUR', date: '2020-05-30' }
|
||||||
|
]}, { gasLimit: 300000 }]],
|
||||||
];
|
];
|
||||||
|
|
||||||
const funds = [
|
const funds = [
|
||||||
|
|||||||
@@ -10,17 +10,18 @@ import "../apps/contribution/contracts/Contribution.sol";
|
|||||||
import "../apps/contributor/contracts/Contributor.sol";
|
import "../apps/contributor/contracts/Contributor.sol";
|
||||||
import "../apps/token/contracts/Token.sol";
|
import "../apps/token/contracts/Token.sol";
|
||||||
import "../apps/proposal/contracts/Proposal.sol";
|
import "../apps/proposal/contracts/Proposal.sol";
|
||||||
|
import "../apps/reimbursement/contracts/Reimbursement.sol";
|
||||||
|
|
||||||
contract KreditsKit is KitBase {
|
contract KreditsKit is KitBase {
|
||||||
|
|
||||||
// ensure alphabetic order
|
// ensure alphabetic order
|
||||||
enum Apps { Contribution, Contributor, Proposal, Token }
|
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
|
||||||
bytes32[4] public appIds;
|
bytes32[5] public appIds;
|
||||||
|
|
||||||
event DeployInstance(address dao);
|
event DeployInstance(address dao);
|
||||||
event InstalledApp(address dao, address appProxy, bytes32 appId);
|
event InstalledApp(address dao, address appProxy, bytes32 appId);
|
||||||
|
|
||||||
constructor (DAOFactory _fac, ENS _ens, bytes32[4] _appIds) public KitBase(_fac, _ens) {
|
constructor (DAOFactory _fac, ENS _ens, bytes32[5] _appIds) public KitBase(_fac, _ens) {
|
||||||
appIds = _appIds;
|
appIds = _appIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,18 +42,24 @@ contract KreditsKit is KitBase {
|
|||||||
Contribution contribution = Contribution(_installApp(dao, appIds[uint8(Apps.Contribution)]));
|
Contribution contribution = Contribution(_installApp(dao, appIds[uint8(Apps.Contribution)]));
|
||||||
contribution.initialize(appIds);
|
contribution.initialize(appIds);
|
||||||
|
|
||||||
Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)]));
|
|
||||||
proposal.initialize(appIds);
|
|
||||||
|
|
||||||
acl.createPermission(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), this);
|
acl.createPermission(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), this);
|
||||||
acl.createPermission(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), this);
|
acl.createPermission(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), this);
|
||||||
acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE());
|
acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE());
|
||||||
|
|
||||||
|
Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)]));
|
||||||
|
proposal.initialize(appIds);
|
||||||
|
|
||||||
|
Reimbursement reimbursement = Reimbursement(_installApp(dao, appIds[uint8(Apps.Reimbursement)]));
|
||||||
|
reimbursement.initialize();
|
||||||
|
acl.createPermission(root, reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE(), this);
|
||||||
|
acl.createPermission(root, reimbursement, reimbursement.VETO_REIMBURSEMENT_ROLE(), this);
|
||||||
|
|
||||||
uint256[] memory params = new uint256[](1);
|
uint256[] memory params = new uint256[](1);
|
||||||
params[0] = uint256(203) << 248 | uint256(1) << 240 | uint240(contributor);
|
params[0] = uint256(203) << 248 | uint256(1) << 240 | uint240(contributor);
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.ADD_CONTRIBUTION_ROLE(), params);
|
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.ADD_CONTRIBUTION_ROLE(), params);
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.VETO_CONTRIBUTION_ROLE(), params);
|
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.VETO_CONTRIBUTION_ROLE(), params);
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), params);
|
acl.grantPermissionP(acl.ANY_ENTITY(), contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), params);
|
||||||
|
acl.grantPermissionP(acl.ANY_ENTITY(), reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE(), params);
|
||||||
|
|
||||||
//acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE();
|
//acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE();
|
||||||
acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this);
|
acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this);
|
||||||
@@ -67,6 +74,8 @@ contract KreditsKit is KitBase {
|
|||||||
acl.setPermissionManager(root, contribution, contribution.ADD_CONTRIBUTION_ROLE());
|
acl.setPermissionManager(root, contribution, contribution.ADD_CONTRIBUTION_ROLE());
|
||||||
acl.setPermissionManager(root, contribution, contribution.VETO_CONTRIBUTION_ROLE());
|
acl.setPermissionManager(root, contribution, contribution.VETO_CONTRIBUTION_ROLE());
|
||||||
acl.setPermissionManager(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE());
|
acl.setPermissionManager(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE());
|
||||||
|
acl.setPermissionManager(root, reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE());
|
||||||
|
acl.setPermissionManager(root, reimbursement, reimbursement.VETO_REIMBURSEMENT_ROLE());
|
||||||
|
|
||||||
acl.createPermission(root, token, token.MINT_TOKEN_ROLE(), this);
|
acl.createPermission(root, token, token.MINT_TOKEN_ROLE(), this);
|
||||||
acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE());
|
acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE());
|
||||||
|
|||||||
19000
data/contributions.json
Normal file
19000
data/contributions.json
Normal file
File diff suppressed because it is too large
Load Diff
121
data/contributors.json
Normal file
121
data/contributors.json
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
{
|
||||||
|
"1": {
|
||||||
|
"account": "0x7E8f313C56F809188313aa274Fa67EE58c31515d",
|
||||||
|
"hashDigest": "0x99b8afd7b266e19990924a8be9099e81054b70c36b20937228a77a5cf75723b8",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"account": "0x49575f3DD9a0d60aE661BC992f72D837A77f05Bc",
|
||||||
|
"hashDigest": "0xeb78574922d8606419b714174b31961007afefe313111c9db817aa9d3f82e157",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"account": "0xF722709ECC3B05c19d02E82a2a4A4021B8F48C62",
|
||||||
|
"hashDigest": "0x7acd73632c7cc8d317fa9e72e925eaef1d700e69f185b84e3f0168471e17cf2d",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 3
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"account": "0xD4a64570B12dA659Ee4BBd41c3509B7b1F9c51AC",
|
||||||
|
"hashDigest": "0x4d394c58e4b0534446be10a9b7f8b50e5478258719c23a3e158a5ea9fca14bdd",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 4
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"account": "0x35d9e68a5F7A935C64b08221d5DC7f161a415184",
|
||||||
|
"hashDigest": "0xd6f726f37ad52998b8341b7021cb5d9f4dcf7ce09af575358505a2a7c2f81edb",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 5
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"account": "0x8345E84D848792bf750A1d032d76f20f00aeC1a7",
|
||||||
|
"hashDigest": "0x1acdc784e20f62c44ec222552531bf89daafaaca1893a68057a9ada920ea0984",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 6
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"account": "0x4D99d767477Fbb2B47EFeb17E2a78970AD22CCc1",
|
||||||
|
"hashDigest": "0xd6d16bde5ee3d3374dd5981dab0296938b24e3c812e72ba4fa3d38011b6fab24",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 7
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"account": "0x6a6cD99ab0335C92E55fbb4403D67A4f4B52AfEc",
|
||||||
|
"hashDigest": "0xec30c91b31a85eef2af7afce0ba66b0636f1d61a75a12d8ca188a2d9e1626cf2",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 8
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"account": "0x21aB0B3527326dcA4467245654Cf881F5F7a8c5e",
|
||||||
|
"hashDigest": "0xd6c8b0f285e614b12f700d6e66e2e67901c16c420308625f844357283bd555ba",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 9
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"account": "0x150A69bAfA216FD55C7CeF8eA2002cd582dc5982",
|
||||||
|
"hashDigest": "0x7490aabadf995751211686b3b9f4b8cfee3354947df23cec043c15bfb519c817",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 10
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"account": "0x2f65679cAf0c3abCbF77fC68fA56759f4D96C73c",
|
||||||
|
"hashDigest": "0xd147d2d26f7eb1cbe1c5da53c345565df2d3c6c33a8a3e3331952d4b878b2bb0",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 11
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"account": "0x13a24319Abb4e00c383D8a80dACb20690699Ac8C",
|
||||||
|
"hashDigest": "0x84c63c2d3f9510f87717e54a2cecb41f88dce6a41ae6392480ebf6561e30670e",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 12
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"account": "0x0e0F02508b80e401C26F584fF02eE80Ab094CdF9",
|
||||||
|
"hashDigest": "0xe4c34e15b87114e9edd599fa1bbd6d4b1bf45c3b0163d0772158fb93503c1fe1",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 13
|
||||||
|
},
|
||||||
|
"14": {
|
||||||
|
"account": "0x49750D74930b20b2937DDF77A6C30d81882d888E",
|
||||||
|
"hashDigest": "0xa1f18c54e77d1e8f0fa106463b3f66a34a6287bcd9b643febea0ab2e97009665",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 14
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"account": "0x608FD4b95116Ea616990Aaeb1d4f1ce07612f261",
|
||||||
|
"hashDigest": "0x1d9de6de5c72eedca6d7a5e8a9159e2f5fe676506aece3000acefcc821723429",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 15
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"account": "0xCaBba4560c96FADe3Dd6C29cF24Cfb16a228bC1c",
|
||||||
|
"hashDigest": "0x0c81914b8a332808879b06b1a68398edccea7e7facb50767e4116c33914d2c64",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 16
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"account": "0x765E88b4F9a59C3a3b300C6eFF9E6E9fDDf9FbD9",
|
||||||
|
"hashDigest": "0xcfbeeadc244dfdc55bbad50d431871439df067970db84c73023956c96a6f5df2",
|
||||||
|
"hashFunction": 18,
|
||||||
|
"hashSize": 32,
|
||||||
|
"id": 17
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,36 @@
|
|||||||
|
|
||||||
aragon apm publish major --environment=rinkeby"
|
aragon apm publish major --environment=rinkeby"
|
||||||
|
|
||||||
|
## 20212-01-14
|
||||||
|
|
||||||
|
apps/contribution@master » aragon apm publish major --environment=rinkeby
|
||||||
|
eth-provider | Invalid provider preset/location: "local"
|
||||||
|
✔ Start IPFS
|
||||||
|
✔ Applying version bump (major)
|
||||||
|
↓ Building frontend [skipped]
|
||||||
|
→ build script not defined in package.json
|
||||||
|
✔ Deploy contract
|
||||||
|
✔ Determine contract address for version
|
||||||
|
✔ Prepare files for publishing
|
||||||
|
✔ Generate application artifact
|
||||||
|
✔ Publish intent
|
||||||
|
|
||||||
|
⚠ Publishing files from the project's root folder is not recommended. Consider using the distribution folder of your project: "--files <folder>".
|
||||||
|
|
||||||
|
The following information will be published:
|
||||||
|
Contract address: 0x914Da982ef17B56D2e868E3a67E923EbED1aE017
|
||||||
|
Content (ipfs): QmdVrY2R48NFqwLopd8ix1anAK1d6WafDGauou3ZJrB9gf
|
||||||
|
|
||||||
|
? Publish to kredits-contribution.open.aragonpm.eth repo Yes
|
||||||
|
|
||||||
|
✔ Publish kredits-contribution.open.aragonpm.eth
|
||||||
|
|
||||||
|
Successfully published kredits-contribution.open.aragonpm.eth v7.0.0 :
|
||||||
|
|
||||||
|
Transaction hash: 0xb817b2e80e90a6be60b45dd39987498e3132c9962c0501feb7549ad30186c6d5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 2019-04-24 update balances
|
## 2019-04-24 update balances
|
||||||
|
|
||||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v6.0.0:
|
✔ Successfully published kredits-contribution.open.aragonpm.eth v6.0.0:
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# Kredits deployment
|
# Kredits deployment
|
||||||
|
|
||||||
|
|
||||||
|
## 2021-01-14
|
||||||
|
|
||||||
|
apps/contribution@master » aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contribution.open.aragonpm.eth --environment=rinkeby
|
||||||
|
eth-provider | Invalid provider preset/location: "local"
|
||||||
|
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
|
||||||
|
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
|
||||||
|
✔ Upgrading app
|
||||||
|
|
||||||
|
✔ Successfully executed: "Upgrade 'kredits-contribution.open.aragonpm.eth' app instances to v7.0.0"
|
||||||
|
|
||||||
## 2019-04-25 canPerfom fix
|
## 2019-04-25 canPerfom fix
|
||||||
|
|
||||||
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
|
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
lib/abis/Reimbursement.json
Normal file
1
lib/abis/Reimbursement.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@ class Acl extends Base {
|
|||||||
hasPermission (fromAddress, contractAddress, roleID, params = null) {
|
hasPermission (fromAddress, contractAddress, roleID, params = null) {
|
||||||
let roleHash = EthersUtils.keccak256(EthersUtils.toUtf8Bytes(roleID));
|
let roleHash = EthersUtils.keccak256(EthersUtils.toUtf8Bytes(roleID));
|
||||||
|
|
||||||
return this.functions.hasPermission(
|
return this.hasPermission(
|
||||||
fromAddress,
|
fromAddress,
|
||||||
contractAddress,
|
contractAddress,
|
||||||
roleHash,
|
roleHash,
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
const deprecate = require('../utils/deprecate');
|
||||||
|
|
||||||
class Base {
|
class Base {
|
||||||
constructor (contract) {
|
constructor (contract) {
|
||||||
this.contract = contract;
|
this.contract = contract;
|
||||||
}
|
}
|
||||||
|
|
||||||
get functions () {
|
get functions () {
|
||||||
return this.contract.functions;
|
deprecate('The property `functions` is deprecated. contract functions are now directly defined on the ethers contract object. https://github.com/ethers-io/ethers.js/issues/920#issuecomment-650836642');
|
||||||
|
return this.contract;
|
||||||
}
|
}
|
||||||
|
|
||||||
get address () {
|
get address () {
|
||||||
|
|||||||
@@ -4,33 +4,33 @@ const deprecate = require('../utils/deprecate');
|
|||||||
|
|
||||||
class Contribution extends Record {
|
class Contribution extends Record {
|
||||||
get count () {
|
get count () {
|
||||||
return this.functions.contributionsCount();
|
return this.contract.contributionsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
getById (id) {
|
getById (id) {
|
||||||
return this.functions.getContribution(id)
|
return this.contract.getContribution(id)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getData (id) {
|
getData (id) {
|
||||||
return this.functions.getContribution(id);
|
return this.contract.getContribution(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getByContributorId (contributorId) {
|
getByContributorId (contributorId) {
|
||||||
return this.functions.getContributorAddressById(contributorId)
|
return this.contract.getContributorAddressById(contributorId)
|
||||||
.then(address => this.getByContributorAddress(address));
|
.then(address => this.getByContributorAddress(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
getByContributorAddress (address) {
|
getByContributorAddress (address) {
|
||||||
return this.functions.balanceOf(address)
|
return this.contract.balanceOf(address)
|
||||||
.then(async (balance) => {
|
.then(async (balance) => {
|
||||||
const count = balance.toNumber();
|
const count = balance.toNumber();
|
||||||
const contributions = [];
|
const contributions = [];
|
||||||
|
|
||||||
for (let index = 0; index < count; index++) {
|
for (let index = 0; index < count; index++) {
|
||||||
const id = await this.functions.tokenOfOwnerByIndex(address, index);
|
const id = await this.contract.tokenOfOwnerByIndex(address, index);
|
||||||
const contribution = await this.getById(id);
|
const contribution = await this.getById(id);
|
||||||
contributions.push(contribution);
|
contributions.push(contribution);
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ class Contribution extends Record {
|
|||||||
ipfsHashAttr.hashSize,
|
ipfsHashAttr.hashSize,
|
||||||
];
|
];
|
||||||
|
|
||||||
return this.functions.add(...contribution, callOptions);
|
return this.contract.add(...contribution, callOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,20 @@ const formatKredits = require('../utils/format-kredits');
|
|||||||
|
|
||||||
class Contributor extends Record {
|
class Contributor extends Record {
|
||||||
get count () {
|
get count () {
|
||||||
return this.functions.contributorsCount();
|
return this.contract.contributorsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
getById (id) {
|
getById (id) {
|
||||||
return this.functions.getContributorById(id)
|
return this.contract.getContributorById(id)
|
||||||
.then(data => {
|
.then(contractData => {
|
||||||
|
let data = {...contractData};
|
||||||
data.balanceInt = formatKredits(data.balance);
|
data.balanceInt = formatKredits(data.balance);
|
||||||
return this.ipfs.catAndMerge(data, ContributorSerializer.deserialize);
|
return this.ipfs.catAndMerge(data, ContributorSerializer.deserialize);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getData (id) {
|
getData (id) {
|
||||||
return this.functions.getContributorById(id);
|
return this.contract.getContributorById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
filterByAccount (search) {
|
filterByAccount (search) {
|
||||||
@@ -61,7 +62,7 @@ class Contributor extends Record {
|
|||||||
ipfsHashAttr.hashSize,
|
ipfsHashAttr.hashSize,
|
||||||
];
|
];
|
||||||
|
|
||||||
return this.functions.addContributor(...contributor, callOptions);
|
return this.contract.addContributor(...contributor, callOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ class Contributor extends Record {
|
|||||||
return this.ipfs
|
return this.ipfs
|
||||||
.add(jsonStr)
|
.add(jsonStr)
|
||||||
.then(ipfsHashAttr => {
|
.then(ipfsHashAttr => {
|
||||||
return this.functions.updateContributorProfileHash(
|
return this.contract.updateContributorProfileHash(
|
||||||
contributorId,
|
contributorId,
|
||||||
ipfsHashAttr.hashDigest,
|
ipfsHashAttr.hashDigest,
|
||||||
ipfsHashAttr.hashFunction,
|
ipfsHashAttr.hashFunction,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module.exports = {
|
|||||||
Contribution: require('./contribution'),
|
Contribution: require('./contribution'),
|
||||||
Proposal: require('./proposal'),
|
Proposal: require('./proposal'),
|
||||||
Token: require('./token'),
|
Token: require('./token'),
|
||||||
|
Reimbursement: require('./reimbursement'),
|
||||||
Kernel: require('./kernel'),
|
Kernel: require('./kernel'),
|
||||||
Acl: require('./acl'),
|
Acl: require('./acl'),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ class Kernel extends Base {
|
|||||||
|
|
||||||
getApp (appName) {
|
getApp (appName) {
|
||||||
if (appName === 'Acl') {
|
if (appName === 'Acl') {
|
||||||
return this.functions.acl();
|
return this.contract.acl();
|
||||||
}
|
}
|
||||||
return this.functions.getApp(KERNEL_APP_ADDR_NAMESPACE, this.appNamehash(appName));
|
return this.contract.getApp(KERNEL_APP_ADDR_NAMESPACE, this.appNamehash(appName));
|
||||||
}
|
}
|
||||||
|
|
||||||
appNamehash (appName) {
|
appNamehash (appName) {
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ const deprecate = require('../utils/deprecate');
|
|||||||
|
|
||||||
class Proposal extends Record {
|
class Proposal extends Record {
|
||||||
get count () {
|
get count () {
|
||||||
return this.functions.proposalsCount();
|
return this.contract.proposalsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
getById (id) {
|
getById (id) {
|
||||||
return this.functions.getProposal(id)
|
return this.contract.getProposal(id)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||||
});
|
});
|
||||||
@@ -33,7 +33,7 @@ class Proposal extends Record {
|
|||||||
ipfsHashAttr.hashSize,
|
ipfsHashAttr.hashSize,
|
||||||
];
|
];
|
||||||
|
|
||||||
return this.functions.addProposal(...proposal, callOptions);
|
return this.contract.addProposal(...proposal, callOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,18 +9,6 @@ class Record extends Base {
|
|||||||
return Promise.all(records);
|
return Promise.all(records);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pinIpfsHashes () {
|
|
||||||
return this.count.then(count => {
|
|
||||||
let promises = [...Array(count).keys()].map(i => {
|
|
||||||
let id = i + 1; // 0 => 1 - ids start with 1 and not with 0
|
|
||||||
return this.getData(id).then(data => {
|
|
||||||
return this.ipfs.pin(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return Promise.all(promises);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Record;
|
module.exports = Record;
|
||||||
|
|||||||
65
lib/contracts/reimbursement.js
Normal file
65
lib/contracts/reimbursement.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
const Record = require('./record');
|
||||||
|
const ExpenseSerializer = require('../serializers/expense');
|
||||||
|
|
||||||
|
class Reimbursement extends Record {
|
||||||
|
get count () {
|
||||||
|
return this.functions.reimbursementsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
getById (id) {
|
||||||
|
return this.functions.get(id)
|
||||||
|
.then(data => {
|
||||||
|
return this.ipfs.catAndMerge(data, (ipfsDocument) => {
|
||||||
|
const expenses = JSON.parse(ipfsDocument);
|
||||||
|
return { expenses };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getData (id) {
|
||||||
|
return this.functions.getReimbursement(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async add (attrs, callOptions = {}) {
|
||||||
|
const amount = parseInt(attrs.amount);
|
||||||
|
const token = attrs.token;
|
||||||
|
const recipientId = attrs.recipientId;
|
||||||
|
const expenses = attrs.expenses.map( e => new ExpenseSerializer(e) );
|
||||||
|
let errorMessage;
|
||||||
|
|
||||||
|
if (typeof amount !== 'number' || amount <= 0) {
|
||||||
|
errorMessage = 'Invalid data: amount must be a positive number.';
|
||||||
|
}
|
||||||
|
if (!token || token === '') {
|
||||||
|
errorMessage = 'Invalid data: token must be a token address.';
|
||||||
|
}
|
||||||
|
if (!recipientId || recipientId === '') {
|
||||||
|
errorMessage = 'Invalid data: recipientId is required.';
|
||||||
|
}
|
||||||
|
if (expenses.length === 0) {
|
||||||
|
errorMessage = 'Invalid data: at least one expense item is required.';
|
||||||
|
}
|
||||||
|
if (errorMessage) { return Promise.reject(new Error(errorMessage)); }
|
||||||
|
|
||||||
|
return Promise.all(expenses.map(e => e.validate()))
|
||||||
|
.then(() => {
|
||||||
|
const jsonStr = JSON.stringify(expenses.map(e => e.data), null, 2);
|
||||||
|
return this.ipfs
|
||||||
|
.add(jsonStr)
|
||||||
|
.then(ipfsHashAttr => {
|
||||||
|
const reimbursement = [
|
||||||
|
amount,
|
||||||
|
token,
|
||||||
|
parseInt(recipientId),
|
||||||
|
ipfsHashAttr.hashDigest,
|
||||||
|
ipfsHashAttr.hashFunction,
|
||||||
|
ipfsHashAttr.hashSize,
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.functions.add(...reimbursement, callOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Reimbursement;
|
||||||
@@ -6,6 +6,7 @@ const deprecate = require('./utils/deprecate');
|
|||||||
const ABIS = {
|
const ABIS = {
|
||||||
Contributor: require('./abis/Contributor.json'),
|
Contributor: require('./abis/Contributor.json'),
|
||||||
Contribution: require('./abis/Contribution.json'),
|
Contribution: require('./abis/Contribution.json'),
|
||||||
|
Reimbursement: require('./abis/Reimbursement.json'),
|
||||||
Token: require('./abis/Token.json'),
|
Token: require('./abis/Token.json'),
|
||||||
Proposal: require('./abis/Proposal.json'),
|
Proposal: require('./abis/Proposal.json'),
|
||||||
Kernel: require('./abis/Kernel.json'),
|
Kernel: require('./abis/Kernel.json'),
|
||||||
@@ -16,6 +17,7 @@ const APP_CONTRACTS = [
|
|||||||
'Contribution',
|
'Contribution',
|
||||||
'Token',
|
'Token',
|
||||||
'Proposal',
|
'Proposal',
|
||||||
|
'Reimbursement',
|
||||||
'Acl',
|
'Acl',
|
||||||
];
|
];
|
||||||
const DaoAddresses = require('./addresses/dao.json');
|
const DaoAddresses = require('./addresses/dao.json');
|
||||||
@@ -121,6 +123,10 @@ class Kredits {
|
|||||||
return this.contractFor('Contribution');
|
return this.contractFor('Contribution');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get Reimbursement () {
|
||||||
|
return this.contractFor('Reimbursement');
|
||||||
|
}
|
||||||
|
|
||||||
get Acl () {
|
get Acl () {
|
||||||
return this.contractFor('Acl');
|
return this.contractFor('Acl');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ class KreditsKit {
|
|||||||
|
|
||||||
appIdFor (contractName) {
|
appIdFor (contractName) {
|
||||||
// see appIds in KreditsKit.sol for more details
|
// see appIds in KreditsKit.sol for more details
|
||||||
const knownContracts = ['Contribution', 'Contributor', 'Proposal', 'Token'];
|
const knownContracts = ['Contribution', 'Contributor', 'Proposal', 'Reimbursement', 'Token'];
|
||||||
return this.contract.functions.appIds(knownContracts.indexOf(contractName));
|
return this.contract.appIds(knownContracts.indexOf(contractName));
|
||||||
}
|
}
|
||||||
|
|
||||||
newDAO (options = {}) {
|
newDAO (options = {}) {
|
||||||
return this.contract.functions.newInstance(options).then(transaction => {
|
return this.contract.newInstance(options).then(transaction => {
|
||||||
return transaction.wait().then(result => {
|
return transaction.wait().then(result => {
|
||||||
const deployEvent = result.events.find(e => e.event === 'DeployInstance');
|
const deployEvent = result.events.find(e => e.event === 'DeployInstance');
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const schemas = require('kosmos-schemas');
|
const schemas = require('@kosmos/schemas');
|
||||||
const validator = require('../utils/validator');
|
const validator = require('../utils/validator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const schemas = require('kosmos-schemas');
|
const schemas = require('@kosmos/schemas');
|
||||||
const validator = require('../utils/validator');
|
const validator = require('../utils/validator');
|
||||||
/**
|
/**
|
||||||
* Handle serialization for JSON-LD object of the contributor, according to
|
* Handle serialization for JSON-LD object of the contributor, according to
|
||||||
@@ -13,7 +13,7 @@ class Contributor {
|
|||||||
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
|
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize object to JSON
|
* Serialize object to JSON
|
||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
@@ -28,7 +28,7 @@ class Contributor {
|
|||||||
github_username,
|
github_username,
|
||||||
gitea_username,
|
gitea_username,
|
||||||
wiki_username,
|
wiki_username,
|
||||||
accounts,
|
zoom_display_name,
|
||||||
} = this;
|
} = this;
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
@@ -36,7 +36,7 @@ class Contributor {
|
|||||||
'@type': 'Contributor',
|
'@type': 'Contributor',
|
||||||
kind,
|
kind,
|
||||||
name,
|
name,
|
||||||
accounts: accounts || [],
|
accounts: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
@@ -68,6 +68,13 @@ class Contributor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (zoom_display_name) {
|
||||||
|
data.accounts.push({
|
||||||
|
'site': 'zoom.us',
|
||||||
|
'username': zoom_display_name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Write it pretty to ipfs
|
// Write it pretty to ipfs
|
||||||
return JSON.stringify(data, null, 2);
|
return JSON.stringify(data, null, 2);
|
||||||
}
|
}
|
||||||
@@ -97,10 +104,11 @@ class Contributor {
|
|||||||
accounts,
|
accounts,
|
||||||
} = JSON.parse(serialized.toString('utf8'));
|
} = JSON.parse(serialized.toString('utf8'));
|
||||||
|
|
||||||
let github_username, github_uid, gitea_username, wiki_username;
|
let github_username, github_uid, gitea_username, wiki_username, zoom_display_name;
|
||||||
let github = accounts.find(a => a.site === 'github.com');
|
let github = accounts.find(a => a.site === 'github.com');
|
||||||
let gitea = accounts.find(a => a.site === 'gitea.kosmos.org');
|
let gitea = accounts.find(a => a.site === 'gitea.kosmos.org');
|
||||||
let wiki = accounts.find(a => a.site === 'wiki.kosmos.org');
|
let wiki = accounts.find(a => a.site === 'wiki.kosmos.org');
|
||||||
|
let zoom = accounts.find(a => a.site === 'zoom.us');
|
||||||
|
|
||||||
if (github) {
|
if (github) {
|
||||||
(({ username: github_username, uid: github_uid} = github));
|
(({ username: github_username, uid: github_uid} = github));
|
||||||
@@ -111,6 +119,9 @@ class Contributor {
|
|||||||
if (wiki) {
|
if (wiki) {
|
||||||
(({ username: wiki_username } = wiki));
|
(({ username: wiki_username } = wiki));
|
||||||
}
|
}
|
||||||
|
if (zoom) {
|
||||||
|
(({ username: zoom_display_name } = zoom));
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
@@ -121,6 +132,7 @@ class Contributor {
|
|||||||
github_username,
|
github_username,
|
||||||
gitea_username,
|
gitea_username,
|
||||||
wiki_username,
|
wiki_username,
|
||||||
|
zoom_display_name,
|
||||||
ipfsData: serialized,
|
ipfsData: serialized,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
100
lib/serializers/expense.js
Normal file
100
lib/serializers/expense.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
const schemas = require('@kosmos/schemas');
|
||||||
|
const validator = require('../utils/validator');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialization and validation for JSON-LD document of the Expense
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
class ExpenseSerializer {
|
||||||
|
|
||||||
|
constructor (attrs) {
|
||||||
|
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize object to JSON
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
serialize () {
|
||||||
|
// Write it pretty to ipfs
|
||||||
|
return JSON.stringify(this.data, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
get data () {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
currency,
|
||||||
|
amount,
|
||||||
|
date,
|
||||||
|
url,
|
||||||
|
tags,
|
||||||
|
details,
|
||||||
|
} = this;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
'@context': 'https://schema.kosmos.org',
|
||||||
|
'@type': 'Expense',
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
currency,
|
||||||
|
amount,
|
||||||
|
date,
|
||||||
|
'tags': tags || [],
|
||||||
|
'details': details || {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
data['url'] = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate serialized data against schema
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
validate () {
|
||||||
|
const serialized = JSON.parse(this.serialize());
|
||||||
|
const valid = validator.validate(serialized, schemas['expense']);
|
||||||
|
return valid ? Promise.resolve() : Promise.reject(validator.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize JSON to object
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
static deserialize (serialized) {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
currency,
|
||||||
|
amount,
|
||||||
|
date,
|
||||||
|
url,
|
||||||
|
tags,
|
||||||
|
details,
|
||||||
|
} = JSON.parse(serialized.toString('utf8'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
currency,
|
||||||
|
amount,
|
||||||
|
date,
|
||||||
|
url,
|
||||||
|
tags,
|
||||||
|
details,
|
||||||
|
ipfsData: serialized,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ExpenseSerializer;
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
class IpfsPinner {
|
|
||||||
constructor (kredits) {
|
|
||||||
this.kredits = kredits;
|
|
||||||
}
|
|
||||||
|
|
||||||
pinAll () {
|
|
||||||
return Promise.all([
|
|
||||||
this.kredits.Contributor.pinIpfsHashes(),
|
|
||||||
this.kredits.Contribution.pinIpfsHashes(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor (callback) {
|
|
||||||
this.kredits.Contribution.on('ContributionAdded', (id) => {
|
|
||||||
this.kredits.Contribution.getData(id)
|
|
||||||
.then(data => { return this.kredits.ipfs.pin(data); })
|
|
||||||
.then(callback);
|
|
||||||
});
|
|
||||||
this.kredits.Contributor.on('ContributorAdded', (id) => {
|
|
||||||
this.kredits.Contribution.getData(id)
|
|
||||||
.then(data => { return this.kredits.ipfs.pin(data); })
|
|
||||||
.then(callback);
|
|
||||||
});
|
|
||||||
this.kredits.Contributor.on('ContributorProfileUpdated', (id) => {
|
|
||||||
this.kredits.Contributor.getData(id)
|
|
||||||
.then(data => { return this.kredits.ipfs.pin(data); })
|
|
||||||
.then(callback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
module.exports = IpfsPinner;
|
|
||||||
@@ -11,7 +11,8 @@ class IPFS {
|
|||||||
this._ipfsAPI = ipfsClient(config);
|
this._ipfsAPI = ipfsClient(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
catAndMerge (data, deserialize) {
|
catAndMerge (contractData, deserialize) {
|
||||||
|
let data = {...contractData}; // data from ethers.js is not extensible. this copy the attributes in a new object
|
||||||
// if no hash details are found simply return the data; nothing to merge
|
// if no hash details are found simply return the data; nothing to merge
|
||||||
if (!data.hashSize || data.hashSize === 0) {
|
if (!data.hashSize || data.hashSize === 0) {
|
||||||
return data;
|
return data;
|
||||||
@@ -36,7 +37,7 @@ class IPFS {
|
|||||||
|
|
||||||
cat (hashData) {
|
cat (hashData) {
|
||||||
let ipfsHash = hashData; // default - if it is a string
|
let ipfsHash = hashData; // default - if it is a string
|
||||||
if (hashData.hasOwnProperty('hashSize')) {
|
if (Object.prototype.hasOwnProperty.call(hashData, 'hashSize')) {
|
||||||
ipfsHash = this.encodeHash(hashData);
|
ipfsHash = this.encodeHash(hashData);
|
||||||
}
|
}
|
||||||
if (this._config['gatewayUrl']) {
|
if (this._config['gatewayUrl']) {
|
||||||
@@ -48,7 +49,7 @@ class IPFS {
|
|||||||
|
|
||||||
pin (hashData) {
|
pin (hashData) {
|
||||||
let ipfsHash = hashData; // default - if it is a string
|
let ipfsHash = hashData; // default - if it is a string
|
||||||
if (hashData.hasOwnProperty('hashSize')) {
|
if (Object.prototype.hasOwnProperty.call(hashData, 'hashSize')) {
|
||||||
ipfsHash = this.encodeHash(hashData);
|
ipfsHash = this.encodeHash(hashData);
|
||||||
}
|
}
|
||||||
return this._ipfsAPI.pin.add(multihashes.toB58String(ipfsHash));
|
return this._ipfsAPI.pin.add(multihashes.toB58String(ipfsHash));
|
||||||
|
|||||||
31328
package-lock.json
generated
31328
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kredits-contracts",
|
"name": "kredits-contracts",
|
||||||
"version": "5.4.0",
|
"version": "6.0.0",
|
||||||
"description": "Ethereum contracts and npm wrapper for Kredits",
|
"description": "Ethereum contracts and npm wrapper for Kredits",
|
||||||
"main": "./lib/kredits.js",
|
"main": "./lib/kredits.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@@ -15,15 +15,16 @@
|
|||||||
"compile-contracts": "truffle compile --all",
|
"compile-contracts": "truffle compile --all",
|
||||||
"bootstrap": "npm run reset:hard && npm run seeds",
|
"bootstrap": "npm run reset:hard && npm run seeds",
|
||||||
"reset": "npm run deploy:kit && npm run deploy:dao",
|
"reset": "npm run deploy:kit && npm run deploy:dao",
|
||||||
"reset:hard": "npm run deploy:apps && npm run reset",
|
"reset:hard": "npm run compile-contracts && npm run deploy:apps && npm run reset",
|
||||||
"deploy:kit": "npm run compile-contracts && aragon contracts exec scripts/deploy-kit.js",
|
"deploy:kit": "truffle exec scripts/deploy-kit.js",
|
||||||
"deploy:dao": "aragon contracts exec scripts/new-dao.js",
|
"deploy:dao": "truffle exec scripts/new-dao.js",
|
||||||
"deploy:apps": "./scripts/every-app.sh \"aragon apm publish major\"",
|
"deploy:apps": "./scripts/every-app.sh \"aragon apm publish major --propagate-content=false --build=false --prepublish=false --skip-confirmation\"",
|
||||||
"devchain": "aragon devchain --port 7545",
|
"devchain": "aragon devchain --port 7545",
|
||||||
"dao:address": "truffle exec scripts/current-address.js",
|
"dao:address": "truffle exec scripts/current-address.js",
|
||||||
"lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"",
|
"lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"",
|
||||||
"lint:contract-tests": "eslint apps/*/test",
|
"lint:contract-tests": "eslint apps/*/test",
|
||||||
"lint:wrapper": "eslint lib/",
|
"lint:wrapper": "eslint lib/",
|
||||||
|
"test": "npm run test:token && npm run test:contributor && npm run test:contribution && npm run test:proposal",
|
||||||
"test:token": "cd apps/token && npm run test",
|
"test:token": "cd apps/token && npm run test",
|
||||||
"test:contributor": "cd apps/contributor && npm run test",
|
"test:contributor": "cd apps/contributor && npm run test",
|
||||||
"test:contribution": "cd apps/contribution && npm run test",
|
"test:contribution": "cd apps/contribution && npm run test",
|
||||||
@@ -41,25 +42,28 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/67P/truffle-kredits#readme",
|
"homepage": "https://github.com/67P/truffle-kredits#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aragon/cli": "^5.9.6",
|
|
||||||
"@aragon/kits-base": "^1.0.0",
|
"@aragon/kits-base": "^1.0.0",
|
||||||
"@aragon/os": "^4.2.0",
|
"@aragon/os": "^4.4.0",
|
||||||
"async-each-series": "^1.1.0",
|
"async-each-series": "^1.1.0",
|
||||||
"cli-table": "^0.3.1",
|
"cli-table": "^0.3.1",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^7.1.0",
|
||||||
"eslint-plugin-import": "^2.17.3",
|
"eslint-plugin-import": "^2.20.2",
|
||||||
"eslint-plugin-node": "^8.0.1",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.1.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eth-provider": "^0.2.2",
|
"eth-provider": "^0.2.5",
|
||||||
|
"ethereum-block-by-date": "^1.4.0",
|
||||||
|
"homedir": "^0.6.0",
|
||||||
"promptly": "^3.0.3",
|
"promptly": "^3.0.3",
|
||||||
"solc": "^0.4.26",
|
"solc": "^0.6.8",
|
||||||
"solhint": "^2.1.0",
|
"solhint": "^2.3.1",
|
||||||
"yargs": "^12.0.0"
|
"truffle-hdwallet-provider": "^1.0.17",
|
||||||
|
"truffle-hdwallet-provider-privkey": "^0.3.0",
|
||||||
|
"yargs": "^15.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ethers": "^4.0.29",
|
"ethers": "^5.0.2",
|
||||||
"ipfs-http-client": "^30.1.3",
|
"ipfs-http-client": "^41.0.1",
|
||||||
"kosmos-schemas": "^2.1.0",
|
"@kosmos/schemas": "^3.0.0",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"tv4": "^1.3.0"
|
"tv4": "^1.3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ module.exports = async function(callback) {
|
|||||||
let contributorAccount;
|
let contributorAccount;
|
||||||
if (contributor.length < 5) {
|
if (contributor.length < 5) {
|
||||||
contributorId = contributor;
|
contributorId = contributor;
|
||||||
contributorAccount = await kredits.Contributor.functions.getContributorAddressById(contributor);
|
contributorAccount = await kredits.Contributor.contract.getContributorAddressById(contributor);
|
||||||
} else {
|
} else {
|
||||||
contributorAccount = contributor;
|
contributorAccount = contributor;
|
||||||
contributorId = await kredits.Contributor.functions.getContributorIdByAddress(contributor);
|
contributorId = await kredits.Contributor.contract.getContributorIdByAddress(contributor);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Creating a contribution for contributor account ${contributorAccount} ID: ${contributorId}`);
|
console.log(`Creating a contribution for contributor account ${contributorAccount} ID: ${contributorId}`);
|
||||||
@@ -45,7 +45,7 @@ module.exports = async function(callback) {
|
|||||||
console.log("\nAdding contribution:");
|
console.log("\nAdding contribution:");
|
||||||
console.log(contributionAttributes);
|
console.log(contributionAttributes);
|
||||||
|
|
||||||
kredits.Contribution.addContribution(contributionAttributes, { gasLimit: 300000 })
|
kredits.Contribution.add(contributionAttributes, { gasLimit: 300000 })
|
||||||
.then(result => {
|
.then(result => {
|
||||||
console.log("\n\nResult:");
|
console.log("\n\nResult:");
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ module.exports = async function(callback) {
|
|||||||
let contributorAccount;
|
let contributorAccount;
|
||||||
if (contributor.length < 5) {
|
if (contributor.length < 5) {
|
||||||
contributorId = contributor;
|
contributorId = contributor;
|
||||||
contributorAccount = await kredits.Contributor.functions.getContributorAddressById(contributor);
|
contributorAccount = await kredits.Contributor.contract.getContributorAddressById(contributor);
|
||||||
} else {
|
} else {
|
||||||
contributorAccount = contributor;
|
contributorAccount = contributor;
|
||||||
contributorId = await kredits.Contributor.functions.getContributorIdByAddress(contributor);
|
contributorId = await kredits.Contributor.contract.getContributorIdByAddress(contributor);
|
||||||
}
|
}
|
||||||
console.log(`Creating a proposal for contributor ID #${contributorId} account: ${contributorAccount}`);
|
console.log(`Creating a proposal for contributor ID #${contributorId} account: ${contributorAccount}`);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const files = [
|
|||||||
'Kernel',
|
'Kernel',
|
||||||
'Proposal',
|
'Proposal',
|
||||||
'Token',
|
'Token',
|
||||||
|
'Reimbursement',
|
||||||
'ACL'
|
'ACL'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ module.exports = async function(callback) {
|
|||||||
|
|
||||||
if (c.contributorId === recipient && confirmed && !c.vetoed && !c.claimed) {
|
if (c.contributorId === recipient && confirmed && !c.vetoed && !c.claimed) {
|
||||||
console.log(`Claiming contribution ID=${c.id}`);
|
console.log(`Claiming contribution ID=${c.id}`);
|
||||||
return kredits.Contribution.functions.claim(c.id, { gasLimit: 500000 }).then(tx => {
|
return kredits.Contribution.contract.claim(c.id, { gasLimit: 500000 }).then(tx => {
|
||||||
table.push([
|
table.push([
|
||||||
c.id.toString(),
|
c.id.toString(),
|
||||||
`${c.description}`,
|
`${c.description}`,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ module.exports = async function(callback) {
|
|||||||
|
|
||||||
method = await promptly.prompt('Function: ');
|
method = await promptly.prompt('Function: ');
|
||||||
}
|
}
|
||||||
if (!contractWrapper[method] && !contractWrapper.functions[method]) {
|
if (!contractWrapper[method] && !contractWrapper.contract[method]) {
|
||||||
callback(new Error(`Method ${method} is not defined on ${contractName}`));
|
callback(new Error(`Method ${method} is not defined on ${contractName}`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ module.exports = async function(callback) {
|
|||||||
if (contractWrapper[method]) {
|
if (contractWrapper[method]) {
|
||||||
func = contractWrapper[method];
|
func = contractWrapper[method];
|
||||||
} else {
|
} else {
|
||||||
func = contractWrapper.functions[method];
|
func = contractWrapper.contract[method];
|
||||||
}
|
}
|
||||||
func.apply(contractWrapper, args).then((result) => {
|
func.apply(contractWrapper, args).then((result) => {
|
||||||
console.log("\nResult:");
|
console.log("\nResult:");
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
const knownDAOAddresses = require('../lib/addresses/dao.json');
|
const knownDAOAddresses = require('../lib/addresses/dao.json');
|
||||||
const knownKreditsKitAddresses = require('../lib/addresses/KreditsKit.json');
|
const knownKreditsKitAddresses = require('../lib/addresses/KreditsKit.json');
|
||||||
const getNetworkId = require('./helpers/networkid.js')
|
const getNetworkId = require('./helpers/networkid.js')
|
||||||
|
const ethers = require('ethers');
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
module.exports = async function(callback) {
|
||||||
const networkId = await getNetworkId(web3)
|
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
||||||
|
let network = await provider.getNetwork();
|
||||||
|
let networkId = network.chainId;
|
||||||
|
|
||||||
console.log('# All known DAO addresses');
|
console.log('# All known DAO addresses');
|
||||||
Object.keys(knownDAOAddresses).forEach((networkId) => {
|
Object.keys(knownDAOAddresses).forEach((networkId) => {
|
||||||
|
|||||||
@@ -3,23 +3,33 @@ const deployDAOFactory = require('@aragon/os/scripts/deploy-daofactory.js')
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const argv = require('yargs').argv
|
const argv = require('yargs').argv
|
||||||
const namehash = require('ethers').utils.namehash;
|
const ethers = require('ethers');
|
||||||
|
const namehash = ethers.utils.namehash;
|
||||||
|
|
||||||
const fileInject = require('./helpers/file_inject.js')
|
const fileInject = require('./helpers/file_inject.js')
|
||||||
const getNetworkId = require('./helpers/networkid.js')
|
|
||||||
|
|
||||||
const DAOFactory = artifacts.require('DAOFactory')
|
const DAOFactory = artifacts.require('DAOFactory')
|
||||||
const KreditsKit = artifacts.require('KreditsKit')
|
const KreditsKit = artifacts.require('KreditsKit')
|
||||||
|
|
||||||
const arapp = require('../arapp.json')
|
const arapp = require('../arapp.json')
|
||||||
const environment = argv['network'] || argv['environment'] || 'development'
|
const environment = argv['network'] || argv['environment'] || 'development'
|
||||||
const apm = arapp.environments[environment].apm
|
|
||||||
const ensAddr = arapp.environments[environment].registry || process.env.ENS
|
|
||||||
const daoFactoryAddress = arapp.environments[environment].daoFactory || process.env.DAO_FACTORY
|
|
||||||
|
|
||||||
|
const kreditsArappConfig = arapp.environments[environment].kredits || {}
|
||||||
|
|
||||||
|
// typically we use the open.aragonpm.eth aragonpm.
|
||||||
|
const apm = kreditsArappConfig.apmDomain || argv['apmDomain'] || 'open.aragonpm.eth'
|
||||||
|
|
||||||
|
// daoFactory is environment specific.
|
||||||
|
// See https://github.com/aragon/deployments/tree/master/environments/ for the official daoFactory
|
||||||
|
// Locally we deploy our own daoFactory and no daoFactory is required (`daoFactoryAddress` is null).
|
||||||
|
const daoFactoryAddress = kreditsArappConfig.daoFactory || argv['daoFactory']
|
||||||
|
|
||||||
|
const ensAddr = arapp.environments[environment].registry || argv['ensAddress']
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
module.exports = async function(callback) {
|
||||||
const networkId = await getNetworkId(web3)
|
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
||||||
|
const network = await provider.getNetwork();
|
||||||
|
const networkId = network.chainId;
|
||||||
console.log(`Deploying to networkId: ${networkId}`)
|
console.log(`Deploying to networkId: ${networkId}`)
|
||||||
|
|
||||||
if (!ensAddr) {
|
if (!ensAddr) {
|
||||||
|
|||||||
49
scripts/export/contributions.js
Normal file
49
scripts/export/contributions.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const ethers = require('ethers');
|
||||||
|
const Kredits = require('../../lib/kredits');
|
||||||
|
const provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_rinkeby');
|
||||||
|
|
||||||
|
const arapp = require('../../arapp.json');
|
||||||
|
const apm = arapp.environments['rinkeby'].apm;
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const kredits = await new Kredits(provider, null, { apm });
|
||||||
|
//kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||||
|
await kredits.init();
|
||||||
|
|
||||||
|
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
||||||
|
|
||||||
|
const count = await kredits.Contribution.count;
|
||||||
|
const currentBlockHeight = await provider.getBlockNumber();
|
||||||
|
|
||||||
|
const backup = {};
|
||||||
|
const promises = [];
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
promises.push(new Promise((resolve, reject) => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
console.log(`Loading contribution #${i}`);
|
||||||
|
await kredits.Contribution.contract.getContribution(i).then(contractData => {
|
||||||
|
backup[i] = {
|
||||||
|
amount: contractData.amount,
|
||||||
|
contributorId: contractData.contributorId,
|
||||||
|
hashDigest: contractData.hashDigest,
|
||||||
|
hashFunction: contractData.hashFunction,
|
||||||
|
hashSize: contractData.hashSize,
|
||||||
|
confirmedAtBlock: contractData.confirmedAtBlock,
|
||||||
|
confirmed: contractData.confirmedAtBlock <= currentBlockHeight,
|
||||||
|
vetoed: contractData.vetoed,
|
||||||
|
id: contractData.id,
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}, 100 * i);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises).then(() => {
|
||||||
|
fs.writeFileSync("./data/contributions.json", JSON.stringify(backup, null, 2));
|
||||||
|
console.log("Exported");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
44
scripts/export/contributors.js
Normal file
44
scripts/export/contributors.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const ethers = require('ethers');
|
||||||
|
const Kredits = require('../../lib/kredits');
|
||||||
|
const provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_rinkeby');
|
||||||
|
|
||||||
|
const arapp = require('../../arapp.json');
|
||||||
|
const apm = arapp.environments['rinkeby'].apm;
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const kredits = await new Kredits(provider, null, { apm });
|
||||||
|
//kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||||
|
await kredits.init();
|
||||||
|
|
||||||
|
console.log(`Using Contributor at: ${kredits.Contributor.contract.address}`);
|
||||||
|
|
||||||
|
const count = await kredits.Contributor.count;
|
||||||
|
|
||||||
|
const backup = {};
|
||||||
|
const promises = [];
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
promises.push(new Promise((resolve, reject) => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
console.log(`Loading contributor #${i}`);
|
||||||
|
await kredits.Contributor.contract.getContributorById(i).then(contractData => {
|
||||||
|
backup[i] = {
|
||||||
|
account: contractData.account,
|
||||||
|
hashDigest: contractData.hashDigest,
|
||||||
|
hashFunction: contractData.hashFunction,
|
||||||
|
hashSize: contractData.hashSize,
|
||||||
|
id: contractData.id,
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}, 100 * i);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises).then(() => {
|
||||||
|
fs.writeFileSync("./data/contributors.json", JSON.stringify(backup, null, 2));
|
||||||
|
console.log("Exported");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
19
scripts/find-block-for-date.js
Normal file
19
scripts/find-block-for-date.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const promptly = require('promptly');
|
||||||
|
const EthDater = require('ethereum-block-by-date');
|
||||||
|
const initKredits = require('./helpers/init_kredits.js');
|
||||||
|
|
||||||
|
module.exports = async function(callback) {
|
||||||
|
let kredits;
|
||||||
|
try { kredits = await initKredits(web3); } catch(e) { callback(e); return; }
|
||||||
|
|
||||||
|
const dater = new EthDater(kredits.provider);
|
||||||
|
const dateStr = await promptly.prompt('Specify a date and time (e.g. 2021-05-07T14:00:40Z): ');
|
||||||
|
const blockData = await dater.getDate(dateStr, true);
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
The closest block is #${blockData.block}:
|
||||||
|
https://rinkeby.etherscan.io/block/${blockData.block}
|
||||||
|
`);
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
const argv = require('yargs').argv;
|
const argv = require('yargs').argv;
|
||||||
const ethers = require('ethers');
|
const ethers = require('ethers');
|
||||||
const getNetworkId = require('./networkid.js');
|
|
||||||
const Kredits = require('../../lib/kredits');
|
const Kredits = require('../../lib/kredits');
|
||||||
|
|
||||||
const arapp = require('../../arapp.json');
|
const arapp = require('../../arapp.json');
|
||||||
@@ -10,7 +9,7 @@ const apm = arapp.environments[environment].apm;
|
|||||||
module.exports = async function(web3) {
|
module.exports = async function(web3) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
||||||
let signer = provider.getSigner();
|
const signer = provider.getSigner();
|
||||||
// checking if siner supports signing transactions
|
// checking if siner supports signing transactions
|
||||||
signer.getAddress().then(_ => {
|
signer.getAddress().then(_ => {
|
||||||
new Kredits(provider, signer, { apm }).init().then(kredits => {
|
new Kredits(provider, signer, { apm }).init().then(kredits => {
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
module.exports = function(web3) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let func;
|
|
||||||
if (web3.version.getNetwork) {
|
|
||||||
func = web3.version.getNetwork;
|
|
||||||
} else {
|
|
||||||
func = web3.eth.net.getId;
|
|
||||||
}
|
|
||||||
func((err, network) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
resolve(network);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const getNetworkId = require('./networkid.js');
|
const ethers = require('ethers');
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
module.exports = async function(callback) {
|
||||||
const daoAddressPath = 'lib/addresses/dao.json';
|
const daoAddressPath = 'lib/addresses/dao.json';
|
||||||
|
|
||||||
// TODO maybe do the same for KreditsKit address file
|
// TODO maybe do the same for KreditsKit address file
|
||||||
try {
|
try {
|
||||||
const networkId = await getNetworkId(web3);
|
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
||||||
|
const network = await provider.getNetwork();
|
||||||
|
const networkId = network.chainId;
|
||||||
const daoAddresses = JSON.parse(fs.readFileSync(daoAddressPath));
|
const daoAddresses = JSON.parse(fs.readFileSync(daoAddressPath));
|
||||||
const oldNetworkId = Math.max(...Object.keys(daoAddresses).map(a => parseInt(a)));
|
const oldNetworkId = Math.max(...Object.keys(daoAddresses).map(a => parseInt(a)));
|
||||||
const localDaoAddress = daoAddresses[oldNetworkId];
|
const localDaoAddress = daoAddresses[oldNetworkId];
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
const Kredits = require('../lib/kredits');
|
|
||||||
const IpfsPinner = require('../lib/utils/ipfs-pinner');
|
|
||||||
|
|
||||||
const network = process.env.ETH_NETWORK || 'rinkeby';
|
|
||||||
const rpcUrl = process.env.ETH_RPC_URL;
|
|
||||||
const apm = process.env.APM_DOMAIN || 'open.aragonpm.eth';
|
|
||||||
|
|
||||||
const ipfsConfig = {
|
|
||||||
host: process.env.IPFS_HOST || 'localhost',
|
|
||||||
port: process.env.IPFS_PORT || '5001',
|
|
||||||
protocol: process.env.IPFS_PROTOCOL || 'http',
|
|
||||||
};
|
|
||||||
console.log(`Using IPFS:`, ipfsConfig);
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
const kredits = await Kredits.for({ network, rpcUrl }, { apm, ipfsConfig }).init();
|
|
||||||
const ipfsPinner = new IpfsPinner(kredits);
|
|
||||||
|
|
||||||
ipfsPinner.pinAll().then(pins => {
|
|
||||||
console.log('Pinned', JSON.stringify(pins, null, 2));
|
|
||||||
});
|
|
||||||
ipfsPinner.monitor((pin) => {
|
|
||||||
console.log('Pinned', JSON.stringify(pin));
|
|
||||||
});
|
|
||||||
console.log(`Subscribed to DAO: ${kredits.Kernel.contract.address}`);
|
|
||||||
} catch(e) {
|
|
||||||
console.log(e);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
76
scripts/list-contributions-per-contributor.js
Normal file
76
scripts/list-contributions-per-contributor.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
const promptly = require('promptly');
|
||||||
|
const Table = require('cli-table');
|
||||||
|
|
||||||
|
const initKredits = require('./helpers/init_kredits.js');
|
||||||
|
|
||||||
|
module.exports = async function(callback) {
|
||||||
|
let kredits;
|
||||||
|
try {
|
||||||
|
kredits = await initKredits(web3);
|
||||||
|
} catch(e) {
|
||||||
|
callback(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
||||||
|
|
||||||
|
const table = new Table({
|
||||||
|
head: ['ID', 'Name', 'Kredits']
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
let currentBlockNumber = await kredits.provider.getBlockNumber();
|
||||||
|
console.log(`Current block number: ${currentBlockNumber}`);
|
||||||
|
|
||||||
|
let confirmedBeforeBlock = await promptly.prompt('Before block: ');
|
||||||
|
let confirmedAfterBlock = await promptly.prompt('After block: ');
|
||||||
|
|
||||||
|
let tokens = {};
|
||||||
|
let contributors = await kredits.Contributor.all();
|
||||||
|
contributors.forEach(c => {
|
||||||
|
tokens[c.id] = { amount: 0, contributor: c };
|
||||||
|
});
|
||||||
|
|
||||||
|
let contributionId = await kredits.Contribution.contract.contributionsCount();
|
||||||
|
let nextContribution = true;
|
||||||
|
|
||||||
|
while (nextContribution) {
|
||||||
|
console.log(`Getting contribution: ${contributionId}`);
|
||||||
|
let contribution = await kredits.Contribution.getById(contributionId);
|
||||||
|
contributionId = contributionId - 1;
|
||||||
|
|
||||||
|
// if no conribution is found
|
||||||
|
if (!contribution.exists) {
|
||||||
|
nextContribution = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check if the contribution is older
|
||||||
|
// in that case we assume all other contributions now are older
|
||||||
|
if (contribution.confirmedAtBlock < confirmedAfterBlock) {
|
||||||
|
nextContribution = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the contribution is within the range count it
|
||||||
|
if (!contribution.vetoed && contribution.confirmedAtBlock < confirmedBeforeBlock && contribution.confirmedAtBlock > confirmedAfterBlock) {
|
||||||
|
// init
|
||||||
|
tokens[contribution.contributorId].amount = tokens[contribution.contributorId].amount + contribution.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(tokens).forEach((contributorId) => {
|
||||||
|
table.push([
|
||||||
|
contributorId,
|
||||||
|
`${tokens[contributorId].contributor.name}`,
|
||||||
|
`${tokens[contributorId].amount}`
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const total = Object.keys(tokens).map(cid => { return tokens[cid].amount}).reduce((a,b) => { return a+b }, 0);
|
||||||
|
console.log(`Total confirmed Kredits: ${total} between block ${confirmedAfterBlock} and ${confirmedBeforeBlock}`);
|
||||||
|
console.log(table.toString());
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
@@ -41,8 +41,8 @@ module.exports = async function(callback) {
|
|||||||
|
|
||||||
console.log(table.toString());
|
console.log(table.toString());
|
||||||
|
|
||||||
let totalKreditsEarnedUnConfirmed = await kredits.Contribution.functions.totalKreditsEarned(false);
|
let totalKreditsEarnedUnConfirmed = await kredits.Contribution.contract.totalKreditsEarned(false);
|
||||||
let totalKreditsEarnedConfirmed = await kredits.Contribution.functions.totalKreditsEarned(true);
|
let totalKreditsEarnedConfirmed = await kredits.Contribution.contract.totalKreditsEarned(true);
|
||||||
console.log(`Total Kredits: ${totalKreditsEarnedConfirmed} (confirmed) | ${totalKreditsEarnedUnConfirmed} (including unconfirmed)`);
|
console.log(`Total Kredits: ${totalKreditsEarnedConfirmed} (confirmed) | ${totalKreditsEarnedUnConfirmed} (including unconfirmed)`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|||||||
52
scripts/list-reimbursements.js
Normal file
52
scripts/list-reimbursements.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
const promptly = require('promptly');
|
||||||
|
const Table = require('cli-table');
|
||||||
|
|
||||||
|
const initKredits = require('./helpers/init_kredits.js');
|
||||||
|
|
||||||
|
module.exports = async function(callback) {
|
||||||
|
let kredits;
|
||||||
|
try {
|
||||||
|
kredits = await initKredits(web3);
|
||||||
|
} catch(e) {
|
||||||
|
callback(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
|
||||||
|
|
||||||
|
const table = new Table({
|
||||||
|
head: ['ID', 'Amount', 'Token', 'recipientId', 'Confirmed?', 'Vetoed?', 'IPFS', 'Expenses']
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
let blockNumber = await kredits.provider.getBlockNumber();
|
||||||
|
let reimbursements = await kredits.Reimbursement.all({page: {size: 1000}});
|
||||||
|
|
||||||
|
let kreditsSum = 0;
|
||||||
|
console.log(`Current block number: ${blockNumber}`);
|
||||||
|
reimbursements.forEach(r => {
|
||||||
|
const confirmed = r.confirmedAtBlock <= blockNumber;
|
||||||
|
|
||||||
|
table.push([
|
||||||
|
r.id.toString(),
|
||||||
|
r.amount.toString(),
|
||||||
|
`${r.token}`,
|
||||||
|
`${r.recipientId}`,
|
||||||
|
`${confirmed}`,
|
||||||
|
`${r.vetoed}`,
|
||||||
|
`${r.ipfsHash}`,
|
||||||
|
`${r.expenses.length}`
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(table.toString());
|
||||||
|
|
||||||
|
let totalAmountUnconfirmed = await kredits.Reimbursement.functions.totalAmount(false);
|
||||||
|
let totalAmountConfirmed = await kredits.Reimbursement.functions.totalAmount(true);
|
||||||
|
console.log(`Total: ${totalAmountConfirmed} (confirmed) | ${totalAmountUnconfirmed} (including unconfirmed)`);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
@@ -3,13 +3,15 @@ const path = require('path');
|
|||||||
|
|
||||||
const ethers = require('ethers');
|
const ethers = require('ethers');
|
||||||
const fileInject = require('./helpers/file_inject.js');
|
const fileInject = require('./helpers/file_inject.js');
|
||||||
const getNetworkId = require('./helpers/networkid.js');
|
|
||||||
const KreditsKit = require('../lib/kreditskit');
|
const KreditsKit = require('../lib/kreditskit');
|
||||||
|
|
||||||
const addressesPath = path.join(__dirname, '..', 'lib/addresses');
|
const addressesPath = path.join(__dirname, '..', 'lib/addresses');
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
module.exports = async function(callback) {
|
||||||
const networkId = await getNetworkId(web3)
|
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
||||||
|
const signer = provider.getSigner();
|
||||||
|
const network = await provider.getNetwork();
|
||||||
|
const networkId = network.chainId;
|
||||||
console.log(`Deploying to networkId: ${networkId}`)
|
console.log(`Deploying to networkId: ${networkId}`)
|
||||||
|
|
||||||
let kitAddresseFile = path.join(addressesPath, 'KreditsKit.json');
|
let kitAddresseFile = path.join(addressesPath, 'KreditsKit.json');
|
||||||
@@ -20,9 +22,6 @@ module.exports = async function(callback) {
|
|||||||
}
|
}
|
||||||
console.log(`Using KreditsKit at: ${kreditsKitAddress}`);
|
console.log(`Using KreditsKit at: ${kreditsKitAddress}`);
|
||||||
|
|
||||||
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
|
|
||||||
let signer = provider.getSigner();
|
|
||||||
|
|
||||||
let kit = await new KreditsKit(provider, signer).init()
|
let kit = await new KreditsKit(provider, signer).init()
|
||||||
|
|
||||||
// TODO: get rid of the hard coded gas limit
|
// TODO: get rid of the hard coded gas limit
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ module.exports = async function(callback) {
|
|||||||
if (contractWrapper[method]) {
|
if (contractWrapper[method]) {
|
||||||
func = contractWrapper[method];
|
func = contractWrapper[method];
|
||||||
} else {
|
} else {
|
||||||
func = contractWrapper.functions[method];
|
func = contractWrapper.contract[method];
|
||||||
}
|
}
|
||||||
func.apply(contractWrapper, args).then((result) => {
|
func.apply(contractWrapper, args).then((result) => {
|
||||||
console.log(`[OK] kredits.${contractName}.${method}(${JSON.stringify(args)}) => ${result.hash}`);
|
console.log(`[OK] kredits.${contractName}.${method}(${JSON.stringify(args)}) => ${result.hash}`);
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ module.exports = async function(callback) {
|
|||||||
let amount = await promptly.prompt('Amount: ', {default: '1'});
|
let amount = await promptly.prompt('Amount: ', {default: '1'});
|
||||||
amount = parseInt(amount);
|
amount = parseInt(amount);
|
||||||
|
|
||||||
let fromAccount = web3.eth.accounts[0];
|
const accounts = await web3.eth.personal.getAccounts();
|
||||||
|
let fromAccount = accounts[0];
|
||||||
let fromBalance = await web3.eth.getBalance(fromAccount);
|
let fromBalance = await web3.eth.getBalance(fromAccount);
|
||||||
let recipientBalance = await web3.eth.getBalance(recipient);
|
let recipientBalance = await web3.eth.getBalance(recipient);
|
||||||
|
|
||||||
@@ -13,11 +14,11 @@ module.exports = async function(callback) {
|
|||||||
console.log(`sender account balance ${fromAccount}: ${fromBalance}`);
|
console.log(`sender account balance ${fromAccount}: ${fromBalance}`);
|
||||||
console.log(`recipient account balance ${recipient}: ${recipientBalance}`);
|
console.log(`recipient account balance ${recipient}: ${recipientBalance}`);
|
||||||
|
|
||||||
console.log(`\nsending ${amount} ETH from ${web3.eth.accounts[0]} to ${recipient}`);
|
console.log(`\nsending ${amount} ETH from ${accounts[0]} to ${recipient}`);
|
||||||
|
|
||||||
let transaction = await web3.eth.sendTransaction({to: recipient, value: web3.toWei(amount), from: web3.eth.accounts[0]});
|
let transaction = await web3.eth.sendTransaction({to: recipient, value: web3.utils.toWei(new web3.utils.BN(amount)), from: accounts[0]});
|
||||||
|
|
||||||
console.log(`transaction id: ${transaction}`);
|
console.log(`transaction id: ${transaction.transactionHash}`);
|
||||||
|
|
||||||
recipientBalance = await web3.eth.getBalance(recipient);
|
recipientBalance = await web3.eth.getBalance(recipient);
|
||||||
console.log(`\nnew recipient account balance ${recipient}: ${recipientBalance}`);
|
console.log(`\nnew recipient account balance ${recipient}: ${recipientBalance}`);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module.exports = async function(callback) {
|
|||||||
console.log(`Recording a veto for contribution #${contributionId}`);
|
console.log(`Recording a veto for contribution #${contributionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
|
kredits.Contribution.contract.veto(contributionId, { gasLimit: 300000 })
|
||||||
.then(result => {
|
.then(result => {
|
||||||
console.log("\n\nResult:");
|
console.log("\n\nResult:");
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
|||||||
Reference in New Issue
Block a user