Skip to content
Request an audit

‹ All findings

Inconsistent Use of lastCumulativeRate in depositTokens() and withdraw() Functions in Borrowings Contract

MediumAutonomint·Sherlock · Hedged stablecoin · 4th December 2024CodebaseM-33

Summary

The depositTokens() and withdraw() functions in the Borrowing contract exhibit inconsistent use of the lastCumulativeRate. This inconsistency arises because the lastCumulativeRate is used in calculations before it is updated, leading to potential inaccuracies in interest calculations among multiple transactions.

Root Cause

In both depositTokens() and withdraw() functions, lastCumulativeRate is passed to BorrowLib.deposit() and BorrowLib.withdraw() respectively, before calling calculateCumulativeRate() to update it.

solidity
        totalNormalizedAmount = BorrowLib.deposit(
            BorrowLibDeposit_Params(
                LTV,
                APR,
@>              lastCumulativeRate,
                totalNormalizedAmount,
                exchangeRate,
                ethPrice,
                lastEthprice
            ),
            depositParam,
            Interfaces(treasury, globalVariables, usda, abond, cds, options),
            assetAddress
        );

        //Call calculateCumulativeRate() to get currentCumulativeRate
@>      calculateCumulativeRate();
        lastEventTime = uint128(block.timestamp);

https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/Core_logic/borrowing.sol#L241C1-L254C11

solidity
        BorrowWithdraw_Result memory result = BorrowLib.withdraw(
            depositDetail,
            BorrowWithdraw_Params(
                toAddress,
                index,
                ethPrice,
                exchangeRate,
                withdrawTime,
                lastCumulativeRate,
                totalNormalizedAmount,
                bondRatio,
                collateralRemainingInWithdraw,
                collateralValueRemainingInWithdraw
            ),
            Interfaces(treasury, globalVariables, usda, abond, cds, options)
        );
.
.
        lastEventTime = uint128(block.timestamp);}

        // Call calculateCumulativeRate function to get the interest
@>      calculateCumulativeRate();

https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/Core_logic/borrowing.sol#L649C1-L664C11

And the lastCumulativeRate is used to calculate normalizedAmount and borrowerDebt

solidity
        // Calculate normalizedAmount
        uint256 normalizedAmount = calculateNormAmount(tokensToMint, libParams.lastCumulativeRate);

https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/lib/BorrowLib.sol#L749C1-L750C100

solidity
            // Calculate th borrower's debt
            uint256 borrowerDebt = calculateDebtAmount(depositDetail.normalizedAmount, params.lastCumulativeRate);

https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/lib/BorrowLib.sol#L824C1-L825C115

This results in using an outdated cumulative rate for the first transaction, while subsequent transactions use the updated rate, causing discrepancies.

Attack Path

  1. Allow a significant time gap since the last transaction to accumulate interest.
  2. Execute two simultaneous transactions (e.g., deposits or withdrawals).
  3. Observe that the first transaction uses an outdated lastCumulativeRate, while the second uses the updated rate.

Impact

The first transaction uses an outdated cumulative rate, while subsequent transactions use the updated cumulative rate, leading to incorrect interest calculations. This discrepancy causes inconsistencies in the normalized deposit amount and borrower debt, potentially affecting the protocol's financial accuracy .

Mitigation

Ensure that calculateCumulativeRate() is called at the beginning of both the depositTokens() and withdraw() functions to update lastCumulativeRate before it is used in any calculations. This ensures that all transactions use the most current cumulative rate.