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.
Files changed (135) hide show
  1. package/README.md +400 -0
  2. package/contracts/Lock.sol +34 -0
  3. package/contracts/bytecode.txt +1 -0
  4. package/contracts/compile-contract.js +168 -0
  5. package/contracts/deploy/deploy-both-contracts.js +286 -0
  6. package/contracts/deploy/deploy-enhanced-contract.js +197 -0
  7. package/contracts/deploy/deploy-private-contract.js +190 -0
  8. package/contracts/deploy/deploy-public-clean.js +1063 -0
  9. package/contracts/deploy/deploy-public-contract.js +1107 -0
  10. package/contracts/deployment.config.example.js +25 -0
  11. package/contracts/remix-compile.js +222 -0
  12. package/contracts/setup-deployment.js +51 -0
  13. package/contracts/src/NZIP-NFT-Private.sol +350 -0
  14. package/contracts/src/NZIP-NFT.sol +265 -0
  15. package/contracts/src/ZipFileNFT-DEPRECATED-6field.sol +260 -0
  16. package/contracts/src/ZipFileNFT-DEPRECATED-Enhanced.sol +289 -0
  17. package/dist/browser/CertificateGeneratorBrowser.d.ts +75 -0
  18. package/dist/browser/CertificateGeneratorBrowser.js +433 -0
  19. package/dist/browser/TokenVerifierBrowser.d.ts +76 -0
  20. package/dist/browser/TokenVerifierBrowser.js +299 -0
  21. package/dist/browser/ZipKitBrowser.d.ts +18 -0
  22. package/dist/browser/ZipKitBrowser.js +250 -0
  23. package/dist/browser/ZipKitStampBrowser.d.ts +2 -0
  24. package/dist/browser/ZipKitStampBrowser.js +12 -0
  25. package/dist/browser-index.d.ts +21 -0
  26. package/dist/browser-index.js +58 -0
  27. package/dist/browser.d.ts +21 -0
  28. package/dist/browser.js +58 -0
  29. package/dist/index.d.ts +29 -0
  30. package/dist/index.js +76 -0
  31. package/dist/server/blockchain/CertificateToken.d.ts +48 -0
  32. package/dist/server/blockchain/CertificateToken.js +386 -0
  33. package/dist/server/blockchain/NFTMinter.d.ts +41 -0
  34. package/dist/server/blockchain/NFTMinter.js +323 -0
  35. package/dist/server/blockchain/TokenQuerier.d.ts +31 -0
  36. package/dist/server/blockchain/TokenQuerier.js +259 -0
  37. package/dist/server/blockchain/TokenVerifier.d.ts +20 -0
  38. package/dist/server/blockchain/TokenVerifier.js +395 -0
  39. package/dist/server/blockchain/WalletAnalyzer.d.ts +81 -0
  40. package/dist/server/blockchain/WalletAnalyzer.js +356 -0
  41. package/dist/server/blockchain/WalletFormatter.d.ts +39 -0
  42. package/dist/server/blockchain/WalletFormatter.js +196 -0
  43. package/dist/server/blockchain/WalletManager.d.ts +46 -0
  44. package/dist/server/blockchain/WalletManager.js +294 -0
  45. package/dist/server/blockchain/ZipMetadata.d.ts +27 -0
  46. package/dist/server/blockchain/ZipMetadata.js +131 -0
  47. package/dist/server/blockchain/ZipTokenProcessor.d.ts +44 -0
  48. package/dist/server/blockchain/ZipTokenProcessor.js +204 -0
  49. package/dist/server/blockchain/constants.d.ts +102 -0
  50. package/dist/server/blockchain/constants.js +968 -0
  51. package/dist/server/blockchain/index.d.ts +9 -0
  52. package/dist/server/blockchain/index.js +44 -0
  53. package/dist/server/blockchain/test-certificate.d.ts +8 -0
  54. package/dist/server/blockchain/test-certificate.js +100 -0
  55. package/dist/server/blockchain/types.d.ts +69 -0
  56. package/dist/server/blockchain/types.js +51 -0
  57. package/dist/server/platform/server/ZipKitServer.d.ts +105 -0
  58. package/dist/server/platform/server/ZipKitServer.js +437 -0
  59. package/dist/server/platform/servercomponents/ZipKitOTS.d.ts +91 -0
  60. package/dist/server/platform/servercomponents/ZipKitOTS.js +271 -0
  61. package/dist/shared/ZipEntry.d.ts +131 -0
  62. package/dist/shared/ZipEntry.js +686 -0
  63. package/dist/shared/ZipKit.d.ts +249 -0
  64. package/dist/shared/ZipKit.js +789 -0
  65. package/dist/shared/components/CertificateOTS.d.ts +15 -0
  66. package/dist/shared/components/CertificateOTS.js +116 -0
  67. package/dist/shared/components/FileSys.d.ts +2 -0
  68. package/dist/shared/components/FileSys.js +113 -0
  69. package/dist/shared/components/HashAccumulator.d.ts +55 -0
  70. package/dist/shared/components/HashAccumulator.js +100 -0
  71. package/dist/shared/components/Support.d.ts +63 -0
  72. package/dist/shared/components/Support.js +70 -0
  73. package/dist/shared/components/Util.d.ts +21 -0
  74. package/dist/shared/components/Util.js +115 -0
  75. package/dist/shared/components/ZipCrypto.d.ts +3 -0
  76. package/dist/shared/components/ZipCrypto.js +78 -0
  77. package/dist/shared/components/merkleTree.d.ts +66 -0
  78. package/dist/shared/components/merkleTree.js +136 -0
  79. package/dist/shared/constants/Errors.d.ts +53 -0
  80. package/dist/shared/constants/Errors.js +69 -0
  81. package/dist/shared/constants/Headers.d.ts +167 -0
  82. package/dist/shared/constants/Headers.js +191 -0
  83. package/dist/shared/types/index.d.ts +21 -0
  84. package/dist/shared/types/index.js +3 -0
  85. package/dist/shared/types.d.ts +33 -0
  86. package/dist/shared/types.js +8 -0
  87. package/dist/shared/version.d.ts +4 -0
  88. package/dist/shared/version.js +7 -0
  89. package/dist/types/index.d.ts +21 -0
  90. package/dist/types/index.js +3 -0
  91. package/examples/unzip-token.ts +488 -0
  92. package/examples/zip-token.ts +604 -0
  93. package/package.json +117 -0
  94. package/src/browser/CertificateGeneratorBrowser.ts +498 -0
  95. package/src/browser/TokenVerifierBrowser.ts +344 -0
  96. package/src/browser/ZipKitBrowser.ts +242 -0
  97. package/src/browser/ZipKitStampBrowser.ts +9 -0
  98. package/src/browser-index.ts +36 -0
  99. package/src/index.ts +48 -0
  100. package/src/server/blockchain/CertificateToken.ts +444 -0
  101. package/src/server/blockchain/NFTMinter.ts +357 -0
  102. package/src/server/blockchain/TokenQuerier.ts +287 -0
  103. package/src/server/blockchain/TokenVerifier.ts +453 -0
  104. package/src/server/blockchain/WalletAnalyzer.ts +397 -0
  105. package/src/server/blockchain/WalletFormatter.ts +206 -0
  106. package/src/server/blockchain/WalletManager.ts +294 -0
  107. package/src/server/blockchain/ZipMetadata.ts +117 -0
  108. package/src/server/blockchain/ZipTokenProcessor.ts +234 -0
  109. package/src/server/blockchain/constants.ts +969 -0
  110. package/src/server/blockchain/index.ts +42 -0
  111. package/src/server/blockchain/test-certificate.ts +137 -0
  112. package/src/server/blockchain/types.ts +134 -0
  113. package/src/server/platform/server/ZipKitServer.ts +459 -0
  114. package/src/server/platform/servercomponents/ZipKitOTS.ts +313 -0
  115. package/src/server/platform/servercomponents/opentimestamps.d.ts +23 -0
  116. package/src/shared/ZipEntry.ts +767 -0
  117. package/src/shared/ZipKit.ts +899 -0
  118. package/src/shared/components/CertificateOTS.ts +132 -0
  119. package/src/shared/components/FileSys.ts +87 -0
  120. package/src/shared/components/HashAccumulator.ts +113 -0
  121. package/src/shared/components/Support.ts +77 -0
  122. package/src/shared/components/Util.ts +113 -0
  123. package/src/shared/components/ZipCrypto.ts +91 -0
  124. package/src/shared/components/merkleTree.ts +162 -0
  125. package/src/shared/constants/Errors.ts +82 -0
  126. package/src/shared/constants/Headers.ts +203 -0
  127. package/src/shared/types/index.ts +25 -0
  128. package/src/shared/types/modules.d.ts +22 -0
  129. package/src/shared/types/opentimestamps.d.ts +23 -0
  130. package/src/shared/types.d.ts +8 -0
  131. package/src/shared/types.ts +43 -0
  132. package/src/shared/version.ts +4 -0
  133. package/src/types/index.ts +25 -0
  134. package/src/types/modules.d.ts +22 -0
  135. package/src/types/opentimestamps.d.ts +23 -0
@@ -0,0 +1,397 @@
1
+ import { ethers } from 'ethers';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+
5
+ // Contract ABI for NZIP tokens
6
+ const NZIP_CONTRACT_ABI = [
7
+ "function getZipFileInfo(uint256 tokenId) view returns (tuple(string fileName, string merkleRootHash, uint256 creationTimestamp, string ipfsHash, uint256 tokenizationTime, address creator))",
8
+ "function ownerOf(uint256 tokenId) view returns (address)",
9
+ "function name() view returns (string)",
10
+ "function symbol() view returns (string)",
11
+ "function totalSupply() view returns (uint256)",
12
+ "function getTokensByMerkleRoot(string merkleRootHash) view returns (uint256[])",
13
+ "event ZipFileTokenized(uint256 indexed tokenId, address indexed creator, string fileName, string merkleRootHash, uint256 creationTimestamp, string ipfsHash)"
14
+ ];
15
+
16
+ // ERC-20 token ABI for checking other tokens
17
+ const ERC20_ABI = [
18
+ "function balanceOf(address owner) view returns (uint256)",
19
+ "function name() view returns (string)",
20
+ "function symbol() view returns (string)",
21
+ "function decimals() view returns (uint8)"
22
+ ];
23
+
24
+ // ERC-721 NFT ABI
25
+ const ERC721_ABI = [
26
+ "function balanceOf(address owner) view returns (uint256)",
27
+ "function name() view returns (string)",
28
+ "function symbol() view returns (string)",
29
+ "function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)"
30
+ ];
31
+
32
+ export interface TokenInfo {
33
+ address: string;
34
+ name: string;
35
+ symbol: string;
36
+ balance: string;
37
+ decimals?: number;
38
+ type: 'ERC20' | 'ERC721' | 'NZIP';
39
+ }
40
+
41
+ export interface NZipTokenDetails {
42
+ tokenId: string;
43
+ merkleRootHash: string;
44
+ fileName: string;
45
+ timestamp: number;
46
+ tokenURI?: string;
47
+ creator: string;
48
+ creationTimestamp: number;
49
+ tokenizationTime: number;
50
+ ipfsHash?: string;
51
+ }
52
+
53
+ export interface WalletBasicInfo {
54
+ ethBalance: string;
55
+ transactionCount: number;
56
+ networkName: string;
57
+ chainId: bigint;
58
+ latestBlock: number;
59
+ }
60
+
61
+ export interface TokenScanResult {
62
+ foundTokens: number[];
63
+ searchMethod: 'recent-events' | 'iteration' | 'common-ids' | 'none';
64
+ }
65
+
66
+ export interface CommonTokenConfig {
67
+ address: string;
68
+ name: string;
69
+ symbol: string;
70
+ type: 'ERC20' | 'ERC721';
71
+ }
72
+
73
+ export class WalletAnalyzer {
74
+ private provider: ethers.JsonRpcProvider;
75
+
76
+ constructor(provider: ethers.JsonRpcProvider) {
77
+ this.provider = provider;
78
+ }
79
+
80
+ /**
81
+ * Get basic wallet information (balance, transaction count, etc.)
82
+ */
83
+ async getWalletBasics(address: string): Promise<WalletBasicInfo> {
84
+ try {
85
+ // Get ETH balance
86
+ const balance = await this.provider.getBalance(address);
87
+ const ethBalance = ethers.formatEther(balance);
88
+
89
+ // Get transaction count (nonce)
90
+ const txCount = await this.provider.getTransactionCount(address);
91
+
92
+ // Get network info
93
+ const network = await this.provider.getNetwork();
94
+
95
+ // Get latest block
96
+ const latestBlock = await this.provider.getBlockNumber();
97
+
98
+ return {
99
+ ethBalance,
100
+ transactionCount: txCount,
101
+ networkName: network.name,
102
+ chainId: network.chainId,
103
+ latestBlock
104
+ };
105
+ } catch (error) {
106
+ throw new Error(`Failed to get wallet basics: ${error}`);
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Scan for NZIP tokens owned by an address using multiple methods
112
+ */
113
+ async scanForNZipTokens(contractAddress: string, ownerAddress: string): Promise<TokenScanResult> {
114
+ const contract = new ethers.Contract(contractAddress, NZIP_CONTRACT_ABI, this.provider);
115
+ let foundTokens: number[] = [];
116
+ let searchMethod: TokenScanResult['searchMethod'] = 'none';
117
+
118
+ // Method 1: Try events with recent blocks only
119
+ try {
120
+ const latestBlock = await this.provider.getBlockNumber();
121
+ const startBlock = Math.max(0, latestBlock - 50000);
122
+
123
+ const filter = contract.filters.ZipFileTokenized(null, ownerAddress);
124
+ const events = await contract.queryFilter(filter, startBlock, 'latest');
125
+
126
+ for (const event of events) {
127
+ if ('args' in event && event.args && event.args.tokenId) {
128
+ const tokenId = Number(event.args.tokenId);
129
+ if (!foundTokens.includes(tokenId)) {
130
+ foundTokens.push(tokenId);
131
+ }
132
+ }
133
+ }
134
+
135
+ if (foundTokens.length > 0) {
136
+ searchMethod = 'recent-events';
137
+ return { foundTokens, searchMethod };
138
+ }
139
+ } catch (eventError) {
140
+ // Continue to next method
141
+ }
142
+
143
+ // Method 2: Direct token ID checking (brute force for small supply)
144
+ try {
145
+ const totalSupply = await contract.totalSupply();
146
+ const maxCheck = Math.min(Number(totalSupply), 50); // Limit to 50 tokens max
147
+
148
+ for (let tokenId = 0; tokenId < maxCheck; tokenId++) {
149
+ try {
150
+ const owner = await contract.ownerOf(tokenId);
151
+ if (owner.toLowerCase() === ownerAddress.toLowerCase()) {
152
+ foundTokens.push(tokenId);
153
+ }
154
+ } catch (ownerError) {
155
+ // Token doesn't exist or other error, skip
156
+ }
157
+ }
158
+
159
+ if (foundTokens.length > 0) {
160
+ searchMethod = 'iteration';
161
+ return { foundTokens, searchMethod };
162
+ }
163
+ } catch (iterationError) {
164
+ // Continue to next method
165
+ }
166
+
167
+ // Method 3: Check specific token IDs that commonly exist
168
+ const commonTokenIds = Array.from({length: 20}, (_, i) => i); // 0-19
169
+
170
+ for (const tokenId of commonTokenIds) {
171
+ try {
172
+ const owner = await contract.ownerOf(tokenId);
173
+ if (owner.toLowerCase() === ownerAddress.toLowerCase()) {
174
+ foundTokens.push(tokenId);
175
+ }
176
+ } catch (ownerError) {
177
+ // Token doesn't exist, skip
178
+ }
179
+ }
180
+
181
+ if (foundTokens.length > 0) {
182
+ searchMethod = 'common-ids';
183
+ }
184
+
185
+ return { foundTokens, searchMethod };
186
+ }
187
+
188
+ /**
189
+ * Get detailed information about NZIP tokens
190
+ */
191
+ async getNZipTokenDetails(contractAddress: string, tokenIds: number[]): Promise<NZipTokenDetails[]> {
192
+ const contract = new ethers.Contract(contractAddress, NZIP_CONTRACT_ABI, this.provider);
193
+ const tokenDetails: NZipTokenDetails[] = [];
194
+
195
+ for (const tokenId of tokenIds) {
196
+ try {
197
+ const zipInfo = await contract.getZipFileInfo(tokenId);
198
+
199
+ tokenDetails.push({
200
+ tokenId: tokenId.toString(),
201
+ merkleRootHash: zipInfo.merkleRootHash,
202
+ fileName: zipInfo.fileName,
203
+ timestamp: Number(zipInfo.creationTimestamp),
204
+ creator: zipInfo.creator,
205
+ creationTimestamp: Number(zipInfo.creationTimestamp),
206
+ tokenizationTime: Number(zipInfo.tokenizationTime),
207
+ ipfsHash: zipInfo.ipfsHash || undefined
208
+ });
209
+ } catch (error) {
210
+ console.error(`Error fetching details for token ${tokenId}:`, error);
211
+ }
212
+ }
213
+
214
+ return tokenDetails;
215
+ }
216
+
217
+ /**
218
+ * Get contract information (name, symbol, total supply)
219
+ */
220
+ async getContractInfo(contractAddress: string): Promise<{name: string, symbol: string, totalSupply: string} | null> {
221
+ try {
222
+ const contract = new ethers.Contract(contractAddress, NZIP_CONTRACT_ABI, this.provider);
223
+
224
+ const [name, symbol, totalSupply] = await Promise.all([
225
+ contract.name(),
226
+ contract.symbol(),
227
+ contract.totalSupply()
228
+ ]);
229
+
230
+ return {
231
+ name,
232
+ symbol,
233
+ totalSupply: totalSupply.toString()
234
+ };
235
+ } catch (error) {
236
+ return null;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Check ERC-20 token balances for common tokens
242
+ */
243
+ async checkERC20Tokens(ownerAddress: string, tokenConfigs: CommonTokenConfig[]): Promise<TokenInfo[]> {
244
+ const foundTokens: TokenInfo[] = [];
245
+
246
+ for (const tokenConfig of tokenConfigs.filter(t => t.type === 'ERC20')) {
247
+ try {
248
+ const contract = new ethers.Contract(tokenConfig.address, ERC20_ABI, this.provider);
249
+
250
+ const balance = await contract.balanceOf(ownerAddress);
251
+ if (balance > 0) {
252
+ let name, symbol, decimals;
253
+
254
+ try {
255
+ [name, symbol, decimals] = await Promise.all([
256
+ contract.name(),
257
+ contract.symbol(),
258
+ contract.decimals()
259
+ ]);
260
+ } catch (metadataError) {
261
+ // Use fallback info if contract calls fail
262
+ name = tokenConfig.name;
263
+ symbol = tokenConfig.symbol;
264
+ decimals = 18; // Default decimals
265
+ }
266
+
267
+ const formattedBalance = ethers.formatUnits(balance, decimals);
268
+
269
+ foundTokens.push({
270
+ address: tokenConfig.address,
271
+ name,
272
+ symbol,
273
+ balance: formattedBalance,
274
+ decimals,
275
+ type: 'ERC20'
276
+ });
277
+ }
278
+ } catch (error) {
279
+ // Token might not exist or might not be ERC20, continue silently
280
+ }
281
+ }
282
+
283
+ return foundTokens;
284
+ }
285
+
286
+ /**
287
+ * Check NFT collection balances
288
+ */
289
+ async checkNFTCollections(ownerAddress: string, nftConfigs: CommonTokenConfig[]): Promise<TokenInfo[]> {
290
+ const foundNFTs: TokenInfo[] = [];
291
+
292
+ for (const nftConfig of nftConfigs) {
293
+ try {
294
+ const contract = new ethers.Contract(nftConfig.address, ERC721_ABI, this.provider);
295
+
296
+ const balance = await contract.balanceOf(ownerAddress);
297
+ if (balance > 0) {
298
+ let name, symbol;
299
+ try {
300
+ [name, symbol] = await Promise.all([
301
+ contract.name(),
302
+ contract.symbol()
303
+ ]);
304
+ } catch (metadataError) {
305
+ name = nftConfig.name;
306
+ symbol = nftConfig.symbol;
307
+ }
308
+
309
+ // Try to get token IDs if balance is small
310
+ let tokenIds: string[] = [];
311
+ if (Number(balance) <= 5) {
312
+ try {
313
+ for (let i = 0; i < Number(balance); i++) {
314
+ const tokenId = await contract.tokenOfOwnerByIndex(ownerAddress, i);
315
+ tokenIds.push(tokenId.toString());
316
+ }
317
+ } catch (enumError) {
318
+ // Unable to enumerate, that's okay
319
+ }
320
+ }
321
+
322
+ foundNFTs.push({
323
+ address: nftConfig.address,
324
+ name,
325
+ symbol,
326
+ balance: balance.toString(),
327
+ type: 'ERC721'
328
+ });
329
+ }
330
+ } catch (error) {
331
+ // Contract might not exist or might not be ERC-721, continue silently
332
+ }
333
+ }
334
+
335
+ return foundNFTs;
336
+ }
337
+
338
+ /**
339
+ * Detect NZIP contract from deployment file
340
+ */
341
+ static detectNZipContract(): string | undefined {
342
+ const deploymentPath = path.join(process.cwd(), 'zipfile-nft-deployment.json');
343
+
344
+ if (fs.existsSync(deploymentPath)) {
345
+ try {
346
+ const deploymentInfo = JSON.parse(fs.readFileSync(deploymentPath, 'utf8'));
347
+ if (deploymentInfo.address) {
348
+ return deploymentInfo.address;
349
+ }
350
+ } catch (error) {
351
+ // Could not read deployment file
352
+ }
353
+ }
354
+
355
+ return undefined;
356
+ }
357
+
358
+ /**
359
+ * Get common token configurations for a network
360
+ */
361
+ static getCommonTokens(network: string): CommonTokenConfig[] {
362
+ const commonTokens: Record<string, CommonTokenConfig[]> = {
363
+ 'base-sepolia': [
364
+ { address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', name: 'USD Coin', symbol: 'USDC', type: 'ERC20' },
365
+ { address: '0x4200000000000000000000000000000000000006', name: 'Wrapped Ether', symbol: 'WETH', type: 'ERC20' },
366
+ { address: '0xE4aB69C077896252FAFBD49EFD26B5D171A32410', name: 'Coinbase Wrapped Staked ETH', symbol: 'cbETH', type: 'ERC20' },
367
+ ],
368
+ 'base': [
369
+ { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', name: 'USD Coin', symbol: 'USDC', type: 'ERC20' },
370
+ { address: '0x4200000000000000000000000000000000000006', name: 'Wrapped Ether', symbol: 'WETH', type: 'ERC20' },
371
+ { address: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', name: 'Dai Stablecoin', symbol: 'DAI', type: 'ERC20' },
372
+ { address: '0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22', name: 'Coinbase Wrapped Staked ETH', symbol: 'cbETH', type: 'ERC20' },
373
+ { address: '0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA', name: 'USD Base Coin', symbol: 'USDbC', type: 'ERC20' },
374
+ ]
375
+ };
376
+
377
+ return commonTokens[network] || [];
378
+ }
379
+
380
+ /**
381
+ * Get common NFT configurations for a network
382
+ */
383
+ static getCommonNFTs(network: string): CommonTokenConfig[] {
384
+ const commonNFTs: Record<string, CommonTokenConfig[]> = {
385
+ 'base-sepolia': [
386
+ // Add known testnet NFTs here when they become available
387
+ ],
388
+ 'base': [
389
+ // Base mainnet NFTs - these are examples, real addresses would be different
390
+ { address: '0x1234567890123456789012345678901234567890', name: 'Base Punks', symbol: 'BPUNK', type: 'ERC721' },
391
+ { address: '0x0987654321098765432109876543210987654321', name: 'Base Bears', symbol: 'BBEAR', type: 'ERC721' },
392
+ ]
393
+ };
394
+
395
+ return commonNFTs[network] || [];
396
+ }
397
+ }
@@ -0,0 +1,206 @@
1
+ import { WalletBasicInfo, NZipTokenDetails, TokenInfo, TokenScanResult } from './WalletAnalyzer';
2
+
3
+ export class WalletFormatter {
4
+ /**
5
+ * Display basic wallet information
6
+ */
7
+ static displayWalletBasics(walletInfo: WalletBasicInfo): void {
8
+ console.log('\nšŸ’° Basic Wallet Information');
9
+ console.log('─'.repeat(50));
10
+
11
+ console.log(`ETH Balance: ${walletInfo.ethBalance} ETH`);
12
+ console.log(`Transaction Count: ${walletInfo.transactionCount}`);
13
+ console.log(`Network Name: ${walletInfo.networkName}`);
14
+ console.log(`Chain ID: ${walletInfo.chainId}`);
15
+ console.log(`Latest Block: ${walletInfo.latestBlock}`);
16
+ }
17
+
18
+ /**
19
+ * Display contract information
20
+ */
21
+ static displayContractInfo(contractInfo: {name: string, symbol: string, totalSupply: string} | null, isLegacy: boolean = false): void {
22
+ if (contractInfo) {
23
+ console.log(`Contract Name: ${contractInfo.name}`);
24
+ console.log(`Contract Symbol: ${contractInfo.symbol}`);
25
+ console.log(`Total Supply: ${contractInfo.totalSupply}`);
26
+ } else {
27
+ console.log('Contract Info: Unable to fetch');
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Display token scan progress
33
+ */
34
+ static displayTokenScanProgress(scanResult: TokenScanResult): void {
35
+ console.log('Searching for tokens owned by this address...');
36
+
37
+ if (scanResult.searchMethod === 'recent-events') {
38
+ console.log(' šŸ” Trying recent events (last 50k blocks)...');
39
+ console.log(` āœ… Found ${scanResult.foundTokens.length} tokens from recent events`);
40
+ } else if (scanResult.searchMethod === 'iteration') {
41
+ console.log(' šŸ” Trying recent events (last 50k blocks)...');
42
+ console.log(' āŒ Recent events failed, trying alternative methods...');
43
+ console.log(' šŸ” Checking token ownership by iteration...');
44
+ console.log(` āœ… Found ${scanResult.foundTokens.length} tokens by iteration`);
45
+ } else if (scanResult.searchMethod === 'common-ids') {
46
+ console.log(' šŸ” Trying recent events (last 50k blocks)...');
47
+ console.log(' āŒ Recent events failed, trying alternative methods...');
48
+ console.log(' šŸ” Checking token ownership by iteration...');
49
+ console.log(' āš ļø No tokens found by iteration, checking common IDs...');
50
+ console.log(' šŸ” Checking common token IDs (0-19)...');
51
+ console.log(` āœ… Found ${scanResult.foundTokens.length} tokens from common IDs`);
52
+ } else {
53
+ console.log(' šŸ” Trying recent events (last 50k blocks)...');
54
+ console.log(' āŒ Recent events failed, trying alternative methods...');
55
+ console.log(' šŸ” Checking token ownership by iteration...');
56
+ console.log(' āš ļø No tokens found by iteration, checking common IDs...');
57
+ console.log(' šŸ” Checking common token IDs (0-19)...');
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Display detailed NZIP token information
63
+ */
64
+ static displayNZipTokenDetails(tokenDetails: NZipTokenDetails[], scanResult: TokenScanResult, contractAddress: string): void {
65
+ if (tokenDetails.length > 0) {
66
+ console.log(`\nāœ… Found ${tokenDetails.length} NZIP token(s) using ${scanResult.searchMethod}:`);
67
+ console.log('šŸ“‹ Your NZIP Token Details:');
68
+ console.log('═'.repeat(80));
69
+
70
+ for (const token of tokenDetails.sort((a, b) => parseInt(a.tokenId) - parseInt(b.tokenId))) {
71
+ console.log(`\nšŸŽÆ Token ID ${token.tokenId}:`);
72
+ console.log(` File Name: ${token.fileName}`);
73
+ console.log(` Merkle Root: ${token.merkleRootHash}`);
74
+
75
+ // Convert timestamps to dates
76
+ const creationDate = new Date(token.creationTimestamp * 1000);
77
+ const tokenizationDate = new Date(token.tokenizationTime * 1000);
78
+
79
+ // Format dates in a more readable format
80
+ const formatOptions: Intl.DateTimeFormatOptions = {
81
+ year: 'numeric',
82
+ month: 'short',
83
+ day: '2-digit',
84
+ hour: '2-digit',
85
+ minute: '2-digit',
86
+ second: '2-digit',
87
+ timeZoneName: 'short'
88
+ };
89
+
90
+ console.log(` Created: ${creationDate.toLocaleDateString('en-US', formatOptions)}`);
91
+ console.log(` Tokenized: ${tokenizationDate.toLocaleDateString('en-US', formatOptions)}`);
92
+
93
+ // Show time difference between creation and tokenization
94
+ const timeDiffSeconds = token.tokenizationTime - token.creationTimestamp;
95
+ if (timeDiffSeconds > 0) {
96
+ if (timeDiffSeconds < 60) {
97
+ console.log(` Tokenization Delay: ${timeDiffSeconds} seconds`);
98
+ } else if (timeDiffSeconds < 3600) {
99
+ console.log(` Tokenization Delay: ${Math.round(timeDiffSeconds / 60)} minutes`);
100
+ } else {
101
+ console.log(` Tokenization Delay: ${Math.round(timeDiffSeconds / 3600)} hours`);
102
+ }
103
+ }
104
+
105
+ if (token.ipfsHash && token.ipfsHash !== '') {
106
+ console.log(` IPFS Hash: ${token.ipfsHash}`);
107
+ }
108
+
109
+ console.log(` Creator: ${token.creator}`);
110
+
111
+ // Calculate age since creation (using current time)
112
+ const now = Date.now();
113
+ const ageMs = now - (token.creationTimestamp * 1000);
114
+ const ageDays = Math.floor(ageMs / (1000 * 60 * 60 * 24));
115
+ const ageHours = Math.floor((ageMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
116
+ const ageMinutes = Math.floor((ageMs % (1000 * 60 * 60)) / (1000 * 60));
117
+
118
+ if (ageDays > 0) {
119
+ console.log(` Age: ${ageDays} days, ${ageHours} hours`);
120
+ } else if (ageHours > 0) {
121
+ console.log(` Age: ${ageHours} hours, ${ageMinutes} minutes`);
122
+ } else {
123
+ console.log(` Age: ${ageMinutes} minutes`);
124
+ }
125
+ }
126
+ } else {
127
+ console.log('\nāŒ No NZIP tokens found for this address');
128
+ console.log('\nšŸ’” This could mean:');
129
+ console.log(' • You don\'t own any NZIP tokens on this network');
130
+ console.log(' • The tokens are on a different contract or network');
131
+ console.log(' • There are temporary RPC connectivity issues');
132
+ console.log('\nšŸ”§ Try these troubleshooting steps:');
133
+ console.log(' • Verify you\'re on the correct network (--network flag)');
134
+ console.log(' • Check if you have tokens on a different contract (--contract flag)');
135
+ console.log(' • Try again in a few minutes if RPC is experiencing issues');
136
+ console.log(` • Verify the contract address: ${contractAddress}`);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Display ERC-20 token information
142
+ */
143
+ static displayERC20Tokens(tokens: TokenInfo[]): void {
144
+ if (tokens.length > 0) {
145
+ console.log(`\nšŸ’° ERC-20 Token Balances:`);
146
+
147
+ for (const token of tokens) {
148
+ console.log(`\n šŸ’Ž ${token.symbol} (${token.name}):`);
149
+ console.log(` Contract: ${token.address}`);
150
+ console.log(` Balance: ${token.balance} ${token.symbol}`);
151
+ console.log(` Decimals: ${token.decimals}`);
152
+
153
+ // Add USD value estimation for major stablecoins
154
+ if (['USDC', 'USDT', 'DAI', 'USDbC'].includes(token.symbol)) {
155
+ console.log(` Est. USD Value: ~$${token.balance}`);
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Display NFT collection information
163
+ */
164
+ static displayNFTCollections(nfts: TokenInfo[]): void {
165
+ console.log(`\nšŸ–¼ļø Other NFT Collections:`);
166
+
167
+ if (nfts.length > 0) {
168
+ for (const nft of nfts) {
169
+ console.log(`\n šŸ–¼ļø ${nft.symbol} (${nft.name}):`);
170
+ console.log(` Contract: ${nft.address}`);
171
+ console.log(` NFTs Owned: ${nft.balance}`);
172
+ }
173
+ } else {
174
+ console.log(` No other NFT collections found`);
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Display token scan summary
180
+ */
181
+ static displayTokenScanSummary(erc20Count: number, totalScanned: number): void {
182
+ console.log(`\nšŸ“Š Token Scan Summary:`);
183
+ console.log(` ERC-20 Tokens Found: ${erc20Count}`);
184
+ console.log(` Total Tokens Scanned: ${totalScanned}`);
185
+
186
+ if (erc20Count === 0) {
187
+ console.log(`\nšŸ’” No tokens found. This could mean:`);
188
+ console.log(` • This is a new wallet with no token activity`);
189
+ console.log(` • Tokens are on a different network`);
190
+ console.log(` • You have tokens not in our common token list`);
191
+ console.log(` • There are temporary RPC connectivity issues`);
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Display error messages for contract connection issues
197
+ */
198
+ static displayContractError(error: any, contractAddress: string): void {
199
+ console.error('āŒ Error connecting to NZIP contract:', error);
200
+ console.log('\nšŸ”§ Troubleshooting suggestions:');
201
+ console.log(' • Check if the contract address is correct');
202
+ console.log(' • Verify you\'re on the right network');
203
+ console.log(' • Try again later if RPC is experiencing issues');
204
+ console.log(' • Use --contract flag to specify a different contract address');
205
+ }
206
+ }