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

Report #34870

Report Date
August 29, 2024
Status
Closed
Payout

Silent Execution Halt: Division by Zero in Constant Product Calculation

‣
Report Info

Report ID

#34870

Report type

Smart Contract

Has PoC?

Yes

Target

https://etherscan.io/address/0xBA150C2ae0f8450D4B832beeFa3338d4b5982d26

Impacts

Theft of gas

Description

A critical vulnerability in the ConstantProduct2 contract allows for incorrect division by zero in the roundUpDiv function, which is called by calcReserve. This flaw can cause transaction failures, leading to potential griefing attacks and unnecessary gas spending by users. The vulnerability arises due to the absence of a zero-check on the divisor, which can potentially stop the contract from operating when the reserve is zero.

Vulnerability Details

The roundUpDiv function lacks a check to ensure that the divisor (b) is non-zero before performing the division.

Impact Details

  • An attacker can exploit this vulnerability to cause repeated transaction failures, disrupting users and potentially halting operations of the smart contract.
  • Users attempting to execute transactions that trigger this error will incur gas costs without achieving their intended outcomes.

References

    function roundUpDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
@=>     return (a - 1) / b + 1;
    }

Proof of concept

In roundUpDiv Function

Condition Occurs:

  • If the value of b is zero, then (a - 1) / b will attempt to divide by zero.

Why Occurs:

  • There is no check to ensure that b is not zero before the division is performed.

Effect:

  • Will cause contract execution failure and abort the transaction.

Impact on calcReserve Function

Condition Occurs:

  • calcReserve calls roundUpDiv with b as reserves[j == 1 ? 0 : 1] * EXP_PRECISION.
  • If reserves[j == 1 ? 0 : 1] is zero, then b will be zero.

Why Occurs:

  • If any of the reserves in reserves is zero, then the product by EXP_PRECISION is still zero.

Result:

  • The calcReserve function will fail due to division by zero, causing the transaction to be aborted.

Recommendation

Introduce a require statement to ensure that the divisor is not zero before performing the division.

function roundUpDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+   require(b != 0, "Division by zero");
    if (a == 0) return 0;
    return (a - 1) / b + 1;
}

Immunefi Response

Unfortunately, after reviewing your report, Immunefi has decided to close it as it does not meet our project requirements.
Your submission falls under one of the following categories:
  • Non-Vulnerability Issues: These include issues such as typos, layout issues, and other non-security-related problems that do not pose any security threat.
  • Spam Issues: These include reports that are intended to advertise a product or service, to mislead users or defame the company, or are irrelevant to the program.
  • UI/UX Issues: These include issues related to user interface and user experience that do not pose any security threat.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/functions/ConstantProduct2.sol";
import "../src/libraries/LibMath.sol";

contract ConstantProduct2Test is Test {
    ConstantProduct2 constantProduct2;

    function setUp() public {
        constantProduct2 = new ConstantProduct2();
    }

    function testRoundUpDivDivisionByZero() public {
        uint256 a = 1000;
        uint256 b = 0; // Set b to zero

        // Expect the transaction to revert due to division by zero
        vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x12)); // Use the panic code for division by zero
        LibMath.roundUpDiv(a, b);
    }
}