From 9dd9d298ccb5a1ed35e7a2b45f48af84eb83fd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Tue, 23 Aug 2022 16:20:50 +0100 Subject: [PATCH] Allow setting confirmedAtBlock and vetoed during migration --- contracts/Contribution.sol | 12 ++++--- lib/abis/Contribution.json | 2 +- lib/addresses.json | 8 ++--- lib/contracts/contribution.js | 2 +- test/Contribution.js | 66 +++++++++++++++++++++++++++++++---- 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/contracts/Contribution.sol b/contracts/Contribution.sol index d3745cf..b4b65a0 100644 --- a/contracts/Contribution.sol +++ b/contracts/Contribution.sol @@ -168,10 +168,12 @@ 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, uint256 confirmedAtBlock, bool vetoed) public { // require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint32[](0)), 'nope'); // TODO hubot neither has kredits nor a core account + 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; ContributionData storage c = contributions[contributionId]; c.exists = true; @@ -181,12 +183,15 @@ contract Contribution is Initializable { c.hashDigest = hashDigest; c.hashFunction = hashFunction; c.hashSize = hashSize; - if (contributionId < 10) { - c.confirmedAtBlock = block.number; + + if (confirmedAtBlock > 0) { + c.confirmedAtBlock = confirmedAtBlock; } else { c.confirmedAtBlock = block.number + 1 + blocksToWait; } + if (vetoed) { c.vetoed = true; } + contributionsCount++; contributionOwner[contributionId] = contributorId; @@ -196,7 +201,6 @@ contract Contribution is Initializable { } function veto(uint32 contributionId) public onlyCore { - ContributionData storage c = contributions[contributionId]; require(c.exists, 'NOT_FOUND'); require(!c.claimed, 'ALREADY_CLAIMED'); diff --git a/lib/abis/Contribution.json b/lib/abis/Contribution.json index bce7ca6..78552d1 100644 --- a/lib/abis/Contribution.json +++ b/lib/abis/Contribution.json @@ -1 +1 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"contributorId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"amount","type":"uint32"}],"name":"ContributionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"contributorId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"amount","type":"uint32"}],"name":"ContributionClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":false,"internalType":"address","name":"vetoedByAccount","type":"address"}],"name":"ContributionVetoed","type":"event"},{"inputs":[{"internalType":"uint32","name":"amount","type":"uint32"},{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksToWait","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"contributionOwner","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"contributions","outputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"uint32","name":"amount","type":"uint32"},{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"string","name":"tokenMetadataURL","type":"string"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"vetoed","type":"bool"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributionsCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributorContract","outputs":[{"internalType":"contract ContributorInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"getContribution","outputs":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"uint32","name":"amount","type":"uint32"},{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"}],"name":"getContributorAddressById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributorAccount","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"blocksToWait_","type":"uint32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownedContributions","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"setContributorContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"setTokenContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenContract","outputs":[{"internalType":"contract IToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"tokenMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"index","type":"uint32"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"confirmedOnly","type":"bool"}],"name":"totalKreditsEarned","outputs":[{"internalType":"uint32","name":"amount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"bool","name":"confirmedOnly","type":"bool"}],"name":"totalKreditsEarnedByContributor","outputs":[{"internalType":"uint32","name":"amount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"veto","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"contributorId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"amount","type":"uint32"}],"name":"ContributionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"contributorId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"amount","type":"uint32"}],"name":"ContributionClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":false,"internalType":"address","name":"vetoedByAccount","type":"address"}],"name":"ContributionVetoed","type":"event"},{"inputs":[{"internalType":"uint32","name":"amount","type":"uint32"},{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"vetoed","type":"bool"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksToWait","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"contributionOwner","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"contributions","outputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"uint32","name":"amount","type":"uint32"},{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"string","name":"tokenMetadataURL","type":"string"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"vetoed","type":"bool"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributionsCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributorContract","outputs":[{"internalType":"contract ContributorInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finishMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"getContribution","outputs":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"uint32","name":"amount","type":"uint32"},{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"bytes32","name":"hashDigest","type":"bytes32"},{"internalType":"uint8","name":"hashFunction","type":"uint8"},{"internalType":"uint8","name":"hashSize","type":"uint8"},{"internalType":"uint256","name":"confirmedAtBlock","type":"uint256"},{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"}],"name":"getContributorAddressById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributorAccount","type":"address"}],"name":"getContributorIdByAddress","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"blocksToWait_","type":"uint32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrationDone","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownedContributions","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"setContributorContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"setTokenContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenContract","outputs":[{"internalType":"contract IToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"tokenMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"index","type":"uint32"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"confirmedOnly","type":"bool"}],"name":"totalKreditsEarned","outputs":[{"internalType":"uint32","name":"amount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributorId","type":"uint32"},{"internalType":"bool","name":"confirmedOnly","type":"bool"}],"name":"totalKreditsEarnedByContributor","outputs":[{"internalType":"uint32","name":"amount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"veto","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/addresses.json b/lib/addresses.json index 5bba5b6..cba931a 100644 --- a/lib/addresses.json +++ b/lib/addresses.json @@ -1,8 +1,8 @@ { "1337": { - "Contributor": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", - "Contribution": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "Token": "0x0165878A594ca255338adfa4d48449f69242Eb8F", - "Reimbursement": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" + "Contributor": "0xCc66f9A3cA2670972938FAD91d0865c4a62DFB25", + "Contribution": "0x8999CaBc43E28202c5A2257f2a95A45b1F8A62BD", + "Token": "0xe082678eCF749982e33Ea6839852a8cd989aEDE2", + "Reimbursement": "0x984f797d26d3da2E9b9f8Ae4eeFEACC60fCAA90C" } } \ No newline at end of file diff --git a/lib/contracts/contribution.js b/lib/contracts/contribution.js index 0f2bbb7..f6648d9 100644 --- a/lib/contracts/contribution.js +++ b/lib/contracts/contribution.js @@ -58,7 +58,7 @@ class Contribution extends Record { ipfsHashAttr.hashSize, ]; - return this.contract.add(...contribution, callOptions); + return this.contract.add(...contribution, 0, false, callOptions); }); } diff --git a/test/Contribution.js b/test/Contribution.js index 02de504..b6d6a25 100644 --- a/test/Contribution.js +++ b/test/Contribution.js @@ -27,7 +27,7 @@ describe("Contribution contract", async function () { }); it("sets the data migration flag", async function () { - expect(await Contribution.migrationDone()).to.equal(false); + expect(await Contribution.migrationDone()).to.be.false; }); it("sets the deployer address", async function () { @@ -45,7 +45,7 @@ describe("Contribution contract", async function () { it("does not allow random accounts to mark the migration as finished", async function () { await expect(Contribution.connect(addr1).finishMigration()).to.be.revertedWith("Deployer only"); - expect(await Contribution.migrationDone()).to.equal(false); + expect(await Contribution.migrationDone()).to.be.false; }); it("allows the deployer to mark the migration as finished", async function () { @@ -59,22 +59,32 @@ describe("Contribution contract", async function () { const contributionFactory = await ethers.getContractFactory("Contribution"); Contribution = await upgrades.deployProxy(contributionFactory, [40321]); await Contribution.setContributorContract(Contributor.address).then(res => res.wait()) + await Contribution.finishMigration(); }); it("does not allow non-contributors to add a contribution", async function () { await expect(Contribution.connect(addr7).add( 500, 1, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", - 18, 32 + 18, 32, 0, false )).to.be.revertedWith("requires kredits or core status"); expect(await Contribution.contributionsCount()).to.equal(0); }); + it("does not allow special arguments outside of a migration", async function () { + await expect(Contribution.connect(addr7).add( + 500, 1, + "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", + 18, 32, 23000, true + )).to.be.revertedWith("extra arguments during migration only"); + expect(await Contribution.contributionsCount()).to.equal(0); + }); + it("allows core contributors to add a contribution", async function () { await Contribution.connect(addr2).add( 2001, 1, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", - 18, 32 + 18, 32, 0, false ); expect(await Contribution.contributionsCount()).to.equal(1); }); @@ -84,23 +94,65 @@ describe("Contribution contract", async function () { await Contribution.connect(addr1).add( 5000, 8, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", - 18, 32 + 18, 32, 0, false ); await Contribution.connect(addr7).add( 1500, 1, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", - 18, 32 + 18, 32, 0, false ); expect(await Contribution.contributionsCount()).to.equal(3); }); + it("sets confirmedAtBlock to current block plus blocksToWait", async function () { + await Contribution.connect(addr1).add( + 500, 3, + "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", + 18, 32, 0, false + ); + expect(await Contribution.contributionsCount()).to.equal(4); + const c = await Contribution.getContribution(4); + const currentBlockNumber = await kredits.provider.getBlockNumber(); + expect(c['confirmedAtBlock']).to.equal(currentBlockNumber + 1 + 40321); + }); + it("emits a ContributionAdded event", async function () { await expect(Contribution.connect(addr1).add( 2001, 1, "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", - 18, 32 + 18, 32, 0, false )).to.emit(Contribution, "ContributionAdded").withArgs(anyValue, 1, 2001); }); + + describe("with extra arguments during migration", async function () { + before(async function () { + const contributionFactory = await ethers.getContractFactory("Contribution"); + Contribution = await upgrades.deployProxy(contributionFactory, [40321]); + await Contribution.setContributorContract(Contributor.address).then(res => res.wait()) + }); + + it("allows to add a contribution with custom confirmedAtBlock", async function () { + await Contribution.connect(addr2).add( + 2001, 1, + "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", + 18, 32, 23000, false + ); + expect(await Contribution.contributionsCount()).to.equal(1); + const c = await Contribution.getContribution(1); + expect(c['confirmedAtBlock'].toNumber()).to.equal(23000); + }); + + it("allows to add a vetoed contribution", async function () { + await Contribution.connect(addr2).add( + 2001, 1, + "0xe794f010e617449719c64076546254129f63a6d16cf200031afa646aeb35777f", + 18, 32, 23000, true + ); + expect(await Contribution.contributionsCount()).to.equal(2); + const c = await Contribution.getContribution(2); + expect(c['vetoed']).to.be.true; + }); + }); }); });