From 408e21c8b9365151bd0d6ce9936e8d143a2e60ff Mon Sep 17 00:00:00 2001 From: kadenzipfel Date: Sun, 12 Jun 2022 12:56:54 -0700 Subject: [PATCH 1/3] Use assembly to pack ownership data --- contracts/ERC721A.sol | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/contracts/ERC721A.sol b/contracts/ERC721A.sol index e4bdd4e38..c79fb1ab7 100644 --- a/contracts/ERC721A.sol +++ b/contracts/ERC721A.sol @@ -552,10 +552,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] = _packTransferOwnershipData(to); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { @@ -575,6 +572,15 @@ contract ERC721A is IERC721A { _afterTokenTransfers(from, to, tokenId, 1); } + /** + * @dev Packs ownership data into single uint + */ + function _packTransferOwnershipData(address to) private view returns (uint256 packedData) { + assembly { + packedData := or(to, or(shl(BITPOS_START_TIMESTAMP, timestamp()), BITMASK_NEXT_INITIALIZED)) + } + } + /** * @dev Equivalent to `_burn(tokenId, false)`. */ @@ -630,11 +636,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] = _packBurnOwnershipData(from); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { @@ -659,6 +661,18 @@ contract ERC721A is IERC721A { } } + /** + * @dev Packs ownership data into single uint + */ + function _packBurnOwnershipData(address from) private view returns (uint256 packedData) { + assembly { + packedData := or( + from, + or(shl(BITPOS_START_TIMESTAMP, timestamp()), or(BITMASK_BURNED, BITMASK_NEXT_INITIALIZED)) + ) + } + } + /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. * From aae31c58621b8acceee713ad10c089226ca11e16 Mon Sep 17 00:00:00 2001 From: kadenzipfel Date: Sun, 12 Jun 2022 13:22:14 -0700 Subject: [PATCH 2/3] Remove memvar from loop --- contracts/ERC721A.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/ERC721A.sol b/contracts/ERC721A.sol index c79fb1ab7..9940c5497 100644 --- a/contracts/ERC721A.sol +++ b/contracts/ERC721A.sol @@ -494,10 +494,11 @@ contract ERC721A is IERC721A { (block.timestamp << BITPOS_START_TIMESTAMP) | (_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; } From 5d63ec215cc7d2f6aff28e1c5e125a76c3e0bbf4 Mon Sep 17 00:00:00 2001 From: kadenzipfel Date: Mon, 13 Jun 2022 07:50:56 -0700 Subject: [PATCH 3/3] Consolidate packOwnershipData functions --- contracts/ERC721A.sol | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/contracts/ERC721A.sol b/contracts/ERC721A.sol index 9940c5497..54b9ee108 100644 --- a/contracts/ERC721A.sol +++ b/contracts/ERC721A.sol @@ -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,10 +499,10 @@ 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 = startTokenId; uint256 end = quantity + startTokenId; @@ -553,7 +563,7 @@ contract ERC721A is IERC721A { // - `startTimestamp` to the timestamp of transfering. // - `burned` to `false`. // - `nextInitialized` to `true`. - _packedOwnerships[tokenId] = _packTransferOwnershipData(to); + _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) { @@ -573,15 +583,6 @@ contract ERC721A is IERC721A { _afterTokenTransfers(from, to, tokenId, 1); } - /** - * @dev Packs ownership data into single uint - */ - function _packTransferOwnershipData(address to) private view returns (uint256 packedData) { - assembly { - packedData := or(to, or(shl(BITPOS_START_TIMESTAMP, timestamp()), BITMASK_NEXT_INITIALIZED)) - } - } - /** * @dev Equivalent to `_burn(tokenId, false)`. */ @@ -637,7 +638,7 @@ contract ERC721A is IERC721A { // - `startTimestamp` to the timestamp of burning. // - `burned` to `true`. // - `nextInitialized` to `true`. - _packedOwnerships[tokenId] = _packBurnOwnershipData(from); + _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) { @@ -662,18 +663,6 @@ contract ERC721A is IERC721A { } } - /** - * @dev Packs ownership data into single uint - */ - function _packBurnOwnershipData(address from) private view returns (uint256 packedData) { - assembly { - packedData := or( - from, - or(shl(BITPOS_START_TIMESTAMP, timestamp()), or(BITMASK_BURNED, BITMASK_NEXT_INITIALIZED)) - ) - } - } - /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. *