sfrxETH security/technical analysis
Introduction
This is a technical analysis of all the smart contracts of the sfrxETH asset and its main dependencies.
Disclosure: This is not an exhaustive security review of the asset like the ones done by the Frax team, but an analysis from an Aave technical service provider on different aspects we consider critical to review before new listings. Consequently, like with any security review, this is not an absolute statement that the asset is flawless or not, only a disclosure of any potential problem or trust assumptions.
We appreciate the responsiveness of the Frax team answering all our questions during the process.
Analysis
sfrxETH is a staked version of frxETH that accrues the staking yield ETH PoS validation.
For the context of this analysis, our focus has been on the following aspects, critical for the correct and secure integration with Aave:
- Mechanism to update the exchange rate of the asset for the underlying ETH.
- Access control (ownerships, admin roles) and nature of the entities involved.
- Any miscellaneous aspect of the code and system’s security we can consider of importance.
General points
- The main contracts are non-upgradable, with well-known dependencies like OZ or Solmate.
- The system’s admin roles are mainly controlled by the Frax Team 3-of-5 Gnosis Safe and a Timelock smart contract with a 2-day lock period owned by the Frax Comptroller (Gnosis Safe 3-of-5).
Contracts
The following is a non-exhaustive overview of the main smart contracts involved in sfrxETH.
sfrxETH
A staked token version of frxETH that accrues staking rewards. The exchange rate of frxETH per sfrxETH increases over time as staking rewards are added to the vault.
- It’s a non-upgradable xERC4626 inheriting from a Solmate ERC4626 Vault contract.
- The exchange rate is obtained by calling the
pricePerShare()
function. Where the formula istotalAssets() / total sfrxETH supply
. totalAssets()
is the sum ofstoredTotalAssets
+lastRewardAmount_
, wherelastRewardAmount_
is distributed linearly during the rewards cycle. This cycle is a time period of seven days during which the exchange rate increases linearly, in order to make this process progressive and protect the system.- Any rewards accrued from staking ETH are sent to the Gnosis Safe address, converted to frxETH, and then transferred to the sfrxETH to account for rewards in the next cycle. There’s no limit to the amount of frxETH that can be added, but since the rewards are distributed linearly, this may reduce a rapid increase in the exchange rate within a short period of time, spreading it out over seven days.
- The principal interaction functions (mint, deposit, redeem, withdraw) have an
andSync
modifier that callssyncRewards()
when the reward cycle is completed.syncRewards()
function takes into account any additional frxETH injected into the Vault over its internal balance. The next reward value is calculated asasset.balanceOf(address(this)) - storedTotalAssets_ - lastRewardAmount_
. Then thestoredTotalAssets_
is incremented with thelastRewardAmount_
, and thelastRewardAmount_
becomes thenextRewards
.
frxETH
A token pegged to ETH, not accrue staking rewards.
- It’s a non-upgradeable ERC20 contract controlled by a 3-of-5 Gnosis safe and a Timelock, control regulated in the
onlyByOwnGov()
modifier. - The functions
minter_mint()
andminter_burn_from()
are used for minting and burning frxETH. Both functions have anonlyMinters
modifier, which allows the frxETHMinter contract and the Gnosis safe to call them. - The Timelock and the Gnosis safe can add/remove minters, due to the previously mentioned
onlyByOwnGov()
modifier. - Mint/burn functions are not limited by a maximum amount, meaning authorised addresses can mint any amount of frxETH.
frxETHMinter
Contract to mint frxETH and sfrxETH from ETH.
- It’s a non-upgradeable contract controlled by a 3-of-5 Gnosis safe and a Timelock.
- frxETH is minted to the user who sends/deposits ETH in this contract.
- It’s possible to mint sfrxETH for ETH by calling the
submitAndDeposit()
function. - This contract also keeps track of all allowed validators added by the admins via the
addValidator()
function. - Whenever 32 ETH become available for staking, the
depositEther()
function is called (anyone can call it), and the ETH is sent to the ETH 2.0 deposit contract to be delegated to a validator (obtained by callinggetNextValidator()
). The contract restricts each validator to receive only 32 ETH.
FraxEtherRedemptionQueue
Contract for redeeming ETH from frxETH or sfrxETH.
- It’s a non-upgradeable contract controlled by the general Timelock.
- Users can send their frxETH at any time by calling the
enterRedemptionQueue()
function or srfxETH (via theenterRedemptionQueueViaSfrxEth()
function) for a redemption NFT, which adds the requested amount to the redemption queue. - The frxETH redemption queue waiting time is 11 days and can fetched in the
queueLengthSecs
variable by callingredemptionQueueState()
. - After the waiting time, users can redeem ETH by calling the
burnRedemptionTicketNft()
function.
Miscellaneous
- In its totality, the system has undergone one audit by Code4rena.
- The possibility of minting an unlimited amount of frxETH is quite dangerous. To reduce the risk, the Frax team has set the mint roles to a Timelock and the Frax Multisig. However, the Timelock admin and the Frax Multisig share three common signers, and this overlap undermines the security and independence of both systems. Generally, the community should be aware that important trust on signers of the system’s multi-sig is expected.
Conclusion
sfrxETH is an asset with good maturity in the market and no incident, however we believe the following points could be improved:
- Having access for both a timelock and multi-sig on the
onlyByOwnGov()
is problematic, as it makes possible to skip any timelock on a critical functionality like adding new minters. We recommend make this more strict to always respect the timelock. - Adding extra limitations for minting dynamics, for example having a maximum mint per period of time/blocks.
- Adding extra limitations for the amount of rewards that can be “injected” for a rewards cycle.
- Study the addition of higher multi-sig threshold, but prioritising on-chain protections like the previously mentioned.
- We believe at least an extra audit of the system apart for the existing Code4rena should be done.
Considering the criticality of ETH LSTs listings on Aave v3, our recommendation is for the community to wait until the previous points are addressed.