Move contracts to root level for hardhart usage
byebye aragon apps
This commit is contained in:
parent
1425c3664a
commit
a626409221
4
.gitignore
vendored
4
.gitignore
vendored
@ -6,3 +6,7 @@ node_modules
|
|||||||
.tm_properties
|
.tm_properties
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
cache
|
||||||
|
artifacts
|
||||||
|
.openzeppelin
|
||||||
|
204
contracts/Contribution.sol
Normal file
204
contracts/Contribution.sol
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
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);
|
||||||
|
// TODO Maybe use for validation
|
||||||
|
// function exists(uint32 contributorId) public view returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Contribution is Initializable {
|
||||||
|
ContributorInterface public contributorContract;
|
||||||
|
IToken public tokenContract;
|
||||||
|
|
||||||
|
bytes32 public constant ADD_CONTRIBUTION_ROLE = keccak256("ADD_CONTRIBUTION_ROLE");
|
||||||
|
bytes32 public constant VETO_CONTRIBUTION_ROLE = keccak256("VETO_CONTRIBUTION_ROLE");
|
||||||
|
|
||||||
|
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
||||||
|
|
||||||
|
struct ContributionData {
|
||||||
|
uint32 contributorId;
|
||||||
|
uint32 amount;
|
||||||
|
bool claimed;
|
||||||
|
bytes32 hashDigest;
|
||||||
|
uint8 hashFunction;
|
||||||
|
uint8 hashSize;
|
||||||
|
string tokenMetadataURL;
|
||||||
|
uint256 confirmedAtBlock;
|
||||||
|
bool vetoed;
|
||||||
|
bool exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
string internal name_;
|
||||||
|
string internal symbol_;
|
||||||
|
|
||||||
|
// map contribution ID to contributor
|
||||||
|
mapping(uint32 => uint32) public contributionOwner;
|
||||||
|
// map contributor to contribution IDs
|
||||||
|
mapping(uint32 => uint32[]) public ownedContributions;
|
||||||
|
|
||||||
|
mapping(uint32 => ContributionData) public contributions;
|
||||||
|
uint32 public contributionsCount;
|
||||||
|
|
||||||
|
uint32 public blocksToWait;
|
||||||
|
|
||||||
|
event ContributionAdded(uint32 id, uint32 indexed contributorId, uint32 amount);
|
||||||
|
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
|
||||||
|
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
||||||
|
|
||||||
|
function initialize(uint32 blocksToWait_) public initializer {
|
||||||
|
blocksToWait = blocksToWait_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO who can call this when?
|
||||||
|
function setTokenContract(address token) public {
|
||||||
|
tokenContract = IToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO who can call this when?
|
||||||
|
function setContributorContract(address contributor) public {
|
||||||
|
contributorContract = ContributorInterface(contributor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
|
||||||
|
return contributorContract.getContributorIdByAddress(contributorAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorAddressById(uint32 contributorId) public view returns (address) {
|
||||||
|
return contributorContract.getContributorAddressById(contributorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Token standard functions (ERC 721)
|
||||||
|
//
|
||||||
|
|
||||||
|
function name() external view returns (string memory) {
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function symbol() external view returns (string memory) {
|
||||||
|
return symbol_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Balance is amount of ERC271 tokens, not amount of kredits
|
||||||
|
function balanceOf(address owner) public view returns (uint256) {
|
||||||
|
require(owner != address(0));
|
||||||
|
uint32 contributorId = getContributorIdByAddress(owner);
|
||||||
|
return ownedContributions[contributorId].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ownerOf(uint32 contributionId) public view returns (address) {
|
||||||
|
require(exists(contributionId));
|
||||||
|
uint32 contributorId = contributions[contributionId].contributorId;
|
||||||
|
return getContributorAddressById(contributorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenOfOwnerByIndex(address owner, uint32 index) public view returns (uint32) {
|
||||||
|
uint32 contributorId = getContributorIdByAddress(owner);
|
||||||
|
return ownedContributions[contributorId][index];
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenMetadata(uint32 contributionId) public view returns (string memory) {
|
||||||
|
return contributions[contributionId].tokenMetadataURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Custom functions
|
||||||
|
//
|
||||||
|
|
||||||
|
function totalKreditsEarned(bool confirmedOnly) public view returns (uint32 amount) {
|
||||||
|
for (uint32 i = 1; i <= contributionsCount; i++) {
|
||||||
|
ContributionData memory c = contributions[i];
|
||||||
|
if (!c.vetoed && (block.number >= c.confirmedAtBlock || !confirmedOnly)) {
|
||||||
|
amount += c.amount; // should use safemath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) public view returns (uint32 amount) {
|
||||||
|
uint256 tokenCount = ownedContributions[contributorId].length;
|
||||||
|
for (uint256 i = 0; i < tokenCount; i++) {
|
||||||
|
uint32 cId = ownedContributions[contributorId][i];
|
||||||
|
ContributionData memory c = contributions[cId];
|
||||||
|
if (!c.vetoed && (block.number >= c.confirmedAtBlock || !confirmedOnly)) {
|
||||||
|
amount += c.amount; // should use safemath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContribution(uint32 contributionId) public view returns (uint32 id, uint32 contributorId, uint32 amount, bool claimed, 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,
|
||||||
|
c.confirmedAtBlock,
|
||||||
|
c.exists,
|
||||||
|
c.vetoed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public{
|
||||||
|
//require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint32[](0)), 'nope');
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
c.confirmedAtBlock = block.number + 1 + blocksToWait;
|
||||||
|
}
|
||||||
|
|
||||||
|
contributionsCount++;
|
||||||
|
|
||||||
|
contributionOwner[contributionId] = contributorId;
|
||||||
|
ownedContributions[contributorId].push(contributionId);
|
||||||
|
|
||||||
|
emit ContributionAdded(contributionId, contributorId, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function veto(uint32 contributionId) public {
|
||||||
|
ContributionData storage c = contributions[contributionId];
|
||||||
|
require(c.exists, 'NOT_FOUND');
|
||||||
|
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
152
contracts/Contributor.sol
Normal file
152
contracts/Contributor.sol
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||||
|
|
||||||
|
interface ITokenBalance {
|
||||||
|
function balanceOf(address contributorAccount) external view returns (uint256);
|
||||||
|
}
|
||||||
|
interface IContributionBalance {
|
||||||
|
function totalKreditsEarnedByContributor(uint32 contributorId, bool confirmedOnly) external view returns (uint32 amount);
|
||||||
|
function balanceOf(address owner) external view returns (uint256);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Contributor is Initializable {
|
||||||
|
IContributionBalance public contributionContract;
|
||||||
|
ITokenBalance public tokenContract;
|
||||||
|
|
||||||
|
struct Contributor {
|
||||||
|
address account;
|
||||||
|
bytes32 hashDigest;
|
||||||
|
uint8 hashFunction;
|
||||||
|
uint8 hashSize;
|
||||||
|
bool exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping (address => uint32) public contributorIds;
|
||||||
|
mapping (uint32 => Contributor) public contributors;
|
||||||
|
uint32 public contributorsCount;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
function initialize() public initializer {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO who can call this when?
|
||||||
|
function setContributionContract(address contribution) public {
|
||||||
|
contributionContract = IContributionBalance(contribution);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO who can call this when?
|
||||||
|
function setTokenContract(address token) public {
|
||||||
|
tokenContract = ITokenBalance(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
function coreContributorsCount() public view returns (uint32) {
|
||||||
|
uint32 count = 0;
|
||||||
|
for (uint32 i = 1; i <= contributorsCount; i++) {
|
||||||
|
if (isCoreTeam(i)) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public {
|
||||||
|
require(newAccount != address(0), "invalid new account address");
|
||||||
|
require(getContributorAddressById(id) == oldAccount, "contributor does not exist");
|
||||||
|
|
||||||
|
contributorIds[oldAccount] = 0;
|
||||||
|
contributorIds[newAccount] = id;
|
||||||
|
contributors[id].account = newAccount;
|
||||||
|
emit ContributorAccountUpdated(id, oldAccount, newAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
||||||
|
Contributor storage c = contributors[id];
|
||||||
|
bytes32 oldHashDigest = c.hashDigest;
|
||||||
|
c.hashDigest = hashDigest;
|
||||||
|
c.hashFunction = hashFunction;
|
||||||
|
c.hashSize = hashSize;
|
||||||
|
|
||||||
|
ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addContributor(address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
||||||
|
require(!addressExists(account));
|
||||||
|
uint32 _id = contributorsCount + 1;
|
||||||
|
assert(!contributors[_id].exists); // this can not be acually
|
||||||
|
Contributor storage c = contributors[_id];
|
||||||
|
c.exists = true;
|
||||||
|
c.hashDigest = hashDigest;
|
||||||
|
c.hashFunction = hashFunction;
|
||||||
|
c.hashSize = hashSize;
|
||||||
|
c.account = account;
|
||||||
|
contributorIds[account] = _id;
|
||||||
|
|
||||||
|
contributorsCount += 1;
|
||||||
|
emit ContributorAdded(_id, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCoreTeam(uint32 id) view public 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 < 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(uint32 id) view public returns (bool) {
|
||||||
|
return contributors[id].exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addressIsCore(address account) view public returns (bool) {
|
||||||
|
uint32 id = getContributorIdByAddress(account);
|
||||||
|
return isCoreTeam(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addressExists(address account) view public returns (bool) {
|
||||||
|
return getContributorByAddress(account).exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorIdByAddress(address account) view public returns (uint32) {
|
||||||
|
return contributorIds[account];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorAddressById(uint32 id) view public returns (address) {
|
||||||
|
return contributors[id].account;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorByAddress(address account) internal view returns (Contributor memory) {
|
||||||
|
uint32 id = contributorIds[account];
|
||||||
|
return contributors[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorById(uint32 _id) public view returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, uint32 totalKreditsEarned, uint256 contributionsCount, bool exists ) {
|
||||||
|
id = _id;
|
||||||
|
Contributor storage c = contributors[_id];
|
||||||
|
account = c.account;
|
||||||
|
hashDigest = c.hashDigest;
|
||||||
|
hashFunction = c.hashFunction;
|
||||||
|
hashSize = c.hashSize;
|
||||||
|
isCore = isCoreTeam(id);
|
||||||
|
balance = tokenContract.balanceOf(c.account);
|
||||||
|
totalKreditsEarned = contributionContract.totalKreditsEarnedByContributor(_id, true);
|
||||||
|
contributionsCount = contributionContract.balanceOf(c.account);
|
||||||
|
exists = c.exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function canPerform(address _who, address _where, bytes32 _what, uint256[] memory _how) public returns (bool) {
|
||||||
|
address sender = _who;
|
||||||
|
if (sender == address(0)) {
|
||||||
|
sender = tx.origin;
|
||||||
|
}
|
||||||
|
// _what == keccak256('VOTE_PROPOSAL_ROLE')
|
||||||
|
if (_what == 0xd61216798314d2fc33e42ff2021d66707b1e38517d3f7166798a9d3a196a9c96) {
|
||||||
|
return contributorIds[sender] != uint256(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressIsCore(sender);
|
||||||
|
}
|
||||||
|
}
|
@ -1,99 +0,0 @@
|
|||||||
pragma solidity 0.4.24;
|
|
||||||
|
|
||||||
import "@aragon/os/contracts/apps/AragonApp.sol";
|
|
||||||
import "@aragon/os/contracts/kernel/Kernel.sol";
|
|
||||||
import "@aragon/os/contracts/acl/ACL.sol";
|
|
||||||
|
|
||||||
import "@aragon/kits-base/contracts/KitBase.sol";
|
|
||||||
|
|
||||||
import "../apps/contribution/contracts/Contribution.sol";
|
|
||||||
import "../apps/contributor/contracts/Contributor.sol";
|
|
||||||
import "../apps/token/contracts/Token.sol";
|
|
||||||
import "../apps/proposal/contracts/Proposal.sol";
|
|
||||||
import "../apps/reimbursement/contracts/Reimbursement.sol";
|
|
||||||
|
|
||||||
contract KreditsKit is KitBase {
|
|
||||||
|
|
||||||
// ensure alphabetic order
|
|
||||||
enum Apps { Contribution, Contributor, Proposal, Reimbursement, Token }
|
|
||||||
bytes32[5] public appIds;
|
|
||||||
|
|
||||||
event DeployInstance(address dao);
|
|
||||||
event InstalledApp(address dao, address appProxy, bytes32 appId);
|
|
||||||
|
|
||||||
constructor (DAOFactory _fac, ENS _ens, bytes32[5] _appIds) public KitBase(_fac, _ens) {
|
|
||||||
appIds = _appIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
function newInstance() public returns (Kernel dao) {
|
|
||||||
address root = msg.sender;
|
|
||||||
dao = fac.newDAO(this);
|
|
||||||
ACL acl = ACL(dao.acl());
|
|
||||||
|
|
||||||
acl.createPermission(this, dao, dao.APP_MANAGER_ROLE(), this);
|
|
||||||
|
|
||||||
Contributor contributor = Contributor(_installApp(dao, appIds[uint8(Apps.Contributor)]));
|
|
||||||
contributor.initialize(root, appIds);
|
|
||||||
acl.createPermission(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), this);
|
|
||||||
|
|
||||||
Token token = Token(_installApp(dao, appIds[uint8(Apps.Token)]));
|
|
||||||
token.initialize(appIds);
|
|
||||||
|
|
||||||
Contribution contribution = Contribution(_installApp(dao, appIds[uint8(Apps.Contribution)]));
|
|
||||||
contribution.initialize(appIds);
|
|
||||||
|
|
||||||
acl.createPermission(root, contribution, contribution.ADD_CONTRIBUTION_ROLE(), this);
|
|
||||||
acl.createPermission(root, contribution, contribution.VETO_CONTRIBUTION_ROLE(), this);
|
|
||||||
acl.grantPermission(proposal, contribution, contribution.ADD_CONTRIBUTION_ROLE());
|
|
||||||
|
|
||||||
Proposal proposal = Proposal(_installApp(dao, appIds[uint8(Apps.Proposal)]));
|
|
||||||
proposal.initialize(appIds);
|
|
||||||
|
|
||||||
Reimbursement reimbursement = Reimbursement(_installApp(dao, appIds[uint8(Apps.Reimbursement)]));
|
|
||||||
reimbursement.initialize();
|
|
||||||
acl.createPermission(root, reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE(), this);
|
|
||||||
acl.createPermission(root, reimbursement, reimbursement.VETO_REIMBURSEMENT_ROLE(), this);
|
|
||||||
|
|
||||||
uint256[] memory params = new uint256[](1);
|
|
||||||
params[0] = uint256(203) << 248 | uint256(1) << 240 | uint240(contributor);
|
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.ADD_CONTRIBUTION_ROLE(), params);
|
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), contribution, contribution.VETO_CONTRIBUTION_ROLE(), params);
|
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), contributor, contributor.MANAGE_CONTRIBUTORS_ROLE(), params);
|
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE(), params);
|
|
||||||
|
|
||||||
//acl.setPermissionManager(this, proposal, proposal.VOTE_PROPOSAL_ROLE();
|
|
||||||
acl.createPermission(root, proposal, proposal.VOTE_PROPOSAL_ROLE(), this);
|
|
||||||
acl.grantPermissionP(acl.ANY_ENTITY(), proposal, proposal.VOTE_PROPOSAL_ROLE(), params);
|
|
||||||
|
|
||||||
acl.createPermission(root, proposal, proposal.ADD_PROPOSAL_ROLE(), this);
|
|
||||||
//acl.grantPermissionP(address(-1), proposal, proposal.ADD_PROPOSAL_ROLE(), params);
|
|
||||||
acl.grantPermission(acl.ANY_ENTITY(), proposal, proposal.ADD_PROPOSAL_ROLE());
|
|
||||||
|
|
||||||
acl.setPermissionManager(root, proposal, proposal.VOTE_PROPOSAL_ROLE());
|
|
||||||
acl.setPermissionManager(root, proposal, proposal.ADD_PROPOSAL_ROLE());
|
|
||||||
acl.setPermissionManager(root, contribution, contribution.ADD_CONTRIBUTION_ROLE());
|
|
||||||
acl.setPermissionManager(root, contribution, contribution.VETO_CONTRIBUTION_ROLE());
|
|
||||||
acl.setPermissionManager(root, contributor, contributor.MANAGE_CONTRIBUTORS_ROLE());
|
|
||||||
acl.setPermissionManager(root, reimbursement, reimbursement.ADD_REIMBURSEMENT_ROLE());
|
|
||||||
acl.setPermissionManager(root, reimbursement, reimbursement.VETO_REIMBURSEMENT_ROLE());
|
|
||||||
|
|
||||||
acl.createPermission(root, token, token.MINT_TOKEN_ROLE(), this);
|
|
||||||
acl.grantPermission(contribution, token, token.MINT_TOKEN_ROLE());
|
|
||||||
acl.setPermissionManager(root, token, token.MINT_TOKEN_ROLE());
|
|
||||||
|
|
||||||
|
|
||||||
cleanupDAOPermissions(dao, acl, root);
|
|
||||||
|
|
||||||
emit DeployInstance(dao);
|
|
||||||
return dao;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _installApp(Kernel _dao, bytes32 _appId) internal returns (AragonApp) {
|
|
||||||
address baseAppAddress = latestVersionAppBase(_appId);
|
|
||||||
require(baseAppAddress != address(0), "App should be deployed");
|
|
||||||
AragonApp appProxy = AragonApp(_dao.newAppInstance(_appId, baseAppAddress, new bytes(0), true));
|
|
||||||
|
|
||||||
emit InstalledApp(_dao, appProxy, _appId);
|
|
||||||
return appProxy;
|
|
||||||
}
|
|
||||||
}
|
|
89
contracts/Reimbursement.sol
Normal file
89
contracts/Reimbursement.sol
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||||
|
|
||||||
|
contract Reimbursement is Initializable {
|
||||||
|
bytes32 public constant ADD_REIMBURSEMENT_ROLE = keccak256("ADD_REIMBURSEMENT_ROLE");
|
||||||
|
bytes32 public constant VETO_REIMBURSEMENT_ROLE = keccak256("VETO_REIMBURSEMENT_ROLE");
|
||||||
|
// bytes32 public constant MANAGE_APPS_ROLE = keccak256("MANAGE_APPS_ROLE");
|
||||||
|
|
||||||
|
struct ReimbursementData {
|
||||||
|
uint32 recipientId;
|
||||||
|
uint256 amount;
|
||||||
|
address token;
|
||||||
|
bytes32 hashDigest;
|
||||||
|
uint8 hashFunction;
|
||||||
|
uint8 hashSize;
|
||||||
|
uint256 confirmedAtBlock;
|
||||||
|
bool vetoed;
|
||||||
|
bool exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping(uint32 => ReimbursementData) public reimbursements;
|
||||||
|
uint32 public reimbursementsCount;
|
||||||
|
|
||||||
|
uint32 public blocksToWait;
|
||||||
|
|
||||||
|
event ReimbursementAdded(uint32 id, address indexed addedByAccount, uint256 amount);
|
||||||
|
event ReimbursementVetoed(uint32 id, address vetoedByAccount);
|
||||||
|
|
||||||
|
function initialize() public initializer {
|
||||||
|
blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||||
|
}
|
||||||
|
|
||||||
|
function totalAmount(bool confirmedOnly) public view returns (uint256 amount) {
|
||||||
|
for (uint32 i = 1; i <= reimbursementsCount; i++) {
|
||||||
|
ReimbursementData memory r = reimbursements[i];
|
||||||
|
if (!r.vetoed && (block.number >= r.confirmedAtBlock || !confirmedOnly)) {
|
||||||
|
amount += r.amount; // should use safemath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(uint32 reimbursementId) public view returns (uint32 id, uint32 recipientId, uint256 amount, address token, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool exists, bool vetoed) {
|
||||||
|
id = reimbursementId;
|
||||||
|
ReimbursementData storage r = reimbursements[id];
|
||||||
|
return (
|
||||||
|
id,
|
||||||
|
r.recipientId,
|
||||||
|
r.amount,
|
||||||
|
r.token,
|
||||||
|
r.hashDigest,
|
||||||
|
r.hashFunction,
|
||||||
|
r.hashSize,
|
||||||
|
r.confirmedAtBlock,
|
||||||
|
r.exists,
|
||||||
|
r.vetoed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(uint256 amount, address token, uint32 recipientId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
||||||
|
uint32 reimbursementId = reimbursementsCount + 1;
|
||||||
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
|
r.exists = true;
|
||||||
|
r.amount = amount;
|
||||||
|
r.token = token;
|
||||||
|
r.recipientId = recipientId;
|
||||||
|
r.hashDigest = hashDigest;
|
||||||
|
r.hashFunction = hashFunction;
|
||||||
|
r.hashSize = hashSize;
|
||||||
|
r.confirmedAtBlock = block.number + blocksToWait;
|
||||||
|
|
||||||
|
reimbursementsCount++;
|
||||||
|
|
||||||
|
emit ReimbursementAdded(reimbursementId, msg.sender, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function veto(uint32 reimbursementId) public {
|
||||||
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
|
require(r.exists, 'NOT_FOUND');
|
||||||
|
require(block.number < r.confirmedAtBlock, 'VETO_PERIOD_ENDED');
|
||||||
|
r.vetoed = true;
|
||||||
|
|
||||||
|
emit ReimbursementVetoed(reimbursementId, msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(uint32 reimbursementId) public view returns (bool) {
|
||||||
|
return reimbursements[reimbursementId].exists;
|
||||||
|
}
|
||||||
|
}
|
25
contracts/Token.sol
Normal file
25
contracts/Token.sol
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
|
||||||
|
|
||||||
|
contract Token is Initializable, ERC20Upgradeable {
|
||||||
|
using SafeMathUpgradeable for uint256;
|
||||||
|
|
||||||
|
bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
|
||||||
|
|
||||||
|
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
||||||
|
|
||||||
|
function initialize() public virtual initializer {
|
||||||
|
__ERC20_init('Kredits', 'KS');
|
||||||
|
}
|
||||||
|
|
||||||
|
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public {
|
||||||
|
require(amount > 0, "INVALID_AMOUNT");
|
||||||
|
|
||||||
|
uint256 amountInWei = amount.mul(1 ether);
|
||||||
|
_mint(contributorAccount, amountInWei);
|
||||||
|
emit LogMint(contributorAccount, amount, contributionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
pragma solidity 0.4.24;
|
|
||||||
|
|
||||||
import "@aragon/os/contracts/apm/APMNamehash.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract APMNamehashOpen is APMNamehash {
|
|
||||||
bytes32 public constant OPEN_TITLE = keccak256("open");
|
|
||||||
bytes32 public constant OPEN_APM_NODE = keccak256(abi.encodePacked(APM_NODE, OPEN_TITLE));
|
|
||||||
|
|
||||||
function apmNamehashOpen(string name) internal pure returns (bytes32) {
|
|
||||||
return keccak256(abi.encodePacked(OPEN_APM_NODE, keccak256(name)));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
pragma solidity 0.4.24;
|
|
||||||
|
|
||||||
import "@aragon/os/contracts/apps/AragonApp.sol";
|
|
||||||
|
|
||||||
|
|
||||||
// This is a "Dummy" app which's only purpose to exist is because
|
|
||||||
// Aragon's CLI still doesn't support running a Kit inside a project
|
|
||||||
// which isn't considered to be a "valid" Aragon project.
|
|
||||||
// It requires us to have an arrap.json file pointing to the contract
|
|
||||||
// and a manifest.json file which describes the front-end structure.
|
|
||||||
contract DummyApp is AragonApp {
|
|
||||||
function initialize() public onlyInit {
|
|
||||||
initialized();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
pragma solidity ^0.4.4;
|
|
||||||
|
|
||||||
contract Migrations {
|
|
||||||
address public owner;
|
|
||||||
uint public last_completed_migration;
|
|
||||||
|
|
||||||
modifier restricted() {
|
|
||||||
if (msg.sender == owner) _;
|
|
||||||
}
|
|
||||||
|
|
||||||
function constructor() public {
|
|
||||||
owner = msg.sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCompleted(uint completed) public restricted {
|
|
||||||
last_completed_migration = completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgrade(address new_address) public restricted {
|
|
||||||
Migrations upgraded = Migrations(new_address);
|
|
||||||
upgraded.setCompleted(last_completed_migration);
|
|
||||||
}
|
|
||||||
}
|
|
63
hardhat.config.js
Normal file
63
hardhat.config.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
require("@nomiclabs/hardhat-waffle");
|
||||||
|
require('hardhat-deploy');
|
||||||
|
require("hardhat-deploy-ethers");
|
||||||
|
require('@openzeppelin/hardhat-upgrades');
|
||||||
|
|
||||||
|
const promptly = require('promptly');
|
||||||
|
|
||||||
|
// This is a sample Hardhat task. To learn how to create your own go to
|
||||||
|
// https://hardhat.org/guides/create-task.html
|
||||||
|
task("accounts", "Prints the list of accounts", async () => {
|
||||||
|
const accounts = await ethers.getSigners();
|
||||||
|
|
||||||
|
for (const account of accounts) {
|
||||||
|
console.log(account.address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
task('fund', "Send eth to an address", async () => {
|
||||||
|
const to = await promptly.prompt('Address:');
|
||||||
|
const value = await promptly.prompt('Value:');
|
||||||
|
|
||||||
|
const signer = await ethers.getSigners();
|
||||||
|
|
||||||
|
const fundTransaction = await signer[0].sendTransaction({to: to, value: ethers.utils.parseEther(value)});
|
||||||
|
console.log(fundTransaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
task("create-wallet", "Creates a new wallet json", async () => {
|
||||||
|
const wallet = ethers.Wallet.createRandom();
|
||||||
|
|
||||||
|
console.log('New wallet:');
|
||||||
|
console.log(`Address: ${wallet.address}`);
|
||||||
|
console.log(`Public key: ${wallet.publicKey}`);
|
||||||
|
console.log(`Private key: ${wallet.privateKey}`);
|
||||||
|
console.log(`Mnemonic: ${JSON.stringify(wallet.mnemonic)}`);
|
||||||
|
|
||||||
|
const password = await promptly.prompt('Encryption password: ')
|
||||||
|
const encryptedJSON = await wallet.encrypt(password);
|
||||||
|
|
||||||
|
console.log('Encrypted wallet JSON:');
|
||||||
|
console.log(encryptedJSON);
|
||||||
|
});
|
||||||
|
|
||||||
|
// You need to export an object to set up your config
|
||||||
|
// Go to https://hardhat.org/config/ to learn more
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type import('hardhat/config').HardhatUserConfig
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
solidity: "0.8.0",
|
||||||
|
// defaultNetwork: 'localhost',
|
||||||
|
networks: {
|
||||||
|
hardhat: {
|
||||||
|
chainId: 1337
|
||||||
|
}
|
||||||
|
},
|
||||||
|
namedAccounts: {
|
||||||
|
deployer: {
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
8
lib/addresses.json
Normal file
8
lib/addresses.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"1337": {
|
||||||
|
"Contributor": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07",
|
||||||
|
"Contribution": "0x922D6956C99E12DFeB3224DEA977D0939758A1Fe",
|
||||||
|
"Token": "0x5081a39b8A5f0E35a8D959395a630b68B74Dd30f",
|
||||||
|
"Reimbursement": "0x1fA02b2d6A771842690194Cf62D91bdd92BfE28d"
|
||||||
|
}
|
||||||
|
}
|
@ -7,20 +7,15 @@ const ABIS = {
|
|||||||
Contributor: require('./abis/Contributor.json'),
|
Contributor: require('./abis/Contributor.json'),
|
||||||
Contribution: require('./abis/Contribution.json'),
|
Contribution: require('./abis/Contribution.json'),
|
||||||
Reimbursement: require('./abis/Reimbursement.json'),
|
Reimbursement: require('./abis/Reimbursement.json'),
|
||||||
Token: require('./abis/Token.json'),
|
Token: require('./abis/Token.json')
|
||||||
Proposal: require('./abis/Proposal.json'),
|
|
||||||
Kernel: require('./abis/Kernel.json'),
|
|
||||||
Acl: require('./abis/ACL.json'),
|
|
||||||
};
|
};
|
||||||
const APP_CONTRACTS = [
|
const APP_CONTRACTS = [
|
||||||
'Contributor',
|
'Contributor',
|
||||||
'Contribution',
|
'Contribution',
|
||||||
'Token',
|
'Token',
|
||||||
'Proposal',
|
'Reimbursement'
|
||||||
'Reimbursement',
|
|
||||||
'Acl',
|
|
||||||
];
|
];
|
||||||
const DaoAddresses = require('./addresses/dao.json');
|
const Addresses = require('./addresses.json');
|
||||||
|
|
||||||
const Contracts = require('./contracts');
|
const Contracts = require('./contracts');
|
||||||
const IPFS = require('./utils/ipfs');
|
const IPFS = require('./utils/ipfs');
|
||||||
@ -48,18 +43,9 @@ class Kredits {
|
|||||||
init (names) {
|
init (names) {
|
||||||
let contractsToLoad = names || APP_CONTRACTS;
|
let contractsToLoad = names || APP_CONTRACTS;
|
||||||
return this.provider.getNetwork().then(network => {
|
return this.provider.getNetwork().then(network => {
|
||||||
this.addresses['Kernel'] = this.addresses['Kernel'] || DaoAddresses[network.chainId.toString()];
|
if (Object.keys(this.addresses).length === 0) {
|
||||||
let addressPromises = contractsToLoad.map((contractName) => {
|
this.addresses = Addresses[network.chainId.toString()];
|
||||||
return this.Kernel.getApp(contractName).then((address) => {
|
}
|
||||||
this.addresses[contractName] = address;
|
|
||||||
}).catch((error) => {
|
|
||||||
throw new Error(`Failed to get address for ${contractName} from DAO at ${this.Kernel.contract.address}
|
|
||||||
- ${error.message}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(addressPromises).then(() => { return this; });
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,16 +72,7 @@ class Kredits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static availableNetworks () {
|
static availableNetworks () {
|
||||||
return Object.keys(DaoAddresses);
|
return Object.keys(Addresses);
|
||||||
}
|
|
||||||
|
|
||||||
get Kernel () {
|
|
||||||
let k = this.contractFor('Kernel');
|
|
||||||
// in case we want to use a special apm (e.g. development vs. production)
|
|
||||||
if (this.options.apm) {
|
|
||||||
k.apm = this.options.apm;
|
|
||||||
}
|
|
||||||
return k;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get Contributor () {
|
get Contributor () {
|
||||||
@ -107,10 +84,6 @@ class Kredits {
|
|||||||
return this.Contributor;
|
return this.Contributor;
|
||||||
}
|
}
|
||||||
|
|
||||||
get Proposal () {
|
|
||||||
return this.contractFor('Proposal');
|
|
||||||
}
|
|
||||||
|
|
||||||
get Operator () {
|
get Operator () {
|
||||||
return this.Proposal;
|
return this.Proposal;
|
||||||
}
|
}
|
||||||
@ -127,10 +100,6 @@ class Kredits {
|
|||||||
return this.contractFor('Reimbursement');
|
return this.contractFor('Reimbursement');
|
||||||
}
|
}
|
||||||
|
|
||||||
get Acl () {
|
|
||||||
return this.contractFor('Acl');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be private
|
// Should be private
|
||||||
contractFor (name) {
|
contractFor (name) {
|
||||||
if (this.contracts[name]) {
|
if (this.contracts[name]) {
|
||||||
|
16038
package-lock.json
generated
16038
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@ -42,8 +42,10 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/67P/truffle-kredits#readme",
|
"homepage": "https://github.com/67P/truffle-kredits#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aragon/kits-base": "^1.0.0",
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
"@aragon/os": "^4.4.0",
|
"@nomiclabs/hardhat-waffle": "^2.0.0",
|
||||||
|
"@openzeppelin/contracts-upgradeable": "^4.1.0",
|
||||||
|
"@openzeppelin/hardhat-upgrades": "^1.8.2",
|
||||||
"async-each-series": "^1.1.0",
|
"async-each-series": "^1.1.0",
|
||||||
"cli-table": "^0.3.1",
|
"cli-table": "^0.3.1",
|
||||||
"eslint": "^7.1.0",
|
"eslint": "^7.1.0",
|
||||||
@ -52,12 +54,14 @@
|
|||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eth-provider": "^0.2.5",
|
"eth-provider": "^0.2.5",
|
||||||
"ethereum-block-by-date": "^1.4.0",
|
"ethereum-block-by-date": "^1.4.0",
|
||||||
|
"ethereum-waffle": "^3.3.0",
|
||||||
|
"hardhat": "^2.0.3",
|
||||||
|
"hardhat-deploy": "^0.7.0-beta.35",
|
||||||
|
"hardhat-deploy-ethers": "^0.3.0-beta.7",
|
||||||
"homedir": "^0.6.0",
|
"homedir": "^0.6.0",
|
||||||
"promptly": "^3.0.3",
|
"promptly": "^3.0.3",
|
||||||
"solc": "^0.6.8",
|
"solc": "^0.6.8",
|
||||||
"solhint": "^2.3.1",
|
"solhint": "^2.3.1",
|
||||||
"truffle-hdwallet-provider": "^1.0.17",
|
|
||||||
"truffle-hdwallet-provider-privkey": "^0.3.0",
|
|
||||||
"yargs": "^15.0.0"
|
"yargs": "^15.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
const promptly = require('promptly');
|
const promptly = require('promptly');
|
||||||
const { inspect } = require('util');
|
const { inspect } = require('util');
|
||||||
|
|
||||||
const initKredits = require('./helpers/init_kredits.js');
|
const { ethers } = require("hardhat");
|
||||||
|
const Kredits = require('../lib/kredits');
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
async function main() {
|
||||||
let kredits;
|
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||||
try {
|
await kredits.init();
|
||||||
kredits = await initKredits(web3);
|
|
||||||
} catch(e) {
|
|
||||||
callback(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Using Contributions at: ${kredits.Contribution.contract.address}`);
|
console.log(`Using Contributions at: ${kredits.Contribution.contract.address}`);
|
||||||
|
|
||||||
@ -49,10 +45,11 @@ module.exports = async function(callback) {
|
|||||||
.then(result => {
|
.then(result => {
|
||||||
console.log("\n\nResult:");
|
console.log("\n\nResult:");
|
||||||
console.log(result);
|
console.log(result);
|
||||||
callback();
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log('Failed to create contribution');
|
console.log('Failed to create contribution');
|
||||||
callback(inspect(error));
|
console.log(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const promptly = require('promptly');
|
const promptly = require('promptly');
|
||||||
|
|
||||||
const initKredits = require('./helpers/init_kredits.js');
|
const { ethers } = require("hardhat");
|
||||||
|
const Kredits = require('../lib/kredits');
|
||||||
|
|
||||||
async function prompt(message, options) {
|
async function prompt(message, options) {
|
||||||
if (!options) {
|
if (!options) {
|
||||||
@ -8,15 +9,9 @@ async function prompt(message, options) {
|
|||||||
}
|
}
|
||||||
return await promptly.prompt(message, options);
|
return await promptly.prompt(message, options);
|
||||||
}
|
}
|
||||||
|
async function main() {
|
||||||
module.exports = async function(callback) {
|
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||||
let kredits;
|
await kredits.init();
|
||||||
try {
|
|
||||||
kredits = await initKredits(web3);
|
|
||||||
} catch(e) {
|
|
||||||
callback(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Using contributors at: ${kredits.Contributor.contract.address}`);
|
console.log(`Using contributors at: ${kredits.Contributor.contract.address}`);
|
||||||
|
|
||||||
@ -36,9 +31,10 @@ module.exports = async function(callback) {
|
|||||||
kredits.Contributor.add(contributorAttributes, { gasLimit: 350000 }).then((result) => {
|
kredits.Contributor.add(contributorAttributes, { gasLimit: 350000 }).then((result) => {
|
||||||
console.log("\n\nResult:");
|
console.log("\n\nResult:");
|
||||||
console.log(result);
|
console.log(result);
|
||||||
callback();
|
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.log('Failed to create contributor');
|
console.log('Failed to create contributor');
|
||||||
callback(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
53
scripts/create-proxy.js
Normal file
53
scripts/create-proxy.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
const { ethers, upgrades } = require("hardhat");
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fileInject = require('./helpers/file_inject.js');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const network = await hre.ethers.provider.getNetwork();
|
||||||
|
const networkId = network.chainId;
|
||||||
|
console.log(`Deploying to network #${networkId}`);
|
||||||
|
|
||||||
|
const Contributor = await ethers.getContractFactory("Contributor");
|
||||||
|
const Contribution = await ethers.getContractFactory("Contribution");
|
||||||
|
const Token = await ethers.getContractFactory("Token");
|
||||||
|
const Reimbursement = await ethers.getContractFactory("Reimbursement");
|
||||||
|
|
||||||
|
const contributor = await upgrades.deployProxy(Contributor, []);
|
||||||
|
await contributor.deployed();
|
||||||
|
console.log("Contributor deployed to:", contributor.address);
|
||||||
|
|
||||||
|
const blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||||
|
const contribution = await upgrades.deployProxy(Contribution, [blocksToWait]);
|
||||||
|
await contribution.deployed();
|
||||||
|
console.log("Contribution deployed to:", contribution.address);
|
||||||
|
|
||||||
|
const token = await upgrades.deployProxy(Token, []);
|
||||||
|
await token.deployed();
|
||||||
|
console.log("Token deployed to:", token.address);
|
||||||
|
|
||||||
|
const reimbursement = await upgrades.deployProxy(Reimbursement, []);
|
||||||
|
await reimbursement.deployed();
|
||||||
|
console.log("Reimbursement deployed to:", reimbursement.address);
|
||||||
|
|
||||||
|
await contributor.setTokenContract(token.address);
|
||||||
|
await contributor.setContributionContract(contribution.address);
|
||||||
|
|
||||||
|
await contribution.setTokenContract(token.address);
|
||||||
|
await contribution.setContributorContract(contributor.address);
|
||||||
|
|
||||||
|
const c = await contributor.contributionContract();
|
||||||
|
console.log(c);
|
||||||
|
|
||||||
|
const addresses = {
|
||||||
|
Contributor: contributor.address,
|
||||||
|
Contribution: contribution.address,
|
||||||
|
Token: token.address,
|
||||||
|
Reimbursement: reimbursement.address
|
||||||
|
};
|
||||||
|
|
||||||
|
const libPath = path.join(__dirname, '..', 'lib');
|
||||||
|
fileInject(path.join(libPath, 'addresses.json'), networkId, addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
@ -1,16 +1,13 @@
|
|||||||
const promptly = require('promptly');
|
const promptly = require('promptly');
|
||||||
const Table = require('cli-table');
|
const Table = require('cli-table');
|
||||||
|
|
||||||
const initKredits = require('./helpers/init_kredits.js');
|
const { ethers } = require("hardhat");
|
||||||
|
const Kredits = require('../lib/kredits');
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
async function main() {
|
||||||
let kredits;
|
let kredits;
|
||||||
try {
|
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||||
kredits = await initKredits(web3);
|
await kredits.init();
|
||||||
} catch(e) {
|
|
||||||
callback(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
console.log(`Using Contribution at: ${kredits.Contribution.contract.address}`);
|
||||||
|
|
||||||
@ -47,6 +44,6 @@ module.exports = async function(callback) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
const promptly = require('promptly');
|
const promptly = require('promptly');
|
||||||
const Table = require('cli-table');
|
const Table = require('cli-table');
|
||||||
const ethers = require('ethers');
|
|
||||||
|
|
||||||
const initKredits = require('./helpers/init_kredits.js');
|
const { ethers } = require("hardhat");
|
||||||
|
const Kredits = require('../lib/kredits');
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
async function main() {
|
||||||
let kredits;
|
let kredits;
|
||||||
try {
|
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
|
||||||
kredits = await initKredits(web3);
|
await kredits.init();
|
||||||
} catch(e) {
|
|
||||||
callback(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Using Contributor at: ${kredits.Contributor.contract.address}`);
|
console.log(`Using Contributor at: ${kredits.Contributor.contract.address}`);
|
||||||
|
|
||||||
@ -19,27 +15,22 @@ module.exports = async function(callback) {
|
|||||||
head: ['ID', 'Account', 'Name', 'Core?', 'Balance', 'Kredits earned', 'Contributions count', 'IPFS']
|
head: ['ID', 'Account', 'Name', 'Core?', 'Balance', 'Kredits earned', 'Contributions count', 'IPFS']
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
const contributors = await kredits.Contributor.all()
|
||||||
const contributors = await kredits.Contributor.all()
|
|
||||||
|
|
||||||
contributors.forEach((c) => {
|
contributors.forEach((c) => {
|
||||||
table.push([
|
table.push([
|
||||||
c.id.toString(),
|
c.id.toString(),
|
||||||
c.account,
|
c.account,
|
||||||
`${c.name}`,
|
`${c.name}`,
|
||||||
c.isCore,
|
c.isCore,
|
||||||
c.balanceInt.toString(),
|
c.balanceInt.toString(),
|
||||||
c.totalKreditsEarned.toString(),
|
c.totalKreditsEarned.toString(),
|
||||||
c.contributionsCount.toString(),
|
c.contributionsCount.toString(),
|
||||||
c.ipfsHash
|
c.ipfsHash
|
||||||
])
|
])
|
||||||
})
|
});
|
||||||
|
|
||||||
console.log(table.toString())
|
console.log(table.toString());
|
||||||
} catch(e) {
|
|
||||||
callback(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user