Compare commits
1 Commits
master
...
feature/co
Author | SHA1 | Date | |
---|---|---|---|
759436f870 |
@ -1,6 +0,0 @@
|
||||
.openzeppelin
|
||||
artifacts
|
||||
cache
|
||||
deployments
|
||||
gitno
|
||||
node_modules
|
40
.drone.yml
40
.drone.yml
@ -1,40 +0,0 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: setup
|
||||
image: gitea.kosmos.org/kredits/docker-ci:latest
|
||||
commands:
|
||||
- cp -r /app/node_modules /drone/src/node_modules
|
||||
- chown -R drone:drone /drone/src
|
||||
- su drone -c 'npm install'
|
||||
- name: lint js
|
||||
image: gitea.kosmos.org/kredits/docker-ci:latest
|
||||
commands:
|
||||
- su drone -c 'npm run lint:wrapper'
|
||||
depends_on:
|
||||
- setup
|
||||
# - name: lint contracts
|
||||
# image: gitea.kosmos.org/kredits/docker-ci:latest
|
||||
# commands:
|
||||
# - su drone -c 'npm run lint:contracts'
|
||||
# depends_on:
|
||||
# - setup
|
||||
- name: build contracts
|
||||
image: gitea.kosmos.org/kredits/docker-ci:latest
|
||||
commands:
|
||||
- su drone -c 'npm run devchain -- --silent' &
|
||||
- sleep 5
|
||||
- su drone -c 'npm run build'
|
||||
depends_on:
|
||||
- setup
|
||||
- name: test
|
||||
image: gitea.kosmos.org/kredits/docker-ci:latest
|
||||
commands:
|
||||
- su drone -c 'npm run devchain -- --silent' &
|
||||
- sleep 5
|
||||
- su drone -c 'npm test'
|
||||
depends_on:
|
||||
- setup
|
||||
- build contracts
|
@ -1,2 +0,0 @@
|
||||
/scripts/
|
||||
/test/
|
33
.eslintrc.js
33
.eslintrc.js
@ -1,33 +0,0 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es6': true,
|
||||
'node': true
|
||||
},
|
||||
'extends': 'eslint:recommended',
|
||||
'globals': {
|
||||
'Atomics': 'readonly',
|
||||
'SharedArrayBuffer': 'readonly'
|
||||
},
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 2018,
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'rules': {
|
||||
'comma-dangle': ['error', {
|
||||
arrays: 'always-multiline',
|
||||
objects: 'always-multiline',
|
||||
imports: 'never',
|
||||
exports: 'never',
|
||||
functions: 'ignore',
|
||||
}],
|
||||
'eol-last': ['error', 'always'],
|
||||
semi: ['error', 'always'],
|
||||
'space-before-function-paren': ['error', {
|
||||
anonymous: 'never',
|
||||
named: 'always',
|
||||
asyncArrow: 'always',
|
||||
}],
|
||||
'indent': ['error', 2]
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
name-template: 'v$RESOLVED_VERSION'
|
||||
tag-template: 'v$RESOLVED_VERSION'
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- release/major
|
||||
minor:
|
||||
labels:
|
||||
- release/minor
|
||||
- feature
|
||||
patch:
|
||||
labels:
|
||||
- release/patch
|
||||
default: patch
|
@ -1,11 +0,0 @@
|
||||
name: Release Drafter
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
jobs:
|
||||
release_drafter_job:
|
||||
name: Update release notes draft
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Release Drafter
|
||||
uses: https://github.com/raucao/gitea-release-drafter@dev
|
4
.github/release-drafter.yml
vendored
4
.github/release-drafter.yml
vendored
@ -1,4 +0,0 @@
|
||||
template: |
|
||||
## Changes
|
||||
|
||||
$CHANGES
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,13 +1,3 @@
|
||||
build
|
||||
node_modules
|
||||
**/node_modules
|
||||
.ganache-db
|
||||
.tm_properties
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
|
||||
data
|
||||
|
||||
cache
|
||||
artifacts
|
||||
.openzeppelin/unknown-1337.json
|
||||
.env
|
||||
.ganache-db
|
@ -1,937 +0,0 @@
|
||||
{
|
||||
"manifestVersion": "3.2",
|
||||
"admin": {
|
||||
"address": "0xcf844786B3E8b23f6d6D8CA845c0DE07047D54a7",
|
||||
"txHash": "0xafcf40769c999bae279f48e7d81d0f698c82286dd4178029021f82ecb549e645"
|
||||
},
|
||||
"proxies": [
|
||||
{
|
||||
"address": "0x0E4b2A1b7655266Ba9A029B50eEB42DBCd83090B",
|
||||
"txHash": "0xfd629e11999d0448404c81e33ea79cbd18f8a978cf93afcf5c45e97eb63991f8",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x242fab10d4F395B9DCC59b8Adc6629722c2E65d2",
|
||||
"txHash": "0xcd6633873db24736e9f40a4c401b658b469b290176e0d03e640ccfb7945a5426",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x4fe4311a91F90ff98f0978002D84AE4771fe7cF1",
|
||||
"txHash": "0x8b6e5088ad7f39918bf9e3e67cdc45bd9bf2a62b13e4f7a1441ad3bca27b4c04",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x252b3Ab7913d6Ed8f303a7e5452F0BFf8bE6b64d",
|
||||
"txHash": "0x138a863f21ab0ef2400434280bc8c9e389e6dead125b5622deb9533eb2506a53",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x2C5cf87C0dE8e4E3642de900Fa7B4b630163E2aA",
|
||||
"txHash": "0x0e4310cd5faba8ce7cae60b3de1412050b4315957e58bc8415680eb5e9de0314",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x95DC31665D193E377f54b70C535fcDb205525291",
|
||||
"txHash": "0xb03a4d57e80f73d65f29f75fc419fd6197148e979ed9c330353c8574d952c544",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x049bA8E70FEbFfd6d03C71211bDA37B4ff064115",
|
||||
"txHash": "0x5f561059950c1e06fc62cfc7cac4c4618a0e066704fb680b659ae9a08b6e1d27",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x7ab26A0f00eF0D6e05e5BDE047505a4eD53aF809",
|
||||
"txHash": "0xfa73dbe843ea1151f925f531365fb919b6138c8963e62332c8e00cf5141e457c",
|
||||
"kind": "transparent"
|
||||
},
|
||||
{
|
||||
"address": "0x99EC72b34295b62f4bC1527Da461262c615a0b2c",
|
||||
"txHash": "0x1ca664ffdf50a6519b900c84e715d43a59ae39b35d5914ecb964f5440d486098",
|
||||
"kind": "transparent"
|
||||
}
|
||||
],
|
||||
"impls": {
|
||||
"4ef0a0d41e92c95e53ad65fb957441f9b9443f4fe2d1c2221dfde7d1341db071": {
|
||||
"address": "0x73069A23A5252E9c0D0b5F0493918277074ED987",
|
||||
"txHash": "0x4c139a7a70dea23d9fdbcb7d8d381be7593fc3d80d59f29aec0fd6f16698136b",
|
||||
"layout": {
|
||||
"storage": [
|
||||
{
|
||||
"label": "_initialized",
|
||||
"offset": 0,
|
||||
"slot": "0",
|
||||
"type": "t_uint8",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62",
|
||||
"retypedFrom": "bool"
|
||||
},
|
||||
{
|
||||
"label": "_initializing",
|
||||
"offset": 1,
|
||||
"slot": "0",
|
||||
"type": "t_bool",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67"
|
||||
},
|
||||
{
|
||||
"label": "deployer",
|
||||
"offset": 2,
|
||||
"slot": "0",
|
||||
"type": "t_address",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:15"
|
||||
},
|
||||
{
|
||||
"label": "contributionContract",
|
||||
"offset": 0,
|
||||
"slot": "1",
|
||||
"type": "t_contract(IContributionBalance)2238",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:16"
|
||||
},
|
||||
{
|
||||
"label": "tokenContract",
|
||||
"offset": 0,
|
||||
"slot": "2",
|
||||
"type": "t_contract(IToken)2221",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:17"
|
||||
},
|
||||
{
|
||||
"label": "contributorIds",
|
||||
"offset": 0,
|
||||
"slot": "3",
|
||||
"type": "t_mapping(t_address,t_uint32)",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:28"
|
||||
},
|
||||
{
|
||||
"label": "contributors",
|
||||
"offset": 0,
|
||||
"slot": "4",
|
||||
"type": "t_mapping(t_uint32,t_struct(Contributor)2261_storage)",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:29"
|
||||
},
|
||||
{
|
||||
"label": "contributorsCount",
|
||||
"offset": 0,
|
||||
"slot": "5",
|
||||
"type": "t_uint32",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:30"
|
||||
},
|
||||
{
|
||||
"label": "profileManager",
|
||||
"offset": 4,
|
||||
"slot": "5",
|
||||
"type": "t_address",
|
||||
"contract": "Contributor",
|
||||
"src": "contracts/Contributor.sol:32"
|
||||
}
|
||||
],
|
||||
"types": {
|
||||
"t_address": {
|
||||
"label": "address",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_bool": {
|
||||
"label": "bool",
|
||||
"numberOfBytes": "1"
|
||||
},
|
||||
"t_bytes32": {
|
||||
"label": "bytes32",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_contract(IContributionBalance)2238": {
|
||||
"label": "contract IContributionBalance",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_contract(IToken)2221": {
|
||||
"label": "contract IToken",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_mapping(t_address,t_uint32)": {
|
||||
"label": "mapping(address => uint32)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_mapping(t_uint32,t_struct(Contributor)2261_storage)": {
|
||||
"label": "mapping(uint32 => struct Contributor.Contributor)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_struct(Contributor)2261_storage": {
|
||||
"label": "struct Contributor.Contributor",
|
||||
"members": [
|
||||
{
|
||||
"label": "account",
|
||||
"type": "t_address",
|
||||
"offset": 0,
|
||||
"slot": "0"
|
||||
},
|
||||
{
|
||||
"label": "hashDigest",
|
||||
"type": "t_bytes32",
|
||||
"offset": 0,
|
||||
"slot": "1"
|
||||
},
|
||||
{
|
||||
"label": "hashFunction",
|
||||
"type": "t_uint8",
|
||||
"offset": 0,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "hashSize",
|
||||
"type": "t_uint8",
|
||||
"offset": 1,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "exists",
|
||||
"type": "t_bool",
|
||||
"offset": 2,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "kreditsWithdrawn",
|
||||
"type": "t_uint32",
|
||||
"offset": 3,
|
||||
"slot": "2"
|
||||
}
|
||||
],
|
||||
"numberOfBytes": "96"
|
||||
},
|
||||
"t_uint32": {
|
||||
"label": "uint32",
|
||||
"numberOfBytes": "4"
|
||||
},
|
||||
"t_uint8": {
|
||||
"label": "uint8",
|
||||
"numberOfBytes": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"960de0fa0d50c2ede5b2a868a9475e44622a753d4ff7829422c7eb342572b189": {
|
||||
"address": "0x872fa1C9d207b5ce3CE786f2099c3EeA621dFD70",
|
||||
"txHash": "0xb338b0878d66e466425c9032ef0f9019f91cda395fae4f83c999534249cd228d",
|
||||
"layout": {
|
||||
"storage": [
|
||||
{
|
||||
"label": "_initialized",
|
||||
"offset": 0,
|
||||
"slot": "0",
|
||||
"type": "t_uint8",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62",
|
||||
"retypedFrom": "bool"
|
||||
},
|
||||
{
|
||||
"label": "_initializing",
|
||||
"offset": 1,
|
||||
"slot": "0",
|
||||
"type": "t_bool",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67"
|
||||
},
|
||||
{
|
||||
"label": "contributorContract",
|
||||
"offset": 2,
|
||||
"slot": "0",
|
||||
"type": "t_contract(ContributorInterface)1546",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:14"
|
||||
},
|
||||
{
|
||||
"label": "name_",
|
||||
"offset": 0,
|
||||
"slot": "1",
|
||||
"type": "t_string_storage",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:28"
|
||||
},
|
||||
{
|
||||
"label": "symbol_",
|
||||
"offset": 0,
|
||||
"slot": "2",
|
||||
"type": "t_string_storage",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:29"
|
||||
},
|
||||
{
|
||||
"label": "contributionOwner",
|
||||
"offset": 0,
|
||||
"slot": "3",
|
||||
"type": "t_mapping(t_uint32,t_uint32)",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:32"
|
||||
},
|
||||
{
|
||||
"label": "ownedContributions",
|
||||
"offset": 0,
|
||||
"slot": "4",
|
||||
"type": "t_mapping(t_uint32,t_array(t_uint32)dyn_storage)",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:34"
|
||||
},
|
||||
{
|
||||
"label": "contributions",
|
||||
"offset": 0,
|
||||
"slot": "5",
|
||||
"type": "t_mapping(t_uint32,t_struct(ContributionData)1570_storage)",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:36"
|
||||
},
|
||||
{
|
||||
"label": "contributionsCount",
|
||||
"offset": 0,
|
||||
"slot": "6",
|
||||
"type": "t_uint32",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:37"
|
||||
},
|
||||
{
|
||||
"label": "blocksToWait",
|
||||
"offset": 4,
|
||||
"slot": "6",
|
||||
"type": "t_uint32",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:40"
|
||||
},
|
||||
{
|
||||
"label": "deployer",
|
||||
"offset": 8,
|
||||
"slot": "6",
|
||||
"type": "t_address",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:43"
|
||||
},
|
||||
{
|
||||
"label": "migrationDone",
|
||||
"offset": 28,
|
||||
"slot": "6",
|
||||
"type": "t_bool",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:46"
|
||||
}
|
||||
],
|
||||
"types": {
|
||||
"t_address": {
|
||||
"label": "address",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_array(t_uint32)dyn_storage": {
|
||||
"label": "uint32[]",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_bool": {
|
||||
"label": "bool",
|
||||
"numberOfBytes": "1"
|
||||
},
|
||||
"t_bytes32": {
|
||||
"label": "bytes32",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_contract(ContributorInterface)1546": {
|
||||
"label": "contract ContributorInterface",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_mapping(t_uint32,t_array(t_uint32)dyn_storage)": {
|
||||
"label": "mapping(uint32 => uint32[])",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_mapping(t_uint32,t_struct(ContributionData)1570_storage)": {
|
||||
"label": "mapping(uint32 => struct Contribution.ContributionData)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_mapping(t_uint32,t_uint32)": {
|
||||
"label": "mapping(uint32 => uint32)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_string_storage": {
|
||||
"label": "string",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_struct(ContributionData)1570_storage": {
|
||||
"label": "struct Contribution.ContributionData",
|
||||
"members": [
|
||||
{
|
||||
"label": "contributorId",
|
||||
"type": "t_uint32",
|
||||
"offset": 0,
|
||||
"slot": "0"
|
||||
},
|
||||
{
|
||||
"label": "amount",
|
||||
"type": "t_uint32",
|
||||
"offset": 4,
|
||||
"slot": "0"
|
||||
},
|
||||
{
|
||||
"label": "hashDigest",
|
||||
"type": "t_bytes32",
|
||||
"offset": 0,
|
||||
"slot": "1"
|
||||
},
|
||||
{
|
||||
"label": "hashFunction",
|
||||
"type": "t_uint8",
|
||||
"offset": 0,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "hashSize",
|
||||
"type": "t_uint8",
|
||||
"offset": 1,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "tokenMetadataURL",
|
||||
"type": "t_string_storage",
|
||||
"offset": 0,
|
||||
"slot": "3"
|
||||
},
|
||||
{
|
||||
"label": "confirmedAtBlock",
|
||||
"type": "t_uint256",
|
||||
"offset": 0,
|
||||
"slot": "4"
|
||||
},
|
||||
{
|
||||
"label": "vetoed",
|
||||
"type": "t_bool",
|
||||
"offset": 0,
|
||||
"slot": "5"
|
||||
},
|
||||
{
|
||||
"label": "exists",
|
||||
"type": "t_bool",
|
||||
"offset": 1,
|
||||
"slot": "5"
|
||||
}
|
||||
],
|
||||
"numberOfBytes": "192"
|
||||
},
|
||||
"t_uint256": {
|
||||
"label": "uint256",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_uint32": {
|
||||
"label": "uint32",
|
||||
"numberOfBytes": "4"
|
||||
},
|
||||
"t_uint8": {
|
||||
"label": "uint8",
|
||||
"numberOfBytes": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"75d216a88a04f139c0c69c1369ddd6ded974ebf995ccce44546b6ace2dabb597": {
|
||||
"address": "0x2D7848AF9Af0d2d8D67bbaAbf84D58Bd19F17eFa",
|
||||
"txHash": "0x8a6621bfc3db4c2bc2d294d69e6d25d499c7667b8da1910b3b0f2bc43968adba",
|
||||
"layout": {
|
||||
"storage": [
|
||||
{
|
||||
"label": "_initialized",
|
||||
"offset": 0,
|
||||
"slot": "0",
|
||||
"type": "t_uint8",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62",
|
||||
"retypedFrom": "bool"
|
||||
},
|
||||
{
|
||||
"label": "_initializing",
|
||||
"offset": 1,
|
||||
"slot": "0",
|
||||
"type": "t_bool",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67"
|
||||
},
|
||||
{
|
||||
"label": "__gap",
|
||||
"offset": 0,
|
||||
"slot": "1",
|
||||
"type": "t_array(t_uint256)50_storage",
|
||||
"contract": "ContextUpgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36"
|
||||
},
|
||||
{
|
||||
"label": "_balances",
|
||||
"offset": 0,
|
||||
"slot": "51",
|
||||
"type": "t_mapping(t_address,t_uint256)",
|
||||
"contract": "ERC20Upgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:37"
|
||||
},
|
||||
{
|
||||
"label": "_allowances",
|
||||
"offset": 0,
|
||||
"slot": "52",
|
||||
"type": "t_mapping(t_address,t_mapping(t_address,t_uint256))",
|
||||
"contract": "ERC20Upgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:39"
|
||||
},
|
||||
{
|
||||
"label": "_totalSupply",
|
||||
"offset": 0,
|
||||
"slot": "53",
|
||||
"type": "t_uint256",
|
||||
"contract": "ERC20Upgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:41"
|
||||
},
|
||||
{
|
||||
"label": "_name",
|
||||
"offset": 0,
|
||||
"slot": "54",
|
||||
"type": "t_string_storage",
|
||||
"contract": "ERC20Upgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:43"
|
||||
},
|
||||
{
|
||||
"label": "_symbol",
|
||||
"offset": 0,
|
||||
"slot": "55",
|
||||
"type": "t_string_storage",
|
||||
"contract": "ERC20Upgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44"
|
||||
},
|
||||
{
|
||||
"label": "__gap",
|
||||
"offset": 0,
|
||||
"slot": "56",
|
||||
"type": "t_array(t_uint256)45_storage",
|
||||
"contract": "ERC20Upgradeable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:400"
|
||||
},
|
||||
{
|
||||
"label": "contributorContract",
|
||||
"offset": 0,
|
||||
"slot": "101",
|
||||
"type": "t_contract(ContributorInterface)3364",
|
||||
"contract": "Token",
|
||||
"src": "contracts/Token.sol:13"
|
||||
},
|
||||
{
|
||||
"label": "contributorContractAddress",
|
||||
"offset": 0,
|
||||
"slot": "102",
|
||||
"type": "t_address",
|
||||
"contract": "Token",
|
||||
"src": "contracts/Token.sol:16"
|
||||
}
|
||||
],
|
||||
"types": {
|
||||
"t_address": {
|
||||
"label": "address",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_array(t_uint256)45_storage": {
|
||||
"label": "uint256[45]",
|
||||
"numberOfBytes": "1440"
|
||||
},
|
||||
"t_array(t_uint256)50_storage": {
|
||||
"label": "uint256[50]",
|
||||
"numberOfBytes": "1600"
|
||||
},
|
||||
"t_bool": {
|
||||
"label": "bool",
|
||||
"numberOfBytes": "1"
|
||||
},
|
||||
"t_contract(ContributorInterface)3364": {
|
||||
"label": "contract ContributorInterface",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_mapping(t_address,t_mapping(t_address,t_uint256))": {
|
||||
"label": "mapping(address => mapping(address => uint256))",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_mapping(t_address,t_uint256)": {
|
||||
"label": "mapping(address => uint256)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_string_storage": {
|
||||
"label": "string",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_uint256": {
|
||||
"label": "uint256",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_uint8": {
|
||||
"label": "uint8",
|
||||
"numberOfBytes": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"d06fbc00ef593e162a054b1f961d39eaf32e0734f8ba230d3519837b8548e33b": {
|
||||
"address": "0x5b8AF16247593465cC82b68A7Af49338E141A207",
|
||||
"txHash": "0x2e052dd42231aa43a484c5a4c376e73b70fd14026611be0b585c826d37fe829c",
|
||||
"layout": {
|
||||
"storage": [
|
||||
{
|
||||
"label": "_initialized",
|
||||
"offset": 0,
|
||||
"slot": "0",
|
||||
"type": "t_uint8",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62",
|
||||
"retypedFrom": "bool"
|
||||
},
|
||||
{
|
||||
"label": "_initializing",
|
||||
"offset": 1,
|
||||
"slot": "0",
|
||||
"type": "t_bool",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67"
|
||||
},
|
||||
{
|
||||
"label": "contributorContract",
|
||||
"offset": 2,
|
||||
"slot": "0",
|
||||
"type": "t_contract(ContributorInterface)2958",
|
||||
"contract": "Reimbursement",
|
||||
"src": "contracts/Reimbursement.sol:14"
|
||||
},
|
||||
{
|
||||
"label": "reimbursements",
|
||||
"offset": 0,
|
||||
"slot": "1",
|
||||
"type": "t_mapping(t_uint32,t_struct(ReimbursementData)2982_storage)",
|
||||
"contract": "Reimbursement",
|
||||
"src": "contracts/Reimbursement.sol:29"
|
||||
},
|
||||
{
|
||||
"label": "reimbursementsCount",
|
||||
"offset": 0,
|
||||
"slot": "2",
|
||||
"type": "t_uint32",
|
||||
"contract": "Reimbursement",
|
||||
"src": "contracts/Reimbursement.sol:30"
|
||||
},
|
||||
{
|
||||
"label": "blocksToWait",
|
||||
"offset": 4,
|
||||
"slot": "2",
|
||||
"type": "t_uint32",
|
||||
"contract": "Reimbursement",
|
||||
"src": "contracts/Reimbursement.sol:32"
|
||||
}
|
||||
],
|
||||
"types": {
|
||||
"t_address": {
|
||||
"label": "address",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_bool": {
|
||||
"label": "bool",
|
||||
"numberOfBytes": "1"
|
||||
},
|
||||
"t_bytes32": {
|
||||
"label": "bytes32",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_contract(ContributorInterface)2958": {
|
||||
"label": "contract ContributorInterface",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_mapping(t_uint32,t_struct(ReimbursementData)2982_storage)": {
|
||||
"label": "mapping(uint32 => struct Reimbursement.ReimbursementData)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_struct(ReimbursementData)2982_storage": {
|
||||
"label": "struct Reimbursement.ReimbursementData",
|
||||
"members": [
|
||||
{
|
||||
"label": "recipientId",
|
||||
"type": "t_uint32",
|
||||
"offset": 0,
|
||||
"slot": "0"
|
||||
},
|
||||
{
|
||||
"label": "amount",
|
||||
"type": "t_uint256",
|
||||
"offset": 0,
|
||||
"slot": "1"
|
||||
},
|
||||
{
|
||||
"label": "token",
|
||||
"type": "t_address",
|
||||
"offset": 0,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "hashDigest",
|
||||
"type": "t_bytes32",
|
||||
"offset": 0,
|
||||
"slot": "3"
|
||||
},
|
||||
{
|
||||
"label": "hashFunction",
|
||||
"type": "t_uint8",
|
||||
"offset": 0,
|
||||
"slot": "4"
|
||||
},
|
||||
{
|
||||
"label": "hashSize",
|
||||
"type": "t_uint8",
|
||||
"offset": 1,
|
||||
"slot": "4"
|
||||
},
|
||||
{
|
||||
"label": "confirmedAtBlock",
|
||||
"type": "t_uint256",
|
||||
"offset": 0,
|
||||
"slot": "5"
|
||||
},
|
||||
{
|
||||
"label": "vetoed",
|
||||
"type": "t_bool",
|
||||
"offset": 0,
|
||||
"slot": "6"
|
||||
},
|
||||
{
|
||||
"label": "exists",
|
||||
"type": "t_bool",
|
||||
"offset": 1,
|
||||
"slot": "6"
|
||||
}
|
||||
],
|
||||
"numberOfBytes": "224"
|
||||
},
|
||||
"t_uint256": {
|
||||
"label": "uint256",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_uint32": {
|
||||
"label": "uint32",
|
||||
"numberOfBytes": "4"
|
||||
},
|
||||
"t_uint8": {
|
||||
"label": "uint8",
|
||||
"numberOfBytes": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"27e6fdeedf4e7e81a2c2ecc839d0c13414aa8f5527d4d3573f469358c8aad652": {
|
||||
"address": "0xfaeA425E6eDd4e9B31dAa3614c7c7862751D6782",
|
||||
"txHash": "0xe7768586dbfb5d528db3c9d0c2a608a4fcb5d7f04eb9f89913ac21b8d20a72df",
|
||||
"layout": {
|
||||
"storage": [
|
||||
{
|
||||
"label": "_initialized",
|
||||
"offset": 0,
|
||||
"slot": "0",
|
||||
"type": "t_uint8",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62",
|
||||
"retypedFrom": "bool"
|
||||
},
|
||||
{
|
||||
"label": "_initializing",
|
||||
"offset": 1,
|
||||
"slot": "0",
|
||||
"type": "t_bool",
|
||||
"contract": "Initializable",
|
||||
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67"
|
||||
},
|
||||
{
|
||||
"label": "contributorContract",
|
||||
"offset": 2,
|
||||
"slot": "0",
|
||||
"type": "t_contract(ContributorInterface)1546",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:14"
|
||||
},
|
||||
{
|
||||
"label": "name_",
|
||||
"offset": 0,
|
||||
"slot": "1",
|
||||
"type": "t_string_storage",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:28"
|
||||
},
|
||||
{
|
||||
"label": "symbol_",
|
||||
"offset": 0,
|
||||
"slot": "2",
|
||||
"type": "t_string_storage",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:29"
|
||||
},
|
||||
{
|
||||
"label": "contributionOwner",
|
||||
"offset": 0,
|
||||
"slot": "3",
|
||||
"type": "t_mapping(t_uint32,t_uint32)",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:32"
|
||||
},
|
||||
{
|
||||
"label": "ownedContributions",
|
||||
"offset": 0,
|
||||
"slot": "4",
|
||||
"type": "t_mapping(t_uint32,t_array(t_uint32)dyn_storage)",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:34"
|
||||
},
|
||||
{
|
||||
"label": "contributions",
|
||||
"offset": 0,
|
||||
"slot": "5",
|
||||
"type": "t_mapping(t_uint32,t_struct(ContributionData)1570_storage)",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:36"
|
||||
},
|
||||
{
|
||||
"label": "contributionsCount",
|
||||
"offset": 0,
|
||||
"slot": "6",
|
||||
"type": "t_uint32",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:37"
|
||||
},
|
||||
{
|
||||
"label": "blocksToWait",
|
||||
"offset": 4,
|
||||
"slot": "6",
|
||||
"type": "t_uint32",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:40"
|
||||
},
|
||||
{
|
||||
"label": "deployer",
|
||||
"offset": 8,
|
||||
"slot": "6",
|
||||
"type": "t_address",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:43"
|
||||
},
|
||||
{
|
||||
"label": "migrationDone",
|
||||
"offset": 28,
|
||||
"slot": "6",
|
||||
"type": "t_bool",
|
||||
"contract": "Contribution",
|
||||
"src": "contracts/Contribution.sol:46"
|
||||
}
|
||||
],
|
||||
"types": {
|
||||
"t_address": {
|
||||
"label": "address",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_array(t_uint32)dyn_storage": {
|
||||
"label": "uint32[]",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_bool": {
|
||||
"label": "bool",
|
||||
"numberOfBytes": "1"
|
||||
},
|
||||
"t_bytes32": {
|
||||
"label": "bytes32",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_contract(ContributorInterface)1546": {
|
||||
"label": "contract ContributorInterface",
|
||||
"numberOfBytes": "20"
|
||||
},
|
||||
"t_mapping(t_uint32,t_array(t_uint32)dyn_storage)": {
|
||||
"label": "mapping(uint32 => uint32[])",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_mapping(t_uint32,t_struct(ContributionData)1570_storage)": {
|
||||
"label": "mapping(uint32 => struct Contribution.ContributionData)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_mapping(t_uint32,t_uint32)": {
|
||||
"label": "mapping(uint32 => uint32)",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_string_storage": {
|
||||
"label": "string",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_struct(ContributionData)1570_storage": {
|
||||
"label": "struct Contribution.ContributionData",
|
||||
"members": [
|
||||
{
|
||||
"label": "contributorId",
|
||||
"type": "t_uint32",
|
||||
"offset": 0,
|
||||
"slot": "0"
|
||||
},
|
||||
{
|
||||
"label": "amount",
|
||||
"type": "t_uint32",
|
||||
"offset": 4,
|
||||
"slot": "0"
|
||||
},
|
||||
{
|
||||
"label": "hashDigest",
|
||||
"type": "t_bytes32",
|
||||
"offset": 0,
|
||||
"slot": "1"
|
||||
},
|
||||
{
|
||||
"label": "hashFunction",
|
||||
"type": "t_uint8",
|
||||
"offset": 0,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "hashSize",
|
||||
"type": "t_uint8",
|
||||
"offset": 1,
|
||||
"slot": "2"
|
||||
},
|
||||
{
|
||||
"label": "tokenMetadataURL",
|
||||
"type": "t_string_storage",
|
||||
"offset": 0,
|
||||
"slot": "3"
|
||||
},
|
||||
{
|
||||
"label": "confirmedAtBlock",
|
||||
"type": "t_uint256",
|
||||
"offset": 0,
|
||||
"slot": "4"
|
||||
},
|
||||
{
|
||||
"label": "vetoed",
|
||||
"type": "t_bool",
|
||||
"offset": 0,
|
||||
"slot": "5"
|
||||
},
|
||||
{
|
||||
"label": "exists",
|
||||
"type": "t_bool",
|
||||
"offset": 1,
|
||||
"slot": "5"
|
||||
}
|
||||
],
|
||||
"numberOfBytes": "192"
|
||||
},
|
||||
"t_uint256": {
|
||||
"label": "uint256",
|
||||
"numberOfBytes": "32"
|
||||
},
|
||||
"t_uint32": {
|
||||
"label": "uint32",
|
||||
"numberOfBytes": "4"
|
||||
},
|
||||
"t_uint8": {
|
||||
"label": "uint8",
|
||||
"numberOfBytes": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"solhint:default",
|
||||
"solhint:recommended"
|
||||
],
|
||||
"rules": {
|
||||
"max-line-length": "warn"
|
||||
}
|
||||
}
|
13
Dockerfile
13
Dockerfile
@ -1,13 +0,0 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:16.16
|
||||
#ENV NODE_ENV=production
|
||||
|
||||
RUN useradd -ms /bin/bash drone
|
||||
|
||||
WORKDIR /app
|
||||
COPY ["package.json", "package-lock.json*", "./"]
|
||||
RUN chown -R drone:drone /app
|
||||
USER drone
|
||||
RUN npm install
|
||||
USER root
|
158
README.md
158
README.md
@ -1,158 +0,0 @@
|
||||
[](https://www.npmjs.com/package/@kredits/contracts)
|
||||
[](https://drone.kosmos.org/kredits/contracts)
|
||||
|
||||
# Kredits Contracts
|
||||
|
||||
This repository contains the Solidity smart contracts and the JavaScript API
|
||||
wrapper for [Kosmos Kredits](https://wiki.kosmos.org/Kredits).
|
||||
|
||||
## Development
|
||||
|
||||
### Installation
|
||||
|
||||
#### App dependencies
|
||||
|
||||
All requirements are defined in `package.json`.
|
||||
|
||||
$ npm install
|
||||
|
||||
### Local development chain
|
||||
|
||||
We use [hardhat](https://hardhat.org/) as development environment for the
|
||||
smart contracts.
|
||||
|
||||
To run a local development chain run:
|
||||
|
||||
$ npm run devchain # or: hardhat node --network hardhat
|
||||
|
||||
### Bootstrap
|
||||
|
||||
1. Run an EVM node and ipfs
|
||||
|
||||
$ npm run devchain
|
||||
$ ipfs daemon
|
||||
|
||||
2. Compile contracts and build ABIs
|
||||
|
||||
(compiled artifacts will be in `/artifacts`)
|
||||
$ npm run build
|
||||
|
||||
3. Deploy new upgradable contract proxies
|
||||
|
||||
$ npm run deploy:dao
|
||||
|
||||
4. Execute seeds to create demo contributors, contributions, etc. (optional)
|
||||
|
||||
$ npm run seeds
|
||||
|
||||
**Step 2-4 is also summarized in `npm run bootstrap`**
|
||||
|
||||
5. Show contract addresses
|
||||
|
||||
$ cat lib/addresses.json
|
||||
|
||||
## Fund a local development account
|
||||
|
||||
If you need to fund development accounts with devchain coins:
|
||||
|
||||
$ npm run fund # or hardhat fund --network localhost
|
||||
|
||||
## Specs / Testing
|
||||
|
||||
With a local development chain running:
|
||||
|
||||
$ hardhat test
|
||||
|
||||
If you add or change contract code, please make sure to add and/or adapt tests
|
||||
accordingly. Don't worry, it's easy! You can use existing tests as a template
|
||||
for new ones.
|
||||
|
||||
## Contract architecture
|
||||
|
||||
We use the [OpenZeppelin hardhat
|
||||
proxy](https://www.npmjs.com/package/@openzeppelin/hardhat-upgrades) for
|
||||
deploying and managing upgradeable contracts. (see `scripts/create-proxy.js`)
|
||||
|
||||
Each contract is independent and is connected to its dependencies by storing
|
||||
the addresses of the other contracts.
|
||||
|
||||
## Helper scripts
|
||||
|
||||
`scripts/` contains some helper scripts to interact with the contracts from the
|
||||
CLI. _At some point these should be moved into a real nice CLI._
|
||||
|
||||
To run these scripts use `hardhat run`. For example: `hardhat run
|
||||
scripts/list-contributors.js --network localhost`. (NOTE: add `--network
|
||||
localhost` or the network you want to use)
|
||||
|
||||
Some scripts are also defined as npm script, see `package.json`.
|
||||
|
||||
### repl/console
|
||||
|
||||
Similar to cli.js but only provides a REPL with an initialized `kredits`
|
||||
instance.
|
||||
|
||||
$ hardhat console --network localhost
|
||||
|
||||
### add-{contributor, contribution, proposal}.js
|
||||
|
||||
Script to add a new entries to the contracts using the JS wrapper
|
||||
|
||||
$ hardhat run scripts/add-{contributor, contribution, proposal}.js --network localhost
|
||||
|
||||
### list-{contributors, contributions, proposals}.js
|
||||
|
||||
List contract entries
|
||||
|
||||
$ hardhat run scripts/list-{contributors, contributions, proposals}.js --network localhost
|
||||
|
||||
### seeds.js
|
||||
|
||||
Run seeds defined in `config/seeds.js`.
|
||||
|
||||
$ npm run seeds
|
||||
|
||||
### Get the contract addresses
|
||||
|
||||
All contract addresses are stored in `lib/addresses.json`
|
||||
|
||||
$ cat lib/addresses.json
|
||||
|
||||
## Upgradeable contracts
|
||||
|
||||
We use OpenZeppelin for an upgradeable contracts:
|
||||
[https://www.npmjs.com/package/@openzeppelin/hardhat-upgrades](https://www.npmjs.com/package/@openzeppelin/hardhat-upgrades)
|
||||
|
||||
Refer to the OpenZeppelin README and `scripts/create-proxy.js`
|
||||
|
||||
[OpenZeppelin Step by Step guide](https://forum.openzeppelin.com/t/openzeppelin-upgrades-step-by-step-tutorial-for-hardhat/3580)
|
||||
|
||||
For an upgrade example checkout `scripts/upgrade-example.js`
|
||||
|
||||
|
||||
## Deployment to other networks
|
||||
|
||||
Deployable networks are configured in the `hardhat.config.js`.
|
||||
|
||||
To deploy to those networks provide the `--network` argument to the hardhat
|
||||
commands, e.g. `--network rsk`.
|
||||
|
||||
Please note that some npm scripts combine multiple hardhat commands. In those
|
||||
cases the hardhat commands needs to be run manually with the `--network`
|
||||
argument. (=> don't use `npm run bootstrap`)
|
||||
|
||||
Set a `DEPLOY_KEY` environment variable with the private key (HEX) which will
|
||||
be used as a root/deploy account
|
||||
|
||||
Typical deployment flow:
|
||||
|
||||
$ npm run build
|
||||
$ hardhat run scripts/create-proxy.js --network rsk
|
||||
# OR with deploy key:
|
||||
$ DEPLOY_KEY=0xsomething hardhat run scripts/create-proxy.js --network rsk
|
||||
$ # commit the new addresses in the addresses.json file if needed
|
||||
|
||||
To run the console on one of the non localhost networks you can also just pass
|
||||
on the --network argument.
|
||||
|
||||
$ hardhat console --network rsk
|
153
README.mdown
Normal file
153
README.mdown
Normal file
@ -0,0 +1,153 @@
|
||||
# Kredits
|
||||
|
||||
This repository contains all the contracts for Kredits as a [truffle framework](http://truffleframework.com/) project.
|
||||
|
||||
## Development
|
||||
|
||||
### Installation
|
||||
|
||||
$ npm install
|
||||
|
||||
### Requirements
|
||||
|
||||
All requirements are defined in `package.json`.
|
||||
|
||||
Those can be installed globally for convenience:
|
||||
* [truffle framework](http://truffleframework.com): `npm install -g truffle`
|
||||
* [ganache](http://truffleframework.com/ganache): `npm install -g ganache-cli`
|
||||
|
||||
We use following solidity contract libraries:
|
||||
* [Open Zeppelin](https://github.com/OpenZeppelin/zeppelin-solidity)
|
||||
|
||||
For local development it is recommended to use [ganache-cli](https://github.com/trufflesuite/ganache-cli) (or the [ganache GUI](http://truffleframework.com/ganache/) to run a local development chain.
|
||||
Using the ganache simulator no full Ethereum node is required.
|
||||
|
||||
We default to:
|
||||
|
||||
* port 7545 for development to not get in conflict with the default Ethereum RPC port.
|
||||
* network ID 100 to stay on the same network id
|
||||
* store ganache data in .ganache-db to presist the chain data across restarts
|
||||
* use a fixed Mnemonic code to get the same accounts across restarts
|
||||
|
||||
Have a look at `ganache-cli` for more configuration options.
|
||||
|
||||
Run your ganache simulator before using Kredits locally:
|
||||
|
||||
$ npm run ganache (which is: ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits)
|
||||
|
||||
### Truffle console
|
||||
|
||||
Truffle comes with a simple REPL to interact with the Smart Contracts. Have a look at the [documentation here](http://truffleframework.com/docs/getting_started/console)
|
||||
|
||||
NOTE: There are promisses, have a look at the examples:
|
||||
|
||||
```javascript
|
||||
Token.deployed().then(function(token) {
|
||||
token.totalSupply.call().then(function(value) {
|
||||
console.log(value.toString());
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
Also please be aware of the differences between web3.js 0.2x.x and [1.x.x](https://web3js.readthedocs.io/en/1.0/) - [web3 repo](https://github.com/ethereum/web3.js/)
|
||||
|
||||
|
||||
## Contract Deployment
|
||||
|
||||
Truffle uses migration scripts to deploy contract to various networks. Have a look at the `migrations` folder for those.
|
||||
The Ethereum nodes for the different networks need to be configured in `truffle.js`.
|
||||
|
||||
Run the truffle migration scripts:
|
||||
|
||||
$ truffle deploy
|
||||
$ truffle deploy --network=<network config from truffle.js>
|
||||
|
||||
Truffle keeps track of already executed migration scripts. To reset the migration use the `--reset` option
|
||||
|
||||
$ truffle migrate --reset
|
||||
|
||||
Migration scripts can also be run from within `truffle console` or `truffle develop`
|
||||
|
||||
To initially bootstrap a local development chain in ganache you can use the bootstrap script:
|
||||
|
||||
$ npm run bootstrap (= `truffle migrate --reset && truffle exec scripts/seeds.js && npm run build-json`)
|
||||
|
||||
|
||||
## Helper scripts
|
||||
|
||||
`scripts/` contains some helper scripts to interact with the contracts from the CLI.
|
||||
At some point these should be moved into a real nice CLI.
|
||||
|
||||
To run these scripts use `truffle exec`. For example: `truffle exec scripts/add-proposal.js`
|
||||
|
||||
### cli.js
|
||||
|
||||
Call any function on any contract:
|
||||
|
||||
$ truffle exec scripts/cli.js <Contract Name> <Function> [<optional> <arguments>]
|
||||
|
||||
For example:
|
||||
$ truffle exec scripts/cli.js Operator proposalsCount
|
||||
|
||||
Please note that the contract name and the function are case sensitive.
|
||||
|
||||
### add-contributor.js
|
||||
Adds a new core contributor, creates a proposal for the new contributor and votes for that one.
|
||||
|
||||
$ truffle exec scripts/add-contributor.js <ethereum address> [<profile IPFS hash>]
|
||||
|
||||
### add-proposal.js
|
||||
Adds a new proposal for an existing contributor
|
||||
|
||||
$ truffle exec scripts/add-proposal.js <ethereum address> [<proposal IPFS hash>]
|
||||
|
||||
### send-funds.js
|
||||
Sends funds to an address. Helpful in development mode to for example fund a metamask account.
|
||||
|
||||
$ truffle exec scripts/send-funds.js <ethereum address>
|
||||
|
||||
### seeds.js
|
||||
Run seeds defined in `config/seeds.js`.
|
||||
|
||||
$ truffle exec scripts/seeds.js
|
||||
or
|
||||
$ npm run seeds
|
||||
|
||||
|
||||
## Upgradeable contracts
|
||||
|
||||
Some of the contracts use upgradability ideas from [zeppelinos](https://github.com/zeppelinos/labs) (see `contracts/upgradable`).
|
||||
|
||||
The basic idea is to have a Registry contract that knows about the current implementations and a Proxy contract that uses `delegatecall` to call the current implementation.
|
||||
That means the Proxy contract holds the storage and the address of that one does not change but the actuall implemenation is managed through the Registry.
|
||||
|
||||
To deploy a new version a new contract is deployed then the version is registered (`addVersion()`) in the Registry and on the Proxy contract is "upgraded" (`upgrade()`) to the new version.
|
||||
|
||||
The Registry knows about all the different contracts and implementations. Versions are stored as uint and automatically incremented for every added implementation.
|
||||
|
||||
|
||||
### Example:
|
||||
|
||||
Deployment is best done using the [truffle deployer]()
|
||||
|
||||
1. Setup
|
||||
1. deploy the Registry
|
||||
2. deploy the contract
|
||||
3. register the contract at the Registry:
|
||||
`registry.addVersion('Token', Token.address)`
|
||||
4. create the Proxy:
|
||||
`registry.createProxy('Token', 1)`
|
||||
2. Update
|
||||
1. deploy a new Version of the contract
|
||||
2. register the new version at the Registry:
|
||||
`registry.addVersion('Token', NewToken.address)`
|
||||
3. set the new implementation address on the Proxy contract:
|
||||
`registry.upgrade('Token', 2)`
|
||||
|
||||
|
||||
## Known Issues
|
||||
|
||||
When resetting ganache Metamask might have an invalid transaction nonce and transactions get rejected.
|
||||
Nonces in Ethereum must be incrementing and have no gap.
|
||||
|
||||
To solve this reset the metamask account (Account -> Settings -> Reset Account)
|
@ -1,91 +1,9 @@
|
||||
const contractCalls = [
|
||||
['Contributor', 'add', [{
|
||||
account: '0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
||||
name: 'bumi',
|
||||
kind: 'person',
|
||||
url: '',
|
||||
github_username: 'bumi',
|
||||
github_uid: 318,
|
||||
gitea_username: 'bumi',
|
||||
wiki_username: 'Bumi',
|
||||
}, { gasLimit: 200000 }]],
|
||||
|
||||
['Contributor', 'add', [{
|
||||
account: '0x49575f3DD9a0d60aE661BC992f72D837A77f05Bc',
|
||||
name: 'raucao',
|
||||
kind: 'person',
|
||||
url: '',
|
||||
github_username: 'raucao',
|
||||
github_uid: 842,
|
||||
gitea_username: 'raucao',
|
||||
wiki_username: 'Basti',
|
||||
}, { gasLimit: 200000 }]],
|
||||
|
||||
['Contributor', 'add', [{
|
||||
account: '0xF722709ECC3B05c19d02E82a2a4A4021B8F48C62',
|
||||
name: 'Manuel',
|
||||
kind: 'person',
|
||||
url: '',
|
||||
github_username: 'fsmanuel',
|
||||
github_uid: 54812,
|
||||
wiki_username: 'Manuel',
|
||||
}, { gasLimit: 200000 }]],
|
||||
|
||||
['Contribution', 'add', [{
|
||||
contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF',
|
||||
date: '2019-04-11', amount: 500, kind: 'dev',
|
||||
description: '[67P/kredits-contracts] Test this thing',
|
||||
url: '',
|
||||
confirmedAtBlock: 1,
|
||||
}, { gasLimit: 350000 }]],
|
||||
|
||||
['Contribution', 'add', [{
|
||||
contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB',
|
||||
date: '2019-04-11', amount: 1500, kind: 'dev',
|
||||
description: '[67P/kredits-web] Reviewed stuff',
|
||||
url: '',
|
||||
confirmedAtBlock: 1,
|
||||
}, { gasLimit: 350000 }]],
|
||||
|
||||
['Contribution', 'add', [{
|
||||
contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF',
|
||||
date: '2019-04-11', amount: 5000, kind: 'dev',
|
||||
description: '[67P/kredits-contracts] Add tests',
|
||||
url: '',
|
||||
confirmedAtBlock: 1,
|
||||
}, { 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: 1500, kind: 'design',
|
||||
description: '[67P/kredits-web] Expense UI, first draft',
|
||||
url: '',
|
||||
}, { gasLimit: 350000 }]],
|
||||
|
||||
['Reimbursement', 'add', [{ amount: 346800, recipientId: 2, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
|
||||
{ title: 'Domain kosmos.social', description: 'Yearly registration fee for domain kosmos.social', amount: 69.00, currency: 'EUR', amountSats: 69216, date: '2020-04-30' },
|
||||
], confirmedAtBlock: 1 }, { gasLimit: 300000 }]],
|
||||
|
||||
['Reimbursement', 'add', [{ amount: 1116000, recipientId: 1, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
|
||||
{ title: 'Server rent', description: 'Dedicated server: andromeda.kosmos.org, April 2020', amount: 61, currency: 'EUR', amountSats: 61191, date: '2020-05-28' },
|
||||
{ title: 'Server rent', description: 'Dedicated server: centaurus.kosmos.org, April 2020', amount: 32, currency: 'EUR', amountSats: 32201, date: '2020-05-28' },
|
||||
], confirmedAtBlock: 1 }, { 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', amountSats: 13944, date: '2020-05-30' },
|
||||
]}, { gasLimit: 300000 }]],
|
||||
let contractCalls = [
|
||||
['Contributor', 'add', [{ account: '0x7e8f313c56f809188313aa274fa67ee58c31515d', name: 'bumi', isCore: true, kind: 'preson', url: '', github_username: 'bumi', github_uid: 318, wiki_username: 'bumi' }, {gasLimit: 200000}]],
|
||||
['Contributor', 'add', [{ account: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', name: 'raucau', isCore: true, kind: 'person', url: '', github_username: 'skddc', github_uid: 842, wiki_username: 'raucau' }, {gasLimit: 200000}]],
|
||||
['Operator', 'addProposal', [{ contributorId: 2, amount: 42, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
|
||||
['Operator', 'addProposal', [{ contributorId: 3, amount: 23, kind: 'code', description: 'runs the seeds', url: '' }, {gasLimit: 350000}]],
|
||||
['Operator', 'addProposal', [{contributorId: 3, amount: 100, kind: 'code', description: 'hacks on kredits', url: '' }, {gasLimit: 350000}]],
|
||||
['Operator', 'vote', ['1', {gasLimit: 250000}]]
|
||||
];
|
||||
|
||||
const funds = [
|
||||
'0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
||||
'0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827',
|
||||
];
|
||||
|
||||
module.exports = { contractCalls, funds };
|
||||
module.exports = { contractCalls };
|
||||
|
@ -1,199 +0,0 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
interface ContributorInterface {
|
||||
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||
function addressIsCore(address sender) external view returns (bool);
|
||||
// TODO Maybe use for validation
|
||||
// function exists(uint32 contributorId) public view returns (bool);
|
||||
}
|
||||
|
||||
contract Contribution is Initializable {
|
||||
ContributorInterface public contributorContract;
|
||||
|
||||
struct ContributionData {
|
||||
uint32 contributorId;
|
||||
uint32 amount;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
string tokenMetadataURL;
|
||||
uint256 confirmedAtBlock;
|
||||
bool vetoed;
|
||||
bool exists;
|
||||
}
|
||||
|
||||
string internal name_;
|
||||
string internal symbol_;
|
||||
|
||||
// map contribution ID to contributor
|
||||
mapping(uint32 => uint32) public contributionOwner;
|
||||
// map contributor to contribution IDs
|
||||
mapping(uint32 => uint32[]) public ownedContributions;
|
||||
|
||||
mapping(uint32 => ContributionData) public contributions;
|
||||
uint32 public contributionsCount;
|
||||
|
||||
// Confirmation veto period
|
||||
uint32 public blocksToWait;
|
||||
|
||||
// The address that deployed the contract
|
||||
address public deployer;
|
||||
|
||||
// Data migration flag
|
||||
bool public migrationDone;
|
||||
|
||||
event ContributionAdded(uint32 id, uint32 indexed contributorId, uint32 amount);
|
||||
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
||||
|
||||
modifier onlyCore {
|
||||
require(contributorContract.addressIsCore(tx.origin), "Core only");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyDeployer {
|
||||
require(msg.sender == deployer, "Deployer only");
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(uint32 blocksToWait_) public initializer {
|
||||
deployer = msg.sender;
|
||||
migrationDone = false;
|
||||
blocksToWait = blocksToWait_;
|
||||
}
|
||||
|
||||
function finishMigration() public onlyDeployer {
|
||||
migrationDone = true;
|
||||
}
|
||||
|
||||
function setContributorContract(address contributor) public {
|
||||
require(address(contributorContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||
contributorContract = ContributorInterface(contributor);
|
||||
}
|
||||
|
||||
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
|
||||
return contributorContract.getContributorIdByAddress(contributorAccount);
|
||||
}
|
||||
|
||||
function getContributorAddressById(uint32 contributorId) public view returns (address) {
|
||||
return contributorContract.getContributorAddressById(contributorId);
|
||||
}
|
||||
|
||||
//
|
||||
// Token standard functions (ERC 721)
|
||||
//
|
||||
|
||||
function name() external view returns (string memory) {
|
||||
return name_;
|
||||
}
|
||||
|
||||
function symbol() external view returns (string memory) {
|
||||
return symbol_;
|
||||
}
|
||||
|
||||
// Balance is amount of ERC271 tokens, not amount of kredits
|
||||
function balanceOf(address owner) public view returns (uint256) {
|
||||
require(owner != address(0), "Address invalid");
|
||||
uint32 contributorId = getContributorIdByAddress(owner);
|
||||
return ownedContributions[contributorId].length;
|
||||
}
|
||||
|
||||
function ownerOf(uint32 contributionId) public view returns (address) {
|
||||
require(exists(contributionId), "Contribution does not exist");
|
||||
uint32 contributorId = contributions[contributionId].contributorId;
|
||||
return getContributorAddressById(contributorId);
|
||||
}
|
||||
|
||||
function tokenOfOwnerByIndex(address owner, uint32 index) public view returns (uint32) {
|
||||
uint32 contributorId = getContributorIdByAddress(owner);
|
||||
return ownedContributions[contributorId][index];
|
||||
}
|
||||
|
||||
function tokenMetadata(uint32 contributionId) public view returns (string memory) {
|
||||
return contributions[contributionId].tokenMetadataURL;
|
||||
}
|
||||
|
||||
//
|
||||
// Custom functions
|
||||
//
|
||||
|
||||
function totalKreditsEarned(bool confirmedOnly) public view returns (uint32 amount) {
|
||||
for (uint32 i = 1; i <= contributionsCount; i++) {
|
||||
ContributionData memory c = contributions[i];
|
||||
if (!c.vetoed && (block.number >= c.confirmedAtBlock || !confirmedOnly)) {
|
||||
amount += c.amount; // should use safemath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) public view returns (uint32 amount) {
|
||||
uint256 tokenCount = ownedContributions[contributorId].length;
|
||||
for (uint256 i = 0; i < tokenCount; i++) {
|
||||
uint32 cId = ownedContributions[contributorId][i];
|
||||
ContributionData memory c = contributions[cId];
|
||||
if (!c.vetoed && (block.number >= c.confirmedAtBlock || !confirmedOnly)) {
|
||||
amount += c.amount; // should use safemath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getContribution(uint32 contributionId) public view returns (uint32 id, uint32 contributorId, uint32 amount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
|
||||
id = contributionId;
|
||||
ContributionData storage c = contributions[id];
|
||||
return (
|
||||
id,
|
||||
c.contributorId,
|
||||
c.amount,
|
||||
c.hashDigest,
|
||||
c.hashFunction,
|
||||
c.hashSize,
|
||||
c.confirmedAtBlock,
|
||||
c.exists,
|
||||
c.vetoed
|
||||
);
|
||||
}
|
||||
|
||||
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool vetoed) public {
|
||||
require((confirmedAtBlock == 0 && vetoed == false) || migrationDone == false, "Extra arguments not allowed");
|
||||
require(balanceOf(msg.sender) > 0 || contributorContract.addressIsCore(msg.sender), "Requires kredits or core status");
|
||||
|
||||
uint32 contributionId = contributionsCount + 1;
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
c.exists = true;
|
||||
c.amount = amount;
|
||||
c.contributorId = contributorId;
|
||||
c.hashDigest = hashDigest;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
|
||||
if (confirmedAtBlock > 0) {
|
||||
c.confirmedAtBlock = confirmedAtBlock;
|
||||
} else {
|
||||
c.confirmedAtBlock = block.number + 1 + blocksToWait;
|
||||
}
|
||||
|
||||
if (vetoed) { c.vetoed = true; }
|
||||
|
||||
contributionsCount++;
|
||||
|
||||
contributionOwner[contributionId] = contributorId;
|
||||
ownedContributions[contributorId].push(contributionId);
|
||||
|
||||
emit ContributionAdded(contributionId, contributorId, amount);
|
||||
}
|
||||
|
||||
function veto(uint32 contributionId) public onlyCore {
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
require(c.exists, "NOT_FOUND");
|
||||
require(block.number < c.confirmedAtBlock, "VETO_PERIOD_ENDED");
|
||||
c.vetoed = true;
|
||||
|
||||
emit ContributionVetoed(contributionId, msg.sender);
|
||||
}
|
||||
|
||||
function exists(uint32 contributionId) public view returns (bool) {
|
||||
return contributions[contributionId].exists;
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
interface IToken {
|
||||
function mintFor(address contributorAccount, uint256 amount) external;
|
||||
function balanceOf(address contributorAccount) external view returns (uint256);
|
||||
}
|
||||
interface IContributionBalance {
|
||||
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) external view returns (uint32 amount);
|
||||
function balanceOf(address owner) external view returns (uint256);
|
||||
}
|
||||
|
||||
contract Contributor is Initializable {
|
||||
address public deployer;
|
||||
IContributionBalance public contributionContract;
|
||||
IToken public tokenContract;
|
||||
|
||||
struct Contributor {
|
||||
address account;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
bool exists;
|
||||
uint32 kreditsWithdrawn;
|
||||
}
|
||||
|
||||
mapping (address => uint32) public contributorIds;
|
||||
mapping (uint32 => Contributor) public contributors;
|
||||
uint32 public contributorsCount;
|
||||
|
||||
address public profileManager;
|
||||
|
||||
event ContributorProfileUpdated(uint32 id, bytes32 oldHashDigest, bytes32 newHashDigest); // what should be logged
|
||||
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
|
||||
event ContributorAdded(uint32 id, address account);
|
||||
|
||||
modifier onlyCore {
|
||||
require(addressIsCore(tx.origin), "Core only");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyContributors {
|
||||
require(addressExists(msg.sender) && contributionContract.balanceOf(msg.sender) > 0, "Contributors only");
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(address profileManagerAddress) public initializer {
|
||||
deployer = msg.sender;
|
||||
profileManager = profileManagerAddress;
|
||||
}
|
||||
|
||||
function reinitialize(address profileManagerAddress) public reinitializer(2) {
|
||||
profileManager = profileManagerAddress;
|
||||
}
|
||||
|
||||
function setContributionContract(address contribution) public onlyCore {
|
||||
require(address(contributionContract) == address(0) || addressIsCore(msg.sender), "Core only");
|
||||
contributionContract = IContributionBalance(contribution);
|
||||
}
|
||||
|
||||
function setTokenContract(address token) public onlyCore {
|
||||
require(address(tokenContract) == address(0) || addressIsCore(msg.sender), "Core only");
|
||||
tokenContract = IToken(token);
|
||||
}
|
||||
|
||||
function coreContributorsCount() public view returns (uint32) {
|
||||
uint32 count = 0;
|
||||
for (uint32 i = 1; i <= contributorsCount; i++) {
|
||||
if (isCoreTeam(i)) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public onlyCore {
|
||||
require(newAccount != address(0), "invalid new account address");
|
||||
require(getContributorAddressById(id) == oldAccount, "contributor does not exist");
|
||||
|
||||
contributorIds[oldAccount] = 0;
|
||||
contributorIds[newAccount] = id;
|
||||
contributors[id].account = newAccount;
|
||||
emit ContributorAccountUpdated(id, oldAccount, newAccount);
|
||||
}
|
||||
|
||||
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public onlyCore {
|
||||
Contributor storage c = contributors[id];
|
||||
bytes32 oldHashDigest = c.hashDigest;
|
||||
c.hashDigest = hashDigest;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
|
||||
emit ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
|
||||
}
|
||||
|
||||
function addContributor(address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
||||
require(!addressExists(account), "Address already in use");
|
||||
require((msg.sender == profileManager) || addressIsCore(msg.sender), "Only core and profile manager");
|
||||
uint32 _id = contributorsCount + 1;
|
||||
assert(!contributors[_id].exists); // this can not be acually
|
||||
Contributor storage c = contributors[_id];
|
||||
c.exists = true;
|
||||
c.hashDigest = hashDigest;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
c.account = account;
|
||||
c.kreditsWithdrawn = 0;
|
||||
contributorIds[account] = _id;
|
||||
|
||||
contributorsCount += 1;
|
||||
emit ContributorAdded(_id, account);
|
||||
}
|
||||
|
||||
function isCoreTeam(uint32 id) public view returns (bool) {
|
||||
// TODO: for simplicity we simply define the first contributors as core
|
||||
// later this needs to be changed to something more dynamic
|
||||
return id > 0 && id < 7;
|
||||
}
|
||||
|
||||
function exists(uint32 id) public view returns (bool) {
|
||||
return contributors[id].exists;
|
||||
}
|
||||
|
||||
function addressIsCore(address account) public view returns (bool) {
|
||||
// the deployer is always core
|
||||
if(account == deployer) {
|
||||
return true;
|
||||
}
|
||||
uint32 id = getContributorIdByAddress(account);
|
||||
return isCoreTeam(id);
|
||||
}
|
||||
|
||||
function addressExists(address account) public view returns (bool) {
|
||||
return getContributorByAddress(account).exists;
|
||||
}
|
||||
|
||||
function getContributorIdByAddress(address account) public view returns (uint32) {
|
||||
return contributorIds[account];
|
||||
}
|
||||
|
||||
function getContributorAddressById(uint32 id) public view returns (address) {
|
||||
return contributors[id].account;
|
||||
}
|
||||
|
||||
function getContributorByAddress(address account) internal view returns (Contributor memory) {
|
||||
uint32 id = contributorIds[account];
|
||||
return contributors[id];
|
||||
}
|
||||
|
||||
function getContributorById(uint32 _id) public view returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, uint32 totalKreditsEarned, uint256 contributionsCount, bool exists, uint256 kreditsWithdrawn) {
|
||||
id = _id;
|
||||
Contributor storage c = contributors[_id];
|
||||
account = c.account;
|
||||
hashDigest = c.hashDigest;
|
||||
hashFunction = c.hashFunction;
|
||||
hashSize = c.hashSize;
|
||||
isCore = isCoreTeam(id);
|
||||
balance = tokenContract.balanceOf(c.account);
|
||||
totalKreditsEarned = contributionContract.totalKreditsEarnedByContributor(_id, true);
|
||||
contributionsCount = contributionContract.balanceOf(c.account);
|
||||
exists = c.exists;
|
||||
kreditsWithdrawn = c.kreditsWithdrawn;
|
||||
}
|
||||
|
||||
function withdraw() public onlyContributors {
|
||||
uint32 id = getContributorIdByAddress(msg.sender);
|
||||
Contributor storage c = contributors[id];
|
||||
|
||||
// TODO check if we need a failsafe for unconfirmed or malicious txs
|
||||
uint32 confirmedKredits = contributionContract.totalKreditsEarnedByContributor(id, true);
|
||||
uint32 amountWithdrawable = confirmedKredits - c.kreditsWithdrawn;
|
||||
require (amountWithdrawable > 0, "No kredits available");
|
||||
|
||||
c.kreditsWithdrawn += amountWithdrawable;
|
||||
tokenContract.mintFor(msg.sender, amountWithdrawable);
|
||||
}
|
||||
}
|
128
contracts/Contributors.sol
Normal file
128
contracts/Contributors.sol
Normal file
@ -0,0 +1,128 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
// import basic ERC20 details to be able to call balanceOf
|
||||
import 'zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol';
|
||||
import './upgradeable/Upgradeable.sol';
|
||||
|
||||
contract Contributors is Upgradeable {
|
||||
|
||||
struct Contributor {
|
||||
address account;
|
||||
bytes32 ipfsHash;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
bool isCore;
|
||||
bool exists;
|
||||
}
|
||||
|
||||
mapping (address => uint) public contributorIds;
|
||||
mapping (uint => Contributor) public contributors;
|
||||
uint256 public contributorsCount;
|
||||
|
||||
event ContributorProfileUpdated(uint id, bytes32 oldIpfsHash, bytes32 newIpfsHash);
|
||||
event ContributorAccountUpdated(uint id, address oldAccount, address newAccount);
|
||||
event ContributorAdded(uint id, address account);
|
||||
|
||||
modifier onlyCoreOrOperator() {
|
||||
require(msg.sender == registry.getProxyFor('Operator') || addressIsCore(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(address sender) public payable {
|
||||
require(msg.sender == address(registry));
|
||||
uint _id = 1;
|
||||
Contributor storage c = contributors[_id];
|
||||
c.exists = true;
|
||||
c.isCore = true;
|
||||
c.account = sender;
|
||||
contributorIds[sender] = _id;
|
||||
contributorsCount += 1;
|
||||
}
|
||||
|
||||
function coreContributorsCount() view public returns (uint) {
|
||||
uint count = 0;
|
||||
for (uint256 i = 1; i <= contributorsCount; i++) {
|
||||
if (contributors[i].isCore) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
function updateContributorAccount(uint id, address oldAccount, address newAccount) public onlyCoreOrOperator {
|
||||
contributorIds[oldAccount] = 0;
|
||||
contributorIds[newAccount] = id;
|
||||
contributors[id].account = newAccount;
|
||||
ContributorAccountUpdated(id, oldAccount, newAccount);
|
||||
}
|
||||
|
||||
function updateContributorIpfsHash(uint id, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public onlyCoreOrOperator {
|
||||
Contributor storage c = contributors[id];
|
||||
bytes32 oldIpfsHash = c.ipfsHash;
|
||||
c.ipfsHash = ipfsHash;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
|
||||
ContributorProfileUpdated(id, oldIpfsHash, c.ipfsHash);
|
||||
}
|
||||
|
||||
function addContributor(address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore) public onlyCoreOrOperator {
|
||||
require(!addressExists(account));
|
||||
uint _id = contributorsCount + 1;
|
||||
assert(!contributors[_id].exists); // this can not be acually
|
||||
Contributor storage c = contributors[_id];
|
||||
c.exists = true;
|
||||
c.isCore = isCore;
|
||||
c.ipfsHash = ipfsHash;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
c.account = account;
|
||||
contributorIds[account] = _id;
|
||||
|
||||
contributorsCount += 1;
|
||||
ContributorAdded(_id, account);
|
||||
}
|
||||
|
||||
function isCore(uint id) view public returns (bool) {
|
||||
return contributors[id].isCore;
|
||||
}
|
||||
|
||||
function exists(uint id) view public returns (bool) {
|
||||
return contributors[id].exists;
|
||||
}
|
||||
|
||||
function addressIsCore(address account) view public returns (bool) {
|
||||
return getContributorByAddress(account).isCore;
|
||||
}
|
||||
|
||||
function addressExists(address account) view public returns (bool) {
|
||||
return getContributorByAddress(account).exists;
|
||||
}
|
||||
|
||||
function getContributorIdByAddress(address account) view public returns (uint) {
|
||||
return contributorIds[account];
|
||||
}
|
||||
|
||||
function getContributorAddressById(uint id) view public returns (address) {
|
||||
return contributors[id].account;
|
||||
}
|
||||
|
||||
function getContributorByAddress(address account) internal view returns (Contributor) {
|
||||
uint id = contributorIds[account];
|
||||
return contributors[id];
|
||||
}
|
||||
|
||||
function getContributorById(uint _id) public view returns (uint id, address account, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, bool isCore, uint balance, bool exists ) {
|
||||
id = _id;
|
||||
Contributor storage c = contributors[_id];
|
||||
account = c.account;
|
||||
ipfsHash = c.ipfsHash;
|
||||
hashFunction = c.hashFunction;
|
||||
hashSize = c.hashSize;
|
||||
isCore = c.isCore;
|
||||
exists = c.exists;
|
||||
|
||||
ERC20Basic token = ERC20Basic(registry.getProxyFor('Token'));
|
||||
balance = token.balanceOf(account);
|
||||
}
|
||||
}
|
23
contracts/Migrations.sol
Normal file
23
contracts/Migrations.sol
Normal file
@ -0,0 +1,23 @@
|
||||
pragma solidity ^0.4.17;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
uint public last_completed_migration;
|
||||
|
||||
modifier restricted() {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) public restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) public restricted {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
}
|
123
contracts/Operator.sol
Normal file
123
contracts/Operator.sol
Normal file
@ -0,0 +1,123 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
// ToDo: only load interfaces
|
||||
import './Token.sol';
|
||||
import './Contributors.sol';
|
||||
|
||||
contract Operator is Upgradeable {
|
||||
|
||||
struct Proposal {
|
||||
address creatorAccount;
|
||||
uint contributorId;
|
||||
uint votesCount;
|
||||
uint votesNeeded;
|
||||
uint256 amount;
|
||||
bool executed;
|
||||
bytes32 ipfsHash;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
uint256[] voterIds;
|
||||
mapping (uint256 => bool) votes;
|
||||
bool exists;
|
||||
}
|
||||
|
||||
mapping(uint256 => Proposal) public proposals;
|
||||
uint256 public proposalsCount;
|
||||
|
||||
event ProposalCreated(uint256 id, address creatorAccount, uint256 contributorId, uint256 amount);
|
||||
event ProposalVoted(uint256 id, uint256 voterId, uint256 totalVotes);
|
||||
event ProposalExecuted(uint256 id, uint256 contributorId, uint256 amount);
|
||||
|
||||
modifier coreOnly() {
|
||||
require(contributorsContract().addressIsCore(msg.sender));
|
||||
_;
|
||||
}
|
||||
modifier contributorOnly() {
|
||||
require(contributorsContract().addressExists(msg.sender));
|
||||
_;
|
||||
}
|
||||
modifier noEther() {
|
||||
require(msg.value == 0);
|
||||
_;
|
||||
}
|
||||
|
||||
function contributorsContract() view public returns (Contributors) {
|
||||
return Contributors(registry.getProxyFor('Contributors'));
|
||||
}
|
||||
function tokenContract() view public returns (Token) {
|
||||
return Token(registry.getProxyFor('Token'));
|
||||
}
|
||||
|
||||
function contributorsCount() view public returns (uint) {
|
||||
return contributorsContract().contributorsCount();
|
||||
}
|
||||
function coreContributorsCount() view public returns (uint) {
|
||||
return contributorsContract().coreContributorsCount();
|
||||
}
|
||||
|
||||
function addProposal(uint contributorId, uint256 amount, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize) public {
|
||||
require(contributorsContract().exists(contributorId));
|
||||
|
||||
uint256 proposalId = proposalsCount + 1;
|
||||
uint256 _votesNeeded = contributorsContract().coreContributorsCount() / 100 * 75;
|
||||
|
||||
var p = proposals[proposalId];
|
||||
p.creatorAccount = msg.sender;
|
||||
p.contributorId = contributorId;
|
||||
p.amount = amount;
|
||||
p.ipfsHash = ipfsHash;
|
||||
p.hashFunction = hashFunction;
|
||||
p.hashSize = hashSize;
|
||||
p.votesCount = 0;
|
||||
p.votesNeeded = _votesNeeded;
|
||||
p.exists = true;
|
||||
|
||||
proposalsCount++;
|
||||
ProposalCreated(proposalId, msg.sender, p.contributorId, p.amount);
|
||||
}
|
||||
|
||||
function getProposal(uint proposalId) public view returns (uint256 id, address creatorAccount, uint256 contributorId, uint256 votesCount, uint256 votesNeeded, uint256 amount, bool executed, bytes32 ipfsHash, uint8 hashFunction, uint8 hashSize, uint256[] voterIds, bool exists) {
|
||||
id = proposalId;
|
||||
Proposal storage p = proposals[id];
|
||||
return (
|
||||
id,
|
||||
p.creatorAccount,
|
||||
p.contributorId,
|
||||
p.votesCount,
|
||||
p.votesNeeded,
|
||||
p.amount,
|
||||
p.executed,
|
||||
p.ipfsHash,
|
||||
p.hashFunction,
|
||||
p.hashSize,
|
||||
p.voterIds,
|
||||
p.exists
|
||||
);
|
||||
}
|
||||
|
||||
function vote(uint256 proposalId) public coreOnly {
|
||||
var p = proposals[proposalId];
|
||||
require(!p.executed);
|
||||
uint256 voterId = contributorsContract().getContributorIdByAddress(msg.sender);
|
||||
require(p.votes[voterId] != true);
|
||||
p.voterIds.push(voterId);
|
||||
p.votes[voterId] = true;
|
||||
|
||||
p.votesCount++;
|
||||
if (p.votesCount >= p.votesNeeded) {
|
||||
executeProposal(proposalId);
|
||||
}
|
||||
ProposalVoted(proposalId, voterId, p.votesCount);
|
||||
}
|
||||
|
||||
function executeProposal(uint proposalId) private {
|
||||
var p = proposals[proposalId];
|
||||
require(!p.executed);
|
||||
require(p.votesCount >= p.votesNeeded);
|
||||
address recipientAddress = contributorsContract().getContributorAddressById(p.contributorId);
|
||||
tokenContract().mintFor(recipientAddress, p.amount, proposalId);
|
||||
p.executed = true;
|
||||
ProposalExecuted(proposalId, p.contributorId, p.amount);
|
||||
}
|
||||
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
interface ContributorInterface {
|
||||
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||
function addressIsCore(address sender) external view returns (bool);
|
||||
// TODO Maybe use for validation
|
||||
// function exists(uint32 contributorId) public view returns (bool);
|
||||
}
|
||||
|
||||
contract Reimbursement is Initializable {
|
||||
ContributorInterface public contributorContract;
|
||||
|
||||
struct ReimbursementData {
|
||||
uint32 recipientId;
|
||||
uint256 amount;
|
||||
// TODO remove token entirely
|
||||
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;
|
||||
|
||||
// The address that deployed the contract
|
||||
address public deployer;
|
||||
|
||||
// Data migration flag
|
||||
bool public migrationDone;
|
||||
|
||||
event ReimbursementAdded(uint32 id, address indexed addedByAccount, uint256 amount);
|
||||
event ReimbursementVetoed(uint32 id, address vetoedByAccount);
|
||||
|
||||
modifier onlyCore {
|
||||
require(contributorContract.addressIsCore(tx.origin), "Core only");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyDeployer {
|
||||
require(msg.sender == deployer, "Deployer only");
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize() public initializer {
|
||||
deployer = msg.sender;
|
||||
migrationDone = false;
|
||||
blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||
}
|
||||
|
||||
function finishMigration() public onlyDeployer {
|
||||
migrationDone = true;
|
||||
}
|
||||
|
||||
function setContributorContract(address contributor) public {
|
||||
require(address(contributorContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||
contributorContract = ContributorInterface(contributor);
|
||||
}
|
||||
|
||||
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
|
||||
return contributorContract.getContributorIdByAddress(contributorAccount);
|
||||
}
|
||||
|
||||
function getContributorAddressById(uint32 contributorId) public view returns (address) {
|
||||
return contributorContract.getContributorAddressById(contributorId);
|
||||
}
|
||||
|
||||
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, uint256 confirmedAtBlock, bool vetoed) public onlyCore {
|
||||
require((confirmedAtBlock == 0 && vetoed == false) || migrationDone == false, "Extra arguments not allowed");
|
||||
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;
|
||||
|
||||
if (confirmedAtBlock > 0) {
|
||||
r.confirmedAtBlock = confirmedAtBlock;
|
||||
} else {
|
||||
r.confirmedAtBlock = block.number + 1 + blocksToWait;
|
||||
}
|
||||
|
||||
if (vetoed) { r.vetoed = true; }
|
||||
|
||||
reimbursementsCount++;
|
||||
|
||||
emit ReimbursementAdded(reimbursementId, msg.sender, amount);
|
||||
}
|
||||
|
||||
function veto(uint32 reimbursementId) public onlyCore {
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,41 +1,27 @@
|
||||
pragma solidity ^0.8.0;
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
|
||||
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
|
||||
import 'zeppelin-solidity/contracts/token/ERC20/BasicToken.sol';
|
||||
import './upgradeable/Upgradeable.sol';
|
||||
|
||||
contract Token is Upgradeable, BasicToken {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint8 public decimals;
|
||||
|
||||
event LogMint(address indexed recipient, uint256 amount, uint256 proposalId);
|
||||
|
||||
function initialize(address sender) public payable {
|
||||
require(msg.sender == address(registry));
|
||||
name = 'Kredits';
|
||||
symbol = 'K';
|
||||
decimals = 18;
|
||||
}
|
||||
|
||||
function mintFor(address contributorAccount, uint256 amount, uint proposalId) onlyRegistryContractFor('Operator') public {
|
||||
totalSupply_ = totalSupply_.add(amount);
|
||||
balances[contributorAccount] = balances[contributorAccount].add(amount);
|
||||
|
||||
LogMint(contributorAccount, amount, proposalId);
|
||||
}
|
||||
|
||||
interface ContributorInterface {
|
||||
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||
function addressIsCore(address sender) external view returns (bool);
|
||||
}
|
||||
|
||||
contract Token is Initializable, ERC20Upgradeable {
|
||||
ContributorInterface public contributorContract;
|
||||
using SafeMathUpgradeable for uint256;
|
||||
|
||||
address public contributorContractAddress;
|
||||
|
||||
event KreditsMinted(address indexed recipient, uint256 amount);
|
||||
|
||||
function initialize() public virtual initializer {
|
||||
__ERC20_init("Kredits", "KS");
|
||||
}
|
||||
|
||||
function decimals() public view virtual override returns (uint8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function setContributorContract(address contributor) public {
|
||||
require(address(contributorContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||
contributorContract = ContributorInterface(contributor);
|
||||
contributorContractAddress = contributor;
|
||||
}
|
||||
|
||||
function mintFor(address contributorAccount, uint256 amount) public {
|
||||
require(contributorContractAddress == msg.sender, "Only Contributor");
|
||||
require(amount > 0, "INVALID_AMOUNT");
|
||||
|
||||
_mint(contributorAccount, amount);
|
||||
emit KreditsMinted(contributorAccount, amount);
|
||||
}
|
||||
}
|
||||
|
53
contracts/upgradeable/IRegistry.sol
Normal file
53
contracts/upgradeable/IRegistry.sol
Normal file
@ -0,0 +1,53 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
/**
|
||||
* @title IRegistry
|
||||
* @dev This contract represents the interface of a registry contract
|
||||
*/
|
||||
interface IRegistry {
|
||||
/**
|
||||
* @dev This event will be emitted every time a new proxy is created
|
||||
* @param name of the contract, as specified in the registry
|
||||
* @param proxy representing the address of the proxy created
|
||||
*/
|
||||
event ProxyCreated(string name, address proxy);
|
||||
|
||||
/**
|
||||
* @dev This event will be emitted every time a new implementation is registered
|
||||
* @param name of the contract, as specified in the registry
|
||||
* @param version representing the version name of the registered implementation
|
||||
* @param implementation representing the address of the registered implementation
|
||||
*/
|
||||
event VersionAdded(string name, uint version, address implementation);
|
||||
|
||||
/**
|
||||
* @dev This event will be emitted every time a proxy is upgraded to a new version
|
||||
* @param name of the contract, as specified in the registry
|
||||
* @param version representing the version name of the registered implementation
|
||||
*/
|
||||
event ProxyImplementationUpgraded(string name, uint version);
|
||||
|
||||
/**
|
||||
* @dev Registers a new version with its implementation address
|
||||
* @param name of the contract, as specified in the registry
|
||||
* @param implementation representing the address of the new implementation to be registered
|
||||
*/
|
||||
function addVersion(string name, address implementation) public;
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the implementation for a given version
|
||||
* @param name of the contract, as specified in the registry
|
||||
* @param version to query the implementation of
|
||||
* @return address of the implementation registered for the given version
|
||||
*/
|
||||
function getVersion(string name, uint version) public view returns (address);
|
||||
|
||||
/**
|
||||
* @dev Tells the latest address of the implementation
|
||||
* @param name of the contract, as specified in the registry
|
||||
* @return address of the implementation registered for the latest version
|
||||
*/
|
||||
function getLatestVersion(string name) public view returns (address);
|
||||
|
||||
function getProxyFor(string name) public view returns (address);
|
||||
}
|
23
contracts/upgradeable/Migrations.sol
Normal file
23
contracts/upgradeable/Migrations.sol
Normal file
@ -0,0 +1,23 @@
|
||||
pragma solidity ^0.4.17;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
uint public last_completed_migration;
|
||||
|
||||
modifier restricted() {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) public restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) public restricted {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
}
|
36
contracts/upgradeable/Proxy.sol
Normal file
36
contracts/upgradeable/Proxy.sol
Normal file
@ -0,0 +1,36 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
/**
|
||||
* @title Proxy
|
||||
* @dev Gives the possibility to delegate any call to a foreign implementation.
|
||||
*/
|
||||
contract Proxy {
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the implementation where every call will be delegated.
|
||||
* @return address of the implementation to which it will be delegated
|
||||
*/
|
||||
function implementation() public view returns (address);
|
||||
|
||||
/**
|
||||
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
|
||||
* This function will return whatever the implementation call returns
|
||||
*/
|
||||
function () payable public {
|
||||
address _impl = implementation();
|
||||
require(_impl != address(0));
|
||||
bytes memory data = msg.data;
|
||||
|
||||
assembly {
|
||||
let result := delegatecall(gas, _impl, add(data, 0x20), mload(data), 0, 0)
|
||||
let size := returndatasize
|
||||
|
||||
let ptr := mload(0x40)
|
||||
returndatacopy(ptr, 0, size)
|
||||
|
||||
switch result
|
||||
case 0 { revert(ptr, size) }
|
||||
default { return(ptr, size) }
|
||||
}
|
||||
}
|
||||
}
|
86
contracts/upgradeable/Registry.sol
Normal file
86
contracts/upgradeable/Registry.sol
Normal file
@ -0,0 +1,86 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import './IRegistry.sol';
|
||||
import './Upgradeable.sol';
|
||||
import './UpgradeabilityProxy.sol';
|
||||
|
||||
/**
|
||||
* @title Registry
|
||||
* @dev This contract works as a registry of versions, it holds the implementations for the registered versions.
|
||||
*/
|
||||
contract Registry is IRegistry {
|
||||
// mapping of contract names to versions to implementation
|
||||
// "Token" => "1.0.0" => "0x123"
|
||||
mapping(bytes32 => mapping(uint => address)) public versions;
|
||||
|
||||
// current version for a certain contract
|
||||
mapping(bytes32 => uint) public currentVersions;
|
||||
|
||||
// mapping of the contract names to the proxy addresses
|
||||
mapping(bytes32 => address) public proxies;
|
||||
|
||||
/**
|
||||
* @dev Registers a new version with its implementation address
|
||||
* @param name of the contract
|
||||
* @param implementation representing the address of the new implementation to be registered
|
||||
*/
|
||||
function addVersion(string name, address implementation) public {
|
||||
bytes32 key = keccak256(name);
|
||||
currentVersions[key] = currentVersions[key] + 1;
|
||||
uint version = currentVersions[key];
|
||||
require(versions[key][version] == 0x0);
|
||||
versions[key][version] = implementation;
|
||||
VersionAdded(name, version, implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the implementation for a given version
|
||||
* @param name of the contract
|
||||
* @param version to query the implementation of
|
||||
* @return address of the implementation registered for the given version
|
||||
*/
|
||||
function getVersion(string name, uint version) public view returns (address) {
|
||||
bytes32 key = keccak256(name);
|
||||
return versions[key][version];
|
||||
}
|
||||
|
||||
function getLatestVersion(string name) public view returns (address) {
|
||||
bytes32 key = keccak256(name);
|
||||
uint current = currentVersions[key];
|
||||
return getVersion(name, current);
|
||||
}
|
||||
|
||||
function getProxyFor(string name) public view returns (address) {
|
||||
bytes32 key = keccak256(name);
|
||||
return proxies[key];
|
||||
}
|
||||
|
||||
function upgrade(string name, uint version) public {
|
||||
bytes32 key = keccak256(name);
|
||||
UpgradeabilityProxy(proxies[key]).upgradeTo(version);
|
||||
ProxyImplementationUpgraded(name, version);
|
||||
}
|
||||
|
||||
function upgradeToLatest(string name) public {
|
||||
bytes32 key = keccak256(name);
|
||||
uint current = currentVersions[key];
|
||||
upgrade(name, current);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates an upgradeable proxy
|
||||
* @param name of the contract
|
||||
* @param version representing the first version to be set for the proxy
|
||||
* @return address of the new proxy created
|
||||
*/
|
||||
function createProxy(string name, uint version) public payable returns (UpgradeabilityProxy) {
|
||||
bytes32 key = keccak256(name);
|
||||
require(proxies[key] == 0x0);
|
||||
UpgradeabilityProxy proxy = new UpgradeabilityProxy(name, version);
|
||||
proxies[key] = address(proxy);
|
||||
Upgradeable(proxy).initialize.value(msg.value)(msg.sender);
|
||||
ProxyCreated(name, proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
}
|
28
contracts/upgradeable/UpgradeabilityProxy.sol
Normal file
28
contracts/upgradeable/UpgradeabilityProxy.sol
Normal file
@ -0,0 +1,28 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import './Proxy.sol';
|
||||
import './IRegistry.sol';
|
||||
import './UpgradeabilityStorage.sol';
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityProxy
|
||||
* @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
|
||||
*/
|
||||
contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
|
||||
|
||||
function UpgradeabilityProxy(string _name, uint _version) public {
|
||||
_proxiedContractName = _name;
|
||||
registry = IRegistry(msg.sender);
|
||||
upgradeTo(_version);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrades the implementation to the requested version
|
||||
* @param _version representing the version name of the new implementation to be set
|
||||
*/
|
||||
function upgradeTo(uint _version) public {
|
||||
require(msg.sender == address(registry));
|
||||
_implementation = registry.getVersion(_proxiedContractName, _version);
|
||||
}
|
||||
|
||||
}
|
37
contracts/upgradeable/UpgradeabilityStorage.sol
Normal file
37
contracts/upgradeable/UpgradeabilityStorage.sol
Normal file
@ -0,0 +1,37 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import './IRegistry.sol';
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityStorage
|
||||
* @dev This contract holds all the necessary state variables to support the upgrade functionality
|
||||
*/
|
||||
contract UpgradeabilityStorage {
|
||||
// Versions registry
|
||||
IRegistry internal registry;
|
||||
|
||||
// Address of the current implementation
|
||||
address internal _implementation;
|
||||
|
||||
// contract name
|
||||
string public _proxiedContractName;
|
||||
|
||||
|
||||
modifier requireRegistry() {
|
||||
require(address(registry) != 0x0);
|
||||
_;
|
||||
}
|
||||
modifier onlyRegistryContractFor(string name) {
|
||||
require(address(registry) != 0x0);
|
||||
require(msg.sender == registry.getProxyFor(name));
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the current implementation
|
||||
* @return address of the current implementation
|
||||
*/
|
||||
function implementation() public view returns (address) {
|
||||
return _implementation;
|
||||
}
|
||||
}
|
19
contracts/upgradeable/Upgradeable.sol
Normal file
19
contracts/upgradeable/Upgradeable.sol
Normal file
@ -0,0 +1,19 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import './UpgradeabilityStorage.sol';
|
||||
|
||||
/**
|
||||
* @title Upgradeable
|
||||
* @dev This contract holds all the minimum required functionality for a behavior to be upgradeable.
|
||||
* This means, required state variables for owned upgradeability purpose and simple initialization validation.
|
||||
*/
|
||||
contract Upgradeable is UpgradeabilityStorage {
|
||||
/**
|
||||
* @dev Validates the caller is the versions registry.
|
||||
* THIS FUNCTION SHOULD BE OVERRIDDEN CALLING SUPER
|
||||
* @param sender representing the address deploying the initial behavior of the contract
|
||||
*/
|
||||
function initialize(address sender) public payable {
|
||||
require(msg.sender == address(registry));
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
# Contribution deployments
|
||||
|
||||
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
|
||||
|
||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v6.0.0:
|
||||
ℹ Contract address: 0x2c083EEA83fd3a99C93759D97D0317A43261c758
|
||||
ℹ Content (ipfs): QmULpSqz7BgTFmDu8AL7YZZEz525xkcEzf3dPKtbRdUtFs
|
||||
ℹ Transaction hash: 0x8b01c4c00162e918659d267a2beaf33b578e2aaf9f427f1aa9a43029333c5cd7
|
||||
|
||||
## 2019-04-10 - Weltempfänger release
|
||||
|
||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v5.0.0:
|
||||
ℹ Contract address: 0xe0f7dB486321b917e3A986Bdb2F2b9d51BA98fa9
|
||||
ℹ Content (ipfs): QmU3XEBb4f5jU8MFFEpwaa95C1mhc82UeYLRWLrKsvcQNw
|
||||
ℹ Transaction hash: 0xd736ff5f79f8142be3fad1a50580fb40aa468838da397f8630285fd91a445af3
|
||||
|
||||
|
||||
## 2019-04-04
|
||||
|
||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v4.0.0:
|
||||
ℹ Contract address: 0x7485e8fbde0112C53587079db450Eb002D359372
|
||||
ℹ Content (ipfs): QmZKxYPm8wz4phgL4428Gh7MjmbyFFDMP2st7qhNL9qGDQ
|
||||
ℹ Transaction hash: 0x7d9be7920db675be88e8f60ebf08dc62ee77c4e6e454c5fbf0f91f6ac97e4c26
|
||||
|
||||
|
||||
## 2019-03-26
|
||||
|
||||
### v3.0.0 appids
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v3.0.0:
|
||||
ℹ Contract address: 0x9b4954834f070380faf9B6CB3794C7eA92d3B506
|
||||
ℹ Content (ipfs): Qma3yvT5AmBbJHL8WkpXHs7aCFqpGd9ZaMpbiz3cT6Un59
|
||||
ℹ Transaction hash: 0xc2b2d19e1b6d68ba50ed051a35c22eac74c69bd50665aed65488f9209171d382
|
||||
|
||||
## 2019-03-25
|
||||
|
||||
### v2.0.0 updated appid hashes
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v2.0.0:
|
||||
ℹ Contract address: 0x2765F13d82B83C0C9d770715e1fB376ab01C0361
|
||||
ℹ Content (ipfs): QmYiv1cMh6cj8pcbmaTUAWxf93k4UhN8mPJWeqEo7BEkMx
|
||||
ℹ Transaction hash: 0xe4841a6552527c8fbeb6aa44769f95ce60d99413958c6289f67e8ec83823ee96
|
||||
|
||||
|
||||
### v1.0.0
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0x1F460107361047064d982f61002D1BdEb02Ce705
|
||||
ℹ Content (ipfs): QmQ6rTWCGcseCmGb6thYG2kwijHk6W84qaFPeftZ4bUY2k
|
||||
ℹ Transaction hash: 0xeee90c5d18a8cb8ac845f52a4202cd62b27c23b4251b69c3681a854786b6e336
|
||||
|
@ -1,51 +0,0 @@
|
||||
# Contributor deployments
|
||||
|
||||
aragon apm publish major --environment=rinkeby
|
||||
|
||||
## 2019-04-25 canPerform fix
|
||||
|
||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v6.0.0:
|
||||
ℹ Contract address: 0xA5379D49C718845A1BD7720c6BE3872bA69906cc
|
||||
ℹ Content (ipfs): QmdennNV6s2FNpe6QNYxrUsUXPVdnQGvh1vCi22Tqs8ojq
|
||||
ℹ Transaction hash: 0x51077afeff70a24e87c78bb23ea13bdb9b4445bd43ea7a74a4178fadfeeb6c35
|
||||
|
||||
## 2019-04-24 update balances
|
||||
|
||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v5.0.0:
|
||||
ℹ Contract address: 0xadefa3b66b68a127Fe38bEa1813b844EE69CFD86
|
||||
ℹ Content (ipfs): QmeygbQgoj2McLWzo9hJayLWuBZqFaK4HTpa5qLeQdkn5K
|
||||
ℹ Transaction hash: 0x4237a9636f6e4a8190e0d5bcfa85a452da097bf654a173a88e0e1de3d078f08d
|
||||
|
||||
|
||||
## 2019-04-10 - Weltempfänger release
|
||||
|
||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v4.0.0:
|
||||
ℹ Contract address: 0x08a6D4D915FCAA5524F05F5F715a6C17cB6eeA6B
|
||||
ℹ Content (ipfs): QmR62PWwe1EzommfkhJDYcTvHoZjbXuv9dTG6vCn5dWCsb
|
||||
ℹ Transaction hash: 0xd5317c9e207a413485c55ec3046b09d467d978443680304737a6d7d3db0c90e1
|
||||
|
||||
|
||||
## 2019-04-04
|
||||
|
||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v3.0.0:
|
||||
ℹ Contract address: 0x95D8458E28C8de7216279512601A3B9Dc512D70B
|
||||
ℹ Content (ipfs): QmSpHnmsf8FybvqfD49kwxvDixwiBUR7D5yG4BWSnnwCPS
|
||||
ℹ Transaction hash: 0x736f9751b07a91178f453c279ecb57604b3b5686ae5d7115880f3b27fbeb50f2
|
||||
|
||||
## 2019-03-26
|
||||
|
||||
### v2.0.0 support for appids
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v2.0.0:
|
||||
ℹ Contract address: 0xf8e7B45b3c5A98dbE3D69C6828052dfD9fe2dc69
|
||||
ℹ Content (ipfs): QmTDduMJVUVcqz5SgVEns1xwY9LqYrMoAyYcx3pMrPxn6i
|
||||
ℹ Transaction hash: 0x48b38f32f5dcb52a0a8603743b66a7ca490fec04ccb1888dcfd37106bbd3b886
|
||||
|
||||
|
||||
## 2019-03-25
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0x6D80EFEE6F9A40AA86Ef7c4C95c8b2e453d260fb
|
||||
ℹ Content (ipfs): QmbGSQPwi3AXHjDFG2fkMpJrBJLtyuaA6DVPMkFTfMpksn
|
||||
ℹ Transaction hash: 0x26376c59dfdb617c35b740a0f110bf3040cdad0103593cdc788267a84d9847b9
|
||||
|
@ -1,68 +0,0 @@
|
||||
# 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
|
||||
|
||||
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
|
||||
✔ Fetching kredits-contributor.open.aragonpm.eth@latest
|
||||
✔ Upgrading app
|
||||
✔ Successfully executed: "Set the resolving address of 'kredits-contributor.open.aragonpm.eth' in namespace 'App code' to 0xA5379D49C718845A1BD7720c6BE3872bA69906cc"
|
||||
|
||||
## 2019-04-24 upgrade contributor and contribution
|
||||
|
||||
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
|
||||
eth-provider | Invalid provider preset/location: "local"
|
||||
✔ Fetching kredits-contributor.open.aragonpm.eth@latest
|
||||
✔ Upgrading app
|
||||
✔ Successfully executed: "Set the resolving address of 'kredits-contributor.open.aragonpm.eth' in namespace 'App code' to 0xadefa3b66b68a127Fe38bEa1813b844EE69CFD86"
|
||||
|
||||
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contribution.open.aragonpm.eth --environment=rinkeby
|
||||
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
|
||||
✔ Upgrading app
|
||||
✔ Successfully executed: "Set the resolving address of 'kredits-contribution.open.aragonpm.eth' in namespace 'App code' to 0x2c083EEA83fd3a99C93759D97D0317A43261c758"
|
||||
|
||||
## 2019-04-10 - Weltempfänger release
|
||||
|
||||
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
|
||||
Created new DAO at: 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14
|
||||
|
||||
## 2019-04-04
|
||||
|
||||
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
|
||||
Created new DAO at: 0xcd75458fbc4aa2231252d5b21f1391fd031e5cb2
|
||||
|
||||
### 2019-03-26
|
||||
|
||||
kredits/truffle-kredits@aragonos » truffle exec scripts/new-dao.js --network=rinkeby
|
||||
Using network 'rinkeby'.
|
||||
|
||||
Deploying to networkId: 4
|
||||
Using KreditsKit at: 0x1d6a9c2146a330575ee860eef9a012b5ff7caa68
|
||||
|
||||
Created new DAO at: 0x95a7ce185efc2d1f13efd2a00ee9247c51ea7009"
|
||||
|
||||
|
||||
### 2019-03-25
|
||||
|
||||
kredits/truffle-kredits@aragonos » aragon contracts exec scripts/new-dao.js --network=rinkeby
|
||||
ℹ Use of `--network` is deprecated and has been replaced with `--environment`. You may need to update your arapp.json
|
||||
ℹ Passing the command to Truffle
|
||||
Using network 'rinkeby'.
|
||||
|
||||
Deploying to networkId: 4
|
||||
Using KreditsKit at: 0xf4f3963718e5c2b426dd5c3ef0ab4b31ffb7a318
|
||||
|
||||
Created new DAO at: 0x8b7c0bec9476ce08d9769a87d272b03b350712e2
|
||||
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
https://rinkeby.etherscan.io/tx/0x4deb02b3740b3baa7735097d57c1456a5cb329ee741d123478fdb5114e2c305b
|
@ -1,62 +0,0 @@
|
||||
# KreditsKit deployments
|
||||
|
||||
## 2019-04-04
|
||||
|
||||
Deploying to networkId: 4
|
||||
Using ENS at: 0x98Df287B6C145399Aaa709692c8D308357bC085D
|
||||
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
|
||||
Found apps: [contribution,contributor,proposal,token].open.aragonpm.eth
|
||||
Deployed KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
|
||||
|
||||
## 2019-03-26
|
||||
|
||||
Using network 'rinkeby'.
|
||||
|
||||
Deploying to networkId: 4
|
||||
Using ENS at: 0x98Df287B6C145399Aaa709692c8D308357bC085D
|
||||
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
|
||||
Found apps: [contribution,contributor,proposal,token].open.aragonpm.eth
|
||||
Deployed KreditsKit at: 0x1d6a9c2146a330575ee860eef9a012b5ff7caa68
|
||||
|
||||
|
||||
|
||||
### fails
|
||||
a few deployments to fix the deploy script
|
||||
|
||||
## 2019-03-25
|
||||
|
||||
### fixed kit with correct appids
|
||||
|
||||
kredits/truffle-kredits@aragonos » aragon contracts exec scripts/deploy-kit.js --debug --network=rinkeby
|
||||
ℹ Use of `--network` is deprecated and has been replaced with `--environment`. You may need to update your arapp.json
|
||||
ℹ Passing the command to Truffle
|
||||
Using network 'rinkeby'.
|
||||
|
||||
Deploying to networkId: 4
|
||||
Using ENS at: 0x98Df287B6C145399Aaa709692c8D308357bC085D
|
||||
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
|
||||
Found apps: [contribution,contributor,proposal,token].open.aragonpm.eth
|
||||
Deployed KreditsKit at: 0xf4f3963718e5c2b426dd5c3ef0ab4b31ffb7a318
|
||||
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
|
||||
### test with fixed deploy script
|
||||
kredits/truffle-kredits@aragonos » ENS=0x98df287b6c145399aaa709692c8d308357bc085d DAO_FACTORY=0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d truffle exec scripts/deploy-kit.js --network=rinkeby
|
||||
Using network 'rinkeby'.
|
||||
|
||||
Deploying to networkId: 4
|
||||
Using ENS at: 0x98df287b6c145399aaa709692c8d308357bc085d
|
||||
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
|
||||
Deployed KreditsKit at: 0x83afd3c99563fc467aec69e0187ffd53fc8faa76
|
||||
|
||||
### success
|
||||
kredits/truffle-kredits@aragonos » ENS=0x98df287b6c145399aaa709692c8d308357bc085d DAO_FACTORY=0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d truffle exec scripts/deploy-kit.js --network=rinkeby
|
||||
Using network 'rinkeby'.
|
||||
|
||||
Using ENS at: 0x98df287b6c145399aaa709692c8d308357bc085d
|
||||
Using DAOFactory at: 0x2298d27a9b847c681d2b2c2828ab9d79013f5f1d
|
||||
Deployed KreditsKit at: 0x1fd2f9206addaf86f3ef921a3b7c84400374ba68
|
||||
|
||||
### deployment script error:
|
||||
deployment script failure at: https://rinkeby.etherscan.io/tx/0x3571b889b6b9b2b3f26dd0ee7fb82c7ece90b28d910078f2e06753d878832af4"
|
||||
|
@ -1,43 +0,0 @@
|
||||
# Proposal deployments
|
||||
|
||||
## 2019-04-10 - Weltempfänger release
|
||||
|
||||
✔ Successfully published kredits-proposal.open.aragonpm.eth v5.0.0:
|
||||
ℹ Contract address: 0x4ce5b0286483c66b861e5599a199054687434552
|
||||
ℹ Content (ipfs): QmNYXEcmvKTGxYiob7WUf85oZhdmFDCuGiA6TsRrDE9TYb
|
||||
ℹ Transaction hash: 0x0482b58a1ba87d494c6391026399d0ac41b45384330d916f3f99ba70e501584b
|
||||
|
||||
|
||||
## 2019-04-04
|
||||
|
||||
✔ Successfully published kredits-proposal.open.aragonpm.eth v4.0.0:
|
||||
ℹ Contract address: 0x4993275362Ba50D76f349A262B7b842e7FbD7490
|
||||
ℹ Content (ipfs): QmesCPKLapASPTB3rnPpSdD7ULkg8BQwRcpdE1B8WwfSh7
|
||||
ℹ Transaction hash: 0xe4be7b1a75b663eb345b957b216a8476b0f75e2bbfc5880943b05c82fab15dff
|
||||
|
||||
|
||||
## 2019-03-26
|
||||
|
||||
### v3.0.0 appids
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-proposal.open.aragonpm.eth v3.0.0:
|
||||
ℹ Contract address: 0x9f47c31aBB6F53ff2fec09C0bF79c3337C20f5AA
|
||||
ℹ Content (ipfs): Qmdxg33FxAQSH7U8oTApaM5SgUUC9btiA6tu5Hystzp5tV
|
||||
ℹ Transaction hash: 0xceb572f3fff368b9f07fc835577529a113e2de8ff7972a51ffaf4c63acbda9eb
|
||||
|
||||
|
||||
## 2019-03-25
|
||||
|
||||
### v2.0.0 updated appid hashes
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-proposal.open.aragonpm.eth v2.0.0:
|
||||
ℹ Contract address: 0x0a48dc5415f4d7A3B2B4a9aaD4A7a8775f923ce3
|
||||
ℹ Content (ipfs): QmZej9xPJN7aTiQ7SzWziRuzEjjfMzjPakcGYcoN8QQBMH
|
||||
ℹ Transaction hash: 0xf14c308b9f92b43a719fab2602c624dc2e11d0f629a0be9a6ec8ac47719ee9ca
|
||||
|
||||
### v1.0.0
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-proposal.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xFc04eB3eF666507F96A22d330d8a852d8eC996EA
|
||||
ℹ Content (ipfs): QmRTzoYr7B5f8gDGY8RmoodJkMm59D4jSJLZNRnhAd4wCg
|
||||
ℹ Transaction hash: 0xce419d9d555551eefc624a7ac87c19b5d660eb9c4fe0da611cd5e28e3ee6844f
|
@ -1,34 +0,0 @@
|
||||
# Token deployments
|
||||
|
||||
## 2019-04-10 - Weltempfänger release
|
||||
|
||||
✔ Successfully published kredits-token.open.aragonpm.eth v4.0.0:
|
||||
ℹ Contract address: 0x05E0C2bbdA8e5BeE22AC1E20C1457dA4de63aE26
|
||||
ℹ Content (ipfs): QmUuYLRMRNZcundUk2pxVaSjMNvtB7hzdf3eyoaUNqDPow
|
||||
ℹ Transaction hash: 0x98c28b5ca645904d56eb83c4783682f018c0fcee015b3a3d5fa8bd609223fb89
|
||||
|
||||
|
||||
## 2019-04-04
|
||||
|
||||
✔ Successfully published kredits-token.open.aragonpm.eth v3.0.0:
|
||||
ℹ Contract address: 0xd9913A96e087f50E71BF14c62cBCa3b9635392A9
|
||||
ℹ Content (ipfs): QmfZ7LwjkQRuLsEnVjrEF3ryTaHsL6YTxffiiDS5KWmHQG
|
||||
ℹ Transaction hash: 0x102b27e154d1e144ec084f5e8dc78e1626fda9f26c20db3e3b230fac381c317a
|
||||
|
||||
|
||||
## 2019-03-26
|
||||
|
||||
### v2.0.0 support for appIds
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-token.open.aragonpm.eth v2.0.0:
|
||||
ℹ Contract address: 0xc126919B3b30F14b848c2cc66Ec21A1e85a7c621
|
||||
ℹ Content (ipfs): QmWB9JrWa93vtdv5VG2yohiWTbDiuzbz9P58apJdP3FnNP
|
||||
ℹ Transaction hash: 0xa5ccd532a91d67b0616ee5505144988be4360440daf70dc2f5108dd2a59f3d68
|
||||
|
||||
|
||||
## 2019-03-25
|
||||
from account: 0x18f6d06de7e6d556b1bbb5875f8cfafb5eaef9c5
|
||||
✔ Successfully published kredits-token.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xB4147Be6d4bcC790c6CbD3d508354DDfd3EbC8e6
|
||||
ℹ Content (ipfs): QmQPue7WzQhaXbTLJwyZXSHaRY1u5ezWxyVmBP8bEgGoTE
|
||||
ℹ Transaction hash: 0xa7866d81e236adfeaff6bf2d5dbc9f9757fbc1b0ce689357901194913fe93a3b"
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
@ -1,90 +0,0 @@
|
||||
require("@nomiclabs/hardhat-waffle");
|
||||
require("hardhat-deploy");
|
||||
require("hardhat-deploy-ethers");
|
||||
require("@nomicfoundation/hardhat-chai-matchers");
|
||||
require("@openzeppelin/hardhat-upgrades");
|
||||
const Kredits = require("./lib/kredits");
|
||||
|
||||
const promptly = require("promptly");
|
||||
|
||||
extendEnvironment(async (hre) => {
|
||||
hre.kredits = new Kredits(
|
||||
hre.ethers.provider,
|
||||
hre.ethers.provider.getSigner()
|
||||
);
|
||||
await hre.kredits.init();
|
||||
});
|
||||
|
||||
// This is a sample Hardhat task. To learn how to create your own go to
|
||||
// https://hardhat.org/guides/create-task.html
|
||||
task("accounts", "Prints the list of accounts", async () => {
|
||||
const accounts = await ethers.getSigners();
|
||||
|
||||
for (const account of accounts) {
|
||||
console.log(account.address);
|
||||
}
|
||||
});
|
||||
|
||||
task("fund", "Send eth to an address", async () => {
|
||||
const to = await promptly.prompt("Address:");
|
||||
const value = await promptly.prompt("Value:");
|
||||
|
||||
const signer = await ethers.getSigners();
|
||||
|
||||
const fundTransaction = await signer[0].sendTransaction({
|
||||
to: to,
|
||||
value: ethers.utils.parseEther(value),
|
||||
});
|
||||
console.log(fundTransaction);
|
||||
});
|
||||
|
||||
task("create-wallet", "Creates a new wallet json", async () => {
|
||||
const wallet = ethers.Wallet.createRandom();
|
||||
|
||||
console.log("New wallet:");
|
||||
console.log(`Address: ${wallet.address}`);
|
||||
console.log(`Public key: ${wallet.publicKey}`);
|
||||
console.log(`Private key: ${wallet.privateKey}`);
|
||||
console.log(`Mnemonic: ${JSON.stringify(wallet.mnemonic)}`);
|
||||
|
||||
const password = await promptly.prompt("Encryption password: ");
|
||||
const encryptedJSON = await wallet.encrypt(password);
|
||||
|
||||
console.log("Encrypted wallet JSON:");
|
||||
console.log(encryptedJSON);
|
||||
});
|
||||
|
||||
// You need to export an object to set up your config
|
||||
// Go to https://hardhat.org/config/ to learn more
|
||||
|
||||
/**
|
||||
* @type import('hardhat/config').HardhatUserConfig
|
||||
*/
|
||||
module.exports = {
|
||||
solidity: "0.8.2",
|
||||
defaultNetwork: "localhost",
|
||||
networks: {
|
||||
hardhat: {
|
||||
chainId: 1337,
|
||||
},
|
||||
rinkeby: {
|
||||
url: "https://rinkeby.infura.io/v3/2e73045db2e84711912f8d0e5968f309",
|
||||
accounts: [
|
||||
process.env.DEPLOY_KEY ||
|
||||
"0xffb4230bdf9b1f1dd48f0bc54e4007436733f225a4f163d4f7e58e620ae329eb",
|
||||
],
|
||||
},
|
||||
rsk: {
|
||||
url: "https://rsk-testnet.kosmos.org",
|
||||
accounts: [
|
||||
process.env.DEPLOY_KEY ||
|
||||
"0xffb4230bdf9b1f1dd48f0bc54e4007436733f225a4f163d4f7e58e620ae329eb",
|
||||
],
|
||||
},
|
||||
},
|
||||
namedAccounts: {
|
||||
deployer: {
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
lib/abis/Contributors.json
Normal file
1
lib/abis/Contributors.json
Normal file
@ -0,0 +1 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contributors","outputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"contributorIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldIpfsHash","type":"bytes32"},{"indexed":false,"name":"newIpfsHash","type":"bytes32"}],"name":"ContributorProfileUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"oldAccount","type":"address"},{"indexed":false,"name":"newAccount","type":"address"}],"name":"ContributorAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"account","type":"address"}],"name":"ContributorAdded","type":"event"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"oldAccount","type":"address"},{"name":"newAccount","type":"address"}],"name":"updateContributorAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"updateContributorIpfsHash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"}],"name":"addContributor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"isCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"exists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressIsCore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"addressExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"id","type":"uint256"}],"name":"getContributorAddressById","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"getContributorById","outputs":[{"name":"id","type":"uint256"},{"name":"account","type":"address"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"isCore","type":"bool"},{"name":"balance","type":"uint256"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]
|
1
lib/abis/Operator.json
Normal file
1
lib/abis/Operator.json
Normal file
@ -0,0 +1 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposalsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"creatorAccount","type":"address"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"voterId","type":"uint256"},{"indexed":false,"name":"totalVotes","type":"uint256"}],"name":"ProposalVoted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"contributorId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ProposalExecuted","type":"event"},{"constant":true,"inputs":[],"name":"contributorsContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coreContributorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"contributorId","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"}],"name":"addProposal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"getProposal","outputs":[{"name":"id","type":"uint256"},{"name":"creatorAccount","type":"address"},{"name":"contributorId","type":"uint256"},{"name":"votesCount","type":"uint256"},{"name":"votesNeeded","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"executed","type":"bool"},{"name":"ipfsHash","type":"bytes32"},{"name":"hashFunction","type":"uint8"},{"name":"hashSize","type":"uint8"},{"name":"voterIds","type":"uint256[]"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"proposalId","type":"uint256"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
|
1
lib/abis/Registry.json
Normal file
1
lib/abis/Registry.json
Normal file
@ -0,0 +1 @@
|
||||
[{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"currentVersions","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"name":"versions","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"proxy","type":"address"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"},{"indexed":false,"name":"implementation","type":"address"}],"name":"VersionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"version","type":"uint256"}],"name":"ProxyImplementationUpgraded","type":"event"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"implementation","type":"address"}],"name":"addVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"getVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getLatestVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"getProxyFor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"upgradeToLatest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"version","type":"uint256"}],"name":"createProxy","outputs":[{"name":"","type":"address"}],"payable":true,"stateMutability":"payable","type":"function"}]
|
@ -1 +0,0 @@
|
||||
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":true,"internalType":"address","name":"addedByAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReimbursementAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":false,"internalType":"address","name":"vetoedByAccount","type":"address"}],"name":"ReimbursementVetoed","type":"event"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"recipientId","type":"uint32"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"vetoed","type":"bool"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"blocksToWait","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributorContract","outputs":[{"internalType":"contract ContributorInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"reimbursementId","type":"uint32"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finishMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"reimbursementId","type":"uint32"}],"name":"get","outputs":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"uint32","name":"recipientId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"}],"name":"getContributorAddressById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributorAccount","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrationDone","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"reimbursements","outputs":[{"internalType":"uint32","name":"recipientId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"vetoed","type":"bool"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reimbursementsCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"setContributorContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"confirmedOnly","type":"bool"}],"name":"totalAmount","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"reimbursementId","type":"uint32"}],"name":"veto","outputs":[],"stateMutability":"nonpayable","type":"function"}]
|
@ -1 +1 @@
|
||||
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"KreditsMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributorContract","outputs":[{"internalType":"contract ContributorInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributorContractAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contributorAccount","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"setContributorContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
|
||||
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_proxiedContractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"proposalId","type":"uint256"}],"name":"LogMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"contributorAccount","type":"address"},{"name":"amount","type":"uint256"},{"name":"proposalId","type":"uint256"}],"name":"mintFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"31": {
|
||||
"Contributor": "0x95DC31665D193E377f54b70C535fcDb205525291",
|
||||
"Contribution": "0x049bA8E70FEbFfd6d03C71211bDA37B4ff064115",
|
||||
"Token": "0x7ab26A0f00eF0D6e05e5BDE047505a4eD53aF809",
|
||||
"Reimbursement": "0x99EC72b34295b62f4bC1527Da461262c615a0b2c"
|
||||
},
|
||||
"1337": {
|
||||
"Contributor": "0xCc66f9A3cA2670972938FAD91d0865c4a62DFB25",
|
||||
"Contribution": "0x8999CaBc43E28202c5A2257f2a95A45b1F8A62BD",
|
||||
"Token": "0xe082678eCF749982e33Ea6839852a8cd989aEDE2",
|
||||
"Reimbursement": "0x984f797d26d3da2E9b9f8Ae4eeFEACC60fCAA90C"
|
||||
}
|
||||
}
|
1
lib/addresses/Contributors.json
Normal file
1
lib/addresses/Contributors.json
Normal file
@ -0,0 +1 @@
|
||||
{"42":"0x205fe1b3dac678b594c5f0535e7d158e38591f93","100":"0xa7fc9b1f678c41396b53904f94f50a42ff44d826"}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"4": "0x76e069b47b79442657eaf0555a32c6b16fa1b8b4"
|
||||
}
|
1
lib/addresses/Operator.json
Normal file
1
lib/addresses/Operator.json
Normal file
@ -0,0 +1 @@
|
||||
{"42":"0x9fd66ee78a5ebe86006f12b37ff59c63f9caa15b","100":"0x95d3bd7d136bb0b7ac9988097e964236f8a9976e"}
|
1
lib/addresses/Registry.json
Normal file
1
lib/addresses/Registry.json
Normal file
@ -0,0 +1 @@
|
||||
{"42":"0xc270e6ea4fe303df9f1a3d4a132ac425264082e7","100":"0x7458dea485d9d8301e3ce43e8a1ec1456be5ba83"}
|
1
lib/addresses/Token.json
Normal file
1
lib/addresses/Token.json
Normal file
@ -0,0 +1 @@
|
||||
{"42":"0xf71ccf7ab48044ef9ae0b5e6983dbd3266b78b36","100":"0x3fc29fbe40c2d0ca78c7e81342f00226650fe2ad"}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"4": "0xc34edf7d11b7f8433d597f0bb0697acdff55ef14"
|
||||
}
|
@ -1,22 +1,27 @@
|
||||
const deprecate = require('../utils/deprecate');
|
||||
|
||||
class Base {
|
||||
constructor (contract) {
|
||||
constructor(contract) {
|
||||
this.contract = contract;
|
||||
}
|
||||
|
||||
get 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 functions() {
|
||||
return this.contract.functions;
|
||||
}
|
||||
|
||||
get address () {
|
||||
return this.contract.address;
|
||||
get ipfs() {
|
||||
if (!this._ipfsAPI) { throw new Error('IPFS API not configured; please set an ipfs instance'); }
|
||||
return this._ipfsAPI;
|
||||
}
|
||||
|
||||
on (type, callback) {
|
||||
return this.contract.on(type, callback);
|
||||
set ipfs(ipfsAPI) {
|
||||
this._ipfsAPI = ipfsAPI;
|
||||
}
|
||||
|
||||
on(type, callback) {
|
||||
let eventMethod = `on${type.toLowerCase()}`;
|
||||
// Don't use this.contract.events here. Seems to be a bug in ethers.js
|
||||
this.contract[eventMethod] = callback;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Base;
|
||||
|
@ -1,76 +0,0 @@
|
||||
const Record = require('./record');
|
||||
const ContributionSerializer = require('../serializers/contribution');
|
||||
const deprecate = require('../utils/deprecate');
|
||||
|
||||
class Contribution extends Record {
|
||||
get count () {
|
||||
return this.contract.contributionsCount();
|
||||
}
|
||||
|
||||
getById (id) {
|
||||
return this.contract.getContribution(id)
|
||||
.then(data => {
|
||||
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||
});
|
||||
}
|
||||
|
||||
getData (id) {
|
||||
return this.contract.getContribution(id);
|
||||
}
|
||||
|
||||
getByContributorId (contributorId) {
|
||||
return this.contract.getContributorAddressById(contributorId)
|
||||
.then(address => this.getByContributorAddress(address));
|
||||
}
|
||||
|
||||
getByContributorAddress (address) {
|
||||
return this.contract.balanceOf(address)
|
||||
.then(async (balance) => {
|
||||
const count = balance.toNumber();
|
||||
const contributions = [];
|
||||
|
||||
for (let index = 0; index < count; index++) {
|
||||
const id = await this.contract.tokenOfOwnerByIndex(address, index);
|
||||
const contribution = await this.getById(id);
|
||||
contributions.push(contribution);
|
||||
}
|
||||
|
||||
return contributions;
|
||||
});
|
||||
}
|
||||
|
||||
async add (contributionAttr, callOptions = {}) {
|
||||
const contribution = new ContributionSerializer(contributionAttr);
|
||||
const confirmedAtBlock = contributionAttr.confirmedAtBlock || 0;
|
||||
const vetoed = contributionAttr.vetoed || false;
|
||||
|
||||
try { await contribution.validate(); }
|
||||
catch (error) { return Promise.reject(error); }
|
||||
|
||||
const jsonStr = contribution.serialize();
|
||||
|
||||
return this.ipfs
|
||||
.add(jsonStr)
|
||||
.then(ipfsHashAttr => {
|
||||
let contribution = [
|
||||
contributionAttr.amount,
|
||||
contributionAttr.contributorId,
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
confirmedAtBlock,
|
||||
vetoed,
|
||||
];
|
||||
|
||||
return this.contract.add(...contribution, callOptions);
|
||||
});
|
||||
}
|
||||
|
||||
addContribution () {
|
||||
deprecate('The function `addContribution()` is deprecated and will be removed in the next major version. Use `add()` instead');
|
||||
return this.add(...arguments);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Contribution;
|
@ -1,100 +1,57 @@
|
||||
const Record = require('./record');
|
||||
const ContributorSerializer = require('../serializers/contributor');
|
||||
const formatKredits = require('../utils/format-kredits');
|
||||
const ethers = require('ethers');
|
||||
const RSVP = require('rsvp');
|
||||
|
||||
class Contributor extends Record {
|
||||
get count () {
|
||||
return this.contract.contributorsCount();
|
||||
const ContributorSerializer = require('../serializers/contributor');
|
||||
const Base = require('./base');
|
||||
|
||||
class Contributor extends Base {
|
||||
all() {
|
||||
return this.functions.contributorsCount()
|
||||
.then((count) => {
|
||||
count = count.toNumber();
|
||||
let contributors = [];
|
||||
|
||||
for (let id = 1; id <= count; id++) {
|
||||
contributors.push(this.getById(id));
|
||||
}
|
||||
|
||||
return RSVP.all(contributors);
|
||||
});
|
||||
}
|
||||
|
||||
getById (id) {
|
||||
return this.contract.getContributorById(id)
|
||||
.then(contractData => {
|
||||
let data = {...contractData};
|
||||
data.balanceInt = formatKredits(data.balance);
|
||||
getById(id) {
|
||||
id = ethers.utils.bigNumberify(id);
|
||||
|
||||
return this.functions.getContributorById(id)
|
||||
.then((data) => {
|
||||
// TODO: remove when naming updated on the contract
|
||||
data.hashDigest = data.ipfsHash;
|
||||
return data;
|
||||
})
|
||||
// Fetch IPFS data if available
|
||||
.then((data) => {
|
||||
return this.ipfs.catAndMerge(data, ContributorSerializer.deserialize);
|
||||
});
|
||||
}
|
||||
|
||||
getData (id) {
|
||||
return this.contract.getContributorById(id);
|
||||
}
|
||||
add(contributorAttr, callOptions = {}) {
|
||||
let json = ContributorSerializer.serialize(contributorAttr);
|
||||
// TODO: validate against schema
|
||||
|
||||
filterByAccount (search) {
|
||||
return this._byAccount(search, 'filter');
|
||||
}
|
||||
|
||||
findByAccount (search) {
|
||||
return this._byAccount(search, 'find');
|
||||
}
|
||||
|
||||
_byAccount (search, method = 'filter') {
|
||||
return this.all().then((contributors) => {
|
||||
const searchEntries = Object.entries(search);
|
||||
|
||||
return contributors[method]((contributor) => {
|
||||
if (!contributor.accounts) { return false; }
|
||||
return contributor.accounts.find((account) => {
|
||||
return searchEntries.every((item) => {
|
||||
let [ key, value ] = item;
|
||||
return account[key] === value;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async add (contributorAttr, callOptions = {}) {
|
||||
let contributor = new ContributorSerializer(contributorAttr);
|
||||
|
||||
try { await contributor.validate(); }
|
||||
catch (error) { return Promise.reject(error); }
|
||||
|
||||
const jsonStr = contributor.serialize();
|
||||
|
||||
// console.log('Adding IPFS doc for', contributorAttr.account);
|
||||
return this.ipfs
|
||||
.add(jsonStr)
|
||||
.add(json)
|
||||
.then((ipfsHashAttr) => {
|
||||
let contributor = [
|
||||
contributorAttr.account,
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
contributorAttr.isCore,
|
||||
];
|
||||
|
||||
// console.log('Adding onchain record for', contributorAttr.account);
|
||||
return this.contract.addContributor(...contributor, callOptions);
|
||||
}).catch(err => {
|
||||
console.log('Failed to add IPFS document:', err.message);
|
||||
throw(err);
|
||||
return this.functions.addContributor(...contributor, callOptions);
|
||||
});
|
||||
}
|
||||
|
||||
updateProfile (contributorId, updateAttr, callOptions = {}) {
|
||||
return this.getById(contributorId).then(async (contributor) => {
|
||||
let updatedContributorAttr = Object.assign(contributor, updateAttr);
|
||||
let updatedContributor = new ContributorSerializer(updatedContributorAttr);
|
||||
|
||||
try { await updatedContributor.validate(); }
|
||||
catch (error) { return Promise.reject(error); }
|
||||
|
||||
const jsonStr = updatedContributor.serialize();
|
||||
|
||||
return this.ipfs
|
||||
.add(jsonStr)
|
||||
.then(ipfsHashAttr => {
|
||||
return this.contract.updateContributorProfileHash(
|
||||
contributorId,
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
callOptions
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Contributor;
|
||||
|
@ -1,7 +1,6 @@
|
||||
module.exports = {
|
||||
Contributor: require('./contributor'),
|
||||
Contribution: require('./contribution'),
|
||||
Proposal: require('./proposal'),
|
||||
Contributors: require('./contributor'),
|
||||
Operator: require('./operator'),
|
||||
Token: require('./token'),
|
||||
Reimbursement: require('./reimbursement'),
|
||||
Registry: require('./registry')
|
||||
};
|
||||
|
57
lib/contracts/operator.js
Normal file
57
lib/contracts/operator.js
Normal file
@ -0,0 +1,57 @@
|
||||
const ethers = require('ethers');
|
||||
const RSVP = require('rsvp');
|
||||
|
||||
const ContributionSerializer = require('../serializers/contribution');
|
||||
const Base = require('./base');
|
||||
|
||||
class Operator extends Base {
|
||||
all() {
|
||||
return this.functions.proposalsCount()
|
||||
.then((count) => {
|
||||
count = count.toNumber();
|
||||
let proposals = [];
|
||||
|
||||
for (let id = 1; id <= count; id++) {
|
||||
proposals.push(this.getById(id));
|
||||
}
|
||||
|
||||
return RSVP.all(proposals);
|
||||
});
|
||||
}
|
||||
|
||||
getById(id) {
|
||||
id = ethers.utils.bigNumberify(id);
|
||||
|
||||
return this.functions.getProposal(id)
|
||||
.then((data) => {
|
||||
// TODO: remove when naming updated on the contract
|
||||
data.hashDigest = data.ipfsHash;
|
||||
return data;
|
||||
})
|
||||
// Fetch IPFS data if available
|
||||
.then((data) => {
|
||||
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||
});
|
||||
}
|
||||
|
||||
addProposal(proposalAttr, callOptions = {}) {
|
||||
let json = ContributionSerializer.serialize(proposalAttr);
|
||||
// TODO: validate against schema
|
||||
|
||||
return this.ipfs
|
||||
.add(json)
|
||||
.then((ipfsHashAttr) => {
|
||||
let proposal = [
|
||||
proposalAttr.contributorId,
|
||||
proposalAttr.amount,
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
];
|
||||
|
||||
return this.functions.addProposal(...proposal, callOptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Operator;
|
@ -1,46 +0,0 @@
|
||||
const Record = require('./record');
|
||||
const ContributionSerializer = require('../serializers/contribution');
|
||||
const deprecate = require('../utils/deprecate');
|
||||
|
||||
class Proposal extends Record {
|
||||
get count () {
|
||||
return this.contract.proposalsCount();
|
||||
}
|
||||
|
||||
getById (id) {
|
||||
return this.contract.getProposal(id)
|
||||
.then(data => {
|
||||
return this.ipfs.catAndMerge(data, ContributionSerializer.deserialize);
|
||||
});
|
||||
}
|
||||
|
||||
async add (proposalAttr, callOptions = {}) {
|
||||
const contribution = new ContributionSerializer(proposalAttr);
|
||||
|
||||
try { await contribution.validate(); }
|
||||
catch (error) { return Promise.reject(error); }
|
||||
|
||||
const jsonStr = contribution.serialize();
|
||||
|
||||
return this.ipfs
|
||||
.add(jsonStr)
|
||||
.then((ipfsHashAttr) => {
|
||||
let proposal = [
|
||||
proposalAttr.contributorId,
|
||||
proposalAttr.amount,
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
];
|
||||
|
||||
return this.contract.addProposal(...proposal, callOptions);
|
||||
});
|
||||
}
|
||||
|
||||
addProposal () {
|
||||
deprecate('The function `addProposal()` is deprecated and will be removed in the next major version. Use `add()` instead');
|
||||
return this.add(...arguments);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Proposal;
|
@ -1,14 +0,0 @@
|
||||
const Base = require('./base');
|
||||
const paged = require('../utils/pagination');
|
||||
|
||||
class Record extends Base {
|
||||
all (options = {}) {
|
||||
return this.count
|
||||
.then((count) => {
|
||||
let records = paged(count, options).map((id) => this.getById(id));
|
||||
return Promise.all(records);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Record;
|
6
lib/contracts/registry.js
Normal file
6
lib/contracts/registry.js
Normal file
@ -0,0 +1,6 @@
|
||||
const Base = require('./base');
|
||||
|
||||
class Registry extends Base {
|
||||
}
|
||||
|
||||
module.exports = Registry;
|
@ -1,71 +0,0 @@
|
||||
const Record = require("./record");
|
||||
const ExpenseSerializer = require("../serializers/expense");
|
||||
|
||||
class Reimbursement extends Record {
|
||||
get count () {
|
||||
return this.contract.reimbursementsCount();
|
||||
}
|
||||
|
||||
getById (id) {
|
||||
return this.contract.get(id).then((data) => {
|
||||
return this.ipfs.catAndMerge(data, (ipfsDocument) => {
|
||||
const expenses = JSON.parse(ipfsDocument);
|
||||
return { expenses };
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getData (id) {
|
||||
return this.contract.get(id);
|
||||
}
|
||||
|
||||
async add (attrs, callOptions = {}) {
|
||||
const amount = parseInt(attrs.amount);
|
||||
const token = attrs.token;
|
||||
const recipientId = attrs.recipientId;
|
||||
const confirmedAtBlock = attrs.confirmedAtBlock || 0;
|
||||
const vetoed = attrs.vetoed || false;
|
||||
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,
|
||||
confirmedAtBlock,
|
||||
vetoed,
|
||||
];
|
||||
|
||||
return this.contract.add(...reimbursement, callOptions);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Reimbursement;
|
@ -4,3 +4,4 @@ class Token extends Base {
|
||||
}
|
||||
|
||||
module.exports = Token;
|
||||
|
||||
|
117
lib/kredits.js
117
lib/kredits.js
@ -1,113 +1,78 @@
|
||||
const ethers = require('ethers');
|
||||
const RSVP = require('rsvp');
|
||||
|
||||
const Preflight = require('./utils/preflight');
|
||||
const deprecate = require('./utils/deprecate');
|
||||
const Healthcheck = require('./utils/healthcheck');
|
||||
|
||||
const ABIS = {
|
||||
Contributor: require('./abis/Contributor.json'),
|
||||
Contribution: require('./abis/Contribution.json'),
|
||||
Reimbursement: require('./abis/Reimbursement.json'),
|
||||
Token: require('./abis/Token.json'),
|
||||
Contributors: require('./abis/Contributors.json'),
|
||||
Operator: require('./abis/Operator.json'),
|
||||
Registry: require('./abis/Registry.json'),
|
||||
Token: require('./abis/Token.json')
|
||||
};
|
||||
// const APP_CONTRACTS = [
|
||||
// 'Contributor',
|
||||
// 'Contribution',
|
||||
// 'Token',
|
||||
// 'Reimbursement',
|
||||
// ];
|
||||
const Addresses = require('./addresses.json');
|
||||
const RegistryAddress = require('./addresses/Registry.json');
|
||||
|
||||
const Contracts = require('./contracts');
|
||||
const IPFS = require('./utils/ipfs');
|
||||
const IPFS = require('./utils/ipfs')
|
||||
|
||||
// Helpers
|
||||
function capitalize (word) {
|
||||
function capitalize(word) {
|
||||
let [first, ...rest] = word;
|
||||
return `${first.toUpperCase()}${rest.join('')}`;
|
||||
}
|
||||
|
||||
class Kredits {
|
||||
|
||||
constructor (provider, signer, options = {}) {
|
||||
const { addresses, abis, ipfsConfig } = options;
|
||||
constructor(provider, signer, options = {}) {
|
||||
let { addresses, abis, ipfsConfig } = options;
|
||||
|
||||
this.provider = provider;
|
||||
this.signer = signer;
|
||||
this.options = options;
|
||||
this.addresses = addresses || {};
|
||||
// by default we only need the registry address.
|
||||
// the rest is loaded from there in the init() function
|
||||
this.addresses = addresses || { Registry: RegistryAddress[this.provider.chainId.toString()] }; // chainID must be a string
|
||||
this.abis = abis || ABIS;
|
||||
this.ipfs = new IPFS(ipfsConfig);
|
||||
this.contracts = {};
|
||||
}
|
||||
|
||||
init (/* names */) {
|
||||
// TODO implement
|
||||
// const contractsToLoad = names || APP_CONTRACTS;
|
||||
|
||||
return this.provider.getNetwork().then(network => {
|
||||
if (Object.keys(this.addresses).length === 0) {
|
||||
this.addresses = Addresses[network.chainId.toString()];
|
||||
}
|
||||
return this;
|
||||
init(names) {
|
||||
let contractsToLoad = names || Object.keys(ABIS);
|
||||
let addressPromises = contractsToLoad.map((contractName) => {
|
||||
return this.Registry.functions.getProxyFor(contractName).then((address) => {
|
||||
this.addresses[contractName] = address;
|
||||
}).catch((error) => {
|
||||
throw new Error(`Failed to get address for ${contractName} from registry at ${this.Registry.contract.address}
|
||||
- correct registry? does it have version entry? - ${error.message}`
|
||||
);
|
||||
});
|
||||
});
|
||||
return RSVP.all(addressPromises).then(() => { return this });
|
||||
}
|
||||
|
||||
static setup (provider, signer, ipfsConfig = null) {
|
||||
deprecate('Kredits.setup() is deprecated use new Kredits().init() instead');
|
||||
static setup(provider, signer, ipfsConfig = null) {
|
||||
console.log('Kredits.setup() is deprecated use new Kredits().init() instead');
|
||||
return new Kredits(provider, signer, { ipfsConfig: ipfsConfig }).init();
|
||||
}
|
||||
|
||||
static for (connectionOptions, kreditsOptions) {
|
||||
let { network, rpcUrl, wallet } = connectionOptions;
|
||||
if (!rpcUrl && network === 'local') { rpcUrl = 'http://localhost:8545'; }
|
||||
let ethProvider, signer;
|
||||
if (rpcUrl) {
|
||||
ethProvider = new ethers.providers.JsonRpcProvider(rpcUrl);
|
||||
} else {
|
||||
ethProvider = new ethers.getDefaultProvider(network);
|
||||
}
|
||||
if (wallet) {
|
||||
signer = wallet.connect(ethProvider);
|
||||
} else if (ethProvider.getSigner) {
|
||||
// Only useful for reading data, not writing. The (unused) address is
|
||||
// necessary because without an address, ethers.js will try to look up
|
||||
// the provider's account 0, which doesn't work on our public RSK nodes.
|
||||
signer = ethProvider.getSigner('0xfa77675540E550b911a6AABF3805ac17C6641ec1');
|
||||
}
|
||||
return new Kredits(ethProvider, signer, kreditsOptions);
|
||||
get Registry() {
|
||||
return this.contractFor('registry');
|
||||
}
|
||||
|
||||
static availableNetworks () {
|
||||
return Object.keys(Addresses);
|
||||
get Contributor() {
|
||||
// TODO: rename to contributor
|
||||
return this.contractFor('contributors');
|
||||
}
|
||||
|
||||
get Contributor () {
|
||||
return this.contractFor('Contributor');
|
||||
get Operator() {
|
||||
return this.contractFor('operator');
|
||||
}
|
||||
|
||||
get Contributors () {
|
||||
deprecate('Contributors is deprecated use Contributor instead');
|
||||
return this.contractFor('Contributor');
|
||||
}
|
||||
|
||||
get Operator () {
|
||||
return this.Proposal;
|
||||
}
|
||||
|
||||
get Token () {
|
||||
return this.contractFor('Token');
|
||||
}
|
||||
|
||||
get Contribution () {
|
||||
return this.contractFor('Contribution');
|
||||
}
|
||||
|
||||
get Reimbursement () {
|
||||
return this.contractFor('Reimbursement');
|
||||
get Token() {
|
||||
return this.contractFor('token');
|
||||
}
|
||||
|
||||
// Should be private
|
||||
contractFor (name) {
|
||||
contractFor(name) {
|
||||
if (this.contracts[name]) {
|
||||
return this.contracts[name];
|
||||
}
|
||||
@ -119,16 +84,16 @@ class Kredits {
|
||||
throw new Error(`Address or ABI not found for ${contractName}`);
|
||||
}
|
||||
|
||||
const signerOrProvider = this.signer || this.provider;
|
||||
const contract = new ethers.Contract(address, abi, signerOrProvider);
|
||||
let signerOrProvider = this.signer || this.provider;
|
||||
let contract = new ethers.Contract(address, abi, signerOrProvider);
|
||||
this.contracts[name] = new Contracts[contractName](contract);
|
||||
this.contracts[name].ipfs = this.ipfs;
|
||||
|
||||
return this.contracts[name];
|
||||
}
|
||||
|
||||
preflightChecks () {
|
||||
return new Preflight(this).check();
|
||||
healthcheck() {
|
||||
return new Healthcheck(this).check();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
const ethers = require('ethers');
|
||||
|
||||
const ABI = require('./abis/KreditsKit.json');
|
||||
const Addresses = require('./addresses/KreditsKit.json');
|
||||
|
||||
class KreditsKit {
|
||||
|
||||
constructor (provider, signer, options = {}) {
|
||||
let { address, abi } = options;
|
||||
|
||||
this.provider = provider;
|
||||
this.signer = signer;
|
||||
this.options = options;
|
||||
this.address = address;
|
||||
this.abi = abi || ABI;
|
||||
}
|
||||
|
||||
init () {
|
||||
return this.provider.getNetwork().then((network) => {
|
||||
this.address = this.address || Addresses[network.chainId.toString()];
|
||||
this.contract = new ethers.Contract(
|
||||
this.address,
|
||||
this.abi,
|
||||
(this.signer || this.provider)
|
||||
);
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
appIdFor (contractName) {
|
||||
// see appIds in KreditsKit.sol for more details
|
||||
const knownContracts = ['Contribution', 'Contributor', 'Proposal', 'Reimbursement', 'Token'];
|
||||
return this.contract.appIds(knownContracts.indexOf(contractName));
|
||||
}
|
||||
|
||||
newDAO (options = {}) {
|
||||
return this.contract.newInstance(options).then(transaction => {
|
||||
return transaction.wait().then(result => {
|
||||
const deployEvent = result.events.find(e => e.event === 'DeployInstance');
|
||||
return {
|
||||
daoAddress: deployEvent.args.dao,
|
||||
transactionHash: transaction.hash,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = KreditsKit;
|
@ -1,75 +1,19 @@
|
||||
const schemas = require('@kosmos/schemas');
|
||||
const validator = require('../utils/validator');
|
||||
|
||||
/**
|
||||
* Serialization and validation for JSON-LD document of the contribution.
|
||||
* Handle serialization for JSON-LD object of the contribution, according to
|
||||
* https://github.com/67P/kosmos-schemas/blob/master/schemas/contribution.json
|
||||
*
|
||||
* @class
|
||||
* @public
|
||||
*/
|
||||
class Contribution {
|
||||
|
||||
constructor (attrs) {
|
||||
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize object to JSON
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
serialize () {
|
||||
/**
|
||||
* Deserialize JSON to object
|
||||
*
|
||||
* @method
|
||||
* @public
|
||||
*/
|
||||
static deserialize(serialized) {
|
||||
let {
|
||||
contributorIpfsHash,
|
||||
date,
|
||||
time,
|
||||
kind,
|
||||
description,
|
||||
url,
|
||||
details,
|
||||
} = this;
|
||||
|
||||
let data = {
|
||||
'@context': 'https://schema.kosmos.org',
|
||||
'@type': 'Contribution',
|
||||
'contributor': {
|
||||
'ipfs': contributorIpfsHash,
|
||||
},
|
||||
date,
|
||||
time,
|
||||
kind,
|
||||
description,
|
||||
'details': details || {},
|
||||
};
|
||||
|
||||
if (url) {
|
||||
data['url'] = url;
|
||||
}
|
||||
|
||||
// Write it pretty to ipfs
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate serialized data against schema
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
validate () {
|
||||
const serialized = JSON.parse(this.serialize());
|
||||
const valid = validator.validate(serialized, schemas['contribution']);
|
||||
return valid ? Promise.resolve() : Promise.reject(validator.error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize JSON to object
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
static deserialize (serialized) {
|
||||
let {
|
||||
date,
|
||||
time,
|
||||
kind,
|
||||
description,
|
||||
details,
|
||||
@ -77,8 +21,6 @@ class Contribution {
|
||||
} = JSON.parse(serialized.toString('utf8'));
|
||||
|
||||
return {
|
||||
date,
|
||||
time,
|
||||
kind,
|
||||
description,
|
||||
details,
|
||||
@ -87,6 +29,39 @@ class Contribution {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize object to JSON
|
||||
*
|
||||
* @method
|
||||
* @public
|
||||
*/
|
||||
static serialize(deserialized) {
|
||||
let {
|
||||
contributorIpfsHash,
|
||||
kind,
|
||||
description,
|
||||
url,
|
||||
details
|
||||
} = deserialized;
|
||||
|
||||
let data = {
|
||||
"@context": "https://schema.kosmos.org",
|
||||
"@type": "Contribution",
|
||||
"contributor": {
|
||||
"ipfs": contributorIpfsHash
|
||||
},
|
||||
kind,
|
||||
description,
|
||||
"details": details || {}
|
||||
};
|
||||
|
||||
if (url) {
|
||||
data["url"] = url;
|
||||
}
|
||||
|
||||
// Write it pretty to ipfs
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Contribution;
|
||||
|
@ -1,5 +1,3 @@
|
||||
const schemas = require('@kosmos/schemas');
|
||||
const validator = require('../utils/validator');
|
||||
/**
|
||||
* Handle serialization for JSON-LD object of the contributor, according to
|
||||
* https://github.com/67P/kosmos-schemas/blob/master/schemas/contributor.json
|
||||
@ -8,95 +6,13 @@ const validator = require('../utils/validator');
|
||||
* @public
|
||||
*/
|
||||
class Contributor {
|
||||
|
||||
constructor (attrs) {
|
||||
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize object to JSON
|
||||
*
|
||||
* @method
|
||||
* @public
|
||||
*/
|
||||
serialize () {
|
||||
let {
|
||||
name,
|
||||
kind,
|
||||
url,
|
||||
github_uid,
|
||||
github_username,
|
||||
gitea_username,
|
||||
wiki_username,
|
||||
zoom_display_name,
|
||||
} = this;
|
||||
|
||||
let data = {
|
||||
'@context': 'https://schema.kosmos.org',
|
||||
'@type': 'Contributor',
|
||||
kind,
|
||||
name,
|
||||
accounts: [],
|
||||
};
|
||||
|
||||
if (url) {
|
||||
data['url'] = url;
|
||||
}
|
||||
|
||||
if (github_uid) {
|
||||
data.accounts.push({
|
||||
'site': 'github.com',
|
||||
'uid': github_uid,
|
||||
'username': github_username,
|
||||
'url': `https://github.com/${github_username}`,
|
||||
});
|
||||
}
|
||||
|
||||
if (gitea_username) {
|
||||
data.accounts.push({
|
||||
'site': 'gitea.kosmos.org',
|
||||
'username': gitea_username,
|
||||
'url': `https://gitea.kosmos.org/${gitea_username}`,
|
||||
});
|
||||
}
|
||||
|
||||
if (wiki_username) {
|
||||
data.accounts.push({
|
||||
'site': 'wiki.kosmos.org',
|
||||
'username': wiki_username,
|
||||
'url': `https://wiki.kosmos.org/User:${wiki_username}`,
|
||||
});
|
||||
}
|
||||
|
||||
if (zoom_display_name) {
|
||||
data.accounts.push({
|
||||
'site': 'zoom.us',
|
||||
'username': zoom_display_name,
|
||||
});
|
||||
}
|
||||
|
||||
// Write it pretty to ipfs
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate serialized data against schema
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
validate () {
|
||||
const serialized = JSON.parse(this.serialize());
|
||||
const valid = validator.validate(serialized, schemas['contributor']);
|
||||
return valid ? Promise.resolve() : Promise.reject(validator.error);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Deserialize JSON to object
|
||||
*
|
||||
* @method
|
||||
* @public
|
||||
*/
|
||||
static deserialize (serialized) {
|
||||
static deserialize(serialized) {
|
||||
let {
|
||||
name,
|
||||
kind,
|
||||
@ -104,24 +20,16 @@ class Contributor {
|
||||
accounts,
|
||||
} = JSON.parse(serialized.toString('utf8'));
|
||||
|
||||
let github_username, github_uid, gitea_username, wiki_username, zoom_display_name;
|
||||
let github = accounts.find(a => a.site === 'github.com');
|
||||
let gitea = accounts.find(a => a.site === 'gitea.kosmos.org');
|
||||
let wiki = accounts.find(a => a.site === 'wiki.kosmos.org');
|
||||
let zoom = accounts.find(a => a.site === 'zoom.us');
|
||||
let github_username, github_uid, wiki_username;
|
||||
let github = accounts.find((a) => a.site === 'github.com');
|
||||
let wiki = accounts.find((a) => a.site === 'wiki.kosmos.org');
|
||||
|
||||
if (github) {
|
||||
(({ username: github_username, uid: github_uid} = github));
|
||||
}
|
||||
if (gitea) {
|
||||
(({ username: gitea_username } = gitea));
|
||||
}
|
||||
if (wiki) {
|
||||
(({ username: wiki_username } = wiki));
|
||||
}
|
||||
if (zoom) {
|
||||
(({ username: zoom_display_name } = zoom));
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
@ -130,13 +38,59 @@ class Contributor {
|
||||
accounts,
|
||||
github_uid,
|
||||
github_username,
|
||||
gitea_username,
|
||||
wiki_username,
|
||||
zoom_display_name,
|
||||
ipfsData: serialized,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize object to JSON
|
||||
*
|
||||
* @method
|
||||
* @public
|
||||
*/
|
||||
static serialize(deserialized) {
|
||||
let {
|
||||
name,
|
||||
kind,
|
||||
url,
|
||||
github_uid,
|
||||
github_username,
|
||||
wiki_username,
|
||||
} = deserialized;
|
||||
|
||||
let data = {
|
||||
"@context": "https://schema.kosmos.org",
|
||||
"@type": "Contributor",
|
||||
kind,
|
||||
name,
|
||||
"accounts": []
|
||||
};
|
||||
|
||||
if (url) {
|
||||
data["url"] = url;
|
||||
}
|
||||
|
||||
if (github_uid) {
|
||||
data.accounts.push({
|
||||
"site": "github.com",
|
||||
"uid": github_uid,
|
||||
"username": github_username,
|
||||
"url": `https://github.com/${github_username}`
|
||||
});
|
||||
}
|
||||
|
||||
if (wiki_username) {
|
||||
data.accounts.push({
|
||||
"site": "wiki.kosmos.org",
|
||||
"username": wiki_username,
|
||||
"url": `https://wiki.kosmos.org/User:${wiki_username}`
|
||||
});
|
||||
}
|
||||
|
||||
// Write it pretty to ipfs
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Contributor;
|
||||
|
@ -1,104 +0,0 @@
|
||||
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,
|
||||
amountSats,
|
||||
date,
|
||||
url,
|
||||
tags,
|
||||
details,
|
||||
} = this;
|
||||
|
||||
const data = {
|
||||
'@context': 'https://schema.kosmos.org',
|
||||
'@type': 'Expense',
|
||||
title,
|
||||
description,
|
||||
currency,
|
||||
amount,
|
||||
amountSats,
|
||||
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,
|
||||
amountSats,
|
||||
date,
|
||||
url,
|
||||
tags,
|
||||
details,
|
||||
} = JSON.parse(serialized.toString('utf8'));
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
currency,
|
||||
amount,
|
||||
amountSats,
|
||||
date,
|
||||
url,
|
||||
tags,
|
||||
details,
|
||||
ipfsData: serialized,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ExpenseSerializer;
|
@ -1,5 +0,0 @@
|
||||
/*eslint no-console: ["error", { allow: ["warn"] }] */
|
||||
|
||||
module.exports = function deprecate (msg) {
|
||||
console.warn(msg);
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
const ethersUtils = require('ethers').utils;
|
||||
|
||||
module.exports = function(value, options = {}) {
|
||||
let etherValue = ethersUtils.formatEther(value);
|
||||
if (options.asFloat) {
|
||||
return parseFloat(etherValue);
|
||||
} else {
|
||||
return parseInt(etherValue);
|
||||
}
|
||||
};
|
@ -1,9 +1,9 @@
|
||||
class Preflight {
|
||||
constructor (kredits) {
|
||||
class Healthcheck {
|
||||
constructor(kredits) {
|
||||
this.kredits = kredits;
|
||||
}
|
||||
|
||||
check () {
|
||||
check() {
|
||||
return this.kredits.ipfs._ipfsAPI.id()
|
||||
.catch((error) => {
|
||||
throw new Error(`IPFS node not available; config: ${JSON.stringify(this.kredits.ipfs.config)} - ${error.message}`);
|
||||
@ -25,4 +25,4 @@ class Preflight {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Preflight;
|
||||
module.exports = Healthcheck;
|
@ -1,25 +1,17 @@
|
||||
const ipfsClient = require('ipfs-http-client');
|
||||
const ipfsAPI = require('ipfs-api');
|
||||
const multihashes = require('multihashes');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
class IPFS {
|
||||
constructor (config) {
|
||||
|
||||
constructor(config) {
|
||||
if (!config) {
|
||||
config = { host: 'localhost', port: '5001', protocol: 'http' };
|
||||
}
|
||||
this._ipfsAPI = ipfsAPI(config);
|
||||
this._config = config;
|
||||
this._ipfsAPI = ipfsClient.create(config);
|
||||
|
||||
this._ipfsAPI.id().then(res => {
|
||||
console.debug('IPFS ID:', res.id);
|
||||
}).catch(e => {
|
||||
console.debug('IPFS config:', config);
|
||||
console.warn('Failed to initialize IPFS:', e.message);
|
||||
});
|
||||
}
|
||||
|
||||
async catAndMerge (contractData, deserialize) {
|
||||
let data = {...contractData}; // data from ethers.js is not extensible. this copy the attributes in a new object
|
||||
catAndMerge(data, deserialize) {
|
||||
// if no hash details are found simply return the data; nothing to merge
|
||||
if (!data.hashSize || data.hashSize === 0) {
|
||||
return data;
|
||||
@ -29,57 +21,42 @@ class IPFS {
|
||||
|
||||
return this.cat(data.ipfsHash)
|
||||
.then(deserialize)
|
||||
.then(attributes => {
|
||||
.then((attributes) => {
|
||||
return Object.assign({}, data, attributes);
|
||||
});
|
||||
}
|
||||
|
||||
async add (data) {
|
||||
return this._ipfsAPI.add(data)
|
||||
.then(res => {
|
||||
return this.decodeHash(res.path);
|
||||
add(data) {
|
||||
return this._ipfsAPI
|
||||
.add(new this._ipfsAPI.Buffer(data))
|
||||
.then((res) => {
|
||||
return this.decodeHash(res[0].hash);
|
||||
});
|
||||
}
|
||||
|
||||
async cat (hashData) {
|
||||
cat(hashData) {
|
||||
let ipfsHash = hashData; // default - if it is a string
|
||||
if (Object.prototype.hasOwnProperty.call(hashData, 'hashSize')) {
|
||||
if (hashData.hasOwnProperty('hashSize')) {
|
||||
ipfsHash = this.encodeHash(hashData);
|
||||
}
|
||||
if (this._config['gatewayUrl']) {
|
||||
return fetch(`${this._config['gatewayUrl']}/${ipfsHash}`).then(r => r.text());
|
||||
} else {
|
||||
const res = this._ipfsAPI.cat(ipfsHash);
|
||||
let str = '';
|
||||
for await (const buffer of res) {
|
||||
str += buffer.toString();
|
||||
}
|
||||
return Promise.resolve(str);
|
||||
}
|
||||
return this._ipfsAPI.cat(ipfsHash);
|
||||
}
|
||||
|
||||
pin (hashData) {
|
||||
let ipfsHash = hashData; // default - if it is a string
|
||||
if (Object.prototype.hasOwnProperty.call(hashData, 'hashSize')) {
|
||||
ipfsHash = this.encodeHash(hashData);
|
||||
}
|
||||
return this._ipfsAPI.pin.add(multihashes.toB58String(ipfsHash));
|
||||
}
|
||||
|
||||
decodeHash (ipfsHash) {
|
||||
decodeHash(ipfsHash) {
|
||||
let multihash = multihashes.decode(multihashes.fromB58String(ipfsHash));
|
||||
return {
|
||||
hashDigest: '0x' + multihashes.toHexString(multihash.digest),
|
||||
hashSize: multihash.length,
|
||||
hashFunction: multihash.code,
|
||||
ipfsHash: ipfsHash,
|
||||
ipfsHash: ipfsHash
|
||||
};
|
||||
}
|
||||
|
||||
encodeHash (hashData) {
|
||||
const digest = Buffer.from(hashData.hashDigest.slice(2), 'hex');
|
||||
encodeHash(hashData) {
|
||||
let digest = this._ipfsAPI.Buffer.from(hashData.hashDigest.slice(2), 'hex');
|
||||
return multihashes.encode(digest, hashData.hashFunction, hashData.hashSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = IPFS;
|
||||
|
@ -1,46 +0,0 @@
|
||||
function pageNumber (number, size, recordCount) {
|
||||
let numberOfPages = Math.ceil(recordCount / size);
|
||||
|
||||
number = parseInt(number) || 1;
|
||||
|
||||
// Ensure page number is in range
|
||||
number = number > numberOfPages ? numberOfPages : number;
|
||||
number = number < 1 ? 1 : number;
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
function buildIds (order, number, size, recordCount) {
|
||||
let offset = size * (number - 1);
|
||||
|
||||
let start;
|
||||
let mapFunction;
|
||||
|
||||
if (order === 'asc') {
|
||||
start = 1 + offset;
|
||||
mapFunction = (_, i) => start + i;
|
||||
} else {
|
||||
start = recordCount - offset;
|
||||
mapFunction = (_, i) => start - i;
|
||||
}
|
||||
|
||||
// Ensure size is in range
|
||||
let end = offset + size;
|
||||
if (end > recordCount) {
|
||||
let diff = end - recordCount;
|
||||
size = size - diff;
|
||||
}
|
||||
|
||||
return Array.from({ length: size }, mapFunction);
|
||||
}
|
||||
|
||||
module.exports = function paged (recordCount, options = {}) {
|
||||
let { order, page } = options;
|
||||
order = order || 'desc';
|
||||
page = page || {};
|
||||
|
||||
let size = parseInt(page.size) || 25;
|
||||
let number = pageNumber(page.number, size, recordCount);
|
||||
|
||||
return buildIds(order, number, size, recordCount);
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
const tv4 = require('tv4');
|
||||
const validator = tv4.freshApi();
|
||||
|
||||
validator.addFormat({
|
||||
'date': function(value) {
|
||||
const dateRegexp = /^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/;
|
||||
return dateRegexp.test(value) ? null : 'A valid ISO 8601 full-date string is expected';
|
||||
},
|
||||
'time': function(value) {
|
||||
const timeRegexp = /^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(([Zz])|([+|-]([01][0-9]|2[0-3]):[0-5][0-9]))$/;
|
||||
return timeRegexp.test(value) ? null : 'A valid ISO 8601 full-time string is expected';
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = validator;
|
5
migrations/1519035571_registry.js
Normal file
5
migrations/1519035571_registry.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Registry = artifacts.require('./upgradeable/Registry.sol');
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Registry);
|
||||
};
|
15
migrations/1520798600_token.js
Normal file
15
migrations/1520798600_token.js
Normal file
@ -0,0 +1,15 @@
|
||||
var Registry = artifacts.require('./Registry.sol');
|
||||
var Token = artifacts.require('./Token.sol');
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Token).then(function(token) {
|
||||
console.log('Registry address: ', Registry.address);
|
||||
console.log('Token address: ', Token.address);
|
||||
Registry.deployed().then(function(registry) {
|
||||
registry.addVersion('Token', Token.address);
|
||||
registry.createProxy('Token', 1);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
13
migrations/1522427321_contributors.js
Normal file
13
migrations/1522427321_contributors.js
Normal file
@ -0,0 +1,13 @@
|
||||
var Registry = artifacts.require('./Registry.sol');
|
||||
var Contributors = artifacts.require('./Contributors.sol');
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Contributors).then(function(contributors) {
|
||||
console.log('Registry address: ', Registry.address);
|
||||
console.log('Contributors address: ', Contributors.address);
|
||||
Registry.deployed().then(function(registry) {
|
||||
registry.addVersion('Contributors', Contributors.address);
|
||||
registry.createProxy('Contributors', 1);
|
||||
});
|
||||
});
|
||||
};
|
13
migrations/1522430935_operator.js
Normal file
13
migrations/1522430935_operator.js
Normal file
@ -0,0 +1,13 @@
|
||||
var Registry = artifacts.require('./Registry.sol');
|
||||
var Operator = artifacts.require('./Operator.sol');
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Operator).then(function(operator) {
|
||||
console.log('Registry address: ', Registry.address);
|
||||
console.log('Operator address: ', Operator.address);
|
||||
Registry.deployed().then(function(registry) {
|
||||
registry.addVersion('Operator', Operator.address);
|
||||
registry.createProxy('Operator', 1);
|
||||
});
|
||||
});
|
||||
};
|
5
migrations/1_initial_migration.js
Normal file
5
migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Migrations = artifacts.require("./Migrations.sol");
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Migrations);
|
||||
};
|
39227
package-lock.json
generated
39227
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
78
package.json
78
package.json
@ -1,80 +1,38 @@
|
||||
{
|
||||
"name": "@kredits/contracts",
|
||||
"version": "7.5.0",
|
||||
"description": "Smart contracts and JavaScript API for Kredits",
|
||||
"name": "kredits-contracts",
|
||||
"version": "1.0.0",
|
||||
"description": "Ethereum contracts and npm wrapper for Kredits",
|
||||
"main": "./lib/kredits.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"wallet:create": "hardhat create-wallet",
|
||||
"devchain": "hardhat node --network hardhat",
|
||||
"deploy:dao": "hardhat run scripts/create-proxy.js",
|
||||
"postshrinkwrap": "node scripts/fix-package-lock.js &>/dev/null || true",
|
||||
"build": "npm run build:contracts && npm run build:json",
|
||||
"build:contracts": "hardhat compile --force",
|
||||
"build:json": "node ./scripts/build-json.js",
|
||||
"seeds": "hardhat run scripts/seeds.js",
|
||||
"fund": "hardhat fund",
|
||||
"bootstrap": "npm run build && npm run deploy:dao && npm run seeds",
|
||||
"repl": "hardhat console",
|
||||
"lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"",
|
||||
"lint:contract-tests": "eslint apps/*/test",
|
||||
"lint:wrapper": "eslint lib/",
|
||||
"test": "hardhat test",
|
||||
"setup-git-hooks": "sh scripts/git-hooks/install",
|
||||
"preversion": "npm test && npm run build",
|
||||
"version": "git add lib/abis"
|
||||
"build-json": "truffle compile && node ./scripts/build-json.js",
|
||||
"bootstrap": "truffle migrate --reset && npm run build-json && truffle exec scripts/seeds.js",
|
||||
"ganache": "ganache-cli -p 7545 -i 100 --db=./.ganache-db -m kredits",
|
||||
"dev": "truffle migrate && npm run build-json",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/67P/kredits-contracts.git"
|
||||
"url": "git+https://github.com/67P/truffle-kredits.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/67P/kredits-contracts/issues"
|
||||
"url": "https://github.com/67P/truffle-kredits/issues"
|
||||
},
|
||||
"homepage": "https://github.com/67P/kredits-contracts#readme",
|
||||
"homepage": "https://github.com/67P/truffle-kredits#readme",
|
||||
"devDependencies": {
|
||||
"@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||
"@openzeppelin/contracts-upgradeable": "^4.8.3",
|
||||
"@openzeppelin/hardhat-upgrades": "^1.10.0",
|
||||
"async-each-series": "^1.1.0",
|
||||
"chai": "^4.3.6",
|
||||
"cli-table": "^0.3.1",
|
||||
"colors": "^1.0.3",
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eth-provider": "^0.11.0",
|
||||
"ethereum-block-by-date": "^1.4.0",
|
||||
"ethereum-waffle": "^3.4.0",
|
||||
"hardhat": "^2.6.4",
|
||||
"hardhat-deploy": "^0.11.4",
|
||||
"hardhat-deploy-ethers": "^0.3.0-beta.10",
|
||||
"homedir": "^0.6.0",
|
||||
"mocha": "^10.0.0",
|
||||
"ganache-cli": "^6.0.3",
|
||||
"promptly": "^3.0.3",
|
||||
"solhint": "^3.3.7",
|
||||
"truffle-hdwallet-provider": "^1.0.17",
|
||||
"truffle-hdwallet-provider-privkey": "^0.3.0",
|
||||
"web3-providers-ws": "^1.7.3",
|
||||
"yargs": "^15.0.0"
|
||||
"truffle": "^4.1.3",
|
||||
"zeppelin-solidity": "^1.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kosmos/schemas": "^3.2.0",
|
||||
"ethers": "^5.4.7",
|
||||
"ipfs-http-client": "^56.0.3",
|
||||
"multihashes": "^4.0.3",
|
||||
"node-fetch": "^2.6.0",
|
||||
"tv4": "^1.3.0"
|
||||
},
|
||||
"keywords": [
|
||||
"kosmos",
|
||||
"kredits"
|
||||
]
|
||||
"ethers": "3.0.15",
|
||||
"ipfs-api": "^19.0.0",
|
||||
"rsvp": "^4.8.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
const promptly = require('promptly');
|
||||
const { inspect } = require('util');
|
||||
|
||||
const { ethers } = require("hardhat");
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
console.log(`Using Contributions at: ${kredits.Contribution.contract.address}`);
|
||||
|
||||
let contributor = await promptly.prompt('Contributor (address or id): ');
|
||||
let contributorId;
|
||||
let contributorAccount;
|
||||
if (contributor.length < 5) {
|
||||
contributorId = contributor;
|
||||
contributorAccount = await kredits.Contributor.contract.getContributorAddressById(contributor);
|
||||
} else {
|
||||
contributorAccount = contributor;
|
||||
contributorId = await kredits.Contributor.contract.getContributorIdByAddress(contributor);
|
||||
}
|
||||
|
||||
console.log(`Creating a contribution for contributor account ${contributorAccount} ID: ${contributorId}`);
|
||||
|
||||
[ dateNow, timeNow ] = (new Date()).toISOString().split('T');
|
||||
|
||||
let contributionAttributes = {
|
||||
contributorId,
|
||||
date: dateNow,
|
||||
time: timeNow,
|
||||
amount: await promptly.prompt('Amount: '),
|
||||
description: await promptly.prompt('Description: '),
|
||||
kind: await promptly.prompt('Kind: ', { default: 'dev' }),
|
||||
url: await promptly.prompt('URL: ', { default: '' })
|
||||
}
|
||||
|
||||
const contributorData = await kredits.Contributor.getById(contributorId);
|
||||
contributionAttributes.contributorIpfsHash = contributorData.ipfsHash;
|
||||
|
||||
console.log("\nAdding contribution:");
|
||||
console.log(contributionAttributes);
|
||||
|
||||
kredits.Contribution.add(contributionAttributes, { gasLimit: 300000 })
|
||||
.then(result => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Failed to create contribution');
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
@ -1,6 +1,8 @@
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
const promptly = require('promptly');
|
||||
const bs58 = require('bs58');
|
||||
|
||||
const { ethers } = require("hardhat");
|
||||
const ethers = require('ethers');
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
async function prompt(message, options) {
|
||||
@ -9,32 +11,40 @@ async function prompt(message, options) {
|
||||
}
|
||||
return await promptly.prompt(message, options);
|
||||
}
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
console.log(`Using contributors at: ${kredits.Contributor.contract.address}`);
|
||||
module.exports = function(callback) {
|
||||
Registry.deployed().then(async (registry) => {
|
||||
|
||||
let contributorAttributes = {
|
||||
account: await prompt('Contributor address: ', {}),
|
||||
name: await prompt('Name: '),
|
||||
kind: await prompt('Kind (default person): ', {default: 'person'}),
|
||||
url: await prompt('URL: '),
|
||||
github_username: await prompt('GitHub username: '),
|
||||
github_uid: parseInt(await prompt('GitHub UID: ')),
|
||||
wiki_username: await prompt('Wiki username: '),
|
||||
};
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await Kredits.setup(provider, provider.getSigner());
|
||||
|
||||
console.log("\nAdding contributor:");
|
||||
console.log(contributorAttributes);
|
||||
console.log(`Using contributors at: ${kredits.Contributor.contract.address}`);
|
||||
|
||||
let contributorAttributes = {
|
||||
account: await prompt('Contributor address: ', {}),
|
||||
name: await prompt('Name: '),
|
||||
isCore: await prompt('core? y/n') === 'y',
|
||||
kind: await prompt('Kind (default person): ', {default: 'person'}),
|
||||
url: await prompt('URL: '),
|
||||
github_username: await prompt('GitHub username: '),
|
||||
github_uid: await prompt('GitHub UID: '),
|
||||
wiki_username: await prompt('Wiki username: '),
|
||||
};
|
||||
|
||||
console.log("\nAdding contributor:");
|
||||
console.log(contributorAttributes);
|
||||
|
||||
kredits.Contributor.add(contributorAttributes, {gasLimit: 250000}).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create contributor');
|
||||
callback(error);
|
||||
});
|
||||
|
||||
kredits.Contributor.add(contributorAttributes, { gasLimit: 350000 }).then((result) => {
|
||||
console.log("\n\nResult:");
|
||||
console.log(result);
|
||||
}).catch((error) => {
|
||||
console.log('Failed to create contributor');
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
|
38
scripts/add-proposal.js
Normal file
38
scripts/add-proposal.js
Normal file
@ -0,0 +1,38 @@
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
const Operator = artifacts.require('./Operator.sol');
|
||||
const Contributors = artifacts.require('./Contributors.sol');
|
||||
const promptly = require('promptly');
|
||||
|
||||
const bs58 = require('bs58');
|
||||
|
||||
function getBytes32FromMultiash(multihash) {
|
||||
const decoded = bs58.decode(multihash);
|
||||
|
||||
return {
|
||||
digest: `0x${decoded.slice(2).toString('hex')}`,
|
||||
hashFunction: decoded[0],
|
||||
size: decoded[1],
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function(callback) {
|
||||
Registry.deployed().then(async (registry) => {
|
||||
var operatorAddress = await registry.getProxyFor('Operator');
|
||||
var contributorsAddress = await registry.getProxyFor('Contributors');
|
||||
|
||||
var operator = await Operator.at(operatorAddress);
|
||||
var contributors = await Contributors.at(contributorsAddress);
|
||||
|
||||
let recipientAddress = await promptly.prompt('Contributor address: ');
|
||||
let ipfsHash = await promptly.prompt('IPFS hash (blank for default): ', { default: 'QmQNA1hhVyL1Vm6HiRxXe9xmc6LUMBDyiNMVgsjThtyevs' });
|
||||
|
||||
let multihash = getBytes32FromMultiash(ipfsHash);
|
||||
|
||||
let contributorId = await contributors.getContributorIdByAddress(recipientAddress);
|
||||
|
||||
let result = await operator.addProposal(contributorId.toNumber(), 23, multihash.digest, multihash.hashFunction, multihash.size);
|
||||
console.log('Proposal added, tx: ', result.tx);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
@ -1,18 +1,33 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const contractsPath = path.join(__dirname, "..", "artifacts", "contracts");
|
||||
const libPath = path.join(__dirname, "..", "lib");
|
||||
const abisPath = path.join(libPath, "abis");
|
||||
const contractsPath = path.join(__dirname, '..', 'build', 'contracts');
|
||||
const libPath = path.join(__dirname, '..', 'lib');
|
||||
const abisPath = path.join(libPath, 'abis');
|
||||
const addressesPath = path.join(libPath, 'addresses');
|
||||
|
||||
const files = ["Contributor", "Contribution", "Token", "Reimbursement"];
|
||||
const files = [
|
||||
'Contributors',
|
||||
'Operator',
|
||||
'Registry',
|
||||
'Token'
|
||||
];
|
||||
|
||||
files.forEach((fileName) => {
|
||||
let file = require(`${contractsPath}/${fileName}.sol/${fileName}.json`);
|
||||
let file = require(`${contractsPath}/${fileName}.json`);
|
||||
let abiFile = path.join(abisPath, `${fileName}.json`);
|
||||
fs.writeFileSync(abiFile, JSON.stringify(file.abi));
|
||||
|
||||
if (fileName === 'Registry') {
|
||||
let addresseFile = path.join(addressesPath, `${fileName}.json`);
|
||||
let content = fs.readFileSync(addresseFile);
|
||||
let addresses = Object.keys(file.networks)
|
||||
.reduce((addresses, key) => {
|
||||
addresses[key] = file.networks[key].address;
|
||||
return addresses;
|
||||
}, JSON.parse(content));
|
||||
fs.writeFileSync(addresseFile, JSON.stringify(addresses));
|
||||
}
|
||||
});
|
||||
|
||||
console.log(
|
||||
"Don't forget to reaload the JSON files from your application; i.e. restart kredits-web"
|
||||
);
|
||||
console.log("Don't forget to reaload the JSON files from your application; i.e. restart kredits-web");
|
||||
|
56
scripts/cli.js
Normal file
56
scripts/cli.js
Normal file
@ -0,0 +1,56 @@
|
||||
const REPL = require('repl');
|
||||
const promptly = require('promptly');
|
||||
|
||||
const ethers = require('ethers');
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
module.exports = function(callback) {
|
||||
const Registry = artifacts.require('./Registry.sol');
|
||||
Registry.deployed().then(async (registry) => {
|
||||
let contractName = await promptly.prompt('Contract Name: ');
|
||||
let method = await promptly.prompt('Function: ');
|
||||
let argumentInput = await promptly.prompt('Arguments (comma separated): ', { default: '' });
|
||||
let args = [];
|
||||
if (argumentInput !== '') {
|
||||
args = argumentInput.split(',').map(a => a.trim());
|
||||
}
|
||||
|
||||
const networkId = parseInt(web3.version.network);
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
web3.currentProvider, { chainId: networkId }
|
||||
);
|
||||
const kredits = await Kredits.setup(provider, provider.getSigner());
|
||||
|
||||
const contract = kredits[contractName].contract;
|
||||
console.log(`Using ${contractName} at ${contract.address}`);
|
||||
console.log(`Calling ${method} with ${JSON.stringify(args)}`);
|
||||
|
||||
if (!contract[method]) {
|
||||
callback(new Error(`Method ${method} is not defined on ${contractName}`));
|
||||
return;
|
||||
}
|
||||
|
||||
contract[method](...args).then((result) => {
|
||||
console.log("\nResult:");
|
||||
console.log(result);
|
||||
|
||||
console.log("\nStartig a REPL. (type .exit to exit)");
|
||||
console.log(`defined variables: result, ${contractName}, kredis`);
|
||||
let r = REPL.start();
|
||||
r.context.result = result;
|
||||
r.context[contractName] = contract;
|
||||
r.context.kredits = kredits;
|
||||
|
||||
r.on('exit', () => {
|
||||
console.log('Bye');
|
||||
callback();
|
||||
})
|
||||
}).catch((error) => {
|
||||
console.log("Call failed. Probably the contract raised an error?\n");
|
||||
console.log("...");
|
||||
callback(error);
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
const { ethers, upgrades } = require("hardhat");
|
||||
const path = require("path");
|
||||
const fileInject = require("./helpers/file_inject.js");
|
||||
|
||||
function handleError(error) {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const network = await hre.ethers.provider.getNetwork();
|
||||
const networkId = network.chainId;
|
||||
console.log(`Deploying to network #${networkId}`);
|
||||
|
||||
const contractFactories = {};
|
||||
const contracts = {};
|
||||
|
||||
contractFactories.Contributor = await ethers.getContractFactory("Contributor");
|
||||
contractFactories.Contribution = await ethers.getContractFactory("Contribution");
|
||||
contractFactories.Token = await ethers.getContractFactory("Token");
|
||||
contractFactories.Reimbursement = await ethers.getContractFactory("Reimbursement");
|
||||
|
||||
async function deployContractProxy (contractName, params=[]) {
|
||||
let contract = await upgrades.deployProxy(contractFactories[contractName], params)
|
||||
.catch(handleError);
|
||||
|
||||
contracts[contractName] = contract;
|
||||
|
||||
await contract.deployed().then(() => {
|
||||
console.log(`${contractName} deployed to:`, contract.address);
|
||||
console.log("...waiting for 1 confirmation");
|
||||
}).catch(handleError);
|
||||
|
||||
await contract.deployTransaction.wait().catch(handleError);
|
||||
}
|
||||
|
||||
const blocksVetoPeriod = 40320; // 7 days; 15 seconds block time
|
||||
|
||||
await deployContractProxy('Contributor', [ '0x0000000000000000000000000000000000000000' ] );
|
||||
await deployContractProxy('Contribution', [ blocksVetoPeriod ]);
|
||||
await deployContractProxy('Token');
|
||||
await deployContractProxy('Reimbursement');
|
||||
|
||||
console.log('Calling Contributor#setTokenContract')
|
||||
await contracts.Contributor.functions
|
||||
.setTokenContract(contracts.Token.address)
|
||||
.then(res => {
|
||||
console.log(`...transaction published: ${res.hash}`);
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
console.log('Calling Contributor#setContributionContract')
|
||||
await contracts.Contributor.functions
|
||||
.setContributionContract(contracts.Contribution.address)
|
||||
.then(res => {
|
||||
console.log(`...transaction published: ${res.hash}`);
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
console.log('Calling Contribution#setContributorContract')
|
||||
await contracts.Contribution.functions
|
||||
.setContributorContract(contracts.Contributor.address)
|
||||
.then(res => {
|
||||
console.log(`...transaction published: ${res.hash}`);
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
console.log('Calling Token#setContributorContract')
|
||||
await contracts.Token.functions
|
||||
.setContributorContract(contracts.Contributor.address)
|
||||
.then(res => {
|
||||
console.log(`...transaction published: ${res.hash}`);
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
console.log('Calling Reimbursement#setContributorContract')
|
||||
await contracts.Reimbursement.functions
|
||||
.setContributorContract(contracts.Contributor.address)
|
||||
.then(res => {
|
||||
console.log(`...transaction published: ${res.hash}`);
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
const addresses = {
|
||||
Contributor: contracts.Contributor.address,
|
||||
Contribution: contracts.Contribution.address,
|
||||
Token: contracts.Token.address,
|
||||
Reimbursement: contracts.Reimbursement.address,
|
||||
};
|
||||
|
||||
console.log("Writing addresses.json");
|
||||
const libPath = path.join(__dirname, "..", "lib");
|
||||
fileInject(path.join(libPath, "addresses.json"), networkId, addresses);
|
||||
console.log("DONE!");
|
||||
}
|
||||
|
||||
main();
|
@ -1,43 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const Kredits = require('../../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
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 hre.ethers.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();
|
@ -1,38 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const Kredits = require('../../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
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();
|
@ -1,44 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const Kredits = require('../../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
|
||||
|
||||
const count = await kredits.Reimbursement.count;
|
||||
const currentBlockHeight = await hre.ethers.provider.getBlockNumber();
|
||||
|
||||
const backup = {};
|
||||
const promises = [];
|
||||
for (let i = 1; i <= count; i++) {
|
||||
promises.push(new Promise((resolve, reject) => {
|
||||
setTimeout(async () => {
|
||||
console.log(`Loading reimbursement #${i}`);
|
||||
await kredits.Reimbursement.contract.get(i).then(contractData => {
|
||||
backup[i] = {
|
||||
recipientId: contractData.recipientId,
|
||||
amount: contractData.amount,
|
||||
token: contractData.token,
|
||||
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/reimbursements.json", JSON.stringify(backup, null, 2));
|
||||
console.log("Exported");
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
@ -1,22 +0,0 @@
|
||||
const promptly = require('promptly');
|
||||
const EthDater = require('ethereum-block-by-date');
|
||||
|
||||
const { ethers } = require("hardhat");
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
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}
|
||||
`);
|
||||
|
||||
}
|
||||
|
||||
main();
|
@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
cp -f scripts/git-hooks/pre-commit .git/hooks
|
@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run appropriate linter against staged files
|
||||
#
|
||||
if [ $(git diff --name-only --cached lib/ | wc -l) != 0 ]; then
|
||||
./node_modules/.bin/eslint lib/
|
||||
if [ $? != 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# TODO master not linted yet, uncomment this when ready
|
||||
# if [ $(git diff --name-only --cached contracts/ | wc -l) != 0 ]; then
|
||||
# solhint contracts/**/*.sol && apps/*/contracts/**/*.sol
|
||||
# if [ $? != 0 ]; then
|
||||
# exit 1
|
||||
# fi
|
||||
# fi
|
@ -1,8 +0,0 @@
|
||||
// help, give me a better name
|
||||
|
||||
const fs = require('fs');
|
||||
module.exports = function (file, networkId, data) {
|
||||
let content = JSON.parse(fs.readFileSync(file));
|
||||
content[networkId] = data;
|
||||
fs.writeFileSync(file, JSON.stringify(content, null, 2));
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const Kredits = require('../../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
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;
|
||||
console.log(`Currently ${count} entries`);
|
||||
|
||||
try {
|
||||
const data = fs.readFileSync("./data/contributions.json");
|
||||
const contributions = JSON.parse(data);
|
||||
const ids = Object.keys(contributions)
|
||||
.map(k => parseInt(k))
|
||||
.sort(function(a, b) { return a - b });
|
||||
|
||||
const currentBlockHeight = await kredits.provider.getBlockNumber();
|
||||
const confirmationPeriod = 40320 // blocks
|
||||
const unconfirmedHeight = currentBlockHeight + confirmationPeriod;
|
||||
|
||||
const startId = parseInt(process.env.START_AT || "0");
|
||||
for (const contributionId of ids) {
|
||||
if (contributionId < startId) {
|
||||
continue;
|
||||
}
|
||||
const c = contributions[contributionId.toString()];
|
||||
|
||||
const confirmedAtBlock = c.confirmed ? currentBlockHeight : unconfirmedHeight;
|
||||
|
||||
const result = await kredits.Contribution.contract.add(
|
||||
c.amount, c.contributorId,
|
||||
c.hashDigest, c.hashFunction, c.hashSize,
|
||||
confirmedAtBlock, c.vetoed
|
||||
);
|
||||
console.log(`Adding contribution #${contributionId}: ${result.hash}`);
|
||||
await result.wait();
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@ -1,34 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const Kredits = require('../../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
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;
|
||||
console.log(`Currently ${count} entries`);
|
||||
try {
|
||||
const data = fs.readFileSync("./data/contributors.json");
|
||||
const contributors = JSON.parse(data);
|
||||
const ids = Object.keys(contributors)
|
||||
.map(k => parseInt(k))
|
||||
.sort(function(a, b){return a-b});
|
||||
|
||||
for (const contributorId of ids) {
|
||||
const contributor = contributors[contributorId.toString()];
|
||||
const result = await kredits.Contributor.contract.addContributor(
|
||||
contributor.account,
|
||||
contributor.hashDigest,
|
||||
contributor.hashFunction,
|
||||
contributor.hashSize,
|
||||
);
|
||||
console.log(`Adding contributor #${contributorId}: ${result.hash}`);
|
||||
await result.wait();
|
||||
};
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@ -1,36 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const Kredits = require('../../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
|
||||
const count = await kredits.Reimbursement.count;
|
||||
console.log(`Currently ${count} entries`);
|
||||
try {
|
||||
const data = fs.readFileSync("./data/reimbursements.json");
|
||||
const reimbursements = JSON.parse(data);
|
||||
const ids = Object.keys(reimbursements)
|
||||
.map(k => parseInt(k))
|
||||
.sort(function(a, b) { return a - b });
|
||||
|
||||
for (const reimbursementId of ids) {
|
||||
const reimbursement = reimbursements[reimbursementId.toString()];
|
||||
const result = await kredits.Reimbursement.contract.add(
|
||||
reimbursement.amount,
|
||||
reimbursement.token,
|
||||
reimbursement.recipientId,
|
||||
reimbursement.hashDigest,
|
||||
reimbursement.hashFunction,
|
||||
reimbursement.hashSize,
|
||||
);
|
||||
console.log(`Adding reimbursement #${reimbursementId}: ${result.hash}`);
|
||||
await result.wait();
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@ -1,68 +0,0 @@
|
||||
const promptly = require('promptly');
|
||||
const Table = require('cli-table');
|
||||
|
||||
const { ethers } = require("hardhat");
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
||||
|
||||
const table = new Table({
|
||||
head: ['ID', 'Name', 'Kredits']
|
||||
})
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
main();
|
@ -1,48 +0,0 @@
|
||||
const promptly = require('promptly');
|
||||
const Table = require('cli-table');
|
||||
|
||||
const { ethers } = require("hardhat");
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
let kredits;
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||
await kredits.init();
|
||||
|
||||
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
||||
|
||||
const table = new Table({
|
||||
head: ['ID', 'Contributor ID', 'Description', 'Amount', 'Confirmed?', 'Vetoed?', 'IPFS']
|
||||
})
|
||||
|
||||
try {
|
||||
let blockNumber = await kredits.provider.getBlockNumber();
|
||||
let contributions = await kredits.Contribution.all({page: {size: 1000}});
|
||||
|
||||
let kreditsSum = 0;
|
||||
console.log(`Current block number: ${blockNumber}`);
|
||||
contributions.forEach((c) => {
|
||||
const confirmed = c.confirmedAtBlock <= blockNumber;
|
||||
|
||||
table.push([
|
||||
c.id.toString(),
|
||||
c.contributorId,
|
||||
`${c.description}`,
|
||||
c.amount.toString(),
|
||||
`${confirmed} (${c.confirmedAtBlock})`,
|
||||
c.vetoed,
|
||||
c.ipfsHash
|
||||
])
|
||||
});
|
||||
|
||||
console.log(table.toString());
|
||||
|
||||
let totalKreditsEarnedUnConfirmed = await kredits.Contribution.contract.totalKreditsEarned(false);
|
||||
let totalKreditsEarnedConfirmed = await kredits.Contribution.contract.totalKreditsEarned(true);
|
||||
console.log(`Total Kredits: ${totalKreditsEarnedConfirmed} (confirmed) | ${totalKreditsEarnedUnConfirmed} (including unconfirmed)`);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@ -1,34 +0,0 @@
|
||||
const Table = require('cli-table');
|
||||
const Kredits = require('../lib/kredits');
|
||||
|
||||
async function main() {
|
||||
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.Contributors.count;
|
||||
console.log(`Currently ${count} entries`);
|
||||
|
||||
const table = new Table({
|
||||
head: ['ID', 'Account', 'Name', 'Core?', 'Balance', 'Kredits earned', 'Contributions count', 'IPFS']
|
||||
})
|
||||
|
||||
const contributors = await kredits.Contributor.all()
|
||||
|
||||
contributors.forEach((c) => {
|
||||
table.push([
|
||||
c.id.toString(),
|
||||
c.account,
|
||||
`${c.name}`,
|
||||
c.isCore,
|
||||
c.balanceInt.toString(),
|
||||
c.totalKreditsEarned.toString(),
|
||||
c.contributionsCount.toString(),
|
||||
c.ipfsHash
|
||||
])
|
||||
});
|
||||
|
||||
console.log(table.toString());
|
||||
}
|
||||
|
||||
main();
|
@ -1,49 +0,0 @@
|
||||
const Table = require("cli-table");
|
||||
const Kredits = require("../lib/kredits");
|
||||
|
||||
async function main() {
|
||||
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner());
|
||||
await kredits.init();
|
||||
|
||||
console.log(
|
||||
`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`
|
||||
);
|
||||
|
||||
const table = new Table({
|
||||
head: ["ID", "Amount", "Token", "recipientId", "Confirmed?", "Vetoed?", "IPFS", "Expenses"],
|
||||
});
|
||||
|
||||
const blockNumber = await kredits.provider.getBlockNumber();
|
||||
const reimbursements = await kredits.Reimbursement.all();
|
||||
|
||||
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());
|
||||
|
||||
const totalAmountUnconfirmed = await kredits.Reimbursement.contract.totalAmount(
|
||||
false
|
||||
);
|
||||
const totalAmountConfirmed = await kredits.Reimbursement.contract.totalAmount(
|
||||
true
|
||||
);
|
||||
console.log(
|
||||
`Total: ${totalAmountConfirmed} (confirmed) | ${totalAmountUnconfirmed} (including unconfirmed)`
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user