-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Sneaky Ginger Falcon
High
Price Lookup Failure Preventing Claims
Impact
Depositors cannot claim shares due to flawed price lookup logic:
All user deposits become permanently locked
Vulnerability Details
The claimableOf() and _claim() functions use incorrect price lookup method:
https://github.com/sherlock-audit/2025-07-mellow-flexible-vaults/blob/main/flexible-vaults/src/queues/DepositQueue.sol#L126C1-L141C1
function _claim(address account) internal returns (bool) {
DepositQueueStorage storage $ = _depositQueueStorage();
Checkpoints.Checkpoint224 memory request = $.requestOf[account];
uint256 priceD18 = $.prices.lowerLookup(request._key);
if (priceD18 == 0) {
return false;
}
uint256 shares = Math.mulDiv(request._value, priceD18, 1 ether);
delete $.requestOf[account];
if (shares != 0) {
IShareModule(vault()).shareManager().mintAllocatedShares(account, shares);
}
emit DepositRequestClaimed(account, shares, request._key);
return true;
}
/// @inheritdoc IDepositQueue
function claimableOf(address account) public view returns (uint256) {
DepositQueueStorage storage $ = _depositQueueStorage();
Checkpoints.Checkpoint224 memory request = $.requestOf[account];
if (request._key == 0) {
return 0;
}
uint256 priceD18 = $.prices.lowerLookup(request._key);
if (priceD18 == 0) {
return 0;
}
return Math.mulDiv(request._value, priceD18, 1 ether);
}-
Uses lowerLookup() which finds price at greatest timestamp ≤ deposit timestamp
-
Prices are only recorded at report timestamps ≥ deposit timestamp
Result: Lookup always returns 0, making claims impossible
Attack Scenario
User deposits 100 USDC at timestamp T=1000
Oracle reports price at T=2000 (price = 1.1e18)
User tries to claim:
lowerLookup(1000) searches for price ≤ 1000 → finds nothing → returns 0
Claim fails despite valid report
Result: 100 USDC permanently locked, user gets 0 shares