Skip to content
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

Incorrect assumption of loss in liquidatePositionBadDebt(), leads to undue burning of Treasury shares #434

Closed
howlbot-integration bot opened this issue Aug 20, 2024 · 4 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-190 🤖_86_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards sufficient quality report This report is of sufficient quality

Comments

@howlbot-integration
Copy link

Lines of code

https://github.com/code-423n4/2024-07-loopfi/blob/57871f64bdea450c1f04c9a53dc1a78223719164/src/CDPVault.sol#L607

Vulnerability details

Impact

Undue burning of Treasury shares in PoolV3 leading to loss of profit to stakers, protocol and dLp lockers.

Proof of Concept

  1. First thing to note is that, CDPVault records profit for every interest paid. see proofs;
    In liquidatePosition()
if (deltaDebt == maxRepayment) { 
            newDebt = 0;
            newCumulativeIndex = debtData.cumulativeIndexNow;
            profit = debtData.accruedInterest; // during full liquidation
            position.cumulativeQuotaInterest = 0; 

during full repayment

 } else if (deltaDebt < 0) {
            uint256 maxRepayment = calcTotalDebt(debtData);
            uint256 amount = abs(deltaDebt);
            if (amount >= maxRepayment) {
                amount = maxRepayment; // U:[CM-11]
                deltaDebt = -toInt256(maxRepayment);
            }

            poolUnderlying.safeTransferFrom(creditor, address(pool), amount);

            uint128 newCumulativeQuotaInterest;
            if (amount == maxRepayment) {
                newDebt = 0;
                newCumulativeIndex = debtData.cumulativeIndexNow;
                profit = debtData.accruedInterest;
                newCumulativeQuotaInterest = 0;

It can also be observed in calDecrease() that when cumulativeQuotaInterest or accumulatedInterest is repaid, profit is recorded. here

  1. Now that it is proven that, interest is being recorded as profit and shares are minted in repayCreditAccount() to treasury, let us examine what was done wrong in liquidatePositionBadDebt()
  2. The liquidatePositionBadDebt() incorrectly assumes that, once the repayAmount is less than totalDebt, a loss occurs, this is not correct in all cases.

Instance

accrued Interest    =========== cumulativeQuotaInterest + accruedInterest = 200
total debt value    =========== 1,200(debt + accruedInterest)
collateral value    =========== 1,166 (debt > collater)
repayAmount         =========== 1,050
discountPrice       =========== 0.9
takeCollateral.     =========== 1,166

From the snippet above, it shows that, debt is 1,000 and liquidator repaid 1,050, which leaves 50 as part of the interest payment and shares should be minted to the treasury for that. But the current implementation of liquidatePositionBadDebt() does other wise, by burning treasury shares worth 1,200 - 1,050 = 150. In the real sense, 150 was not lost here, 50 was gained as part interest payment!

@>>     uint256 loss = calcTotalDebt(debtData) - repayAmount;

        // transfer the repay amount from the liquidator to the vault
        poolUnderlying.safeTransferFrom(msg.sender, address(pool), repayAmount);

        position.cumulativeQuotaInterest = 0;
        position.cumulativeQuotaIndexLU = debtData.cumulativeQuotaIndexNow;
        // update liquidated position
        position = _modifyPosition(
            owner,
            position,
            0,
            debtData.cumulativeIndexNow,
            -toInt256(takeCollateral),
            totalDebt
        );

 @>>       pool.repayCreditAccount(debtData.debt, 0, loss); // U:[CM-11]

Tools Used

Manual review

Recommended Mitigation Steps

check if the repaid amount is greater or less than the actual debt, if it is greater, the difference should be minted as profit to the treasury, if lower, difference should be burnt from treasury.

Assessed type

Math

@howlbot-integration howlbot-integration bot added 3 (High Risk) Assets can be stolen/lost/compromised directly 🤖_86_group AI based duplicate group recommendation bug Something isn't working duplicate-96 sufficient quality report This report is of sufficient quality labels Aug 20, 2024
howlbot-integration bot added a commit that referenced this issue Aug 20, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 2, 2024

koolexcrypto marked the issue as satisfactory

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Oct 2, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 2, 2024

koolexcrypto marked the issue as not a duplicate

@c4-judge c4-judge reopened this Oct 2, 2024
@c4-judge c4-judge closed this as completed Oct 2, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 2, 2024

koolexcrypto marked the issue as duplicate of #190

@c4-judge
Copy link
Contributor

c4-judge commented Oct 2, 2024

koolexcrypto changed the severity to 2 (Med Risk)

@c4-judge c4-judge added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value downgraded by judge Judge downgraded the risk level of this issue and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Oct 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-190 🤖_86_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

1 participant