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: 15/133
Findings: 2
Award: $405.87
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: cccz
Also found by: Trust, rotcivegaf, wagmi
393.0581 USDC - $393.06
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.
Consider the scenario
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.
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.
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
🌟 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.8108 USDC - $12.81
Id | Title |
---|---|
1 | Redundant zero initialization |
2 | Short require strings save gas |
3 | Use != 0 instead of > 0 |
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;
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
!= 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