-
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
The creation of bad debt (mark-down
of Credit) can force other loans in auction to also create bad debt
#476
Comments
0xSorryNotSorry marked the issue as high quality report |
The issue is well demonstrated, properly formatted, contains a coded POC. |
0xSorryNotSorry marked the issue as duplicate of #1069 |
Trumpero marked the issue as satisfactory |
Trumpero changed the severity to 3 (High Risk) |
Hi @Trumpero, I understand that labeling a report as Thank you for taking the time to read my comment. |
Trumpero marked the issue as selected for report |
Lines of code
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/LendingTerm.sol#L751-L768
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/LendingTerm.sol#L664-L668
Vulnerability details
Bug Description
The creation of bad debt results in the
mark down
ofCredit
, i.e.Credit
experiences inflation. This is done so that the protocol can adjust to the bad debt that was produced. It follows that whenCredit
is marked down all active loans can be consideredmarked up
, meaning that the borrowers will be expected to repay with moreCredit
, sinceCredit
is now worth less. We can observe how this is done by examining theLendingTerm::getLoanDebt
function:LendingTerm::getLoanDebt#L216-L230
As we can see above, the debt of a borrower (principle + interests) is adjusted by the
creditMultiplier
. ThiscreditMultiplier
starts at1e18
and getsmarked down
when bad debt is produced in the system. Theloan.borrowCreditMultiplier
is thecreditMultiplier
value at the time that the user took out the loan. Therefore, this function calculates the adjusted debt of a borrower with respect to the amount of bad debt that was produced (inflation ofCredit
) since the borrower took out the loan. This function is called every time a borrower makes a payment for their loan, ensuring that the appropriate debt is always considered. However, this function is only called once during the entire auction process:LendingTerm::_call#L664-L668
The above code is taken from the
_call
function, which is the starting point for an auction. When a loan misses a requiredpartialPayment
or the term is offboarded, this function can be permissionlessly called. As we can see, the debt of the loan is read from thegetLoanDebt
function and then stored in theloan
struct in thecallDebt
field. This means that thecallDebt
represents a snapshot of the debt atblock.timestamp
. Therefore, thecallDebt
is the loan debt with respect to thecreditMultiplier
valued at the time that the loan was called. What if thecreditMultiplier
gets updated after the auction process begins? This would result in thecallDebt
of the loan being less than what the actual debt of the loan should be (Credit
is worth less, but the collateral is worth the same). We can understand the true magnitude of this discrepancy by observing theLendingTerm::onBid
function:LendingTerm::onBid#L750-L768
As we can see above, the
principle
of the loan is calcualted with respect to the currentcreditMultiplier
. ThecreditFromBidder
is thecallDebt
when the auction is in its first phase:AuctionHouse::getBidDetail#L133-L136
This is where the issue lies. Remember, the
callDebt
represents a snapshot of the loan debt at the time which the loan was called. ThecallDebt
does not consider a potential updatedcreditMultiplier
. Therefore, if amark down
is generated that results inprinciple > creditFromBidder
, then execution of theonBid
function would continue on line 762. This will result in a negativepnl
being calculated, which ultimately means that this gauge will experience a loss. However, if thecollateralToBorrower
is not 0, the function will revert. Therefore, when theprinciple
is greater than thecallDebt
, due to themark down
ofCredit
, the auction can only receive a bid if thecollateralToBorrower
is 0. Let us observe theAuctionHouse::bid
andAuctionHouse::getBidDetail
functions in order to understand what scenario would result incollateralToBorrower == 0
:AuctionHouse::bid#L169-L186
As seen above, the
onBidDetail
function is invoked to retrieve the necessarycollateralReceived
andcreditAsked
values. TheonBid
function is then invoked and thecollateralToBorrower
is equal to thecollateralAmount - collateralReceived
. ThecollateralAmount
is the full collateral of the loan. Therefore, if thecollateralReceived == collateralAmount
, we will have satisfied the following condition:collateralToBorrower == 0
. This is exactly what occurs during the second phase of an auction:AuctionHouse::getBidDetail#L143-L146
Therefore, given the situation where a loan is placed in auction and then a large enough
mark down
ofCredit
occurs, such thatprinciple > creditFromBidder
, only bids occuring during the second phase of the auction will be allowed. In addition, given thatprinciple > creditFromBidder
, bad debt will also be produced in this auction.Lets briefly discuss what scenarios would result in
principle > callDebt
. Reminder: ThecallDebt
represents the maximum value thatcreditFromBidder
can be. ThecallDebt
is a snapshot of the full debt of a borrower (principle + interests). Therefore, if themark down
results in a percent decrease ofCredit
greater than the interest of the borrower's loan, then the adjustedprinciple
will be greater than thecallDebt
. Consider the following situation:A term has an interest rate of 4%. The term has multiple loans opened and the term is being off-boarded after half a year. Lets assume no loans have been paid off during this time. Therefore, the interest for all loans is ~2%. Suppose a loan undergoes auction before other loans are called and this loan results in the creation of bad debt (worse case scenario), which results in a
mark down
> 2%. All other loans that are in auction during thismark down
will be forced to create bad debt since the adjustedprinciple
for all loans in auction will be greater than the loans'callDebt
.Impact
The creation of bad debt has the potential to force other loans to create additional bad debt if the following conditions are met:
mark down
mark down
is greater than the interest owed for the loansThis can greatly impact the health of the protocol as the
Credit
token is used for all core functionalities. Amark down
is a mechanism to allow the system to properly adjust to the creation of bad debt, however I would argue that the creation of bad debt should not result in other loans being forced to produce losses which can ultimately produce more bad debt.This has the ability to affect loans in other terms as well. All loans in auction during the
mark down
, originating from any term in the market, can potentially be forced to produce a loss/bad debt. The magnitude of this additionalmark down
ofCredit
will be greater if the affected loans have relatively low interest accrued and a large borrow amount.Secondary effects are that no user's will be able to bid during the first phase of the auction. This first phase is meant to be an opportunity for the borrower to properly repay their full debt before the second phase begins, where the borrower can potentially be out-bid by another liquidator and lose the opportunity to receive their collateral.
Proof of Concept
The following test demonstrates the scenario described above in which a
mark down
ofCredit
results in other loans in auction being forced to create additional bad debt.Place the test inside of the
test/unit/loan/
directory:Tools Used
manual
Recommended Mitigation Steps
Credit
debt is calculated in most areas of the system with respect to the current multiplier, except for during the auction process. I would suggest calculating thecallDebt
dynamically with respect to the currentcreditMultiplier
during the auction process instead of having it represent a 'snapshot' of the borrower's debt.Assessed type
Other
The text was updated successfully, but these errors were encountered: