Skip to content

Latest commit

 

History

History
138 lines (93 loc) · 4.59 KB

File metadata and controls

138 lines (93 loc) · 4.59 KB

Zany Tweed Quail

Medium

"Integer Overflow in _valueOfUnderlying Function of the LenderCommitmentGroup_Smart Contract"

Summary

https://github.com/sherlock-audit/2024-11-teller-finance-update/blob/main/teller-protocol-v2-audit-2024/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol#L494

The _valueOfUnderlying function calculates the share amount to be minted to the share recipient; however, the calculations within the function are prone to overflow.

Root Cause

The issue originates in the _valueOfUnderlying function, which calculates the share amount. However, improper handling of the calculation results in an integer overflow, causing it to reach the maximum value of uint256. and it affects the addPrincipalToCommitmentGroup

`

 function _valueOfUnderlying(uint256 amount, uint256 rate)
    internal
    pure
    returns (uint256 value_)
{
    if (rate == 0) {
        return 0;
    }

    value_ = (amount * EXCHANGE_RATE_EXPANSION_FACTOR) / rate;  @audit 
}`

` function addPrincipalToCommitmentGroup(
    uint256 _amount,
    address _sharesRecipient
) external returns (uint256 sharesAmount_) {
    //transfers the primary principal token from msg.sender into this contract escrow
    
    principalToken.transferFrom(msg.sender, address(this), _amount);

    sharesAmount_ = _valueOfUnderlying(_amount, sharesExchangeRate()); @audit It Revert here 

    totalPrincipalTokensCommitted += _amount;
    //principalTokensCommittedByLender[msg.sender] += _amount;

    //mint shares equal to _amount and give them to the shares recipient !!!
    poolSharesToken.mint(_sharesRecipient, sharesAmount_);
}`
`

Impact

Integer Overflow on the _valueOfUnderlying function which leads to overflow on the calculation of the share amount and it affects the addPrincipalToCommitmentGroup function

PoC

// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13;

contract Overflow { uint256 public immutable EXCHANGE_RATE_EXPANSION_FACTOR = 1e36; uint256 public totalSupply = 1e18; uint256 public totalPrincipalTokensCommitted = 100e36; uint256 public totalPrincipalTokensWithdrawn = 10e36;

uint256 public totalInterestCollected = 50e36;
int256 public tokenDifferenceFromLiquidations = 20e36;

function sharesExchangeRate() public view virtual returns (uint256 rate_) {
    uint256 poolTotalEstimatedValue = getPoolTotalEstimatedValue();

    if (totalSupply == 0) {
        return EXCHANGE_RATE_EXPANSION_FACTOR; // 1 to 1 for first swap
    }

    rate_ = (poolTotalEstimatedValue * EXCHANGE_RATE_EXPANSION_FACTOR) / totalSupply;
}

function sharesExchangeRateInverse() public view virtual returns (uint256 rate_) {
    return (EXCHANGE_RATE_EXPANSION_FACTOR * EXCHANGE_RATE_EXPANSION_FACTOR) / sharesExchangeRate();
}

function getPoolTotalEstimatedValue() public view returns (uint256 poolTotalEstimatedValue_) {
    int256 poolTotalEstimatedValueSigned = int256(totalPrincipalTokensCommitted) + int256(totalInterestCollected)
        + int256(tokenDifferenceFromLiquidations) - int256(totalPrincipalTokensWithdrawn);

    //if the poolTotalEstimatedValue_ is less than 0, we treat it as 0.
    poolTotalEstimatedValue_ =
        poolTotalEstimatedValueSigned > int256(0) ? uint256(poolTotalEstimatedValueSigned) : 0;
}


// Change  the visibility to public for testing purpose 
function _valueOfUnderlying(uint256 amount, uint256 rate) public pure returns (uint256 value_) {
    if (rate == 0) {
        return 0;
    }

    value_ = (amount * EXCHANGE_RATE_EXPANSION_FACTOR) / rate;
}

} `

// The contract

` // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13;

import {Test, console} from "forge-std/Test.sol"; import {Counter} from "../src/Counter.sol";

contract OverFlowTest is Test { Overflow public overflow;

function setUp() public {
    overflow = new Overflow();
    }

  function testFuzz_valueofUnderlying(uint256 amount) public {
    uint256 poolTotalEstimatedValue = overflow.getPoolTotalEstimatedValue();
    console.log(poolTotalEstimatedValue);
    uint256 rate = counter.sharesExchangeRate();
    // console.log(rate);
    uint256 value = counter._valueOfUnderlying(amount, rate);

    console.log(value);
}


}
  `    `

Mitigation

Recheck the _valueOfUnderlying` function calculation to handle the shares amount calculation properly