DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: low
Invalid

Unoptimized Iteration in checkUpkeep function

Relevant GitHub Links

https://github.com/Cyfrin/2024-07-zaros/blob/main/src/external/chainlink/keepers/liquidation/LiquidationKeeper.sol#L44-L88

Summary

The loop in checkUpkeep does not have any gas optimization measures and could potentially lead to high gas consumption for large ranges.

Vulnerability Details

Inefficient Iteration: Looping through large ranges without optimization.

function checkUpkeep(bytes calldata checkData)
external
view
returns (bool upkeepNeeded, bytes memory performData)
{
(uint256 checkLowerBound, uint256 checkUpperBound, uint256 performLowerBound, uint256 performUpperBound) =
abi.decode(checkData, (uint256, uint256, uint256, uint256));
if (checkLowerBound >= checkUpperBound || performLowerBound >= performUpperBound) {
revert Errors.InvalidBounds();
}
IPerpsEngine perpsEngine = _getLiquidationKeeperStorage().perpsEngine;
uint128[] memory liquidatableAccountsIds =
perpsEngine.checkLiquidatableAccounts(checkLowerBound, checkUpperBound);
uint128[] memory accountsToBeLiquidated;
if (liquidatableAccountsIds.length == 0 || liquidatableAccountsIds.length <= performLowerBound) {
performData = abi.encode(accountsToBeLiquidated);
return (upkeepNeeded, performData);
}
uint256 boundsDelta = performUpperBound - performLowerBound;
uint256 performLength =
boundsDelta > liquidatableAccountsIds.length ? liquidatableAccountsIds.length : boundsDelta;
accountsToBeLiquidated = new uint128[](performLength);
for (uint256 i; i < performLength; i++) {
uint256 accountIdIndexAtLiquidatableAccounts = performLowerBound + i;
if (accountIdIndexAtLiquidatableAccounts >= liquidatableAccountsIds.length) {
break;
}
accountsToBeLiquidated[i] = liquidatableAccountsIds[accountIdIndexAtLiquidatableAccounts];
if (!upkeepNeeded && liquidatableAccountsIds[accountIdIndexAtLiquidatableAccounts] != 0) {
upkeepNeeded = true;
}
}
bytes memory extraData = abi.encode(accountsToBeLiquidated, address(this));
return (upkeepNeeded, extraData);
}

Impact

High Gas Costs: Inefficient loops can lead to high gas consumption and potential transaction reversion.

Tools Used

Manual

Recommendations

Implement gas-efficient looping mechanisms or break down the process into smaller chunks.

function checkUpkeep(bytes calldata checkData)
external
view
returns (bool upkeepNeeded, bytes memory performData)
{
(uint256 checkLowerBound, uint256 checkUpperBound, uint256 performLowerBound, uint256 performUpperBound) =
abi.decode(checkData, (uint256, uint256, uint256, uint256));
if (checkLowerBound >= checkUpperBound || performLowerBound >= performUpperBound) {
revert Errors.InvalidBounds();
}
IPerpsEngine perpsEngine = _getLiquidationKeeperStorage().perpsEngine;
uint128[] memory liquidatableAccountsIds =
perpsEngine.checkLiquidatableAccounts(checkLowerBound, checkUpperBound);
uint128[] memory accountsToBeLiquidated;
if (liquidatableAccountsIds.length == 0 || liquidatableAccountsIds.length <= performLowerBound) {
performData = abi.encode(accountsToBeLiquidated);
return (upkeepNeeded, performData);
}
uint256 boundsDelta = performUpperBound - performLowerBound;
uint256 performLength =
boundsDelta > liquidatableAccountsIds.length ? liquidatableAccountsIds.length : boundsDelta;
accountsToBeLiquidated = new uint128[](performLength);
+ uint256 MAX_ITERATIONS = 100; // Example limit to avoid excessive gas consumption
+ for (uint256 i = 0; i < performLength && i < MAX_ITERATIONS; i++) {
uint256 accountIdIndexAtLiquidatableAccounts = performLowerBound + i;
if (accountIdIndexAtLiquidatableAccounts >= liquidatableAccountsIds.length) {
break;
}
accountsToBeLiquidated[i] = liquidatableAccountsIds[accountIdIndexAtLiquidatableAccounts];
if (!upkeepNeeded && liquidatableAccountsIds[accountIdIndexAtLiquidatableAccounts] != 0) {
upkeepNeeded = true;
}
}
bytes memory extraData = abi.encode(accountsToBeLiquidated, address(this));
return (upkeepNeeded, extraData);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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