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
Rank: 62/133
Findings: 2
Award: $41.14
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: rotcivegaf
Also found by: 0x040, 0x1f8b, 0x4non, 0xNazgul, 0xSmartContract, 0xf15ers, 8olidity, Aymen0909, B2, Bahurum, Bnke0x0, Ch_301, CodingNameKiki, Deivitto, Diana, Funen, IllIllI, JC, JLevick, KIntern_NA, Lambda, OptimismSec, PaludoX0, RockingMiles, Rolezn, Sm4rty, Soosh, Tagir2003, Tointer, TomJ, Triangle, Trust, V_B, Waze, Yiko, __141345__, a12jmx, ajtra, asutorufos, ayeslick, aysha, bbuddha, bharg4v, bobirichman, brgltd, bytera, c3phas, cryptostellar5, cryptphi, csanuragjain, datapunk, delfin454000, durianSausage, exd0tpy, gogo, got_targ, jag, joestakey, karanctf, ladboy233, leosathya, lukris02, mics, millersplanet, natzuu, neko_nyaa, obront, oyc_109, parashar, peritoflores, rbserver, ret2basic, rokinot, ronnyx2017, rvierdiiev, sach1r0, seyni, sikorico, slowmoses, tnevler, yasir, yongskiws
28.3211 USDC - $28.32
You allow in some arrays to have duplicates. Sometimes you assumes there are no duplicates in the array.
OperatorRegistry.addValidator
pushed validator
without checking if already exist (other similar code samples are checking if exists, therefore I think it might be medium)
owner param should be validated to make sure the owner address is not address(0). Otherwise if not given the right input all only owner accessible functions will be unaccessible.
Owned.sol.nominateNewOwner _owner
Users can mistakenly think that the return value is the named return, but it is actually the actualreturn statement that comes after. To know that the user needs to read the code and is confusing. Furthermore, removing either the actual return or the named return will save gas.
sfrxETH.sol, mintWithSignature sfrxETH.sol, depositWithSignature
To give more trust to users: functions that set key/critical variables should be put behind a timelock.
https://github.com/code-423n4/2022-09-frax/tree/main/src/OperatorRegistry.sol#L202 https://github.com/code-423n4/2022-09-frax/tree/main/src/ERC20/ERC20PermitPermissionedMint.sol#L94 https://github.com/code-423n4/2022-09-frax/tree/main/src/OperatorRegistry.sol#L181
A malicious attacker that is also a protocol owner can push unlimitedly to an array, that some function loop over this array. If increasing the array size enough, calling the function that does a loop over the array will always revert since there is a gas limit. This is a Med Risk issue since it can lead to DoS with a reasonable chance of having untrusted owner or even an owner that did a mistake in good faith.
ERC20PermitPermissionedMint.sol (L83): Unbounded loop on the array minters_array that can be publicly pushed by ['addMinter'] and can't be pulled OperatorRegistry.sol (L113): Unbounded loop on the array validators that can be publicly pushed by ['addValidator', 'removeValidator'] and can't be pulled
external / public functions parameters should be validated to make sure the address is not 0. Otherwise if not given the right input it can mistakenly lead to loss of user funds.
ERC20PermitPermissionedMint.sol.minter_burn_from b_address ERC20PermitPermissionedMint.sol.setTimelock _timelock_address ERC20PermitPermissionedMint.sol.addMinter minter_address ERC20PermitPermissionedMint.sol.minter_mint m_address OperatorRegistry.sol.setTimelock _timelock_address ERC20PermitPermissionedMint.sol.removeMinter minter_address sfrxETH.sol.depositWithSignature receiver sfrxETH.sol.mintWithSignature receiver
🌟 Selected for report: pfapostol
Also found by: 0x040, 0x1f8b, 0x4non, 0x5rings, 0xA5DF, 0xNazgul, 0xSmartContract, 0xmatt, 0xsam, Amithuddar, Aymen0909, B2, Ben, Bnke0x0, Chom, CodingNameKiki, Deivitto, Diana, Fitraldys, Funen, IllIllI, JAGADESH, JC, Metatron, Ocean_Sky, PaludoX0, Pheonix, RaymondFam, ReyAdmirado, RockingMiles, Rohan16, Rolezn, Satyam_Sharma, Sm4rty, SnowMan, SooYa, Tagir2003, TomJ, Tomio, Triangle, V_B, Waze, __141345__, ajtra, albincsergo, asutorufos, aysha, beardofginger, bobirichman, brgltd, bulej93, bytera, c3phas, ch0bu, cryptostellar5, cryptphi, d3e4, delfin454000, dharma09, drdr, durianSausage, emrekocak, erictee, fatherOfBlocks, gogo, got_targ, imare, jag, karanctf, ladboy233, leosathya, lukris02, medikko, mics, millersplanet, natzuu, neko_nyaa, oyc_109, peanuts, prasantgupta52, rbserver, ret2basic, rokinot, ronnyx2017, rotcivegaf, sach1r0, samruna, seyni, slowmoses, tnevler, wagmi, zishansami
12.8158 USDC - $12.82
Boolean variables can be checked within conditionals directly without the use of equality operators to true/false.
ERC20PermitPermissionedMint.sol, 68: require(minters[minter_address] == false, "Address already exists"); ERC20PermitPermissionedMint.sol, 78: require(minters[minter_address] == true, "Address nonexistant");
In the following files there are state variables that could be set immutable to save gas.
DOMAIN_SEPARATOR in SigUtils.sol
Caching the array length is more gas efficient. This is because access to a local variable in solidity is more efficient than query storage / calldata / memory. We recommend to change from:
for (uint256 i=0; i<array.length; i++) { ... }
to:
uint len = array.length for (uint256 i=0; i<len; i++) { ... }
ERC20PermitPermissionedMint.sol, minters_array, 84
Prefix increments are cheaper than postfix increments.
Further more, using unchecked {++x} is even more gas efficient, and the gas saving accumulates every iteration and can make a real change
There is no risk of overflow caused by increamenting the iteration index in for loops (the ++i
in for (uint256 i = 0; i < numIterations; ++i)
).
But increments perform overflow checks that are not necessary in this case.
These functions use not using prefix increments (++x
) or not using the unchecked keyword:
just change to unchecked: OperatorRegistry.sol, i, 84 just change to unchecked: OperatorRegistry.sol, i, 63 change to prefix increment and unchecked: ERC20PermitPermissionedMint.sol, i, 84
In for loops you initialize the index to start from 0, but it already initialized to 0 in default and this assignment cost gas. It is more clear and gas efficient to declare without assigning 0 and will have the same meaning:
OperatorRegistry.sol, 84 ERC20PermitPermissionedMint.sol, 84 OperatorRegistry.sol, 63
You can change the order of the storage variables to decrease memory uses.
In deployGoerli.s.sol,rearranging the storage fields can optimize to: 4 slots from: 5 slots. The new order of types (you choose the actual variables): 1. bytes 2. address 3. uint32 4. address 5. address
The following functions are used exactly once. Therefore you can inline them and save gas and improve code clearness.
sfrxETH.sol, beforeWithdraw SigUtils.sol, getStructHash