Frax Ether Liquid Staking contest - B2's results

A liquid ETH staking derivative designed to uniquely leverage the Frax Finance ecosystem.

General Information

Platform: Code4rena

Start Date: 22/09/2022

Pot Size: $30,000 USDC

Total HM: 12

Participants: 133

Period: 3 days

Judge: 0xean

Total Solo HM: 2

Id: 165

League: ETH

Frax Finance

Findings Distribution

Researcher Performance

Rank: 59/133

Findings: 2

Award: $42.00

🌟 Selected for report: 0

🚀 Solo Findings: 0

public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents’ functions and change the visibility from external to public

File: main/src/OperatorRegistry.sol #1 82 function popValidators(uint256 times) public onlyByOwnGov {

Missing 0 address check

If contract miss this zero check address validation there is chance that contract will loose some functionality

File: main/src/OperatorRegistry.sol #1 41 timelock_address = _timelock_address;

Floating Pragma

File: main/src/OperatorRegistry.sol #1 2 pragma solidity ^0.8.0;

Use of Block.timestamp

Block timestamps have historically been used for a variety of applications, such as entropy for random numbers , locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.

File: main/src/sfrxETH.sol #1 50 if (block.timestamp >= rewardsCycleEnd) { syncRewards(); }

Use Solidity version of atleast 0.8.

File: main/src/OperatorRegistry.sol #1 2 pragma solidity ^0.8.0;

APPROVE should be replaced with SAFEAPPROVE or SAFEINCREASEALLOWANCE/SAFEDECREASEALLOWANCE()

approve is subject to a known front-running attack. Consider using safeapprove instead.

File: main/src/frxETHMinter.sol #1 75 frxETHToken.approve(address(sfrxETHToken), msg.value);

Event is missing indexed fields

Each event should use three indexed fields if there are three or more fields

File: main/src/OperatorRegistry.sol #1 212 event ValidatorRemoved(bytes pubKey, uint256 remove_idx, bool dont_care_about_ordering);

.length should not be looked up in every loop of a for-loop\

Even memory arrays incur the overhead of bit tests and bit shifts to calculate the array length. Storage array length checks incur an extra Gwarmaccess (100 gas) PER-LOOP.

FIle: main/src/OperatorRegistry.sol #1 114 for (uint256 i = 0; i < original_validators.length; ++i) {

++i costs less gas than ++i, especially when it's used in for-loops (--i/i-- too)

File: main/src/ERC20/ERC20PermitPermissionedMint.sol #1 84 for (uint i = 0; i < minters_array.length; i++){

++i/i++ should be unchecked{++i}/unchecked{++i} when it is not possible for them to overflow, as is the case when used in for- and while-loops

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP

FIle: main/src/OperatorRegistry.sol #1 114 for (uint256 i = 0; i < original_validators.length; ++i) {

Use a more recent version of solidity

Use a solidity version of at least 0.8.13 to get the ability to use using for with a list of free functions

FIle: main/src/OperatorRegistry.sol #1 2 pragma solidity ^0.8.0;

Using > 0 costs more gas than != 0 when used on a uint in a require() statement

File: main/src/frxETHMinter.sol #1 79 require(sfrxeth_recieved > 0, 'No sfrxETH was returned');

It costs more gas to initialize variables to zero than to let the default of zero be applied

File: main/src/OperatorRegistry.sol #1 63 for (uint256 i = 0; i < arrayLength; ++i) {

Using private rather than public for constants, saves gas

If needed, the value can be read from the verified contract source code

File: main/src/frxETHMinter.sol #1 38 uint256 public constant DEPOSIT_SIZE = 32 ether;

Use custom errors rather than revert()/require() strings to save deployment gas

Custom errors are available from solidity version 0.8.4. Use Solidity latest solidity version

File: main/src/OperatorRegistry.sol #1 46 require(msg.sender == timelock_address || msg.sender == owner, "Not owner or timelock");

<x> += <y> costs more gas than <x> = <x> + <y> for state variables

File: main/src/frxETHMinter.sol #1 97 currentWithheldETH += withheld_amt;
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