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

`LiquidationKeeper::performUpkeep` has wrong decode format leading to get wrong `accountsToBeLiquidated`

Summary

LiquidationKeeper::performUpkeep has wrong decode format leading to get wrong accountsToBeLiquidated.

Vulnerability Details

In LiquidationKeeper::checkUpkeep, when upkeepNeeded is equal to true, performUpkeep() will be called.
The performData (performUpkeep function input paramater) is the data which was passed back from the checkData simulation. In this case the input of performUpkeep() is extraData = abi.encode(accountsToBeLiquidated, address(this)).

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); // @audit-info upkeepNeeded = false
}
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); // @audit-info upkeepNeeded = true
}

However the decode of performData misses the address(this). The result of decoded accountsToBeLiquidated will be wrong.

function performUpkeep(bytes calldata peformData) external override onlyForwarder {
@> uint128[] memory accountsToBeLiquidated = abi.decode(peformData, (uint128[]));
LiquidationKeeperStorage storage self = _getLiquidationKeeperStorage();
(IPerpsEngine perpsEngine) = (self.perpsEngine);
perpsEngine.liquidateAccounts(accountsToBeLiquidated);
}

Impact

LiquidationKeeper::performUpkeep has wrong decode format leading to get wrong accountsToBeLiquidated.

Tools Used

manual

Recommendations

function performUpkeep(bytes calldata peformData) external override onlyForwarder {
- uint128[] memory accountsToBeLiquidated = abi.decode(peformData, (uint128[]));
+ (uint128[] memory accountsToBeLiquidated,) = abi.decode(peformData, (uint128[], address));
LiquidationKeeperStorage storage self = _getLiquidationKeeperStorage();
(IPerpsEngine perpsEngine) = (self.perpsEngine);
perpsEngine.liquidateAccounts(accountsToBeLiquidated);
}
Updates

Lead Judging Commences

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

Error is in decoding of `peformData`

Support

FAQs

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