Closed sherlock-admin4 closed 5 months ago
Issue is a duplicate of 63 and is invalid for the same reason
If Bob did not call the collateral updates for many epochs _revertIfUndercollateralized won't proceed. maxAllowedActiveOwedMOf will be 0 because collateralOf will be 0 because block.timestamp >= collateralExpiryTimestampOf(minter_)
xiaoming90
high
Minter can retrieve collateral even if its account is underwater
Summary
Minter can retrieve collateral even if its account is underwater. As a result, the protocol could incur excessive bad debt, the M tokens will not be backed by sufficient collateral assets, there will be an increased risk of insolvency, and the M token might depeg.
Vulnerability Detail
When the minters want to withdraw their collateral, they will execute the
proposeRetrieval
function with the amount of collateral to be withdrawn. Toward the end of the function (in Line 234), it will call the_revertIfUndercollateralized
function to ensure that the withdrawal will not result in the account being undercollateralized.https://github.com/sherlock-audit/2023-10-mzero/blob/main/protocol/src/MinterGateway.sol#L214
However, the
_revertIfUndercollateralized
function does not consider the account's pending penalty to the owned principal due to missed collateral updates. Thus, the owned M used in the check is undervalued, allowing the account to withdraw its collateral even if the account is already under-collateralized when factoring in the pending penalties incurred.https://github.com/sherlock-audit/2023-10-mzero/blob/main/protocol/src/MinterGateway.sol#L1018
In addition, the
activeOwedMOf
function used in Line 1026 above in the_revertIfUndercollateralized
function also does not take into consideration the account's pending penalties.https://github.com/sherlock-audit/2023-10-mzero/blob/main/protocol/src/MinterGateway.sol#L513
The following simplified example illustrates the issue. For simplicity's sake, assume the minter rate is zero, and the mint ratio is 100%.
At T1, Bob's
maxAllowedActiveOwedM_
is 100 based on his collateral assets, and he minted 50 M tokens. Thus, hisactiveOwedMOf
will be 50 M tokens.At T50, Bob did not call the collateral updates for many epochs. As a result, he accumulated a penalty of 100 M tokens for all his missed updates. If one calls the
getPenaltyForMissedCollateralUpdates
against Bob's account, it will return 100 M tokens as Bob's penalty. If someone intends to repay Bob's debt now, they must repay a total debt of 150 M tokens (50 + 100). Bob's account is technically underwater at this point (Debt >maxAllowedActiveOwedM_
).At T51, Bob decided to retrieve 45 of his collateral. When the
_revertIfUndercollateralized
function is executed to check whether Bob's account is undercollateralized via the following logic and determine that Bob's account is still healthy:The protocol will proceed to facilitate the retrieval of 45 collateral for Bob since the protocol deems his account healthy, and his collateral will decrease to 55.
Before the retrieval, 150 debts were backed by 100 collateral. After the retrieval, the 150 debts were backed by 55 collateral. The account and protocol are in a worse position after the retrieval, and its M tokens are backed by fewer collateral. This indicates that the collateral checks and the mechanism to ensure the protocol's solvency are inadequate.
Impact
The protocol could incur excessive bad debt, the M tokens will not be backed by sufficient collateral assets, there will be an increased risk of insolvency, and the M token might depeg.
Code Snippet
https://github.com/sherlock-audit/2023-10-mzero/blob/main/protocol/src/MinterGateway.sol#L214
Tool used
Manual Review
Recommendation
When determining if an account is undercollateralized during retrieval, the protocol should consider the account's debt in its entirety, including the debt from the accumulated penalties. This will prevent minters whose accounts are already in an unhealthy position due to incurred penalties from retrieving their collateral, which causes the owned M tokens to be backed by even fewer collateral after the transaction.
Duplicate of #63