From 29a80a29e68cd3f757cbb22fe060384e0aa4ac0d Mon Sep 17 00:00:00 2001 From: Manuel Montenegro Date: Wed, 12 Jun 2024 08:34:55 +0200 Subject: [PATCH] Format code --- contracts/CumulativeMerkleDrop.sol | 41 ++- test/CumulativeMerkle.test.js | 467 ++++++++++++++++++++--------- 2 files changed, 354 insertions(+), 154 deletions(-) diff --git a/contracts/CumulativeMerkleDrop.sol b/contracts/CumulativeMerkleDrop.sol index 4a9d74c1..50a947d8 100644 --- a/contracts/CumulativeMerkleDrop.sol +++ b/contracts/CumulativeMerkleDrop.sol @@ -9,7 +9,6 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IApplication.sol"; import "./interfaces/ICumulativeMerkleDrop.sol"; - contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { using SafeERC20 for IERC20; using MerkleProof for bytes32[]; @@ -38,8 +37,14 @@ contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { address newOwner ) { require(IERC20(token_).totalSupply() > 0, "Token contract must be set"); - require(rewardsHolder_ != address(0), "Rewards Holder must be an address"); - require(address(application_) != address(0), "Application must be an address"); + require( + rewardsHolder_ != address(0), + "Rewards Holder must be an address" + ); + require( + address(application_) != address(0), + "Application must be an address" + ); transferOwnership(newOwner); token = token_; @@ -53,7 +58,10 @@ contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { } function setRewardsHolder(address rewardsHolder_) external onlyOwner { - require(rewardsHolder_ != address(0), "Rewards holder must be an address"); + require( + rewardsHolder_ != address(0), + "Rewards holder must be an address" + ); emit RewardsHolderUpdated(rewardsHolder, rewardsHolder_); rewardsHolder = rewardsHolder_; } @@ -68,7 +76,9 @@ contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { require(merkleRoot == expectedMerkleRoot, "Merkle root was updated"); // Verify the merkle proof - bytes32 leaf = keccak256(abi.encodePacked(stakingProvider, beneficiary, cumulativeAmount)); + bytes32 leaf = keccak256( + abi.encodePacked(stakingProvider, beneficiary, cumulativeAmount) + ); require(verify(merkleProof, expectedMerkleRoot, leaf), "Invalid proof"); // Mark it claimed @@ -80,7 +90,12 @@ contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { unchecked { uint256 amount = cumulativeAmount - preclaimed; IERC20(token).safeTransferFrom(rewardsHolder, beneficiary, amount); - emit Claimed(stakingProvider, amount, beneficiary, expectedMerkleRoot); + emit Claimed( + stakingProvider, + amount, + beneficiary, + expectedMerkleRoot + ); } } @@ -91,7 +106,13 @@ contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { bytes32 expectedMerkleRoot, bytes32[] calldata merkleProof ) public { - claim(stakingProvider, beneficiary, cumulativeAmount, expectedMerkleRoot, merkleProof); + claim( + stakingProvider, + beneficiary, + cumulativeAmount, + expectedMerkleRoot, + merkleProof + ); application.withdrawRewards(stakingProvider); } @@ -125,7 +146,11 @@ contract CumulativeMerkleDrop is Ownable, ICumulativeMerkleDrop { } } - function verify(bytes32[] calldata merkleProof, bytes32 root, bytes32 leaf) public pure returns (bool) { + function verify( + bytes32[] calldata merkleProof, + bytes32 root, + bytes32 leaf + ) public pure returns (bool) { return merkleProof.verify(root, leaf); } } diff --git a/test/CumulativeMerkle.test.js b/test/CumulativeMerkle.test.js index 52541adc..3d77aec6 100644 --- a/test/CumulativeMerkle.test.js +++ b/test/CumulativeMerkle.test.js @@ -1,24 +1,24 @@ -const { ethers } = require('hardhat') -const { expect } = require('chai') -const { MerkleTree } = require('merkletreejs') -const fc = require('fast-check') -const keccak256 = require('keccak256') +const { ethers } = require("hardhat") +const { expect } = require("chai") +const { MerkleTree } = require("merkletreejs") +const fc = require("fast-check") +const keccak256 = require("keccak256") -const { dist } = require('./constants') -const { cumDist } = require('./constants') +const { dist } = require("./constants") +const { cumDist } = require("./constants") -function genMerkleLeaf (account, beneficiary, amount) { +function genMerkleLeaf(account, beneficiary, amount) { const amountHex = ethers.BigNumber.from(amount).toHexString() - const leaf = account + beneficiary.substr(2) + amountHex.slice(2).padStart(64, '0') + const leaf = + account + beneficiary.substr(2) + amountHex.slice(2).padStart(64, "0") return MerkleTree.bufferToHex(keccak256(leaf)) } function onlyUnique(value, index, self) { - return self.indexOf(value) === index; + return self.indexOf(value) === index } - -describe('Cumulative Merkle Distribution', function () { +describe("Cumulative Merkle Distribution", function () { let token before(function () { @@ -28,31 +28,35 @@ describe('Cumulative Merkle Distribution', function () { }) beforeEach(async function () { - const Token = await ethers.getContractFactory('TokenMock') + const Token = await ethers.getContractFactory("TokenMock") token = await Token.deploy() }) - context('when set Merkle Root for first time', async function () { + context("when set Merkle Root for first time", async function () { let merkleDist beforeEach(async function () { - const MerkleDist = await ethers.getContractFactory('CumulativeMerkleDrop') - const [owner, rewardsHolder] = await ethers.getSigners(); + const MerkleDist = await ethers.getContractFactory("CumulativeMerkleDrop") + const [owner, rewardsHolder] = await ethers.getSigners() await token.mint(rewardsHolder.address, 10) - merkleDist = await MerkleDist.deploy(token.address, rewardsHolder.address, owner.address) + merkleDist = await MerkleDist.deploy( + token.address, + rewardsHolder.address, + owner.address + ) }) - it('should be 0 before setting it up', async function () { + it("should be 0 before setting it up", async function () { const contractMerkleRoot = await merkleDist.merkleRoot() expect(parseInt(contractMerkleRoot, 16)).to.equal(0) }) - it('should be possible to be set a new one', async function () { + it("should be possible to be set a new one", async function () { await fc.assert( fc.asyncProperty( fc.hexaString({ minLength: 64, maxLength: 64 }), async function (merkleRoot) { - merkleRoot = '0x' + merkleRoot + merkleRoot = "0x" + merkleRoot await merkleDist.setMerkleRoot(merkleRoot) const contractMerkleRoot = await merkleDist.merkleRoot() expect(contractMerkleRoot).to.equal(merkleRoot) @@ -61,21 +65,27 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should be emitted an event', async function () { + it("should be emitted an event", async function () { const prevMerkleRoot = await merkleDist.merkleRoot() - const nextMerkleRoot = '0xb2c0cd477fff5f352df19233236e02bac0c4170a783f11cd39589413132914cc' + const nextMerkleRoot = + "0xb2c0cd477fff5f352df19233236e02bac0c4170a783f11cd39589413132914cc" const tx = merkleDist.setMerkleRoot(nextMerkleRoot) - await expect(tx).to.emit(merkleDist, 'MerkelRootUpdated').withArgs(prevMerkleRoot, nextMerkleRoot) + await expect(tx) + .to.emit(merkleDist, "MerkelRootUpdated") + .withArgs(prevMerkleRoot, nextMerkleRoot) }) it("only contract's owner should can change Merkle Root", async function () { const [owner, addr1] = await ethers.getSigners() - const merkleRoot = '0xb2c0cd477fff5f352df19233236e02bac0c4170a783f11cd39589413132914cc' - await expect(merkleDist.connect(addr1).setMerkleRoot(merkleRoot)).to.be.revertedWith('Ownable: caller is not the owner') + const merkleRoot = + "0xb2c0cd477fff5f352df19233236e02bac0c4170a783f11cd39589413132914cc" + await expect( + merkleDist.connect(addr1).setMerkleRoot(merkleRoot) + ).to.be.revertedWith("Ownable: caller is not the owner") }) }) - context('when batch claim tokens', async function () { + context("when batch claim tokens", async function () { let merkleDist let merkleRoot let totalAmount @@ -91,32 +101,72 @@ describe('Cumulative Merkle Distribution', function () { }) beforeEach(async function () { - const MerkleDist = await ethers.getContractFactory('CumulativeMerkleDrop') - const [_, rewardsHolder] = await ethers.getSigners(); + const MerkleDist = await ethers.getContractFactory("CumulativeMerkleDrop") + const [_, rewardsHolder] = await ethers.getSigners() await token.mint(rewardsHolder.address, totalAmount) - merkleDist = await MerkleDist.deploy(token.address, rewardsHolder.address, rewardsHolder.address) + merkleDist = await MerkleDist.deploy( + token.address, + rewardsHolder.address, + rewardsHolder.address + ) await merkleDist.connect(rewardsHolder).setMerkleRoot(merkleRoot) - await token.connect(rewardsHolder).approve(merkleDist.address, totalAmount) + await token + .connect(rewardsHolder) + .approve(merkleDist.address, totalAmount) }) - it('should accounts get tokens', async function () { + it("should accounts get tokens", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: 1 }), async function (index) { - const claimAccounts = proofAccounts.slice((proofAccounts.length / 2) * index, (proofAccounts.length / 2) * (index + 1)) - const claimAmounts = Array.from(claimAccounts).map((claimAccount, _) => ethers.BigNumber.from(dist.claims[claimAccount].amount)) - const claimProofs = Array.from(claimAccounts).map((claimAccount, _) => dist.claims[claimAccount].proof) - const claimBeneficiaries = Array.from(claimAccounts).map((claimAccount, _) => dist.claims[claimAccount].beneficiary) - const claimStructs = Array.from(claimAccounts).map((claimAccount, index) => [claimAccount, claimBeneficiaries[index], claimAmounts[index], claimProofs[index]]) - const prevBalances = await Promise.all(claimBeneficiaries.map(async (beneficiary, _) => await token.balanceOf(beneficiary))) + const claimAccounts = proofAccounts.slice( + (proofAccounts.length / 2) * index, + (proofAccounts.length / 2) * (index + 1) + ) + const claimAmounts = Array.from(claimAccounts).map( + (claimAccount, _) => + ethers.BigNumber.from(dist.claims[claimAccount].amount) + ) + const claimProofs = Array.from(claimAccounts).map( + (claimAccount, _) => dist.claims[claimAccount].proof + ) + const claimBeneficiaries = Array.from(claimAccounts).map( + (claimAccount, _) => dist.claims[claimAccount].beneficiary + ) + const claimStructs = Array.from(claimAccounts).map( + (claimAccount, index) => [ + claimAccount, + claimBeneficiaries[index], + claimAmounts[index], + claimProofs[index], + ] + ) + const prevBalances = await Promise.all( + claimBeneficiaries.map( + async (beneficiary, _) => await token.balanceOf(beneficiary) + ) + ) await merkleDist.batchClaim(merkleRoot, claimStructs) - const afterBalancesHex = await Promise.all(claimBeneficiaries.map(async (beneficiary, _) => await token.balanceOf(beneficiary))) - const afterBalances = Array.from(afterBalancesHex).map((afterAmmount, _) => parseInt(afterAmmount["_hex"], 16)) - const additions = Object.fromEntries(claimBeneficiaries.filter(onlyUnique).map((i) => [i, 0])) - claimBeneficiaries.forEach((beneficiary, index) => {additions[beneficiary] += parseInt(claimAmounts[index], 10)}) - const expBalances = Array.from(prevBalances).map((prevAmmount, index) => parseInt(prevAmmount + additions[claimBeneficiaries[index]], 10)) + const afterBalancesHex = await Promise.all( + claimBeneficiaries.map( + async (beneficiary, _) => await token.balanceOf(beneficiary) + ) + ) + const afterBalances = Array.from(afterBalancesHex).map( + (afterAmmount, _) => parseInt(afterAmmount["_hex"], 16) + ) + const additions = Object.fromEntries( + claimBeneficiaries.filter(onlyUnique).map((i) => [i, 0]) + ) + claimBeneficiaries.forEach((beneficiary, index) => { + additions[beneficiary] += parseInt(claimAmounts[index], 10) + }) + const expBalances = Array.from(prevBalances).map( + (prevAmmount, index) => + parseInt(prevAmmount + additions[claimBeneficiaries[index]], 10) + ) expBalances.forEach((expAmount, index) => { expect(expAmount).to.equal(afterBalances[index]) }) @@ -126,7 +176,7 @@ describe('Cumulative Merkle Distribution', function () { }) }) - context('when claim tokens', async function () { + context("when claim tokens", async function () { let merkleDist let merkleRoot let totalAmount @@ -142,42 +192,66 @@ describe('Cumulative Merkle Distribution', function () { }) beforeEach(async function () { - const MerkleDist = await ethers.getContractFactory('CumulativeMerkleDrop') + const MerkleDist = await ethers.getContractFactory("CumulativeMerkleDrop") const [owner, rewardsHolder] = await ethers.getSigners() await token.mint(rewardsHolder.address, totalAmount) - merkleDist = await MerkleDist.deploy(token.address, rewardsHolder.address, owner.address) + merkleDist = await MerkleDist.deploy( + token.address, + rewardsHolder.address, + owner.address + ) await merkleDist.setMerkleRoot(merkleRoot) - await token.connect(rewardsHolder).approve(merkleDist.address, totalAmount) + await token + .connect(rewardsHolder) + .approve(merkleDist.address, totalAmount) }) - it('should be emitted an event', async function () { + it("should be emitted an event", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), async function (index) { const claimAccount = proofAccounts[index] - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary - const tx = merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof) - await expect(tx).to.emit(merkleDist, 'Claimed').withArgs(claimAccount, claimAmount, claimBeneficiary, merkleRoot) + const tx = merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + await expect(tx) + .to.emit(merkleDist, "Claimed") + .withArgs(claimAccount, claimAmount, claimBeneficiary, merkleRoot) } ) ) }) - it('should accounts get tokens', async function () { + it("should accounts get tokens", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), async function (index) { const claimAccount = proofAccounts[index] - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary const prevBalance = await token.balanceOf(claimBeneficiary) const expBalance = prevBalance.add(claimAmount) - await merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof) + await merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) const afterBalance = await token.balanceOf(claimBeneficiary) expect(expBalance).to.equal(afterBalance) } @@ -185,20 +259,28 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should rewards holder to reduce its balance', async function () { + it("should rewards holder to reduce its balance", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), async function (index) { const [owner, rewardsHolder] = await ethers.getSigners() const claimAccount = proofAccounts[index] - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary preBalance = await token.balanceOf(rewardsHolder.address) expBalance = preBalance.sub(claimAmount) - await merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof) + await merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) const afterBalance = await token.balanceOf(rewardsHolder.address) expect(expBalance).to.equal(afterBalance) } @@ -206,18 +288,26 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should not be possible to claim for fake accounts', async function () { + it("should not be possible to claim for fake accounts", async function () { claimAccount = ethers.Wallet.createRandom().address claimAmount = 100000 claimProof = [ - '0xf558bba7dd8aef6fdfb36ea106d965fd7ef483aa217cc02e2c33b78cdfb74cab', - '0x7a8326f3dfbbddc4a0bc1e3e5005d4cecf6a7c89d386692a27dc5235b55e92cd' + "0xf558bba7dd8aef6fdfb36ea106d965fd7ef483aa217cc02e2c33b78cdfb74cab", + "0x7a8326f3dfbbddc4a0bc1e3e5005d4cecf6a7c89d386692a27dc5235b55e92cd", ] claimBeneficiary = ethers.Wallet.createRandom().address - await expect(merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof)).to.be.revertedWith('Invalid proof') + await expect( + merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + ).to.be.revertedWith("Invalid proof") }) - it('should not be possible to claim a different amount of tokens', async function () { + it("should not be possible to claim a different amount of tokens", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), @@ -226,30 +316,54 @@ describe('Cumulative Merkle Distribution', function () { const claimAccount = proofAccounts[index] const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary - await expect(merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof)).to.be.revertedWith('Invalid proof') + await expect( + merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + ).to.be.revertedWith("Invalid proof") } ) ) }) - it('should not be possible to claim twice', async function () { + it("should not be possible to claim twice", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), async function (index) { const claimAccount = proofAccounts[index] - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary - await merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof) - await expect(merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof)).to.be.revertedWith('Nothing to claim') + await merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + await expect( + merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + ).to.be.revertedWith("Nothing to claim") } ) ) }) }) - context('when set a new Merkle Distribution (cumulative)', async function () { + context("when set a new Merkle Distribution (cumulative)", async function () { let merkleDist let merkleRoot let cumulativeMerkleRoot @@ -271,96 +385,153 @@ describe('Cumulative Merkle Distribution', function () { }) beforeEach(async function () { - const MerkleDist = await ethers.getContractFactory('CumulativeMerkleDrop') - const [owner, rewardsHolder] = await ethers.getSigners(); + const MerkleDist = await ethers.getContractFactory("CumulativeMerkleDrop") + const [owner, rewardsHolder] = await ethers.getSigners() await token.mint(rewardsHolder.address, totalAmount) - merkleDist = await MerkleDist.deploy(token.address, rewardsHolder.address, owner.address) + merkleDist = await MerkleDist.deploy( + token.address, + rewardsHolder.address, + owner.address + ) await merkleDist.setMerkleRoot(merkleRoot) - await token.connect(rewardsHolder).approve(merkleDist.address, totalAmount) + await token + .connect(rewardsHolder) + .approve(merkleDist.address, totalAmount) }) - it('should be possible to set a new Merkle Root after claiming', async function () { + it("should be possible to set a new Merkle Root after claiming", async function () { const claimAccount = proofAccounts[0] - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary - await merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof) + await merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) await merkleDist.setMerkleRoot(cumulativeMerkleRoot) const contractMerkleRoot = await merkleDist.merkleRoot() expect(contractMerkleRoot).to.equal(cumulativeMerkleRoot) }) - it('should not be possible to claim using old Merkle Root', async function () { + it("should not be possible to claim using old Merkle Root", async function () { const claimAccount = proofAccounts[0] - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) const claimProof = dist.claims[claimAccount].proof const claimBeneficiary = dist.claims[claimAccount].beneficiary await merkleDist.setMerkleRoot(cumulativeMerkleRoot) - await expect(merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof)).to.be.revertedWith('Merkle root was updated') + await expect( + merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + ).to.be.revertedWith("Merkle root was updated") }) - context('after claiming all tokens of the previous distribution', async function () { - beforeEach(async function () { - for (claimAccount of proofAccounts) { - const claimAmount = ethers.BigNumber.from(dist.claims[claimAccount].amount) - const claimProof = dist.claims[claimAccount].proof - const claimBeneficiary = dist.claims[claimAccount].beneficiary - await merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, merkleRoot, claimProof) - } - }) - - it('should not be possible to claim without enough balance in contract', async function () { - await merkleDist.setMerkleRoot(cumulativeMerkleRoot) - - const claimAccount = cumulativeProofAccounts[0] - const claimAmount = ethers.BigNumber.from(cumDist.claims[claimAccount].amount) - const claimProof = cumDist.claims[claimAccount].proof - const claimBeneficiary = cumDist.claims[claimAccount].beneficiary - - await expect(merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, cumulativeMerkleRoot, claimProof)).to.be.revertedWith('Transfer amount exceeds allowance') - }) - - it('should be possible to claim new distribution tokens', async function () { - const [owner, rewardsHolder] = await ethers.getSigners(); - await token.mint(rewardsHolder.address, cumulativetotalAmount) - await merkleDist.setMerkleRoot(cumulativeMerkleRoot) - await token.connect(rewardsHolder).approve(merkleDist.address, cumulativetotalAmount) - - await fc.assert( - fc.asyncProperty( - fc.integer({ min: 0, max: cumulativeProofAccounts.length - 1 }), - async function (index) { - const claimAccount = cumulativeProofAccounts[index] - const claimAmount = ethers.BigNumber.from(cumDist.claims[claimAccount].amount) - const claimProof = cumDist.claims[claimAccount].proof - const claimBeneficiary = cumDist.claims[claimAccount].beneficiary - - // add up all rewards from previous distribution - let prevReward = {} - proofAccounts.forEach((account, _) => { - if (dist.claims[account].beneficiary === claimBeneficiary) { - prevReward[account] = dist.claims[account].amount - } - }) - - // update reward for current distribution - prevReward[claimAccount] = claimAmount - const reducer = (accumulator, curr) => parseInt(accumulator, 10) + curr; - const totalReward = Object.values(prevReward) - - await merkleDist.claim(claimAccount, claimBeneficiary, claimAmount, cumulativeMerkleRoot, claimProof) - const balance = await token.balanceOf(claimBeneficiary) - expect(totalReward.reduce(reducer)).to.equal(balance) - } + context( + "after claiming all tokens of the previous distribution", + async function () { + beforeEach(async function () { + for (claimAccount of proofAccounts) { + const claimAmount = ethers.BigNumber.from( + dist.claims[claimAccount].amount + ) + const claimProof = dist.claims[claimAccount].proof + const claimBeneficiary = dist.claims[claimAccount].beneficiary + await merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + merkleRoot, + claimProof + ) + } + }) + + it("should not be possible to claim without enough balance in contract", async function () { + await merkleDist.setMerkleRoot(cumulativeMerkleRoot) + + const claimAccount = cumulativeProofAccounts[0] + const claimAmount = ethers.BigNumber.from( + cumDist.claims[claimAccount].amount ) - ) - }) - }) + const claimProof = cumDist.claims[claimAccount].proof + const claimBeneficiary = cumDist.claims[claimAccount].beneficiary + + await expect( + merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + cumulativeMerkleRoot, + claimProof + ) + ).to.be.revertedWith("Transfer amount exceeds allowance") + }) + + it("should be possible to claim new distribution tokens", async function () { + const [owner, rewardsHolder] = await ethers.getSigners() + await token.mint(rewardsHolder.address, cumulativetotalAmount) + await merkleDist.setMerkleRoot(cumulativeMerkleRoot) + await token + .connect(rewardsHolder) + .approve(merkleDist.address, cumulativetotalAmount) + + await fc.assert( + fc.asyncProperty( + fc.integer({ min: 0, max: cumulativeProofAccounts.length - 1 }), + async function (index) { + const claimAccount = cumulativeProofAccounts[index] + const claimAmount = ethers.BigNumber.from( + cumDist.claims[claimAccount].amount + ) + const claimProof = cumDist.claims[claimAccount].proof + const claimBeneficiary = + cumDist.claims[claimAccount].beneficiary + + // add up all rewards from previous distribution + let prevReward = {} + proofAccounts.forEach((account, _) => { + if (dist.claims[account].beneficiary === claimBeneficiary) { + prevReward[account] = dist.claims[account].amount + } + }) + + // update reward for current distribution + prevReward[claimAccount] = claimAmount + const reducer = (accumulator, curr) => + parseInt(accumulator, 10) + curr + const totalReward = Object.values(prevReward) + + await merkleDist.claim( + claimAccount, + claimBeneficiary, + claimAmount, + cumulativeMerkleRoot, + claimProof + ) + const balance = await token.balanceOf(claimBeneficiary) + expect(totalReward.reduce(reducer)).to.equal(balance) + } + ) + ) + }) + } + ) }) - context('when verify Merkle Proof', async function () { + context("when verify Merkle Proof", async function () { let merkleDist let merkleRoot let proofAccounts @@ -374,14 +545,18 @@ describe('Cumulative Merkle Distribution', function () { }) beforeEach(async function () { - const MerkleDist = await ethers.getContractFactory('CumulativeMerkleDrop') - const [owner, rewardsHolder] = await ethers.getSigners(); + const MerkleDist = await ethers.getContractFactory("CumulativeMerkleDrop") + const [owner, rewardsHolder] = await ethers.getSigners() await token.mint(rewardsHolder.address, 10) - merkleDist = await MerkleDist.deploy(token.address, rewardsHolder.address, owner.address) + merkleDist = await MerkleDist.deploy( + token.address, + rewardsHolder.address, + owner.address + ) await merkleDist.setMerkleRoot(merkleRoot) }) - it('should not be verified if no Merkle Proof', async function () { + it("should not be verified if no Merkle Proof", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), @@ -398,7 +573,7 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should not be verified with incorrect Merkle Proof', async function () { + it("should not be verified with incorrect Merkle Proof", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), @@ -408,8 +583,8 @@ describe('Cumulative Merkle Distribution', function () { const beneficiary = dist.claims[account].beneficiary const leaf = genMerkleLeaf(account, beneficiary, amount) const claimProof = [ - MerkleTree.bufferToHex(keccak256('proof1')), - MerkleTree.bufferToHex(keccak256('proof2')) + MerkleTree.bufferToHex(keccak256("proof1")), + MerkleTree.bufferToHex(keccak256("proof2")), ] const verif = await merkleDist.verify(claimProof, merkleRoot, leaf) expect(verif).to.be.false @@ -418,7 +593,7 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should a correct MerkleProof be verified', async function () { + it("should a correct MerkleProof be verified", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), @@ -435,13 +610,13 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should not be verified a Merkle Proof with incorrect root', async function () { + it("should not be verified a Merkle Proof with incorrect root", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), fc.hexaString({ minLength: 64, maxLength: 64 }), async function (index, root) { - root = '0x' + root + root = "0x" + root const account = proofAccounts[index] const amount = dist.claims[account].amount const beneficiary = dist.claims[account].beneficiary @@ -454,7 +629,7 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should not be verified a Merkle Proof with incorrect amount', async function () { + it("should not be verified a Merkle Proof with incorrect amount", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }), @@ -471,7 +646,7 @@ describe('Cumulative Merkle Distribution', function () { ) }) - it('should not be verified a Merkle Proof with incorrect account', async function () { + it("should not be verified a Merkle Proof with incorrect account", async function () { await fc.assert( fc.asyncProperty( fc.integer({ min: 0, max: proofAccounts.length - 1 }),