29188 - [SC - Insight] StakingBonuscalculateBonus wrongly utilizes BPS

Submitted on Mar 10th 2024 at 01:21:12 UTC by @jovi for Boost | ZeroLend

Report ID: #29188

Report type: Smart Contract

Report severity: Insight

Target: https://github.com/zerolend/governance

Impacts:

  • Protocol insolvency

  • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Brief/Intro

The calculateBonus function at the StakingBonus contract utilizes BPS in a pattern that may lead to over-accrual of bonuses.

Vulnerability Details

Basis points (bps) are a common unit of measure for interest rates and other percentages in finance. One basis point is equal to 1/100 of 1%. In decimal form, one basis point appears as 0.0001 (0.01/100) The usage of basis points is correctly implemented in other parts of the code but not in this one, as it divides the bonusBps variable by 100.

function calculateBonus(
        uint256 amount
    ) public view override returns (uint256) {
        uint256 bonus = (amount * bonusBps) / 100;
        // if we don't have enough funds to pay out bonuses, then return 0
        if (zero.balanceOf(address(this)) < bonus) return 0;
        return (amount * bonusBps) / 100;
    }

Impact Details

If the admin decides to set a bonus of 1% then call setBonusBps at the contract, the bonus calculation at the calculateBonus view function will actually return 100%. The reason for that is it will divide the equivalent of 1% in bps (which is 100) by 100. This is concerning as any bonus rate over 1% will yield more value in bonuses than in the actual pending amount. It can generate bonuses of up to 100 times the pending amount.

References

calculateBonus is called at the onERC721Received function at the StakingBonus contract: governance/contracts/vesting/StakingBonus.sol at a30d8bb825306dfae1ec5a5a47658df57fd1189b · zerolend/governance (github.com)

calculateBonus implementation at the StakingBonus contract: https://github.com/zerolend/governance/blob/a30d8bb825306dfae1ec5a5a47658df57fd1189b/contracts/vesting/StakingBonus.sol#L89C5-L96C6

Proof of concept

Paste the following code snippet inside the test folder:

Set up the StakingBonus contract, give him some ZERO balance. Call setBonusBps with 1%, which should be 100 bps. Call calculate bonus with a amount and watch it return the amount. Set bonus to 100%. Watch calculate bonus become 100x the amount.

Run the test with the following command:

Last updated

Was this helpful?