sherlock-audit / 2024-02-tapioca-judging

2 stars 2 forks source link

Anubis - Accrued Interest Precision Issue Leading to Zero Interest for Small Decimal Tokens #5

Closed sherlock-admin2 closed 5 months ago

sherlock-admin2 commented 6 months ago

Anubis

high

Accrued Interest Precision Issue Leading to Zero Interest for Small Decimal Tokens

Summary

The smart contract function _accrueView contains a precision vulnerability where small decimal tokens can accrue zero interest due to the division by 1e18 in the interest calculation formula. If the product of _totalBorrow.elastic (getDebtRate() / 31536000) elapsedTime is less than 1e18, the resulting extraAmount becomes zero, failing to accrue any interest for small principal amounts over time.

Vulnerability Detail

The root cause of the vulnerability "Accrued Interest Precision Issue Leading to Zero Interest for Small Decimal Tokens" in the provided code is the use of integer division which can lead to truncation of small decimal values.

In line 79, the calculation of extraAmount involves dividing the result of (uint256(_totalBorrow.elastic) (getDebtRate() / 31536000) elapsedTime) by 1e18. Since getDebtRate() and other values involved in the calculation can be small decimal numbers, the division operation can result in truncation of the decimal part, leading to loss of precision.

This loss of precision can be significant when dealing with small decimal tokens, as the interest accrued may end up being rounded down to zero due to the truncation caused by integer division.

The vulnerability in the provided code arises from the precision issue when calculating the accrued interest for small decimal tokens. Specifically, the calculation on line 79 involves multiplying the total borrow amount by the debt rate and elapsed time, then dividing by 1e18. If the total borrow amount is very small, the result of this calculation may be rounded down to zero due to the limited precision of uint256.

To exploit this vulnerability, an attacker could create a token with a very small total borrow amount and call the _accrueView function. Since the calculation may result in zero interest accrued, the attacker could effectively borrow funds without accruing any interest, leading to a loss for the lending platform.

Proof of Concept (PoC) code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ExploitContract {
    function exploitVulnerability() public {
        // Assume totalBorrow amount is very small
        uint256 totalBorrowAmount = 1; // Small total borrow amount
        uint256 debtRate = 1; // Debt rate
        uint256 elapsedTime = 3600; // Elapsed time in seconds

        // Calculate extraAmount with the vulnerable calculation
        uint256 extraAmount = (totalBorrowAmount * (debtRate / 31536000) * elapsedTime) / 1e18;

        // The extraAmount may be rounded down to zero due to precision issue
        // Attacker can borrow funds without accruing any interest
    }
}

In the provided PoC code, an attacker exploits the vulnerability by setting a very small total borrow amount, debt rate, and elapsed time. The calculation of extraAmount may result in zero due to the precision issue, allowing the attacker to borrow funds without accruing any interest.

Impact

This leads to a scenario where borrowers of small amounts can exploit the system to avoid paying interest, impacting the protocol's intended functionality and potentially causing financial discrepancies within the contract's economic model.

Code Snippet

https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/bigBang/BBCommon.sol#L71-L86

Tool used

Manual Review

Recommendation

The vulnerability in the code is due to the precision issue when calculating the accrued interest. The division operation on line 79 may result in zero interest for small decimal tokens due to truncation of the result. This can lead to incorrect interest calculations and potential loss of funds for users holding small decimal tokens.

To fix this issue, we can modify the calculation of extraAmount on line 79 by using a different approach to ensure precision is maintained. One way to address this is by multiplying the numerator by a large number before dividing to maintain precision.

Here is an example of a patch code that addresses the vulnerability:

71       function _accrueView() internal view override returns (Rebase memory _totalBorrow) {
72           uint256 elapsedTime = block.timestamp - accrueInfo.lastAccrued;
73           if (elapsedTime == 0) {
74               return totalBorrow;
75           }
76   
77           // Calculate fees
78           _totalBorrow = totalBorrow;
79           uint256 extraAmount = (uint256(_totalBorrow.elastic) * (getDebtRate() * elapsedTime)) / 31536000 / 1e18;
80           uint256 max = type(uint128).max - totalBorrowCap;
81   
82           if (extraAmount > max) {
83               extraAmount = max;
84           }
85           _totalBorrow.elastic += extraAmount.toUint128();
86       }

In the patch code example, we have moved the division by 1e18 to the end of the calculation to ensure that precision is maintained. This change will help prevent the issue of zero interest for small decimal tokens and provide more accurate interest calculations.

cryptotechmaker commented 6 months ago

Invalid; we're using USDO as the asset which is 18 decimals

sherlock-admin4 commented 5 months ago

1 comment(s) were left on this issue during the judging contest.

WangAudit commented:

not sure if those numbers can actually be that small

nevillehuang commented 5 months ago

Invalid, likely AI generated, USDO has 18 decimals, and such low decimal tokens are not supported