@@ -14,9 +14,11 @@ function toSingleton(address account) pure returns (address[] memory) {
14
14
}
15
15
16
16
contract ERC721ConsecutiveTarget is StdUtils , ERC721Consecutive {
17
+ uint96 private immutable _offset;
17
18
uint256 public totalMinted = 0 ;
18
19
19
- constructor (address [] memory receivers , uint256 [] memory batches ) ERC721 ("" , "" ) {
20
+ constructor (address [] memory receivers , uint256 [] memory batches , uint256 startingId ) ERC721 ("" , "" ) {
21
+ _offset = uint96 (startingId);
20
22
for (uint256 i = 0 ; i < batches.length ; i++ ) {
21
23
address receiver = receivers[i % receivers.length ];
22
24
uint96 batchSize = uint96 (bound (batches[i], 0 , _maxBatchSize ()));
@@ -28,43 +30,71 @@ contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive {
28
30
function burn (uint256 tokenId ) public {
29
31
_burn (tokenId);
30
32
}
33
+
34
+ function _firstConsecutiveId () internal view virtual override returns (uint96 ) {
35
+ return _offset;
36
+ }
31
37
}
32
38
33
39
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 {
35
41
vm.assume (receiver != address (0 ));
36
42
37
- ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches);
43
+ uint256 startingTokenId = bound (startingId, 0 , 5000 );
44
+
45
+ ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches, startingTokenId);
38
46
39
47
assertEq (token.balanceOf (receiver), token.totalMinted ());
40
48
}
41
49
42
- function test_ownership (address receiver , uint256 [] calldata batches , uint256 [2 ] calldata unboundedTokenId ) public {
50
+ function test_ownership (
51
+ address receiver ,
52
+ uint256 [] calldata batches ,
53
+ uint256 [2 ] calldata unboundedTokenId ,
54
+ uint96 startingId
55
+ ) public {
43
56
vm.assume (receiver != address (0 ));
44
57
45
- ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches);
58
+ uint256 startingTokenId = bound (startingId, 0 , 5000 );
59
+
60
+ ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches, startingTokenId);
46
61
47
62
if (token.totalMinted () > 0 ) {
48
- uint256 validTokenId = bound (unboundedTokenId[0 ], 0 , token.totalMinted () - 1 );
63
+ uint256 validTokenId = bound (
64
+ unboundedTokenId[0 ],
65
+ startingTokenId,
66
+ startingTokenId + token.totalMinted () - 1
67
+ );
49
68
assertEq (token.ownerOf (validTokenId), receiver);
50
69
}
51
70
52
- uint256 invalidTokenId = bound (unboundedTokenId[1 ], token.totalMinted (), type (uint256 ).max);
71
+ uint256 invalidTokenId = bound (
72
+ unboundedTokenId[1 ],
73
+ startingTokenId + token.totalMinted (),
74
+ startingTokenId + token.totalMinted () + 1
75
+ );
53
76
vm.expectRevert ();
54
77
token.ownerOf (invalidTokenId);
55
78
}
56
79
57
- function test_burn (address receiver , uint256 [] calldata batches , uint256 unboundedTokenId ) public {
80
+ function test_burn (
81
+ address receiver ,
82
+ uint256 [] calldata batches ,
83
+ uint256 unboundedTokenId ,
84
+ uint96 startingId
85
+ ) public {
58
86
vm.assume (receiver != address (0 ));
59
87
60
- ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches);
88
+ uint256 startingTokenId = bound (startingId, 0 , 5000 );
89
+
90
+ ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches, startingTokenId);
61
91
62
92
// only test if we minted at least one token
63
93
uint256 supply = token.totalMinted ();
64
94
vm.assume (supply > 0 );
65
95
66
96
// burn a token in [0; supply[
67
- uint256 tokenId = bound (unboundedTokenId, 0 , supply - 1 );
97
+ uint256 tokenId = bound (unboundedTokenId, startingTokenId, startingTokenId + supply - 1 );
68
98
token.burn (tokenId);
69
99
70
100
// balance should have decreased
@@ -78,25 +108,28 @@ contract ERC721ConsecutiveTest is Test {
78
108
function test_transfer (
79
109
address [2 ] calldata accounts ,
80
110
uint256 [2 ] calldata unboundedBatches ,
81
- uint256 [2 ] calldata unboundedTokenId
111
+ uint256 [2 ] calldata unboundedTokenId ,
112
+ uint96 startingId
82
113
) public {
83
114
vm.assume (accounts[0 ] != address (0 ));
84
115
vm.assume (accounts[1 ] != address (0 ));
85
116
vm.assume (accounts[0 ] != accounts[1 ]);
86
117
118
+ uint256 startingTokenId = bound (startingId, 1 , 5000 );
119
+
87
120
address [] memory receivers = new address [](2 );
88
121
receivers[0 ] = accounts[0 ];
89
122
receivers[1 ] = accounts[1 ];
90
123
91
124
// We assume _maxBatchSize is 5000 (the default). This test will break otherwise.
92
125
uint256 [] memory batches = new uint256 [](2 );
93
- batches[0 ] = bound (unboundedBatches[0 ], 1 , 5000 );
94
- batches[1 ] = bound (unboundedBatches[1 ], 1 , 5000 );
126
+ batches[0 ] = bound (unboundedBatches[0 ], startingTokenId , 5000 );
127
+ batches[1 ] = bound (unboundedBatches[1 ], startingTokenId , 5000 );
95
128
96
- ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (receivers, batches);
129
+ ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (receivers, batches, startingTokenId );
97
130
98
- uint256 tokenId0 = bound (unboundedTokenId[0 ], 0 , batches[0 ] - 1 );
99
- uint256 tokenId1 = bound (unboundedTokenId[1 ], 0 , batches[1 ] - 1 ) + batches[0 ];
131
+ uint256 tokenId0 = bound (unboundedTokenId[0 ], startingTokenId , batches[0 ]);
132
+ uint256 tokenId1 = bound (unboundedTokenId[1 ], startingTokenId , batches[1 ]) + batches[0 ];
100
133
101
134
assertEq (token.ownerOf (tokenId0), accounts[0 ]);
102
135
assertEq (token.ownerOf (tokenId1), accounts[1 ]);
@@ -119,4 +152,29 @@ contract ERC721ConsecutiveTest is Test {
119
152
assertEq (token.balanceOf (accounts[0 ]), batches[0 ]);
120
153
assertEq (token.balanceOf (accounts[1 ]), batches[1 ]);
121
154
}
155
+
156
+ function test_start_consecutive_id (
157
+ address receiver ,
158
+ uint256 [2 ] calldata unboundedBatches ,
159
+ uint256 [2 ] calldata unboundedTokenId ,
160
+ uint96 startingId
161
+ ) public {
162
+ vm.assume (receiver != address (0 ));
163
+
164
+ uint256 startingTokenId = bound (startingId, 1 , 5000 );
165
+
166
+ // We assume _maxBatchSize is 5000 (the default). This test will break otherwise.
167
+ uint256 [] memory batches = new uint256 [](2 );
168
+ batches[0 ] = bound (unboundedBatches[0 ], startingTokenId, 5000 );
169
+ batches[1 ] = bound (unboundedBatches[1 ], startingTokenId, 5000 );
170
+
171
+ ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget (toSingleton (receiver), batches, startingTokenId);
172
+
173
+ uint256 tokenId0 = bound (unboundedTokenId[0 ], startingTokenId, batches[0 ]);
174
+ uint256 tokenId1 = bound (unboundedTokenId[1 ], startingTokenId, batches[1 ]);
175
+
176
+ assertEq (token.ownerOf (tokenId0), receiver);
177
+ assertEq (token.ownerOf (tokenId1), receiver);
178
+ assertEq (token.balanceOf (receiver), batches[0 ] + batches[1 ]);
179
+ }
122
180
}
0 commit comments