Compare commits

...

11 Commits

Author SHA1 Message Date
Râu Cao
f0a71ca8f1 7.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-13 21:01:34 +02:00
Râu Cao
117918e66f Remove obsolete npm scripts 2023-08-13 20:59:09 +02:00
d0d456b357 Merge pull request 'Migrate to proper RSK testnet deployment' (#242) from new-final-deploy into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #242
2023-08-13 18:54:35 +00:00
cda84fa2ce Add support to start the contribution import from a specific id
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-08-13 14:46:48 +02:00
97e2db93be Add reimbursement import 2023-08-13 14:46:48 +02:00
17c582f6df Add export script for reimbursements 2023-08-13 14:46:48 +02:00
Râu Cao
914d4d9585 Update hardhat config
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-07 23:06:40 +02:00
Râu Cao
0deeba14fc Upgrade testnet contribution contract, reinit contributor contract 2023-08-07 23:05:38 +02:00
Râu Cao
c61632d949 Resolve some solhint errors and warnings 2023-08-07 23:05:15 +02:00
Râu Cao
0b593ec795 Merge branch 'master' into new-final-deploy 2023-08-07 22:07:45 +02:00
Râu Cao
401c528e95 Ignore .env 2023-08-07 22:06:42 +02:00
13 changed files with 332 additions and 38 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ data
cache cache
artifacts artifacts
.openzeppelin/unknown-1337.json .openzeppelin/unknown-1337.json
.env

View File

@@ -86,7 +86,7 @@
"label": "contributionContract", "label": "contributionContract",
"offset": 0, "offset": 0,
"slot": "1", "slot": "1",
"type": "t_contract(IContributionBalance)2236", "type": "t_contract(IContributionBalance)2238",
"contract": "Contributor", "contract": "Contributor",
"src": "contracts/Contributor.sol:16" "src": "contracts/Contributor.sol:16"
}, },
@@ -94,7 +94,7 @@
"label": "tokenContract", "label": "tokenContract",
"offset": 0, "offset": 0,
"slot": "2", "slot": "2",
"type": "t_contract(IToken)2219", "type": "t_contract(IToken)2221",
"contract": "Contributor", "contract": "Contributor",
"src": "contracts/Contributor.sol:17" "src": "contracts/Contributor.sol:17"
}, },
@@ -110,7 +110,7 @@
"label": "contributors", "label": "contributors",
"offset": 0, "offset": 0,
"slot": "4", "slot": "4",
"type": "t_mapping(t_uint32,t_struct(Contributor)2259_storage)", "type": "t_mapping(t_uint32,t_struct(Contributor)2261_storage)",
"contract": "Contributor", "contract": "Contributor",
"src": "contracts/Contributor.sol:29" "src": "contracts/Contributor.sol:29"
}, },
@@ -144,11 +144,11 @@
"label": "bytes32", "label": "bytes32",
"numberOfBytes": "32" "numberOfBytes": "32"
}, },
"t_contract(IContributionBalance)2236": { "t_contract(IContributionBalance)2238": {
"label": "contract IContributionBalance", "label": "contract IContributionBalance",
"numberOfBytes": "20" "numberOfBytes": "20"
}, },
"t_contract(IToken)2219": { "t_contract(IToken)2221": {
"label": "contract IToken", "label": "contract IToken",
"numberOfBytes": "20" "numberOfBytes": "20"
}, },
@@ -156,11 +156,11 @@
"label": "mapping(address => uint32)", "label": "mapping(address => uint32)",
"numberOfBytes": "32" "numberOfBytes": "32"
}, },
"t_mapping(t_uint32,t_struct(Contributor)2259_storage)": { "t_mapping(t_uint32,t_struct(Contributor)2261_storage)": {
"label": "mapping(uint32 => struct Contributor.Contributor)", "label": "mapping(uint32 => struct Contributor.Contributor)",
"numberOfBytes": "32" "numberOfBytes": "32"
}, },
"t_struct(Contributor)2259_storage": { "t_struct(Contributor)2261_storage": {
"label": "struct Contributor.Contributor", "label": "struct Contributor.Contributor",
"members": [ "members": [
{ {
@@ -717,6 +717,221 @@
} }
} }
} }
},
"27e6fdeedf4e7e81a2c2ecc839d0c13414aa8f5527d4d3573f469358c8aad652": {
"address": "0xfaeA425E6eDd4e9B31dAa3614c7c7862751D6782",
"txHash": "0xe7768586dbfb5d528db3c9d0c2a608a4fcb5d7f04eb9f89913ac21b8d20a72df",
"layout": {
"storage": [
{
"label": "_initialized",
"offset": 0,
"slot": "0",
"type": "t_uint8",
"contract": "Initializable",
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62",
"retypedFrom": "bool"
},
{
"label": "_initializing",
"offset": 1,
"slot": "0",
"type": "t_bool",
"contract": "Initializable",
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67"
},
{
"label": "contributorContract",
"offset": 2,
"slot": "0",
"type": "t_contract(ContributorInterface)1546",
"contract": "Contribution",
"src": "contracts/Contribution.sol:14"
},
{
"label": "name_",
"offset": 0,
"slot": "1",
"type": "t_string_storage",
"contract": "Contribution",
"src": "contracts/Contribution.sol:28"
},
{
"label": "symbol_",
"offset": 0,
"slot": "2",
"type": "t_string_storage",
"contract": "Contribution",
"src": "contracts/Contribution.sol:29"
},
{
"label": "contributionOwner",
"offset": 0,
"slot": "3",
"type": "t_mapping(t_uint32,t_uint32)",
"contract": "Contribution",
"src": "contracts/Contribution.sol:32"
},
{
"label": "ownedContributions",
"offset": 0,
"slot": "4",
"type": "t_mapping(t_uint32,t_array(t_uint32)dyn_storage)",
"contract": "Contribution",
"src": "contracts/Contribution.sol:34"
},
{
"label": "contributions",
"offset": 0,
"slot": "5",
"type": "t_mapping(t_uint32,t_struct(ContributionData)1570_storage)",
"contract": "Contribution",
"src": "contracts/Contribution.sol:36"
},
{
"label": "contributionsCount",
"offset": 0,
"slot": "6",
"type": "t_uint32",
"contract": "Contribution",
"src": "contracts/Contribution.sol:37"
},
{
"label": "blocksToWait",
"offset": 4,
"slot": "6",
"type": "t_uint32",
"contract": "Contribution",
"src": "contracts/Contribution.sol:40"
},
{
"label": "deployer",
"offset": 8,
"slot": "6",
"type": "t_address",
"contract": "Contribution",
"src": "contracts/Contribution.sol:43"
},
{
"label": "migrationDone",
"offset": 28,
"slot": "6",
"type": "t_bool",
"contract": "Contribution",
"src": "contracts/Contribution.sol:46"
}
],
"types": {
"t_address": {
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_uint32)dyn_storage": {
"label": "uint32[]",
"numberOfBytes": "32"
},
"t_bool": {
"label": "bool",
"numberOfBytes": "1"
},
"t_bytes32": {
"label": "bytes32",
"numberOfBytes": "32"
},
"t_contract(ContributorInterface)1546": {
"label": "contract ContributorInterface",
"numberOfBytes": "20"
},
"t_mapping(t_uint32,t_array(t_uint32)dyn_storage)": {
"label": "mapping(uint32 => uint32[])",
"numberOfBytes": "32"
},
"t_mapping(t_uint32,t_struct(ContributionData)1570_storage)": {
"label": "mapping(uint32 => struct Contribution.ContributionData)",
"numberOfBytes": "32"
},
"t_mapping(t_uint32,t_uint32)": {
"label": "mapping(uint32 => uint32)",
"numberOfBytes": "32"
},
"t_string_storage": {
"label": "string",
"numberOfBytes": "32"
},
"t_struct(ContributionData)1570_storage": {
"label": "struct Contribution.ContributionData",
"members": [
{
"label": "contributorId",
"type": "t_uint32",
"offset": 0,
"slot": "0"
},
{
"label": "amount",
"type": "t_uint32",
"offset": 4,
"slot": "0"
},
{
"label": "hashDigest",
"type": "t_bytes32",
"offset": 0,
"slot": "1"
},
{
"label": "hashFunction",
"type": "t_uint8",
"offset": 0,
"slot": "2"
},
{
"label": "hashSize",
"type": "t_uint8",
"offset": 1,
"slot": "2"
},
{
"label": "tokenMetadataURL",
"type": "t_string_storage",
"offset": 0,
"slot": "3"
},
{
"label": "confirmedAtBlock",
"type": "t_uint256",
"offset": 0,
"slot": "4"
},
{
"label": "vetoed",
"type": "t_bool",
"offset": 0,
"slot": "5"
},
{
"label": "exists",
"type": "t_bool",
"offset": 1,
"slot": "5"
}
],
"numberOfBytes": "192"
},
"t_uint256": {
"label": "uint256",
"numberOfBytes": "32"
},
"t_uint32": {
"label": "uint32",
"numberOfBytes": "4"
},
"t_uint8": {
"label": "uint8",
"numberOfBytes": "1"
}
}
}
} }
} }
} }

