Platform: Code4rena
Start Date: 21/08/2023
Pot Size: $125,000 USDC
Total HM: 26
Participants: 189
Period: 16 days
Judge: GalloDaSballo
Total Solo HM: 3
Id: 278
League: ETH
Rank: 76/189
Findings: 2
Award: $115.50
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: LokiThe5th
Also found by: 0xPsuedoPandit, 0xTiwa, 0xnev, 0xvj, Evo, Jiamin, Juntao, QiuhaoLi, T1MOH, Udsen, circlelooper, crunch, eeshenggoh, gjaldon, hals, josephdara, kutugu, minhtrng, niki, umarkhatab_465
96.3292 USDC - $96.33
In the PerpetualAtlanticVaultLP contract, the convertToShares function was to return a given amount of shares received for a given amount of assets but the amounts of shares received has to be converted from a 1e18 precision to a 1e8 precision but instead a 1e8 precision was used directly.
function convertToShares( uint256 assets ) public view returns (uint256 shares) { uint256 supply = totalSupply; uint256 rdpxPriceInAlphaToken = perpetualAtlanticVault.getUnderlyingPrice(); uint256 totalVaultCollateral = totalCollateral() + ((_rdpxCollateral * rdpxPriceInAlphaToken) / 1e8); return supply == 0 ? assets : assets.mulDivDown(supply, totalVaultCollateral); }
As seen above, the price is gotten from the perpetualAtlanticVault.getUnderlyingPrice()
function getUnderlyingPrice() public view returns (uint256) { return IRdpxEthOracle(addresses.assetPriceOracle).getRdpxPriceInEth(); }
which in turn returns the rdpxEthOracle.getRdpxPriceInEth function, which returns the price of rdpx in eth in 1e18 decimals not 1e8, therefore there is a surplus of 1e10 decimals after each conversion.
Manual review
The amount of assets converted to shares should be converted in the 1e18 precision not 1e8 precision to avoid surplus 1e10 decimals.
uint256 totalVaultCollateral = totalCollateral() + ((_rdpxCollateral * rdpxPriceInAlphaToken) / 1e18);
Decimal
#0 - c4-pre-sort
2023-09-12T09:00:58Z
bytes032 marked the issue as duplicate of #397
#1 - c4-pre-sort
2023-09-12T09:01:06Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-15T18:39:58Z
GalloDaSballo marked the issue as duplicate of #549
#3 - c4-judge
2023-10-20T18:28:00Z
GalloDaSballo marked the issue as satisfactory
#4 - c4-judge
2023-10-20T18:28:12Z
GalloDaSballo changed the severity to 2 (Med Risk)
#5 - c4-judge
2023-10-20T18:28:21Z
GalloDaSballo changed the severity to 3 (High Risk)
🌟 Selected for report: juancito
Also found by: 0xDING99YA, 0xTiwa, 0xkazim, 0xnev, ABA, ArmedGoose, Aymen0909, Bauchibred, Evo, IceBear, KrisApostolov, MohammedRizwan, Nikki, QiuhaoLi, T1MOH, Toshii, WoolCentaur, Yanchuan, __141345__, asui, bart1e, carrotsmuggler, catellatech, chaduke, codegpt, deadrxsezzz, degensec, dethera, dirk_y, erebus, ether_sky, gjaldon, glcanvas, jasonxiale, josephdara, klau5, kodyvim, ladboy233, lsaudit, minhquanym, parsely, peakbolt, pep7siup, rvierdiiev, said, savi0ur, sces60107, tapir, ubermensch, volodya, zzebra83
19.1724 USDC - $19.17
The removeAssetFromtokenReserves() is used to remove assets from the reserve tokens and also the reserve assets. It removes the assets details from the reserve assets array and pops the last element of the reserve assets array after overwriting the removed asset but it does not remove the symbol from the reserve token array instead it removes the last symbol without overwriting the removed symbol.
function removeAssetFromtokenReserves( string memory _assetSymbol ) external onlyRole(DEFAULT_ADMIN_ROLE) { uint256 index = reservesIndex[_assetSymbol]; _validate(index != 0, 18); // remove the asset from the mapping reservesIndex[_assetSymbol] = 0; // add new index for the last element reservesIndex[reserveTokens[reserveTokens.length - 1]] = index; // update the index of reserveAsset with the last element reserveAsset[index] = reserveAsset[reserveAsset.length - 1]; // remove the last element reserveAsset.pop(); reserveTokens.pop(); emit LogAssetRemovedFromtokenReserves(_assetSymbol, index); }
Manual review.
Update the removeAssetFromtokenReserves() to be able to pop the right symbol.
function removeAssetFromtokenReserves( string memory _assetSymbol ) external onlyRole(DEFAULT_ADMIN_ROLE) { uint256 index = reservesIndex[_assetSymbol]; _validate(index != 0, 18); // remove the asset from the mapping reservesIndex[_assetSymbol] = 0; // add new index for the last element reservesIndex[reserveTokens[reserveTokens.length - 1]] = index; // update the index of reserveAsset with the last element reserveAsset[index] = reserveAsset[reserveAsset.length - 1]; reserveTokens[index] = reserveTokens[reserveTokens.length - 1]; // remove the last element reserveAsset.pop(); reserveTokens.pop(); emit LogAssetRemovedFromtokenReserves(_assetSymbol, index); }
Other
#0 - c4-pre-sort
2023-09-07T09:49:13Z
bytes032 marked the issue as duplicate of #33
#1 - c4-pre-sort
2023-09-11T15:04:44Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-15T09:06:46Z
GalloDaSballo changed the severity to 2 (Med Risk)
#3 - c4-judge
2023-10-15T13:11:25Z
GalloDaSballo changed the severity to QA (Quality Assurance)
#4 - c4-judge
2023-10-20T18:18:07Z
GalloDaSballo marked the issue as grade-b