Platform: Code4rena
Start Date: 28/11/2022
Pot Size: $192,500 USDC
Total HM: 33
Participants: 106
Period: 11 days
Judge: LSDan
Total Solo HM: 15
Id: 186
League: ETH
Rank: 50/106
Findings: 2
Award: $148.85
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0xNazgul, Atarpara, Awesome, Aymen0909, BClabs, Kong, ali_shehab, bullseye, chaduke, csanuragjain, datapunk, fatherOfBlocks, hansfriese, kaliberpoziomka8552, nicobevi, pashov, pzeus, shark, unforgiven, web3er, xiaoming90
44.934 USDC - $44.93
https://github.com/code-423n4/2022-11-paraspace/blob/main/paraspace-core/contracts/misc/NFTFloorOracle.sol#L167-L172 https://github.com/code-423n4/2022-11-paraspace/blob/main/paraspace-core/contracts/misc/NFTFloorOracle.sol#L326-L338
The nfts price feeders in the NFTFloorOracle
contract should be added or removed only by the admin
but because the removeFeeder
function is missing the onlyRole(DEFAULT_ADMIN_ROLE)
modifier any user can remove a feeder, this could impact the whole protocol if all the feeders for a given nft collection are removed (for example).
The issue occurs in the removeFeeder
function below :
File: paraspace-core/contracts/misc/NFTFloorOracle.sol Line 167-172
function removeFeeder(address _feeder) external onlyWhenFeederExisted(_feeder) { _removeFeeder(_feeder); }
As you can see the function contain only the onlyWhenFeederExisted(_feeder)
modifier and calls the internal function _removeFeeder
which also contain the same modifier :
File: paraspace-core/contracts/misc/NFTFloorOracle.sol Line 326-328
function _removeFeeder(address _feeder) internal onlyWhenFeederExisted(_feeder)
So any user can call the removeFeeder
function to remove an existing feeder and this is wrong because only the admin
should have the power to remove feeders.
Manual review
To solve this issue the onlyRole(DEFAULT_ADMIN_ROLE)
modifier must be added to the removeFeeder
function :
function removeFeeder(address _feeder) external onlyRole(DEFAULT_ADMIN_ROLE) { _removeFeeder(_feeder); }
#0 - JeffCX
2022-12-18T04:02:06Z
#1 - c4-judge
2022-12-20T16:59:24Z
dmvt marked the issue as duplicate of #31
#2 - c4-judge
2023-01-09T14:11:09Z
dmvt changed the severity to 3 (High Risk)
#3 - c4-judge
2023-01-23T15:59:33Z
dmvt marked the issue as satisfactory
🌟 Selected for report: IllIllI
Also found by: 0x4non, 0x52, 0xAgro, 0xNazgul, 0xSmartContract, 0xackermann, 9svR6w, Awesome, Aymen0909, B2, BRONZEDISC, Bnke0x0, Deekshith99, Deivitto, Diana, Dravee, HE1M, Jeiwan, Kaiziron, KingNFT, Lambda, Mukund, PaludoX0, RaymondFam, Rolezn, Sathish9098, Secureverse, SmartSek, __141345__, ahmedov, ayeslick, brgltd, cccz, ch0bu, chrisdior4, cryptonue, cryptostellar5, csanuragjain, datapunk, delfin454000, erictee, gz627, gzeon, helios, i_got_hacked, ignacio, imare, jadezti, jayphbee, joestakey, kankodu, ksk2345, ladboy233, martin, nadin, nicobevi, oyc_109, pashov, pavankv, pedr02b2, pzeus, rbserver, ronnyx2017, rvierdiiev, shark, unforgiven, xiaoming90, yjrwkk
103.9175 USDC - $103.92
Issue | Risk | Instances | |
---|---|---|---|
1 | Immutable state variables lack zero address checks | Low | 15 |
2 | Remove redundant checks | NC | 2 |
3 | Remove redundant state variables | NC | 3 |
4 | Use scientific notation | NC | 1 |
5 | 2**<N> should be re-written as type(uint<N>).max | NC | 3 |
Constructors should check the values written in an immutable state variables(address) is not the address(0)
Instances include:
File: paraspace-core/contracts/misc/ParaSpaceOracle.sol Line 57
ADDRESSES_PROVIDER = provider;
File: paraspace-core/contracts/misc/UniswapV3OracleWrapper.sol Line 28-30
UNISWAP_V3_FACTORY = IUniswapV3Factory(_factory); UNISWAP_V3_POSITION_MANAGER = INonfungiblePositionManager(_manager); ADDRESSES_PROVIDER = IPoolAddressesProvider(_addressProvider);
File: paraspace-core/contracts/protocol/pool/PoolApeStaking.sol Line 52
ADDRESSES_PROVIDER = provider;
File: paraspace-core/contracts/protocol/pool/PoolCore.sol Line 65
ADDRESSES_PROVIDER = provider;
File: paraspace-core/contracts/protocol/pool/PoolMarketplace.sol Line 63
ADDRESSES_PROVIDER = provider;
File: paraspace-core/contracts/protocol/pool/PoolParameters.sol Line 90
ADDRESSES_PROVIDER = provider;
File: paraspace-core/contracts/protocol/tokenization/NTokenApeStaking.sol Line 33
_apeCoinStaking = ApeCoinStaking(apeCoinStaking);
File: paraspace-core/contracts/protocol/tokenization/NTokenApeStaking.sol Line 48-54
punk = _punk; wpunk = _wpunk; pool = _pool; Punk = IPunks(punk); WPunk = IWrappedPunks(wpunk); Pool = IPool(pool);
Add non-zero address checks in the constructors for the instances aforementioned.
When a public/external
function calls an internal
function it is redundant to include the same modifier in both functions, so it's recommended to use the modifier only on one of the functions (either the internal or the public).
There are 2 instances of this issue:
The public function removeAsset
calls the internal function _removeAsset
and both contain the same modifier onlyWhenAssetExisted(_asset)
, so this modifier should be removed from one of them.
File: paraspace-core/contracts/misc/NFTFloorOracle.sol Line 148-154
function removeAsset(address _asset) external onlyRole(DEFAULT_ADMIN_ROLE) onlyWhenAssetExisted(_asset) { _removeAsset(_asset); }
File: paraspace-core/contracts/misc/NFTFloorOracle.sol Line 296-298
function _removeAsset(address _asset) internal onlyWhenAssetExisted(_asset)
The public function removeFeeder
calls the internal function _removeFeeder
and both contain the same modifier onlyWhenFeederExisted(_feeder)
, so this modifier should be removed from one of them.
File: paraspace-core/contracts/misc/NFTFloorOracle.sol Line 167-172
function removeFeeder(address _feeder) external onlyWhenFeederExisted(_feeder) { _removeFeeder(_feeder); }
File: paraspace-core/contracts/misc/NFTFloorOracle.sol Line 326-328
function _removeFeeder(address _feeder) internal onlyWhenFeederExisted(_feeder)
In the WPunkGateway
contract the following state variables : punk
, wpunk
and pool
are redundant and can be removed because the value of each variable can be derived from its interface : Punk
, WPunk
and Pool
respectively and this by using address(<interface>)
.
In the WPunkGateway
contract the following state variables are redundant and can be removed :
File: paraspace-core/contracts/ui/WPunkGateway.sol Line 33-35
address public immutable punk; address public immutable wpunk; address public immutable pool;
Those variables are unnecessary because for each one there exist another state variable that store the same value :
IPunks internal immutable Punk; IWrappedPunks internal immutable WPunk; IPool internal immutable Pool;
And for example if we need to get the pool
address we can obtain it by using address(Pool)
directly (and the same apply for the other variables).
The aforementioned state variables should be removed.
When using multiples of 10 you shouldn't use decimal literals or exponentiation (e.g. 1000000, 10**18) but use scientific notation for better readability.
Instances include:
File: paraspace-core/contracts/misc/UniswapV3OracleWrapper.sol Line 245
oracleData.token0Price * (10**18)
Use scientific notation for the instances aforementioned.
2**<N>
should be re-written as type(uint<N>).max
:Instances include:
File: paraspace-core/contracts/misc/UniswapV3OracleWrapper.sol
Replace the aforementioned statements for better readability.
#0 - c4-judge
2023-01-25T17:01:58Z
dmvt marked the issue as grade-b