Platform: Code4rena
Start Date: 08/09/2023
Pot Size: $70,000 USDC
Total HM: 8
Participants: 84
Period: 6 days
Judge: gzeon
Total Solo HM: 2
Id: 285
League: ETH
Rank: 12/84
Findings: 1
Award: $1,143.09
🌟 Selected for report: 0
🚀 Solo Findings: 0
1143.0858 USDC - $1,143.09
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L686
In _fromPriceDecimals()
function. When both _value and decimals are relatively small numbers, this function may return zero. As a result, _decreaseDepositLimits()
cannot properly update lpValues
.
The _fromPriceDecimals()
function is responsible for converting the decimal representation of a value from the price decimals back to its intended decimals. However, a specific scenario can lead to unexpected behavior.
When both _value
and the decimals
of the currency are relatively low numbers, especially when the decimals value results in a larger denominator, _fromPriceDecimals()
may return a result of 0.
Ex. _value = 10000000000 decimals = 6
function _fromPriceDecimals(uint256 _value, uint8 decimals, address liquidityPool) internal view returns (uint128 value) { if (PRICE_DECIMALS == decimals) return _toUint128(_value); value = _toUint128(_value / 10 ** (PRICE_DECIMALS - decimals)); }
Consider the following scenario:
a user initiates the mint()
function on the LiquidityPool contract with a particularly small value for shares
. This action subsequently triggers the execution of the processMint()
function within the InvestmentManager contract. During this process, the _currencyAmount
variable is calculated using the _calculateCurrencyAmount()
function.
uint128 _currencyAmount = _calculateCurrencyAmount(_trancheTokenAmount, liquidityPool, depositPrice); _deposit(_trancheTokenAmount, _currencyAmount, liquidityPool, user); currencyAmount = uint256(_currencyAmount);
_calculateCurrencyAmount()
calculates currencyAmountInPriceDecimals
, it is then used to calculated currencyAmount
in _fromPriceDecimals()
uint256 currencyAmountInPriceDecimals = _toPriceDecimals( trancheTokenAmount, trancheTokenDecimals, liquidityPool ).mulDiv(price, 10 ** PRICE_DECIMALS, MathLib.Rounding.Down); currencyAmount = _fromPriceDecimals(currencyAmountInPriceDecimals, currencyDecimals, liquidityPool);
Assume currencyAmount
= 0. _deposit()
will only decrease trancheTokenAmount
but not currencyAmount
, yet user still receives trancheTokenAmount
.
_decreaseDepositLimits(user, liquidityPool, currencyAmount, trancheTokenAmount); // decrease the possible deposit limits require(lPool.checkTransferRestriction(msg.sender, user, 0), "InvestmentManager/trancheTokens-not-a-member"); require( lPool.transferFrom(address(escrow), user, trancheTokenAmount), "InvestmentManager/trancheTokens-transfer-failed" );
function _decreaseDepositLimits(address user, address liquidityPool, uint128 _currency, uint128 trancheTokens) internal { LPValues storage lpValues = orderbook[user][liquidityPool]; if (lpValues.maxDeposit < _currency) { lpValues.maxDeposit = 0; } else { lpValues.maxDeposit = lpValues.maxDeposit - _currency; } if (lpValues.maxMint < trancheTokens) { lpValues.maxMint = 0; } else { lpValues.maxMint = lpValues.maxMint - trancheTokens; } }
Manual Review
function _fromPriceDecimals(uint256 _value, uint8 decimals, address liquidityPool) internal view returns (uint128 value) { if (PRICE_DECIMALS == decimals) return _toUint128(_value); value = _toUint128(_value / 10 ** (PRICE_DECIMALS - decimals)); + require(value != 0); }
Math
#0 - raymondfam
2023-09-15T06:38:41Z
Unlikely. _value has earlier been normalized to 1e18.
#1 - c4-pre-sort
2023-09-15T06:38:57Z
raymondfam marked the issue as low quality report
#2 - c4-pre-sort
2023-09-15T06:39:01Z
raymondfam marked the issue as primary issue
#3 - c4-judge
2023-09-25T16:48:38Z
gzeon-c4 marked the issue as duplicate of #118
#4 - c4-judge
2023-09-26T18:15:40Z
gzeon-c4 marked the issue as satisfactory