-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ProfitManager's "creditMultiplier" calculation does not count undistributed rewards; this can cause value losses to users #292
Comments
0xSorryNotSorry marked the issue as sufficient quality report |
0xSorryNotSorry marked the issue as primary issue |
0xSorryNotSorry marked the issue as high quality report |
The issue is well demonstrated, properly formatted, contains a coded POC. |
Confirming this issue, and thanks a lot for the quality of the report! I wonder if this should be qualified as "Medium", as duplicates of this issue are qualified as Medium, and even though the protocol could end up with funds left in the PSM, all users are treated the same way, and there is always the possibility to recover the funds and organize and airdrop / multisend. |
eswak (sponsor) confirmed |
eswak marked the issue as disagree with severity |
Trumpero changed the severity to 2 (Med Risk) |
Trumpero marked the issue as satisfactory |
Trumpero marked the issue as selected for report |
Hey @Trumpero, I believe that this issue should be a high because the creditMultiplier directly influences the value of CREDIT in the system, using the incorrect method will lead to an inaccurate representation of the CREDIT value. Note that creditMultiplier can only decrease, and due to the current logical error, it's diminishing too quickly, resulting in direct losses for borrowers and holders. |
I agree with @0xbtk that this issue should be a high. |
@eswak Could you take a second look at this? Isn't the CreditToken.totalSupply() return the Total number of the tokens in existence.. If a slashing event occurs, why would the I think the value of the creditMultiplier is correctly calculated by using the amount of existing supply at the moment when the slashing event occurs. I reiterate again, why a supply that is meant to be unlocked in the future would need to be considered in the present? I just want to emphasize something, the |
I've taken a second look at the report and the problem seems to be a legit issue, if the undistributed rewards are not included as part of the existing supply at the moment of the slashing that would bring down the creditMultiplier more than what it should if all the undistributed rewards are included, this would cause that the PSM module has more PeggedTokens than what they could be claimed for using the total CreditTokens in existence. As for the severity, I think @eswak has a point in his comment (severity should be medium), all the funds that would've been left in the PSM could've been recovered and distributed to the users so they ended up equal as if the creditMultiplier would've been updated considering all the supply, I mean, the users would not lose their assets permanently, right? It would be a temporary loss while the extra funds are correctly distributed, it may take some extra work, but in the end, all users could get the exact amount of peggedTokens they could've claimed if the creditMultiplier had been updated correctly. No PeggedTokens would be lost in reality, there would only be more PeggedTokens in the PSM module than the total PeggedTokens that could be claimed for, thus, the extra tokens can be claimed by governance and distributed accordingly, making whole to all the users. Plus, all new minting and borrowing, and basically everything, from that point onwards will use the new value of the creditMultiplier, even though it was brought down more than what it should, all the accounting from that point and beyond it will use the new value of the creditMultiplier |
Hey @stalinMacias the point of the credit multiplier update, and the goal of the math behind it, is to depreciate the synthetic versus the underlying so that:
This report proves how the second point is not respected, so value can remain locked in the protocol at the user’s expense. This should be clear in the PoC but you are very right that I should have point it out in the report. @Trumpero A few wardens suggested this finding could be high and I tend to agree with that because the remediation of a governance action suggested by the sponsor may in practice not always be feasible in terms of:
|
@3docSec For the points that you've just mentioned is exactly why this fits as a medium severity. Yes, it may take some extra work to governance for preparing the distribution of the extra PeggedTokens left in the PSM module. As for the second point, how much gas does it take to make an ERC20 transfer? Include it inside a batch of transfers, and how much would it cost to make full the user? Unless the user's difference was less than 1-2 usd then it might be more expensive to credit the difference, but even though, that is doable, that's the reason why this is fine as a medium severity, for a report to be classified as a high severity, there should be a permanent loss of funds, a way that it is impossible to recover them |
Hey @stalinMacias, not all borrowers will redeem their credit in the PSM. Those holding credit during a loss will incur more losses than they should. Any thoughts on how governance can refund them? Check out #484 for more info. |
@0xbtk Those incurred losses for the holders are exactly what it should be distributed by governance. As for the question of how could governance refund them, The SimplePSM contract inherits from the CoreRef contract, the CoreRef has the emergencyAction(), governance can simply craft a calldata to transfer the extra PeggedTokens that needs to be distributed to the holders who were impacted by the creditMultiplier going down more than what it should. So, governance transfers those PeggedTokens to an account of their own, they collect the information of how many PeggedTokens need to be sent to who to cover the difference and then they do those transfers in batch. That's it, governance recovered the extra tokens and distributed them. That is because I consider this issue not to be a high severity. The tokens are not lost and they are not stuck forever in the PSM. |
I consider this issue as medium because it doesn't cause a direct loss to the protocol or users. As the sponsor stated, the protocol could end up with funds left in the PSM, but all users are treated the same way, and Governor can still recover the funds by |
Lines of code
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/governance/ProfitManager.sol#L330-L334
Vulnerability details
The function
notifyPnL
in ProfitManager is called by LendingTerms when a loan is closed to report a profit or loss.In case there is a loss, the amount in excess of the protocol's buffer is attributed to the credit token holders: this is done by slashing the
creditMultiplier
with the effect of depreciating the credit token relatively to the collateral.The math for slashing the
creditMultiplier
is the following:It is particularly interesting that
totalSupply()
is used, since in a similar high-level accounting calculation,totalBorrowedCredit()
,targetTotalSupply()
is used instead:The usage of
totalSupply()
here can be problematic when a significant portion of the supply is in undistributed rewards.In this case, the
creditMultiplier
slashing will be higher than it should becausetotalSupply()
will return a much lower value thantargetTotalSupply()
.Impact
creditMultiplier
slashing will always be higher than it should for correct accounting, penalizing credit token holders, and finally locking value in the protocol.The negative effects will be proportional to the relative supply of credit tokens in undistributed rewards versus the interpolated supply of the credit token.
Proof of Concept
The following PoC in Foundry (full setup here) shows how an overshot
creditMultiplier
slashing locks collateral value in
SimplePSM
, with a net loss for protocol users, in a real-wold scenario:Tools Used
Code review, Foundry
Recommended Mitigation Steps
Consider using
targetTotalSupply()
instead oftotalSupply()
in thecreditMultiplier
slashing calculation:Assessed type
Math
The text was updated successfully, but these errors were encountered: