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: 48/189
Findings: 4
Award: $301.20
π Selected for report: 0
π Solo Findings: 0
π Selected for report: bart1e
Also found by: 0x3b, 0xCiphky, Aymen0909, HHK, Inspex, bin2chen, chaduke, gkrastenov, jasonxiale, josephdara, kodyvim, peakbolt, pep7siup, rokinot, rvierdiiev, tapir
181.367 USDC - $181.37
The recoverERC721 function in the UNiV3LiquidityAmo is used to send NFTs from the amo contract to the rdpxV2Core. However there is a critical issue here, any NFT sent to the rdpxV2Core is lost forever. It is locked in without any method to retrieve it. There is no transfer or approve function for NFTs that are sent to the rdpxV2Core contract. The only tokens that can be extracted are ERC20 tokens. This permanently bricks the removeLiquidity() function in the UNiV3LiquidityAmo contract since it has to burn the NFT to complete the redeem.
univ3_positions.decreaseLiquidity(decreaseLiquidityParams); univ3_positions.collect(collect_params); univ3_positions.burn(pos.token_id);
function recoverERC721( address tokenAddress, uint256 token_id ) external onlyRole(DEFAULT_ADMIN_ROLE) { // Only the owner address can ever receive the recovery withdrawal // INonfungiblePositionManager inherits IERC721 so the latter does not need to be imported INonfungiblePositionManager(tokenAddress).safeTransferFrom( address(this), rdpxV2Core, token_id ); emit RecoveredERC721(tokenAddress, token_id); }
Although the ERC721 holder is inherited from open zeppelin, there is no method implemented to transfer it out
Manual Review
I suggest that the NFT should be transferred to the msg.sender, or a withdrawNFT function should be added to the rdpxV2Core
ERC721
#0 - c4-pre-sort
2023-09-09T06:41:08Z
bytes032 marked the issue as duplicate of #106
#1 - c4-pre-sort
2023-09-12T06:10:03Z
bytes032 marked the issue as sufficient quality report
#2 - c4-pre-sort
2023-09-12T06:12:22Z
bytes032 marked the issue as duplicate of #935
#3 - c4-judge
2023-10-20T18:05:40Z
GalloDaSballo marked the issue as satisfactory
π Selected for report: said
Also found by: 0Kage, 0xCiphky, 0xkazim, 836541, AkshaySrivastav, Evo, HChang26, HHK, KrisApostolov, Neon2835, QiuhaoLi, Tendency, Toshii, bart1e, bin2chen, carrotsmuggler, chaduke, etherhood, gjaldon, glcanvas, josephdara, lanrebayode77, mahdikarimi, max10afternoon, nobody2018, peakbolt, qpzm, rvierdiiev, sces60107, tapir, ubermensch, volodya
4.3283 USDC - $4.33
The liquidity pooled from the PerpetualAtlanticVaultLP is used by the core contract. This liquidity is provided by anyone, and after each epoch 1 week
an incentive is paid after to further incentivise liquidity provision. However, the funds can be stolen from the Lp contract immediately they are deposited.
Once the rdpx incentive is paid into the contract,
deposit
and redeem
in the same functionManual Review
Use a TWAP method to allocate rdpx incentives when users are withdrawing collateral. Or instead pay the incentive in the collateral token to the simply increase the value of every holders share.
ERC20
#0 - bytes032
2023-09-09T10:50:24Z
The warden doesn't explain precisely why would that happen and that's because of #867
#1 - c4-pre-sort
2023-09-09T10:51:18Z
bytes032 marked the issue as low quality report
#2 - c4-pre-sort
2023-09-14T07:15:28Z
bytes032 marked the issue as sufficient quality report
#3 - c4-sponsor
2023-09-25T16:39:44Z
psytama (sponsor) disputed
#4 - psytama
2023-09-25T16:40:59Z
Insufficient POC issue, what the issue is is not clear.
#5 - c4-judge
2023-10-12T11:33:06Z
GalloDaSballo marked the issue as duplicate of #867
#6 - c4-judge
2023-10-12T11:33:14Z
GalloDaSballo marked the issue as partial-25
π 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
The function convertToShares is used to get the asset conversion to shares, however there is a mathematical oversight here. The prices gotten from the oracle are in 18 decimals, however the calculations are done in 8 decimals
In the perpetuallatlanticvaultlp.convertToShares()
function convertToShares( uint256 assets ) public view returns (uint256 shares) { uint256 supply = totalSupply; uint256 rdpxPriceInAlphaToken = perpetualAtlanticVault.getUnderlyingPrice(); uint256 totalVaultCollateral = totalCollateral() + ((_rdpxCollateral * rdpxPriceInAlphaToken) / 1e8); //@audit price conversion here assumes 8 decimals for the price returned return supply == 0 ? assets : assets.mulDivDown(supply, totalVaultCollateral); }
In the perpetualAtlanticVault.getUnderlyingPrice():
/// @inheritdoc IPerpetualAtlanticVault function getUnderlyingPrice() public view returns (uint256) { return IRdpxEthOracle(addresses.assetPriceOracle).getRdpxPriceInEth(); }
from the interface comment see that it assumes a return price of 8 decimals https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/IPerpetualAtlanticVault.sol#L20-L24
However in the IRdpxEthOracle.getRdpxPriceInEth()
/// @notice Returns the price of rDPX in ETH /// @return price price of rDPX in ETH in 1e18 decimals function getRdpxPriceInEth() external view override returns (uint price) { require( blockTimestampLast + timePeriod + nonUpdateTolerance > block.timestamp, "RdpxEthOracle: UPDATE_TOLERANCE_EXCEEDED" ); price = consult(token0, 1e18); require(price > 0, "RdpxEthOracle: PRICE_ZERO"); }
The price is returned in 18 decimals : https://github.com/dopex-io/rdpx-eth-oracle/blob/5762c2339b1c45b87ff4db172e43cef4a0ff603a/src/RdpxEthOracle.sol#L241C2-L253C6
This causes an issue because the decimals are handled based on the assumption that the oracle returns 8 decimals which it returns 18
Manual Review
Perform the accurate scaling by dividing by 1e18 instead of 1e8
Decimal
#0 - c4-pre-sort
2023-09-09T11:23:53Z
bytes032 marked the issue as duplicate of #549
#1 - c4-pre-sort
2023-09-12T05:22:25Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T18:28:02Z
GalloDaSballo marked the issue as satisfactory
#3 - c4-judge
2023-10-20T18:28:12Z
GalloDaSballo changed the severity to 2 (Med Risk)
#4 - 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
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L218-L229 https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L274-L284
Rounding of shares to assets do not conform to the ERC4626 standard: EIP 4626's Security Considerations (https://eips.ethereum.org/EIPS/eip-4626)
Finally, ERC-4626 Vault implementers should be aware of the need for specific, opposing rounding directions across the different mutable and view methods, as it is considered most secure to favor the Vault itself during calculations over its users:
If (1) itβs calculating how many shares to issue to a user for a certain amount of the underlying tokens they provide or (2) itβs determining the amount of the underlying tokens to transfer to them for returning a certain amount of shares, it should round down. If (1) itβs calculating the amount of shares a user has to supply to receive a given amount of the underlying tokens or (2) itβs calculating the amount of underlying tokens a user has to provide to receive a certain amount of shares, it should round up.
This shows the rounding direction required for deposit/redeem. However this is not the case here even though this contract is an ERC4626 contract : https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L112-L121 https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L137-L149
/// @notice Returns the amount of shares recieved for a given amount of assets 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); } function _convertToAssets( uint256 shares ) internal view virtual returns (uint256 assets, uint256 rdpxAmount) { uint256 supply = totalSupply; return (supply == 0) ? (shares, 0) : ( shares.mulDivDown(totalCollateral(), supply), shares.mulDivDown(_rdpxCollateral, supply) ); }
As seen above, both deposits and withdrawals are a being rounded down. This is an issue for the users when they are to redeem their tokens. Since both the rdpx amount and the collateral amount is being rounded down
Manual Review , Solodit
I recommend that deposits should be left as they are, however redeeming should roundup the amount being sent back to the user.
Math
#0 - c4-pre-sort
2023-09-07T13:18:48Z
bytes032 marked the issue as duplicate of #699
#1 - c4-pre-sort
2023-09-13T14:37:04Z
bytes032 marked the issue as not a duplicate
#2 - c4-pre-sort
2023-09-13T14:37:15Z
bytes032 marked the issue as not a duplicate
#3 - c4-pre-sort
2023-09-13T14:37:53Z
bytes032 marked the issue as duplicate of #1481
#4 - c4-pre-sort
2023-09-13T14:37:58Z
bytes032 marked the issue as duplicate of #1481
#5 - c4-judge
2023-10-20T19:52:42Z
GalloDaSballo changed the severity to QA (Quality Assurance)