@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,494 @@
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 MigrationContractArbitrum {
10
+ // Define struct to hold all UPC minted tokenIds
11
+ struct MintedIds {
12
+ uint256[2] upc3;
13
+ uint256[9] upc4;
14
+ uint256[3] upc5;
15
+ uint256[1] upc6;
16
+ uint256[2] upc10;
17
+ uint256[1] upc11;
18
+ uint256[4] upc19;
19
+ uint256[2] upc20;
20
+ uint256[1] upc25;
21
+ uint256[2] upc28;
22
+ uint256[2] upc31;
23
+ uint256[1] upc32;
24
+ uint256[1] upc38;
25
+ uint256[1] upc39;
26
+ uint256[1] upc43;
27
+ uint256[27] upc47;
28
+ uint256[145] upc49;
29
+ }
30
+
31
+ address[] private transferOwners;
32
+
33
+ constructor(address[] memory _transferOwners) {
34
+ transferOwners = _transferOwners;
35
+ }
36
+
37
+ function executeMigration(
38
+ address hookAddress,
39
+ address resolverAddress,
40
+ address v4HookAddress,
41
+ address v4ResolverAddress,
42
+ address fallbackV4ResolverAddress
43
+ )
44
+ external
45
+ {
46
+ // Validate addresses
47
+ require(hookAddress != address(0), "Hook address not set");
48
+ require(resolverAddress != address(0), "Resolver address not set");
49
+ require(v4HookAddress != address(0), "V4 Hook address not set");
50
+ require(v4ResolverAddress != address(0), "V4 Resolver address not set");
51
+ require(fallbackV4ResolverAddress != address(0), "V4 fallback resolver address not set");
52
+
53
+ JB721TiersHook hook = JB721TiersHook(hookAddress);
54
+ Banny721TokenUriResolver resolver = Banny721TokenUriResolver(resolverAddress);
55
+ IERC721 v4Hook = IERC721(v4HookAddress);
56
+ Banny721TokenUriResolver v4Resolver = Banny721TokenUriResolver(v4ResolverAddress);
57
+ Banny721TokenUriResolver fallbackV4Resolver = Banny721TokenUriResolver(fallbackV4ResolverAddress);
58
+
59
+ // Arbitrum migration - 205 items
60
+
61
+ // Step 1: Assets are already minted to this contract by the deployer
62
+
63
+ // Assets are already minted to this contract by the deployer
64
+
65
+ // Create and populate the struct
66
+ // Token IDs are generated as: UPC * 1000000000 + unitNumber (where unitNumber starts at 1)
67
+ MintedIds memory sortedMintedIds;
68
+
69
+ // Populate UPC 3 minted tokenIds (2 items)
70
+ for (uint256 i = 0; i < 2; i++) {
71
+ sortedMintedIds.upc3[i] = 3 * 1_000_000_000 + (i + 1);
72
+ }
73
+ // Populate UPC 4 minted tokenIds (9 items)
74
+ for (uint256 i = 0; i < 9; i++) {
75
+ sortedMintedIds.upc4[i] = 4 * 1_000_000_000 + (i + 1);
76
+ }
77
+ // Populate UPC 5 minted tokenIds (3 items)
78
+ for (uint256 i = 0; i < 3; i++) {
79
+ sortedMintedIds.upc5[i] = 5 * 1_000_000_000 + (i + 1);
80
+ }
81
+ // Populate UPC 6 minted tokenIds (1 items)
82
+ for (uint256 i = 0; i < 1; i++) {
83
+ sortedMintedIds.upc6[i] = 6 * 1_000_000_000 + (i + 1);
84
+ }
85
+ // Populate UPC 10 minted tokenIds (2 items)
86
+ for (uint256 i = 0; i < 2; i++) {
87
+ sortedMintedIds.upc10[i] = 10 * 1_000_000_000 + (i + 1);
88
+ }
89
+ // Populate UPC 11 minted tokenIds (1 items)
90
+ for (uint256 i = 0; i < 1; i++) {
91
+ sortedMintedIds.upc11[i] = 11 * 1_000_000_000 + (i + 1);
92
+ }
93
+ // Populate UPC 19 minted tokenIds (4 items)
94
+ for (uint256 i = 0; i < 4; i++) {
95
+ sortedMintedIds.upc19[i] = 19 * 1_000_000_000 + (i + 1);
96
+ }
97
+ // Populate UPC 20 minted tokenIds (2 items)
98
+ for (uint256 i = 0; i < 2; i++) {
99
+ sortedMintedIds.upc20[i] = 20 * 1_000_000_000 + (i + 1);
100
+ }
101
+ // Populate UPC 25 minted tokenIds (1 items)
102
+ for (uint256 i = 0; i < 1; i++) {
103
+ sortedMintedIds.upc25[i] = 25 * 1_000_000_000 + (i + 1);
104
+ }
105
+ // Populate UPC 28 minted tokenIds (2 items)
106
+ for (uint256 i = 0; i < 2; i++) {
107
+ sortedMintedIds.upc28[i] = 28 * 1_000_000_000 + (i + 1);
108
+ }
109
+ // Populate UPC 31 minted tokenIds (2 items)
110
+ for (uint256 i = 0; i < 2; i++) {
111
+ sortedMintedIds.upc31[i] = 31 * 1_000_000_000 + (i + 1);
112
+ }
113
+ // Populate UPC 32 minted tokenIds (1 items)
114
+ for (uint256 i = 0; i < 1; i++) {
115
+ sortedMintedIds.upc32[i] = 32 * 1_000_000_000 + (i + 1);
116
+ }
117
+ // Populate UPC 38 minted tokenIds (1 items)
118
+ for (uint256 i = 0; i < 1; i++) {
119
+ sortedMintedIds.upc38[i] = 38 * 1_000_000_000 + (i + 1);
120
+ }
121
+ // Populate UPC 39 minted tokenIds (1 items)
122
+ for (uint256 i = 0; i < 1; i++) {
123
+ sortedMintedIds.upc39[i] = 39 * 1_000_000_000 + (i + 1);
124
+ }
125
+ // Populate UPC 43 minted tokenIds (1 items)
126
+ for (uint256 i = 0; i < 1; i++) {
127
+ sortedMintedIds.upc43[i] = 43 * 1_000_000_000 + (i + 1);
128
+ }
129
+ // Populate UPC 47 minted tokenIds (27 items)
130
+ for (uint256 i = 0; i < 27; i++) {
131
+ sortedMintedIds.upc47[i] = 47 * 1_000_000_000 + (i + 1);
132
+ }
133
+ // Populate UPC 49 minted tokenIds (145 items)
134
+ for (uint256 i = 0; i < 145; i++) {
135
+ sortedMintedIds.upc49[i] = 49 * 1_000_000_000 + (i + 1);
136
+ }
137
+ // Step 1.5: Approve resolver to transfer all tokens owned by this contract
138
+ // The resolver needs approval to transfer outfits and backgrounds to itself during decoration
139
+ IERC721(address(hook)).setApprovalForAll(address(resolver), true);
140
+
141
+ // Step 2: Process each Banny body and dress them
142
+
143
+ // Dress Banny 3000000001 (Orange)
144
+ {
145
+ uint256[] memory outfitIds = new uint256[](4);
146
+ outfitIds[0] = sortedMintedIds.upc19[0]; // V4: 19000000001 -> V5: sortedMintedIds.upc19[0]
147
+ outfitIds[1] = sortedMintedIds.upc25[0]; // V4: 25000000001 -> V5: sortedMintedIds.upc25[0]
148
+ outfitIds[2] = sortedMintedIds.upc38[0]; // V4: 38000000001 -> V5: sortedMintedIds.upc38[0]
149
+ outfitIds[3] = sortedMintedIds.upc47[0]; // V4: 47000000001 -> V5: sortedMintedIds.upc47[0]
150
+
151
+ resolver.decorateBannyWith(address(hook), 3_000_000_001, sortedMintedIds.upc5[0], outfitIds);
152
+
153
+ MigrationHelper.verifyV4AssetMatch(
154
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_001
155
+ );
156
+ }
157
+
158
+ // Dress Banny 4000000003 (Original)
159
+ {
160
+ uint256[] memory outfitIds = new uint256[](3);
161
+ outfitIds[0] = sortedMintedIds.upc11[0]; // V4: 11000000001 -> V5: sortedMintedIds.upc11[0]
162
+ outfitIds[1] = sortedMintedIds.upc19[2]; // V4: 19000000003 -> V5: sortedMintedIds.upc19[2]
163
+ outfitIds[2] = sortedMintedIds.upc28[0]; // V4: 28000000001 -> V5: sortedMintedIds.upc28[0]
164
+
165
+ resolver.decorateBannyWith(address(hook), 4_000_000_003, sortedMintedIds.upc6[0], outfitIds);
166
+
167
+ MigrationHelper.verifyV4AssetMatch(
168
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_003
169
+ );
170
+ }
171
+
172
+ // Dress Banny 4000000004 (Original)
173
+ {
174
+ uint256[] memory outfitIds = new uint256[](2);
175
+ outfitIds[0] = sortedMintedIds.upc10[0]; // V4: 10000000001 -> V5: sortedMintedIds.upc10[0]
176
+ outfitIds[1] = sortedMintedIds.upc20[0]; // V4: 20000000001 -> V5: sortedMintedIds.upc20[0]
177
+
178
+ resolver.decorateBannyWith(address(hook), 4_000_000_004, 0, outfitIds);
179
+
180
+ MigrationHelper.verifyV4AssetMatch(
181
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_004
182
+ );
183
+ }
184
+
185
+ // Dress Banny 4000000005 (Original)
186
+ {
187
+ uint256[] memory outfitIds = new uint256[](2);
188
+ outfitIds[0] = sortedMintedIds.upc31[0]; // V4: 31000000001 -> V5: sortedMintedIds.upc31[0]
189
+ outfitIds[1] = sortedMintedIds.upc49[1]; // V4: 49000000002 -> V5: sortedMintedIds.upc49[1]
190
+
191
+ resolver.decorateBannyWith(address(hook), 4_000_000_005, 0, outfitIds);
192
+
193
+ MigrationHelper.verifyV4AssetMatch(
194
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_005
195
+ );
196
+ }
197
+
198
+ // Dress Banny 4000000007 (Original)
199
+ {
200
+ uint256[] memory outfitIds = new uint256[](3);
201
+ outfitIds[0] = sortedMintedIds.upc10[1]; // V4: 10000000002 -> V5: sortedMintedIds.upc10[1]
202
+ outfitIds[1] = sortedMintedIds.upc20[1]; // V4: 20000000002 -> V5: sortedMintedIds.upc20[1]
203
+ outfitIds[2] = sortedMintedIds.upc43[0]; // V4: 43000000001 -> V5: sortedMintedIds.upc43[0]
204
+
205
+ resolver.decorateBannyWith(address(hook), 4_000_000_007, sortedMintedIds.upc5[1], outfitIds);
206
+
207
+ MigrationHelper.verifyV4AssetMatch(
208
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_007
209
+ );
210
+ }
211
+
212
+ // Dress Banny 4000000009 (Original)
213
+ {
214
+ uint256[] memory outfitIds = new uint256[](1);
215
+ outfitIds[0] = sortedMintedIds.upc28[1]; // V4: 28000000002 -> V5: sortedMintedIds.upc28[1]
216
+
217
+ resolver.decorateBannyWith(address(hook), 4_000_000_009, 0, outfitIds);
218
+
219
+ MigrationHelper.verifyV4AssetMatch(
220
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_009
221
+ );
222
+ }
223
+
224
+ // Step 3: Transfer all assets to rightful owners using constructor data
225
+ // Generate token IDs in the same order as items appear (matching mint order)
226
+ // Token ID format: UPC * 1000000000 + unitNumber
227
+ uint256[] memory generatedTokenIds = new uint256[](transferOwners.length);
228
+
229
+ generatedTokenIds[0] = 3_000_000_001; // Token ID (V4: 3000000001)
230
+ generatedTokenIds[1] = 3_000_000_002; // Token ID (V4: 3000000002)
231
+ generatedTokenIds[2] = 4_000_000_001; // Token ID (V4: 4000000001)
232
+ generatedTokenIds[3] = 4_000_000_002; // Token ID (V4: 4000000002)
233
+ generatedTokenIds[4] = 4_000_000_003; // Token ID (V4: 4000000003)
234
+ generatedTokenIds[5] = 4_000_000_004; // Token ID (V4: 4000000004)
235
+ generatedTokenIds[6] = 4_000_000_005; // Token ID (V4: 4000000005)
236
+ generatedTokenIds[7] = 4_000_000_006; // Token ID (V4: 4000000006)
237
+ generatedTokenIds[8] = 4_000_000_007; // Token ID (V4: 4000000007)
238
+ generatedTokenIds[9] = 4_000_000_008; // Token ID (V4: 4000000008)
239
+ generatedTokenIds[10] = 4_000_000_009; // Token ID (V4: 4000000009)
240
+ generatedTokenIds[11] = 19_000_000_002; // Token ID (V4: 19000000002)
241
+ generatedTokenIds[12] = 19_000_000_004; // Token ID (V4: 19000000004)
242
+ generatedTokenIds[13] = 31_000_000_002; // Token ID (V4: 31000000002)
243
+ generatedTokenIds[14] = 32_000_000_001; // Token ID (V4: 32000000001)
244
+ generatedTokenIds[15] = 39_000_000_001; // Token ID (V4: 39000000001)
245
+ generatedTokenIds[16] = 47_000_000_002; // Token ID (V4: 47000000002)
246
+ generatedTokenIds[17] = 47_000_000_003; // Token ID (V4: 47000000003)
247
+ generatedTokenIds[18] = 47_000_000_004; // Token ID (V4: 47000000004)
248
+ generatedTokenIds[19] = 47_000_000_005; // Token ID (V4: 47000000005)
249
+ generatedTokenIds[20] = 47_000_000_006; // Token ID (V4: 47000000006)
250
+ generatedTokenIds[21] = 47_000_000_007; // Token ID (V4: 47000000007)
251
+ generatedTokenIds[22] = 47_000_000_008; // Token ID (V4: 47000000008)
252
+ generatedTokenIds[23] = 47_000_000_009; // Token ID (V4: 47000000009)
253
+ generatedTokenIds[24] = 47_000_000_010; // Token ID (V4: 47000000010)
254
+ generatedTokenIds[25] = 47_000_000_011; // Token ID (V4: 47000000011)
255
+ generatedTokenIds[26] = 47_000_000_012; // Token ID (V4: 47000000012)
256
+ generatedTokenIds[27] = 47_000_000_013; // Token ID (V4: 47000000013)
257
+ generatedTokenIds[28] = 47_000_000_014; // Token ID (V4: 47000000014)
258
+ generatedTokenIds[29] = 47_000_000_015; // Token ID (V4: 47000000015)
259
+ generatedTokenIds[30] = 47_000_000_016; // Token ID (V4: 47000000016)
260
+ generatedTokenIds[31] = 47_000_000_017; // Token ID (V4: 47000000017)
261
+ generatedTokenIds[32] = 47_000_000_018; // Token ID (V4: 47000000018)
262
+ generatedTokenIds[33] = 47_000_000_019; // Token ID (V4: 47000000019)
263
+ generatedTokenIds[34] = 47_000_000_020; // Token ID (V4: 47000000020)
264
+ generatedTokenIds[35] = 47_000_000_021; // Token ID (V4: 47000000021)
265
+ generatedTokenIds[36] = 47_000_000_022; // Token ID (V4: 47000000022)
266
+ generatedTokenIds[37] = 47_000_000_023; // Token ID (V4: 47000000023)
267
+ generatedTokenIds[38] = 47_000_000_024; // Token ID (V4: 47000000024)
268
+ generatedTokenIds[39] = 47_000_000_025; // Token ID (V4: 47000000025)
269
+ generatedTokenIds[40] = 47_000_000_026; // Token ID (V4: 47000000026)
270
+ generatedTokenIds[41] = 47_000_000_027; // Token ID (V4: 47000000027)
271
+ generatedTokenIds[42] = 49_000_000_001; // Token ID (V4: 49000000001)
272
+ generatedTokenIds[43] = 49_000_000_003; // Token ID (V4: 49000000003)
273
+ generatedTokenIds[44] = 49_000_000_004; // Token ID (V4: 49000000004)
274
+ generatedTokenIds[45] = 49_000_000_005; // Token ID (V4: 49000000005)
275
+ generatedTokenIds[46] = 49_000_000_006; // Token ID (V4: 49000000006)
276
+ generatedTokenIds[47] = 49_000_000_007; // Token ID (V4: 49000000007)
277
+ generatedTokenIds[48] = 49_000_000_008; // Token ID (V4: 49000000008)
278
+ generatedTokenIds[49] = 49_000_000_009; // Token ID (V4: 49000000009)
279
+ generatedTokenIds[50] = 49_000_000_010; // Token ID (V4: 49000000010)
280
+ generatedTokenIds[51] = 49_000_000_011; // Token ID (V4: 49000000011)
281
+ generatedTokenIds[52] = 49_000_000_012; // Token ID (V4: 49000000012)
282
+ generatedTokenIds[53] = 49_000_000_013; // Token ID (V4: 49000000013)
283
+ generatedTokenIds[54] = 49_000_000_014; // Token ID (V4: 49000000014)
284
+ generatedTokenIds[55] = 49_000_000_015; // Token ID (V4: 49000000015)
285
+ generatedTokenIds[56] = 49_000_000_016; // Token ID (V4: 49000000016)
286
+ generatedTokenIds[57] = 49_000_000_017; // Token ID (V4: 49000000017)
287
+ generatedTokenIds[58] = 49_000_000_018; // Token ID (V4: 49000000018)
288
+ generatedTokenIds[59] = 49_000_000_019; // Token ID (V4: 49000000019)
289
+ generatedTokenIds[60] = 49_000_000_020; // Token ID (V4: 49000000020)
290
+ generatedTokenIds[61] = 49_000_000_021; // Token ID (V4: 49000000021)
291
+ generatedTokenIds[62] = 49_000_000_022; // Token ID (V4: 49000000022)
292
+ generatedTokenIds[63] = 49_000_000_023; // Token ID (V4: 49000000023)
293
+ generatedTokenIds[64] = 49_000_000_024; // Token ID (V4: 49000000024)
294
+ generatedTokenIds[65] = 49_000_000_025; // Token ID (V4: 49000000025)
295
+ generatedTokenIds[66] = 49_000_000_026; // Token ID (V4: 49000000026)
296
+ generatedTokenIds[67] = 49_000_000_027; // Token ID (V4: 49000000027)
297
+ generatedTokenIds[68] = 49_000_000_028; // Token ID (V4: 49000000028)
298
+ generatedTokenIds[69] = 49_000_000_029; // Token ID (V4: 49000000029)
299
+ generatedTokenIds[70] = 49_000_000_030; // Token ID (V4: 49000000030)
300
+ generatedTokenIds[71] = 49_000_000_031; // Token ID (V4: 49000000031)
301
+ generatedTokenIds[72] = 49_000_000_032; // Token ID (V4: 49000000032)
302
+ generatedTokenIds[73] = 49_000_000_033; // Token ID (V4: 49000000033)
303
+ generatedTokenIds[74] = 49_000_000_034; // Token ID (V4: 49000000034)
304
+ generatedTokenIds[75] = 49_000_000_035; // Token ID (V4: 49000000035)
305
+ generatedTokenIds[76] = 49_000_000_036; // Token ID (V4: 49000000036)
306
+ generatedTokenIds[77] = 49_000_000_037; // Token ID (V4: 49000000037)
307
+ generatedTokenIds[78] = 49_000_000_038; // Token ID (V4: 49000000038)
308
+ generatedTokenIds[79] = 49_000_000_039; // Token ID (V4: 49000000039)
309
+ generatedTokenIds[80] = 49_000_000_040; // Token ID (V4: 49000000040)
310
+ generatedTokenIds[81] = 49_000_000_041; // Token ID (V4: 49000000041)
311
+ generatedTokenIds[82] = 49_000_000_042; // Token ID (V4: 49000000042)
312
+ generatedTokenIds[83] = 49_000_000_043; // Token ID (V4: 49000000043)
313
+ generatedTokenIds[84] = 49_000_000_044; // Token ID (V4: 49000000044)
314
+ generatedTokenIds[85] = 49_000_000_045; // Token ID (V4: 49000000045)
315
+ generatedTokenIds[86] = 49_000_000_046; // Token ID (V4: 49000000046)
316
+ generatedTokenIds[87] = 49_000_000_047; // Token ID (V4: 49000000047)
317
+ generatedTokenIds[88] = 49_000_000_048; // Token ID (V4: 49000000048)
318
+ generatedTokenIds[89] = 49_000_000_049; // Token ID (V4: 49000000049)
319
+ generatedTokenIds[90] = 49_000_000_050; // Token ID (V4: 49000000050)
320
+ generatedTokenIds[91] = 49_000_000_051; // Token ID (V4: 49000000051)
321
+ generatedTokenIds[92] = 49_000_000_052; // Token ID (V4: 49000000052)
322
+ generatedTokenIds[93] = 49_000_000_053; // Token ID (V4: 49000000053)
323
+ generatedTokenIds[94] = 49_000_000_054; // Token ID (V4: 49000000054)
324
+ generatedTokenIds[95] = 49_000_000_055; // Token ID (V4: 49000000055)
325
+ generatedTokenIds[96] = 49_000_000_056; // Token ID (V4: 49000000056)
326
+ generatedTokenIds[97] = 49_000_000_057; // Token ID (V4: 49000000057)
327
+ generatedTokenIds[98] = 49_000_000_058; // Token ID (V4: 49000000058)
328
+ generatedTokenIds[99] = 49_000_000_059; // Token ID (V4: 49000000059)
329
+ generatedTokenIds[100] = 49_000_000_060; // Token ID (V4: 49000000060)
330
+ generatedTokenIds[101] = 49_000_000_061; // Token ID (V4: 49000000061)
331
+ generatedTokenIds[102] = 49_000_000_062; // Token ID (V4: 49000000062)
332
+ generatedTokenIds[103] = 49_000_000_063; // Token ID (V4: 49000000063)
333
+ generatedTokenIds[104] = 49_000_000_064; // Token ID (V4: 49000000064)
334
+ generatedTokenIds[105] = 49_000_000_065; // Token ID (V4: 49000000065)
335
+ generatedTokenIds[106] = 49_000_000_066; // Token ID (V4: 49000000066)
336
+ generatedTokenIds[107] = 49_000_000_067; // Token ID (V4: 49000000067)
337
+ generatedTokenIds[108] = 49_000_000_068; // Token ID (V4: 49000000068)
338
+ generatedTokenIds[109] = 49_000_000_069; // Token ID (V4: 49000000069)
339
+ generatedTokenIds[110] = 49_000_000_070; // Token ID (V4: 49000000070)
340
+ generatedTokenIds[111] = 49_000_000_071; // Token ID (V4: 49000000071)
341
+ generatedTokenIds[112] = 49_000_000_072; // Token ID (V4: 49000000072)
342
+ generatedTokenIds[113] = 49_000_000_073; // Token ID (V4: 49000000073)
343
+ generatedTokenIds[114] = 49_000_000_074; // Token ID (V4: 49000000074)
344
+ generatedTokenIds[115] = 49_000_000_075; // Token ID (V4: 49000000075)
345
+ generatedTokenIds[116] = 49_000_000_076; // Token ID (V4: 49000000076)
346
+ generatedTokenIds[117] = 49_000_000_077; // Token ID (V4: 49000000077)
347
+ generatedTokenIds[118] = 49_000_000_078; // Token ID (V4: 49000000078)
348
+ generatedTokenIds[119] = 49_000_000_079; // Token ID (V4: 49000000079)
349
+ generatedTokenIds[120] = 49_000_000_080; // Token ID (V4: 49000000080)
350
+ generatedTokenIds[121] = 49_000_000_081; // Token ID (V4: 49000000081)
351
+ generatedTokenIds[122] = 49_000_000_082; // Token ID (V4: 49000000082)
352
+ generatedTokenIds[123] = 49_000_000_083; // Token ID (V4: 49000000083)
353
+ generatedTokenIds[124] = 49_000_000_084; // Token ID (V4: 49000000084)
354
+ generatedTokenIds[125] = 49_000_000_085; // Token ID (V4: 49000000085)
355
+ generatedTokenIds[126] = 49_000_000_086; // Token ID (V4: 49000000086)
356
+ generatedTokenIds[127] = 49_000_000_087; // Token ID (V4: 49000000087)
357
+ generatedTokenIds[128] = 49_000_000_088; // Token ID (V4: 49000000088)
358
+ generatedTokenIds[129] = 49_000_000_089; // Token ID (V4: 49000000089)
359
+ generatedTokenIds[130] = 49_000_000_090; // Token ID (V4: 49000000090)
360
+ generatedTokenIds[131] = 49_000_000_091; // Token ID (V4: 49000000091)
361
+ generatedTokenIds[132] = 49_000_000_092; // Token ID (V4: 49000000092)
362
+ generatedTokenIds[133] = 49_000_000_093; // Token ID (V4: 49000000093)
363
+ generatedTokenIds[134] = 49_000_000_094; // Token ID (V4: 49000000094)
364
+ generatedTokenIds[135] = 49_000_000_095; // Token ID (V4: 49000000095)
365
+ generatedTokenIds[136] = 49_000_000_096; // Token ID (V4: 49000000096)
366
+ generatedTokenIds[137] = 49_000_000_097; // Token ID (V4: 49000000097)
367
+ generatedTokenIds[138] = 49_000_000_098; // Token ID (V4: 49000000098)
368
+ generatedTokenIds[139] = 49_000_000_099; // Token ID (V4: 49000000099)
369
+ generatedTokenIds[140] = 49_000_000_100; // Token ID (V4: 49000000100)
370
+ generatedTokenIds[141] = 49_000_000_101; // Token ID (V4: 49000000101)
371
+ generatedTokenIds[142] = 49_000_000_102; // Token ID (V4: 49000000102)
372
+ generatedTokenIds[143] = 49_000_000_103; // Token ID (V4: 49000000103)
373
+ generatedTokenIds[144] = 49_000_000_104; // Token ID (V4: 49000000104)
374
+ generatedTokenIds[145] = 49_000_000_105; // Token ID (V4: 49000000105)
375
+ generatedTokenIds[146] = 49_000_000_106; // Token ID (V4: 49000000106)
376
+ generatedTokenIds[147] = 49_000_000_107; // Token ID (V4: 49000000107)
377
+ generatedTokenIds[148] = 49_000_000_108; // Token ID (V4: 49000000108)
378
+ generatedTokenIds[149] = 49_000_000_109; // Token ID (V4: 49000000109)
379
+ generatedTokenIds[150] = 49_000_000_110; // Token ID (V4: 49000000110)
380
+ generatedTokenIds[151] = 49_000_000_111; // Token ID (V4: 49000000111)
381
+ generatedTokenIds[152] = 49_000_000_112; // Token ID (V4: 49000000112)
382
+ generatedTokenIds[153] = 49_000_000_113; // Token ID (V4: 49000000113)
383
+ generatedTokenIds[154] = 49_000_000_114; // Token ID (V4: 49000000114)
384
+ generatedTokenIds[155] = 49_000_000_115; // Token ID (V4: 49000000115)
385
+ generatedTokenIds[156] = 49_000_000_116; // Token ID (V4: 49000000116)
386
+ generatedTokenIds[157] = 49_000_000_117; // Token ID (V4: 49000000117)
387
+ generatedTokenIds[158] = 49_000_000_118; // Token ID (V4: 49000000118)
388
+ generatedTokenIds[159] = 49_000_000_119; // Token ID (V4: 49000000119)
389
+ generatedTokenIds[160] = 49_000_000_120; // Token ID (V4: 49000000120)
390
+ generatedTokenIds[161] = 49_000_000_121; // Token ID (V4: 49000000121)
391
+ generatedTokenIds[162] = 49_000_000_122; // Token ID (V4: 49000000122)
392
+ generatedTokenIds[163] = 49_000_000_123; // Token ID (V4: 49000000123)
393
+ generatedTokenIds[164] = 49_000_000_124; // Token ID (V4: 49000000124)
394
+ generatedTokenIds[165] = 49_000_000_125; // Token ID (V4: 49000000125)
395
+ generatedTokenIds[166] = 49_000_000_126; // Token ID (V4: 49000000126)
396
+ generatedTokenIds[167] = 49_000_000_127; // Token ID (V4: 49000000127)
397
+ generatedTokenIds[168] = 49_000_000_128; // Token ID (V4: 49000000128)
398
+ generatedTokenIds[169] = 49_000_000_129; // Token ID (V4: 49000000129)
399
+ generatedTokenIds[170] = 49_000_000_130; // Token ID (V4: 49000000130)
400
+ generatedTokenIds[171] = 49_000_000_131; // Token ID (V4: 49000000131)
401
+ generatedTokenIds[172] = 49_000_000_132; // Token ID (V4: 49000000132)
402
+ generatedTokenIds[173] = 49_000_000_133; // Token ID (V4: 49000000133)
403
+ generatedTokenIds[174] = 49_000_000_134; // Token ID (V4: 49000000134)
404
+ generatedTokenIds[175] = 49_000_000_135; // Token ID (V4: 49000000135)
405
+ generatedTokenIds[176] = 49_000_000_136; // Token ID (V4: 49000000136)
406
+ generatedTokenIds[177] = 49_000_000_137; // Token ID (V4: 49000000137)
407
+ generatedTokenIds[178] = 49_000_000_138; // Token ID (V4: 49000000138)
408
+ generatedTokenIds[179] = 49_000_000_139; // Token ID (V4: 49000000139)
409
+ generatedTokenIds[180] = 49_000_000_140; // Token ID (V4: 49000000140)
410
+ generatedTokenIds[181] = 49_000_000_141; // Token ID (V4: 49000000141)
411
+ generatedTokenIds[182] = 49_000_000_142; // Token ID (V4: 49000000142)
412
+ generatedTokenIds[183] = 49_000_000_143; // Token ID (V4: 49000000143)
413
+ generatedTokenIds[184] = 49_000_000_144; // Token ID (V4: 49000000144)
414
+ generatedTokenIds[185] = 49_000_000_145; // Token ID (V4: 49000000145)
415
+ generatedTokenIds[186] = 5_000_000_003; // Token ID (V4: 5000000003)
416
+
417
+ uint256 successfulTransfers = 0;
418
+ uint256 skippedResolverOwned = 0;
419
+
420
+ for (uint256 i = 0; i < transferOwners.length; i++) {
421
+ uint256 tokenId = generatedTokenIds[i];
422
+ // Verify V4 ownership before transferring V5
423
+ address v4Owner = v4Hook.ownerOf(tokenId);
424
+ require(
425
+ v4Owner == transferOwners[i] || v4Owner == address(fallbackV4ResolverAddress),
426
+ "V4/V5 ownership mismatch for token"
427
+ );
428
+
429
+ // Skip transfer if V4 owner is the resolver (resolver holds these tokens, we shouldn't transfer to
430
+ // resolver)
431
+ if (v4Owner == address(v4ResolverAddress) || v4Owner == address(fallbackV4ResolverAddress)) {
432
+ // Token is held by resolver, skip transfer
433
+ skippedResolverOwned++;
434
+ continue;
435
+ }
436
+
437
+ IERC721(address(hook)).transferFrom(address(this), transferOwners[i], tokenId);
438
+ successfulTransfers++;
439
+ }
440
+
441
+ // Verify all expected items were processed (transferred or skipped as expected)
442
+ require(successfulTransfers + skippedResolverOwned == transferOwners.length, "Not all items were processed");
443
+
444
+ // Final verification: Ensure this contract no longer owns any tokens
445
+ // This ensures all transfers completed successfully and no tokens were left behind
446
+ require(hook.balanceOf(address(this)) == 0, "Contract still owns tokens after migration");
447
+
448
+ // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
449
+
450
+ // // Collect unique owners
451
+ // address[] memory uniqueOwners = new address[](10);
452
+
453
+ // uniqueOwners[0] = 0x2aa64E6d80390F5C017F0313cB908051BE2FD35e;
454
+ // uniqueOwners[1] = 0x7C3F14075F6477fea1aF6cf59f325afDfcD3Ddf7;
455
+ // uniqueOwners[2] = 0x1C51517d8277C9aD6d701Fb5394ceC0C18219eDb;
456
+ // uniqueOwners[3] = 0xfD282d9f4d06C4BDc6a41af1Ae920A0AD70D18a3;
457
+ // uniqueOwners[4] = 0x08B3e694caA2F1fcF8eF71095CED1326f3454B89;
458
+ // uniqueOwners[5] = 0x9fDf876a50EA8f95017dCFC7709356887025B5BB;
459
+ // uniqueOwners[6] = 0x187089B33E5812310Ed32A57F53B3fAD0383a19D;
460
+ // uniqueOwners[7] = 0xc6404f24DB2f573F07F3A60758765caad198c0c3;
461
+ // uniqueOwners[8] = 0xB2d3900807094D4Fe47405871B0C8AdB58E10D42;
462
+ // uniqueOwners[9] = 0x57a482EA32c7F75A9C0734206f5BD4f9BCb38e12;
463
+
464
+ // // Collect unique tier IDs
465
+ // uint256[] memory uniqueTierIds = new uint256[](17);
466
+
467
+ // uniqueTierIds[0] = 3;
468
+ // uniqueTierIds[1] = 4;
469
+ // uniqueTierIds[2] = 5;
470
+ // uniqueTierIds[3] = 6;
471
+ // uniqueTierIds[4] = 10;
472
+ // uniqueTierIds[5] = 11;
473
+ // uniqueTierIds[6] = 19;
474
+ // uniqueTierIds[7] = 20;
475
+ // uniqueTierIds[8] = 25;
476
+ // uniqueTierIds[9] = 28;
477
+ // uniqueTierIds[10] = 31;
478
+ // uniqueTierIds[11] = 32;
479
+ // uniqueTierIds[12] = 38;
480
+ // uniqueTierIds[13] = 39;
481
+ // uniqueTierIds[14] = 43;
482
+ // uniqueTierIds[15] = 47;
483
+ // uniqueTierIds[16] = 49;
484
+
485
+ // // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
486
+ // MigrationHelper.verifyTierBalances(
487
+ // hookAddress,
488
+ // v4HookAddress,
489
+ // fallbackV4ResolverAddress,
490
+ // uniqueOwners,
491
+ // uniqueTierIds
492
+ // );
493
+ }
494
+ }
@@ -0,0 +1,170 @@
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 MigrationContractArbitrum1 {
10
+ // Define struct to hold all UPC minted tokenIds
11
+ struct MintedIds {
12
+ uint256[2] upc3;
13
+ uint256[2] upc4;
14
+ uint256[1] upc5;
15
+ uint256[1] upc19;
16
+ uint256[1] upc25;
17
+ uint256[1] upc38;
18
+ uint256[1] upc47;
19
+ }
20
+
21
+ address[] private transferOwners;
22
+
23
+ constructor(address[] memory _transferOwners) {
24
+ transferOwners = _transferOwners;
25
+ }
26
+
27
+ function executeMigration(
28
+ address hookAddress,
29
+ address resolverAddress,
30
+ address v4HookAddress,
31
+ address v4ResolverAddress,
32
+ address fallbackV4ResolverAddress
33
+ )
34
+ external
35
+ {
36
+ // Validate addresses
37
+ require(hookAddress != address(0), "Hook address not set");
38
+ require(resolverAddress != address(0), "Resolver address not set");
39
+ require(v4HookAddress != address(0), "V4 Hook address not set");
40
+ require(v4ResolverAddress != address(0), "V4 Resolver address not set");
41
+ require(fallbackV4ResolverAddress != address(0), "V4 fallback resolver address not set");
42
+
43
+ JB721TiersHook hook = JB721TiersHook(hookAddress);
44
+ Banny721TokenUriResolver resolver = Banny721TokenUriResolver(resolverAddress);
45
+ IERC721 v4Hook = IERC721(v4HookAddress);
46
+ Banny721TokenUriResolver v4Resolver = Banny721TokenUriResolver(v4ResolverAddress);
47
+ Banny721TokenUriResolver fallbackV4Resolver = Banny721TokenUriResolver(fallbackV4ResolverAddress);
48
+
49
+ // Arbitrum migration chunk 1/3 - 9 items
50
+
51
+ // Step 1: Assets are already minted to this contract by the deployer
52
+
53
+ // Assets are already minted to this contract by the deployer
54
+
55
+ // Create and populate the struct
56
+ // Token IDs follow formula: upc * 1000000000 + unitNumber (unitNumber starts at 1 per UPC)
57
+ MintedIds memory sortedMintedIds;
58
+
59
+ // Populate UPC 3 minted tokenIds (2 items)
60
+ sortedMintedIds.upc3[0] = 3_000_000_001; // Token ID: 3 * 1000000000 + 1
61
+ sortedMintedIds.upc3[1] = 3_000_000_002; // Token ID: 3 * 1000000000 + 2
62
+ // Populate UPC 4 minted tokenIds (2 items)
63
+ sortedMintedIds.upc4[0] = 4_000_000_001; // Token ID: 4 * 1000000000 + 1
64
+ sortedMintedIds.upc4[1] = 4_000_000_002; // Token ID: 4 * 1000000000 + 2
65
+ // Populate UPC 5 minted tokenIds (1 items)
66
+ sortedMintedIds.upc5[0] = 5_000_000_001; // Token ID: 5 * 1000000000 + 1
67
+ // Populate UPC 19 minted tokenIds (1 items)
68
+ sortedMintedIds.upc19[0] = 19_000_000_001; // Token ID: 19 * 1000000000 + 1
69
+ // Populate UPC 25 minted tokenIds (1 items)
70
+ sortedMintedIds.upc25[0] = 25_000_000_001; // Token ID: 25 * 1000000000 + 1
71
+ // Populate UPC 38 minted tokenIds (1 items)
72
+ sortedMintedIds.upc38[0] = 38_000_000_001; // Token ID: 38 * 1000000000 + 1
73
+ // Populate UPC 47 minted tokenIds (1 items)
74
+ sortedMintedIds.upc47[0] = 47_000_000_001; // Token ID: 47 * 1000000000 + 1
75
+ // Step 1.5: Approve resolver to transfer all tokens owned by this contract
76
+ // The resolver needs approval to transfer outfits and backgrounds to itself during decoration
77
+ IERC721(address(hook)).setApprovalForAll(address(resolver), true);
78
+
79
+ // Step 2: Process each Banny body and dress them
80
+
81
+ // Dress Banny 3000000001 (Orange)
82
+ {
83
+ uint256[] memory outfitIds = new uint256[](4);
84
+ outfitIds[0] = 19_000_000_001; // V4: 19000000001 -> V5: 19000000001
85
+ outfitIds[1] = 25_000_000_001; // V4: 25000000001 -> V5: 25000000001
86
+ outfitIds[2] = 38_000_000_001; // V4: 38000000001 -> V5: 38000000001
87
+ outfitIds[3] = 47_000_000_001; // V4: 47000000001 -> V5: 47000000001
88
+
89
+ resolver.decorateBannyWith(address(hook), 3_000_000_001, 5_000_000_001, outfitIds);
90
+
91
+ MigrationHelper.verifyV4AssetMatch(
92
+ resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 3_000_000_001
93
+ );
94
+ }
95
+
96
+ // Step 3: Transfer all assets to rightful owners using constructor data
97
+ // Generate token IDs in the same order as items appear (matching mint order)
98
+ // Token ID format: UPC * 1000000000 + unitNumber
99
+ // Note: Only banny body token IDs are guaranteed to match between V4 and V5.
100
+ // Outfits/backgrounds being worn by bannys may have different IDs, but that's OK
101
+ // since they're not transferred (only used in decorateBannyWith calls).
102
+ uint256[] memory generatedTokenIds = new uint256[](transferOwners.length);
103
+
104
+ generatedTokenIds[0] = 3_000_000_001; // Token ID (V4: 3000000001)
105
+ generatedTokenIds[1] = 3_000_000_002; // Token ID (V4: 3000000002)
106
+ generatedTokenIds[2] = 4_000_000_001; // Token ID (V4: 4000000001)
107
+ generatedTokenIds[3] = 4_000_000_002; // Token ID (V4: 4000000002)
108
+
109
+ uint256 successfulTransfers = 0;
110
+ uint256 skippedResolverOwned = 0;
111
+
112
+ for (uint256 i = 0; i < transferOwners.length; i++) {
113
+ uint256 tokenId = generatedTokenIds[i];
114
+ // Verify V4 ownership before transferring V5
115
+ address v4Owner = v4Hook.ownerOf(tokenId);
116
+ require(
117
+ v4Owner == transferOwners[i] || v4Owner == address(fallbackV4ResolverAddress),
118
+ "V4/V5 ownership mismatch for token"
119
+ );
120
+
121
+ // Skip transfer if V4 owner is the resolver (resolver holds these tokens, we shouldn't transfer to
122
+ // resolver)
123
+ if (v4Owner == address(v4ResolverAddress) || v4Owner == address(fallbackV4ResolverAddress)) {
124
+ // Token is held by resolver, skip transfer
125
+ skippedResolverOwned++;
126
+ continue;
127
+ }
128
+
129
+ IERC721(address(hook)).safeTransferFrom(address(this), transferOwners[i], tokenId);
130
+ successfulTransfers++;
131
+ }
132
+
133
+ // Verify all expected items were processed (transferred or skipped as expected)
134
+ require(successfulTransfers + skippedResolverOwned == transferOwners.length, "Not all items were processed");
135
+
136
+ // Final verification: Ensure this contract no longer owns any tokens
137
+ // This ensures all transfers completed successfully and no tokens were left behind
138
+ require(hook.balanceOf(address(this)) == 0, "Contract still owns tokens after migration");
139
+
140
+ // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
141
+
142
+ // // Collect unique owners
143
+ // address[] memory uniqueOwners = new address[](4);
144
+
145
+ // uniqueOwners[0] = 0x2aa64E6d80390F5C017F0313cB908051BE2FD35e;
146
+ // uniqueOwners[1] = 0x7C3F14075F6477fea1aF6cf59f325afDfcD3Ddf7;
147
+ // uniqueOwners[2] = 0x1C51517d8277C9aD6d701Fb5394ceC0C18219eDb;
148
+ // uniqueOwners[3] = 0xfD282d9f4d06C4BDc6a41af1Ae920A0AD70D18a3;
149
+
150
+ // // Collect unique tier IDs
151
+ // uint256[] memory uniqueTierIds = new uint256[](7);
152
+
153
+ // uniqueTierIds[0] = 3;
154
+ // uniqueTierIds[1] = 4;
155
+ // uniqueTierIds[2] = 5;
156
+ // uniqueTierIds[3] = 19;
157
+ // uniqueTierIds[4] = 25;
158
+ // uniqueTierIds[5] = 38;
159
+ // uniqueTierIds[6] = 47;
160
+
161
+ // // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
162
+ // MigrationHelper.verifyTierBalances(
163
+ // hookAddress,
164
+ // v4HookAddress,
165
+ // fallbackV4ResolverAddress,
166
+ // uniqueOwners,
167
+ // uniqueTierIds
168
+ // );
169
+ }
170
+ }