The performLowerBound
parameter in the LiquidationKeeper::checkUpkeep
function is used for two distinct purposes: (1) as a threshold for determining if upkeep is needed (2) and as a starting index for selecting accounts to be liquidated.
This will lead to skip liquidation of liquidatable accounts which indexes are below performLowerBound
performLowerBound
is first used as a threshold to determine if upkeep is needed:
It is then used as the starting index for selecting accounts to be liquidated:
These two purposes are logically distinct and not related.
Using the same parameter for both purposes will lead to unexpected behavior.
Example:
performLowerBound = 3
and performUpperBound = 10
checkLiquidatableAccounts
returns an array of 4
accounts all liquidatables
boundsDelta = 7
and so bounded to 4
because of liquidatableAccountsIds.length
the first accessed index inside the for loop is accountIdIndexAtLiquidatableAccounts = performLowerBound + i = 3
as liquidatableAccountsIds.length = 4
, only the last element will be accessed liquidatableAccountsIds[3]
the 3 other accounts are not liquidated
Unintended skipping of liquidatable accounts.
Manual review
Separate the two concerns into distinct parameters, performLowerBound
to decide if upkeep is needd, and startIndex
which could simply be the first element of liquidatableAccountsIds
It also seems that boundsDelta
could simply be performUpperBound
, as this would restrict the upkeep to this maximum value of iteration.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.