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: 54/133
Findings: 2
Award: $47.99
🌟 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
https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L190-L204 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L159-L174
True trustlessness is hard, but there's not much point in having open source smart contracts unless the goal is achieved completely. The moment a vector exists where a rug pull could occur a user should be rightly suspicious.
Although TimelockController
is used on the timelock_address
the same does not hold for the owner
. The owner
in the contract can withdraw ERC20 tokens or ether to themselves without going through the timelock, anytime they want (now or in the future).
See lines 159-174 and lines 190 - 204.
The onlyByOwnGov
modifier makes sure that only the timelock can call the contract, or the deployer or owner of the contract.
The emergency functions,recoverEther
and recoverERC20
, are extremely powewr functions and should only be called by the timelock contract which is has governance mechnisms to prevent unilateral use. This does not hold for the owner
who could always use these functions to completely drain the contract of funds.
The contract also lets the owner
call setWithHoldRatio
anytime they want, without a timelock. In combination with moveWithheldETH
this presents another rug pull vector.
Manual Inspection
Split the authority modifiers into two. Only the timelock_address
should exclusively be able to recoverEth
, recoverERC20
, setWithHoldRatio
and moveWithheldETH
from the contract.
The two modifiers could be implemented as follows:
modifier onlyTimeLock() { require(msg.sender == timelock_address , "Caller Not timelock"); _; } modifier onlyOwner() { require(msg.sender == owner , "Caller Not owner"); _; }
#0 - FortisFortuna
2022-09-25T21:12:08Z
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-26T18:15:14Z
Duplicate of #107
🌟 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.0141 USDC - $28.01
frxETHMinter._submit
can lead to loss of fundsAlthough the amount we are speaking about are tiny, perhaps consider rounding up when the withholdRatio
is set to a non-zero value. Otherwise the possiblity exists that when extremely small msg.value
s are sent nothing is withheld.
The only check done for msg.value
is to see if it is greater than zero on line 88. No other checks are done
require(msg.value != 0, "Cannot submit 0");
However, msg.value
on line 96, is being divided by a constant RATIO_PRECISION
which can lead to a result of zero for withheld_amt