neozipkit 0.1.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 +400 -0
- package/contracts/Lock.sol +34 -0
- package/contracts/bytecode.txt +1 -0
- package/contracts/compile-contract.js +168 -0
- package/contracts/deploy/deploy-both-contracts.js +286 -0
- package/contracts/deploy/deploy-enhanced-contract.js +197 -0
- package/contracts/deploy/deploy-private-contract.js +190 -0
- package/contracts/deploy/deploy-public-clean.js +1063 -0
- package/contracts/deploy/deploy-public-contract.js +1107 -0
- package/contracts/deployment.config.example.js +25 -0
- package/contracts/remix-compile.js +222 -0
- package/contracts/setup-deployment.js +51 -0
- package/contracts/src/NZIP-NFT-Private.sol +350 -0
- package/contracts/src/NZIP-NFT.sol +265 -0
- package/contracts/src/ZipFileNFT-DEPRECATED-6field.sol +260 -0
- package/contracts/src/ZipFileNFT-DEPRECATED-Enhanced.sol +289 -0
- package/dist/browser/CertificateGeneratorBrowser.d.ts +75 -0
- package/dist/browser/CertificateGeneratorBrowser.js +433 -0
- package/dist/browser/TokenVerifierBrowser.d.ts +76 -0
- package/dist/browser/TokenVerifierBrowser.js +299 -0
- package/dist/browser/ZipKitBrowser.d.ts +18 -0
- package/dist/browser/ZipKitBrowser.js +250 -0
- package/dist/browser/ZipKitStampBrowser.d.ts +2 -0
- package/dist/browser/ZipKitStampBrowser.js +12 -0
- package/dist/browser-index.d.ts +21 -0
- package/dist/browser-index.js +58 -0
- package/dist/browser.d.ts +21 -0
- package/dist/browser.js +58 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +76 -0
- package/dist/server/blockchain/CertificateToken.d.ts +48 -0
- package/dist/server/blockchain/CertificateToken.js +386 -0
- package/dist/server/blockchain/NFTMinter.d.ts +41 -0
- package/dist/server/blockchain/NFTMinter.js +323 -0
- package/dist/server/blockchain/TokenQuerier.d.ts +31 -0
- package/dist/server/blockchain/TokenQuerier.js +259 -0
- package/dist/server/blockchain/TokenVerifier.d.ts +20 -0
- package/dist/server/blockchain/TokenVerifier.js +395 -0
- package/dist/server/blockchain/WalletAnalyzer.d.ts +81 -0
- package/dist/server/blockchain/WalletAnalyzer.js +356 -0
- package/dist/server/blockchain/WalletFormatter.d.ts +39 -0
- package/dist/server/blockchain/WalletFormatter.js +196 -0
- package/dist/server/blockchain/WalletManager.d.ts +46 -0
- package/dist/server/blockchain/WalletManager.js +294 -0
- package/dist/server/blockchain/ZipMetadata.d.ts +27 -0
- package/dist/server/blockchain/ZipMetadata.js +131 -0
- package/dist/server/blockchain/ZipTokenProcessor.d.ts +44 -0
- package/dist/server/blockchain/ZipTokenProcessor.js +204 -0
- package/dist/server/blockchain/constants.d.ts +102 -0
- package/dist/server/blockchain/constants.js +968 -0
- package/dist/server/blockchain/index.d.ts +9 -0
- package/dist/server/blockchain/index.js +44 -0
- package/dist/server/blockchain/test-certificate.d.ts +8 -0
- package/dist/server/blockchain/test-certificate.js +100 -0
- package/dist/server/blockchain/types.d.ts +69 -0
- package/dist/server/blockchain/types.js +51 -0
- package/dist/server/platform/server/ZipKitServer.d.ts +105 -0
- package/dist/server/platform/server/ZipKitServer.js +437 -0
- package/dist/server/platform/servercomponents/ZipKitOTS.d.ts +91 -0
- package/dist/server/platform/servercomponents/ZipKitOTS.js +271 -0
- package/dist/shared/ZipEntry.d.ts +131 -0
- package/dist/shared/ZipEntry.js +686 -0
- package/dist/shared/ZipKit.d.ts +249 -0
- package/dist/shared/ZipKit.js +789 -0
- package/dist/shared/components/CertificateOTS.d.ts +15 -0
- package/dist/shared/components/CertificateOTS.js +116 -0
- package/dist/shared/components/FileSys.d.ts +2 -0
- package/dist/shared/components/FileSys.js +113 -0
- package/dist/shared/components/HashAccumulator.d.ts +55 -0
- package/dist/shared/components/HashAccumulator.js +100 -0
- package/dist/shared/components/Support.d.ts +63 -0
- package/dist/shared/components/Support.js +70 -0
- package/dist/shared/components/Util.d.ts +21 -0
- package/dist/shared/components/Util.js +115 -0
- package/dist/shared/components/ZipCrypto.d.ts +3 -0
- package/dist/shared/components/ZipCrypto.js +78 -0
- package/dist/shared/components/merkleTree.d.ts +66 -0
- package/dist/shared/components/merkleTree.js +136 -0
- package/dist/shared/constants/Errors.d.ts +53 -0
- package/dist/shared/constants/Errors.js +69 -0
- package/dist/shared/constants/Headers.d.ts +167 -0
- package/dist/shared/constants/Headers.js +191 -0
- package/dist/shared/types/index.d.ts +21 -0
- package/dist/shared/types/index.js +3 -0
- package/dist/shared/types.d.ts +33 -0
- package/dist/shared/types.js +8 -0
- package/dist/shared/version.d.ts +4 -0
- package/dist/shared/version.js +7 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.js +3 -0
- package/examples/unzip-token.ts +488 -0
- package/examples/zip-token.ts +604 -0
- package/package.json +117 -0
- package/src/browser/CertificateGeneratorBrowser.ts +498 -0
- package/src/browser/TokenVerifierBrowser.ts +344 -0
- package/src/browser/ZipKitBrowser.ts +242 -0
- package/src/browser/ZipKitStampBrowser.ts +9 -0
- package/src/browser-index.ts +36 -0
- package/src/index.ts +48 -0
- package/src/server/blockchain/CertificateToken.ts +444 -0
- package/src/server/blockchain/NFTMinter.ts +357 -0
- package/src/server/blockchain/TokenQuerier.ts +287 -0
- package/src/server/blockchain/TokenVerifier.ts +453 -0
- package/src/server/blockchain/WalletAnalyzer.ts +397 -0
- package/src/server/blockchain/WalletFormatter.ts +206 -0
- package/src/server/blockchain/WalletManager.ts +294 -0
- package/src/server/blockchain/ZipMetadata.ts +117 -0
- package/src/server/blockchain/ZipTokenProcessor.ts +234 -0
- package/src/server/blockchain/constants.ts +969 -0
- package/src/server/blockchain/index.ts +42 -0
- package/src/server/blockchain/test-certificate.ts +137 -0
- package/src/server/blockchain/types.ts +134 -0
- package/src/server/platform/server/ZipKitServer.ts +459 -0
- package/src/server/platform/servercomponents/ZipKitOTS.ts +313 -0
- package/src/server/platform/servercomponents/opentimestamps.d.ts +23 -0
- package/src/shared/ZipEntry.ts +767 -0
- package/src/shared/ZipKit.ts +899 -0
- package/src/shared/components/CertificateOTS.ts +132 -0
- package/src/shared/components/FileSys.ts +87 -0
- package/src/shared/components/HashAccumulator.ts +113 -0
- package/src/shared/components/Support.ts +77 -0
- package/src/shared/components/Util.ts +113 -0
- package/src/shared/components/ZipCrypto.ts +91 -0
- package/src/shared/components/merkleTree.ts +162 -0
- package/src/shared/constants/Errors.ts +82 -0
- package/src/shared/constants/Headers.ts +203 -0
- package/src/shared/types/index.ts +25 -0
- package/src/shared/types/modules.d.ts +22 -0
- package/src/shared/types/opentimestamps.d.ts +23 -0
- package/src/shared/types.d.ts +8 -0
- package/src/shared/types.ts +43 -0
- package/src/shared/version.ts +4 -0
- package/src/types/index.ts +25 -0
- package/src/types/modules.d.ts +22 -0
- package/src/types/opentimestamps.d.ts +23 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as readline from 'readline';
|
|
4
|
+
import { ethers } from 'ethers';
|
|
5
|
+
import {
|
|
6
|
+
WalletSetupResult,
|
|
7
|
+
WalletInfo,
|
|
8
|
+
NetworkConfig,
|
|
9
|
+
NETWORKS,
|
|
10
|
+
MintingOptions
|
|
11
|
+
} from './types';
|
|
12
|
+
|
|
13
|
+
export class WalletManager {
|
|
14
|
+
private wallet: ethers.Wallet | null = null;
|
|
15
|
+
private provider: ethers.JsonRpcProvider | null = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Prompts the user for input
|
|
19
|
+
*/
|
|
20
|
+
private async promptUser(question: string): Promise<string> {
|
|
21
|
+
const rl = readline.createInterface({
|
|
22
|
+
input: process.stdin,
|
|
23
|
+
output: process.stdout
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return new Promise<string>((resolve) => {
|
|
27
|
+
rl.question(question, (answer: string) => {
|
|
28
|
+
rl.close();
|
|
29
|
+
resolve(answer.trim());
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Looks for existing wallet files in the current directory and wallet subdirectory
|
|
36
|
+
*/
|
|
37
|
+
private findExistingWallets(): string[] {
|
|
38
|
+
const walletFiles: string[] = [];
|
|
39
|
+
const currentDir = process.cwd();
|
|
40
|
+
const walletDir = path.join(currentDir, 'wallet');
|
|
41
|
+
|
|
42
|
+
// Common wallet file names to look for
|
|
43
|
+
const walletFileNames = [
|
|
44
|
+
'neozip-wallet.json',
|
|
45
|
+
'wallet.json',
|
|
46
|
+
'private-key.txt',
|
|
47
|
+
'private.key'
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
// Search in current directory
|
|
51
|
+
for (const fileName of walletFileNames) {
|
|
52
|
+
const filePath = path.join(currentDir, fileName);
|
|
53
|
+
if (fs.existsSync(filePath)) {
|
|
54
|
+
walletFiles.push(filePath);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Search in wallet subdirectory
|
|
59
|
+
if (fs.existsSync(walletDir)) {
|
|
60
|
+
for (const fileName of walletFileNames) {
|
|
61
|
+
const filePath = path.join(walletDir, fileName);
|
|
62
|
+
if (fs.existsSync(filePath)) {
|
|
63
|
+
walletFiles.push(filePath);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return walletFiles;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Loads wallet information from a file
|
|
73
|
+
*/
|
|
74
|
+
private loadWalletFromFile(filePath: string): string | null {
|
|
75
|
+
try {
|
|
76
|
+
const content = fs.readFileSync(filePath, 'utf8').trim();
|
|
77
|
+
|
|
78
|
+
// Try to parse as JSON first (for neozip-wallet.json format)
|
|
79
|
+
try {
|
|
80
|
+
const walletData = JSON.parse(content);
|
|
81
|
+
if (walletData.privateKey) {
|
|
82
|
+
console.log(`Found wallet file: ${filePath}`);
|
|
83
|
+
console.log(`Wallet address: ${walletData.address}`);
|
|
84
|
+
return walletData.privateKey;
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
// If not JSON, treat as plain private key
|
|
88
|
+
if (content.startsWith('0x') && content.length === 66) {
|
|
89
|
+
console.log(`Found private key file: ${filePath}`);
|
|
90
|
+
return content;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return null;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.warn(`Could not read wallet file ${filePath}:`, error);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Sets up a Base wallet for token operations
|
|
103
|
+
*/
|
|
104
|
+
async setupWallet(options: MintingOptions): Promise<WalletSetupResult> {
|
|
105
|
+
try {
|
|
106
|
+
const networkConfig = NETWORKS[options.network] || NETWORKS['base-sepolia'];
|
|
107
|
+
|
|
108
|
+
let privateKey: string;
|
|
109
|
+
|
|
110
|
+
// Check if wallet is explicitly provided via command line
|
|
111
|
+
if (options.wallet) {
|
|
112
|
+
if (fs.existsSync(options.wallet)) {
|
|
113
|
+
// Read wallet from specified file
|
|
114
|
+
const loadedKey = this.loadWalletFromFile(options.wallet);
|
|
115
|
+
if (!loadedKey) {
|
|
116
|
+
throw new Error(`Could not load valid private key from ${options.wallet}`);
|
|
117
|
+
}
|
|
118
|
+
privateKey = loadedKey;
|
|
119
|
+
} else {
|
|
120
|
+
// Use directly provided private key or mnemonic
|
|
121
|
+
privateKey = options.wallet;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// Look for existing wallet files
|
|
125
|
+
const existingWallets = this.findExistingWallets();
|
|
126
|
+
|
|
127
|
+
if (existingWallets.length > 0) {
|
|
128
|
+
// Automatically use the first available wallet
|
|
129
|
+
const selectedWallet = existingWallets[0];
|
|
130
|
+
const relativePath = path.relative(process.cwd(), selectedWallet);
|
|
131
|
+
console.log(`Using existing wallet: ${relativePath}`);
|
|
132
|
+
|
|
133
|
+
const loadedKey = this.loadWalletFromFile(selectedWallet);
|
|
134
|
+
if (!loadedKey) {
|
|
135
|
+
throw new Error(`Could not load valid private key from ${selectedWallet}`);
|
|
136
|
+
}
|
|
137
|
+
privateKey = loadedKey;
|
|
138
|
+
} else {
|
|
139
|
+
// Automatically create new wallet
|
|
140
|
+
console.log('No existing wallet found. Creating new wallet...');
|
|
141
|
+
privateKey = await this.createNewWallet();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Create wallet instance without provider first
|
|
146
|
+
this.wallet = new ethers.Wallet(privateKey);
|
|
147
|
+
console.log(`Using wallet: ${this.wallet.address}`);
|
|
148
|
+
|
|
149
|
+
// Try to connect to the network - FAIL if connection fails
|
|
150
|
+
const networkConnected = await this.connectToNetwork(networkConfig, options.mintToken);
|
|
151
|
+
|
|
152
|
+
if (!networkConnected) {
|
|
153
|
+
return {
|
|
154
|
+
wallet: null,
|
|
155
|
+
provider: null,
|
|
156
|
+
success: false,
|
|
157
|
+
message: `Failed to connect to ${networkConfig.name} network. Blockchain operations require network connectivity.`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
wallet: this.wallet,
|
|
163
|
+
provider: this.provider,
|
|
164
|
+
success: true,
|
|
165
|
+
message: `Wallet setup successful for ${networkConfig.name}`
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error('Error setting up wallet:', error);
|
|
170
|
+
return {
|
|
171
|
+
wallet: null,
|
|
172
|
+
provider: null,
|
|
173
|
+
success: false,
|
|
174
|
+
message: `Wallet setup failed: ${error instanceof Error ? error.message : String(error)}`
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Creates a new wallet and saves it to file
|
|
181
|
+
*/
|
|
182
|
+
private async createNewWallet(): Promise<string> {
|
|
183
|
+
console.log('Creating a new wallet...');
|
|
184
|
+
const newWallet = ethers.Wallet.createRandom();
|
|
185
|
+
|
|
186
|
+
// Save the wallet info
|
|
187
|
+
const walletInfo: WalletInfo = {
|
|
188
|
+
address: newWallet.address,
|
|
189
|
+
privateKey: newWallet.privateKey,
|
|
190
|
+
mnemonic: newWallet.mnemonic?.phrase || ""
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// Ensure wallet directory exists
|
|
194
|
+
const walletDir = path.join(process.cwd(), 'wallet');
|
|
195
|
+
if (!fs.existsSync(walletDir)) {
|
|
196
|
+
fs.mkdirSync(walletDir, { recursive: true });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const walletFilePath = path.join(walletDir, 'neozip-wallet.json');
|
|
200
|
+
fs.writeFileSync(walletFilePath, JSON.stringify(walletInfo, null, 2));
|
|
201
|
+
|
|
202
|
+
console.log(`New wallet created and saved to ${walletFilePath}`);
|
|
203
|
+
console.log(`Wallet address: ${newWallet.address}`);
|
|
204
|
+
console.log(`IMPORTANT: Please fund this wallet with BASE to use for minting NFTs!`);
|
|
205
|
+
|
|
206
|
+
return newWallet.privateKey;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Connects to the specified blockchain network
|
|
211
|
+
*/
|
|
212
|
+
private async connectToNetwork(networkConfig: NetworkConfig, mintToken: boolean): Promise<boolean> {
|
|
213
|
+
try {
|
|
214
|
+
console.log(`Attempting to connect to ${networkConfig.name} network...`);
|
|
215
|
+
this.provider = new ethers.JsonRpcProvider(networkConfig.rpcUrl);
|
|
216
|
+
|
|
217
|
+
// Set a timeout for network connection
|
|
218
|
+
let networkTimedOut = false;
|
|
219
|
+
const networkTimeout = setTimeout(() => {
|
|
220
|
+
networkTimedOut = true;
|
|
221
|
+
console.error("Network connection timeout");
|
|
222
|
+
}, 5000);
|
|
223
|
+
|
|
224
|
+
// Test the connection
|
|
225
|
+
const network = await Promise.race([
|
|
226
|
+
this.provider.getNetwork(),
|
|
227
|
+
new Promise((_, reject) =>
|
|
228
|
+
setTimeout(() => {
|
|
229
|
+
if (networkTimedOut) reject(new Error("Network connection timeout"));
|
|
230
|
+
}, 5100)
|
|
231
|
+
)
|
|
232
|
+
]);
|
|
233
|
+
|
|
234
|
+
clearTimeout(networkTimeout);
|
|
235
|
+
|
|
236
|
+
// Connect wallet to provider
|
|
237
|
+
if (this.wallet) {
|
|
238
|
+
this.wallet = this.wallet.connect(this.provider);
|
|
239
|
+
|
|
240
|
+
// Check wallet balance
|
|
241
|
+
const balance = await this.provider.getBalance(this.wallet.address);
|
|
242
|
+
const balanceEth = ethers.formatEther(balance);
|
|
243
|
+
console.log(`Wallet balance: ${balanceEth} ETH`);
|
|
244
|
+
|
|
245
|
+
// Check if balance is sufficient for minting
|
|
246
|
+
const minBalance = 0.0001;
|
|
247
|
+
if (parseFloat(balanceEth) < minBalance && mintToken) {
|
|
248
|
+
console.error(`ERROR: Insufficient balance (${balanceEth} ETH). Minimum required: ${minBalance} ETH`);
|
|
249
|
+
console.error('Get testnet ETH from: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet');
|
|
250
|
+
throw new Error(`Insufficient balance for minting. Current: ${balanceEth} ETH, Required: ${minBalance} ETH`);
|
|
251
|
+
} else if (mintToken) {
|
|
252
|
+
console.log(`✅ Sufficient balance for token minting`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
console.log(`✅ Successfully connected to ${networkConfig.name}`);
|
|
257
|
+
return true;
|
|
258
|
+
|
|
259
|
+
} catch (networkError: unknown) {
|
|
260
|
+
const errorMessage = networkError instanceof Error ? networkError.message : String(networkError);
|
|
261
|
+
console.error(`Failed to connect to ${networkConfig.name} network: ${errorMessage}`);
|
|
262
|
+
this.provider = null;
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Gets the current wallet instance
|
|
269
|
+
*/
|
|
270
|
+
getWallet(): ethers.Wallet | null {
|
|
271
|
+
return this.wallet;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Gets the current provider instance
|
|
276
|
+
*/
|
|
277
|
+
getProvider(): ethers.JsonRpcProvider | null {
|
|
278
|
+
return this.provider;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Checks if wallet is connected and ready for transactions
|
|
283
|
+
*/
|
|
284
|
+
isReady(): boolean {
|
|
285
|
+
return this.wallet !== null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Checks if provider is connected
|
|
290
|
+
*/
|
|
291
|
+
isOnline(): boolean {
|
|
292
|
+
return this.provider !== null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { NZipTokenInfo, ContractInfo, NETWORKS } from './types';
|
|
4
|
+
|
|
5
|
+
export class ZipMetadata {
|
|
6
|
+
/**
|
|
7
|
+
* Creates the META-INF/NZIP.TOKEN content
|
|
8
|
+
*/
|
|
9
|
+
static createTokenInfo(
|
|
10
|
+
tokenId: string,
|
|
11
|
+
transactionHash: string,
|
|
12
|
+
contractInfo: ContractInfo,
|
|
13
|
+
merkleRoot: string,
|
|
14
|
+
fileName: string,
|
|
15
|
+
network: string,
|
|
16
|
+
blockNumber?: number,
|
|
17
|
+
ipfsHash?: string,
|
|
18
|
+
creationTimestamp?: number
|
|
19
|
+
): NZipTokenInfo {
|
|
20
|
+
const networkConfig = NETWORKS[network];
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
version: "1.0",
|
|
24
|
+
tokenId,
|
|
25
|
+
contractAddress: contractInfo.address,
|
|
26
|
+
network: networkConfig.name,
|
|
27
|
+
networkChainId: networkConfig.chainId,
|
|
28
|
+
transactionHash,
|
|
29
|
+
merkleRoot,
|
|
30
|
+
fileName,
|
|
31
|
+
mintedAt: new Date().toISOString(),
|
|
32
|
+
creationTimestamp,
|
|
33
|
+
blockNumber,
|
|
34
|
+
ipfsHash
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates the META-INF directory and NZIP.TOKEN file
|
|
40
|
+
*/
|
|
41
|
+
static async createTokenFile(tokenInfo: NZipTokenInfo): Promise<string> {
|
|
42
|
+
const currentDir = process.cwd();
|
|
43
|
+
|
|
44
|
+
// Create META-INF directory in current directory
|
|
45
|
+
const metaInfDir = path.join(currentDir, 'META-INF');
|
|
46
|
+
if (!fs.existsSync(metaInfDir)) {
|
|
47
|
+
fs.mkdirSync(metaInfDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Create NZIP.TOKEN file
|
|
51
|
+
const tokenFilePath = path.join(metaInfDir, 'NZIP.TOKEN');
|
|
52
|
+
const tokenContent = JSON.stringify(tokenInfo, null, 2);
|
|
53
|
+
|
|
54
|
+
fs.writeFileSync(tokenFilePath, tokenContent);
|
|
55
|
+
console.log(`Created token metadata file: ${path.relative(currentDir, tokenFilePath)}`);
|
|
56
|
+
|
|
57
|
+
return tokenFilePath;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reads token information from a ZIP file's META-INF/NZIP.TOKEN
|
|
62
|
+
*/
|
|
63
|
+
static readTokenInfo(zipFilePath: string): NZipTokenInfo | null {
|
|
64
|
+
// This would require extracting the META-INF/NZIP.TOKEN file from the ZIP
|
|
65
|
+
// For now, return null - this can be implemented when needed
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Validates token information structure
|
|
71
|
+
*/
|
|
72
|
+
static validateTokenInfo(tokenInfo: any): tokenInfo is NZipTokenInfo {
|
|
73
|
+
return (
|
|
74
|
+
typeof tokenInfo === 'object' &&
|
|
75
|
+
typeof tokenInfo.version === 'string' &&
|
|
76
|
+
typeof tokenInfo.tokenId === 'string' &&
|
|
77
|
+
typeof tokenInfo.contractAddress === 'string' &&
|
|
78
|
+
typeof tokenInfo.network === 'string' &&
|
|
79
|
+
typeof tokenInfo.networkChainId === 'number' &&
|
|
80
|
+
typeof tokenInfo.transactionHash === 'string' &&
|
|
81
|
+
typeof tokenInfo.merkleRoot === 'string' &&
|
|
82
|
+
typeof tokenInfo.fileName === 'string' &&
|
|
83
|
+
typeof tokenInfo.mintedAt === 'string'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Creates a human-readable summary of the token information
|
|
89
|
+
*/
|
|
90
|
+
static createTokenSummary(tokenInfo: NZipTokenInfo): string {
|
|
91
|
+
return `
|
|
92
|
+
═══════════════════════════════════════════════════════════════
|
|
93
|
+
NeoZip Token Information
|
|
94
|
+
═══════════════════════════════════════════════════════════════
|
|
95
|
+
Token ID: ${tokenInfo.tokenId}
|
|
96
|
+
Contract: ${tokenInfo.contractAddress}
|
|
97
|
+
Network: ${tokenInfo.network} (Chain ID: ${tokenInfo.networkChainId})
|
|
98
|
+
Transaction: ${tokenInfo.transactionHash}
|
|
99
|
+
Block Number: ${tokenInfo.blockNumber || 'Unknown'}
|
|
100
|
+
Merkle Root: ${tokenInfo.merkleRoot}
|
|
101
|
+
File Name: ${tokenInfo.fileName}
|
|
102
|
+
Minted At: ${tokenInfo.mintedAt}
|
|
103
|
+
IPFS Hash: ${tokenInfo.ipfsHash || 'Not uploaded'}
|
|
104
|
+
Version: ${tokenInfo.version}
|
|
105
|
+
═══════════════════════════════════════════════════════════════
|
|
106
|
+
`.trim();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* No cleanup needed since we write to the current directory
|
|
111
|
+
*/
|
|
112
|
+
static cleanupTokenFile(tokenFilePath: string): void {
|
|
113
|
+
// No cleanup needed since we're writing to the current directory
|
|
114
|
+
// The META-INF/NZIP.TOKEN file should remain in the current directory
|
|
115
|
+
console.log(`Token metadata file preserved at: ${path.relative(process.cwd(), tokenFilePath)}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { ethers } from 'ethers';
|
|
4
|
+
import { WalletManager } from './WalletManager';
|
|
5
|
+
import { NFTMinter } from './NFTMinter';
|
|
6
|
+
import { ZipMetadata } from './ZipMetadata';
|
|
7
|
+
import {
|
|
8
|
+
MintingOptions,
|
|
9
|
+
ZipTokenData,
|
|
10
|
+
WalletSetupResult,
|
|
11
|
+
MintingResult,
|
|
12
|
+
ContractInfo,
|
|
13
|
+
NZipTokenInfo
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
interface ProcessorState {
|
|
17
|
+
walletSetup?: WalletSetupResult;
|
|
18
|
+
mintingResult?: MintingResult;
|
|
19
|
+
tokenInfo?: NZipTokenInfo;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ZipTokenProcessor {
|
|
24
|
+
private walletManager: WalletManager;
|
|
25
|
+
private nftMinter: NFTMinter | null = null;
|
|
26
|
+
private zipTokenData: ZipTokenData;
|
|
27
|
+
|
|
28
|
+
constructor(zipFile: string, merkleRoot: string, options: MintingOptions) {
|
|
29
|
+
this.walletManager = new WalletManager();
|
|
30
|
+
|
|
31
|
+
this.zipTokenData = {
|
|
32
|
+
zipFile,
|
|
33
|
+
merkleRoot,
|
|
34
|
+
fileName: path.basename(zipFile),
|
|
35
|
+
timestamp: new Date().toISOString()
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Processes the complete ZIP token workflow
|
|
41
|
+
*/
|
|
42
|
+
async processZipToken(options: MintingOptions): Promise<ProcessorState> {
|
|
43
|
+
const state: ProcessorState = {};
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Setup wallet if needed
|
|
47
|
+
if (options.wallet || options.mintToken) {
|
|
48
|
+
console.log('Setting up wallet...');
|
|
49
|
+
const walletResult = await this.walletManager.setupWallet(options);
|
|
50
|
+
state.walletSetup = walletResult;
|
|
51
|
+
|
|
52
|
+
if (!walletResult.success) {
|
|
53
|
+
state.error = `Wallet setup failed: ${walletResult.message}`;
|
|
54
|
+
return state;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Initialize NFT minter with wallet and provider
|
|
58
|
+
this.nftMinter = new NFTMinter(
|
|
59
|
+
walletResult.wallet,
|
|
60
|
+
walletResult.provider
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Mint token if requested
|
|
65
|
+
if (options.mintToken && this.nftMinter) {
|
|
66
|
+
console.log('Minting NFT token...');
|
|
67
|
+
const mintingResult = await this.nftMinter.mintZipFileNFT(this.zipTokenData);
|
|
68
|
+
state.mintingResult = mintingResult;
|
|
69
|
+
|
|
70
|
+
if (!mintingResult.success) {
|
|
71
|
+
state.error = `Minting failed: ${mintingResult.message}`;
|
|
72
|
+
return state;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Validate that we have complete token data for successful minting
|
|
76
|
+
if (!mintingResult.tokenId || !mintingResult.txHash) {
|
|
77
|
+
state.error = `Minting incomplete: Missing token ID or transaction hash`;
|
|
78
|
+
return state;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log('Preparing token metadata...');
|
|
82
|
+
|
|
83
|
+
// Check if this was an existing token (message contains "existing token")
|
|
84
|
+
if (mintingResult.message.includes('existing token')) {
|
|
85
|
+
console.log('Using existing token from your wallet...');
|
|
86
|
+
// Create token info from existing token data
|
|
87
|
+
const tokenInfo = await this.createTokenInfoFromExisting(mintingResult, options);
|
|
88
|
+
if (!tokenInfo) {
|
|
89
|
+
state.error = `Failed to create token metadata from existing token`;
|
|
90
|
+
return state;
|
|
91
|
+
}
|
|
92
|
+
state.tokenInfo = tokenInfo;
|
|
93
|
+
} else {
|
|
94
|
+
// Create token info from new minting
|
|
95
|
+
const tokenInfo = this.createTokenInfo(mintingResult, options);
|
|
96
|
+
if (!tokenInfo) {
|
|
97
|
+
state.error = `Failed to create token metadata`;
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
state.tokenInfo = tokenInfo;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log('\n' + ZipMetadata.createTokenSummary(state.tokenInfo));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return state;
|
|
107
|
+
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
110
|
+
console.error('Error in ZIP token processing:', error);
|
|
111
|
+
state.error = `Processing error: ${errorMessage}`;
|
|
112
|
+
return state;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Gets the ZIP token data
|
|
118
|
+
*/
|
|
119
|
+
getZipTokenData(): ZipTokenData {
|
|
120
|
+
return this.zipTokenData;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Gets the wallet manager instance
|
|
125
|
+
*/
|
|
126
|
+
getWalletManager(): WalletManager {
|
|
127
|
+
return this.walletManager;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Gets the NFT minter instance
|
|
132
|
+
*/
|
|
133
|
+
getNFTMinter(): NFTMinter | null {
|
|
134
|
+
return this.nftMinter;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Loads contract deployment information
|
|
139
|
+
*/
|
|
140
|
+
private loadContractInfo(): ContractInfo | null {
|
|
141
|
+
try {
|
|
142
|
+
const contractInfoPath = path.join(process.cwd(), 'zipfile-nft-deployment.json');
|
|
143
|
+
|
|
144
|
+
if (!fs.existsSync(contractInfoPath)) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const contractInfo = JSON.parse(fs.readFileSync(contractInfoPath, 'utf8'));
|
|
149
|
+
return contractInfo as ContractInfo;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Error loading contract info:', error);
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Creates token information object
|
|
158
|
+
*/
|
|
159
|
+
private createTokenInfo(
|
|
160
|
+
mintingResult: MintingResult,
|
|
161
|
+
options: MintingOptions
|
|
162
|
+
): NZipTokenInfo | null {
|
|
163
|
+
if (!mintingResult.success || !mintingResult.tokenId || !mintingResult.txHash) {
|
|
164
|
+
console.error('Cannot create token metadata: minting was not successful or missing token data');
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
// Load contract information
|
|
170
|
+
const contractInfo = this.loadContractInfo();
|
|
171
|
+
if (!contractInfo) {
|
|
172
|
+
console.error('Cannot load contract information for token metadata');
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Create token information with REAL data only
|
|
177
|
+
const tokenInfo = ZipMetadata.createTokenInfo(
|
|
178
|
+
mintingResult.tokenId,
|
|
179
|
+
mintingResult.txHash,
|
|
180
|
+
contractInfo,
|
|
181
|
+
this.zipTokenData.merkleRoot,
|
|
182
|
+
this.zipTokenData.fileName,
|
|
183
|
+
options.network,
|
|
184
|
+
undefined, // blockNumber - will be filled later if needed
|
|
185
|
+
undefined, // ipfsHash - not implemented yet
|
|
186
|
+
Math.floor(Date.now() / 1000) // creationTimestamp
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return tokenInfo;
|
|
190
|
+
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error('Error creating token metadata:', error);
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creates token information object from existing token
|
|
199
|
+
*/
|
|
200
|
+
private async createTokenInfoFromExisting(
|
|
201
|
+
mintingResult: MintingResult,
|
|
202
|
+
options: MintingOptions
|
|
203
|
+
): Promise<NZipTokenInfo | null> {
|
|
204
|
+
if (!mintingResult.success || !mintingResult.tokenId || !mintingResult.txHash) {
|
|
205
|
+
console.error('Cannot create token metadata: minting was not successful or missing token data');
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
// Load contract information
|
|
211
|
+
const contractInfo = this.loadContractInfo();
|
|
212
|
+
if (!contractInfo) {
|
|
213
|
+
console.error('Cannot load contract information for token metadata');
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Create token information with REAL data only
|
|
218
|
+
const tokenInfo = ZipMetadata.createTokenInfo(
|
|
219
|
+
mintingResult.tokenId,
|
|
220
|
+
mintingResult.txHash,
|
|
221
|
+
contractInfo,
|
|
222
|
+
this.zipTokenData.merkleRoot,
|
|
223
|
+
this.zipTokenData.fileName,
|
|
224
|
+
options.network
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
return tokenInfo;
|
|
228
|
+
|
|
229
|
+
} catch (error) {
|
|
230
|
+
console.error('Error creating token metadata:', error);
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|