Guild Holders can frontrun notifyPnL to escape losing GUILD when a loss in a lending term occurs #630
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-877
edited-by-warden
sufficient quality report
This report is of sufficient quality
unsatisfactory
does not satisfy C4 submission criteria; not eligible for awards
Lines of code
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/tokens/GuildToken.sol#L137-L140
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/tokens/GuildToken.sol#L214-L217
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/tokens/GuildToken.sol#L252-L255
Vulnerability details
Description
When a loss occurs in a lending term (loan generates bad debt), all the weight allocated to that term by Guild holders before the loss occurred must be burnt. To know if a Guild holder's weight is to be burnt, the timestamp when the loss occurs
lastGaugeLoss[gauge]
, is compared with the timestamp of the first time the holder voted for the termlastGaugeLossApplied[gauge][user]
. The check below is done whenapplyGaugeLoss
is called in GuildToken to apply the loss of a term to a Guild holder.If
_lastGaugeLossApplied < _lastGaugeLoss
it means the holder voted before the loss occurred and the weight he allocated must be burnt. A similar check is done in incrementGauge and decrementGauge to prevent the user from increasing or decreasing his voting weight and updatinglastGaugeLossApplied[gauge][user]
to escape having his weight burnt. Here's the check in_incrementGaugeWeight
and_decrmentGaugeWeight
functions which are called by theincrementGauge
anddecrementGauge
functions respectively.The two checks above protect the weight of a holder who votes for a term in the same block where a loss occurs from being burnt. This is logical since the new weight didn't support the loan the loss occurred. But this also allows weights that supported the loan from being burnt if they can update
lastGaugeLossApplied[gauge][user]
in the same block where the loss occurs. The holder can update it if he calls incrementGauge. It's updated in this if statement inincrementGauge
.The first section of the if statement in
incrementGauge
will setlastGaugeLossApplied[gauge][user]
to block.timestamp which is what he needs. But his weight will have to be empty. To do that he can calldecrementGauge
to remove his weight before callingincrementWeight
to add the weight back and resetlastGaugeLossApplied[gauge][user]
to block.timestamp. This allows him to remain in the pool and escape burning. He can do this provided the issuance doesn't become greater than the debt ceiling of the term when he decrements else thedecrementGauge
call will revert.To do this he can frontrun any transaction that calls
notifyPnL
on the term with a transaction that decrements and increments his weight on the same block before thenotifyPnL
transaction is processed.He may also decide to frontrun the call with a call to
decrementGauge
to allow him to leave the pool.Stakers in SurplusGuildMinter will also escape getting slashed if they can unstake and stake in the same block the loss occurs before the loss transaction is processed. They can also just completely unstake their position and abandon the term.
Impact
This allows a holder to escape getting his weight burnt despite supporting a loan that produces a bad debt.
Proof of Concept
A scenario this can occur is:
decrementGauge
andincrementGauge
.Here's a POC in code. The code can be run in GuildToken.t.sol.
Tools Used
Manual Analysis
Recommended Mitigation Steps
From the code,
notifyPnl
is called with debt when a loan is forgiven, and from the AuctionHouse when the total debt of a loan is not covered.Calls to
decrementGauge
can be reverted if the associated lending term currently has a loan in the auction. This prevents holders from calling it to remove all their weight when they notice a bid in the auction will produce bad debt.It's difficult to suggest a fix for forgiving a loan since it will pass through governance and holders can see that they'll be burnt even before it is done.
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: