Platform: Code4rena
Start Date: 02/06/2023
Pot Size: $100,000 USDC
Total HM: 15
Participants: 75
Period: 7 days
Judge: Picodes
Total Solo HM: 5
Id: 249
League: ETH
Rank: 53/75
Findings: 1
Award: $21.62
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JCN
Also found by: 0x70C9, 0xSmartContract, 0xWaitress, 0xhacksmithh, DavidGiladi, K42, LaScaloneta, Rageur, Raihan, SAAJ, SAQ, SM3_SS, Sathish9098, Tomio, bigtone, c3phas, ernestognw, etherhood, koxuan, matrix_0wl, mgf15, naman1778, niser93, petrichor, piyushshukla, sebghatullah, shamsulhaq123
21.6219 USDC - $21.62
Title: empty constructor
Proof of Concept: NodeELRewardVault.sol#L14
Recommended Mitigation Steps: Remove if unused for gas saving
Title: Using msg.sender
directly is more effective
Proof of Concept: OperatorRewardsCollector.sol#L47 SDCollateral.sol#L44 SDCollateral.sol#L59
Recommended Mitigation Steps:
delete operator
and use msg.sender
directly instead of caching it.
uint256 amount = balances[msg.sender]; balances[msg.sender] -= amount;
Title: function getTotalQueuedValidatorCount()
gas improvement on returning value
Proof of Concept: PermissionedNodeRegistry.sol#L487
Recommended Mitigation Steps:
by set totalQueuedValidators
in returns L#486 and delete L#487 can save gas
function getTotalQueuedValidatorCount() external view override returns (uint256 totalQueuedValidators) { //@audit-info: set here
Title: function getOperatorTotalNonTerminalKeys()
gas improvement on returning value
Proof of Concept: PermissionedNodeRegistry.sol#L533
Recommended Mitigation Steps:
by set totalNonWithdrawnKeyCount
in returns L#526 and delete L#533 can save gas
function getOperatorTotalNonTerminalKeys( address _nodeOperator, uint256 _startIndex, uint256 _endIndex ) public view override returns (uint64 totalNonWithdrawnKeyCount) { //@audit-info: set here
Title: Avoid unnecessary memory allocation and copy
Proof of Concept: PermissionlessPool.sol#L276-L286
Recommended Mitigation Steps:
instead of allocating a new bytes array and copying the values one by one, you can use abi.encodePacked
to directly pack the values into a bytes array.
Consider change it to:
function to_little_endian_64(uint256 _depositAmount) internal pure returns (bytes memory) { uint64 value = uint64(_depositAmount / 1 gwei); return abi.encodePacked(value); }
Title: Avoid unnecessary variable assignments
Proof of Concept: PoolUtils.sol#L256-L257
Recommended Mitigation Steps:
Instead of assigning usersETH
and collateralETH
to variables, use it directly.
Consider change it to:
function calculateRewardShare(uint8 _poolId, uint256 _totalRewards) external view override returns ( uint256 userShare, uint256 operatorShare, uint256 protocolShare ) { uint256 TOTAL_STAKED_ETH = staderConfig.getStakedEthPerNode(); uint256 protocolFeeBps = getProtocolFee(_poolId); uint256 operatorFeeBps = getOperatorFee(_poolId); uint256 _userShareBeforeCommission = (_totalRewards * (TOTAL_STAKED_ETH - getCollateralETH(_poolId))) / TOTAL_STAKED_ETH; //@audit-info: set here protocolShare = (protocolFeeBps * _userShareBeforeCommission) / staderConfig.getTotalFee(); operatorShare = (_totalRewards * getCollateralETH(_poolId)) / TOTAL_STAKED_ETH; //@audit-info: set here operatorShare += (operatorFeeBps * _userShareBeforeCommission) / staderConfig.getTotalFee(); userShare = _totalRewards - protocolShare - operatorShare; }
#0 - c4-judge
2023-06-13T21:39:17Z
Picodes marked the issue as grade-a
#1 - c4-sponsor
2023-06-21T13:15:00Z
manoj9april marked the issue as sponsor acknowledged
#2 - c4-judge
2023-07-03T13:51:28Z
Picodes marked the issue as grade-b