Merge branch 'master' into chore/linter
# Conflicts: # lib/contracts/contribution.js # lib/contracts/contributor.js # lib/contracts/proposal.js # lib/kredits.js # lib/serializers/contributor.js # yarn.lock
This commit is contained in:
commit
145b3ea766
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@ node_modules
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
.ganache-db
|
.ganache-db
|
||||||
.tm_properties
|
.tm_properties
|
||||||
|
yarn-error.log
|
||||||
|
.DS_Store
|
||||||
|
22
README.md
22
README.md
@ -36,7 +36,7 @@ development ganache.
|
|||||||
|
|
||||||
$ npm run devchain (or aragon devchain --port 7545)
|
$ npm run devchain (or aragon devchain --port 7545)
|
||||||
|
|
||||||
To clear/reset the chain use:
|
To clear/reset the chain use (e.g. if you run out of funds on your devchain)
|
||||||
|
|
||||||
$ npm run devchain -- --reset (or aragon devchain --port 7545 --reset)
|
$ npm run devchain -- --reset (or aragon devchain --port 7545 --reset)
|
||||||
|
|
||||||
@ -174,6 +174,26 @@ Runs `npm install` for each app and publishes a new version.
|
|||||||
or
|
or
|
||||||
$ npm run deploy:apps
|
$ npm run deploy:apps
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Apps deployment
|
||||||
|
|
||||||
|
To deploy a new app version run:
|
||||||
|
|
||||||
|
$ aragon apm publish major --environment=NETWORK_TO_DEPLOY
|
||||||
|
|
||||||
|
### KreditsKit
|
||||||
|
|
||||||
|
deploy the KreditsKit as Kit to create new DAOs
|
||||||
|
|
||||||
|
$ truffle exec scripts/deploy-kit.js --network=NETWORK_TO_DEPLOY
|
||||||
|
|
||||||
|
### Creating a new DAO
|
||||||
|
|
||||||
|
make sure all apps and the KreditsKit are deployed, then create a new DAO:
|
||||||
|
|
||||||
|
$ truffle exec scripts/new-dao.js --network=NETWORK_TO_DEPLOY
|
||||||
|
|
||||||
## ACL / Permissions
|
## ACL / Permissions
|
||||||
|
|
||||||
## Upgradeable contracts
|
## Upgradeable contracts
|
||||||
|
@ -118,6 +118,26 @@ contract Contribution is AragonApp {
|
|||||||
// Custom functions
|
// Custom functions
|
||||||
//
|
//
|
||||||
|
|
||||||
|
function totalKreditsEarned(bool confirmedOnly) public view returns (uint256 count) {
|
||||||
|
for (uint32 i = 1; i <= contributionsCount; i++) {
|
||||||
|
ContributionData memory c = contributions[i];
|
||||||
|
if (block.number >= c.confirmedAtBlock || !confirmedOnly) {
|
||||||
|
count += c.amount; // should use safemath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) public view returns (uint256 count) {
|
||||||
|
uint256 tokenBalance = ownedContributions[contributorId].length;
|
||||||
|
for (uint256 i = 0; i < tokenBalance; i++) {
|
||||||
|
uint32 cId = ownedContributions[contributorId][i];
|
||||||
|
ContributionData memory c = contributions[cId];
|
||||||
|
if (block.number >= c.confirmedAtBlock || !confirmedOnly) {
|
||||||
|
count += c.amount; // should use safemath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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, bool claimed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
|
||||||
id = contributionId;
|
id = contributionId;
|
||||||
ContributionData storage c = contributions[id];
|
ContributionData storage c = contributions[id];
|
||||||
|
8145
apps/contribution/yarn.lock
Normal file
8145
apps/contribution/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,10 @@ import "@aragon/os/contracts/kernel/IKernel.sol";
|
|||||||
interface ITokenBalance {
|
interface ITokenBalance {
|
||||||
function balanceOf(address contributorAccount) public view returns (uint256);
|
function balanceOf(address contributorAccount) public view returns (uint256);
|
||||||
}
|
}
|
||||||
|
interface IContributionBalance {
|
||||||
|
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) public view returns (uint256 count);
|
||||||
|
function balanceOf(address owner) public view returns (uint256);
|
||||||
|
}
|
||||||
|
|
||||||
contract Contributor is AragonApp {
|
contract Contributor is AragonApp {
|
||||||
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
||||||
@ -43,6 +47,12 @@ contract Contributor is AragonApp {
|
|||||||
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]);
|
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Token)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getContributionContract() public view returns (address) {
|
||||||
|
IKernel k = IKernel(kernel());
|
||||||
|
|
||||||
|
return k.getApp(KERNEL_APP_ADDR_NAMESPACE, appIds[uint8(Apps.Contribution)]);
|
||||||
|
}
|
||||||
|
|
||||||
function coreContributorsCount() view public returns (uint32) {
|
function coreContributorsCount() view public returns (uint32) {
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
for (uint32 i = 1; i <= contributorsCount; i++) {
|
for (uint32 i = 1; i <= contributorsCount; i++) {
|
||||||
@ -118,7 +128,7 @@ contract Contributor is AragonApp {
|
|||||||
return contributors[id];
|
return contributors[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContributorById(uint32 _id) public view returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, bool exists ) {
|
function getContributorById(uint32 _id) public view returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, uint256 totalKreditsEarned, uint256 contributionsCount, bool exists ) {
|
||||||
id = _id;
|
id = _id;
|
||||||
Contributor storage c = contributors[_id];
|
Contributor storage c = contributors[_id];
|
||||||
account = c.account;
|
account = c.account;
|
||||||
@ -128,6 +138,9 @@ contract Contributor is AragonApp {
|
|||||||
isCore = isCoreTeam(id);
|
isCore = isCoreTeam(id);
|
||||||
address token = getTokenContract();
|
address token = getTokenContract();
|
||||||
balance = ITokenBalance(token).balanceOf(c.account);
|
balance = ITokenBalance(token).balanceOf(c.account);
|
||||||
|
address contribution = getContributionContract();
|
||||||
|
totalKreditsEarned = IContributionBalance(contribution).totalKreditsEarnedByContributor(_id, true);
|
||||||
|
contributionsCount = IContributionBalance(contribution).balanceOf(c.account);
|
||||||
exists = c.exists;
|
exists = c.exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8145
apps/contributor/yarn.lock
Normal file
8145
apps/contributor/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
8145
apps/proposal/yarn.lock
Normal file
8145
apps/proposal/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
8145
apps/token/yarn.lock
Normal file
8145
apps/token/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,36 @@
|
|||||||
const contractCalls = [
|
const contractCalls = [
|
||||||
['Contributor', 'add', [{ account: '0x7e8f313c56f809188313aa274fa67ee58c31515d', name: 'bumi', kind: 'person', url: '', github_username: 'bumi', github_uid: 318, wiki_username: 'bumi' }, { gasLimit: 200000 }]],
|
['Contributor', 'add', [{
|
||||||
['Contributor', 'add', [{ account: '0x49575f3DD9a0d60aE661BC992f72D837A77f05Bc', name: 'raucao', kind: 'person', url: '', github_username: 'skddc', github_uid: 842, wiki_username: 'raucau' }, { gasLimit: 200000 }]],
|
account: '0x7e8f313c56f809188313aa274fa67ee58c31515d',
|
||||||
|
name: 'bumi',
|
||||||
|
kind: 'person',
|
||||||
|
url: '',
|
||||||
|
github_username: 'bumi',
|
||||||
|
github_uid: 318,
|
||||||
|
gitea_username: 'bumi',
|
||||||
|
wiki_username: 'Bumi'
|
||||||
|
}, { gasLimit: 200000 }]],
|
||||||
|
|
||||||
|
['Contributor', 'add', [{
|
||||||
|
account: '0x49575f3DD9a0d60aE661BC992f72D837A77f05Bc',
|
||||||
|
name: 'raucao',
|
||||||
|
kind: 'person',
|
||||||
|
url: '',
|
||||||
|
github_username: 'skddc',
|
||||||
|
github_uid: 842,
|
||||||
|
gitea_username: 'raucao',
|
||||||
|
wiki_username: 'Basti'
|
||||||
|
}, { gasLimit: 200000 }]],
|
||||||
|
|
||||||
|
['Contributor', 'add', [{
|
||||||
|
account: '0xF722709ECC3B05c19d02E82a2a4A4021B8F48C62',
|
||||||
|
name: 'Manuel',
|
||||||
|
kind: 'person',
|
||||||
|
url: '',
|
||||||
|
github_username: 'fsmanuel',
|
||||||
|
github_uid: 54812,
|
||||||
|
wiki_username: 'Manuel'
|
||||||
|
}, { gasLimit: 200000 }]],
|
||||||
|
|
||||||
['Proposal', 'addProposal', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-09', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
|
['Proposal', 'addProposal', [{ contributorId: 1, contributorIpfsHash: 'QmWKCYGr2rSf6abUPaTYqf98urvoZxGrb7dbspFZA6oyVF', date: '2019-04-09', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
|
||||||
['Proposal', 'addProposal', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-10', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
|
['Proposal', 'addProposal', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-10', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Ran the seeds', url: '' }, { gasLimit: 350000 }]],
|
||||||
['Proposal', 'addProposal', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Hacked on kredits', url: '' }, { gasLimit: 350000 }]],
|
['Proposal', 'addProposal', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 500, kind: 'dev', description: '[67P/kredits-contracts] Hacked on kredits', url: '' }, { gasLimit: 350000 }]],
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
# Contribution deployments
|
# Contribution deployments
|
||||||
|
|
||||||
|
aragon apm publish major --environment=rinkeby"
|
||||||
|
|
||||||
|
## 2019-04-24 update balances
|
||||||
|
|
||||||
|
✔ Successfully published kredits-contribution.open.aragonpm.eth v6.0.0:
|
||||||
|
ℹ Contract address: 0x2c083EEA83fd3a99C93759D97D0317A43261c758
|
||||||
|
ℹ Content (ipfs): QmULpSqz7BgTFmDu8AL7YZZEz525xkcEzf3dPKtbRdUtFs
|
||||||
|
ℹ Transaction hash: 0x8b01c4c00162e918659d267a2beaf33b578e2aaf9f427f1aa9a43029333c5cd7
|
||||||
|
|
||||||
|
## 2019-04-10 - Weltempfänger release
|
||||||
|
|
||||||
|
✔ Successfully published kredits-contribution.open.aragonpm.eth v5.0.0:
|
||||||
|
ℹ Contract address: 0xe0f7dB486321b917e3A986Bdb2F2b9d51BA98fa9
|
||||||
|
ℹ Content (ipfs): QmU3XEBb4f5jU8MFFEpwaa95C1mhc82UeYLRWLrKsvcQNw
|
||||||
|
ℹ Transaction hash: 0xd736ff5f79f8142be3fad1a50580fb40aa468838da397f8630285fd91a445af3
|
||||||
|
|
||||||
|
|
||||||
## 2019-04-04
|
## 2019-04-04
|
||||||
|
|
||||||
✔ Successfully published kredits-contribution.open.aragonpm.eth v4.0.0:
|
✔ Successfully published kredits-contribution.open.aragonpm.eth v4.0.0:
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
# Contributor deployments
|
# Contributor deployments
|
||||||
|
|
||||||
|
aragon apm publish major --environment=rinkeby
|
||||||
|
|
||||||
|
## 2019-04-29 update balances
|
||||||
|
|
||||||
|
✔ Successfully published kredits-contributor.open.aragonpm.eth v5.0.0:
|
||||||
|
ℹ Contract address: 0xadefa3b66b68a127Fe38bEa1813b844EE69CFD86
|
||||||
|
ℹ Content (ipfs): QmeygbQgoj2McLWzo9hJayLWuBZqFaK4HTpa5qLeQdkn5K
|
||||||
|
ℹ Transaction hash: 0x4237a9636f6e4a8190e0d5bcfa85a452da097bf654a173a88e0e1de3d078f08d
|
||||||
|
|
||||||
|
|
||||||
|
## 2019-04-10 - Weltempfänger release
|
||||||
|
|
||||||
|
✔ Successfully published kredits-contributor.open.aragonpm.eth v4.0.0:
|
||||||
|
ℹ Contract address: 0x08a6D4D915FCAA5524F05F5F715a6C17cB6eeA6B
|
||||||
|
ℹ Content (ipfs): QmR62PWwe1EzommfkhJDYcTvHoZjbXuv9dTG6vCn5dWCsb
|
||||||
|
ℹ Transaction hash: 0xd5317c9e207a413485c55ec3046b09d467d978443680304737a6d7d3db0c90e1
|
||||||
|
|
||||||
|
|
||||||
## 2019-04-04
|
## 2019-04-04
|
||||||
|
|
||||||
✔ Successfully published kredits-contributor.open.aragonpm.eth v3.0.0:
|
✔ Successfully published kredits-contributor.open.aragonpm.eth v3.0.0:
|
||||||
|
@ -1,5 +1,24 @@
|
|||||||
# Kredits deployment
|
# Kredits deployment
|
||||||
|
|
||||||
|
## 2019-04-24 upgrade contributor and contribution
|
||||||
|
|
||||||
|
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contributor.open.aragonpm.eth --environment=rinkeby
|
||||||
|
eth-provider | Invalid provider preset/location: "local"
|
||||||
|
✔ Fetching kredits-contributor.open.aragonpm.eth@latest
|
||||||
|
✔ Upgrading app
|
||||||
|
✔ Successfully executed: "Set the resolving address of 'kredits-contributor.open.aragonpm.eth' in namespace 'App code' to 0xadefa3b66b68a127Fe38bEa1813b844EE69CFD86"
|
||||||
|
|
||||||
|
|
||||||
|
aragon dao upgrade 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14 kredits-contribution.open.aragonpm.eth --environment=rinkeby
|
||||||
|
✔ Fetching kredits-contribution.open.aragonpm.eth@latest
|
||||||
|
✔ Upgrading app
|
||||||
|
✔ Successfully executed: "Set the resolving address of 'kredits-contribution.open.aragonpm.eth' in namespace 'App code' to 0x2c083EEA83fd3a99C93759D97D0317A43261c758"
|
||||||
|
|
||||||
|
## 2019-04-10 - Weltempfänger release
|
||||||
|
|
||||||
|
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
|
||||||
|
Created new DAO at: 0xc34edf7d11b7f8433d597f0bb0697acdff55ef14
|
||||||
|
|
||||||
## 2019-04-04
|
## 2019-04-04
|
||||||
|
|
||||||
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
|
Using KreditsKit at: 0x76e069b47b79442657eaf0555a32c6b16fa1b8b4
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
# Proposal deployments
|
# Proposal deployments
|
||||||
|
|
||||||
|
## 2019-04-10 - Weltempfänger release
|
||||||
|
|
||||||
|
✔ Successfully published kredits-proposal.open.aragonpm.eth v5.0.0:
|
||||||
|
ℹ Contract address: 0x4ce5b0286483c66b861e5599a199054687434552
|
||||||
|
ℹ Content (ipfs): QmNYXEcmvKTGxYiob7WUf85oZhdmFDCuGiA6TsRrDE9TYb
|
||||||
|
ℹ Transaction hash: 0x0482b58a1ba87d494c6391026399d0ac41b45384330d916f3f99ba70e501584b
|
||||||
|
|
||||||
|
|
||||||
## 2019-04-04
|
## 2019-04-04
|
||||||
|
|
||||||
✔ Successfully published kredits-proposal.open.aragonpm.eth v4.0.0:
|
✔ Successfully published kredits-proposal.open.aragonpm.eth v4.0.0:
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
# Token deployments
|
# Token deployments
|
||||||
|
|
||||||
|
## 2019-04-10 - Weltempfänger release
|
||||||
|
|
||||||
|
✔ Successfully published kredits-token.open.aragonpm.eth v4.0.0:
|
||||||
|
ℹ Contract address: 0x05E0C2bbdA8e5BeE22AC1E20C1457dA4de63aE26
|
||||||
|
ℹ Content (ipfs): QmUuYLRMRNZcundUk2pxVaSjMNvtB7hzdf3eyoaUNqDPow
|
||||||
|
ℹ Transaction hash: 0x98c28b5ca645904d56eb83c4783682f018c0fcee015b3a3d5fa8bd609223fb89
|
||||||
|
|
||||||
|
|
||||||
## 2019-04-04
|
## 2019-04-04
|
||||||
|
|
||||||
✔ Successfully published kredits-token.open.aragonpm.eth v3.0.0:
|
✔ Successfully published kredits-token.open.aragonpm.eth v3.0.0:
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,4 +1,3 @@
|
|||||||
{
|
{
|
||||||
"4": "0x76e069b47b79442657eaf0555a32c6b16fa1b8b4",
|
"4": "0x76e069b47b79442657eaf0555a32c6b16fa1b8b4"
|
||||||
"41787949": "0xa35aacdfccac54d3d96e0d29050c773b251c2c83"
|
|
||||||
}
|
}
|
@ -1,4 +1,3 @@
|
|||||||
{
|
{
|
||||||
"4": "0xcd75458fbc4aa2231252d5b21f1391fd031e5cb2",
|
"4": "0xc34edf7d11b7f8433d597f0bb0697acdff55ef14"
|
||||||
"41787949": "0x183af3950364390a266edff2a0e7c4c2f95c0691"
|
|
||||||
}
|
}
|
@ -1,19 +1,9 @@
|
|||||||
|
const Record = require('./record');
|
||||||
const ContributionSerializer = require('../serializers/contribution');
|
const ContributionSerializer = require('../serializers/contribution');
|
||||||
const Base = require('./base');
|
|
||||||
|
|
||||||
class Contribution extends Base {
|
class Contribution extends Record {
|
||||||
all () {
|
get count () {
|
||||||
return this.functions.contributionsCount()
|
return this.functions.contributionsCount();
|
||||||
.then(async (count) => {
|
|
||||||
let contributions = [];
|
|
||||||
|
|
||||||
for (let id = 1; id <= count; id++) {
|
|
||||||
const contribution = await this.getById(id);
|
|
||||||
contributions.push(contribution);
|
|
||||||
}
|
|
||||||
|
|
||||||
return contributions;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getById (id) {
|
getById (id) {
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
const RSVP = require('rsvp');
|
const Record = require('./record');
|
||||||
|
|
||||||
const ContributorSerializer = require('../serializers/contributor');
|
const ContributorSerializer = require('../serializers/contributor');
|
||||||
const Base = require('./base');
|
const formatKredits = require('../utils/format-kredits');
|
||||||
|
|
||||||
class Contributor extends Base {
|
class Contributor extends Record {
|
||||||
all () {
|
get count () {
|
||||||
return this.functions.contributorsCount()
|
return this.functions.contributorsCount();
|
||||||
.then(count => {
|
|
||||||
let contributors = [];
|
|
||||||
|
|
||||||
for (let id = 1; id <= count; id++) {
|
|
||||||
contributors.push(this.getById(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return RSVP.all(contributors);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getById (id) {
|
getById (id) {
|
||||||
return this.functions.getContributorById(id)
|
return this.functions.getContributorById(id)
|
||||||
.then((data) => {
|
.then(data => {
|
||||||
|
data.balanceInt = formatKredits(data.balance);
|
||||||
return this.ipfs.catAndMerge(data, ContributorSerializer.deserialize);
|
return this.ipfs.catAndMerge(data, ContributorSerializer.deserialize);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -48,12 +39,16 @@ class Contributor extends Base {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
add (contributorAttr, callOptions = {}) {
|
async add (contributorAttr, callOptions = {}) {
|
||||||
let json = ContributorSerializer.serialize(contributorAttr);
|
let contributor = new ContributorSerializer(contributorAttr);
|
||||||
// TODO: validate against schema
|
|
||||||
|
try { await contributor.validate(); }
|
||||||
|
catch (error) { return Promise.reject(error); }
|
||||||
|
|
||||||
|
const jsonStr = contributor.serialize();
|
||||||
|
|
||||||
return this.ipfs
|
return this.ipfs
|
||||||
.add(json)
|
.add(jsonStr)
|
||||||
.then((ipfsHashAttr) => {
|
.then((ipfsHashAttr) => {
|
||||||
let contributor = [
|
let contributor = [
|
||||||
contributorAttr.account,
|
contributorAttr.account,
|
||||||
@ -65,6 +60,30 @@ class Contributor extends Base {
|
|||||||
return this.functions.addContributor(...contributor, callOptions);
|
return this.functions.addContributor(...contributor, callOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateProfile (contributorId, updateAttr, callOptions = {}) {
|
||||||
|
return this.getById(contributorId).then(async (contributor) => {
|
||||||
|
let updatedContributorAttr = Object.assign(contributor, updateAttr)
|
||||||
|
let updatedContributor = new ContributorSerializer(updatedContributorAttr);
|
||||||
|
|
||||||
|
try { await updatedContributor.validate(); }
|
||||||
|
catch (error) { return Promise.reject(error); }
|
||||||
|
|
||||||
|
const jsonStr = updatedContributor.serialize();
|
||||||
|
|
||||||
|
return this.ipfs
|
||||||
|
.add(jsonStr)
|
||||||
|
.then(ipfsHashAttr => {
|
||||||
|
return this.functions.updateContributorProfileHash(
|
||||||
|
contributorId,
|
||||||
|
ipfsHashAttr.hashDigest,
|
||||||
|
ipfsHashAttr.hashFunction,
|
||||||
|
ipfsHashAttr.hashSize,
|
||||||
|
callOptions
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Contributor;
|
module.exports = Contributor;
|
||||||
|
@ -1,20 +1,9 @@
|
|||||||
const RSVP = require('rsvp');
|
const Record = require('./record');
|
||||||
|
|
||||||
const ContributionSerializer = require('../serializers/contribution');
|
const ContributionSerializer = require('../serializers/contribution');
|
||||||
const Base = require('./base');
|
|
||||||
|
|
||||||
class Proposal extends Base {
|
class Proposal extends Record {
|
||||||
all () {
|
get count () {
|
||||||
return this.functions.proposalsCount()
|
return this.functions.proposalsCount();
|
||||||
.then(count => {
|
|
||||||
let proposals = [];
|
|
||||||
|
|
||||||
for (let id = 1; id <= count; id++) {
|
|
||||||
proposals.push(this.getById(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return RSVP.all(proposals);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getById (id) {
|
getById (id) {
|
||||||
|
14
lib/contracts/record.js
Normal file
14
lib/contracts/record.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const Base = require('./base');
|
||||||
|
const paged = require('../utils/pagination');
|
||||||
|
|
||||||
|
class Record extends Base {
|
||||||
|
all(options = {}) {
|
||||||
|
return this.count
|
||||||
|
.then((count) => {
|
||||||
|
let records = paged(count, options).map((id) => this.getById(id));
|
||||||
|
return Promise.all(records);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Record
|
@ -1,5 +1,4 @@
|
|||||||
const ethers = require('ethers');
|
const ethers = require('ethers');
|
||||||
const RSVP = require('rsvp');
|
|
||||||
|
|
||||||
const Preflight = require('./utils/preflight');
|
const Preflight = require('./utils/preflight');
|
||||||
|
|
||||||
@ -57,7 +56,8 @@ class Kredits {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return RSVP.all(addressPromises).then(() => { return this; });
|
|
||||||
|
return Promise.all(addressPromises).then(() => { return this });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
const schemas = require('kosmos-schemas');
|
||||||
|
const validator = require('../utils/validator');
|
||||||
/**
|
/**
|
||||||
* Handle serialization for JSON-LD object of the contributor, according to
|
* Handle serialization for JSON-LD object of the contributor, according to
|
||||||
* https://github.com/67P/kosmos-schemas/blob/master/schemas/contributor.json
|
* https://github.com/67P/kosmos-schemas/blob/master/schemas/contributor.json
|
||||||
@ -6,41 +8,9 @@
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
class Contributor {
|
class Contributor {
|
||||||
/**
|
|
||||||
* Deserialize JSON to object
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
static deserialize (serialized) {
|
|
||||||
let {
|
|
||||||
name,
|
|
||||||
kind,
|
|
||||||
url,
|
|
||||||
accounts,
|
|
||||||
} = JSON.parse(serialized.toString('utf8'));
|
|
||||||
|
|
||||||
let github_username, github_uid, wiki_username;
|
constructor (attrs) {
|
||||||
let github = accounts.find((a) => a.site === 'github.com');
|
Object.keys(attrs).forEach(a => this[a] = attrs[a]);
|
||||||
let wiki = accounts.find((a) => a.site === 'wiki.kosmos.org');
|
|
||||||
|
|
||||||
if (github) {
|
|
||||||
(({ username: github_username, uid: github_uid} = github));
|
|
||||||
}
|
|
||||||
if (wiki) {
|
|
||||||
(({ username: wiki_username } = wiki));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
kind,
|
|
||||||
url,
|
|
||||||
accounts,
|
|
||||||
github_uid,
|
|
||||||
github_username,
|
|
||||||
wiki_username,
|
|
||||||
ipfsData: serialized,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,15 +19,16 @@ class Contributor {
|
|||||||
* @method
|
* @method
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
static serialize (deserialized) {
|
serialize () {
|
||||||
let {
|
let {
|
||||||
name,
|
name,
|
||||||
kind,
|
kind,
|
||||||
url,
|
url,
|
||||||
github_uid,
|
github_uid,
|
||||||
github_username,
|
github_username,
|
||||||
|
gitea_username,
|
||||||
wiki_username,
|
wiki_username,
|
||||||
} = deserialized;
|
} = this;
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
"@context": "https://schema.kosmos.org",
|
"@context": "https://schema.kosmos.org",
|
||||||
@ -80,6 +51,14 @@ class Contributor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gitea_username) {
|
||||||
|
data.accounts.push({
|
||||||
|
"site": "gitea.kosmos.org",
|
||||||
|
"username": gitea_username,
|
||||||
|
"url": `https://gitea.kosmos.org/${gitea_username}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (wiki_username) {
|
if (wiki_username) {
|
||||||
data.accounts.push({
|
data.accounts.push({
|
||||||
"site": "wiki.kosmos.org",
|
"site": "wiki.kosmos.org",
|
||||||
@ -91,6 +70,60 @@ class Contributor {
|
|||||||
// Write it pretty to ipfs
|
// Write it pretty to ipfs
|
||||||
return JSON.stringify(data, null, 2);
|
return JSON.stringify(data, null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate serialized data against schema
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
validate () {
|
||||||
|
const serialized = JSON.parse(this.serialize());
|
||||||
|
const valid = validator.validate(serialized, schemas['contributor']);
|
||||||
|
return valid ? Promise.resolve() : Promise.reject(validator.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize JSON to object
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
static deserialize (serialized) {
|
||||||
|
let {
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
url,
|
||||||
|
accounts,
|
||||||
|
} = JSON.parse(serialized.toString('utf8'));
|
||||||
|
|
||||||
|
let github_username, github_uid, gitea_username, wiki_username;
|
||||||
|
let github = accounts.find(a => a.site === 'github.com');
|
||||||
|
let gitea = accounts.find(a => a.site === 'gitea.kosmos.org');
|
||||||
|
let wiki = accounts.find(a => a.site === 'wiki.kosmos.org');
|
||||||
|
|
||||||
|
if (github) {
|
||||||
|
(({ username: github_username, uid: github_uid} = github));
|
||||||
|
}
|
||||||
|
if (gitea) {
|
||||||
|
(({ username: gitea_username } = gitea));
|
||||||
|
}
|
||||||
|
if (wiki) {
|
||||||
|
(({ username: wiki_username } = wiki));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
url,
|
||||||
|
accounts,
|
||||||
|
github_uid,
|
||||||
|
github_username,
|
||||||
|
gitea_username,
|
||||||
|
wiki_username,
|
||||||
|
ipfsData: serialized,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Contributor;
|
module.exports = Contributor;
|
||||||
|
10
lib/utils/format-kredits.js
Normal file
10
lib/utils/format-kredits.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const ethersUtils = require('ethers').utils;
|
||||||
|
|
||||||
|
module.exports = function (value, options = {}) {
|
||||||
|
let etherValue = ethersUtils.formatEther(value);
|
||||||
|
if (options.asFloat) {
|
||||||
|
return parseFloat(etherValue);
|
||||||
|
} else {
|
||||||
|
return parseInt(etherValue);
|
||||||
|
}
|
||||||
|
}
|
46
lib/utils/pagination.js
Normal file
46
lib/utils/pagination.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
function pageNumber(number, size, recordCount) {
|
||||||
|
let numberOfPages = Math.ceil(recordCount / size);
|
||||||
|
|
||||||
|
number = parseInt(number) || 1;
|
||||||
|
|
||||||
|
// Ensure page number is in range
|
||||||
|
number = number < 1 ? 1 : number;
|
||||||
|
number = number > numberOfPages ? numberOfPages : number;
|
||||||
|
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildIds(order, number, size, recordCount) {
|
||||||
|
let offset = size * (number - 1);
|
||||||
|
|
||||||
|
let start;
|
||||||
|
let mapFunction;
|
||||||
|
|
||||||
|
if (order === 'asc') {
|
||||||
|
start = 1 + offset;
|
||||||
|
mapFunction = (_, i) => start + i;
|
||||||
|
} else {
|
||||||
|
start = recordCount - offset;
|
||||||
|
mapFunction = (_, i) => start - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure size is in range
|
||||||
|
let end = offset + size;
|
||||||
|
if (end > recordCount) {
|
||||||
|
let diff = end - recordCount;
|
||||||
|
size = size - diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from({ length: size }, mapFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function paged(recordCount, options = {}) {
|
||||||
|
let { order, page } = options;
|
||||||
|
order = order || 'desc';
|
||||||
|
page = page || {};
|
||||||
|
|
||||||
|
let size = parseInt(page.size) || 25;
|
||||||
|
let number = pageNumber(page.number, size, recordCount);
|
||||||
|
|
||||||
|
return buildIds(order, number, size, recordCount);
|
||||||
|
};
|
7
package-lock.json
generated
7
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kredits-contracts",
|
"name": "kredits-contracts",
|
||||||
"version": "5.0.0",
|
"version": "5.3.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -11776,8 +11776,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"kosmos-schemas": {
|
"kosmos-schemas": {
|
||||||
"version": "github:67P/kosmos-schemas#28a5e9f1fc2e083165e4e02ce3361c3f4fafa592",
|
"version": "2.0.0",
|
||||||
"from": "github:67P/kosmos-schemas#feature/contribution_date_time",
|
"resolved": "https://registry.npmjs.org/kosmos-schemas/-/kosmos-schemas-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-zIjWcDxaN94m1vPgUaI5LRX6y07Ihw9ScPoGKf1NkZ0sLgD/CRV8YIKRyDafH5mThe3uBN2+F6H6Gp5qhNhALg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brfs-babel": "^1.0.0"
|
"brfs-babel": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kredits-contracts",
|
"name": "kredits-contracts",
|
||||||
"version": "5.0.0",
|
"version": "5.3.0",
|
||||||
"description": "Ethereum contracts and npm wrapper for Kredits",
|
"description": "Ethereum contracts and npm wrapper for Kredits",
|
||||||
"main": "./lib/kredits.js",
|
"main": "./lib/kredits.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@ -52,8 +52,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ethers": "^4.0.27",
|
"ethers": "^4.0.27",
|
||||||
"ipfs-http-client": "^30.1.1",
|
"ipfs-http-client": "^30.1.1",
|
||||||
"kosmos-schemas": "github:67P/kosmos-schemas#feature/contribution_date_time",
|
"kosmos-schemas": "^2.0.0",
|
||||||
"rsvp": "^4.8.2",
|
|
||||||
"tv4": "^1.3.0"
|
"tv4": "^1.3.0"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -26,7 +26,7 @@ module.exports = async function(callback) {
|
|||||||
kind: await prompt('Kind (default person): ', {default: 'person'}),
|
kind: await prompt('Kind (default person): ', {default: 'person'}),
|
||||||
url: await prompt('URL: '),
|
url: await prompt('URL: '),
|
||||||
github_username: await prompt('GitHub username: '),
|
github_username: await prompt('GitHub username: '),
|
||||||
github_uid: await prompt('GitHub UID: '),
|
github_uid: parseInt(await prompt('GitHub UID: ')),
|
||||||
wiki_username: await prompt('Wiki username: '),
|
wiki_username: await prompt('Wiki username: '),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ module.exports = async function(callback) {
|
|||||||
let blockNumber = await kredits.provider.getBlockNumber();
|
let blockNumber = await kredits.provider.getBlockNumber();
|
||||||
let contributions = await kredits.Contribution.all();
|
let contributions = await kredits.Contribution.all();
|
||||||
|
|
||||||
|
console.log(`Current block number: ${blockNumber}`);
|
||||||
contributions.forEach((c) => {
|
contributions.forEach((c) => {
|
||||||
const confirmed = c.confirmedAtBlock <= blockNumber;
|
const confirmed = c.confirmedAtBlock <= blockNumber;
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ module.exports = async function(callback) {
|
|||||||
c.contributorId,
|
c.contributorId,
|
||||||
`${c.description}`,
|
`${c.description}`,
|
||||||
c.amount.toString(),
|
c.amount.toString(),
|
||||||
confirmed,
|
`${confirmed} (${c.confirmedAtBlock})`,
|
||||||
c.vetoed,
|
c.vetoed,
|
||||||
c.claimed,
|
c.claimed,
|
||||||
c.ipfsHash
|
c.ipfsHash
|
||||||
@ -38,6 +39,9 @@ module.exports = async function(callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log(table.toString());
|
console.log(table.toString());
|
||||||
|
|
||||||
|
let totalKreditsEarned = await kredits.Contribution.functions.totalKreditsEarned(true);
|
||||||
|
console.log(`Total confirmed kredits: ${totalKreditsEarned}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -15,24 +15,31 @@ module.exports = async function(callback) {
|
|||||||
|
|
||||||
console.log(`Using Contributor at: ${kredits.Contributor.contract.address}`);
|
console.log(`Using Contributor at: ${kredits.Contributor.contract.address}`);
|
||||||
|
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
head: ['ID', 'Account', 'Name', 'Core?', 'Balance', 'IPFS']
|
head: ['ID', 'Account', 'Name', 'Core?', 'Balance', 'Kredits earned', 'Contributions count', 'IPFS']
|
||||||
})
|
})
|
||||||
|
|
||||||
let contributors = await kredits.Contributor.all()
|
try {
|
||||||
|
const contributors = await kredits.Contributor.all()
|
||||||
|
|
||||||
|
contributors.forEach((c) => {
|
||||||
|
table.push([
|
||||||
|
c.id.toString(),
|
||||||
|
c.account,
|
||||||
|
`${c.name}`,
|
||||||
|
c.isCore,
|
||||||
|
c.balanceInt.toString(),
|
||||||
|
c.totalKreditsEarned.toString(),
|
||||||
|
c.contributionsCount.toString(),
|
||||||
|
c.ipfsHash
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(table.toString())
|
||||||
|
} catch(e) {
|
||||||
|
callback(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
contributors.forEach((c) => {
|
|
||||||
table.push([
|
|
||||||
c.id.toString(),
|
|
||||||
c.account,
|
|
||||||
`${c.name}`,
|
|
||||||
c.isCore,
|
|
||||||
ethers.utils.formatEther(c.balance),
|
|
||||||
c.ipfsHash
|
|
||||||
])
|
|
||||||
})
|
|
||||||
console.log(table.toString())
|
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user