<!-- canonical: https://0xsimao.com/findings/autonomint-cumulative-deposit-withdraw-borrowings -->

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

Medium · Sherlock · Hedged stablecoin · 4th December 2024

Finding M-33 of the Autonomint competition.

- Protocol: https://audits.sherlock.xyz/contests/569
- Report: /reports/autonomint
- Codebase: https://github.com/0xsimao/2024-11-autonomint/tree/0d324e04d4c0ca306e1ae4d4c65f0cb9d681751b
- Source: https://github.com/sherlock-audit/2024-11-autonomint-judging/issues/961

---

### 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.



### Internal pre-conditions

_No response_

### External pre-conditions

_No response_

### 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 .



### PoC

_No response_

### 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.

---

Related findings:

- [`rewardData.releaseRate` is incorrectly calculated on `RewardsController::config()` when `block.timestamp > start` and `rewardData.lastConfig != rewardData.start`](https://0xsimao.com/findings/exactly-protocol-update-staking-contract-reward-release-rewards-timestamp): Exactly Protocol Update - Staking Contract
- [Setting maxFundingFeePerBlock to a lower value than abs(lastFundingRate) will brick getPendingAccFundingFees()](https://0xsimao.com/findings/ostium-fee-abs-brick-fees): Ostium
- [BasicVault::manualRedeem() and BasicVault::manualDeposit() are inconsistent](https://0xsimao.com/findings/mitosis-manual-redeem-deposit-inconsistent): Mitosis
- [`LenderCommitmentGroup` pools will have incorrect exchange rate when fee-on-transfer tokens are used](https://0xsimao.com/findings/teller-finance-pools-exchange-fee-transfer): Teller Finance
