Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized committed May 9, 2022
1 parent aed0402 commit 4ffb9b8
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 25 deletions.
51 changes: 26 additions & 25 deletions contracts/ERC721A.sol
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ contract ERC721A is Context, ERC165, IERC721A {
uint256 packed;
assembly {
// uint256(uint160(to)) | (block.timestamp << 160)
packed := or(to, shl(160, timestamp()))
packed := or(or(to, shl(160, timestamp())), shl(225, eq(quantity, 1)))
}
_packedOwnerships[startTokenId] = packed;
}
Expand Down Expand Up @@ -418,7 +418,7 @@ contract ERC721A is Context, ERC165, IERC721A {
uint256 packed;
assembly {
// uint256(uint160(to)) | (block.timestamp << 160)
packed := or(to, shl(160, timestamp()))
packed := or(or(to, shl(160, timestamp())), shl(225, eq(quantity, 1)))
}
_packedOwnerships[startTokenId] = packed;
}
Expand Down Expand Up @@ -477,23 +477,24 @@ contract ERC721A is Context, ERC165, IERC721A {
{ // Scoped for extra gas optimization.
uint256 packed;
assembly {
// uint256(uint160(to)) | (block.timestamp << 160)
packed := or(to, shl(160, timestamp()))
// uint256(uint160(to)) | (block.timestamp << 160) | (1 << 225)
packed := or(or(to, shl(160, timestamp())),
0x200000000000000000000000000000000000000000000000000000000)
}
_packedOwnerships[tokenId] = packed;
}

// If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
uint256 nextTokenId = tokenId + 1;
uint256 packedNextSlot = _packedOwnerships[nextTokenId];
// We can directly check the entire packed slot.
if (packedNextSlot == 0) {
// This will suffice for checking _exists(nextTokenId),
// as a burned slot cannot contain the zero address.
if (nextTokenId != _currentIndex) {
// Set the `addr` = `from`, and `startTimestamp` = `prevOwnership.startTimestamp`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
if (prevOwnershipPacked & (1 << 225) == 0) {
uint256 nextTokenId = tokenId + 1;
if (_packedOwnerships[nextTokenId] == 0) {
// This will suffice for checking _exists(nextTokenId),
// as a burned slot cannot contain the zero address.
if (nextTokenId != _currentIndex) {
// Set the `addr` = `from`, and `startTimestamp` = `prevOwnership.startTimestamp`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
Expand Down Expand Up @@ -549,24 +550,24 @@ contract ERC721A is Context, ERC165, IERC721A {
assembly {
// Keep track of the previous owner, the timestamp of burning.
// Also sets `burned` to `true`.
// uint256(uint160(from)) | (block.timestamp << 160) | (1 << 224)
// uint256(uint160(from)) | (block.timestamp << 160) | (1 << 224) | (1 << 225)
packed := or(or(from, shl(160, timestamp())),
0x100000000000000000000000000000000000000000000000000000000)
0x300000000000000000000000000000000000000000000000000000000)
}
_packedOwnerships[tokenId] = packed;
}

// If the ownership slot of tokenId+1 is not explicitly set, that means the burn initiator owns it.
// If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
uint256 nextTokenId = tokenId + 1;
uint256 packedNextSlot = _packedOwnerships[nextTokenId];
// We can directly check the entire packed slot.
if (packedNextSlot == 0) {
// This will suffice for checking _exists(nextTokenId),
// as a burned slot cannot contain the zero address.
if (nextTokenId != _currentIndex) {
// Set the `addr` = `from`, and `startTimestamp` = `prevOwnership.startTimestamp`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
if (prevOwnershipPacked & (1 << 225) == 0) {
uint256 nextTokenId = tokenId + 1;
if (_packedOwnerships[nextTokenId] == 0) {
// This will suffice for checking _exists(nextTokenId),
// as a burned slot cannot contain the zero address.
if (nextTokenId != _currentIndex) {
// Set the `addr` = `from`, and `startTimestamp` = `prevOwnership.startTimestamp`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions test/GasUsage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,15 @@ describe('ERC721A Gas Usage', function () {
}
});
});

context('transferFrom', function () {
it('transfer to and fro', async function () {
await this.erc721a.mintTen(this.addr1.address);
await this.erc721a.mintTen(this.owner.address);
for (let i = 0; i < 10; ++i) {
await this.erc721a.connect(this.addr1).transferFrom(this.addr1.address, this.owner.address, 1);
await this.erc721a.connect(this.owner).transferFrom(this.owner.address, this.addr1.address, 1);
}
});
});
});

0 comments on commit 4ffb9b8

Please sign in to comment.