function _extractLiquidationFees(uint256 extraShare, uint256 callerReward)
...
{
callerShare = (extraShare * callerReward) / FEE_PRECISION; // y% of profit goes to caller.
>> feeShare = extraShare - callerShare; // rest goes to the fee
if (feeShare > 0) {
>> uint256 feeAmount = yieldBox.toAmount(assetId, feeShare, false);
>> yieldBox.depositAsset(assetId, address(this), address(penrose), feeAmount, 0);
}
if (callerShare > 0) {
uint256 callerAmount = yieldBox.toAmount(assetId, callerShare, false);
yieldBox.depositAsset(assetId, address(this), msg.sender, callerAmount, 0);
}
}
But _depositFeesToTwTap() uses only refreshPenroseFees() returned yieldBox.toAmount(_assetId, feeShares, false), which consists of interest and borrowing fees only:
This way liquidation fees accumulated on Penrose's YB account are frozen there as there are no Singularity fees distribution mechanics besides withdrawAllMarketFees() $\rightarrow$ _depositFeesToTwTap():
hyh
high
Liquidation fees are permanently frozen on Penrose YB account
Summary
There is no treatment of liquidation fees in SGL, they are frozen on Penrose YB account.
Vulnerability Detail
There are 3 kinds of fees, borrow/interest and liquidation ones. The latter miss the handling logic, so such funds are accumulated and frozen.
Impact
Protocol-wide loss of funds, which othwerwise would be channelled to stakers.
Code Snippet
Interest fees are accumulated in the
accrueInfo.feesEarnedFraction
variable:https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/singularity/SGLCommon.sol#L103-L105
Which is then accumulated on internal Penrose account via withdrawing
feeShares = _removeAsset(_feeTo, msg.sender, balanceOf[address(penrose)])
:https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/Penrose.sol#L565-L568
https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/singularity/Singularity.sol#L285-L298
https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/singularity/SGLCommon.sol#L199-L216
However, liquidation fees are being placed to Penrose account directly and aren't included in the
feeShares = share
variable above:https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/singularity/SGLLiquidation.sol#L297-L312
But
_depositFeesToTwTap()
uses onlyrefreshPenroseFees()
returnedyieldBox.toAmount(_assetId, feeShares, false)
, which consists of interest and borrowing fees only:https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/Penrose.sol#L565-L578
This way liquidation fees accumulated on Penrose's YB account are frozen there as there are no Singularity fees distribution mechanics besides
withdrawAllMarketFees()
$\rightarrow$_depositFeesToTwTap()
:https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/Penrose.sol#L240-L255
Tool used
Manual Review
Recommendation
Consider placing liquidation fees into Penrose internal account, leaving them with common YB account of SGL, e.g.:
https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/singularity/SGLLiquidation.sol#L304-L307