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: 69/84
Findings: 1
Award: $12.79
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: castle_chain
Also found by: 0xAadi, 0xHelium, 0xLook, 0xblackskull, 0xfuje, 0xmystery, 0xnev, 0xpiken, 7ashraf, BARW, Bauchibred, Bughunter101, Ch_301, JP_Courses, Kaysoft, Krace, MohammedRizwan, SanketKogekar, Sathish9098, alexzoid, ast3ros, btk, catellatech, degensec, fatherOfBlocks, grearlake, imtybik, jkoppel, jolah1, klau5, lsaudit, m_Rassska, merlin, mrudenko, nobody2018, rokinot, rvierdiiev, sandy
12.7917 USDC - $12.79
InvestmentManager
If currencyAmountInPriceDecimals
* 10 ** PRICE_DECIMALS
is less than trancheTokenAmountInPriceDecimals
, then this function will return 0 as the price.
For example, currencyAmountInPriceDecimals
is 10, trancheTokenAmountInPriceDecimals
is 100e18, the result is zero.
function _calculatePrice(uint128 currencyAmount, uint128 trancheTokenAmount, address liquidityPool) public view returns (uint256 depositPrice) { (uint8 currencyDecimals, uint8 trancheTokenDecimals) = _getPoolDecimals(liquidityPool); uint256 currencyAmountInPriceDecimals = _toPriceDecimals(currencyAmount, currencyDecimals, liquidityPool); uint256 trancheTokenAmountInPriceDecimals = _toPriceDecimals(trancheTokenAmount, trancheTokenDecimals, liquidityPool); depositPrice = currencyAmountInPriceDecimals.mulDiv( 10 ** PRICE_DECIMALS, trancheTokenAmountInPriceDecimals, MathLib.Rounding.Down ); }
If assets
* 10 ** (PRICE_DECIMALS + trancheTokenDecimals - currencyDecimals) is less than latestPrice
, this function will return zero.
For example, asset
is 10, (PRICE_DECIMALS + trancheTokenDecimals - currencyDecimals)
is 18, lastestPrice
is 100e18, then the calculated shares is zero due to precision loss.
function convertToShares(uint256 _assets, address liquidityPool) public view auth returns (uint256 shares) { (uint8 currencyDecimals, uint8 trancheTokenDecimals) = _getPoolDecimals(liquidityPool); uint128 assets = _toUint128(_assets); shares = assets.mulDiv( 10 ** (PRICE_DECIMALS + trancheTokenDecimals - currencyDecimals), LiquidityPoolLike(liquidityPool).latestPrice(), MathLib.Rounding.Down ); }
This function is similar to convertToShares
.
function convertToAssets(uint256 _shares, address liquidityPool) public view auth returns (uint256 assets) { (uint8 currencyDecimals, uint8 trancheTokenDecimals) = _getPoolDecimals(liquidityPool); uint128 shares = _toUint128(_shares); assets = shares.mulDiv( LiquidityPoolLike(liquidityPool).latestPrice(), 10 ** (PRICE_DECIMALS + trancheTokenDecimals - currencyDecimals), MathLib.Rounding.Down ); }
If _toPriceDecimals(currencyAmount, currencyDecimals, liquidityPool)
* 1e18 is less than price
, it will return zero due to precision loss.
function _calculateTrancheTokenAmount(uint128 currencyAmount, address liquidityPool, uint256 price) internal view returns (uint128 trancheTokenAmount) { (uint8 currencyDecimals, uint8 trancheTokenDecimals) = _getPoolDecimals(liquidityPool); uint256 currencyAmountInPriceDecimals = _toPriceDecimals(currencyAmount, currencyDecimals, liquidityPool).mulDiv( 10 ** PRICE_DECIMALS, price, MathLib.Rounding.Down ); trancheTokenAmount = _fromPriceDecimals(currencyAmountInPriceDecimals, trancheTokenDecimals, liquidityPool); }
This is similar to _calculateTrancheTokenAmount
function _calculateCurrencyAmount(uint128 trancheTokenAmount, address liquidityPool, uint256 price) internal view returns (uint128 currencyAmount) { (uint8 currencyDecimals, uint8 trancheTokenDecimals) = _getPoolDecimals(liquidityPool); uint256 currencyAmountInPriceDecimals = _toPriceDecimals( trancheTokenAmount, trancheTokenDecimals, liquidityPool ).mulDiv(price, 10 ** PRICE_DECIMALS, MathLib.Rounding.Down); currencyAmount = _fromPriceDecimals(currencyAmountInPriceDecimals, currencyDecimals, liquidityPool); }
handleTransfer
should check the approval after transferhandleTransfer
approves this and then transfers currency
to the recipient. After transferring, it should check that the approval is zero or set it to zero.
function handleTransfer(uint128 currency, address recipient, uint128 amount) public onlyGateway { address currencyAddress = currencyIdToAddress[currency]; require(currencyAddress != address(0), "PoolManager/unknown-currency"); EscrowLike(escrow).approve(currencyAddress, address(this), amount); SafeTransferLib.safeTransferFrom(currencyAddress, address(escrow), recipient, amount); }
PoolManager
can only add pools but not removeIn PoolManager
, gateway
could add pools, tranche and currency, but it seems that there is no way to remove any one of them, this might not be convenient to manage in certain situations.
#0 - c4-pre-sort
2023-09-17T01:17:25Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-09-26T17:48:34Z
gzeon-c4 marked the issue as grade-b