Skip to content

Commit

Permalink
Small gas optimization for burn/transfers/mint (#334)
Browse files Browse the repository at this point in the history
* Use assembly to pack ownership data

* Remove memvar from loop

* Consolidate packOwnershipData functions
  • Loading branch information
kadenzipfel authored Jun 13, 2022
1 parent ddc060e commit ad0722c
Showing 1 changed file with 20 additions and 16 deletions.
36 changes: 20 additions & 16 deletions contracts/ERC721A.sol
Original file line number Diff line number Diff line change
@@ -265,6 +265,16 @@ contract ERC721A is IERC721A {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}

/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 value) {
assembly {
// `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`.
value := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}

/**
* @dev See {IERC721-ownerOf}.
*/
@@ -489,15 +499,16 @@ contract ERC721A is IERC721A {
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] =
_addressToUint256(to) |
(block.timestamp << BITPOS_START_TIMESTAMP) |
(_boolToUint256(quantity == 1) << BITPOS_NEXT_INITIALIZED);
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_boolToUint256(quantity == 1) << BITPOS_NEXT_INITIALIZED
);

uint256 offset;
uint256 offset = startTokenId;
uint256 end = quantity + startTokenId;
do {
emit Transfer(address(0), to, startTokenId + offset++);
} while (offset < quantity);
emit Transfer(address(0), to, offset++);
} while (offset < end);

_currentIndex = startTokenId + quantity;
}
@@ -552,10 +563,7 @@ contract ERC721A is IERC721A {
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] =
_addressToUint256(to) |
(block.timestamp << BITPOS_START_TIMESTAMP) |
BITMASK_NEXT_INITIALIZED;
_packedOwnerships[tokenId] = _packOwnershipData(to, BITMASK_NEXT_INITIALIZED);

// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) {
@@ -630,11 +638,7 @@ contract ERC721A is IERC721A {
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] =
_addressToUint256(from) |
(block.timestamp << BITPOS_START_TIMESTAMP) |
BITMASK_BURNED |
BITMASK_NEXT_INITIALIZED;
_packedOwnerships[tokenId] = _packOwnershipData(from, BITMASK_BURNED | BITMASK_NEXT_INITIALIZED);

// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) {

0 comments on commit ad0722c

Please sign in to comment.