@bannynet/core-v6 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +53 -0
  2. package/SKILLS.md +94 -0
  3. package/deployments/banny-core-v5/arbitrum/Banny721TokenUriResolver.json +1809 -0
  4. package/deployments/banny-core-v5/arbitrum_sepolia/Banny721TokenUriResolver.json +1795 -0
  5. package/deployments/banny-core-v5/base/Banny721TokenUriResolver.json +1810 -0
  6. package/deployments/banny-core-v5/base_sepolia/Banny721TokenUriResolver.json +1796 -0
  7. package/deployments/banny-core-v5/ethereum/Banny721TokenUriResolver.json +1795 -0
  8. package/deployments/banny-core-v5/optimism/Banny721TokenUriResolver.json +1810 -0
  9. package/deployments/banny-core-v5/optimism_sepolia/Banny721TokenUriResolver.json +1796 -0
  10. package/deployments/banny-core-v5/sepolia/Banny721TokenUriResolver.json +1795 -0
  11. package/foundry.toml +22 -0
  12. package/package.json +53 -0
  13. package/remappings.txt +1 -0
  14. package/script/1.Fix.s.sol +290 -0
  15. package/script/Add.Denver.s.sol +75 -0
  16. package/script/AirdropOutfits.s.sol +2302 -0
  17. package/script/Deploy.s.sol +440 -0
  18. package/script/Drop1.s.sol +979 -0
  19. package/script/MigrationContractArbitrum.sol +494 -0
  20. package/script/MigrationContractArbitrum1.sol +170 -0
  21. package/script/MigrationContractArbitrum2.sol +204 -0
  22. package/script/MigrationContractArbitrum3.sol +174 -0
  23. package/script/MigrationContractArbitrum4.sol +478 -0
  24. package/script/MigrationContractBase1.sol +444 -0
  25. package/script/MigrationContractBase2.sol +175 -0
  26. package/script/MigrationContractBase3.sol +309 -0
  27. package/script/MigrationContractBase4.sol +350 -0
  28. package/script/MigrationContractBase5.sol +259 -0
  29. package/script/MigrationContractEthereum1.sol +468 -0
  30. package/script/MigrationContractEthereum2.sol +306 -0
  31. package/script/MigrationContractEthereum3.sol +349 -0
  32. package/script/MigrationContractEthereum4.sol +352 -0
  33. package/script/MigrationContractEthereum5.sol +354 -0
  34. package/script/MigrationContractEthereum6.sol +270 -0
  35. package/script/MigrationContractEthereum7.sol +439 -0
  36. package/script/MigrationContractEthereum8.sol +385 -0
  37. package/script/MigrationContractOptimism.sol +196 -0
  38. package/script/helpers/BannyverseDeploymentLib.sol +73 -0
  39. package/script/helpers/MigrationHelper.sol +155 -0
  40. package/script/outfit_drop/generate-migration.js +3441 -0
  41. package/script/outfit_drop/raw.json +43276 -0
  42. package/slither-ci.config.json +10 -0
  43. package/sphinx.lock +521 -0
  44. package/src/Banny721TokenUriResolver.sol +1288 -0
  45. package/src/interfaces/IBanny721TokenUriResolver.sol +137 -0
  46. package/test/Banny721TokenUriResolver.t.sol +669 -0
  47. package/test/BannyAttacks.t.sol +322 -0
  48. package/test/DecorateFlow.t.sol +1056 -0
