Beanstalk Notion
Beanstalk Notion
/
🪲
Bug Reports
/
BIC Notes
/
📄
Report #37605
📄

Report #37605

Report Date
December 10, 2024
Status
Closed
Payout

LibIncentive library does not pay a reward for seasons started with a delay of 239 or 240 seconds which leads to loss of yield

‣
Report Info

Report ID

#37605

Report type

Smart Contract

Has PoC?

Yes

Target

https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70

Impacts

Permanent freezing of unclaimed yield

Description

Every season, someone calls gm() or sunrise() on the Beanstalk diamond to start the next season. The contract calculates what incentive the caller should receive which is minted bean tokens. If the new season is started with a delay of 239 or 240 seconds, no rewards will be minted.

The finding has been submitted in partnership with [TrustSec](https://www.trust-security.xyz/)

Vulnerability Details

The root cause is in LibIncentive.sol

        } else if (secondsLate <= 240) {
            if (secondsLate <= 212) {
                return _scaleReward(beans, 8_243_872);
            }
...
        } else if (secondsLate <= 270) {
            if (secondsLate <= 240) {
                return _scaleReward(beans, 10_892_553);
            }

In case the secondsLate is 239, 240, it goes into the (secondsLate <= 240) outer clause, but does not hit any of the inner if clauses, so it skips the return statement. The function will return 0 and not mint any tokens.

The check below has been erroneously moved to the <= 270 block. It will never get hit.

            if (secondsLate <= 240) {
                return _scaleReward(beans, 10_892_553);
            }

The mitigation is to move the inner secondsLate <= 240 clause into the outer secondsLate <= 240 clause:

Impact Details

The correct amount of Bean tokens to mint for a delay of 240 seconds is 54462765 or 54 tokens which doesn't get minted and is lost. As such, the vulnerability presents a "permanent loss of unclaimed yield".

References

Vulnerable LibIncentive library in production: https://arbiscan.io/address/0x64504c8b23350FEEebd5BB978633C0CfFfb9D536#code

Code in repository: https://github.com/BeanstalkFarms/Beanstalk/blob/master/protocol/contracts/libraries/LibIncentive.sol

Affected upstream file: https://github.com/BeanstalkFarms/Beanstalk/blob/master/protocol/contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol

Proof of concept

The following test can be added in the repository to the Season.test.js file:

it.only("240 seconds after season incentive", async function () {
    await setToSecondsAfterHour(240);
    await beanstalk.connect(owner).sunrise();
    expect(await bean.balanceOf(owner.address)).to.be.equal(to6("0"));
});

It shows that with a delay of 240 seconds, no rewards are paid out.

BIC Response

Thank you for your report. While your findings are correct, this is already a known issue. In our bug bounty program documentation, it reads:

Any unfixed vulnerabilities mentioned in these reports (or otherwise known by the BIC or BCM) are not eligible for a reward.

Therefore we are closing this report and no reward will be issued.

diff --git a/protocol/contracts/libraries/LibIncentive.sol b/protocol/contracts/libraries/LibIncentive.sol
index e4f575295..3a323c575 100644
--- a/protocol/contracts/libraries/LibIncentive.sol
+++ b/protocol/contracts/libraries/LibIncentive.sol
@@ -434,10 +434,10 @@ library LibIncentive {
             if (secondsLate <= 238) {
                 return _scaleReward(beans, 10_677_927);
             }
-        } else if (secondsLate <= 270) {
             if (secondsLate <= 240) {
                 return _scaleReward(beans, 10_892_553);
             }
+        } else if (secondsLate <= 270) {
             if (secondsLate <= 242) {
                 return _scaleReward(beans, 11_111_494);
             }