Forgeries contest - codeislight's results

A protocol for on-chain games with NFT prizes on Ethereum.

General Information

Platform: Code4rena

Start Date: 13/12/2022

Pot Size: $36,500 USDC

Total HM: 5

Participants: 77

Period: 3 days

Judge: gzeon

Total Solo HM: 1

Id: 191

League: ETH

Forgeries

Findings Distribution

Researcher Performance

Rank: 14/77

Findings: 2

Award: $346.08

Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: 9svR6w

Also found by: 0xdeadbeef0x, BAHOZ, codeislight, deliriusz, gasperpre, trustindistrust

Labels

bug
2 (Med Risk)
satisfactory
edited-by-warden
duplicate-101

Awards

320.1346 USDC - $320.13

External Links

Lines of code

https://github.com/smartcontractkit/chainlink/blob/e1e78865d4f3e609e7977777d7fb0604913b63ed/contracts/src/v0.8/VRFCoordinatorV2.sol#L407

Vulnerability details

Impact

  • VRFNFTRandomDraw.initialize() must check keyHash to be one of the corresponding keyHashes for GasPrice supported by the coordinator before assigning the settings storage variable.
  • Note that Chainlink coordinator doesn't check the validity of keyHashes to save on gas fees on their end, refer to the Github link down below.

Proof of Concept

Tools Used

no tools were used, just manual analysis

a practical mitigation would be to have a mapping to check the keyHash validity in VRFNFTRandomDrawFactory:

mapping (bytes32 => bool) public isValidKeyHash; /// @notice Constructor to set the implementation constructor(address _implementation, bytes32[] calldata _keyHashes) initializer { ... for(uint i = 0; i < _keyHashes.length;){ isValidKeyHash[_keyHashes[i]] = true; unchecked { ++i; } } } ... error InvalidKeyHash(); /// @notice Function to make a new drawing /// @param settings settings for the new drawing function makeNewDraw(IVRFNFTRandomDraw.Settings memory settings) external returns (address) { if(!isValidKeyHash[settings.keyHash]) revert InvalidKeyHash(); ... }

#0 - c4-judge

2022-12-17T16:26:29Z

gzeon-c4 marked the issue as duplicate of #194

#1 - c4-judge

2023-01-23T16:51:17Z

gzeon-c4 marked the issue as satisfactory

Awards

25.9485 USDC - $25.95

Labels

bug
G (Gas Optimization)
grade-b
edited-by-warden
G-06

External Links

  • in makeNewDraw function, newDrawing variable could be defined as a variable in the return area to save some gas

    function makeNewDraw(IVRFNFTRandomDraw.Settings memory settings) external returns (address newDrawing) { address admin = msg.sender; // Clone the contract newDrawing = ClonesUpgradeable.clone(implementation); // Setup the new drawing IVRFNFTRandomDraw(newDrawing).initialize(admin, settings); // Emit event for indexing emit SetupNewDrawing(admin, newDrawing); }
  • use unchecked in calculations that is impossible to overflow:

    function _requestRoll() internal { ... unchecked{ // Setup re-draw timelock request.drawTimelock = block.timestamp + settings.drawBufferTime; } ... } function fulfillRandomWords( uint256 _requestId, uint256[] memory _randomWords ) internal override { ... unchecked { // Get total token range uint256 tokenRange = settings.drawingTokenEndId - settings.drawingTokenStartId; // Store a number from it here (reduce number here to reduce gas usage) // We know there will only be 1 word sent at this point. request.currentChosenTokenId = (_randomWords[0] % tokenRange) + settings.drawingTokenStartId; } ... }
  • assign state variables after revert checks, to save gas on SSTORE in case it reverts:

    function initialize(address admin, Settings memory _settings) public initializer { // Check values in memory: if (_settings.drawBufferTime < HOUR_IN_SECONDS) { revert REDRAW_TIMELOCK_NEEDS_TO_BE_MORE_THAN_AN_HOUR(); } if (_settings.drawBufferTime > MONTH_IN_SECONDS) { revert REDRAW_TIMELOCK_NEEDS_TO_BE_LESS_THAN_A_MONTH(); } ... // Set new settings settings = _settings; ... }
  • emit events at the end of the functions to save gas on reverts, the following are the instances:

    emit InitializedDraw(msg.sender, settings); emit SetupDraw(msg.sender, settings); emit WinnerSentNFT( user, address(settings.token), settings.tokenId, settings ); emit OwnerReclaimedNFT(owner());

#0 - c4-judge

2022-12-17T17:47:28Z

gzeon-c4 marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter