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: 109/133
Findings: 1
Award: $21.18
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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.1794 USDC - $21.18
Caching will replace each SLOAD (100 gas) with a much cheaper stack read.
cache weth
:
PuttyV2.sol::fillOrder() 327,17: if (weth == order.baseAsset && msg.value > 0) { 335,23: IWETH(weth).deposit{value: msg.value}(); 336,23: IWETH(weth).transfer(order.maker, msg.value); 351,17: if (weth == order.baseAsset && msg.value > 0) { 358,18: IWETH(weth).deposit{value: msg.value}();
PuttyV2.sol::exercise() 427,17: if (weth == order.baseAsset && msg.value > 0) { 434,18: IWETH(weth).deposit{value: msg.value}();
cache fee
:
PuttyV2.sol 498,17: if (fee > 0) { 499,45: feeAmount = (order.strike * fee) / 1000;
++i
is cheaper than i++
:actually it's important in iterations.
It's better to use unchecked { ++i; }
PuttyV2.sol 556,39: for (uint256 i = 0; i < orders.length; i++) { 594,39: for (uint256 i = 0; i < assets.length; i++) { 611,39: for (uint256 i = 0; i < assets.length; i++) { 627,44: for (uint256 i = 0; i < floorTokens.length; i++) { 637,39: for (uint256 i = 0; i < assets.length; i++) { 647,39: for (uint256 i = 0; i < assets.length; i++) { 658,44: for (uint256 i = 0; i < floorTokens.length; i++) { 670,42: for (uint256 i = 0; i < whitelist.length; i++) { 728,36: for (uint256 i = 0; i < arr.length; i++) { 742,36: for (uint256 i = 0; i < arr.length; i++) {
uint256
default value is 0
so we can remove = 0
for saving some gas:PuttyV2.sol 497,31: uint256 feeAmount = 0; 556,24: for (uint256 i = 0; i < orders.length; i++) { 594,24: for (uint256 i = 0; i < assets.length; i++) { 611,24: for (uint256 i = 0; i < assets.length; i++) { 627,24: for (uint256 i = 0; i < floorTokens.length; i++) { 637,24: for (uint256 i = 0; i < assets.length; i++) { 647,24: for (uint256 i = 0; i < assets.length; i++) { 658,24: for (uint256 i = 0; i < floorTokens.length; i++) { 670,24: for (uint256 i = 0; i < whitelist.length; i++) { 728,24: for (uint256 i = 0; i < arr.length; i++) { 742,24: for (uint256 i = 0; i < arr.length; i++) {
<array>.length
:Even memory arrays incur the overhead of bit tests and bit shifts to calculate the array length.
PuttyV2.sol 556,39: for (uint256 i = 0; i < orders.length; i++) { 594,39: for (uint256 i = 0; i < assets.length; i++) { 611,39: for (uint256 i = 0; i < assets.length; i++) { 627,44: for (uint256 i = 0; i < floorTokens.length; i++) { 637,39: for (uint256 i = 0; i < assets.length; i++) { 647,39: for (uint256 i = 0; i < assets.length; i++) { 658,44: for (uint256 i = 0; i < floorTokens.length; i++) { 670,42: for (uint256 i = 0; i < whitelist.length; i++) { 728,36: for (uint256 i = 0; i < arr.length; i++) { 742,36: for (uint256 i = 0; i < arr.length; i++) {
constant
values such as a call to keccak256()
, should use immutable
rather than constant
:See this issue for a detail description of the issue
PuttyV2.sol 90,9: keccak256(abi.encodePacked("ERC721Asset(address token,uint256 tokenId)")); 96,9: keccak256(abi.encodePacked("ERC20Asset(address token,uint256 tokenAmount)")); 102,9: keccak256(
Custom errors from Solidity 0.8.4 are cheaper than require
messages.
https://blog.soliditylang.org/2021/04/21/custom-errors/
PuttyV2.sol 214,9: require(_weth != address(0), "Unset weth address"); 241,9: require(_fee < 30, "fee must be less than 3%"); 278,9: require(SignatureChecker.isValidSignatureNow(order.maker, orderHash, signature), "Invalid signature"); 281,9: require(!cancelledOrders[orderHash], "Order has been cancelled"); 284,9: require(order.whitelist.length == 0 || isWhitelisted(order.whitelist, msg.sender), "Not whitelisted"); 287,9: require(order.duration < 10_000 days, "Duration too long"); 290,9: require(block.timestamp < order.expiration, "Order has expired"); 293,9: require(order.baseAsset.code.length > 0, "baseAsset is not contract"); 297,15: ? require(floorAssetTokenIds.length == order.floorTokens.length, "Wrong amount of floor tokenIds") 298,15: : require(floorAssetTokenIds.length == 0, "Invalid floor tokens length"); 329,17: require(msg.value == order.premium, "Incorrect ETH amount sent"); 353,17: require(msg.value == order.strike, "Incorrect ETH amount sent"); 395,9: require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner"); 398,9: require(order.isLong, "Can only exercise long positions"); 401,9: require(block.timestamp < positionExpirations[uint256(orderHash)], "Position has expired"); 405,15: ? require(floorAssetTokenIds.length == order.floorTokens.length, "Wrong amount of floor tokenIds") 406,15: : require(floorAssetTokenIds.length == 0, "Invalid floor tokenIds length"); 429,17: require(msg.value == order.strike, "Incorrect ETH amount sent"); 470,9: require(!order.isLong, "Must be short position"); 475,9: require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner"); 481,9: require(block.timestamp > positionExpirations[longPositionId] || isExercised, "Must be exercised or expired"); 527,9: require(msg.sender == order.maker, "Not your order"); 551,9: require(orders.length == signatures.length, "Length mismatch in input"); 552,9: require(signatures.length == floorAssetTokenIds.length, "Length mismatch in input"); 598,13: require(token.code.length > 0, "ERC20: Token is not contract"); 599,13: require(tokenAmount > 0, "ERC20: Amount too small"); 765,9: require(_ownerOf[id] != address(0), "URI query for NOT_MINTED token"); PuttyV2Nft.sol 12,9: require(to != address(0), "INVALID_RECIPIENT"); 13,9: require(_ownerOf[id] == address(0), "ALREADY_MINTED"); 26,9: require(from == _ownerOf[id], "WRONG_FROM"); 27,9: require(to != address(0), "INVALID_RECIPIENT"); 28,9: require( 41,9: require(owner != address(0), "ZERO_ADDRESS");