Platform: Code4rena
Start Date: 08/11/2022
Pot Size: $60,500 USDC
Total HM: 6
Participants: 72
Period: 5 days
Judge: Picodes
Total Solo HM: 2
Id: 178
League: ETH
Rank: 35/72
Findings: 1
Award: $80.83
🌟 Selected for report: 0
🚀 Solo Findings: 0
80.8321 USDC - $80.83
Issue | Instances | |
---|---|---|
1 | Variables inside struct should be packed to save gas | 1 |
2 | storage pointer to a struct is cheaper that copying each value of the struct into memory , same apply for array and mapping | 1 |
struct
should be packed to save gas :As the solidity EVM works with 32 bytes, variables less than 32 bytes should be packed inside a struct so that they can be stored in the same slot, each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings.
There is 1 instance of this issue:
File: contracts/libraries/OrderStructs.sol Line 14-15
struct BasicOrder { address signer; // The order's maker address collection; // The address of the ERC721/ERC1155 token to be purchased CollectionType collectionType; // 0 for ERC721, 1 for ERC1155 uint256[] tokenIds; // The IDs of the tokens to be purchased uint256[] amounts; // Always 1 when ERC721, can be > 1 if ERC1155 uint256 price; // The *taker bid* price to pay for the order address currency; // The order's currency, address(0) for ETH uint256 startTime; // The timestamp when the order starts becoming valid uint256 endTime; // The timestamp when the order stops becoming valid bytes signature; // split to v,r,s for LooksRare }
As the variables startTime
and endTime
can't really overflow 2^64, their values should be packed to save gas, the struct should be modified as follow :
struct BasicOrder { address signer; // The order's maker address collection; // The address of the ERC721/ERC1155 token to be purchased CollectionType collectionType; // 0 for ERC721, 1 for ERC1155 uint256[] tokenIds; // The IDs of the tokens to be purchased uint256[] amounts; // Always 1 when ERC721, can be > 1 if ERC1155 uint256 price; // The *taker bid* price to pay for the order address currency; // The order's currency, address(0) for ETH uint64 startTime; // The timestamp when the order starts becoming valid uint64 endTime; // The timestamp when the order stops becoming valid bytes signature; // split to v,r,s for LooksRare }
storage
pointer to a struct
is cheaper that copying each value of the struct into memory
, same apply for array and mapping :It may not be obvious, but every time you copy a storage
struct/array/mapping to a memory
variable, you are copying each member by reading it from storage
, which is expensive. And when you use the storage
keyword, you are just storing a pointer to the storage
, which is much cheaper. Exception: case when you need to read all or many members multiple times. In report included only cases that saved gas.
There is 1 instance of this issue:
File: contracts/LooksRareAggregator.sol Line 227
FeeData memory feeData = _proxyFeeData[singleTradeData.proxy];
#0 - Picodes
2022-11-21T18:14:32Z
2-invalid as both values are read
#1 - c4-judge
2022-11-21T18:15:03Z
Picodes marked the issue as grade-b
#2 - c4-sponsor
2022-11-24T18:27:22Z
0xhiroshi marked the issue as sponsor disputed