Open code423n4 opened 2 years ago
4.2k
This saves the keccak cost, at the cost of packing, so prob 20 gas
400 gas from SLAODs
We know shift wont' save gas (sponsor feedback) 3 gas from caching the other value
Prefix is 11 per instance = 33
Neat unique report, would recommend using bigger blocks for code, but really nice jbo!
4636
Decided to selectively implement some of them. Lots of clever and good optimizations but not all are worth the readability costs.
Gas Optimizations
UNREVEALED_URI
andBASE_URI
, which can't be changed, can be marked as immutable to save gas when accessing them.mapping(uint256 => mapping(address => mapping(uint256 => uint256))) public getCopiesOfArtGobbledByGobbler;
mapping can be changed to simplify it. We know the gobbler id will be maximum 10000, so it can fit in auint96
. That means that instead of mapping a gobbler id to an address of an nft, we can group them together and create the newmapping(uint256 => mapping(uint256 => uint256))) public getCopiesOfArtGobbledByGobbler;
, where the first uint256 is the gobbler id and the nft contract's address grouped ((gobblerId << 160) | nft
).toWadUnsafe(MAX_MINTABLE)
in theArtGobblers
contract pre deployment so it will save gas on deployment.Cache storage variables to reduce the number of SLOADs
legendaryGobblerAuctionData.numSold
,getGobblerData[id]
in theArtGobblers.mintLegendaryGobbler
ArtGobblers.legendaryGobblerPrice
instead of accessingnumMintedFromGoo
again (uint256 numMintedSinceStart = numMintedFromGoo - numMintedAtStart;
=>uint256 numMintedSinceStart = mintedFromGoo - numMintedAtStart;
)getGobblerData[swapId].idx
andgetGobblerData[currentId].idx
in theArtGobblers.revealGobblers
function. The optimized code:// Get the owner of the current id. address currentIdOwner = getGobblerData[currentId].owner;
// Get the index of the current id. idx = getGobblerData[currentId].idx; uint64 currentIndex = idx == 0 ? uint64(currentId) // Hasn't been shuffled before. : idx; // Shuffled before.
legendaryGobblerAuctionData.startPrice = uint120(cost <= LEGENDARY_GOBBLER_INITIAL_START_PRICE / 2 ? LEGENDARY_GOBBLER_INITIAL_START_PRICE : cost * 2);
in theArtGobblers.mintLegendaryGobbler
function by:cost <= LEGENDARY_GOBBLER_INITIAL_START_PRICE / 2
to2 * cost <= LEGENDARY_GOBBLER_INITIAL_START_PRICE
2 * cost
tocost << 1
cost << 1
instead of calculating it twice The final expression:ArtGobblers.mintLegendaryGobbler
function (getGobblerData[gobblerId].emissionMultiple = uint32(burnedMultipleTotal * 2)
=>getGobblerData[gobblerId].emissionMultiple = uint32(burnedMultipleTotal << 1)
)ArtGobblers.mintLegendaryGobbler
function -legendaryGobblerAuctionData.numSold += 1
=>++legendaryGobblerAuctionData.numSold
getUserData[from].gobblersOwned -= 1;
=>--getUserData[from].gobblersOwned;
getUserData[to].gobblersOwned += 1;
=>++getUserData[to].gobblersOwned;
FIRST_LEGENDARY_GOBBLER_ID - 1
in every iteration of the loop inArtGobblers.revealGobblers
& (2 ** 64 - 1)
instead of% 2 ** 64
. (randomSeed := mod(keccak256(0, 32), shl(64, 1))
=>randomSeed := and(keccak256(0, 32), 0xffffffffffffffff)
)newNumMintedForReserves > (numMintedFromGoo + newNumMintedForReserves) / 5
5 * newNumMintedForReserves > numMintedFromGoo + newNumMintedForReserves
4 * newNumMintedForReserves > numMintedFromGoo
(newNumMintedForReserves << 2) > numMintedFromGoo