Skip to content

Commit b693f7f

Browse files
committed
first consecutive id
1 parent 4fb6833 commit b693f7f

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

contracts/token/ERC721/extensions/ERC721Consecutive.sol

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,13 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
141141
super._afterTokenTransfer(from, to, firstTokenId, batchSize);
142142
}
143143

144+
/**
145+
* @dev Used to offset the first token id in {_totalConsecutiveSupply}
146+
*/
147+
function _firstConsecutiveId() internal view virtual returns (uint96) { return 0; }
148+
144149
function _totalConsecutiveSupply() private view returns (uint96) {
145150
(bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint();
146-
return exists ? latestId + 1 : 0;
151+
return exists ? latestId + 1 : _firstConsecutiveId();
147152
}
148153
}

test/token/ERC721/extensions/ERC721Consecutive.t.sol

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ function toSingleton(address account) pure returns (address[] memory) {
1515

1616
contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive {
1717
uint256 public totalMinted = 0;
18+
uint96 public firstConsecutiveId = 0;
1819

19-
constructor(address[] memory receivers, uint256[] memory batches) ERC721("", "") {
20+
constructor(address[] memory receivers, uint256[] memory batches, uint96 startingId) ERC721("", "") {
21+
firstConsecutiveId = startingId;
2022
for (uint256 i = 0; i < batches.length; i++) {
2123
address receiver = receivers[i % receivers.length];
2224
uint96 batchSize = uint96(bound(batches[i], 0, _maxBatchSize()));
@@ -28,36 +30,43 @@ contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive {
2830
function burn(uint256 tokenId) public {
2931
_burn(tokenId);
3032
}
33+
34+
function _firstConsecutiveId() internal view virtual override returns (uint96) {
35+
return firstConsecutiveId;
36+
}
3137
}
3238

3339
contract ERC721ConsecutiveTest is Test {
34-
function test_balance(address receiver, uint256[] calldata batches) public {
40+
function test_balance(address receiver, uint256[] calldata batches, uint96 startingId) public {
3541
vm.assume(receiver != address(0));
42+
vm.assume(startingId < type(uint96).max - 5000);
3643

37-
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches);
44+
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingId);
3845

3946
assertEq(token.balanceOf(receiver), token.totalMinted());
4047
}
4148

42-
function test_ownership(address receiver, uint256[] calldata batches, uint256[2] calldata unboundedTokenId) public {
49+
function test_ownership(address receiver, uint256[] calldata batches, uint256[2] calldata unboundedTokenId, uint96 startingId) public {
4350
vm.assume(receiver != address(0));
51+
vm.assume(startingId < type(uint96).max - 5000);
4452

45-
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches);
53+
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingId);
4654

4755
if (token.totalMinted() > 0) {
48-
uint256 validTokenId = bound(unboundedTokenId[0], 0, token.totalMinted() - 1);
56+
uint256 validTokenId = bound(unboundedTokenId[0], startingId, startingId + token.totalMinted() - 1);
4957
assertEq(token.ownerOf(validTokenId), receiver);
5058
}
5159

52-
uint256 invalidTokenId = bound(unboundedTokenId[1], token.totalMinted(), type(uint256).max);
60+
uint256 invalidTokenId = bound(unboundedTokenId[1], startingId + token.totalMinted(), startingId + token.totalMinted() + 1);
5361
vm.expectRevert();
5462
token.ownerOf(invalidTokenId);
5563
}
5664

57-
function test_burn(address receiver, uint256[] calldata batches, uint256 unboundedTokenId) public {
65+
function test_burn(address receiver, uint256[] calldata batches, uint256 unboundedTokenId, uint96 startingId) public {
5866
vm.assume(receiver != address(0));
67+
vm.assume(startingId < type(uint96).max - 5000);
5968

60-
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches);
69+
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingId);
6170

6271
// only test if we minted at least one token
6372
uint256 supply = token.totalMinted();
@@ -93,7 +102,7 @@ contract ERC721ConsecutiveTest is Test {
93102
batches[0] = bound(unboundedBatches[0], 1, 5000);
94103
batches[1] = bound(unboundedBatches[1], 1, 5000);
95104

96-
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(receivers, batches);
105+
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(receivers, batches, 0);
97106

98107
uint256 tokenId0 = bound(unboundedTokenId[0], 0, batches[0] - 1);
99108
uint256 tokenId1 = bound(unboundedTokenId[1], 0, batches[1] - 1) + batches[0];
@@ -119,4 +128,28 @@ contract ERC721ConsecutiveTest is Test {
119128
assertEq(token.balanceOf(accounts[0]), batches[0]);
120129
assertEq(token.balanceOf(accounts[1]), batches[1]);
121130
}
131+
132+
function test_start_consecutive_id(
133+
address receiver,
134+
uint256[2] calldata unboundedBatches,
135+
uint256[2] calldata unboundedTokenId,
136+
uint96 startingId
137+
) public {
138+
vm.assume(receiver != address(0));
139+
uint256 startingTokenId = bound(startingId, 1, 5000);
140+
141+
// We assume _maxBatchSize is 5000 (the default). This test will break otherwise.
142+
uint256[] memory batches = new uint256[](2);
143+
batches[0] = bound(unboundedBatches[0], startingTokenId, 5000);
144+
batches[1] = bound(unboundedBatches[1], startingTokenId, 5000);
145+
146+
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, uint96(startingTokenId));
147+
148+
uint256 tokenId0 = bound(unboundedTokenId[0], startingTokenId, batches[0]);
149+
uint256 tokenId1 = bound(unboundedTokenId[1], startingTokenId, batches[1]);
150+
151+
assertEq(token.ownerOf(tokenId0), receiver);
152+
assertEq(token.ownerOf(tokenId1), receiver);
153+
assertEq(token.balanceOf(receiver), batches[0] + batches[1]);
154+
}
122155
}

0 commit comments

Comments
 (0)