DeFiHardhat
12,000 USDC
View results
Submission Details
Severity: low
Invalid

DOS can happen due to xero input to _getSlotsOffset

Summary

if numberOfReserves is zero then the _getSlotsOffset function will be get DOS, it can get out of gas.

Vulnerability Details

function _getSlotsOffset(uint256 numberOfReserves) internal pure returns (uint256 _slotsOffset) {
_slotsOffset = ((numberOfReserves - 1) / 2 + 1) << 5;
}

function update(uint256[] calldata reserves, bytes calldata data) external {
    (bytes16 alpha, uint256 capInterval, CapReservesParameters memory crp) =
        abi.decode(data, (bytes16, uint256, CapReservesParameters));
    uint256 numberOfReserves = reserves.length;
    PumpState memory pumpState;

    // All reserves are stored starting at the msg.sender address slot in storage.
    bytes32 slot = _getSlotForAddress(msg.sender);

    // Read: Last Timestamp & Last Reserves
    (, pumpState.lastTimestamp, pumpState.lastReserves) = slot.readLastReserves();

    // If the last timestamp is 0, then the pump has never been used before.
    if (pumpState.lastTimestamp == 0) {
        _init(slot, uint40(block.timestamp), reserves);
        return;
    }

    bytes16 alphaN;
    bytes16 deltaTimestampBytes;
    uint256 capExponent;
    // Isolate in brackets to prevent stack too deep errors
    {
        uint256 deltaTimestamp = _getDeltaTimestamp(pumpState.lastTimestamp);
        // If no time has passed, don't update the pump reserves.
        if (deltaTimestamp == 0) return;
        alphaN = alpha.powu(deltaTimestamp);
        deltaTimestampBytes = deltaTimestamp.fromUInt();
        // Round up in case capInterval > block time to guarantee capExponent > 0 if time has passed since the last update.
        capExponent = calcCapExponent(deltaTimestamp, capInterval);
    }

    pumpState.lastReserves = _capReserves(msg.sender, pumpState.lastReserves, reserves, capExponent, crp);

    // Read: Cumulative & EMA Reserves
    // Start at the slot after `pumpState.lastReserves`

@>> uint256 numSlots = _getSlotsOffset(numberOfReserves);
assembly {
slot := add(slot, numSlots)

function _init(bytes32 slot, uint40 lastTimestamp, uint256[] memory reserves) internal {
uint256 numberOfReserves = reserves.length;
bytes16[] memory byteReserves = new bytes16;

    // Skip {_capReserve} since we have no prior reference

    for (uint256 i; i < numberOfReserves; ++i) {
        uint256 _reserve = reserves[i];
        if (_reserve == 0) return;
        byteReserves[i] = _reserve.fromUIntToLog2();
    }

    // Write: Last Timestamp & Last Reserves
    slot.storeLastReserves(lastTimestamp, reserves);

    // Write: EMA Reserves
    // Start at the slot after `byteReserves`
   @>> uint256 numSlots = _getSlotsOffset(numberOfReserves);

Impact

Many function will get out of gas due to zero input to the getSlotsOffset.

Tools Used

Recommendations

check numberOfReserves is greater than 0.

Updates

Lead Judging Commences

giovannidisiena Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Informational/Invalid

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.