From e8f5568d35502bc8e0d7ebf5597976b5205be0c7 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Wed, 9 Aug 2023 16:56:59 -0400 Subject: [PATCH] C4 #29 (#885) --- contracts/p0/Furnace.sol | 10 ++++++++-- contracts/p1/Furnace.sol | 10 ++++++++-- test/Furnace.test.ts | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/contracts/p0/Furnace.sol b/contracts/p0/Furnace.sol index 869a3eff7..aa99a8140 100644 --- a/contracts/p0/Furnace.sol +++ b/contracts/p0/Furnace.sol @@ -58,8 +58,14 @@ contract FurnaceP0 is ComponentP0, IFurnace { /// Ratio setting /// @custom:governance function setRatio(uint192 ratio_) public governance { - // solhint-disable-next-line no-empty-blocks - try this.melt() {} catch {} + if (lastPayout > 0) { + // solhint-disable-next-line no-empty-blocks + try this.melt() {} catch { + uint48 numPeriods = uint48((block.timestamp) - lastPayout) / PERIOD; + lastPayout += numPeriods * PERIOD; + lastPayoutBal = main.rToken().balanceOf(address(this)); + } + } require(ratio_ <= MAX_RATIO, "invalid ratio"); // The ratio can safely be set to 0, though it is not recommended emit RatioSet(ratio, ratio_); diff --git a/contracts/p1/Furnace.sol b/contracts/p1/Furnace.sol index 3259e48fd..923ba3373 100644 --- a/contracts/p1/Furnace.sol +++ b/contracts/p1/Furnace.sol @@ -90,8 +90,14 @@ contract FurnaceP1 is ComponentP1, IFurnace { /// Ratio setting /// @custom:governance function setRatio(uint192 ratio_) public governance { - // solhint-disable-next-line no-empty-blocks - if (lastPayout > 0) try this.melt() {} catch {} + if (lastPayout > 0) { + // solhint-disable-next-line no-empty-blocks + try this.melt() {} catch { + uint48 numPeriods = uint48((block.timestamp) - lastPayout) / PERIOD; + lastPayout += numPeriods * PERIOD; + lastPayoutBal = rToken.balanceOf(address(this)); + } + } require(ratio_ <= MAX_RATIO, "invalid ratio"); // The ratio can safely be set to 0 to turn off payouts, though it is not recommended emit RatioSet(ratio, ratio_); diff --git a/test/Furnace.test.ts b/test/Furnace.test.ts index de3a60261..15776210b 100644 --- a/test/Furnace.test.ts +++ b/test/Furnace.test.ts @@ -446,6 +446,45 @@ describe(`FurnaceP${IMPLEMENTATION} contract`, () => { expect(diff).to.be.lte(expectedDiff) }) + + it('Regression test -- C4 June 2023 Issue #29', async () => { + // https://github.com/code-423n4/2023-06-reserve-findings/issues/29 + + // Transfer to Furnace and do first melt + await rToken.connect(addr1).transfer(furnace.address, bn('10e18')) + await setNextBlockTimestamp(Number(await getLatestBlockTimestamp()) + Number(ONE_PERIOD)) + await furnace.melt() + + // Should have updated lastPayout + lastPayoutBal + expect(await furnace.lastPayout()).to.be.closeTo(await getLatestBlockTimestamp(), 12) + expect(await furnace.lastPayout()).to.be.lte(await getLatestBlockTimestamp()) + expect(await furnace.lastPayoutBal()).to.equal(bn('10e18')) + + // Advance 99 periods -- should melt at old ratio + await setNextBlockTimestamp(Number(await getLatestBlockTimestamp()) + 99 * Number(ONE_PERIOD)) + + // Freeze and change ratio + await main.connect(owner).freezeForever() + const maxRatio = bn('1e14') + await expect(furnace.connect(owner).setRatio(maxRatio)) + .to.emit(furnace, 'RatioSet') + .withArgs(config.rewardRatio, maxRatio) + + // Should have updated lastPayout + lastPayoutBal + expect(await furnace.lastPayout()).to.be.closeTo(await getLatestBlockTimestamp(), 12) + expect(await furnace.lastPayout()).to.be.lte(await getLatestBlockTimestamp()) + expect(await furnace.lastPayoutBal()).to.equal(bn('10e18')) // no change + + // Unfreeze and advance 1 period + await main.connect(owner).unfreeze() + await setNextBlockTimestamp(Number(await getLatestBlockTimestamp()) + Number(ONE_PERIOD)) + await expect(furnace.melt()).to.emit(rToken, 'Melted') + + // Should have updated lastPayout + lastPayoutBal + expect(await furnace.lastPayout()).to.be.closeTo(await getLatestBlockTimestamp(), 12) + expect(await furnace.lastPayout()).to.be.lte(await getLatestBlockTimestamp()) + expect(await furnace.lastPayoutBal()).to.equal(bn('9.999e18')) + }) }) describeExtreme('Extreme Bounds', () => {