Skip to content

Commit

Permalink
C4 #29 (#885)
Browse files Browse the repository at this point in the history
  • Loading branch information
tbrent authored Aug 9, 2023
1 parent fe5d38d commit e8f5568
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
10 changes: 8 additions & 2 deletions contracts/p0/Furnace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
Expand Down
10 changes: 8 additions & 2 deletions contracts/p1/Furnace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
Expand Down
39 changes: 39 additions & 0 deletions test/Furnace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down

0 comments on commit e8f5568

Please sign in to comment.