Permissions
This commit is contained in:
parent
623cf6d6da
commit
ffd4a5aeaf
@ -9,6 +9,7 @@ interface IToken {
|
|||||||
interface ContributorInterface {
|
interface ContributorInterface {
|
||||||
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||||
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||||
|
function addressIsCore(address sender) external view returns (bool);
|
||||||
// TODO Maybe use for validation
|
// TODO Maybe use for validation
|
||||||
// function exists(uint32 contributorId) public view returns (bool);
|
// function exists(uint32 contributorId) public view returns (bool);
|
||||||
}
|
}
|
||||||
@ -17,11 +18,6 @@ contract Contribution is Initializable {
|
|||||||
ContributorInterface public contributorContract;
|
ContributorInterface public contributorContract;
|
||||||
IToken public tokenContract;
|
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 {
|
struct ContributionData {
|
||||||
uint32 contributorId;
|
uint32 contributorId;
|
||||||
uint32 amount;
|
uint32 amount;
|
||||||
@ -52,17 +48,22 @@ contract Contribution is Initializable {
|
|||||||
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
|
event ContributionClaimed(uint32 id, uint32 indexed contributorId, uint32 amount);
|
||||||
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
event ContributionVetoed(uint32 id, address vetoedByAccount);
|
||||||
|
|
||||||
|
modifier onlyCore {
|
||||||
|
require(contributorContract.addressIsCore(msg.sender), "Core only");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
function initialize(uint32 blocksToWait_) public initializer {
|
function initialize(uint32 blocksToWait_) public initializer {
|
||||||
blocksToWait = blocksToWait_;
|
blocksToWait = blocksToWait_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO who can call this when?
|
|
||||||
function setTokenContract(address token) public {
|
function setTokenContract(address token) public {
|
||||||
|
require(address(tokenContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||||
tokenContract = IToken(token);
|
tokenContract = IToken(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO who can call this when?
|
|
||||||
function setContributorContract(address contributor) public {
|
function setContributorContract(address contributor) public {
|
||||||
|
require(address(contributorContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||||
contributorContract = ContributorInterface(contributor);
|
contributorContract = ContributorInterface(contributor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +152,7 @@ contract Contribution is Initializable {
|
|||||||
|
|
||||||
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public{
|
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(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint32[](0)), 'nope');
|
||||||
|
require(balanceOf(msg.sender) > 0, "Must have Kredits");
|
||||||
uint32 contributionId = contributionsCount + 1;
|
uint32 contributionId = contributionsCount + 1;
|
||||||
ContributionData storage c = contributions[contributionId];
|
ContributionData storage c = contributions[contributionId];
|
||||||
c.exists = true;
|
c.exists = true;
|
||||||
@ -174,7 +176,8 @@ contract Contribution is Initializable {
|
|||||||
emit ContributionAdded(contributionId, contributorId, amount);
|
emit ContributionAdded(contributionId, contributorId, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function veto(uint32 contributionId) public {
|
function veto(uint32 contributionId) public onlyCore {
|
||||||
|
|
||||||
ContributionData storage c = contributions[contributionId];
|
ContributionData storage c = contributions[contributionId];
|
||||||
require(c.exists, 'NOT_FOUND');
|
require(c.exists, 'NOT_FOUND');
|
||||||
require(!c.claimed, 'ALREADY_CLAIMED');
|
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||||
@ -201,4 +204,5 @@ contract Contribution is Initializable {
|
|||||||
function exists(uint32 contributionId) public view returns (bool) {
|
function exists(uint32 contributionId) public view returns (bool) {
|
||||||
return contributions[contributionId].exists;
|
return contributions[contributionId].exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ interface IContributionBalance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contract Contributor is Initializable {
|
contract Contributor is Initializable {
|
||||||
|
address deployer;
|
||||||
IContributionBalance public contributionContract;
|
IContributionBalance public contributionContract;
|
||||||
ITokenBalance public tokenContract;
|
ITokenBalance public tokenContract;
|
||||||
|
|
||||||
@ -30,18 +31,22 @@ contract Contributor is Initializable {
|
|||||||
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
|
event ContributorAccountUpdated(uint32 id, address oldAccount, address newAccount);
|
||||||
event ContributorAdded(uint32 id, address account);
|
event ContributorAdded(uint32 id, address account);
|
||||||
|
|
||||||
|
modifier onlyCore {
|
||||||
function initialize() public initializer {
|
require(addressIsCore(msg.sender), "Core only");
|
||||||
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO who can call this when?
|
function initialize() public initializer {
|
||||||
function setContributionContract(address contribution) public {
|
deployer = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setContributionContract(address contribution) public onlyCore {
|
||||||
|
require(address(contributionContract) == address(0) || addressIsCore(msg.sender), "Core only");
|
||||||
contributionContract = IContributionBalance(contribution);
|
contributionContract = IContributionBalance(contribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO who can call this when?
|
function setTokenContract(address token) public onlyCore {
|
||||||
function setTokenContract(address token) public {
|
require(address(tokenContract) == address(0) || addressIsCore(msg.sender), "Core only");
|
||||||
tokenContract = ITokenBalance(token);
|
tokenContract = ITokenBalance(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +60,7 @@ contract Contributor is Initializable {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public {
|
function updateContributorAccount(uint32 id, address oldAccount, address newAccount) public onlyCore {
|
||||||
require(newAccount != address(0), "invalid new account address");
|
require(newAccount != address(0), "invalid new account address");
|
||||||
require(getContributorAddressById(id) == oldAccount, "contributor does not exist");
|
require(getContributorAddressById(id) == oldAccount, "contributor does not exist");
|
||||||
|
|
||||||
@ -65,7 +70,7 @@ contract Contributor is Initializable {
|
|||||||
emit ContributorAccountUpdated(id, oldAccount, newAccount);
|
emit ContributorAccountUpdated(id, oldAccount, newAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
function updateContributorProfileHash(uint32 id, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public onlyCore {
|
||||||
Contributor storage c = contributors[id];
|
Contributor storage c = contributors[id];
|
||||||
bytes32 oldHashDigest = c.hashDigest;
|
bytes32 oldHashDigest = c.hashDigest;
|
||||||
c.hashDigest = hashDigest;
|
c.hashDigest = hashDigest;
|
||||||
@ -75,7 +80,7 @@ contract Contributor is Initializable {
|
|||||||
ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
|
ContributorProfileUpdated(id, oldHashDigest, c.hashDigest);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addContributor(address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
function addContributor(address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public onlyCore {
|
||||||
require(!addressExists(account));
|
require(!addressExists(account));
|
||||||
uint32 _id = contributorsCount + 1;
|
uint32 _id = contributorsCount + 1;
|
||||||
assert(!contributors[_id].exists); // this can not be acually
|
assert(!contributors[_id].exists); // this can not be acually
|
||||||
@ -94,7 +99,7 @@ contract Contributor is Initializable {
|
|||||||
function isCoreTeam(uint32 id) view public returns (bool) {
|
function isCoreTeam(uint32 id) view public returns (bool) {
|
||||||
// TODO: for simplicity we simply define the first contributors as core
|
// TODO: for simplicity we simply define the first contributors as core
|
||||||
// later this needs to be changed to something more dynamic
|
// later this needs to be changed to something more dynamic
|
||||||
return id < 7;
|
return id > 1 && id < 7 || msg.sender == deployer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function exists(uint32 id) view public returns (bool) {
|
function exists(uint32 id) view public returns (bool) {
|
||||||
@ -137,16 +142,4 @@ contract Contributor is Initializable {
|
|||||||
exists = c.exists;
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,16 @@ pragma solidity ^0.8.0;
|
|||||||
|
|
||||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||||
|
|
||||||
|
interface ContributorInterface {
|
||||||
|
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||||
|
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||||
|
function addressIsCore(address sender) external view returns (bool);
|
||||||
|
// TODO Maybe use for validation
|
||||||
|
// function exists(uint32 contributorId) public view returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
contract Reimbursement is Initializable {
|
contract Reimbursement is Initializable {
|
||||||
bytes32 public constant ADD_REIMBURSEMENT_ROLE = keccak256("ADD_REIMBURSEMENT_ROLE");
|
ContributorInterface public contributorContract;
|
||||||
bytes32 public constant VETO_REIMBURSEMENT_ROLE = keccak256("VETO_REIMBURSEMENT_ROLE");
|
|
||||||
// bytes32 public constant MANAGE_APPS_ROLE = keccak256("MANAGE_APPS_ROLE");
|
|
||||||
|
|
||||||
struct ReimbursementData {
|
struct ReimbursementData {
|
||||||
uint32 recipientId;
|
uint32 recipientId;
|
||||||
@ -31,6 +37,24 @@ contract Reimbursement is Initializable {
|
|||||||
blocksToWait = 40320; // 7 days; 15 seconds block time
|
blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modifier onlyCore {
|
||||||
|
require(contributorContract.addressIsCore(msg.sender), "Core only");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setContributorContract(address contributor) public {
|
||||||
|
require(address(contributorContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||||
|
contributorContract = ContributorInterface(contributor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorIdByAddress(address contributorAccount) public view returns (uint32) {
|
||||||
|
return contributorContract.getContributorIdByAddress(contributorAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContributorAddressById(uint32 contributorId) public view returns (address) {
|
||||||
|
return contributorContract.getContributorAddressById(contributorId);
|
||||||
|
}
|
||||||
|
|
||||||
function totalAmount(bool confirmedOnly) public view returns (uint256 amount) {
|
function totalAmount(bool confirmedOnly) public view returns (uint256 amount) {
|
||||||
for (uint32 i = 1; i <= reimbursementsCount; i++) {
|
for (uint32 i = 1; i <= reimbursementsCount; i++) {
|
||||||
ReimbursementData memory r = reimbursements[i];
|
ReimbursementData memory r = reimbursements[i];
|
||||||
@ -57,7 +81,7 @@ contract Reimbursement is Initializable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(uint256 amount, address token, uint32 recipientId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public {
|
function add(uint256 amount, address token, uint32 recipientId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public onlyCore {
|
||||||
uint32 reimbursementId = reimbursementsCount + 1;
|
uint32 reimbursementId = reimbursementsCount + 1;
|
||||||
ReimbursementData storage r = reimbursements[reimbursementId];
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
r.exists = true;
|
r.exists = true;
|
||||||
@ -74,7 +98,7 @@ contract Reimbursement is Initializable {
|
|||||||
emit ReimbursementAdded(reimbursementId, msg.sender, amount);
|
emit ReimbursementAdded(reimbursementId, msg.sender, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function veto(uint32 reimbursementId) public {
|
function veto(uint32 reimbursementId) public onlyCore {
|
||||||
ReimbursementData storage r = reimbursements[reimbursementId];
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
require(r.exists, 'NOT_FOUND');
|
require(r.exists, 'NOT_FOUND');
|
||||||
require(block.number < r.confirmedAtBlock, 'VETO_PERIOD_ENDED');
|
require(block.number < r.confirmedAtBlock, 'VETO_PERIOD_ENDED');
|
||||||
|
@ -3,10 +3,19 @@ pragma solidity ^0.8.0;
|
|||||||
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
|
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
|
||||||
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
|
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
|
||||||
|
|
||||||
|
interface ContributorInterface {
|
||||||
|
function getContributorAddressById(uint32 contributorId) external view returns (address);
|
||||||
|
function getContributorIdByAddress(address contributorAccount) external view returns (uint32);
|
||||||
|
function addressIsCore(address sender) external view returns (bool);
|
||||||
|
// TODO Maybe use for validation
|
||||||
|
// function exists(uint32 contributorId) public view returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
contract Token is Initializable, ERC20Upgradeable {
|
contract Token is Initializable, ERC20Upgradeable {
|
||||||
|
ContributorInterface public contributorContract;
|
||||||
using SafeMathUpgradeable for uint256;
|
using SafeMathUpgradeable for uint256;
|
||||||
|
|
||||||
bytes32 public constant MINT_TOKEN_ROLE = keccak256("MINT_TOKEN_ROLE");
|
address public contributionContract;
|
||||||
|
|
||||||
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
event LogMint(address indexed recipient, uint256 amount, uint32 contributionId);
|
||||||
|
|
||||||
@ -14,7 +23,17 @@ contract Token is Initializable, ERC20Upgradeable {
|
|||||||
__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 setContributorContract(address contributor) public {
|
||||||
|
require(address(contributorContract) == address(0) || contributorContract.addressIsCore(msg.sender), "Core only");
|
||||||
|
contributorContract = ContributorInterface(contributor);
|
||||||
|
}
|
||||||
|
|
||||||
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public {
|
function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public {
|
||||||
|
require(contributionContract == msg.sender, "Only Contribution");
|
||||||
require(amount > 0, "INVALID_AMOUNT");
|
require(amount > 0, "INVALID_AMOUNT");
|
||||||
|
|
||||||
uint256 amountInWei = amount.mul(1 ether);
|
uint256 amountInWei = amount.mul(1 ether);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const { ethers, upgrades } = require("hardhat");
|
const { ethers, upgrades } = require("hardhat");
|
||||||
|
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
const fileInject = require('./helpers/file_inject.js');
|
const fileInject = require("./helpers/file_inject.js");
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const network = await hre.ethers.provider.getNetwork();
|
const network = await hre.ethers.provider.getNetwork();
|
||||||
@ -16,19 +16,27 @@ async function main() {
|
|||||||
const contributor = await upgrades.deployProxy(Contributor, []);
|
const contributor = await upgrades.deployProxy(Contributor, []);
|
||||||
await contributor.deployed();
|
await contributor.deployed();
|
||||||
console.log("Contributor deployed to:", contributor.address);
|
console.log("Contributor deployed to:", contributor.address);
|
||||||
|
console.log("...waiting for 1 confirmation");
|
||||||
|
await contributor.deployTransaction.wait();
|
||||||
|
|
||||||
const blocksToWait = 40320; // 7 days; 15 seconds block time
|
const blocksToWait = 40320; // 7 days; 15 seconds block time
|
||||||
const contribution = await upgrades.deployProxy(Contribution, [blocksToWait]);
|
const contribution = await upgrades.deployProxy(Contribution, [blocksToWait]);
|
||||||
await contribution.deployed();
|
await contribution.deployed();
|
||||||
console.log("Contribution deployed to:", contribution.address);
|
console.log("Contribution deployed to:", contribution.address);
|
||||||
|
console.log("...waiting for 1 confirmation");
|
||||||
|
await contribution.deployTransaction.wait();
|
||||||
|
|
||||||
const token = await upgrades.deployProxy(Token, []);
|
const token = await upgrades.deployProxy(Token, []);
|
||||||
await token.deployed();
|
await token.deployed();
|
||||||
console.log("Token deployed to:", token.address);
|
console.log("Token deployed to:", token.address);
|
||||||
|
console.log("...waiting for 1 confirmation");
|
||||||
|
await token.deployTransaction.wait();
|
||||||
|
|
||||||
const reimbursement = await upgrades.deployProxy(Reimbursement, []);
|
const reimbursement = await upgrades.deployProxy(Reimbursement, []);
|
||||||
await reimbursement.deployed();
|
await reimbursement.deployed();
|
||||||
console.log("Reimbursement deployed to:", reimbursement.address);
|
console.log("Reimbursement deployed to:", reimbursement.address);
|
||||||
|
console.log("...waiting for 1 confirmation");
|
||||||
|
await reimbursement.deployTransaction.wait();
|
||||||
|
|
||||||
await contributor.setTokenContract(token.address);
|
await contributor.setTokenContract(token.address);
|
||||||
await contributor.setContributionContract(contribution.address);
|
await contributor.setContributionContract(contribution.address);
|
||||||
@ -36,6 +44,11 @@ async function main() {
|
|||||||
await contribution.setTokenContract(token.address);
|
await contribution.setTokenContract(token.address);
|
||||||
await contribution.setContributorContract(contributor.address);
|
await contribution.setContributorContract(contributor.address);
|
||||||
|
|
||||||
|
await token.setContributionContract(contribution.address);
|
||||||
|
await token.setContributorContract(contributor.address);
|
||||||
|
|
||||||
|
await reimbursement.setContributorContract(contributor.address);
|
||||||
|
|
||||||
const c = await contributor.contributionContract();
|
const c = await contributor.contributionContract();
|
||||||
console.log(c);
|
console.log(c);
|
||||||
|
|
||||||
@ -43,11 +56,11 @@ async function main() {
|
|||||||
Contributor: contributor.address,
|
Contributor: contributor.address,
|
||||||
Contribution: contribution.address,
|
Contribution: contribution.address,
|
||||||
Token: token.address,
|
Token: token.address,
|
||||||
Reimbursement: reimbursement.address
|
Reimbursement: reimbursement.address,
|
||||||
};
|
};
|
||||||
|
|
||||||
const libPath = path.join(__dirname, '..', 'lib');
|
const libPath = path.join(__dirname, "..", "lib");
|
||||||
fileInject(path.join(libPath, 'addresses.json'), networkId, addresses);
|
fileInject(path.join(libPath, "addresses.json"), networkId, addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user