Revert Lend - DanielArmstrong's results

A lending protocol specifically designed for liquidity providers on Uniswap v3.

General Information

Platform: Code4rena

Start Date: 04/03/2024

Pot Size: $88,500 USDC

Total HM: 31

Participants: 105

Period: 11 days

Judge: ronnyx2017

Total Solo HM: 7

Id: 342

League: ETH

Revert

Findings Distribution

Researcher Performance

Rank: 24/105

Findings: 3

Award: $594.73

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
sufficient quality report
:robot:_78_group
duplicate-415

Awards

38.4591 USDC - $38.46

External Links

Lines of code

https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L1251 https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L1263

Vulnerability details

Impact

Since daily increase limit is set much larger than the intention, it is possible to cause a catastrophic exploit to the protocol.

Proof of Concept

V3Vault.sol#_resetDailyLendIncreaseLimit function is the following.

    function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal {
        // daily lend limit reset handling
        uint256 time = block.timestamp / 1 days;
        if (force || time > dailyLendIncreaseLimitLastReset) {
1250:       uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up)
                * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32;
            dailyLendIncreaseLimitLeft =
                dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit;
            dailyLendIncreaseLimitLastReset = time;
        }
    }

L1250 calculates the maximum increase of lending amount during a day to 110% of the present total shares. This is 11 times greater than the intended maximum increase of 10%.

Thus, there is a possibility of causing a catastrophic exploit to the protocol by malicious attacker's attacks.

V3Vault.sol#_resetDailyDebtIncreaseLimit function also has the same issue.

Tools Used

Manual Review

Modify V3Vault.sol#_resetDailyLendIncreaseLimit function as follows.

    function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal {
        // daily lend limit reset handling
        uint256 time = block.timestamp / 1 days;
        if (force || time > dailyLendIncreaseLimitLastReset) {
            uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up)
--              * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32;
++              * MAX_DAILY_LEND_INCREASE_X32 / Q32;
            dailyLendIncreaseLimitLeft =
                dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit;
            dailyLendIncreaseLimitLastReset = time;
        }
    }

In the same way, modify V3Vault.sol#_resetDailyDebtIncreaseLimit function as follows.

    function _resetDailyDebtIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal {
        // daily debt limit reset handling
        uint256 time = block.timestamp / 1 days;
        if (force || time > dailyDebtIncreaseLimitLastReset) {
            uint256 debtIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up)
--              * (Q32 + MAX_DAILY_DEBT_INCREASE_X32) / Q32;
++              * MAX_DAILY_DEBT_INCREASE_X32 / Q32;
            dailyDebtIncreaseLimitLeft =
                dailyDebtIncreaseLimitMin > debtIncreaseLimit ? dailyDebtIncreaseLimitMin : debtIncreaseLimit;
            dailyDebtIncreaseLimitLastReset = time;
        }
    }

Assessed type

Math

#0 - c4-pre-sort

2024-03-21T14:22:27Z

0xEVom marked the issue as duplicate of #415

#1 - c4-pre-sort

2024-03-21T14:22:33Z

0xEVom marked the issue as sufficient quality report

#2 - c4-judge

2024-04-01T06:46:19Z

jhsagd76 marked the issue as satisfactory

#3 - c4-judge

2024-04-01T15:43:13Z

jhsagd76 changed the severity to 2 (Med Risk)

Findings Information

🌟 Selected for report: FastChecker

Also found by: DanielArmstrong

Labels

bug
2 (Med Risk)
satisfactory
sponsor confirmed
sufficient quality report
:robot:_78_group
duplicate-400

Awards

545.9832 USDC - $545.98

External Links

Lines of code

https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L949

Vulnerability details

Impact

First withdraw or repay cannot increase daily available deposit or borrow amount. This results in decreasing the system's incentives. When a user withdraw or repay funds just after new date started, it increases dailyLendIncreaseLimitLeft or dailyDebtIncreaseLimitLeft but it has no effect. That's why it resets them when deposit or borrow. So daily available deposit or borrow amount cannot be increased.

Proof of Concept

V3Vault.sol#_withdraw function is as follows.

    function _withdraw(address receiver, address owner, uint256 amount, bool isShare)
        internal
        returns (uint256 assets, uint256 shares)
    {
        (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96) = _updateGlobalInterest();

        ...

        // when amounts are withdrawn - they may be deposited again
949     dailyLendIncreaseLimitLeft += assets;

        emit Withdraw(msg.sender, receiver, owner, assets, shares);
    }

As you can see above, on L949 it increases dailyLendIncreaseLimitLeft without considering current date.
And V3Vault.sol#_deposit function is as follows.

    function _deposit(address receiver, uint256 amount, bool isShare, bytes memory permitData)
        internal
        returns (uint256 assets, uint256 shares)
    {
        (, uint256 newLendExchangeRateX96) = _updateGlobalInterest();

883     _resetDailyLendIncreaseLimit(newLendExchangeRateX96, false);

        ...

        if (assets > dailyLendIncreaseLimitLeft) {
            revert DailyLendIncreaseLimit();
        } else {
            dailyLendIncreaseLimitLeft -= assets;
        }

        emit Deposit(msg.sender, receiver, assets, shares);
    }

