The implementation of BlueBerryBank.liquidate is wrong, and the liquidator can get all collaterals and underlying token shares by paying only one debt token.
Vulnerability Detail
When a position is liquidatable, anybody can call BlueBerryBank.liquidate and get some collaterals and underlying token shares stored in a vault after paying some debt. The liquidator pays only one debt token at a time.
If the liquidator pays full debt of a debtToken, the share will be same as oldShare.
Let us get back to BlueBerryBank.liquidate. If share = oldShare, liqSize = pos.collateralSize, and all of collateral amounts will be sent to the liquidator. And pos.collateralSize will be 0, and similar things happend to uVaultShare and uTokenSize.
The liquidator paid only one debt, but he will get all of collateral and underlying shares stored in vault. The collateral and underlying supports all debt tokens, not only one debt token, so this implementation is not correct.
Impact
The liquidator gets more than he should get, so it will cause fund loss of the protocol.
XKET
high
Liquidation logic is not correct
Summary
The implementation of
BlueBerryBank.liquidate
is wrong, and the liquidator can get all collaterals and underlying token shares by paying only one debt token.Vulnerability Detail
When a position is liquidatable, anybody can call
BlueBerryBank.liquidate
and get some collaterals and underlying token shares stored in a vault after paying some debt. The liquidator pays only one debt token at a time.If the liquidator pays full debt of a
debtToken
, the share will be same asoldShare
.Because when the liquidator pays
oldDebt
inrepayInternal
,lessShare
will be same asoldShare
.Let us get back to
BlueBerryBank.liquidate
. Ifshare
=oldShare
,liqSize
=pos.collateralSize
, and all of collateral amounts will be sent to the liquidator. Andpos.collateralSize
will be 0, and similar things happend touVaultShare
anduTokenSize
.The liquidator paid only one debt, but he will get all of collateral and underlying shares stored in vault. The collateral and underlying supports all debt tokens, not only one debt token, so this implementation is not correct.
Impact
The liquidator gets more than he should get, so it will cause fund loss of the protocol.
Code Snippet
https://github.com/sherlock-audit/2023-02-blueberry/blob/main/contracts/BlueBerryBank.sol#L522-L527 https://github.com/sherlock-audit/2023-02-blueberry/blob/main/contracts/BlueBerryBank.sol#L760-L787 https://github.com/sherlock-audit/2023-02-blueberry/blob/main/contracts/BlueBerryBank.sol#L529 https://github.com/sherlock-audit/2023-02-blueberry/blob/main/contracts/BlueBerryBank.sol#L533 https://github.com/sherlock-audit/2023-02-blueberry/blob/main/contracts/BlueBerryBank.sol#L538-L544
Tool used
Manual Review
Recommendation
Use
liqSize = (pos.collateralSize * share) * (debt of debtToken) / oldShare / (total debt)
instead of
liqSize = (pos.collateralSize * share) / oldShare
.And same things to
uVaultShare
anduTokenSize
.Duplicate of #127