@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.
- package/README.md +53 -0
- package/SKILLS.md +94 -0
- package/deployments/banny-core-v5/arbitrum/Banny721TokenUriResolver.json +1809 -0
- package/deployments/banny-core-v5/arbitrum_sepolia/Banny721TokenUriResolver.json +1795 -0
- package/deployments/banny-core-v5/base/Banny721TokenUriResolver.json +1810 -0
- package/deployments/banny-core-v5/base_sepolia/Banny721TokenUriResolver.json +1796 -0
- package/deployments/banny-core-v5/ethereum/Banny721TokenUriResolver.json +1795 -0
- package/deployments/banny-core-v5/optimism/Banny721TokenUriResolver.json +1810 -0
- package/deployments/banny-core-v5/optimism_sepolia/Banny721TokenUriResolver.json +1796 -0
- package/deployments/banny-core-v5/sepolia/Banny721TokenUriResolver.json +1795 -0
- package/foundry.toml +22 -0
- package/package.json +53 -0
- package/remappings.txt +1 -0
- package/script/1.Fix.s.sol +290 -0
- package/script/Add.Denver.s.sol +75 -0
- package/script/AirdropOutfits.s.sol +2302 -0
- package/script/Deploy.s.sol +440 -0
- package/script/Drop1.s.sol +979 -0
- package/script/MigrationContractArbitrum.sol +494 -0
- package/script/MigrationContractArbitrum1.sol +170 -0
- package/script/MigrationContractArbitrum2.sol +204 -0
- package/script/MigrationContractArbitrum3.sol +174 -0
- package/script/MigrationContractArbitrum4.sol +478 -0
- package/script/MigrationContractBase1.sol +444 -0
- package/script/MigrationContractBase2.sol +175 -0
- package/script/MigrationContractBase3.sol +309 -0
- package/script/MigrationContractBase4.sol +350 -0
- package/script/MigrationContractBase5.sol +259 -0
- package/script/MigrationContractEthereum1.sol +468 -0
- package/script/MigrationContractEthereum2.sol +306 -0
- package/script/MigrationContractEthereum3.sol +349 -0
- package/script/MigrationContractEthereum4.sol +352 -0
- package/script/MigrationContractEthereum5.sol +354 -0
- package/script/MigrationContractEthereum6.sol +270 -0
- package/script/MigrationContractEthereum7.sol +439 -0
- package/script/MigrationContractEthereum8.sol +385 -0
- package/script/MigrationContractOptimism.sol +196 -0
- package/script/helpers/BannyverseDeploymentLib.sol +73 -0
- package/script/helpers/MigrationHelper.sol +155 -0
- package/script/outfit_drop/generate-migration.js +3441 -0
- package/script/outfit_drop/raw.json +43276 -0
- package/slither-ci.config.json +10 -0
- package/sphinx.lock +521 -0
- package/src/Banny721TokenUriResolver.sol +1288 -0
- package/src/interfaces/IBanny721TokenUriResolver.sol +137 -0
- package/test/Banny721TokenUriResolver.t.sol +669 -0
- package/test/BannyAttacks.t.sol +322 -0
- package/test/DecorateFlow.t.sol +1056 -0
|
@@ -0,0 +1,309 @@
|
|
|
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 MigrationContractBase3 {
|
|
10
|
+
// Define struct to hold all UPC minted tokenIds
|
|
11
|
+
struct MintedIds {
|
|
12
|
+
uint256[27] upc4;
|
|
13
|
+
uint256[3] upc10;
|
|
14
|
+
uint256[1] upc14;
|
|
15
|
+
uint256[1] upc19;
|
|
16
|
+
uint256[2] upc25;
|
|
17
|
+
uint256[1] upc28;
|
|
18
|
+
uint256[1] upc31;
|
|
19
|
+
uint256[1] upc38;
|
|
20
|
+
uint256[2] upc43;
|
|
21
|
+
uint256[1] upc47;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
address[] private transferOwners;
|
|
25
|
+
|
|
26
|
+
constructor(address[] memory _transferOwners) {
|
|
27
|
+
transferOwners = _transferOwners;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function executeMigration(
|
|
31
|
+
address hookAddress,
|
|
32
|
+
address resolverAddress,
|
|
33
|
+
address v4HookAddress,
|
|
34
|
+
address v4ResolverAddress,
|
|
35
|
+
address fallbackV4ResolverAddress
|
|
36
|
+
)
|
|
37
|
+
external
|
|
38
|
+
{
|
|
39
|
+
// Validate addresses
|
|
40
|
+
require(hookAddress != address(0), "Hook address not set");
|
|
41
|
+
require(resolverAddress != address(0), "Resolver address not set");
|
|
42
|
+
require(v4HookAddress != address(0), "V4 Hook address not set");
|
|
43
|
+
require(v4ResolverAddress != address(0), "V4 Resolver address not set");
|
|
44
|
+
require(fallbackV4ResolverAddress != address(0), "V4 fallback resolver address not set");
|
|
45
|
+
|
|
46
|
+
JB721TiersHook hook = JB721TiersHook(hookAddress);
|
|
47
|
+
Banny721TokenUriResolver resolver = Banny721TokenUriResolver(resolverAddress);
|
|
48
|
+
IERC721 v4Hook = IERC721(v4HookAddress);
|
|
49
|
+
Banny721TokenUriResolver v4Resolver = Banny721TokenUriResolver(v4ResolverAddress);
|
|
50
|
+
Banny721TokenUriResolver fallbackV4Resolver = Banny721TokenUriResolver(fallbackV4ResolverAddress);
|
|
51
|
+
|
|
52
|
+
// Base migration chunk 3/4 - 40 items
|
|
53
|
+
|
|
54
|
+
// Step 1: Assets are already minted to this contract by the deployer
|
|
55
|
+
|
|
56
|
+
// Assets are already minted to this contract by the deployer
|
|
57
|
+
|
|
58
|
+
// Create and populate the struct
|
|
59
|
+
// Token IDs follow formula: upc * 1000000000 + unitNumber (unitNumber starts at 1 per UPC)
|
|
60
|
+
MintedIds memory sortedMintedIds;
|
|
61
|
+
|
|
62
|
+
// Populate UPC 4 minted tokenIds (27 items)
|
|
63
|
+
sortedMintedIds.upc4[0] = 4_000_000_042; // Token ID: 4 * 1000000000 + 1
|
|
64
|
+
sortedMintedIds.upc4[1] = 4_000_000_043; // Token ID: 4 * 1000000000 + 2
|
|
65
|
+
sortedMintedIds.upc4[2] = 4_000_000_044; // Token ID: 4 * 1000000000 + 3
|
|
66
|
+
sortedMintedIds.upc4[3] = 4_000_000_045; // Token ID: 4 * 1000000000 + 4
|
|
67
|
+
sortedMintedIds.upc4[4] = 4_000_000_046; // Token ID: 4 * 1000000000 + 5
|
|
68
|
+
sortedMintedIds.upc4[5] = 4_000_000_047; // Token ID: 4 * 1000000000 + 6
|
|
69
|
+
sortedMintedIds.upc4[6] = 4_000_000_048; // Token ID: 4 * 1000000000 + 7
|
|
70
|
+
sortedMintedIds.upc4[7] = 4_000_000_049; // Token ID: 4 * 1000000000 + 8
|
|
71
|
+
sortedMintedIds.upc4[8] = 4_000_000_050; // Token ID: 4 * 1000000000 + 9
|
|
72
|
+
sortedMintedIds.upc4[9] = 4_000_000_051; // Token ID: 4 * 1000000000 + 10
|
|
73
|
+
sortedMintedIds.upc4[10] = 4_000_000_052; // Token ID: 4 * 1000000000 + 11
|
|
74
|
+
sortedMintedIds.upc4[11] = 4_000_000_053; // Token ID: 4 * 1000000000 + 12
|
|
75
|
+
sortedMintedIds.upc4[12] = 4_000_000_054; // Token ID: 4 * 1000000000 + 13
|
|
76
|
+
sortedMintedIds.upc4[13] = 4_000_000_055; // Token ID: 4 * 1000000000 + 14
|
|
77
|
+
sortedMintedIds.upc4[14] = 4_000_000_056; // Token ID: 4 * 1000000000 + 15
|
|
78
|
+
sortedMintedIds.upc4[15] = 4_000_000_057; // Token ID: 4 * 1000000000 + 16
|
|
79
|
+
sortedMintedIds.upc4[16] = 4_000_000_058; // Token ID: 4 * 1000000000 + 17
|
|
80
|
+
sortedMintedIds.upc4[17] = 4_000_000_059; // Token ID: 4 * 1000000000 + 18
|
|
81
|
+
sortedMintedIds.upc4[18] = 4_000_000_060; // Token ID: 4 * 1000000000 + 19
|
|
82
|
+
sortedMintedIds.upc4[19] = 4_000_000_061; // Token ID: 4 * 1000000000 + 20
|
|
83
|
+
sortedMintedIds.upc4[20] = 4_000_000_062; // Token ID: 4 * 1000000000 + 21
|
|
84
|
+
sortedMintedIds.upc4[21] = 4_000_000_063; // Token ID: 4 * 1000000000 + 22
|
|
85
|
+
sortedMintedIds.upc4[22] = 4_000_000_064; // Token ID: 4 * 1000000000 + 23
|
|
86
|
+
sortedMintedIds.upc4[23] = 4_000_000_065; // Token ID: 4 * 1000000000 + 24
|
|
87
|
+
sortedMintedIds.upc4[24] = 4_000_000_066; // Token ID: 4 * 1000000000 + 25
|
|
88
|
+
sortedMintedIds.upc4[25] = 4_000_000_067; // Token ID: 4 * 1000000000 + 26
|
|
89
|
+
sortedMintedIds.upc4[26] = 4_000_000_068; // Token ID: 4 * 1000000000 + 27
|
|
90
|
+
// Populate UPC 10 minted tokenIds (3 items)
|
|
91
|
+
sortedMintedIds.upc10[0] = 10_000_000_002; // Token ID: 10 * 1000000000 + 1
|
|
92
|
+
sortedMintedIds.upc10[1] = 10_000_000_003; // Token ID: 10 * 1000000000 + 2
|
|
93
|
+
sortedMintedIds.upc10[2] = 10_000_000_004; // Token ID: 10 * 1000000000 + 3
|
|
94
|
+
// Populate UPC 14 minted tokenIds (1 items)
|
|
95
|
+
sortedMintedIds.upc14[0] = 14_000_000_003; // Token ID: 14 * 1000000000 + 1
|
|
96
|
+
// Populate UPC 19 minted tokenIds (1 items)
|
|
97
|
+
sortedMintedIds.upc19[0] = 19_000_000_005; // Token ID: 19 * 1000000000 + 1
|
|
98
|
+
// Populate UPC 25 minted tokenIds (2 items)
|
|
99
|
+
sortedMintedIds.upc25[0] = 25_000_000_005; // Token ID: 25 * 1000000000 + 1
|
|
100
|
+
sortedMintedIds.upc25[1] = 25_000_000_006; // Token ID: 25 * 1000000000 + 2
|
|
101
|
+
// Populate UPC 28 minted tokenIds (1 items)
|
|
102
|
+
sortedMintedIds.upc28[0] = 28_000_000_005; // Token ID: 28 * 1000000000 + 1
|
|
103
|
+
// Populate UPC 31 minted tokenIds (1 items)
|
|
104
|
+
sortedMintedIds.upc31[0] = 31_000_000_002; // Token ID: 31 * 1000000000 + 1
|
|
105
|
+
// Populate UPC 38 minted tokenIds (1 items)
|
|
106
|
+
sortedMintedIds.upc38[0] = 38_000_000_001; // Token ID: 38 * 1000000000 + 1
|
|
107
|
+
// Populate UPC 43 minted tokenIds (2 items)
|
|
108
|
+
sortedMintedIds.upc43[0] = 43_000_000_002; // Token ID: 43 * 1000000000 + 1
|
|
109
|
+
sortedMintedIds.upc43[1] = 43_000_000_003; // Token ID: 43 * 1000000000 + 2
|
|
110
|
+
// Populate UPC 47 minted tokenIds (1 items)
|
|
111
|
+
sortedMintedIds.upc47[0] = 47_000_000_003; // Token ID: 47 * 1000000000 + 1
|
|
112
|
+
// Step 1.5: Approve resolver to transfer all tokens owned by this contract
|
|
113
|
+
// The resolver needs approval to transfer outfits and backgrounds to itself during decoration
|
|
114
|
+
IERC721(address(hook)).setApprovalForAll(address(resolver), true);
|
|
115
|
+
|
|
116
|
+
// Step 2: Process each Banny body and dress them
|
|
117
|
+
|
|
118
|
+
// Dress Banny 4000000045 (Original)
|
|
119
|
+
{
|
|
120
|
+
uint256[] memory outfitIds = new uint256[](3);
|
|
121
|
+
outfitIds[0] = 10_000_000_002; // V4: 10000000001 -> V5: 10000000002
|
|
122
|
+
outfitIds[1] = 25_000_000_005; // V4: 25000000002 -> V5: 25000000005
|
|
123
|
+
outfitIds[2] = 43_000_000_002; // V4: 43000000002 -> V5: 43000000002
|
|
124
|
+
|
|
125
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_045, 0, outfitIds);
|
|
126
|
+
|
|
127
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
128
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_045
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Dress Banny 4000000046 (Original)
|
|
133
|
+
{
|
|
134
|
+
uint256[] memory outfitIds = new uint256[](1);
|
|
135
|
+
outfitIds[0] = 47_000_000_003; // V4: 47000000001 -> V5: 47000000003
|
|
136
|
+
|
|
137
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_046, 0, outfitIds);
|
|
138
|
+
|
|
139
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
140
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_046
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Dress Banny 4000000048 (Original)
|
|
145
|
+
{
|
|
146
|
+
uint256[] memory outfitIds = new uint256[](3);
|
|
147
|
+
outfitIds[0] = 10_000_000_003; // V4: 10000000003 -> V5: 10000000003
|
|
148
|
+
outfitIds[1] = 19_000_000_005; // V4: 19000000003 -> V5: 19000000005
|
|
149
|
+
outfitIds[2] = 28_000_000_005; // V4: 28000000004 -> V5: 28000000005
|
|
150
|
+
|
|
151
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_048, 0, outfitIds);
|
|
152
|
+
|
|
153
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
154
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_048
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Dress Banny 4000000049 (Original)
|
|
159
|
+
{
|
|
160
|
+
uint256[] memory outfitIds = new uint256[](1);
|
|
161
|
+
outfitIds[0] = 10_000_000_004; // V4: 10000000004 -> V5: 10000000004
|
|
162
|
+
|
|
163
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_049, 0, outfitIds);
|
|
164
|
+
|
|
165
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
166
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_049
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Dress Banny 4000000050 (Original)
|
|
171
|
+
{
|
|
172
|
+
uint256[] memory outfitIds = new uint256[](4);
|
|
173
|
+
outfitIds[0] = 14_000_000_003; // V4: 14000000001 -> V5: 14000000003
|
|
174
|
+
outfitIds[1] = 31_000_000_002; // V4: 31000000001 -> V5: 31000000002
|
|
175
|
+
outfitIds[2] = 38_000_000_001; // V4: 38000000001 -> V5: 38000000001
|
|
176
|
+
outfitIds[3] = 43_000_000_003; // V4: 43000000003 -> V5: 43000000003
|
|
177
|
+
|
|
178
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_050, 0, outfitIds);
|
|
179
|
+
|
|
180
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
181
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_050
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Dress Banny 4000000054 (Original)
|
|
186
|
+
{
|
|
187
|
+
uint256[] memory outfitIds = new uint256[](1);
|
|
188
|
+
outfitIds[0] = 25_000_000_006; // V4: 25000000005 -> V5: 25000000006
|
|
189
|
+
|
|
190
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_054, 0, outfitIds);
|
|
191
|
+
|
|
192
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
193
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_054
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Step 3: Transfer all assets to rightful owners using constructor data
|
|
198
|
+
// Generate token IDs in the same order as items appear (matching mint order)
|
|
199
|
+
// Token ID format: UPC * 1000000000 + unitNumber
|
|
200
|
+
// Note: Only banny body token IDs are guaranteed to match between V4 and V5.
|
|
201
|
+
// Outfits/backgrounds being worn by bannys may have different IDs, but that's OK
|
|
202
|
+
// since they're not transferred (only used in decorateBannyWith calls).
|
|
203
|
+
uint256[] memory generatedTokenIds = new uint256[](transferOwners.length);
|
|
204
|
+
|
|
205
|
+
generatedTokenIds[0] = 4_000_000_042; // Token ID (V4: 4000000042)
|
|
206
|
+
generatedTokenIds[1] = 4_000_000_043; // Token ID (V4: 4000000043)
|
|
207
|
+
generatedTokenIds[2] = 4_000_000_044; // Token ID (V4: 4000000044)
|
|
208
|
+
generatedTokenIds[3] = 4_000_000_045; // Token ID (V4: 4000000045)
|
|
209
|
+
generatedTokenIds[4] = 4_000_000_046; // Token ID (V4: 4000000046)
|
|
210
|
+
generatedTokenIds[5] = 4_000_000_047; // Token ID (V4: 4000000047)
|
|
211
|
+
generatedTokenIds[6] = 4_000_000_048; // Token ID (V4: 4000000048)
|
|
212
|
+
generatedTokenIds[7] = 4_000_000_049; // Token ID (V4: 4000000049)
|
|
213
|
+
generatedTokenIds[8] = 4_000_000_050; // Token ID (V4: 4000000050)
|
|
214
|
+
generatedTokenIds[9] = 4_000_000_051; // Token ID (V4: 4000000051)
|
|
215
|
+
generatedTokenIds[10] = 4_000_000_052; // Token ID (V4: 4000000052)
|
|
216
|
+
generatedTokenIds[11] = 4_000_000_053; // Token ID (V4: 4000000053)
|
|
217
|
+
generatedTokenIds[12] = 4_000_000_054; // Token ID (V4: 4000000054)
|
|
218
|
+
generatedTokenIds[13] = 4_000_000_055; // Token ID (V4: 4000000055)
|
|
219
|
+
generatedTokenIds[14] = 4_000_000_056; // Token ID (V4: 4000000056)
|
|
220
|
+
generatedTokenIds[15] = 4_000_000_057; // Token ID (V4: 4000000057)
|
|
221
|
+
generatedTokenIds[16] = 4_000_000_058; // Token ID (V4: 4000000058)
|
|
222
|
+
generatedTokenIds[17] = 4_000_000_059; // Token ID (V4: 4000000059)
|
|
223
|
+
generatedTokenIds[18] = 4_000_000_060; // Token ID (V4: 4000000060)
|
|
224
|
+
generatedTokenIds[19] = 4_000_000_061; // Token ID (V4: 4000000061)
|
|
225
|
+
generatedTokenIds[20] = 4_000_000_062; // Token ID (V4: 4000000062)
|
|
226
|
+
generatedTokenIds[21] = 4_000_000_063; // Token ID (V4: 4000000063)
|
|
227
|
+
generatedTokenIds[22] = 4_000_000_064; // Token ID (V4: 4000000064)
|
|
228
|
+
generatedTokenIds[23] = 4_000_000_065; // Token ID (V4: 4000000065)
|
|
229
|
+
generatedTokenIds[24] = 4_000_000_066; // Token ID (V4: 4000000066)
|
|
230
|
+
generatedTokenIds[25] = 4_000_000_067; // Token ID (V4: 4000000067)
|
|
231
|
+
generatedTokenIds[26] = 4_000_000_068; // Token ID (V4: 4000000068)
|
|
232
|
+
|
|
233
|
+
uint256 successfulTransfers = 0;
|
|
234
|
+
uint256 skippedResolverOwned = 0;
|
|
235
|
+
|
|
236
|
+
for (uint256 i = 0; i < transferOwners.length; i++) {
|
|
237
|
+
uint256 tokenId = generatedTokenIds[i];
|
|
238
|
+
// Verify V4 ownership before transferring V5
|
|
239
|
+
address v4Owner = v4Hook.ownerOf(tokenId);
|
|
240
|
+
require(
|
|
241
|
+
v4Owner == transferOwners[i] || v4Owner == address(fallbackV4ResolverAddress),
|
|
242
|
+
"V4/V5 ownership mismatch for token"
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// Skip transfer if V4 owner is the resolver (resolver holds these tokens, we shouldn't transfer to
|
|
246
|
+
// resolver)
|
|
247
|
+
if (v4Owner == address(v4ResolverAddress) || v4Owner == address(fallbackV4ResolverAddress)) {
|
|
248
|
+
// Token is held by resolver, skip transfer
|
|
249
|
+
skippedResolverOwned++;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
IERC721(address(hook)).safeTransferFrom(address(this), transferOwners[i], tokenId);
|
|
254
|
+
successfulTransfers++;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Verify all expected items were processed (transferred or skipped as expected)
|
|
258
|
+
require(successfulTransfers + skippedResolverOwned == transferOwners.length, "Not all items were processed");
|
|
259
|
+
|
|
260
|
+
// Final verification: Ensure this contract no longer owns any tokens
|
|
261
|
+
// This ensures all transfers completed successfully and no tokens were left behind
|
|
262
|
+
require(hook.balanceOf(address(this)) == 0, "Contract still owns tokens after migration");
|
|
263
|
+
|
|
264
|
+
// Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
|
|
265
|
+
|
|
266
|
+
// // Collect unique owners
|
|
267
|
+
// address[] memory uniqueOwners = new address[](16);
|
|
268
|
+
|
|
269
|
+
// uniqueOwners[0] = 0xf7253A0E87E39d2cD6365919D4a3D56D431D0041;
|
|
270
|
+
// uniqueOwners[1] = 0x67BcBE602e870e2286C19E4E0044E583967c9665;
|
|
271
|
+
// uniqueOwners[2] = 0x18deEE9699526f8C8a87004b2e4e55029Fb26b9a;
|
|
272
|
+
// uniqueOwners[3] = 0xFB46349c0A3F04150E8c731B3A4fC415b0850CE3;
|
|
273
|
+
// uniqueOwners[4] = 0xAcD59e854adf632d2322404198624F757C868C97;
|
|
274
|
+
// uniqueOwners[5] = 0xa13d49fCbf79EAF6A0a58cBDD3361422DB4eAfF1;
|
|
275
|
+
// uniqueOwners[6] = 0x1C51517d8277C9aD6d701Fb5394ceC0C18219eDb;
|
|
276
|
+
// uniqueOwners[7] = 0xbeC26FFa12c90217943D1b2958f60A821aE6E549;
|
|
277
|
+
// uniqueOwners[8] = 0x8Ec174c5d86469D1A74094E10485357eBFe2e08e;
|
|
278
|
+
// uniqueOwners[9] = 0xC5704f77f94087CC644d361A5A57295851d242aB;
|
|
279
|
+
// uniqueOwners[10] = 0x99Fa48ccEa8a38CDE6B437450fF9bBdDAFAA4Fc8;
|
|
280
|
+
// uniqueOwners[11] = 0xb6ECb51e3638Eb7aa0C6289ef058DCa27494Acb2;
|
|
281
|
+
// uniqueOwners[12] = 0x57700212B1cB7b67bD7DF3801DA43CA634513fE0;
|
|
282
|
+
// uniqueOwners[13] = 0x9342E2aC6dd4A907948E91E80D2734ecAC1D70eC;
|
|
283
|
+
// uniqueOwners[14] = 0x96D087aba8552A0e111D7fB4Feb2e7621213E244;
|
|
284
|
+
// uniqueOwners[15] = 0x2830e21792019CE670fBc548AacB004b08c7f71f;
|
|
285
|
+
|
|
286
|
+
// // Collect unique tier IDs
|
|
287
|
+
// uint256[] memory uniqueTierIds = new uint256[](10);
|
|
288
|
+
|
|
289
|
+
// uniqueTierIds[0] = 4;
|
|
290
|
+
// uniqueTierIds[1] = 10;
|
|
291
|
+
// uniqueTierIds[2] = 14;
|
|
292
|
+
// uniqueTierIds[3] = 19;
|
|
293
|
+
// uniqueTierIds[4] = 25;
|
|
294
|
+
// uniqueTierIds[5] = 28;
|
|
295
|
+
// uniqueTierIds[6] = 31;
|
|
296
|
+
// uniqueTierIds[7] = 38;
|
|
297
|
+
// uniqueTierIds[8] = 43;
|
|
298
|
+
// uniqueTierIds[9] = 47;
|
|
299
|
+
|
|
300
|
+
// // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
|
|
301
|
+
// MigrationHelper.verifyTierBalances(
|
|
302
|
+
// hookAddress,
|
|
303
|
+
// v4HookAddress,
|
|
304
|
+
// fallbackV4ResolverAddress,
|
|
305
|
+
// uniqueOwners,
|
|
306
|
+
// uniqueTierIds
|
|
307
|
+
// );
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
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 MigrationContractBase4 {
|
|
10
|
+
// Define struct to hold all UPC minted tokenIds
|
|
11
|
+
struct MintedIds {
|
|
12
|
+
uint256[26] upc4;
|
|
13
|
+
uint256[2] upc5;
|
|
14
|
+
uint256[1] upc10;
|
|
15
|
+
uint256[1] upc13;
|
|
16
|
+
uint256[2] upc19;
|
|
17
|
+
uint256[1] upc20;
|
|
18
|
+
uint256[2] upc25;
|
|
19
|
+
uint256[1] upc27;
|
|
20
|
+
uint256[1] upc28;
|
|
21
|
+
uint256[1] upc35;
|
|
22
|
+
uint256[1] upc38;
|
|
23
|
+
uint256[1] upc39;
|
|
24
|
+
uint256[1] upc41;
|
|
25
|
+
uint256[3] upc43;
|
|
26
|
+
uint256[1] upc44;
|
|
27
|
+
uint256[1] upc48;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
address[] private transferOwners;
|
|
31
|
+
|
|
32
|
+
constructor(address[] memory _transferOwners) {
|
|
33
|
+
transferOwners = _transferOwners;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function executeMigration(
|
|
37
|
+
address hookAddress,
|
|
38
|
+
address resolverAddress,
|
|
39
|
+
address v4HookAddress,
|
|
40
|
+
address v4ResolverAddress,
|
|
41
|
+
address fallbackV4ResolverAddress
|
|
42
|
+
)
|
|
43
|
+
external
|
|
44
|
+
{
|
|
45
|
+
// Validate addresses
|
|
46
|
+
require(hookAddress != address(0), "Hook address not set");
|
|
47
|
+
require(resolverAddress != address(0), "Resolver address not set");
|
|
48
|
+
require(v4HookAddress != address(0), "V4 Hook address not set");
|
|
49
|
+
require(v4ResolverAddress != address(0), "V4 Resolver address not set");
|
|
50
|
+
require(fallbackV4ResolverAddress != address(0), "V4 fallback resolver address not set");
|
|
51
|
+
|
|
52
|
+
JB721TiersHook hook = JB721TiersHook(hookAddress);
|
|
53
|
+
Banny721TokenUriResolver resolver = Banny721TokenUriResolver(resolverAddress);
|
|
54
|
+
IERC721 v4Hook = IERC721(v4HookAddress);
|
|
55
|
+
Banny721TokenUriResolver v4Resolver = Banny721TokenUriResolver(v4ResolverAddress);
|
|
56
|
+
Banny721TokenUriResolver fallbackV4Resolver = Banny721TokenUriResolver(fallbackV4ResolverAddress);
|
|
57
|
+
|
|
58
|
+
// Base migration chunk 4/4 - 46 items
|
|
59
|
+
|
|
60
|
+
// Step 1: Assets are already minted to this contract by the deployer
|
|
61
|
+
|
|
62
|
+
// Assets are already minted to this contract by the deployer
|
|
63
|
+
|
|
64
|
+
// Create and populate the struct
|
|
65
|
+
// Token IDs follow formula: upc * 1000000000 + unitNumber (unitNumber starts at 1 per UPC)
|
|
66
|
+
MintedIds memory sortedMintedIds;
|
|
67
|
+
|
|
68
|
+
// Populate UPC 4 minted tokenIds (26 items)
|
|
69
|
+
sortedMintedIds.upc4[0] = 4_000_000_069; // Token ID: 4 * 1000000000 + 1
|
|
70
|
+
sortedMintedIds.upc4[1] = 4_000_000_070; // Token ID: 4 * 1000000000 + 2
|
|
71
|
+
sortedMintedIds.upc4[2] = 4_000_000_071; // Token ID: 4 * 1000000000 + 3
|
|
72
|
+
sortedMintedIds.upc4[3] = 4_000_000_072; // Token ID: 4 * 1000000000 + 4
|
|
73
|
+
sortedMintedIds.upc4[4] = 4_000_000_073; // Token ID: 4 * 1000000000 + 5
|
|
74
|
+
sortedMintedIds.upc4[5] = 4_000_000_074; // Token ID: 4 * 1000000000 + 6
|
|
75
|
+
sortedMintedIds.upc4[6] = 4_000_000_075; // Token ID: 4 * 1000000000 + 7
|
|
76
|
+
sortedMintedIds.upc4[7] = 4_000_000_076; // Token ID: 4 * 1000000000 + 8
|
|
77
|
+
sortedMintedIds.upc4[8] = 4_000_000_077; // Token ID: 4 * 1000000000 + 9
|
|
78
|
+
sortedMintedIds.upc4[9] = 4_000_000_078; // Token ID: 4 * 1000000000 + 10
|
|
79
|
+
sortedMintedIds.upc4[10] = 4_000_000_079; // Token ID: 4 * 1000000000 + 11
|
|
80
|
+
sortedMintedIds.upc4[11] = 4_000_000_080; // Token ID: 4 * 1000000000 + 12
|
|
81
|
+
sortedMintedIds.upc4[12] = 4_000_000_081; // Token ID: 4 * 1000000000 + 13
|
|
82
|
+
sortedMintedIds.upc4[13] = 4_000_000_082; // Token ID: 4 * 1000000000 + 14
|
|
83
|
+
sortedMintedIds.upc4[14] = 4_000_000_083; // Token ID: 4 * 1000000000 + 15
|
|
84
|
+
sortedMintedIds.upc4[15] = 4_000_000_084; // Token ID: 4 * 1000000000 + 16
|
|
85
|
+
sortedMintedIds.upc4[16] = 4_000_000_085; // Token ID: 4 * 1000000000 + 17
|
|
86
|
+
sortedMintedIds.upc4[17] = 4_000_000_086; // Token ID: 4 * 1000000000 + 18
|
|
87
|
+
sortedMintedIds.upc4[18] = 4_000_000_087; // Token ID: 4 * 1000000000 + 19
|
|
88
|
+
sortedMintedIds.upc4[19] = 4_000_000_088; // Token ID: 4 * 1000000000 + 20
|
|
89
|
+
sortedMintedIds.upc4[20] = 4_000_000_089; // Token ID: 4 * 1000000000 + 21
|
|
90
|
+
sortedMintedIds.upc4[21] = 4_000_000_090; // Token ID: 4 * 1000000000 + 22
|
|
91
|
+
sortedMintedIds.upc4[22] = 4_000_000_091; // Token ID: 4 * 1000000000 + 23
|
|
92
|
+
sortedMintedIds.upc4[23] = 4_000_000_092; // Token ID: 4 * 1000000000 + 24
|
|
93
|
+
sortedMintedIds.upc4[24] = 4_000_000_093; // Token ID: 4 * 1000000000 + 25
|
|
94
|
+
sortedMintedIds.upc4[25] = 4_000_000_094; // Token ID: 4 * 1000000000 + 26
|
|
95
|
+
// Populate UPC 5 minted tokenIds (2 items)
|
|
96
|
+
sortedMintedIds.upc5[0] = 5_000_000_002; // Token ID: 5 * 1000000000 + 1
|
|
97
|
+
sortedMintedIds.upc5[1] = 5_000_000_003; // Token ID: 5 * 1000000000 + 2
|
|
98
|
+
// Populate UPC 10 minted tokenIds (1 items)
|
|
99
|
+
sortedMintedIds.upc10[0] = 10_000_000_005; // Token ID: 10 * 1000000000 + 1
|
|
100
|
+
// Populate UPC 13 minted tokenIds (1 items)
|
|
101
|
+
sortedMintedIds.upc13[0] = 13_000_000_001; // Token ID: 13 * 1000000000 + 1
|
|
102
|
+
// Populate UPC 19 minted tokenIds (2 items)
|
|
103
|
+
sortedMintedIds.upc19[0] = 19_000_000_006; // Token ID: 19 * 1000000000 + 1
|
|
104
|
+
sortedMintedIds.upc19[1] = 19_000_000_007; // Token ID: 19 * 1000000000 + 2
|
|
105
|
+
// Populate UPC 20 minted tokenIds (1 items)
|
|
106
|
+
sortedMintedIds.upc20[0] = 20_000_000_001; // Token ID: 20 * 1000000000 + 1
|
|
107
|
+
// Populate UPC 25 minted tokenIds (2 items)
|
|
108
|
+
sortedMintedIds.upc25[0] = 25_000_000_007; // Token ID: 25 * 1000000000 + 1
|
|
109
|
+
sortedMintedIds.upc25[1] = 25_000_000_008; // Token ID: 25 * 1000000000 + 2
|
|
110
|
+
// Populate UPC 27 minted tokenIds (1 items)
|
|
111
|
+
sortedMintedIds.upc27[0] = 27_000_000_001; // Token ID: 27 * 1000000000 + 1
|
|
112
|
+
// Populate UPC 28 minted tokenIds (1 items)
|
|
113
|
+
sortedMintedIds.upc28[0] = 28_000_000_006; // Token ID: 28 * 1000000000 + 1
|
|
114
|
+
// Populate UPC 35 minted tokenIds (1 items)
|
|
115
|
+
sortedMintedIds.upc35[0] = 35_000_000_001; // Token ID: 35 * 1000000000 + 1
|
|
116
|
+
// Populate UPC 38 minted tokenIds (1 items)
|
|
117
|
+
sortedMintedIds.upc38[0] = 38_000_000_002; // Token ID: 38 * 1000000000 + 1
|
|
118
|
+
// Populate UPC 39 minted tokenIds (1 items)
|
|
119
|
+
sortedMintedIds.upc39[0] = 39_000_000_001; // Token ID: 39 * 1000000000 + 1
|
|
120
|
+
// Populate UPC 41 minted tokenIds (1 items)
|
|
121
|
+
sortedMintedIds.upc41[0] = 41_000_000_001; // Token ID: 41 * 1000000000 + 1
|
|
122
|
+
// Populate UPC 43 minted tokenIds (3 items)
|
|
123
|
+
sortedMintedIds.upc43[0] = 43_000_000_004; // Token ID: 43 * 1000000000 + 1
|
|
124
|
+
sortedMintedIds.upc43[1] = 43_000_000_005; // Token ID: 43 * 1000000000 + 2
|
|
125
|
+
sortedMintedIds.upc43[2] = 43_000_000_006; // Token ID: 43 * 1000000000 + 3
|
|
126
|
+
// Populate UPC 44 minted tokenIds (1 items)
|
|
127
|
+
sortedMintedIds.upc44[0] = 44_000_000_003; // Token ID: 44 * 1000000000 + 1
|
|
128
|
+
// Populate UPC 48 minted tokenIds (1 items)
|
|
129
|
+
sortedMintedIds.upc48[0] = 48_000_000_001; // Token ID: 48 * 1000000000 + 1
|
|
130
|
+
// Step 1.5: Approve resolver to transfer all tokens owned by this contract
|
|
131
|
+
// The resolver needs approval to transfer outfits and backgrounds to itself during decoration
|
|
132
|
+
IERC721(address(hook)).setApprovalForAll(address(resolver), true);
|
|
133
|
+
|
|
134
|
+
// Step 2: Process each Banny body and dress them
|
|
135
|
+
|
|
136
|
+
// Dress Banny 4000000073 (Original)
|
|
137
|
+
{
|
|
138
|
+
uint256[] memory outfitIds = new uint256[](4);
|
|
139
|
+
outfitIds[0] = 10_000_000_005; // V4: 10000000007 -> V5: 10000000005
|
|
140
|
+
outfitIds[1] = 19_000_000_006; // V4: 19000000006 -> V5: 19000000006
|
|
141
|
+
outfitIds[2] = 25_000_000_007; // V4: 25000000006 -> V5: 25000000007
|
|
142
|
+
outfitIds[3] = 43_000_000_004; // V4: 43000000005 -> V5: 43000000004
|
|
143
|
+
|
|
144
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_073, 0, outfitIds);
|
|
145
|
+
|
|
146
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
147
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_073
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Dress Banny 4000000079 (Original)
|
|
152
|
+
{
|
|
153
|
+
uint256[] memory outfitIds = new uint256[](3);
|
|
154
|
+
outfitIds[0] = 27_000_000_001; // V4: 27000000001 -> V5: 27000000001
|
|
155
|
+
outfitIds[1] = 38_000_000_002; // V4: 38000000002 -> V5: 38000000002
|
|
156
|
+
outfitIds[2] = 48_000_000_001; // V4: 48000000001 -> V5: 48000000001
|
|
157
|
+
|
|
158
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_079, 0, outfitIds);
|
|
159
|
+
|
|
160
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
161
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_079
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Dress Banny 4000000080 (Original)
|
|
166
|
+
{
|
|
167
|
+
uint256[] memory outfitIds = new uint256[](3);
|
|
168
|
+
outfitIds[0] = 13_000_000_001; // V4: 13000000001 -> V5: 13000000001
|
|
169
|
+
outfitIds[1] = 20_000_000_001; // V4: 20000000001 -> V5: 20000000001
|
|
170
|
+
outfitIds[2] = 44_000_000_003; // V4: 44000000004 -> V5: 44000000003
|
|
171
|
+
|
|
172
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_080, 5_000_000_002, outfitIds);
|
|
173
|
+
|
|
174
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
175
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_080
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Dress Banny 4000000081 (Original)
|
|
180
|
+
{
|
|
181
|
+
uint256[] memory outfitIds = new uint256[](4);
|
|
182
|
+
outfitIds[0] = 19_000_000_007; // V4: 19000000008 -> V5: 19000000007
|
|
183
|
+
outfitIds[1] = 25_000_000_008; // V4: 25000000007 -> V5: 25000000008
|
|
184
|
+
outfitIds[2] = 35_000_000_001; // V4: 35000000002 -> V5: 35000000001
|
|
185
|
+
outfitIds[3] = 43_000_000_005; // V4: 43000000006 -> V5: 43000000005
|
|
186
|
+
|
|
187
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_081, 0, outfitIds);
|
|
188
|
+
|
|
189
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
190
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_081
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Dress Banny 4000000082 (Original)
|
|
195
|
+
{
|
|
196
|
+
uint256[] memory outfitIds = new uint256[](1);
|
|
197
|
+
outfitIds[0] = 43_000_000_006; // V4: 43000000007 -> V5: 43000000006
|
|
198
|
+
|
|
199
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_082, 0, outfitIds);
|
|
200
|
+
|
|
201
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
202
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_082
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Dress Banny 4000000084 (Original)
|
|
207
|
+
{
|
|
208
|
+
uint256[] memory outfitIds = new uint256[](2);
|
|
209
|
+
outfitIds[0] = 39_000_000_001; // V4: 39000000001 -> V5: 39000000001
|
|
210
|
+
outfitIds[1] = 41_000_000_001; // V4: 41000000001 -> V5: 41000000001
|
|
211
|
+
|
|
212
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_084, 5_000_000_003, outfitIds);
|
|
213
|
+
|
|
214
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
215
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_084
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Dress Banny 4000000085 (Original)
|
|
220
|
+
{
|
|
221
|
+
uint256[] memory outfitIds = new uint256[](1);
|
|
222
|
+
outfitIds[0] = 28_000_000_006; // V4: 28000000008 -> V5: 28000000006
|
|
223
|
+
|
|
224
|
+
resolver.decorateBannyWith(address(hook), 4_000_000_085, 0, outfitIds);
|
|
225
|
+
|
|
226
|
+
MigrationHelper.verifyV4AssetMatch(
|
|
227
|
+
resolver, v4Resolver, fallbackV4Resolver, address(hook), v4HookAddress, 4_000_000_085
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Step 3: Transfer all assets to rightful owners using constructor data
|
|
232
|
+
// Generate token IDs in the same order as items appear (matching mint order)
|
|
233
|
+
// Token ID format: UPC * 1000000000 + unitNumber
|
|
234
|
+
// Note: Only banny body token IDs are guaranteed to match between V4 and V5.
|
|
235
|
+
// Outfits/backgrounds being worn by bannys may have different IDs, but that's OK
|
|
236
|
+
// since they're not transferred (only used in decorateBannyWith calls).
|
|
237
|
+
uint256[] memory generatedTokenIds = new uint256[](transferOwners.length);
|
|
238
|
+
|
|
239
|
+
generatedTokenIds[0] = 4_000_000_069; // Token ID (V4: 4000000069)
|
|
240
|
+
generatedTokenIds[1] = 4_000_000_070; // Token ID (V4: 4000000070)
|
|
241
|
+
generatedTokenIds[2] = 4_000_000_071; // Token ID (V4: 4000000071)
|
|
242
|
+
generatedTokenIds[3] = 4_000_000_072; // Token ID (V4: 4000000072)
|
|
243
|
+
generatedTokenIds[4] = 4_000_000_073; // Token ID (V4: 4000000073)
|
|
244
|
+
generatedTokenIds[5] = 4_000_000_074; // Token ID (V4: 4000000074)
|
|
245
|
+
generatedTokenIds[6] = 4_000_000_075; // Token ID (V4: 4000000075)
|
|
246
|
+
generatedTokenIds[7] = 4_000_000_076; // Token ID (V4: 4000000076)
|
|
247
|
+
generatedTokenIds[8] = 4_000_000_077; // Token ID (V4: 4000000077)
|
|
248
|
+
generatedTokenIds[9] = 4_000_000_078; // Token ID (V4: 4000000078)
|
|
249
|
+
generatedTokenIds[10] = 4_000_000_079; // Token ID (V4: 4000000079)
|
|
250
|
+
generatedTokenIds[11] = 4_000_000_080; // Token ID (V4: 4000000080)
|
|
251
|
+
generatedTokenIds[12] = 4_000_000_081; // Token ID (V4: 4000000081)
|
|
252
|
+
generatedTokenIds[13] = 4_000_000_082; // Token ID (V4: 4000000082)
|
|
253
|
+
generatedTokenIds[14] = 4_000_000_083; // Token ID (V4: 4000000083)
|
|
254
|
+
generatedTokenIds[15] = 4_000_000_084; // Token ID (V4: 4000000084)
|
|
255
|
+
generatedTokenIds[16] = 4_000_000_085; // Token ID (V4: 4000000085)
|
|
256
|
+
generatedTokenIds[17] = 4_000_000_086; // Token ID (V4: 4000000086)
|
|
257
|
+
generatedTokenIds[18] = 4_000_000_087; // Token ID (V4: 4000000087)
|
|
258
|
+
generatedTokenIds[19] = 4_000_000_088; // Token ID (V4: 4000000088)
|
|
259
|
+
generatedTokenIds[20] = 4_000_000_089; // Token ID (V4: 4000000089)
|
|
260
|
+
generatedTokenIds[21] = 4_000_000_090; // Token ID (V4: 4000000090)
|
|
261
|
+
generatedTokenIds[22] = 4_000_000_091; // Token ID (V4: 4000000091)
|
|
262
|
+
generatedTokenIds[23] = 4_000_000_092; // Token ID (V4: 4000000092)
|
|
263
|
+
generatedTokenIds[24] = 4_000_000_093; // Token ID (V4: 4000000093)
|
|
264
|
+
generatedTokenIds[25] = 4_000_000_094; // Token ID (V4: 4000000094)
|
|
265
|
+
|
|
266
|
+
uint256 successfulTransfers = 0;
|
|
267
|
+
uint256 skippedResolverOwned = 0;
|
|
268
|
+
|
|
269
|
+
for (uint256 i = 0; i < transferOwners.length; i++) {
|
|
270
|
+
uint256 tokenId = generatedTokenIds[i];
|
|
271
|
+
// Verify V4 ownership before transferring V5
|
|
272
|
+
address v4Owner = v4Hook.ownerOf(tokenId);
|
|
273
|
+
require(
|
|
274
|
+
v4Owner == transferOwners[i] || v4Owner == address(fallbackV4ResolverAddress),
|
|
275
|
+
"V4/V5 ownership mismatch for token"
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// Skip transfer if V4 owner is the resolver (resolver holds these tokens, we shouldn't transfer to
|
|
279
|
+
// resolver)
|
|
280
|
+
if (v4Owner == address(v4ResolverAddress) || v4Owner == address(fallbackV4ResolverAddress)) {
|
|
281
|
+
// Token is held by resolver, skip transfer
|
|
282
|
+
skippedResolverOwned++;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
IERC721(address(hook)).safeTransferFrom(address(this), transferOwners[i], tokenId);
|
|
287
|
+
successfulTransfers++;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Verify all expected items were processed (transferred or skipped as expected)
|
|
291
|
+
require(successfulTransfers + skippedResolverOwned == transferOwners.length, "Not all items were processed");
|
|
292
|
+
|
|
293
|
+
// Final verification: Ensure this contract no longer owns any tokens
|
|
294
|
+
// This ensures all transfers completed successfully and no tokens were left behind
|
|
295
|
+
require(hook.balanceOf(address(this)) == 0, "Contract still owns tokens after migration");
|
|
296
|
+
|
|
297
|
+
// Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
|
|
298
|
+
|
|
299
|
+
// // Collect unique owners
|
|
300
|
+
// address[] memory uniqueOwners = new address[](18);
|
|
301
|
+
|
|
302
|
+
// uniqueOwners[0] = 0x2830e21792019CE670fBc548AacB004b08c7f71f;
|
|
303
|
+
// uniqueOwners[1] = 0x46f3cC6a1c00A5cD8864d2B92f128196CAE07D15;
|
|
304
|
+
// uniqueOwners[2] = 0x8e2B25dF2484000B9127b2D2F8E92079dcEE3E48;
|
|
305
|
+
// uniqueOwners[3] = 0x817738DC393d682Ca5fBb268707b99F2aAe96baE;
|
|
306
|
+
// uniqueOwners[4] = 0x224aBa5D489675a7bD3CE07786FAda466b46FA0F;
|
|
307
|
+
// uniqueOwners[5] = 0x29f4aE3c24681940E537f72830b4Fe4076bDF9fe;
|
|
308
|
+
// uniqueOwners[6] = 0x8b80755C441d355405CA7571443Bb9247B77Ec16;
|
|
309
|
+
// uniqueOwners[7] = 0x3c2736f995535b5a755F3CE2BEb754362820671e;
|
|
310
|
+
// uniqueOwners[8] = 0x6877be9E00d0bc5886c28419901E8cC98C1c2739;
|
|
311
|
+
// uniqueOwners[9] = 0x8DFBdEEC8c5d4970BB5F481C6ec7f73fa1C65be5;
|
|
312
|
+
// uniqueOwners[10] = 0xaECD6D9172d602b93dBA3981991268b44af8096e;
|
|
313
|
+
// uniqueOwners[11] = 0xFd37f4625CA5816157D55a5b3F7Dd8DD5F8a0C2F;
|
|
314
|
+
// uniqueOwners[12] = 0x39a7B6fa1597BB6657Fe84e64E3B836c37d6F75d;
|
|
315
|
+
// uniqueOwners[13] = 0x57a482EA32c7F75A9C0734206f5BD4f9BCb38e12;
|
|
316
|
+
// uniqueOwners[14] = 0xDdB4938755C243a4f60a2f2f8f95dF4F894c58Cc;
|
|
317
|
+
// uniqueOwners[15] = 0x34aA3F359A9D614239015126635CE7732c18fDF3;
|
|
318
|
+
// uniqueOwners[16] = 0xF6cC71878e23c05406B35946CD9d378E0f2f4f2F;
|
|
319
|
+
// uniqueOwners[17] = 0xd2e44E40B5FB960A8A74dD7B9D6b7f14B805b50d;
|
|
320
|
+
|
|
321
|
+
// // Collect unique tier IDs
|
|
322
|
+
// uint256[] memory uniqueTierIds = new uint256[](16);
|
|
323
|
+
|
|
324
|
+
// uniqueTierIds[0] = 4;
|
|
325
|
+
// uniqueTierIds[1] = 5;
|
|
326
|
+
// uniqueTierIds[2] = 10;
|
|
327
|
+
// uniqueTierIds[3] = 13;
|
|
328
|
+
// uniqueTierIds[4] = 19;
|
|
329
|
+
// uniqueTierIds[5] = 20;
|
|
330
|
+
// uniqueTierIds[6] = 25;
|
|
331
|
+
// uniqueTierIds[7] = 27;
|
|
332
|
+
// uniqueTierIds[8] = 28;
|
|
333
|
+
// uniqueTierIds[9] = 35;
|
|
334
|
+
// uniqueTierIds[10] = 38;
|
|
335
|
+
// uniqueTierIds[11] = 39;
|
|
336
|
+
// uniqueTierIds[12] = 41;
|
|
337
|
+
// uniqueTierIds[13] = 43;
|
|
338
|
+
// uniqueTierIds[14] = 44;
|
|
339
|
+
// uniqueTierIds[15] = 48;
|
|
340
|
+
|
|
341
|
+
// // Verify tier balances: V5 should never exceed V4 (except for tiers owned by fallback resolver in V4)
|
|
342
|
+
// MigrationHelper.verifyTierBalances(
|
|
343
|
+
// hookAddress,
|
|
344
|
+
// v4HookAddress,
|
|
345
|
+
// fallbackV4ResolverAddress,
|
|
346
|
+
// uniqueOwners,
|
|
347
|
+
// uniqueTierIds
|
|
348
|
+
// );
|
|
349
|
+
}
|
|
350
|
+
}
|