Frax Ether Liquid Staking contest - wagmi'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: 15/133

Findings: 2

Award: $405.87

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: cccz

Also found by: Trust, rotcivegaf, wagmi

Labels

bug
duplicate
2 (Med Risk)
old-submission-method
mintWithSignature slippage

Awards

393.0581 USDC - $393.06

External Links

Lines of code

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/sfrxETH.sol#L84

Vulnerability details

Impact

Function sfrxETH.mintWithSignature() allows users to approve and mint in one transaction. Users will provide input param shares and function will calculate what assets amount needed to be approved (in case approveMax = false).

uint256 amount = approveMax ? type(uint256).max : previewMint(shares);
asset.permit(msg.sender, address(this), amount, deadline, v, r, s);
return (mint(shares, receiver));

It used previewMint() of ERC4626 to calculate amount from shares input param. Users need to sign a message with this amount value off-chain.

But since in design, the exchange rate of sfrxETH will increase linearly over time (every second), there is no way users can calculate the exact value of amount from share off-chain. For example, users calculate amount = X given shares = Y off-chain and sign amount = X. But when transaction is executed, the exchange rate is changed, amount > X given shares = Y.

The result is user’s signature invalid and cannot be executed.

Proof of Concept

Consider the scenario

  1. Alice wants to approve and mint 100 sfrxETH in 1 transaction. She got the exchange rate from the contract 1 frxETH = 1 sfrxETH. So she signs amount = 100 to approve 100 frxETH. Note that Alice doesn’t want to approve max since it’s more risky and not recommended from her expert crypto friends.

  2. She sends the transaction and waits for it to be executed. But by the time it’s executed, the exchange rate is updated 1.1 frxETH = 1 sfrxETH, which means if she wants to mint 100 sfrxETH she needs to approve 110 frxETH. So her transaction is reverted.

Tools Used

Manual Review

Consider add 1 more input param amount in mintWithSignature() function. Or only allow users to approve max.

#0 - FortisFortuna

2022-09-25T23:37:17Z

Technically correct, though in practice, we will allow user-defined slippage on the UI

#1 - FortisFortuna

2022-09-27T01:04:56Z

#2 - 0xean

2022-10-12T16:58:20Z

closing as dupe of #35

Summary

IdTitle
1Redundant zero initialization
2Short require strings save gas
3Use != 0 instead of > 0

1. Redundant zero initialization

Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.

There are several places where an int is initialized to zero, which looks like:

withholdRatio = 0;

Affected Codes

2. Short require strings save gas

Strings in solidity are handled in 32 byte chunks. A require string longer than 32 bytes uses more gas. Shortening these strings will save gas.

One cases of this gas optimization was found 35 chars https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L167

3. Use != 0 instead of > 0

Using > 0 uses slightly more gas than using != 0. Use != 0 when comparing uint variables to zero, which cannot hold values below zero

Affected Codes

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