Compare commits
92 Commits
v7.0.0-bet
...
master
Author | SHA1 | Date | |
---|---|---|---|
0f872c8f1e | |||
484a9ffcaf | |||
6e9f565587 | |||
f4634fe692 | |||
68968e1fbd | |||
|
a2ebc609ea | ||
beca6afc4f | |||
|
90223dd22e | ||
ea3a591a0c | |||
|
e0f20d363c | ||
|
5e33381f2a | ||
1f91a13f06 | |||
7d2a492fc9 | |||
|
30490ce393 | ||
|
f0a71ca8f1 | ||
|
117918e66f | ||
d0d456b357 | |||
cda84fa2ce | |||
97e2db93be | |||
17c582f6df | |||
|
914d4d9585 | ||
|
0deeba14fc | ||
|
c61632d949 | ||
|
0b593ec795 | ||
|
401c528e95 | ||
ed2033980c | |||
17c7a36cb4 | |||
|
1cb777aa44 | ||
|
21522a86a0 | ||
|
269a2cf87a | ||
3112ef0e95 | |||
|
d63f7ca743 | ||
f10af14fae | |||
|
2692613b9a | ||
|
b49d1130a9 | ||
|
657cdc8afa | ||
|
ae9aa7aaaf | ||
|
708515ba4b | ||
7eceea5d57 | |||
|
089ffd42fe | ||
|
43d9bc0a07 | ||
|
6113e456af | ||
8ef6fc06ce | |||
|
093273f15b | ||
|
1dc54eccea | ||
|
bb662e377c | ||
|
d6bbc441f8 | ||
|
46090b3740 | ||
|
828f831c52 | ||
|
500180c6da | ||
|
b63c68cd1c | ||
c875e775b6 | |||
|
6e0ec8741e | ||
|
a1a68092f6 | ||
c6168e59e8 | |||
e810424163 | |||
f71ff4ce9a | |||
1c097f37a6 | |||
|
d3fb1010d5 | ||
f390b5dff5 | |||
|
1e4f7be5cf | ||
|
258c1cc755 | ||
|
f29054bc0b | ||
fd012d5359 | |||
|
5da710cc14 | ||
|
e99184b83f | ||
|
2b3fd1241d | ||
|
dc2c8130f3 | ||
|
796ccebd84 | ||
|
d72413eb66 | ||
|
9dd9d298cc | ||
|
67add71a22 | ||
|
cd07313679 | ||
|
90172071fa | ||
|
de1574155c | ||
|
0fc4eed09a | ||
|
55877897be | ||
|
59bda71f97 | ||
|
1521e272f9 | ||
|
990e2a9649 | ||
|
883f9adb96 | ||
|
550bc2b9f4 | ||
2fca436fa8 | |||
2b05be1897 | |||
|
46b1bbfbf2 | ||
|
98348dc544 | ||
|
fd93993a1b | ||
|
0d6702fd2b | ||
|
51e50e7c46 | ||
793642c238 | |||
|
c55593d46f | ||
|
2b314556ad |
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@ -0,0 +1,6 @@
|
||||
.openzeppelin
|
||||
artifacts
|
||||
cache
|
||||
deployments
|
||||
gitno
|
||||
node_modules
|
40
.drone.yml
Normal file
40
.drone.yml
Normal file
@ -0,0 +1,40 @@
|
||||
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 +1,2 @@
|
||||
/scripts/
|
||||
/test/
|
||||
|
14
.gitea/release-drafter.yml
Normal file
14
.gitea/release-drafter.yml
Normal file
@ -0,0 +1,14 @@
|
||||
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
|
11
.gitea/workflows/release_drafter.yml
Normal file
11
.gitea/workflows/release_drafter.yml
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -5,6 +5,9 @@ node_modules
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
|
||||
data
|
||||
|
||||
cache
|
||||
artifacts
|
||||
.openzeppelin
|
||||
.openzeppelin/unknown-1337.json
|
||||
.env
|
||||
|
0
.openzeppelin/.keep
Normal file
0
.openzeppelin/.keep
Normal file
937
.openzeppelin/unknown-31.json
Normal file
937
.openzeppelin/unknown-31.json
Normal file
@ -0,0 +1,937 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,6 @@
|
||||
"solhint:recommended"
|
||||
],
|
||||
"rules": {
|
||||
"indent": "2"
|
||||
"max-line-length": "warn"
|
||||
}
|
||||
}
|
||||
|
38
.travis.yml
38
.travis.yml
@ -1,38 +0,0 @@
|
||||
---
|
||||
language: node_js
|
||||
node_js:
|
||||
- "12"
|
||||
|
||||
sudo: false
|
||||
dist: xenial
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- apps/contribution/node_modules
|
||||
- apps/contributor/node_modules
|
||||
- apps/proposal/node_modules
|
||||
- apps/token/node_modules
|
||||
- apps/vault/node_modules
|
||||
|
||||
install:
|
||||
- npm install -g @aragon/cli
|
||||
- npm install -g truffle
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- npm run devchain &
|
||||
- sleep 10
|
||||
|
||||
script:
|
||||
- npm run lint:wrapper
|
||||
- npm run lint:contract-tests
|
||||
# FIXME Fix tests
|
||||
# - npm run test:token
|
||||
# - npm run test:contributor
|
||||
# - npm run test:contribution
|
||||
# - npm run test:proposal
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
# 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
|
32
README.md
32
README.md
@ -1,4 +1,5 @@
|
||||
[](https://www.npmjs.com/package/kredits-contracts)
|
||||
[](https://www.npmjs.com/package/@kredits/contracts)
|
||||
[](https://drone.kosmos.org/kredits/contracts)
|
||||
|
||||
# Kredits Contracts
|
||||
|
||||
@ -26,27 +27,27 @@ To run a local development chain run:
|
||||
|
||||
### Bootstrap
|
||||
|
||||
1. Run an Ethereum node and ipfs
|
||||
1. Run an EVM node and ipfs
|
||||
|
||||
$ npm run devchain
|
||||
$ ipfs daemon
|
||||
|
||||
2. Compile contracts and build ABIs
|
||||
2. Compile contracts and build ABIs
|
||||
|
||||
(compiled artifacts will be in `/artifacts`)
|
||||
$ npm run build
|
||||
|
||||
3. Deploy new upgradable contract proxies
|
||||
3. Deploy new upgradable contract proxies
|
||||
|
||||
$ npm run deploy:dao
|
||||
|
||||
4. Execute seeds to create demo contributors, contributions, etc. (optional)
|
||||
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
|
||||
5. Show contract addresses
|
||||
|
||||
$ cat lib/addresses.json
|
||||
|
||||
@ -56,6 +57,16 @@ 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
|
||||
@ -145,12 +156,3 @@ To run the console on one of the non localhost networks you can also just pass
|
||||
on the --network argument.
|
||||
|
||||
$ hardhat console --network rsk
|
||||
|
||||
|
||||
## 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)
|
||||
|
@ -15,7 +15,7 @@ const contractCalls = [
|
||||
name: 'raucao',
|
||||
kind: 'person',
|
||||
url: '',
|
||||
github_username: 'skddc',
|
||||
github_username: 'raucao',
|
||||
github_uid: 842,
|
||||
gitea_username: 'raucao',
|
||||
wiki_username: 'Basti',
|
||||
@ -31,18 +31,55 @@ const contractCalls = [
|
||||
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: '' }, { gasLimit: 350000 }]],
|
||||
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-web] Reviewed stuff', url: '' }, { gasLimit: 350000 }]],
|
||||
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-contracts] Add tests', url: '' }, { gasLimit: 350000 }]],
|
||||
['Contribution', 'add', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-contracts] Introduce contribution token', url: '' }, { gasLimit: 350000 }]],
|
||||
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 5000, kind: 'dev', description: '[67P/kredits-web] Expense UI, first draft', url: '' }, { gasLimit: 350000 }]],
|
||||
['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 }]],
|
||||
|
||||
['Reimbursement', 'add', [{amount: 1116000, recipientId: 1, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
|
||||
{ title: 'Server rent', description: 'Dedicated server: andromeda.kosmos.org, April 2020', amount: 61, currency: 'EUR', date: '2020-05-28' },
|
||||
{ title: 'Server rent', description: 'Dedicated server: centaurus.kosmos.org, April 2020', amount: 32, currency: 'EUR', date: '2020-05-28' }
|
||||
]}, { gasLimit: 300000 }]],
|
||||
['Reimbursement', 'add', [{amount: 166800, recipientId: 2, token: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', expenses: [
|
||||
{ title: 'Domain kosmos.chat', description: 'Yearly registration fee for domain kosmos.chat', amount: 13.90, currency: 'EUR', date: '2020-05-30' }
|
||||
['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 }]],
|
||||
];
|
||||
|
||||
|
@ -2,10 +2,6 @@ pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
interface IToken {
|
||||
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) external;
|
||||
}
|
||||
|
||||
interface ContributorInterface {
|
||||
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||
@ -16,12 +12,10 @@ interface ContributorInterface {
|
||||
|
||||
contract Contribution is Initializable {
|
||||
ContributorInterface public contributorContract;
|
||||
IToken public tokenContract;
|
||||
|
||||
struct ContributionData {
|
||||
uint32 contributorId;
|
||||
uint32 amount;
|
||||
bool claimed;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
@ -42,10 +36,16 @@ contract Contribution is Initializable {
|
||||
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 ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
|
||||
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
||||
|
||||
modifier onlyCore {
|
||||
@ -53,13 +53,19 @@ contract Contribution is Initializable {
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyDeployer {
|
||||
require(msg.sender == deployer, "Deployer only");
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(uint32 blocksToWait_) public initializer {
|
||||
deployer = msg.sender;
|
||||
migrationDone = false;
|
||||
blocksToWait = blocksToWait_;
|
||||
}
|
||||
|
||||
function setTokenContract(address token) public {
|
||||
require(address(tokenContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||
tokenContract = IToken(token);
|
||||
function finishMigration() public onlyDeployer {
|
||||
migrationDone = true;
|
||||
}
|
||||
|
||||
function setContributorContract(address contributor) public {
|
||||
@ -89,13 +95,13 @@ contract Contribution is Initializable {
|
||||
|
||||
// Balance is amount of ERC271 tokens, not amount of kredits
|
||||
function balanceOf(address owner) public view returns (uint256) {
|
||||
require(owner != address(0));
|
||||
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));
|
||||
require(exists(contributionId), "Contribution does not exist");
|
||||
uint32 contributorId = contributions[contributionId].contributorId;
|
||||
return getContributorAddressById(contributorId);
|
||||
}
|
||||
@ -133,14 +139,13 @@ contract Contribution is Initializable {
|
||||
}
|
||||
}
|
||||
|
||||
function getContribution(uint32 contributionId) public view returns (uint32 id, uint32 contributorId, uint32 amount, bool claimed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
|
||||
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.claimed,
|
||||
c.hashDigest,
|
||||
c.hashFunction,
|
||||
c.hashSize,
|
||||
@ -150,24 +155,27 @@ contract Contribution is Initializable {
|
||||
);
|
||||
}
|
||||
|
||||
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
||||
//require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint32[](0)), 'nope');
|
||||
require(balanceOf(msg.sender) > 0 || contributorContract.addressIsCore(msg.sender), 'must have kredits or core');
|
||||
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.claimed = false;
|
||||
c.contributorId = contributorId;
|
||||
c.hashDigest = hashDigest;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
if (contributionId < 10) {
|
||||
c.confirmedAtBlock = block.number;
|
||||
|
||||
if (confirmedAtBlock > 0) {
|
||||
c.confirmedAtBlock = confirmedAtBlock;
|
||||
} else {
|
||||
c.confirmedAtBlock = block.number + 1 + blocksToWait;
|
||||
}
|
||||
|
||||
if (vetoed) { c.vetoed = true; }
|
||||
|
||||
contributionsCount++;
|
||||
|
||||
contributionOwner[contributionId] = contributorId;
|
||||
@ -177,32 +185,15 @@ contract Contribution is Initializable {
|
||||
}
|
||||
|
||||
function veto(uint32 contributionId) public onlyCore {
|
||||
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
require(c.exists, 'NOT_FOUND');
|
||||
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||
require(block.number < c.confirmedAtBlock, 'VETO_PERIOD_ENDED');
|
||||
require(c.exists, "NOT_FOUND");
|
||||
require(block.number < c.confirmedAtBlock, "VETO_PERIOD_ENDED");
|
||||
c.vetoed = true;
|
||||
|
||||
emit ContributionVetoed(contributionId, msg.sender);
|
||||
}
|
||||
|
||||
function claim(uint32 contributionId) public {
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
require(c.exists, 'NOT_FOUND');
|
||||
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||
require(!c.vetoed, 'VETOED');
|
||||
require(block.number >= c.confirmedAtBlock, 'NOT_CLAIMABLE');
|
||||
|
||||
c.claimed = true;
|
||||
address contributorAccount = getContributorAddressById(c.contributorId);
|
||||
uint256 amount = uint256(c.amount);
|
||||
tokenContract.mintFor(contributorAccount, amount, contributionId);
|
||||
emit ContributionClaimed(contributionId, c.contributorId, c.amount);
|
||||
}
|
||||
|
||||
function exists(uint32 contributionId) public view returns (bool) {
|
||||
return contributions[contributionId].exists;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
interface ITokenBalance {
|
||||
interface IToken {
|
||||
function mintFor(address contributorAccount, uint256 amount) external;
|
||||
function balanceOf(address contributorAccount) external view returns (uint256);
|
||||
}
|
||||
interface IContributionBalance {
|
||||
@ -11,9 +12,9 @@ interface IContributionBalance {
|
||||
}
|
||||
|
||||
contract Contributor is Initializable {
|
||||
address deployer;
|
||||
address public deployer;
|
||||
IContributionBalance public contributionContract;
|
||||
ITokenBalance public tokenContract;
|
||||
IToken public tokenContract;
|
||||
|
||||
struct Contributor {
|
||||
address account;
|
||||
@ -21,12 +22,15 @@ contract Contributor is Initializable {
|
||||
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);
|
||||
@ -36,8 +40,18 @@ contract Contributor is Initializable {
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize() public initializer {
|
||||
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 {
|
||||
@ -47,7 +61,7 @@ contract Contributor is Initializable {
|
||||
|
||||
function setTokenContract(address token) public onlyCore {
|
||||
require(address(tokenContract) == address(0) || addressIsCore(msg.sender), "Core only");
|
||||
tokenContract = ITokenBalance(token);
|
||||
tokenContract = IToken(token);
|
||||
}
|
||||
|
||||
function coreContributorsCount() public view returns (uint32) {
|
||||
@ -77,11 +91,12 @@ contract Contributor is Initializable {
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
|
||||
ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
|
||||
emit ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
|
||||
}
|
||||
|
||||
function addContributor(address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public onlyCore {
|
||||
require(!addressExists(account));
|
||||
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];
|
||||
@ -90,23 +105,24 @@ contract Contributor is Initializable {
|
||||
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) view public returns (bool) {
|
||||
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) view public returns (bool) {
|
||||
function exists(uint32 id) public view returns (bool) {
|
||||
return contributors[id].exists;
|
||||
}
|
||||
|
||||
function addressIsCore(address account) view public returns (bool) {
|
||||
function addressIsCore(address account) public view returns (bool) {
|
||||
// the deployer is always core
|
||||
if(account == deployer) {
|
||||
return true;
|
||||
@ -115,15 +131,15 @@ contract Contributor is Initializable {
|
||||
return isCoreTeam(id);
|
||||
}
|
||||
|
||||
function addressExists(address account) view public returns (bool) {
|
||||
function addressExists(address account) public view returns (bool) {
|
||||
return getContributorByAddress(account).exists;
|
||||
}
|
||||
|
||||
function getContributorIdByAddress(address account) view public returns (uint32) {
|
||||
function getContributorIdByAddress(address account) public view returns (uint32) {
|
||||
return contributorIds[account];
|
||||
}
|
||||
|
||||
function getContributorAddressById(uint32 id) view public returns (address) {
|
||||
function getContributorAddressById(uint32 id) public view returns (address) {
|
||||
return contributors[id].account;
|
||||
}
|
||||
|
||||
@ -132,7 +148,7 @@ contract Contributor is Initializable {
|
||||
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 ) {
|
||||
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;
|
||||
@ -144,6 +160,19 @@ contract Contributor is Initializable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ contract Reimbursement is Initializable {
|
||||
struct ReimbursementData {
|
||||
uint32 recipientId;
|
||||
uint256 amount;
|
||||
// TODO remove token entirely
|
||||
address token;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
@ -30,18 +31,35 @@ contract Reimbursement is Initializable {
|
||||
|
||||
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);
|
||||
|
||||
function initialize() public initializer {
|
||||
blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||
}
|
||||
|
||||
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);
|
||||
@ -81,7 +99,8 @@ contract Reimbursement is Initializable {
|
||||
);
|
||||
}
|
||||
|
||||
function add(uint256 amount, address token, uint32 recipientId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public onlyCore {
|
||||
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;
|
||||
@ -91,7 +110,14 @@ contract Reimbursement is Initializable {
|
||||
r.hashDigest = hashDigest;
|
||||
r.hashFunction = hashFunction;
|
||||
r.hashSize = hashSize;
|
||||
r.confirmedAtBlock = block.number + blocksToWait;
|
||||
|
||||
if (confirmedAtBlock > 0) {
|
||||
r.confirmedAtBlock = confirmedAtBlock;
|
||||
} else {
|
||||
r.confirmedAtBlock = block.number + 1 + blocksToWait;
|
||||
}
|
||||
|
||||
if (vetoed) { r.vetoed = true; }
|
||||
|
||||
reimbursementsCount++;
|
||||
|
||||
@ -100,8 +126,8 @@ contract Reimbursement is Initializable {
|
||||
|
||||
function veto(uint32 reimbursementId) public onlyCore {
|
||||
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||
require(r.exists, 'NOT_FOUND');
|
||||
require(block.number < r.confirmedAtBlock, 'VETO_PERIOD_ENDED');
|
||||
require(r.exists, "NOT_FOUND");
|
||||
require(block.number < r.confirmedAtBlock, "VETO_PERIOD_ENDED");
|
||||
r.vetoed = true;
|
||||
|
||||
emit ReimbursementVetoed(reimbursementId, msg.sender);
|
||||
|
@ -7,38 +7,35 @@ 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 Token is Initializable, ERC20Upgradeable {
|
||||
ContributorInterface public contributorContract;
|
||||
using SafeMathUpgradeable for uint256;
|
||||
|
||||
address public contributionContract;
|
||||
address public contributorContractAddress;
|
||||
|
||||
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
||||
event KreditsMinted(address indexed recipient, uint256 amount);
|
||||
|
||||
function initialize() public virtual initializer {
|
||||
__ERC20_init('Kredits', 'KS');
|
||||
__ERC20_init("Kredits", "KS");
|
||||
}
|
||||
|
||||
function setContributionContract(address contribution) public {
|
||||
require(address(contributionContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||
contributionContract = contribution;
|
||||
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, uint32 contributionId) public {
|
||||
require(contributionContract == msg.sender, "Only Contribution");
|
||||
function mintFor(address contributorAccount, uint256 amount) public {
|
||||
require(contributorContractAddress == msg.sender, "Only Contributor");
|
||||
require(amount > 0, "INVALID_AMOUNT");
|
||||
|
||||
uint256 amountInWei = amount.mul(1 ether);
|
||||
_mint(contributorAccount, amountInWei);
|
||||
emit LogMint(contributorAccount, amount, contributionId);
|
||||
_mint(contributorAccount, amount);
|
||||
emit KreditsMinted(contributorAccount, amount);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
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");
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
[{"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"}],"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":[{"internalType":"uint32","name":"reimbursementId","type":"uint32"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":[{"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"}]
|
||||
[{"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":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"LogMint","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":"contributionContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributorContract","outputs":[{"internalType":"contract ContributorInterface","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"},{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"mintFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contribution","type":"address"}],"name":"setContributionContract","outputs":[],"stateMutability":"nonpayable","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"}]
|
||||
[{"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"}]
|
@ -1,8 +1,14 @@
|
||||
{
|
||||
"31": {
|
||||
"Contributor": "0x95DC31665D193E377f54b70C535fcDb205525291",
|
||||
"Contribution": "0x049bA8E70FEbFfd6d03C71211bDA37B4ff064115",
|
||||
"Token": "0x7ab26A0f00eF0D6e05e5BDE047505a4eD53aF809",
|
||||
"Reimbursement": "0x99EC72b34295b62f4bC1527Da461262c615a0b2c"
|
||||
},
|
||||
"1337": {
|
||||
"Contributor": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
|
||||
"Contribution": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9",
|
||||
"Token": "0x0165878A594ca255338adfa4d48449f69242Eb8F",
|
||||
"Reimbursement": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6"
|
||||
"Contributor": "0xCc66f9A3cA2670972938FAD91d0865c4a62DFB25",
|
||||
"Contribution": "0x8999CaBc43E28202c5A2257f2a95A45b1F8A62BD",
|
||||
"Token": "0xe082678eCF749982e33Ea6839852a8cd989aEDE2",
|
||||
"Reimbursement": "0x984f797d26d3da2E9b9f8Ae4eeFEACC60fCAA90C"
|
||||
}
|
||||
}
|
@ -41,6 +41,8 @@ class Contribution extends Record {
|
||||
|
||||
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); }
|
||||
@ -56,6 +58,8 @@ class Contribution extends Record {
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
confirmedAtBlock,
|
||||
vetoed,
|
||||
];
|
||||
|
||||
return this.contract.add(...contribution, callOptions);
|
||||
|
@ -52,6 +52,7 @@ class Contributor extends Record {
|
||||
|
||||
const jsonStr = contributor.serialize();
|
||||
|
||||
// console.log('Adding IPFS doc for', contributorAttr.account);
|
||||
return this.ipfs
|
||||
.add(jsonStr)
|
||||
.then((ipfsHashAttr) => {
|
||||
@ -62,7 +63,11 @@ class Contributor extends Record {
|
||||
ipfsHashAttr.hashSize,
|
||||
];
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -16,13 +16,15 @@ class Reimbursement extends Record {
|
||||
}
|
||||
|
||||
getData (id) {
|
||||
return this.contract.getReimbursement(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;
|
||||
|
||||
@ -56,6 +58,8 @@ class Reimbursement extends Record {
|
||||
ipfsHashAttr.hashDigest,
|
||||
ipfsHashAttr.hashFunction,
|
||||
ipfsHashAttr.hashSize,
|
||||
confirmedAtBlock,
|
||||
vetoed,
|
||||
];
|
||||
|
||||
return this.contract.add(...reimbursement, callOptions);
|
||||
|
@ -69,7 +69,10 @@ class Kredits {
|
||||
if (wallet) {
|
||||
signer = wallet.connect(ethProvider);
|
||||
} else if (ethProvider.getSigner) {
|
||||
signer = 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);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ class ExpenseSerializer {
|
||||
description,
|
||||
currency,
|
||||
amount,
|
||||
amountSats,
|
||||
date,
|
||||
url,
|
||||
tags,
|
||||
@ -42,6 +43,7 @@ class ExpenseSerializer {
|
||||
description,
|
||||
currency,
|
||||
amount,
|
||||
amountSats,
|
||||
date,
|
||||
'tags': tags || [],
|
||||
'details': details || {},
|
||||
@ -76,6 +78,7 @@ class ExpenseSerializer {
|
||||
description,
|
||||
currency,
|
||||
amount,
|
||||
amountSats,
|
||||
date,
|
||||
url,
|
||||
tags,
|
||||
@ -87,6 +90,7 @@ class ExpenseSerializer {
|
||||
description,
|
||||
currency,
|
||||
amount,
|
||||
amountSats,
|
||||
date,
|
||||
url,
|
||||
tags,
|
||||
|
@ -9,6 +9,13 @@ class IPFS {
|
||||
}
|
||||
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) {
|
||||
|
906
package-lock.json
generated
906
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "kredits-contracts",
|
||||
"version": "7.0.0-beta.0",
|
||||
"description": "Ethereum contracts and npm wrapper for Kredits",
|
||||
"name": "@kredits/contracts",
|
||||
"version": "7.5.0",
|
||||
"description": "Smart contracts and JavaScript API for Kredits",
|
||||
"main": "./lib/kredits.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
@ -21,12 +21,10 @@
|
||||
"lint:contracts": "solhint \"contracts/**/*.sol\" \"apps/*/contracts/**/*.sol\"",
|
||||
"lint:contract-tests": "eslint apps/*/test",
|
||||
"lint:wrapper": "eslint lib/",
|
||||
"test": "npm run test:token && npm run test:contributor && npm run test:contribution && npm run test:proposal",
|
||||
"test:token": "cd apps/token && npm run test",
|
||||
"test:contributor": "cd apps/contributor && npm run test",
|
||||
"test:contribution": "cd apps/contribution && npm run test",
|
||||
"test:proposal": "cd apps/proposal && npm run test",
|
||||
"setup-git-hooks": "sh scripts/git-hooks/install"
|
||||
"test": "hardhat test",
|
||||
"setup-git-hooks": "sh scripts/git-hooks/install",
|
||||
"preversion": "npm test && npm run build",
|
||||
"version": "git add lib/abis"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -39,11 +37,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/67P/kredits-contracts#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.3.2",
|
||||
"@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",
|
||||
@ -57,6 +57,7 @@
|
||||
"hardhat-deploy": "^0.11.4",
|
||||
"hardhat-deploy-ethers": "^0.3.0-beta.10",
|
||||
"homedir": "^0.6.0",
|
||||
"mocha": "^10.0.0",
|
||||
"promptly": "^3.0.3",
|
||||
"solhint": "^3.3.7",
|
||||
"truffle-hdwallet-provider": "^1.0.17",
|
||||
@ -65,7 +66,7 @@
|
||||
"yargs": "^15.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kosmos/schemas": "^3.1.0",
|
||||
"@kosmos/schemas": "^3.2.0",
|
||||
"ethers": "^5.4.7",
|
||||
"ipfs-http-client": "^56.0.3",
|
||||
"multihashes": "^4.0.3",
|
||||
|
@ -1,4 +1,6 @@
|
||||
const { ethers, upgrades } = require("hardhat"); const path = require("path"); const fileInject = require("./helpers/file_inject.js");
|
||||
const { ethers, upgrades } = require("hardhat");
|
||||
const path = require("path");
|
||||
const fileInject = require("./helpers/file_inject.js");
|
||||
|
||||
function handleError(error) {
|
||||
console.error(error.message);
|
||||
@ -34,7 +36,7 @@ async function main() {
|
||||
|
||||
const blocksVetoPeriod = 40320; // 7 days; 15 seconds block time
|
||||
|
||||
await deployContractProxy('Contributor');
|
||||
await deployContractProxy('Contributor', [ '0x0000000000000000000000000000000000000000' ] );
|
||||
await deployContractProxy('Contribution', [ blocksVetoPeriod ]);
|
||||
await deployContractProxy('Token');
|
||||
await deployContractProxy('Reimbursement');
|
||||
@ -55,16 +57,6 @@ async function main() {
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
|
||||
console.log('Calling Contribution#setTokenContract')
|
||||
await contracts.Contribution.functions
|
||||
.setTokenContract(contracts.Token.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)
|
||||
@ -73,14 +65,6 @@ async function main() {
|
||||
return res.wait();
|
||||
}).catch(handleError);
|
||||
|
||||
console.log('Calling Token#setContributionContract')
|
||||
await contracts.Token.functions
|
||||
.setContributionContract(contracts.Contribution.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)
|
||||
|
43
scripts/export/contributions.js
Normal file
43
scripts/export/contributions.js
Normal file
@ -0,0 +1,43 @@
|
||||
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();
|
38
scripts/export/contributors.js
Normal file
38
scripts/export/contributors.js
Normal file
@ -0,0 +1,38 @@
|
||||
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();
|
44
scripts/export/reimbursements.js
Normal file
44
scripts/export/reimbursements.js
Normal file
@ -0,0 +1,44 @@
|
||||
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();
|
45
scripts/import/contributions.js
Normal file
45
scripts/import/contributions.js
Normal file
@ -0,0 +1,45 @@
|
||||
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();
|
34
scripts/import/contributors.js
Normal file
34
scripts/import/contributors.js
Normal file
@ -0,0 +1,34 @@
|
||||
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();
|
36
scripts/import/reimbursements.js
Normal file
36
scripts/import/reimbursements.js
Normal file
@ -0,0 +1,36 @@
|
||||
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();
|
@ -12,7 +12,7 @@ async function main() {
|
||||
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
||||
|
||||
const table = new Table({
|
||||
head: ['ID', 'Contributor ID', 'Description', 'Amount', 'Confirmed?', 'Vetoed?', 'Claimed?', 'IPFS']
|
||||
head: ['ID', 'Contributor ID', 'Description', 'Amount', 'Confirmed?', 'Vetoed?', 'IPFS']
|
||||
})
|
||||
|
||||
try {
|
||||
@ -31,7 +31,6 @@ async function main() {
|
||||
c.amount.toString(),
|
||||
`${confirmed} (${c.confirmedAtBlock})`,
|
||||
c.vetoed,
|
||||
c.claimed,
|
||||
c.ipfsHash
|
||||
])
|
||||
});
|
||||
|
@ -6,6 +6,8 @@ async function main() {
|
||||
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']
|
||||
|
@ -39,7 +39,7 @@ async function main() {
|
||||
contractWrapper.contract[method];
|
||||
|
||||
try {
|
||||
// console.log('trying', func);
|
||||
// console.log('trying', contractName, method, args);
|
||||
const result = await func.apply(contractWrapper, args);
|
||||
// console.log('result:', result);
|
||||
await result.wait();
|
||||
|
@ -7,7 +7,17 @@ async function main() {
|
||||
await kredits.init();
|
||||
|
||||
const ContributorV2 = await ethers.getContractFactory("Contributor");
|
||||
const contributor = await upgrades.upgradeProxy(kredits.Contributor.address, ContributorV2);
|
||||
const contributor = await upgrades.upgradeProxy(
|
||||
kredits.Contributor.address,
|
||||
ContributorV2,
|
||||
{
|
||||
call: {
|
||||
fn: "reinitialize",
|
||||
args: [
|
||||
"0xc80d2513277FA04B10403E2D1d7dAa86F931f4d1"
|
||||
]
|
||||
}
|
||||
});
|
||||
console.log("Contributor upgraded");
|
||||
console.log(`Contributor address: ${contributor.address}`);
|
||||
|
||||
@ -16,4 +26,4 @@ async function main() {
|
||||
console.log("DONE!");
|
||||
}
|
||||
|
||||
main();
|
||||
main()
|
||||
|
157
test/contracts/Contribution.js
Normal file
157
test/contracts/Contribution.js
Normal file
@ -0,0 +1,157 @@
|
||||
const { expect } = require("chai");
|
||||
const { ethers, upgrades } = require("hardhat");
|
||||
const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
|
||||
let owner, addr1, addr2, addr3, addr4, addr5, addr6, addr7;
|
||||
let Contribution, Contributor;
|
||||
|
||||
describe("Contribution contract", async function () {
|
||||
before(async function () {
|
||||
[owner, addr1, addr2, addr3, addr4, addr5, addr6, addr7] = await ethers.getSigners();
|
||||
let accounts = [owner, addr1, addr2, addr3, addr4, addr5, addr6, addr7];
|
||||
const contributorFactory = await ethers.getContractFactory("Contributor");
|
||||
Contributor = await upgrades.deployProxy(contributorFactory, ["0x2946fFfd31096435cb0fc927D306E1C006C5D1aF"]);
|
||||
for (const account of accounts) {
|
||||
await Contributor.addContributor(account.address, "0x99b8afd7b266e19990924a8be9099e81054b70c36b20937228a77a5cf75723b8", 18, 32);
|
||||
}
|
||||
});
|
||||
|
||||
describe("initialize()", function () {
|
||||
before(async function () {
|
||||
// const [owner] = await ethers.getSigners();
|
||||
const contributionFactory = await ethers.getContractFactory("Contribution");
|
||||
Contribution = await upgrades.deployProxy(contributionFactory, [40321]);
|
||||
});
|
||||
|
||||
it("sets the veto confirmation period", async function () {
|
||||
expect(await Contribution.blocksToWait()).to.equal(40321);
|
||||
});
|
||||
|
||||
it("sets the data migration flag", async function () {
|
||||
expect(await Contribution.migrationDone()).to.be.false;
|
||||
});
|
||||
|
||||
it("sets the deployer address", async function () {
|
||||
expect(await Contribution.deployer()).to.equal(owner.address);
|
||||
expect(await Contribution.deployer()).to.not.equal(addr1.address);
|
||||
});
|
||||
});
|
||||
|
||||
describe("finishMigration()", function () {
|
||||
before(async function () {
|
||||
const contributionFactory = await ethers.getContractFactory("Contribution");
|
||||
Contribution = await upgrades.deployProxy(contributionFactory, [40321]);
|
||||
await Contribution.setContributorContract(Contributor.address).then(res => res.wait())
|
||||
});
|
||||
|
||||
it("does not allow random accounts to mark the migration as finished", async function () {
|
||||
await expect(Contribution.connect(addr1).finishMigration()).to.be.revertedWith("Deployer only");
|
||||
expect(await Contribution.migrationDone()).to.be.false;
|
||||
});
|
||||
|
||||
it("allows the deployer to mark the migration as finished", async function () {
|
||||
await Contribution.finishMigration();
|
||||
expect(await Contribution.migrationDone()).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("add()", function () {
|
||||
before(async function () {
|
||||
const contributionFactory = await ethers.getContractFactory("Contribution");
|
||||
Contribution = await upgrades.deployProxy(contributionFactory, [40321]);
|
||||
await Contribution.setContributorContract(Contributor.address).then(res => res.wait())
|
||||
await Contribution.finishMigration();
|
||||
});
|
||||
|
||||
it("does not allow non-contributors to add a contribution", async function () {
|
||||
await expect(Contribution.connect(addr7).add(
|
||||
500, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 0, false
|
||||
)).to.be.revertedWith("Requires kredits or core status");
|
||||
expect(await Contribution.contributionsCount()).to.equal(0);
|
||||
});
|
||||
|
||||
it("does not allow special arguments outside of a migration", async function () {
|
||||
await expect(Contribution.connect(addr7).add(
|
||||
500, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 23000, true
|
||||
)).to.be.revertedWith("Extra arguments not allowed");
|
||||
expect(await Contribution.contributionsCount()).to.equal(0);
|
||||
});
|
||||
|
||||
it("allows core contributors to add a contribution", async function () {
|
||||
await Contribution.connect(addr2).add(
|
||||
2001, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 0, false
|
||||
);
|
||||
expect(await Contribution.contributionsCount()).to.equal(1);
|
||||
});
|
||||
|
||||
it("allows contributors to add a contribution", async function () {
|
||||
// Issue some kredits for new contributor #8 (addr7)
|
||||
await Contribution.connect(addr1).add(
|
||||
5000, 8,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 0, false
|
||||
);
|
||||
await Contribution.connect(addr7).add(
|
||||
1500, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 0, false
|
||||
);
|
||||
expect(await Contribution.contributionsCount()).to.equal(3);
|
||||
});
|
||||
|
||||
it("sets confirmedAtBlock to current block plus blocksToWait", async function () {
|
||||
await Contribution.connect(addr1).add(
|
||||
500, 3,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 0, false
|
||||
);
|
||||
expect(await Contribution.contributionsCount()).to.equal(4);
|
||||
const c = await Contribution.getContribution(4);
|
||||
const currentBlockNumber = await kredits.provider.getBlockNumber();
|
||||
expect(c['confirmedAtBlock']).to.equal(currentBlockNumber + 1 + 40321);
|
||||
});
|
||||
|
||||
it("emits a ContributionAdded event", async function () {
|
||||
await expect(Contribution.connect(addr1).add(
|
||||
2001, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 0, false
|
||||
)).to.emit(Contribution, "ContributionAdded").withArgs(anyValue, 1, 2001);
|
||||
});
|
||||
|
||||
describe("with extra arguments during migration", async function () {
|
||||
before(async function () {
|
||||
const contributionFactory = await ethers.getContractFactory("Contribution");
|
||||
Contribution = await upgrades.deployProxy(contributionFactory, [40321]);
|
||||
await Contribution.setContributorContract(Contributor.address);
|
||||
});
|
||||
|
||||
it("allows to add a contribution with custom confirmedAtBlock", async function () {
|
||||
await Contribution.connect(addr2).add(
|
||||
2001, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 23000, false
|
||||
);
|
||||
expect(await Contribution.contributionsCount()).to.equal(1);
|
||||
const c = await Contribution.getContribution(1);
|
||||
expect(c['confirmedAtBlock'].toNumber()).to.equal(23000);
|
||||
});
|
||||
|
||||
it("allows to add a vetoed contribution", async function () {
|
||||
await Contribution.connect(addr2).add(
|
||||
2001, 1,
|
||||
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 23000, true
|
||||
);
|
||||
expect(await Contribution.contributionsCount()).to.equal(2);
|
||||
const c = await Contribution.getContribution(2);
|
||||
expect(c['vetoed']).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
122
test/contracts/Contributor.js
Normal file
122
test/contracts/Contributor.js
Normal file
@ -0,0 +1,122 @@
|
||||
const { expect } = require("chai");
|
||||
const { ethers, upgrades } = require("hardhat");
|
||||
let owner, addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8;
|
||||
let Contribution, Contributor, Token;
|
||||
|
||||
describe("Contributor contract", async function () {
|
||||
before(async function () {
|
||||
[owner, addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8] = await ethers.getSigners();
|
||||
|
||||
const contributorFactory = await ethers.getContractFactory("Contributor");
|
||||
Contributor = await upgrades.deployProxy(contributorFactory, [addr8.address]);
|
||||
const contributionFactory = await ethers.getContractFactory("Contribution");
|
||||
Contribution = await upgrades.deployProxy(contributionFactory, [40321]);
|
||||
const tokenFactory = await ethers.getContractFactory("Token");
|
||||
Token = await upgrades.deployProxy(tokenFactory);
|
||||
|
||||
await Contributor.setTokenContract(Token.address);
|
||||
await Contributor.setContributionContract(Contribution.address);
|
||||
await Contribution.setContributorContract(Contributor.address);
|
||||
await Token.setContributorContract(Contributor.address);
|
||||
|
||||
let accounts = [owner, addr1, addr2, addr3, addr4, addr5, addr6, addr7];
|
||||
for (const account of accounts) {
|
||||
await Contributor.addContributor(account.address, "0x99b8afd7b266e19990924a8be9099e81054b70c36b20937228a77a5cf75723b8", 18, 32);
|
||||
}
|
||||
});
|
||||
|
||||
describe("initialize()", function () {
|
||||
it("sets the deployer address", async function () {
|
||||
expect(await Contributor.deployer()).to.equal(owner.address);
|
||||
expect(await Contributor.deployer()).to.not.equal(addr1.address);
|
||||
});
|
||||
|
||||
it("sets a profile manager address", async function () {
|
||||
expect(await Contributor.profileManager()).to.equal(addr8.address);
|
||||
});
|
||||
});
|
||||
|
||||
describe("add()", function () {
|
||||
it("does not allow random accounts to create a contributor profile", async function () {
|
||||
await expect(Contributor.connect(addr7).addContributor(
|
||||
"0x608FD4b95116Ea616990Aaeb1d4f1ce07612f261",
|
||||
"0x1d9de6de5c72eedca6d7a5e8a9159e2f5fe676506aece3000acefcc821723429",
|
||||
18, 32
|
||||
)).to.be.revertedWith("Only core and profile manager");
|
||||
expect(await Contributor.contributorsCount()).to.equal(8);
|
||||
});
|
||||
|
||||
it("allows core contributors to create a contributor profile", async function () {
|
||||
await Contributor.connect(addr1).addContributor(
|
||||
"0x608FD4b95116Ea616990Aaeb1d4f1ce07612f261",
|
||||
"0x1d9de6de5c72eedca6d7a5e8a9159e2f5fe676506aece3000acefcc821723429",
|
||||
18, 32
|
||||
);
|
||||
expect(await Contributor.contributorsCount()).to.equal(9);
|
||||
const c = await Contributor.getContributorById(9);
|
||||
expect(c['account']).to.equal("0x608FD4b95116Ea616990Aaeb1d4f1ce07612f261");
|
||||
expect(c['kreditsWithdrawn']).to.equal(0);
|
||||
});
|
||||
|
||||
it("does not allow to create accounts with an existing address", async function () {
|
||||
await expect(Contributor.connect(addr1).addContributor(
|
||||
"0x608FD4b95116Ea616990Aaeb1d4f1ce07612f261",
|
||||
"0x1d9de6de5c72eedca6d7a5e8a9159e2f5fe676506aece3000acefcc821723429",
|
||||
18, 32
|
||||
)).to.be.revertedWith("Address already in use");
|
||||
expect(await Contributor.contributorsCount()).to.equal(9);
|
||||
});
|
||||
|
||||
it("emits a ContributorAdded event", async function () {
|
||||
await expect(Contributor.connect(addr1).addContributor(
|
||||
"0x765E88b4F9a59C3a3b300C6eFF9E6E9fDDf9FbD9",
|
||||
"0xcfbeeadc244dfdc55bbad50d431871439df067970db84c73023956c96a6f5df2",
|
||||
18, 32
|
||||
)).to.emit(Contributor, "ContributorAdded").withArgs(10, "0x765E88b4F9a59C3a3b300C6eFF9E6E9fDDf9FbD9");
|
||||
});
|
||||
|
||||
it("allows the profile manager account to create a contributor profile", async function () {
|
||||
await Contributor.connect(addr8).addContributor(
|
||||
"0x954712B8703Df5255A219B139ba7BFC256E72a15",
|
||||
"0x1d9de6de5c72eedca6d7a5e8a9159e2f5fe676506aece3000acefcc821723429",
|
||||
18, 32
|
||||
);
|
||||
expect(await Contributor.contributorsCount()).to.equal(11);
|
||||
const c = await Contributor.getContributorById(11);
|
||||
expect(c['account']).to.equal("0x954712B8703Df5255A219B139ba7BFC256E72a15");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("withdraw()", function () {
|
||||
before(async function () {
|
||||
// Add some pre-confirmed contributions (confirmedAtBlock 1)
|
||||
await Contribution.add(
|
||||
1500, 2, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 1, false
|
||||
);
|
||||
await Contribution.add(
|
||||
5000, 2, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
|
||||
18, 32, 1, false
|
||||
);
|
||||
await Contribution.finishMigration();
|
||||
});
|
||||
|
||||
it("requires the transaction sender to be a contributor", async function () {
|
||||
await expect(Contributor.withdraw()).to.be.revertedWith("Contributors only");
|
||||
});
|
||||
|
||||
it("executes a withdrawal of all available ERC20 kredits", async function () {
|
||||
let c = await Contributor.getContributorById(2);
|
||||
expect(c['balance']).to.equal(0);
|
||||
await Contributor.connect(addr1).withdraw();
|
||||
c = await Contributor.getContributorById(2);
|
||||
expect(c['balance']).to.equal(6500);
|
||||
expect(c['kreditsWithdrawn']).to.equal(6500);
|
||||
});
|
||||
|
||||
it("requires the withdrawable amount to be larger than 0", async function () {
|
||||
await expect(Contributor.connect(addr1).withdraw()).to.be.revertedWith("No kredits available");
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user