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

The `oracle` could be initialized with empty `reserves` data

Summary

If _init() is called with an empty reserves array, it would initialize the oracle without any reserve data, which could lead to incorrect behavior in subsequent calculations that assume the presence of valid reserve data.

Vulnerability Details

The update() function is responsible for updating the oracle's state with new reserve data. It calls _init() internally when the oracle is being used for the first time (indicated by lastTimestamp being 0).

if (pumpState.lastTimestamp == 0) {
_init(slot, uint40(block.timestamp), reserves);
return;
}

The issue arises because update() does not check whether the reserves array passed to it is non-empty before calling _init(). If update() is called with an empty reserves array, _init() will be called with this empty array, leading to the oracle being initialized with no reserve data.

Initialization with Empty Data:

_init()

function _init(bytes32 slot, uint40 lastTimestamp, uint256[] memory reserves) internal {
uint256 numberOfReserves = reserves.length;
bytes16[] memory byteReserves = new bytes16[](numberOfReserves);
// 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);
assembly {
slot := add(slot, numSlots)
}
slot.storeBytes16(byteReserves); // EMA Reserves
}

There is a missing check for empty reserves array here and therefore if update() is called with an empty reserves array, _init() will set up the oracle with no reserve data, which is not valid for an oracle that is supposed to track reserves.

Impact

Functions that rely on reserve data, such as readLastInstantaneousReserves(), readInstantaneousReserves(), readLastCumulativeReserves(), readCumulativeReserves(), and readTwaReserves(), would then revert everytime with NotInitialized() error since numberOfReserves will always be zero.

Tools Used

Manual Review

Recommendations

_init() should include a check to ensure that the reserves array is not empty before proceeding with the initialization.

function _init(bytes32 slot, uint40 lastTimestamp, uint256[] memory reserves) internal {
uint256 numberOfReserves = reserves.length;
require(numberOfReserves > 0, "Reserves data cannot be empty");
// ... existing _init logic ...
}
Updates

Lead Judging Commences

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

Informational/Invalid

Support

FAQs

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