@@ -0,0 +1,468 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
5
+ import {JB721TiersHook} from "@bananapus/721-hook-v5/src/JB721TiersHook.sol";
6
+ import {Banny721TokenUriResolver} from "../src/Banny721TokenUriResolver.sol";
7
+ import {MigrationHelper} from "./helpers/MigrationHelper.sol";
8
+
9
+ contract MigrationContractEthereum1 {
10
+ // Define struct to hold all UPC minted tokenIds
11
+ struct MintedIds {
12
+ uint256[1] upc1;
13
+ uint256[6] upc2;
14
+ uint256[13] upc3;
15
+ uint256[3] upc5;
16
+ uint256[3] upc6;
17
+ uint256[2] upc7;
18
+ uint256[1] upc10;
19
+ uint256[2] upc14;
20
+ uint256[1] upc17;
21
+ uint256[1] upc18;
22
+ uint256[3] upc19;
23
+ uint256[1] upc21;
24
+ uint256[1] upc23;
25
+ uint256[1] upc25;
26
+ uint256[3] upc26;
27
+ uint256[2] upc31;
28
+ uint256[2] upc32;
29
+ uint256[4] upc35;
30
+ uint256[1] upc37;
31
+ uint256[1] upc39;
32
+ uint256[3] upc43;
33
+ uint256[2] upc44;
34
+ uint256[1] upc46;
35
+ uint256[1] upc47;
36
+ uint256[1] upc48;
37
+ }
38
+
39
+ address[] private transferOwners;
40
+
41
+ constructor(address[] memory _transferOwners) {
42
+ transferOwners = _transferOwners;
43
+ }
44
+
45
+ function executeMigration(
46
+ address hookAddress,
47
+ address resolverAddress,
48
+ address v4HookAddress,
49
+ address v4ResolverAddress,
50
+ address fallbackV4ResolverAddress
51
+ )
52
+ external
53
+ {
54
+ // Validate addresses
55
+ require(hookAddress != address(0), "Hook address not set");
56
+ require(resolverAddress != address(0), "Resolver address not set");
57
+ require(v4HookAddress != address(0), "V4 Hook address not set");
58
+ require(v4ResolverAddress != address(0), "V4 Resolver address not set");
59
+ require(fallbackV4ResolverAddress != address(0), "V4 fallback resolver address not set");
60
+
61
+ JB721TiersHook hook = JB721TiersHook(hookAddress);
62
+ Banny721TokenUriResolver resolver = Banny721TokenUriResolver(resolverAddress);
63
+ IERC721 v4Hook = IERC721(v4HookAddress);
64
+ Banny721TokenUriResolver v4Resolver = Banny721TokenUriResolver(v4ResolverAddress);
65
+ Banny721TokenUriResolver fallbackV4Resolver = Banny721TokenUriResolver(fallbackV4ResolverAddress);
66
+
67
+ // Ethereum migration chunk 1/6 - 60 items
68
+
69
+ // Step 1: Assets are already minted to this contract by the deployer
70
+
71
+ // Assets are already minted to this contract by the deployer
72
+
73
+ // Create and populate the struct
74
+ // Token IDs follow formula: upc * 1000000000 + unitNumber (unitNumber starts at 1 per UPC)
75
+ MintedIds memory sortedMintedIds;
76
+
77
+ // Populate UPC 1 minted tokenIds (1 items)
78
+ sortedMintedIds.upc1[0] = 1_000_000_001; // Token ID: 1 * 1000000000 + 1
79
+ // Populate UPC 2 minted tokenIds (6 items)
80
+ sortedMintedIds.upc2[0] = 2_000_000_001; // Token ID: 2 * 1000000000 + 1
81
+ sortedMintedIds.upc2[1] = 2_000_000_002; // Token ID: 2 * 1000000000 + 2
82
+ sortedMintedIds.upc2[2] = 2_000_000_003; // Token ID: 2 * 1000000000 + 3
83
+ sortedMintedIds.upc2[3] = 2_000_000_004; // Token ID: 2 * 1000000000 + 4
84
+ sortedMintedIds.upc2[4] = 2_000_000_005; // Token ID: 2 * 1000000000 + 5
85
+ sortedMintedIds.upc2[5] = 2_000_000_006; // Token ID: 2 * 1000000000 + 6
86
+ // Populate UPC 3 minted tokenIds (13 items)
87
+ sortedMintedIds.upc3[0] = 3_000_000_001; // Token ID: 3 * 1000000000 + 1
88
+ sortedMintedIds.upc3[1] = 3_000_000_002; // Token ID: 3 * 1000000000 + 2
89
+ sortedMintedIds.upc3[2] = 3_000_000_003; // Token ID: 3 * 1000000000 + 3
90
+ sortedMintedIds.upc3[3] = 3_000_000_004; // Token ID: 3 * 1000000000 + 4
91
+ sortedMintedIds.upc3[4] = 3_000_000_005; // Token ID: 3 * 1000000000 + 5
92
+ sortedMintedIds.upc3[5] = 3_000_000_006; // Token ID: 3 * 1000000000 + 6
93
+ sortedMintedIds.upc3[6] = 3_000_000_007; // Token ID: 3 * 1000000000 + 7
94
+ sortedMintedIds.upc3[7] = 3_000_000_008; // Token ID: 3 * 1000000000 + 8
95
+ sortedMintedIds.upc3[8] = 3_000_000_009; // Token ID: 3 * 1000000000 + 9
96
+ sortedMintedIds.upc3[9] = 3_000_000_010; // Token ID: 3 * 1000000000 + 10
97
+ sortedMintedIds.upc3[10] = 3_000_000_011; // Token ID: 3 * 1000000000 + 11
98
+ sortedMintedIds.upc3[11] = 3_000_000_012; // Token ID: 3 * 1000000000 + 12
99
+ sortedMintedIds.upc3[12] = 3_000_000_013; // Token ID: 3 * 1000000000 + 13
100
+ // Populate UPC 5 minted tokenIds (3 items)
101
+ sortedMintedIds.upc5[0] = 5_000_000_001; // Token ID: 5 * 1000000000 + 1
102
+ sortedMintedIds.upc5[1] = 5_000_000_002; // Token ID: 5 * 1000000000 + 2
103
+ sortedMintedIds.upc5[2] = 5_000_000_003; // Token ID: 5 * 1000000000 + 3
104
+ // Populate UPC 6 minted tokenIds (3 items)
105
+ sortedMintedIds.upc6[0] = 6_000_000_001; // Token ID: 6 * 1000000000 + 1
106
+ sortedMintedIds.upc6[1] = 6_000_000_002; // Token ID: 6 * 1000000000 + 2
107
+ sortedMintedIds.upc6[2] = 6_000_000_003; // Token ID: 6 * 1000000000 + 3
108
+ // Populate UPC 7 minted tokenIds (2 items)
109
+ sortedMintedIds.upc7[0] = 7_000_000_001; // Token ID: 7 * 1000000000 + 1
110
+ sortedMintedIds.upc7[1] = 7_000_000_002; // Token ID: 7 * 1000000000 + 2
111
+ // Populate UPC 10 minted tokenIds (1 items)
112
+ sortedMintedIds.upc10[0] = 10_000_000_001; // Token ID: 10 * 1000000000 + 1
113
+ // Populate UPC 14 minted tokenIds (2 items)
114
+ sortedMintedIds.upc14[0] = 14_000_000_001; // Token ID: 14 * 1000000000 + 1
115
+ sortedMintedIds.upc14[1] = 14_000_000_002; // Token ID: 14 * 1000000000 + 2
116
+ // Populate UPC 17 minted tokenIds (1 items)
117
+ sortedMintedIds.upc17[0] = 17_000_000_001; // Token ID: 17 * 1000000000 + 1
118
+ // Populate UPC 18 minted tokenIds (1 items)
119
+ sortedMintedIds.upc18[0] = 18_000_000_001; // Token ID: 18 * 1000000000 + 1
120
+ // Populate UPC 19 minted tokenIds (3 items)
121
+ sortedMintedIds.upc19[0] = 19_000_000_001; // Token ID: 19 * 1000000000 + 1
122
+ sortedMintedIds.upc19[1] = 19_000_000_002; // Token ID: 19 * 1000000000 + 2
123
+ sortedMintedIds.upc19[2] = 19_000_000_003; // Token ID: 19 * 1000000000 + 3
124
+ // Populate UPC 21 minted tokenIds (1 items)
125
+ sortedMintedIds.upc21[0] = 21_000_000_001; // Token ID: 21 * 1000000000 + 1
126
+ // Populate UPC 23 minted tokenIds (1 items)
127
+ sortedMintedIds.upc23[0] = 23_000_000_001; // Token ID: 23 * 1000000000 + 1
128
+ // Populate UPC 25 minted tokenIds (1 items)
129
+ sortedMintedIds.upc25[0] = 25_000_000_001; // Token ID: 25 * 1000000000 + 1
130
+ // Populate UPC 26 minted tokenIds (3 items)
131
+ sortedMintedIds.upc26[0] = 26_000_000_001; // Token ID: 26 * 1000000000 + 1
132
+ sortedMintedIds.upc26[1] = 26_000_000_002; // Token ID: 26 * 1000000000 + 2
133
+ sortedMintedIds.upc26[2] = 26_000_000_003; // Token ID: 26 * 1000000000 + 3
134
+ // Populate UPC 31 minted tokenIds (2 items)
135
+ sortedMintedIds.upc31[0] = 31_000_000_001; // Token ID: 31 * 1000000000 + 1
136
+ sortedMintedIds.upc31[1] = 31_000_000_002; // Token ID: 31 * 1000000000 + 2
137
+ // Populate UPC 32 minted tokenIds (2 items)
138
+ sortedMintedIds.upc32[0] = 32_000_000_001; // Token ID: 32 * 1000000000 + 1
139
+ sortedMintedIds.upc32[1] = 32_000_000_002; // Token ID: 32 * 1000000000 + 2
140
+ // Populate UPC 35 minted tokenIds (4 items)
141
+ sortedMintedIds.upc35[0] = 35_000_000_001; // Token ID: 35 * 1000000000 + 1
142
+ sortedMintedIds.upc35[1] = 35_000_000_002; // Token ID: 35 * 1000000000 + 2
143
+ sortedMintedIds.upc35[2] = 35_000_000_003; // Token ID: 35 * 1000000000 + 3
144
+ sortedMintedIds.upc35[3] = 35_000_000_004; // Token ID: 35 * 1000000000 + 4
145
+ // Populate UPC 37 minted tokenIds (1 items)
146
+ sortedMintedIds.upc37[0] = 37_000_000_001; // Token ID: 37 * 1000000000 + 1
147
+ // Populate UPC 39 minted tokenIds (1 items)
148
+ sortedMintedIds.upc39[0] = 39_000_000_001; // Token ID: 39 * 1000000000 + 1
149
+ // Populate UPC 43 minted tokenIds (3 items)
150
+ sortedMintedIds.upc43[0] = 43_000_000_001; // Token ID: 43 * 1000000000 + 1
151
+ sortedMintedIds.upc43[1] = 43_000_000_002; // Token ID: 43 * 1000000000 + 2
152
+ sortedMintedIds.upc43[2] = 43_000_000_003; // Token ID: 43 * 1000000000 + 3
153
+ // Populate UPC 44 minted tokenIds (2 items)
154
+ sortedMintedIds.upc44[0] = 44_000_000_001; // Token ID: 44 * 1000000000 + 1
155
+ sortedMintedIds.upc44[1] = 44_000_000_002; // Token ID: 44 * 1000000000 + 2
156
+ // Populate UPC 46 minted tokenIds (1 items)
157
+ sortedMintedIds.upc46[0] = 46_000_000_001; // Token ID: 46 * 1000000000 + 1
158
+ // Populate UPC 47 minted tokenIds (1 items)
159
+ sortedMintedIds.upc47[0] = 47_000_000_001; // Token ID: 47 * 1000000000 + 1
160
+ // Populate UPC 48 minted tokenIds (1 items)
161
+ sortedMintedIds.upc48[0] = 48_000_000_001; // Token ID: 48 * 1000000000 + 1
162
+ // Step 1.5: Approve resolver to transfer all tokens owned by this contract
163
+ // The resolver needs approval to transfer outfits and backgrounds to itself during decoration
164
+ IERC721(address(hook)).setApprovalForAll(address(resolver), true);
165
+
166
+ // Step 2: Process each Banny body and dress them
167
+
168
+ // Dress Banny 1000000001 (Alien)
169
+ {
170
+ uint256[] memory outfitIds = new uint256[](4);
171
+ outfitIds[0] = 7_000_000_002; // V4: 7000000002 -> V5: 7000000002
172
+ outfitIds[1] = 17_000_000_001; // V4: 17000000001 -> V5: 17000000001
173
+ outfitIds[2] = 26_000_000_003; // V4: 26000000004 -> V5: 26000000003
174
+ outfitIds[3] = 46_000_000_001; // V4: 46000000001 -> V5: 46000000001
175
+
176
+ resolver.decorateBannyWith(address(hook), 1_000_000_001, 5_000_000_001, outfitIds);
177
+
178
+ MigrationHelper.verifyV4AssetMatch(
179
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 1_000_000_001
180
+ );
181
+ }
182
+
183
+ // Dress Banny 2000000002 (Pink)
184
+ {
185
+ uint256[] memory outfitIds = new uint256[](5);
186
+ outfitIds[0] = 7_000_000_001; // V4: 7000000001 -> V5: 7000000001
187
+ outfitIds[1] = 14_000_000_002; // V4: 14000000003 -> V5: 14000000002
188
+ outfitIds[2] = 19_000_000_002; // V4: 19000000012 -> V5: 19000000002
189
+ outfitIds[3] = 26_000_000_002; // V4: 26000000003 -> V5: 26000000002
190
+ outfitIds[4] = 35_000_000_004; // V4: 35000000006 -> V5: 35000000004
191
+
192
+ resolver.decorateBannyWith(address(hook), 2_000_000_002, 0, outfitIds);
193
+
194
+ MigrationHelper.verifyV4AssetMatch(
195
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 2_000_000_002
196
+ );
197
+ }
198
+
199
+ // Dress Banny 2000000004 (Pink)
200
+ {
201
+ uint256[] memory outfitIds = new uint256[](1);
202
+ outfitIds[0] = 18_000_000_001; // V4: 18000000002 -> V5: 18000000001
203
+
204
+ resolver.decorateBannyWith(address(hook), 2_000_000_004, 0, outfitIds);
205
+
206
+ MigrationHelper.verifyV4AssetMatch(
207
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 2_000_000_004
208
+ );
209
+ }
210
+
211
+ // Dress Banny 2000000005 (Pink)
212
+ {
213
+ uint256[] memory outfitIds = new uint256[](1);
214
+ outfitIds[0] = 21_000_000_001; // V4: 21000000001 -> V5: 21000000001
215
+
216
+ resolver.decorateBannyWith(address(hook), 2_000_000_005, 5_000_000_002, outfitIds);
217
+
218
+ MigrationHelper.verifyV4AssetMatch(
219
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 2_000_000_005
220
+ );
221
+ }
222
+
223
+ // Dress Banny 2000000006 (Pink)
224
+ {
225
+ uint256[] memory outfitIds = new uint256[](2);
226
+ outfitIds[0] = 19_000_000_003; // V4: 19000000019 -> V5: 19000000003
227
+ outfitIds[1] = 25_000_000_001; // V4: 25000000009 -> V5: 25000000001
228
+
229
+ resolver.decorateBannyWith(address(hook), 2_000_000_006, 5_000_000_003, outfitIds);
230
+
231
+ MigrationHelper.verifyV4AssetMatch(
232
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 2_000_000_006
233
+ );
234
+ }
235
+
236
+ // Dress Banny 3000000001 (Orange)
237
+ {
238
+ uint256[] memory outfitIds = new uint256[](3);
239
+ outfitIds[0] = 14_000_000_001; // V4: 14000000001 -> V5: 14000000001
240
+ outfitIds[1] = 26_000_000_001; // V4: 26000000001 -> V5: 26000000001
241
+ outfitIds[2] = 35_000_000_001; // V4: 35000000001 -> V5: 35000000001
242
+
243
+ resolver.decorateBannyWith(address(hook), 3_000_000_001, 6_000_000_001, outfitIds);
244
+
245
+ MigrationHelper.verifyV4AssetMatch(
246
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_001
247
+ );
248
+ }
249
+
250
+ // Dress Banny 3000000003 (Orange)
251
+ {
252
+ uint256[] memory outfitIds = new uint256[](2);
253
+ outfitIds[0] = 10_000_000_001; // V4: 10000000005 -> V5: 10000000001
254
+ outfitIds[1] = 44_000_000_001; // V4: 44000000003 -> V5: 44000000001
255
+
256
+ resolver.decorateBannyWith(address(hook), 3_000_000_003, 0, outfitIds);
257
+
258
+ MigrationHelper.verifyV4AssetMatch(
259
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_003
260
+ );
261
+ }
262
+
263
+ // Dress Banny 3000000006 (Orange)
264
+ {
265
+ uint256[] memory outfitIds = new uint256[](2);
266
+ outfitIds[0] = 32_000_000_001; // V4: 32000000001 -> V5: 32000000001
267
+ outfitIds[1] = 44_000_000_002; // V4: 44000000004 -> V5: 44000000002
268
+
269
+ resolver.decorateBannyWith(address(hook), 3_000_000_006, 0, outfitIds);
270
+
271
+ MigrationHelper.verifyV4AssetMatch(
272
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_006
273
+ );
274
+ }
275
+
276
+ // Dress Banny 3000000007 (Orange)
277
+ {
278
+ uint256[] memory outfitIds = new uint256[](2);
279
+ outfitIds[0] = 31_000_000_001; // V4: 31000000003 -> V5: 31000000001
280
+ outfitIds[1] = 47_000_000_001; // V4: 47000000003 -> V5: 47000000001
281
+
282
+ resolver.decorateBannyWith(address(hook), 3_000_000_007, 6_000_000_002, outfitIds);
283
+
284
+ MigrationHelper.verifyV4AssetMatch(
285
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_007
286
+ );
287
+ }
288
+
289
+ // Dress Banny 3000000009 (Orange)
290
+ {
291
+ uint256[] memory outfitIds = new uint256[](2);
292
+ outfitIds[0] = 35_000_000_002; // V4: 35000000002 -> V5: 35000000002
293
+ outfitIds[1] = 43_000_000_001; // V4: 43000000005 -> V5: 43000000001
294
+
295
+ resolver.decorateBannyWith(address(hook), 3_000_000_009, 0, outfitIds);
296
+
297
+ MigrationHelper.verifyV4AssetMatch(
298
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_009
299
+ );
300
+ }
301
+
302
+ // Dress Banny 3000000010 (Orange)
303
+ {
304
+ uint256[] memory outfitIds = new uint256[](3);
305
+ outfitIds[0] = 32_000_000_002; // V4: 32000000002 -> V5: 32000000002
306
+ outfitIds[1] = 35_000_000_003; // V4: 35000000004 -> V5: 35000000003
307
+ outfitIds[2] = 48_000_000_001; // V4: 48000000001 -> V5: 48000000001
308
+
309
+ resolver.decorateBannyWith(address(hook), 3_000_000_010, 6_000_000_003, outfitIds);
310
+
311
+ MigrationHelper.verifyV4AssetMatch(
312
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_010
313
+ );
314
+ }
315
+
316
+ // Dress Banny 3000000011 (Orange)
317
+ {
318
+ uint256[] memory outfitIds = new uint256[](3);
319
+ outfitIds[0] = 23_000_000_001; // V4: 23000000001 -> V5: 23000000001
320
+ outfitIds[1] = 39_000_000_001; // V4: 39000000001 -> V5: 39000000001
321
+ outfitIds[2] = 43_000_000_002; // V4: 43000000006 -> V5: 43000000002
322
+
323
+ resolver.decorateBannyWith(address(hook), 3_000_000_011, 0, outfitIds);
324
+
325
+ MigrationHelper.verifyV4AssetMatch(
326
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_011
327
+ );
328
+ }
329
+
330
+ // Dress Banny 3000000013 (Orange)
331
+ {
332
+ uint256[] memory outfitIds = new uint256[](4);
333
+ outfitIds[0] = 19_000_000_001; // V4: 19000000008 -> V5: 19000000001
334
+ outfitIds[1] = 31_000_000_002; // V4: 31000000006 -> V5: 31000000002
335
+ outfitIds[2] = 37_000_000_001; // V4: 37000000001 -> V5: 37000000001
336
+ outfitIds[3] = 43_000_000_003; // V4: 43000000007 -> V5: 43000000003
337
+
338
+ resolver.decorateBannyWith(address(hook), 3_000_000_013, 0, outfitIds);
339
+
340
+ MigrationHelper.verifyV4AssetMatch(
341
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_013
342
+ );
343
+ }
344
+
345
+ // Step 3: Transfer all assets to rightful owners using constructor data
346
+ // Generate token IDs in the same order as items appear (matching mint order)
347
+ // Token ID format: UPC * 1000000000 + unitNumber
348
+ // Note: Only banny body token IDs are guaranteed to match between V4 and V5.
349
+ // Outfits/backgrounds being worn by bannys may have different IDs, but that's OK
350
+ // since they're not transferred (only used in decorateBannyWith calls).
351
+ uint256[] memory generatedTokenIds = new uint256[](transferOwners.length);
352
+
353
+ generatedTokenIds[0] = 1_000_000_001; // Token ID (V4: 1000000001)
354
+ generatedTokenIds[1] = 2_000_000_001; // Token ID (V4: 2000000001)
355
+ generatedTokenIds[2] = 2_000_000_002; // Token ID (V4: 2000000002)
356
+ generatedTokenIds[3] = 2_000_000_003; // Token ID (V4: 2000000003)
357
+ generatedTokenIds[4] = 2_000_000_004; // Token ID (V4: 2000000004)
358
+ generatedTokenIds[5] = 2_000_000_005; // Token ID (V4: 2000000005)
359
+ generatedTokenIds[6] = 2_000_000_006; // Token ID (V4: 2000000006)
360
+ generatedTokenIds[7] = 3_000_000_001; // Token ID (V4: 3000000001)
361
+ generatedTokenIds[8] = 3_000_000_002; // Token ID (V4: 3000000002)
362
+ generatedTokenIds[9] = 3_000_000_003; // Token ID (V4: 3000000003)
363
+ generatedTokenIds[10] = 3_000_000_004; // Token ID (V4: 3000000004)
364
+ generatedTokenIds[11] = 3_000_000_005; // Token ID (V4: 3000000005)
365
+ generatedTokenIds[12] = 3_000_000_006; // Token ID (V4: 3000000006)
366
+ generatedTokenIds[13] = 3_000_000_007; // Token ID (V4: 3000000007)
367
+ generatedTokenIds[14] = 3_000_000_008; // Token ID (V4: 3000000008)
368
+ generatedTokenIds[15] = 3_000_000_009; // Token ID (V4: 3000000009)
369
+ generatedTokenIds[16] = 3_000_000_010; // Token ID (V4: 3000000010)
370
+ generatedTokenIds[17] = 3_000_000_011; // Token ID (V4: 3000000011)
371
+ generatedTokenIds[18] = 3_000_000_012; // Token ID (V4: 3000000012)
372
+ generatedTokenIds[19] = 3_000_000_013; // Token ID (V4: 3000000013)
373
+
374
+ uint256 successfulTransfers = 0;
375
+ uint256 skippedResolverOwned = 0;
376
+
377
+ for (uint256 i = 0; i < transferOwners.length; i++) {
378
+ uint256 tokenId = generatedTokenIds[i];
379
+ // Verify V4 ownership before transferring V5
380
+ address v4Owner = v4Hook.ownerOf(tokenId);
381
+ require(
382
+ v4Owner == transferOwners[i] || v4Owner == address(fallbackV4ResolverAddress),
383
+ "V4/V5 ownership mismatch for token"
384
+ );
385
+
386
+ // Skip transfer if V4 owner is the resolver (resolver holds these tokens, we shouldn't transfer to
387
+ // resolver)
388
+ if (v4Owner == address(v4ResolverAddress) || v4Owner == address(fallbackV4ResolverAddress)) {
389
+ // Token is held by resolver, skip transfer
390
+ skippedResolverOwned++;
391
+ continue;
392
+ }
393
+
394
+ IERC721(address(hook)).safeTransferFrom(address(this), transferOwners[i], tokenId);
395
+ successfulTransfers++;
396
+ }
397
+
398
+ // Verify all expected items were processed (transferred or skipped as expected)
399
+ require(successfulTransfers + skippedResolverOwned == transferOwners.length, "Not all items were processed");
400
+
401
+ // Final verification: Ensure this contract no longer owns any tokens
402
+ // This ensures all transfers completed successfully and no tokens were left behind
403
+ require(hook.balanceOf(address(this)) == 0, "Contract still owns tokens after migration");
404
+
405
+ // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
406
+
407
+ // // Collect unique owners
408
+ // address[] memory uniqueOwners = new address[](19);
409
+
410
+ // uniqueOwners[0] = 0xaECD6D9172d602b93dBA3981991268b44af8096e;
411
+ // uniqueOwners[1] = 0xA2Fa6144168751D116336B58C5288feaF8bb12C1;
412
+ // uniqueOwners[2] = 0x63A2368F4B509438ca90186cb1C15156713D5834;
413
+ // uniqueOwners[3] = 0x15b61e9b0637f45dc0858f083cd240267924125d;
414
+ // uniqueOwners[4] = 0x45C3d8Aacc0d537dAc234AD4C20Ef05d6041CeFe;
415
+ // uniqueOwners[5] = 0x5dee86b297755b3F2ce65e09BA3A700579A9020B;
416
+ // uniqueOwners[6] = 0x817738DC393d682Ca5fBb268707b99F2aAe96baE;
417
+ // uniqueOwners[7] = 0xa13d49fCbf79EAF6A0a58cBDD3361422DB4eAfF1;
418
+ // uniqueOwners[8] = 0x516cAfD745Ec780D20f61c0d71fe258eA765222D;
419
+ // uniqueOwners[9] = 0x126eeFa566ABF5aC3EfDAeF52d79E962CFFdB448;
420
+ // uniqueOwners[10] = 0x289715fFBB2f4b482e2917D2f183FeAb564ec84F;
421
+ // uniqueOwners[11] = 0x1C51517d8277C9aD6d701Fb5394ceC0C18219eDb;
422
+ // uniqueOwners[12] = 0x1786D033D5CbCC235B673e872c7613c2F83DA583;
423
+ // uniqueOwners[13] = 0x38EED3CCeED88f380E436eb21811250797c453C5;
424
+ // uniqueOwners[14] = 0xE16a238d207B9ac8B419C7A866b0De013c73357B;
425
+ // uniqueOwners[15] = 0x0b2c9E0ee3057f4B9b0c2e42894a3D5A9B32b5Af;
426
+ // uniqueOwners[16] = 0x0Cb1D93daEc77Df2ED7Db31C040Fd2174452bD9F;
427
+ // uniqueOwners[17] = 0xa9d20b435A85fAAa002f32d66F7D21564130E9cf;
428
+ // uniqueOwners[18] = 0x6a099Bb96DDF3963d5AddCAbDC0221914cF80b1F;
429
+
430
+ // // Collect unique tier IDs
431
+ // uint256[] memory uniqueTierIds = new uint256[](25);
432
+
433
+ // uniqueTierIds[0] = 1;
434
+ // uniqueTierIds[1] = 2;
435
+ // uniqueTierIds[2] = 3;
436
+ // uniqueTierIds[3] = 5;
437
+ // uniqueTierIds[4] = 6;
438
+ // uniqueTierIds[5] = 7;
439
+ // uniqueTierIds[6] = 10;
440
+ // uniqueTierIds[7] = 14;
441
+ // uniqueTierIds[8] = 17;
442
+ // uniqueTierIds[9] = 18;
443
+ // uniqueTierIds[10] = 19;
444
+ // uniqueTierIds[11] = 21;
445
+ // uniqueTierIds[12] = 23;
446
+ // uniqueTierIds[13] = 25;
447
+ // uniqueTierIds[14] = 26;
448
+ // uniqueTierIds[15] = 31;
449
+ // uniqueTierIds[16] = 32;
450
+ // uniqueTierIds[17] = 35;
451
+ // uniqueTierIds[18] = 37;
452
+ // uniqueTierIds[19] = 39;
453
+ // uniqueTierIds[20] = 43;
454
+ // uniqueTierIds[21] = 44;
455
+ // uniqueTierIds[22] = 46;
456
+ // uniqueTierIds[23] = 47;
457
+ // uniqueTierIds[24] = 48;
458
+
459
+ // // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
460
+ // MigrationHelper.verifyTierBalances(
461
+ // hookAddress,
462
+ // v4HookAddress,
463
+ // fallbackV4ResolverAddress,
464
+ // uniqueOwners,
465
+ // uniqueTierIds
466
+ // );
467
+ }
468
+ }