Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small gas optimization for burn/transfers/mint #334

Merged
merged 3 commits into from
Jun 13, 2022

Conversation

kadenzipfel
Copy link
Contributor

first commit:

  • saves 9 gas per burn
  • saves 3 gas per transfer
  • increases deployment cost but imo worth it

second commit:

  • saves 6*(quantity-1)-8 gas per mint
  • imo super worth the additional upfront cost

https://www.diffchecker.com/rYLkEpYd

@Vectorized
Copy link
Collaborator

Vectorized commented Jun 12, 2022

I think the burn and transfer parts shouldn't be in assembly. Gas savings not really worth the extra function.

Plus, it may make it harder to extend (e.g. for the storage hitchhiking PR #323 ).

Nice catch on the gas savings in the _mint loop.
I changed it to make it cheaper for single mints, but overlooked the increase for multiple mints.

Maybe we can consider using assembly for emitting the Transfer event in _mint.

uint256 end = startTokenId + quantity;

// Use assembly to save around 30+ gas per iteration.
assembly {
    // Emit the `Transfer` event.
    // The event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    log4(
        0, // Start of data. Zero, as no data.
        0, // End of data. Zero, as no data.
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, // Signature.
        0, // `address(0)`.
        to, // `to`.
        startTokenId // `tokenId`.
    )

    for {
        let tokenId := add(startTokenId, 1)
    } iszero(eq(tokenId, end)) {
        tokenId := add(tokenId, 1)
    } {
        log4(0, 0, 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0, to, tokenId)
    }
}

_currentIndex = end;

@kadenzipfel
Copy link
Contributor Author

kadenzipfel commented Jun 13, 2022

I think the burn and transfer parts shouldn't be in assembly. Gas savings not really worth the extra function.

if we're thinking in terms of overall costs, offsetting the deployment cost would only require ~500 transfers, ~166 burns or a combination of the two. for most collections, 500 transfers is trivial and thus imo super worth it

if we're thinking in terms of devex, imo it's much more readable to have the extra function describing the process

Plus, it may make it harder to extend (e.g. for the storage hitchhiking PR #323 ).

it's quite easy to extend actually and in the case of the storage hitchhiking PR the gas savings are even more significant (41 gas for burn, 6 gas for transfer)
see: https://github.com/kadenzipfel/ERC721A/blob/d69b41f83614db42ec9dec97ce3a8d68cebfb843/contracts/ERC721A.sol#L569
https://www.diffchecker.com/xUhWcd6r

Maybe we can consider using assembly for emitting the Transfer event in _mint.

+1

contracts/ERC721A.sol Outdated Show resolved Hide resolved
@cygaar
Copy link
Collaborator

cygaar commented Jun 13, 2022

Renamed the PR to be more descriptive

@cygaar cygaar changed the title gas golfing round 2 Small gas optimization for burn/transfers/mint Jun 13, 2022
@kadenzipfel
Copy link
Contributor Author

updated gas savings: https://www.diffchecker.com/BS9LslEP

@kadenzipfel kadenzipfel requested a review from Vectorized June 13, 2022 14:54
Copy link
Collaborator

@Vectorized Vectorized left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Vectorized Vectorized merged commit ad0722c into chiru-labs:main Jun 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants