Because of incorrect conditions for interaction with liquidatableAccountsIds
array, code can try to get element by index that is out of range resulting in reverting.
LiquidationBranch.checkLiquidatableAccounts()
is an important function for perp engine as it allows for keeper to get liquidatable accounts so then they can be liquidated. Without proper functioning of this function, liquidating of unhealthy accounts can not be possible which can lead to loss for the protocol.
LiquidationBranch.checkLiquidatableAccounts()
create an array that contains ids of liquidatable trading accounts. The length of this array is the difference between upper and lower bounds:
After that, it iterates through provided amount of accounts (upperBound - lowerBound) and checks if this account is liquidatable:
If an account is liquidatable then current trading account id is set to liquidatableAccountsIds
. Index out of bounds error can occur if lowerBound
is not 0. It would happen if liquidatableAccountsIds
length is less than current index i
and current account is liquidatable then it would try to set current account as liquidatable in array.
Lets take an example. Protocol has 10 accounts. First 8 are healthy, other 2 are liquidatable. Keeper tries to call this function with lower bound 5 and upper bound 10. In that case liquidatableAccountsIds
length would be upperBound - lowerBound => 10 - 5 = 5. After iterating to 9th account (which is 4th in loop) index i
would be 9. After checking TradingAccount.isLiquidatable(requiredMaintenanceMarginUsdX18, marginBalanceUsdX18)
that will return true
code will try to set current tradingAccountId to liquidatableAccountsIds
array with current index, but because length of array is 5 and index is 9 transaction would revert.
Modify test/integration/perpetuals/liquidation-branch/checkLiquidatableAccounts/checkLiquidatableAccounts.t.sol test with next code and execute this test with forge test --match-test testFuzz_OutOfBoundErrorWhenLowerBoundIsNotZero
:
Specifically this error can be prevented by checking as part of this condition to check whether current index is greater or equal to liquidatableAccountsIds
array length but this would make function unusable as with large lowerBound (where lowerBound >= upperBound - lowerBound) it would just return an empty array. I would recommend rewriting function where you first get amount of liquidatable accounts, then create array with length of liquidatable accounts and then iterate to fill this array.
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.