View File

@@ -4,6 +4,6 @@
"solhint:recommended" "solhint:recommended"
], ],
"rules": { "rules": {
"indent": "2" "max-line-length": "warn"
} }
} }

View File

@@ -95,13 +95,13 @@ contract Contribution is Initializable {
// Balance is amount of ERC271 tokens, not amount of kredits // Balance is amount of ERC271 tokens, not amount of kredits
function balanceOf(address owner) public view returns (uint256) { function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0)); require(owner != address(0), "Address invalid");
uint32 contributorId = getContributorIdByAddress(owner); uint32 contributorId = getContributorIdByAddress(owner);
return ownedContributions[contributorId].length; return ownedContributions[contributorId].length;
} }
function ownerOf(uint32 contributionId) public view returns (address) { function ownerOf(uint32 contributionId) public view returns (address) {
require(exists(contributionId)); require(exists(contributionId), "Contribution does not exist");
uint32 contributorId = contributions[contributionId].contributorId; uint32 contributorId = contributions[contributionId].contributorId;
return getContributorAddressById(contributorId); return getContributorAddressById(contributorId);
} }
@@ -156,10 +156,8 @@ contract Contribution is Initializable {
} }
function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool vetoed) public { function add(uint32 amount, uint32 contributorId, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint256 confirmedAtBlock, bool vetoed) public {
// require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint32[](0)), 'nope'); require((confirmedAtBlock == 0 && vetoed == false) || migrationDone == false, "Extra arguments not allowed");
// TODO hubot neither has kredits nor a core account require(balanceOf(msg.sender) > 0 || contributorContract.addressIsCore(msg.sender), "Requires kredits or core status");
require((confirmedAtBlock == 0 && vetoed == false) || migrationDone == false, 'extra arguments during migration only');
require(balanceOf(msg.sender) > 0 || contributorContract.addressIsCore(msg.sender), 'requires kredits or core status');
uint32 contributionId = contributionsCount + 1; uint32 contributionId = contributionsCount + 1;
ContributionData storage c = contributions[contributionId]; ContributionData storage c = contributions[contributionId];
@@ -188,8 +186,8 @@ contract Contribution is Initializable {
function veto(uint32 contributionId) public onlyCore { 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(block.number < c.confirmedAtBlock, 'VETO_PERIOD_ENDED'); require(block.number < c.confirmedAtBlock, "VETO_PERIOD_ENDED");
c.vetoed = true; c.vetoed = true;
emit ContributionVetoed(contributionId, msg.sender); emit ContributionVetoed(contributionId, msg.sender);

View File

@@ -112,17 +112,17 @@ contract Contributor is Initializable {
emit ContributorAdded(_id, account); emit ContributorAdded(_id, account);
} }
function isCoreTeam(uint32 id) view public returns (bool) { function isCoreTeam(uint32 id) public view returns (bool) {
// TODO: for simplicity we simply define the first contributors as core // 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 > 0 && id < 7; return id > 0 && id < 7;
} }
function exists(uint32 id) view public returns (bool) { function exists(uint32 id) public view returns (bool) {
return contributors[id].exists; return contributors[id].exists;
} }
function addressIsCore(address account) view public returns (bool) { function addressIsCore(address account) public view returns (bool) {
// the deployer is always core // the deployer is always core
if(account == deployer) { if(account == deployer) {
return true; return true;
@@ -131,15 +131,15 @@ contract Contributor is Initializable {
return isCoreTeam(id); return isCoreTeam(id);
} }
function addressExists(address account) view public returns (bool) { function addressExists(address account) public view returns (bool) {
return getContributorByAddress(account).exists; return getContributorByAddress(account).exists;
} }
function getContributorIdByAddress(address account) view public returns (uint32) { function getContributorIdByAddress(address account) public view returns (uint32) {
return contributorIds[account]; return contributorIds[account];
} }
function getContributorAddressById(uint32 id) view public returns (address) { function getContributorAddressById(uint32 id) public view returns (address) {
return contributors[id].account; return contributors[id].account;
} }
@@ -148,7 +148,7 @@ contract Contributor is Initializable {
return contributors[id]; return contributors[id];
} }
function getContributorById(uint32 _id) view public returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, uint32 totalKreditsEarned, uint256 contributionsCount, bool exists, uint256 kreditsWithdrawn) { function getContributorById(uint32 _id) public view returns (uint32 id, address account, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, bool isCore, uint256 balance, uint32 totalKreditsEarned, uint256 contributionsCount, bool exists, uint256 kreditsWithdrawn) {
id = _id; id = _id;
Contributor storage c = contributors[_id]; Contributor storage c = contributors[_id];
account = c.account; account = c.account;

View File

@@ -101,8 +101,8 @@ contract Reimbursement is Initializable {
function veto(uint32 reimbursementId) public onlyCore { 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");
r.vetoed = true; r.vetoed = true;
emit ReimbursementVetoed(reimbursementId, msg.sender); emit ReimbursementVetoed(reimbursementId, msg.sender);

View File

@@ -62,7 +62,7 @@ task("create-wallet", "Creates a new wallet json", async () => {
*/ */
module.exports = { module.exports = {
solidity: "0.8.2", solidity: "0.8.2",
defaultNetwork: "localhost", defaultNetwork: "hardhat",
networks: { networks: {
hardhat: { hardhat: {
chainId: 1337, chainId: 1337,

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "@kredits/contracts", "name": "@kredits/contracts",
"version": "7.2.0", "version": "7.3.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@kredits/contracts", "name": "@kredits/contracts",
"version": "7.2.0", "version": "7.3.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@kosmos/schemas": "^3.1.0", "@kosmos/schemas": "^3.1.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@kredits/contracts", "name": "@kredits/contracts",
"version": "7.2.0", "version": "7.3.0",
"description": "Smart contracts and JavaScript API for Kredits", "description": "Smart contracts and JavaScript API for Kredits",
"main": "./lib/kredits.js", "main": "./lib/kredits.js",
"directories": { "directories": {
@@ -22,10 +22,6 @@
"lint:contract-tests": "eslint apps/*/test", "lint:contract-tests": "eslint apps/*/test",
"lint:wrapper": "eslint lib/", "lint:wrapper": "eslint lib/",
"test": "hardhat test", "test": "hardhat test",
"test:token": "cd apps/token && npm run test",
"test:contributor": "cd apps/contributor && npm run test",
"test:contribution": "cd apps/contribution && npm run test",
"test:proposal": "cd apps/proposal && npm run test",
"setup-git-hooks": "sh scripts/git-hooks/install" "setup-git-hooks": "sh scripts/git-hooks/install"
}, },
"repository": { "repository": {

View File

@@ -0,0 +1,44 @@
const fs = require('fs');
const Kredits = require('../../lib/kredits');
async function main() {
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
await kredits.init();
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
const count = await kredits.Reimbursement.count;
const currentBlockHeight = await hre.ethers.provider.getBlockNumber();
const backup = {};
const promises = [];
for (let i = 1; i <= count; i++) {
promises.push(new Promise((resolve, reject) => {
setTimeout(async () => {
console.log(`Loading reimbursement #${i}`);
await kredits.Reimbursement.contract.get(i).then(contractData => {
backup[i] = {
recipientId: contractData.recipientId,
amount: contractData.amount,
token: contractData.token,
hashDigest: contractData.hashDigest,
hashFunction: contractData.hashFunction,
hashSize: contractData.hashSize,
confirmedAtBlock: contractData.confirmedAtBlock,
confirmed: contractData.confirmedAtBlock <= currentBlockHeight,
vetoed: contractData.vetoed,
id: contractData.id,
}
resolve();
});
}, 100 * i);
}));
}
await Promise.all(promises).then(() => {
fs.writeFileSync("./data/reimbursements.json", JSON.stringify(backup, null, 2));
console.log("Exported");
});
}
main();

View File

@@ -13,14 +13,18 @@ async function main() {
const data = fs.readFileSync("./data/contributions.json"); const data = fs.readFileSync("./data/contributions.json");
const contributions = JSON.parse(data); const contributions = JSON.parse(data);
const ids = Object.keys(contributions) const ids = Object.keys(contributions)
.map(k => parseInt(k)) .map(k => parseInt(k))
.sort(function(a, b){return a-b}); .sort(function(a, b) { return a - b });
const currentBlockHeight = await kredits.provider.getBlockNumber(); const currentBlockHeight = await kredits.provider.getBlockNumber();
const confirmationPeriod = 40320 // blocks const confirmationPeriod = 40320 // blocks
const unconfirmedHeight = currentBlockHeight + confirmationPeriod; const unconfirmedHeight = currentBlockHeight + confirmationPeriod;
const startId = parseInt(process.env.START_AT || "0");
for (const contributionId of ids) { for (const contributionId of ids) {
if (contributionId < startId) {
continue;
}
const c = contributions[contributionId.toString()]; const c = contributions[contributionId.toString()];
const confirmedAtBlock = c.confirmed ? currentBlockHeight : unconfirmedHeight; const confirmedAtBlock = c.confirmed ? currentBlockHeight : unconfirmedHeight;
@@ -33,7 +37,7 @@ async function main() {
console.log(`Adding contribution #${contributionId}: ${result.hash}`); console.log(`Adding contribution #${contributionId}: ${result.hash}`);
await result.wait(); await result.wait();
}; };
} catch(e) { } catch (e) {
console.error(e); console.error(e);
} }
} }

View File

@@ -0,0 +1,36 @@
const fs = require('fs');
const Kredits = require('../../lib/kredits');
async function main() {
kredits = new Kredits(hre.ethers.provider, hre.ethers.provider.getSigner())
await kredits.init();
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
const count = await kredits.Reimbursement.count;
console.log(`Currently ${count} entries`);
try {
const data = fs.readFileSync("./data/reimbursements.json");
const reimbursements = JSON.parse(data);
const ids = Object.keys(reimbursements)
.map(k => parseInt(k))
.sort(function(a, b) { return a - b });
for (const reimbursementId of ids) {
const reimbursement = reimbursements[reimbursementId.toString()];
const result = await kredits.Reimbursement.contract.add(
reimbursement.amount,
reimbursement.token,
reimbursement.recipientId,
reimbursement.hashDigest,
reimbursement.hashFunction,
reimbursement.hashSize,
);
console.log(`Adding reimbursement #${reimbursementId}: ${result.hash}`);
await result.wait();
};
} catch (e) {
console.error(e);
}
}
main();

View File

@@ -67,7 +67,7 @@ describe("Contribution contract", async function () {
500, 1, 500, 1,
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
18, 32, 0, false 18, 32, 0, false
)).to.be.revertedWith("requires kredits or core status"); )).to.be.revertedWith("Requires kredits or core status");
expect(await Contribution.contributionsCount()).to.equal(0); expect(await Contribution.contributionsCount()).to.equal(0);
}); });
@@ -76,7 +76,7 @@ describe("Contribution contract", async function () {
500, 1, 500, 1,
"0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f",
18, 32, 23000, true 18, 32, 23000, true
)).to.be.revertedWith("extra arguments during migration only"); )).to.be.revertedWith("Extra arguments not allowed");
expect(await Contribution.contributionsCount()).to.equal(0); expect(await Contribution.contributionsCount()).to.equal(0);
}); });