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: 26/133
Findings: 3
Award: $135.62
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ladboy233
Also found by: 0xSmartContract, 8olidity, Aymen0909, Chom, IllIllI, OptimismSec, PaludoX0, TomJ, ayeslick, cccz, csanuragjain, joestakey, neko_nyaa, pashov, peritoflores, rbserver, rvierdiiev
19.982 USDC - $19.98
In frxETHMinter.sol
there is the following code
function recoverEther(uint256 amount) external onlyByOwnGov { (bool success,) = address(owner).call{ value: amount }(""); require(success, "Invalid transfer"); emit EmergencyEtherRecovered(amount); }
This allows the owner
of the contract (bypassing timelock) to withdraw all of the submitted Ether to the contract before it was deposited to the ETH 2.0 deposit contract, esentially rugging everyone who submitted Ether to mint frxETH.
The impact of this issue is that since the protocol is ruggable, it’s reputation will suffer. Also if this is exploited then all of the users will essentially lose all of their submitted Ether
Remove the recoverEther
functionality completely.
#0 - FortisFortuna
2022-09-25T21:14:36Z
We are well aware of the permission structure. The owner will most likely be a large multisig. We mentioned the Frax Multisig in the scope too.
#1 - joestakey
2022-09-26T16:41:28Z
Duplicate of #107
The code loops through the minters_array
until it finds the minter_address
to be removed. Every new minter
will be pushed to the end of the minters_array
array. In the case that there were many minters added already and an owner adds a wrong address as the minter
it is possible that the for loop takes too much gas and the transaction reverts because it will hit the block gas limit.
The impact is a potential Denial of Service when trying to remove a wrong or a malicious minter.
Remove the minters_array
since it’s not used for any critical logic in the code or instead implement the same mechanism to pop a minter from the end of the array as in OperatorRegistry.sol
popValidators()
#0 - FortisFortuna
2022-09-25T22:40:51Z
Technically correct, but in practice, the number of minters will always remain low. If it becomes an issue, we can designate one minter as a "pre-minter" that has a batch of tokens minted to it beforehand, then auxiliary contracts can connect to that instead of ERC20PermitPermissionedMint.sol instead.
#1 - joestakey
2022-09-26T16:43:44Z
Duplicate of #12
🌟 Selected for report: Lambda
Also found by: 0x1f8b, 0x5rings, 0xSky, 0xSmartContract, 8olidity, Chom, CodingNameKiki, IllIllI, Ruhum, Sm4rty, brgltd, hansfriese, m9800, magu, pashov, pedroais, peritoflores, prasantgupta52, rokinot, seyni
12.4859 USDC - $12.49
The frxETHMinter.sol
contract has the following code
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyByOwnGov { require(IERC20(tokenAddress).transfer(owner, tokenAmount), "recoverERC20: Transfer failed"); emit EmergencyERC20Recovered(tokenAddress, tokenAmount); }
but the way to check if the transfer is successful (with a require
statement) won’t work for non-ERC20 compliant tokens like USDT because they do not return a boolean value on transfer()
, so the require
statement will always revert.
The impact is that the implemented recoverERC20
functionality won’t work as expected, resulting in such Non-ERC20 compliant tokens like USDT getting stuck in the contract
Use OpenZeppelin’s SafeERC20 library - safeTransfer
& safeTransferFrom
#0 - FortisFortuna
2022-09-25T21:36:43Z
Not really medium risk. Technically you could use safeTransfer, but if someone were to accidentally send something to this contract, it would most likely be either ETH, FRAX, frxETH, or sfrxETH, all of which are transfer compliant.
#1 - joestakey
2022-09-26T16:41:53Z
Duplicate of #18