From 839e88de2ed116b52b00565cc0b2d41517455f3c Mon Sep 17 00:00:00 2001 From: 0xSamWitch Date: Mon, 7 Aug 2023 14:58:15 +0100 Subject: [PATCH] Add overflow to next clan/global donation --- contracts/Donation.sol | 70 +++++++++++++++++++++++------------------- test/Donation.ts | 60 +++++++++++++++++++++--------------- test/Players/Boosts.ts | 7 ++--- 3 files changed, 75 insertions(+), 62 deletions(-) diff --git a/contracts/Donation.sol b/contracts/Donation.sol index 42e57400..25bf7250 100644 --- a/contracts/Donation.sol +++ b/contracts/Donation.sol @@ -160,42 +160,45 @@ contract Donation is UUPSUpgradeable, OwnableUpgradeable, IOracleRewardCB { } playersEntered[_lastLotteryId].set(_playerId); isRaffleDonation = true; + } - clanId = clans.getClanId(_playerId); - if (clanId != 0) { - // Add raffle donation amount only to the clan reward reward to prevent them reaching it too quickly. - // Note: Make sure no important state is set before the max donations check - if (clanDonationInfo[clanId].nextReward == 0) { - // First time this clan has been donated to - clanDonationInfo[clanId].nextReward = clanBoostRewardItemTokenIds[0]; - } + clanId = clans.getClanId(_playerId); + if (clanId != 0) { + // Add raffle donation amount only to the clan reward reward to prevent them reaching it too quickly. + // Note: Make sure no important state is set before the max donations check + if (clanDonationInfo[clanId].nextReward == 0) { + // First time this clan has been donated to + clanDonationInfo[clanId].nextReward = clanBoostRewardItemTokenIds[0]; + } - uint40 totalDonatedToClan = clanDonationInfo[clanId].totalDonated; - totalDonatedToClan += uint40(_amount / 1 ether); - - if (totalDonatedToClan >= (clanDonationInfo[clanId].lastThreshold + clanThresholdIncrement)) { - // Give the whole clan a reward - clanItemTokenId = clanDonationInfo[clanId].nextReward; - clanDonationInfo[clanId].lastThreshold = totalDonatedToClan; - - // Cycle through them - uint16 nextReward; - if (clanItemTokenId == clanBoostRewardItemTokenIds[clanBoostRewardItemTokenIds.length - 1]) { - // Reached the end so start again - nextReward = clanBoostRewardItemTokenIds[0]; - } else { - // They just happen to be id'ed sequentially. If this changes then this logic will need to change - nextReward = clanItemTokenId + 1; - } - emit LastClanDonationThreshold(clanId, uint(clanDonationInfo[clanId].lastThreshold) * 1 ether, nextReward); - clanDonationInfo[clanId].nextReward = nextReward; + uint40 totalDonatedToClan = clanDonationInfo[clanId].totalDonated; + totalDonatedToClan += uint40(_amount / 1 ether); + + uint nextClanThreshold = (clanDonationInfo[clanId].lastThreshold + clanThresholdIncrement); + if (totalDonatedToClan >= nextClanThreshold) { + // Give the whole clan a reward + clanItemTokenId = clanDonationInfo[clanId].nextReward; + uint remainder = (totalDonatedToClan - nextClanThreshold); + uint numThresholdIncrements = (remainder / clanThresholdIncrement) + 1; + clanDonationInfo[clanId].lastThreshold += uint40(numThresholdIncrements * clanThresholdIncrement); + + // Cycle through them + uint16 nextReward; + if (clanItemTokenId == clanBoostRewardItemTokenIds[clanBoostRewardItemTokenIds.length - 1]) { + // Reached the end so start again + nextReward = clanBoostRewardItemTokenIds[0]; + } else { + // They just happen to be id'ed sequentially. If this changes then this logic will need to change + nextReward = clanItemTokenId + 1; } - - clanDonationInfo[clanId].totalDonated = totalDonatedToClan; - emit DonateToClan(_from, _playerId, _amount * 1 ether, clanId); + emit LastClanDonationThreshold(clanId, uint(clanDonationInfo[clanId].lastThreshold) * 1 ether, nextReward); + clanDonationInfo[clanId].nextReward = nextReward; } - emit Donate(_from, _playerId, _amount, _lastLotteryId, lastRaffleId); + + clanDonationInfo[clanId].totalDonated = totalDonatedToClan; + emit DonateToClan(_from, _playerId, _amount * 1 ether, clanId); } + emit Donate(_from, _playerId, _amount, _lastLotteryId, lastRaffleId); } if (!isRaffleDonation) { @@ -207,7 +210,10 @@ contract Donation is UUPSUpgradeable, OwnableUpgradeable, IOracleRewardCB { // Is a donation threshold hit? if (nextGlobalThreshold != 0 && totalDonated >= nextGlobalThreshold) { globalItemTokenId = nextGlobalRewardItemTokenId; - nextGlobalThreshold = totalDonated + (isBeta ? 1000 : 100_000); + uint nextIncrement = isBeta ? 1000 : 100_000; + uint remainder = (totalDonated - nextGlobalThreshold); + uint numThresholdIncrements = (remainder / nextIncrement) + 1; + nextGlobalThreshold += uint40(numThresholdIncrements * nextIncrement); // Cycle through them uint16 nextReward; diff --git a/test/Donation.ts b/test/Donation.ts index c25cd741..e7f2a12b 100644 --- a/test/Donation.ts +++ b/test/Donation.ts @@ -229,7 +229,7 @@ describe("Donation", function () { .withArgs(alice.address, playerId, raffleEntryCost, 0, 0); }); - it("Check threshold rewards", async function () { + it("Check global threshold rewards", async function () { const {donation, players, alice, playerId} = await loadFixture(deployContracts); const nextThreshold = await donation.getNextGlobalThreshold(); @@ -250,33 +250,36 @@ describe("Donation", function () { await expect(players.connect(alice).donate(0, ethers.utils.parseEther("1500"))) .to.emit(donation, "NextGlobalDonationThreshold") - .withArgs(ethers.utils.parseEther("3500"), EstforConstants.PRAY_TO_THE_BEARDIE_3) + .withArgs(ethers.utils.parseEther("3000"), EstforConstants.PRAY_TO_THE_BEARDIE_3) .and.to.emit(players, "ConsumeGlobalBoostVial"); - // Donated 500 above the old threshold - expect(await donation.getNextGlobalThreshold()).to.eq(ethers.utils.parseEther("3500")); + // Donated 500 above the old threshold, should be + expect(await donation.getNextGlobalThreshold()).to.eq(ethers.utils.parseEther("3000")); // Should go back to the start - await expect(players.connect(alice).donate(0, ethers.utils.parseEther("1000"))) + await expect(players.connect(alice).donate(0, ethers.utils.parseEther("499"))).to.not.emit( + donation, + "NextGlobalDonationThreshold" + ); + await expect(players.connect(alice).donate(0, ethers.utils.parseEther("1"))) .to.emit(donation, "NextGlobalDonationThreshold") - .withArgs(ethers.utils.parseEther("4500"), EstforConstants.PRAY_TO_THE_BEARDIE) + .withArgs(ethers.utils.parseEther("4000"), EstforConstants.PRAY_TO_THE_BEARDIE) .and.to.emit(players, "ConsumeGlobalBoostVial"); + + // Go over multiple increments + await expect(players.connect(alice).donate(0, ethers.utils.parseEther("3500"))) + .to.emit(donation, "NextGlobalDonationThreshold") + .withArgs(ethers.utils.parseEther("7000"), EstforConstants.PRAY_TO_THE_BEARDIE_2) + .and.to.emit(players, "ConsumeGlobalBoostVial"); + + expect(await donation.getTotalDonated()).to.eq(ethers.utils.parseEther("6500")); + expect(await donation.getNextGlobalThreshold()).to.eq(ethers.utils.parseEther("7000")); }); it("Check clan boost rotation", async function () { - const { - donation, - players, - alice, - world, - mockOracleClient, - playerId, - raffleEntryCost, - brush, - clans, - bob, - totalBrush, - } = await loadFixture(deployContracts); + const {donation, players, alice, playerId, raffleEntryCost, brush, clans, bob, totalBrush} = await loadFixture( + deployContracts + ); // Be a member of a clan const clanId = 1; @@ -308,9 +311,6 @@ describe("Donation", function () { expect((await players.activeBoost(playerId)).extraOrLastItemTokenId).to.eq(EstforConstants.LUCK_OF_THE_DRAW); expect((await players.clanBoost(clanId)).itemTokenId).to.eq(EstforConstants.CLAN_BOOSTER); - await ethers.provider.send("evm_increaseTime", [24 * 3600]); - await mockOracleClient.fulfill(getRequestId(await world.requestRandomWords()), world.address); - await expect(players.connect(alice).donate(playerId, raffleEntryCost)) .to.emit(donation, "LastClanDonationThreshold") .withArgs(clanId, raffleEntryCost.mul(2), EstforConstants.CLAN_BOOSTER_3) @@ -319,9 +319,6 @@ describe("Donation", function () { expect((await players.activeBoost(playerId)).extraOrLastItemTokenId).to.eq(EstforConstants.LUCK_OF_THE_DRAW); expect((await players.clanBoost(clanId)).itemTokenId).to.eq(EstforConstants.CLAN_BOOSTER_2); - await ethers.provider.send("evm_increaseTime", [24 * 3600]); - await mockOracleClient.fulfill(getRequestId(await world.requestRandomWords()), world.address); - await expect(players.connect(alice).donate(playerId, raffleEntryCost)) .to.emit(donation, "LastClanDonationThreshold") .withArgs(clanId, raffleEntryCost.mul(3), EstforConstants.CLAN_BOOSTER) @@ -329,6 +326,19 @@ describe("Donation", function () { expect((await players.activeBoost(playerId)).extraOrLastItemTokenId).to.eq(EstforConstants.LUCK_OF_THE_DRAW); expect((await players.clanBoost(clanId)).itemTokenId).to.eq(EstforConstants.CLAN_BOOSTER_3); + + await expect(players.connect(alice).donate(playerId, raffleEntryCost.mul(7).add(ethers.utils.parseEther("1")))) + .to.emit(donation, "LastClanDonationThreshold") + .withArgs(clanId, raffleEntryCost.mul(10), EstforConstants.CLAN_BOOSTER_2) + .and.to.emit(players, "ConsumeClanBoostVial"); + + expect((await players.clanBoost(clanId)).itemTokenId).to.eq(EstforConstants.CLAN_BOOSTER); + + expect(ethers.utils.parseEther((await donation.clanDonationInfo(clanId)).totalDonated.toString())).to.eq( + raffleEntryCost.mul(10).add(ethers.utils.parseEther("1")) + ); + + expect(await donation.getNextClanThreshold(clanId)).to.eq(raffleEntryCost.mul(11)); }); it("Check claiming previous claims works up to 3 other lotteries ago", async function () { diff --git a/test/Players/Boosts.ts b/test/Players/Boosts.ts index 96906c0c..5ba6b7cc 100644 --- a/test/Players/Boosts.ts +++ b/test/Players/Boosts.ts @@ -505,7 +505,7 @@ describe("Boosts", function () { await players.connect(alice).donate(0, nextGlobalThreshold.sub(ethers.utils.parseEther("1"))); await expect(players.connect(alice).donate(playerId, ethers.utils.parseEther("2"))) .to.emit(donation, "NextGlobalDonationThreshold") - .withArgs(ethers.utils.parseEther("2001"), EstforConstants.PRAY_TO_THE_BEARDIE_2) + .withArgs(ethers.utils.parseEther("2000"), EstforConstants.PRAY_TO_THE_BEARDIE_2) .and.to.emit(players, "ConsumeGlobalBoostVial"); await ethers.provider.send("evm_increaseTime", [queuedAction.timespan]); @@ -740,10 +740,7 @@ describe("Boosts", function () { await players.connect(alice).donate(0, maxThreshold.sub(ethers.utils.parseEther("1"))); await expect(players.connect(alice).donate(playerId, raffleCost)) .to.emit(donation, "NextGlobalDonationThreshold") - .withArgs( - ethers.utils.parseEther((2000 + Number(ethers.utils.formatEther(raffleCost)) - 1).toString()), - EstforConstants.PRAY_TO_THE_BEARDIE_2 - ) + .withArgs(ethers.utils.parseEther("2000").toString(), EstforConstants.PRAY_TO_THE_BEARDIE_2) .and.to.emit(donation, "LastClanDonationThreshold") .withArgs(clanId, raffleCost, EstforConstants.CLAN_BOOSTER_2);