It is possible for a user to have an unliquidatable collateral balance, as even though TradingAccountBranch::depositMargin
check that collateral has configured liquidation priority, if admin decide to call GlobalConfiguration::removeCollateralFromLiquidationPriority
for this particular collateral, it is possible that in a same block a user tx to deposit is executed before the admin call.
This balance will then count as margin balance, but will not be accessible to liquidators.
This can happen by race-condition, which means one tx can simply be placed before the other by bad timing. Especially because on Arbitrum there is no public mempool, and transactions are prioritized on a first-come first-served basis.
This means operator/admin have no options to make sure no one sends collateral right before it get removed from the liquidation priority list.
While the TradingAccountBranch::depositMargin
function ensure that the collateral is on the liquidation priority list L342
:
While (1) GlobalConfiguration::removeCollateralFromLiquidationPriority
do not check if marginCollateralConfiguration.totalDeposited
is zero which is understandable to avoid DoS, (2) TradingAccount::getMarginBalanceUsd
will count this collateral as user's margin balance.
But we see that TradingAccount::getMarginBalanceUsd
is used extensively inside the protocol to calculate user's margin balance, to decide if he can create a market order, if the order can be filled, and if the order must be liquidated
Finally, the last piece that make it risk-free for the user is that TradingAccount::deductAccountMargin
which is used to seize user's collateral during liquidation or when an order is updated to seize losses is only able to seize collaterals that are in the collateralLiquidationPriority
list:
What make it even worse is that if user's position PnL is positive, he will get its profit credited.
A user can open risk-less positions with an unliquidatable collateral, and as such steal funds.
When his position will be liquidated, nothing will be seized as user has no seizable collateral.
If user is in profit, he will be able to get rewarded.
While this require some 'luck' to have the deposit hapenning right before the removal of call, the odds to succeed can be increased as the attacker will most probably know when a collateral will be removed from the list, and make a huge deposit in the same block. The attacker could also simply regularly deposit/withdraw collateral if he has no idea when a collateral will be removed from the list.
Manual review
The fix is pretty simple, only collaterals that are in the collateralLiquidationPriority
should be accounted as user's margin balance.
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.