📄

Report #30125

Report Date
April 16, 2024
Status
Closed
Payout

Unfillable Pod Listings caused by large minFillAmount

Report Info

Report ID

#30125

Report type

Smart Contract

Has PoC?

Yes

PoC Link

https://gist.github.com/Sentient-XII/1ee73b14df418fe8e565a0a77b1492c1

Target

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

Impacts

  • Contract fails to deliver promised returns, but doesn't lose value
  • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

In the MarketPlaceFacet.sol when users create listings by calling function createPodListing, the uin256 minFillAmount can be set to large values as large as type(uint256).max because there is no range check for minimum fill value. Essentially, setting minFillAmount to the maximum value creates an impossible condition for buyers. No transaction can fulfill the requirement of buying uint256.max pods, so no purchase can be made.

Vulnerability Details

Users can list pods by calling the following function that calls an internal function of the same name, however there is no range check for minimum value that can lead to impossible to fill amounts.

    function createPodListing(
        uint256 index,
        uint256 start,
        uint256 amount,
        uint24 pricePerPod,
        uint256 maxHarvestableIndex,
        uint256 minFillAmount,
        LibTransfer.To mode
    ) external payable {
        _createPodListing(
            index,
            start,
            amount,
            pricePerPod,
            maxHarvestableIndex,
            minFillAmount,
            mode
        );
    }

    function _createPodListing(
        uint256 index,
        uint256 start,
        uint256 amount,
        uint24 pricePerPod,
        uint256 maxHarvestableIndex,
        uint256 minFillAmount,
        LibTransfer.To mode
    ) internal {
        uint256 plotSize = s.a[msg.sender].field.plots[index];

        require(plotSize >= (start.add(amount)) && amount > 0, "Marketplace: Invalid Plot/Amount.");
        require(pricePerPod > 0, "Marketplace: Pod price must be greater than 0.");
        require(s.f.harvestable <= maxHarvestableIndex, "Marketplace: Expired.");

        if (s.podListings[index] != bytes32(0)) _cancelPodListing(msg.sender, index);

        s.podListings[index] = hashListing(start, amount, pricePerPod, maxHarvestableIndex, minFillAmount, mode);

        bytes memory f;

        emit PodListingCreated(msg.sender, index, start, amount, pricePerPod, maxHarvestableIndex, minFillAmount, f, mode, LibPolynomial.PriceType.Fixed);

    }

When user calls function fillListing that calls the corresponding private function fillListing this check will always fail require(amount >= l.minFillAmount, "Marketplace: Fill must be >= minimum amount.");

    function __fillListing(
        address to,
        PodListing calldata l,
        uint256 amount,
        uint256 beanAmount
    ) private {
        require(amount >= l.minFillAmount, "Marketplace: Fill must be >= minimum amount.");
        require(l.amount >= amount, "Marketplace: Not enough pods in Listing.");

        delete s.podListings[l.index];

        if (l.amount > amount) {
            s.podListings[l.index.add(amount).add(l.start)] = hashListing(
                0,
                l.amount.sub(amount),
                l.pricePerPod,
                l.maxHarvestableIndex,
                l.minFillAmount,
                l.mode
            );
        }

        emit PodListingFilled(l.account, to, l.index, l.start, amount, beanAmount);
    }

Impact Details

Attackers can use this to list pod for sale that only they can cancel, essentially leading to no pods being filled.

  1. Contract fails to deliver promised returns, but doesn't lose value
  2. Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

References

Add any relevant links to documentation or code

Proof of concept

  1. mkdir beanPOC
  2. cd beanPOC
  3. forge init (delete default Counter.sol and Counter.t.sol)
  4. run with forge test --contracts ./src/beanMarket.sol -vv

https://gist.github.com/Sentient-XII/1ee73b14df418fe8e565a0a77b1492c1

BIC Response

This is not a valid bug report because it describes expected behavior. Furthermore, creating a Pod Listing with a minFillAmount that cannot reasonably be satisfied only creates a cost to the creator of the Pod Listing themselves (the cost of gas). There is no reason for Beanstalk to impose arbitrary conditions on the minFillAmount parameter.

Due to these reasons, we are closing the submission and no reward will be issued.