Platform: Code4rena
Start Date: 29/06/2022
Pot Size: $50,000 USDC
Total HM: 20
Participants: 133
Period: 5 days
Judge: hickuphh3
Total Solo HM: 1
Id: 142
League: ETH
Rank: 77/133
Findings: 2
Award: $68.30
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: xiaoming90
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xSolus, 0xf15ers, 0xsanson, AmitN, Bnke0x0, BowTiedWardens, Chom, David_, ElKu, Funen, GalloDaSballo, GimelSec, Hawkeye, IllIllI, JC, JohnSmith, Kaiziron, Kenshin, Lambda, Limbooo, MadWookie, Metatron, MiloTruck, Nethermind, Picodes, ReyAdmirado, Sneakyninja0129, StErMi, TomJ, Treasure-Seeker, TrungOre, Waze, Yiko, _Adam, __141345__, antonttc, async, aysha, catchup, cccz, cryptphi, csanuragjain, danb, datapunk, defsec, delfin454000, dirk_y, doddle0x, durianSausage, exd0tpy, fatherOfBlocks, gogo, hake, hansfriese, horsefacts, hubble, itsmeSTYJ, joestakey, oyc_109, pedroais, peritoflores, rajatbeladiya, reassor, robee, rokinot, samruna, saneryee, sashik_eth, shenwilly, shung, simon135, sseefried, unforgiven, zer0dot, zzzitron
47.1303 USDC - $47.13
@return The domain seperator used when calculating the eip-712 hash.
Change seperator
to separator
utils/cryptography/draft-EIP712.sol: L94
* keccak256("Mail(address to,string contents)"),
Change to,string
to to, string
// Inspired by OraclizeAPI's implementation - MIT licence
Change licence
to License
whitelist
in both comments and codeTerms incorporating "white," "black," "master" or "slave" are potentially problematic. Substituting more neutral terminology is becoming common practice
address[] whitelist;
Suggestion: Change whitelist
to allowlist
Similarly for the following instances of 'whitelist' and its variants:
🌟 Selected for report: GalloDaSballo
Also found by: 0v3rf10w, 0x1f8b, 0xA5DF, 0xDjango, 0xHarry, 0xKitsune, 0xNazgul, 0xNineDec, 0xc0ffEE, 0xf15ers, 0xkatana, 0xsanson, ACai, Aymen0909, Bnke0x0, BowTiedWardens, Chom, ElKu, Fitraldys, Funen, Haruxe, Hawkeye, IllIllI, JC, JohnSmith, Kaiziron, Kenshin, Lambda, Limbooo, MadWookie, Metatron, MiloTruck, Picodes, PwnedNoMore, Randyyy, RedOneN, ReyAdmirado, Ruhum, Sm4rty, StErMi, StyxRave, TerrierLover, TomJ, Tomio, UnusualTurtle, Waze, Yiko, _Adam, __141345__, ajtra, ak1, apostle0x01, asutorufos, c3phas, cRat1st0s, catchup, codetilda, cryptphi, datapunk, defsec, delfin454000, durianSausage, exd0tpy, fatherOfBlocks, gogo, grrwahrr, hake, hansfriese, horsefacts, ignacio, jayfromthe13th, joestakey, ladboy233, m_Rassska, mektigboy, minhquanym, mrpathfindr, natzuu, oyc_109, rajatbeladiya, reassor, rfa, robee, rokinot, sach1r0, saian, sashik_eth, simon135, slywaters, swit, z3s, zeesaw, zer0dot
21.1707 USDC - $21.17
Require
revert string is too longThe revert string below can be shortened to 32 characters or fewer (as shown) to save gas
require(newOwner != address(0), "Ownable: new owner is the zero address");
Change message to Ownable: new owner is 0 address
!= 0
instead of > 0
in a require
statement if variable is an unsigned integer!= 0
should be used where possible since > 0
costs more gas
require(order.baseAsset.code.length > 0, "baseAsset is not contract");
Change order.baseAsset.code.length > 0
to order.baseAsset.code.length != 0
require(token.code.length > 0, "ERC20: Token is not contract");
Change token.code.length > 0
to token.code.length != 0
require(tokenAmount > 0, "ERC20: Amount too small");
Change tokenAmount > 0
to tokenAmount != 0
For example, initializing uint
variables to their default value of 0
is unnecessary and costs gas
uint256 feeAmount = 0;
Change to uint256 feeAmount;
uint256 length = 0;
Change to uint256 length;
The for
loop counter i
is initialized unnecessarily to zero in the 10 loops referenced below:
Example (src/PuttyV2.sol: L556-558):
for (uint256 i = 0; i < orders.length; i++) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Change uint256 i = 0;
to uint256 i;
in all cases
for
loopSince calculating the array length costs gas, it's best to read the length of the array from memory before executing the loop
for (uint256 i = 0; i < orders.length; i++) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Suggestion:
uint256 totalOrdersLength = orders.length; for (uint256 i = 0; i < totalOrdersLength; i++) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Similarly for the additional nine for
loops referenced below:
Note that I will provide an example at the end of this section that combines all the gas-saving recommendations pertaining tofor
loops
i++
instead of i++
to increase count in a for
loopSince use of i++
(or equivalent counter) costs more gas, it is better to use ++i
for (uint256 i = 0; i < orders.length; i++) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Suggestion:
for (uint256 i = 0; i < orders.length; ++i) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Similarly for the nine additional for
loops referenced below:
for
loopUnder/overflow checks are made every time i++
(or ++i
) is called. Such checks are unnecessary since i
is already limited. Therefore, use unchecked{++i}
/unchecked{i++}
instead
for (uint256 i = 0; i < orders.length; i++) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Suggestion:
for (uint256 i = 0; i < orders.length;) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); unchecked{ i++; } }
Similarly for the nine additional for
loops referenced below:
For
loop gas optimization exampleWhile, for presentation purposes, I have separated the for
loop-related gas savings methods, they should be combined. Below I show how all four of the gas saving methods outlined in this submission can be implemented together.
i
) to zero++i
rather than i++
unchecked
++i
for (uint256 i = 0; i < orders.length; i++) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); }
Recommendation:
uint256 totalOrdersLength = orders.length; for (uint256 i; i < totalOrdersLength; ++i) { positionIds[i] = fillOrder(orders[i], signatures[i], floorAssetTokenIds[i]); unchecked{ ++i; } }
uints
or ints
smaller than 32 bytes, if possibleStorage of uints or ints smaller than 32 bytes incurs overhead. Instead, use size of at least 32, then downcast where needed
uint8 private constant _ADDRESS_LENGTH = 20;