Skip to content

Commit

Permalink
Misc Improvements (Codehawks Part 3) Remediations (#934)
Browse files Browse the repository at this point in the history
  • Loading branch information
pizzaman1337 authored Jul 8, 2024
2 parents 232d9e8 + 7742774 commit 9770e21
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 5 deletions.
7 changes: 6 additions & 1 deletion protocol/contracts/beanstalk/sun/SeasonFacet/Sun.sol
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,12 @@ contract Sun is Oracle {
}

// Set new soil.
setSoil(Math.min(uint256(-twaDeltaB), uint256(-instDeltaB)));
if (instDeltaB < 0) {
setSoil(Math.min(uint256(-twaDeltaB), uint256(-instDeltaB)));
} else {
setSoil(uint256(-twaDeltaB));
}

}

/**
Expand Down
12 changes: 10 additions & 2 deletions protocol/contracts/libraries/LibUnripe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,13 @@ library LibUnripe {
// But totalRipeUnderlying = CurrentUnderlying * totalUsdNeeded/usdValueRaised to get the total underlying
// redeem = currentRipeUnderlying * (usdValueRaised/totalUsdNeeded) * UnripeAmountIn/UnripeSupply
uint256 underlyingAmount = s.u[unripeToken].balanceOfUnderlying;
redeem = underlyingAmount.mul(s.recapitalized).div(totalUsdNeeded).mul(amount).div(supply);
if(totalUsdNeeded == 0) {
// when totalUsdNeeded == 0, the barnraise has been fully recapitalized.
redeem = underlyingAmount.mul(amount).div(supply);
} else {
redeem = underlyingAmount.mul(s.recapitalized).div(totalUsdNeeded).mul(amount).div(supply);
}

// cap `redeem to `balanceOfUnderlying in the case that `s.recapitalized` exceeds `totalUsdNeeded`.
// this can occur due to unripe LP chops.
if(redeem > underlyingAmount) redeem = underlyingAmount;
Expand All @@ -178,7 +184,9 @@ library LibUnripe {
function getTotalRecapitalizedPercent() internal view returns (uint256 recapitalizedPercent) {
AppStorage storage s = LibAppStorage.diamondStorage();
uint256 totalUsdNeeded = LibFertilizer.getTotalRecapDollarsNeeded();
if(totalUsdNeeded == 0) return 0;
if (totalUsdNeeded == 0) {
return 1e6; // if zero usd needed, full recap has happened
}
return s.recapitalized.mul(DECIMALS).div(totalUsdNeeded);
}

Expand Down
26 changes: 25 additions & 1 deletion protocol/test/Sun.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,31 @@ describe('Sun', function () {
value: 0
})

// twaDeltaB = -100000000000000000
// twaDeltaB = -100000000
// instantaneousDeltaB = -585786437627
// twaDeltaB, case ID
this.result = await this.season.sunSunrise('-585786437627', 8);
await expect(this.result).to.emit(this.season, 'Soil').withArgs(3, '585786437627');
await expect(await this.field.totalSoil()).to.be.equal('585786437627');
})

it("twaDeltaB < 0, -instDeltaB > 0. (uses twaDeltaB)", async function () {
// go forward 1800 blocks
await advanceTime(1800)
// whitelist well to be included in the instantaneous deltaB calculation
await this.silo.mockWhitelistToken(BEAN_ETH_WELL, this.silo.interface.getSighash("mockBDV(uint256 amount)"), "10000", "1");
// set reserves to 0.5M Beans and 1000 Eth
await await this.well.setReserves([to6('500000'), to18('1000')]);
await await this.well.setReserves([to6('500000'), to18('1000')]);
// go forward 1800 blocks
await advanceTime(1800)
// send 0 eth to beanstalk
await user.sendTransaction({
to: this.diamond.address,
value: 0
})

// twaDeltaB = +500_000
// instantaneousDeltaB = -585786437627
// twaDeltaB, case ID
this.result = await this.season.sunSunrise('-585786437627', 8);
Expand Down
34 changes: 34 additions & 0 deletions protocol/test/Unripe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,40 @@ describe('Unripe', function () {
)
})
})

describe('LP chop all of supply', async function () {
beforeEach(async function () {
// totalDollarsneeded = 47
await this.unripeLP.mint(userAddress, to6('189'))
await this.unripe.connect(owner).addUnderlying(
UNRIPE_LP,
to6('100') // balanceOfUnderlying is 25
)
// s.recapitalized=25
await this.fertilizer.connect(user).setPenaltyParams(to6('100'), to6('100'))

// remaining recapitalization = totalDollarsNeeded - s.recapitalized = 100 - 100 = 0
expect(await this.fertilizer.remainingRecapitalization()).to.be.equal(to6('0'))
// s.recapitalized = 100
expect(await this.unripe.getRecapitalized()).to.be.equal(to6('100'))

// 100000000*100000000/100000000*1000000/189000000 = 529100
expect(await this.unripe.getPenalty(UNRIPE_LP)).to.be.equal(to6('0.529100'))
// user chops ~ all the unripe LP supply
this.result = await this.unripe.connect(user).chop(UNRIPE_LP, to6('189'), EXTERNAL, EXTERNAL)
})

it('emits an event, and chopping unripe bean works', async function () {
await expect(this.result).to.emit(this.unripe, 'Chop').withArgs(
user.address,
UNRIPE_LP,
to6('189'),
to6('100.000000') // 100%
)

// attempt to chop unripe bean
})
})

// Same as above but with different transfer modes used
describe('chop, different transfer modes, half the supply, balanceOfUnderlying Max ≠ Unripe Total Supply, TotalSupply > 100, fert 25% sold', async function () {
Expand Down

0 comments on commit 9770e21

Please sign in to comment.