On L883, it resets dailyLendIncreaseLimitLeft if available through _resetDailyLendIncreaseLimit function.

    function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal {
        // daily lend limit reset handling
        uint256 time = block.timestamp / 1 days;
        if (force || time > dailyLendIncreaseLimitLastReset) {
            uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up)
                * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32;
            dailyLendIncreaseLimitLeft =
                dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit;
            dailyLendIncreaseLimitLastReset = time;
        }
    }

As we can see, if new date starts, it resets dailyLendIncreaseLimitLeft.

So first withdraw cannot increase daily available deposit amount.

This problem occurs in repay and borrow as same way.

Tools Used

Manual Review

We have to modify V3Vault.sol#_withdraw, _repay functions as follows.

    function _withdraw(address receiver, address owner, uint256 amount, bool isShare)
        internal
        returns (uint256 assets, uint256 shares)
    {
        (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96) = _updateGlobalInterest();
        
+       _resetDailyLendIncreaseLimit(newLendExchangeRateX96, false);

        ...

        // when amounts are withdrawn - they may be deposited again
        dailyLendIncreaseLimitLeft += assets;

        emit Withdraw(msg.sender, receiver, owner, assets, shares);
    }
    ...
    function _repay(uint256 tokenId, uint256 amount, bool isShare, bytes memory permitData) internal {
        (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96) = _updateGlobalInterest();

+       _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, false);

        ...

        // when amounts are repayed - they maybe borrowed again
        dailyDebtIncreaseLimitLeft += assets;

        ...

        emit Repay(tokenId, msg.sender, owner, assets, shares);
    }

Assessed type

Error

#0 - c4-pre-sort

2024-03-21T14:59:34Z

0xEVom marked the issue as duplicate of #400

#1 - c4-pre-sort

2024-03-21T14:59:42Z

0xEVom marked the issue as sufficient quality report

#2 - c4-sponsor

2024-03-26T17:28:51Z

kalinbas (sponsor) confirmed

#3 - c4-judge

2024-04-01T10:43:03Z

jhsagd76 marked the issue as satisfactory

Awards

10.2896 USDC - $10.29

Labels

bug
downgraded by judge
grade-b
insufficient quality report
QA (Quality Assurance)
:robot:_78_group
duplicate-367
Q-41

External Links

Lines of code

https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L827 https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L828

Vulnerability details

Impact

When resetting limit values, it resets dailyLendIncreaseLimit and dailyDebyIncreaseLimit forcefully. So daily amounts of lend and debt can exceed limits at that day.

Proof of Concept

V3Vault.sol#setLimits function which resets limits is as follows.

    function setLimits(
        uint256 _minLoanSize,
        uint256 _globalLendLimit,
        uint256 _globalDebtLimit,
        uint256 _dailyLendIncreaseLimitMin,
        uint256 _dailyDebtIncreaseLimitMin
    ) external {
        if (msg.sender != emergencyAdmin && msg.sender != owner()) {
            revert Unauthorized();
        }

        minLoanSize = _minLoanSize;
        globalLendLimit = _globalLendLimit;
        globalDebtLimit = _globalDebtLimit;
        dailyLendIncreaseLimitMin = _dailyLendIncreaseLimitMin;
        dailyDebtIncreaseLimitMin = _dailyDebtIncreaseLimitMin;

        (, uint256 newLendExchangeRateX96) = _updateGlobalInterest();

        // force reset daily limits with new values
827     _resetDailyLendIncreaseLimit(newLendExchangeRateX96, true);
828     _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, true);

        emit SetLimits(
            _minLoanSize, _globalLendLimit, _globalDebtLimit, _dailyLendIncreaseLimitMin, _dailyDebtIncreaseLimitMin
        );
    }

As we can see, on L827, 828 it resets dailyLendIncreaseLimit and dailyDebtIncreaseLimit forcefully.

Tools Used

Manual Review

We have modify V3Vault.sol#setLimits as follows.

    function setLimits(
        uint256 _minLoanSize,
        uint256 _globalLendLimit,
        uint256 _globalDebtLimit,
        uint256 _dailyLendIncreaseLimitMin,
        uint256 _dailyDebtIncreaseLimitMin
    ) external {
        ...

        (, uint256 newLendExchangeRateX96) = _updateGlobalInterest();

-       // force reset daily limits with new values
-       _resetDailyLendIncreaseLimit(newLendExchangeRateX96, true);
-       _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, true);

        emit SetLimits(
            _minLoanSize, _globalLendLimit, _globalDebtLimit, _dailyLendIncreaseLimitMin, _dailyDebtIncreaseLimitMin
        );
    }

Assessed type

Error

#0 - c4-pre-sort

2024-03-21T14:26:06Z

0xEVom marked the issue as duplicate of #367

#1 - c4-pre-sort

2024-03-21T14:26:10Z

0xEVom marked the issue as sufficient quality report

#2 - c4-pre-sort

2024-03-23T20:02:45Z

0xEVom marked the issue as insufficient quality report

#3 - c4-judge

2024-03-31T09:02:11Z

jhsagd76 changed the severity to QA (Quality Assurance)

#4 - c4-judge

2024-04-01T06:45:10Z

jhsagd76 marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter