Closed sherlock-admin2 closed 6 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
valid: there is a decrepancy that will cause the liquidation to revert; high(4)
Escalate
This issue is a duplicate of #180.
Both issues have the same root cause, which is not correctly handling the PnL when updating the total collateral on liquidations. The fix for this issue should be to update the total collateral correctly on liquidate()
, the function _stableCollateralPerShareLiquidation()
doesn't have to change.
Fixing issue #180 will fix this issue as well, therefore, they're duplicates.
Escalate
This issue is a duplicate of #180.
Both issues have the same root cause, which is not correctly handling the PnL when updating the total collateral on liquidations. The fix for this issue should be to update the total collateral correctly on
liquidate()
, the function_stableCollateralPerShareLiquidation()
doesn't have to change.Fixing issue #180 will fix this issue as well, therefore, they're duplicates.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Disagree with the escalation. This issue is not a duplicate of Issue 180.
The root cause of this issue is a discrepancy between the formula used in the invariant check and the actual liquidation function, which will lead to an unexpected revert during the liquidation process, while Issue 180 discusses the wrong formula used when computing the PnL.
Fixing Issue 180 blindly without cross-checking the issue in this report will result in an incomplete fix being implemented.
Most importantly, the solution I proposed in this report:
function _stableCollateralPerShareLiquidation(
..SNIP..
// position is underwater and there is no keeper fee
// evaluate exact decrease in stable collateral
expectedStableCollateralPerShare =
int256(stableCollateralPerShareBefore) +
- ((remainingMargin * 1e18) / int256(stableModule.totalSupply()));
+ (((remainingMargin - positionSummary.profitLoss) * 1e18) / int256(stableModule.totalSupply()));
mapped to the following part (Line 142) of the liquidation logic, where I pointed out the discrepancy. Above uses remainingMargin/settledMargin
, while below uses settledMargin - positionSummary.profitLoss
.
File: LiquidationModule.sol
085: function liquidate(uint256 tokenId) public nonReentrant whenNotPaused liquidationInvariantChecks(vault, tokenId) {
086: FlatcoinStructs.Position memory position = vault.getPosition(tokenId);
..SNIP..
139: // If the settled margin is -ve then the LPs have to bear the cost.
140: // Adjust the stable collateral total to account for user's profit/loss and the negative margin.
141: // Note: We are adding `settledMargin` and `profitLoss` instead of subtracting because of their sign (which will be -ve).
142: vault.updateStableCollateralTotal(settledMargin - positionSummary.profitLoss);
It is unrelated to the solution in Issue 180. In Issue 180, the fix is only to correct the formula within the updateGlobalPositionData
function. Line 142 of the code in the liquidate
function above is correct and mathematically sound and should not be updated to intentionally make it aligned with the invariant check, which will cause another bug to surface if one does so.
@xiaoming9090 we have a few of these underwater case liquidation test scenarios, but none of them revert on liquidation.
If there was an incorrect calculation here, I would expect them to revert, right?
Planning to reject escalation and keep issue state as is.
The root cause of this issue is a discrepancy between the formula used in the invariant check and the actual liquidation function, which will lead to an unexpected revert during the liquidation process, while Issue 180 discusses the wrong formula used when computing the PnL.
I believe this is correct and both reports identify a different issue.
@xiaoming9090 do you have a reply to the sponsor? https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/182#issuecomment-1960453456
@Evert0x This issue should be invalid.
I have reviewed this issue again. When the stableCollateralPerShareBefore
is retrieved from here, the PnL of -5 of the liquidated account already factored in. Thus, the LP's total stable collateral increased by 5.
Subsequently, the settled margin of -3 is added over here. Thus, the overall gain/loss of LP is (5 + -3) = 2. The final result is aligned with the one in the liquidate function, so the invariant check will not revert unexpectedly.
In that case, planning to invalidate (even though this wasn't a proposition in the escalation, but this shows that the two issues are not duplicates and another state change should be made).
Result: Invalid Unique
Rejecting the escalation despite there is a change in issue state since the escalation didn't make correct point.
xiaoming90
high
Inconsistent in the margin transferred to LP during liquidation when settledMargin < 0
Summary
There is a discrepancy in the approach of computing the expected gain and loss per share within the
liquidate
and_stableCollateralPerShareLiquidation
functions, which will lead to an unexpected revert during the liquidation process.Liquidation is the core component of the protocol and is important to the solvency of the protocol. If the liquidation does not execute as intended, underwater positions and bad debt accumulate in the protocol, threatening the solvency of the protocol.
Vulnerability Detail
At Line 109 below, the
settledMargin
is greater than 0, a portion (or all) of the margin will be sent to the liquidator and LPs. If thesettledMargin
is negative, the LPs will bear the cost of the underwater position's loss.When the
liquidate
function is executed, theliquidationInvariantChecks
modifier will be triggered to perform invariant checks before and after the execution.https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/LiquidationModule.sol#L85
The
liquidationInvariantChecks
modifier will trigger the_stableCollateralPerShareLiquidation
function internally. This function will compute theexpectedStableCollateralPerShare
based on the remaining margin (also calledsettledMargin
), as shown in Line 130 below.Assume that the liquidated position's current
settledMargin
is -3 (marginDeposit=2, accruedFee=0, PnL=-5).In this case, at Line 142 above within the
liquidate
function, the expected gain or loss of the LP is computed viasettledMargin - positionSummary.profitLoss
, which is equal to +2 (-3 - (-5))However, within the invariant check (
_stableCollateralPerShareLiquidation
) below, at Line 150 below, the expected gain or loss of the LP is computed only via thesettledMargin
(remaining margin), which is equal to -3.Thus, there is a discrepancy in the approach of computing the expected gain and loss per share within the
liquidate
and_stableCollateralPerShareLiquidation
functions, and theexpectedStableCollateralPerShare
computed will deviate from the actual gain/loss per share during liquidation, leading to an unexpected revert during the check at Line 152 below during the liquidation process.https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/misc/InvariantChecks.sol#L118
Impact
Liquidation is the core component of the protocol and is important to the solvency of the protocol. If the liquidation does not execute as intended, such as in the scenario mentioned above where the invariant check will revert unexpectedly, underwater positions and bad debt accumulate in the protocol, threatening the solvency of the protocol.
Code Snippet
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/misc/InvariantChecks.sol#L118
Tool used
Manual Review
Recommendation
Ensure that the formula used to compute the expected
StableCollateralPerShare
during the invariant check is consistent with the formula used within the actual liquidation function.