Skip to content
Request an audit

‹ All findings

The user overpays the USDA amount for downside protection while withdrawing

Crit/HighAutonomint·Sherlock · Hedged stablecoin · 4th December 2024CodebaseH-32

Summary

The protocol provides >= 20% downside protection on the collateral depending on the volatility of collateral. However, users should pay USDA amount for downside protection, while withdrawing and protocol doesn't cover downside protection.

Root Cause

In the BorrowLib.sol withdraw() function, users return usda and receive collateral. Although protocol covers 20% downside protection, users should return amount of downsideProtected.

Let's see line 867 and line 878, and calculate total usda amount users should hold: burnValue + (borrowerDebt - depositDetail.borrowedAmount) + discountedCollateral = depositDetail.borrowedAmount - discountedCollateral + (borrowerDebt - depositDetail.borrowedAmount) + discountedCollateral = borrowerDebt.

As result, users should return full debt(borrowerDebt) and the protocol doesn't cover downsideProtected.

solidity
    function withdraw(
        ITreasury.DepositDetails memory depositDetail,
        IBorrowing.BorrowWithdraw_Params memory params,
        IBorrowing.Interfaces memory interfaces
    ) external returns (IBorrowing.BorrowWithdraw_Result memory) {

        ...

        // Calculate the USDa to burn
867     uint256 burnValue = depositDetail.borrowedAmount - discountedCollateral;

        // Burn the USDa from the Borrower
        bool success = interfaces.usda.burnFromUser(msg.sender, burnValue);
        if (!success) revert IBorrowing.Borrow_BurnFailed();

        ...

        //Transfer the remaining USDa to the treasury
878     bool transfer = interfaces.usda.transferFrom(
            msg.sender,
            address(interfaces.treasury),
            (borrowerDebt - depositDetail.borrowedAmount) + discountedCollateral
        );
        if (!transfer) revert IBorrowing.Borrow_USDaTransferFailed();
        ...
    }

Internal pre-conditions

External pre-conditions

Attack Path

Impact

Users should return usda amount for downside protection and the protocol doesn't cover downside protection.

Mitigation

Deduct downside protection.

diff
    function withdraw(
        ITreasury.DepositDetails memory depositDetail,
        IBorrowing.BorrowWithdraw_Params memory params,
        IBorrowing.Interfaces memory interfaces
    ) external returns (IBorrowing.BorrowWithdraw_Result memory) {

        ...

        // Calculate the USDa to burn
        uint256 burnValue = depositDetail.borrowedAmount - discountedCollateral;

        // Burn the USDa from the Borrower
        bool success = interfaces.usda.burnFromUser(msg.sender, burnValue);
        if (!success) revert IBorrowing.Borrow_BurnFailed();

        ...

        //Transfer the remaining USDa to the treasury
        bool transfer = interfaces.usda.transferFrom(
            msg.sender,
            address(interfaces.treasury),
-           (borrowerDebt - depositDetail.borrowedAmount) + discountedCollateral
+           (borrowerDebt - depositDetail.borrowedAmount - downsideProtected) + discountedCollateral
        );
        if (!transfer) revert IBorrowing.Borrow_USDaTransferFailed();
        ...
    }