Platform: Code4rena
Start Date: 02/08/2023
Pot Size: $42,000 USDC
Total HM: 13
Participants: 45
Period: 5 days
Judge: hickuphh3
Total Solo HM: 5
Id: 271
League: ETH
Rank: 29/45
Findings: 1
Award: $89.63
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Aymen0909
Also found by: 0xStalin, 0xbepresent, Arz, D_Auditor, Jorgect, T1MOH, bin2chen, dirk_y, josephdara, ptsanev, rvierdiiev, seerether, shirochan, trachev
89.6296 USDC - $89.63
The rngComplete is a function Called by the relayer to complete the Rng relay auction. However it has zero access control.
The function makes calls to the prizepool to close a draw, it also withdraws from a reserve. All these are done with the data passed in as parameters. Hence it should not be left unguarded
function rngComplete( uint256 _randomNumber, uint256 _rngCompletedAt, address _rewardRecipient, uint32 _sequenceId, AuctionResult calldata _rngAuctionResult ) external returns (bytes32) { if (_sequenceHasCompleted(_sequenceId)) revert SequenceAlreadyCompleted(); uint64 _auctionElapsedSeconds = uint64(block.timestamp < _rngCompletedAt ? 0 : block.timestamp - _rngCompletedAt); if (_auctionElapsedSeconds > (_auctionDurationSeconds-1)) revert AuctionExpired(); // Calculate the reward fraction and set the draw auction results UD2x18 rewardFraction = _fractionalReward(_auctionElapsedSeconds); _auctionResults.rewardFraction = rewardFraction; _auctionResults.recipient = _rewardRecipient; _lastSequenceId = _sequenceId; AuctionResult[] memory auctionResults = new AuctionResult[](2); auctionResults[0] = _rngAuctionResult; auctionResults[1] = AuctionResult({ rewardFraction: rewardFraction, recipient: _rewardRecipient }); uint32 drawId = prizePool.closeDraw(_randomNumber); uint256 futureReserve = prizePool.reserve() + prizePool.reserveForOpenDraw(); uint256[] memory _rewards = RewardLib.rewards(auctionResults, futureReserve); emit RngSequenceCompleted( _sequenceId, drawId, _rewardRecipient, _auctionElapsedSeconds, rewardFraction ); for (uint8 i = 0; i < _rewards.length; i++) { uint104 _reward = uint104(_rewards[i]); if (_reward > 0) { prizePool.withdrawReserve(auctionResults[i].recipient, _reward); emit AuctionRewardDistributed(_sequenceId, auctionResults[i].recipient, i, _reward); } } return bytes32(uint(drawId)); }
Manual Review
Since it says that it is a relayer function. Then require that the msg.sender is the rngAuctionRelayer address
Access Control
#0 - c4-pre-sort
2023-08-08T02:58:03Z
raymondfam marked the issue as duplicate of #82
#1 - c4-judge
2023-08-14T02:46:57Z
HickupHH3 marked the issue as satisfactory