📄

Report #30128

Report Date
April 16, 2024
Status
Closed
Payout

Redundant event emission can be misleading to oracles and also blot up the event log.

Report Info

Report ID#30128

Report type

Smart Contract

Has PoC?

Yes

Target

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

Impacts

  • Contract fails to deliver promised returns, but doesn't lose value

Description

The Fertilizer contract emits the ClaimFertilizer event in both the beanstalkUpdate and beanstalkMint functions, potentially leading to confusion and misinterpretation of contract behavior. This redundancy poses a risk of inefficiency and could result in developers and users misunderstanding the intended purpose of each function.

Vulnerability Details

The vulnerability lies in the redundant emission of the ClaimFertilizer event in both the beanstalkUpdate and beanstalkMint functions of the Fertilizer contract. This duplication can lead to confusion among developers and users, as it's not clear from the event alone whether the fertilizer was claimed due to an update or a minting operation. Such ambiguity can result in misinterpretation of contract behavior and may lead to inefficient use of blockchain resources.

...
    event ClaimFertilizer(uint256[] ids, uint256 beans);
...
  function beanstalkUpdate(
        address account,
        uint256[] memory ids,
        uint128 bpf
    ) external onlyOwner returns (uint256) {
        return __update(account, ids, uint256(bpf));
    }

    function beanstalkMint(address account, uint256 id, uint128 amount, uint128 bpf) external onlyOwner {
        if (_balances[id][account].amount > 0) {
            uint256[] memory ids = new uint256[](1);
            ids[0] = id;
            _update(account, ids, bpf);
        }
        _balances[id][account].lastBpf = bpf;
        _safeMint(
            account,
            id,
            amount,
            bytes('0')
        );
    }
    function _update(
        address account,
        uint256[] memory ids,
        uint256 bpf
    ) internal {
        uint256 amount = __update(account, ids, bpf);
        if (amount > 0) IBS(owner()).payFertilizer(account, amount);
    }

    function __update(
        address account,
        uint256[] memory ids,
        uint256 bpf
    ) internal returns (uint256 beans) {
        for (uint256 i; i < ids.length; ++i) {
            uint256 stopBpf = bpf < ids[i] ? bpf : ids[i];
            uint256 deltaBpf = stopBpf - _balances[ids[i]][account].lastBpf;
            if (deltaBpf > 0) {
                beans = beans.add(deltaBpf.mul(_balances[ids[i]][account].amount));
                _balances[ids[i]][account].lastBpf = uint128(stopBpf);
            }
        }
        emit ClaimFertilizer(ids, beans);
    }
...

Impact Details

This includes potential confusion and misunderstanding of contract behavior, increased gas costs due to redundant event emission, and inefficiency in the use of blockchain resources. While there may not be direct financial losses associated with this, the lack of clarity in contract events can lead to indirect consequences such as decreased user trust and adoption.

References

https://www.rareskills.io/post/ethereum-events

Proof of concept

1. When the beanstalkUpdate function is called, it directly calls the __update which emits the ClaimFertilizer event. 2. When the beanstalkMint is called, it indirectly calls the __update via the _update function and eventually emits the ClaimFertilizer event.

Immunefi Response

Thank you for your submission to the Beanstalk bug bounty program. Unfortunately, after reviewing your report, Immunefi has decided to close it due to the assessed impact being out of scope.

Immunefi review:

  • The claimed impact Contract fails to deliver promised returns, but doesn't lose value by the whitehat is in scope of the bug bounty program but the assessed impact doesn't match with the claimed impact for the following reasons.
    • The use of the same event signature in these functions does not result in a failed delivery of promised returns
  • assessed asset by the triage team is in scope for the bug bounty program
  • PoC has not been submitted to the project

Please note that the project will receive a report of the closed submission and may choose to re-open it, but they are not obligated to do so.