neozipkit 0.1.1 → 0.2.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 (115) hide show
  1. package/README.md +52 -105
  2. package/contracts/INTEGRATION.md +338 -0
  3. package/contracts/NETWORKS.md +156 -0
  4. package/contracts/README.md +152 -0
  5. package/{src/server/blockchain → contracts}/constants.ts +5 -22
  6. package/contracts/deploy-bytecode.mjs +94 -0
  7. package/dist/blockchain/ZipKitMinter.d.ts +106 -0
  8. package/dist/blockchain/ZipKitMinter.js +347 -0
  9. package/dist/blockchain/ZipKitNFT.d.ts +3 -0
  10. package/dist/blockchain/ZipKitNFT.js +7 -0
  11. package/dist/blockchain/ZipKitOTS.d.ts +135 -0
  12. package/dist/blockchain/ZipKitOTS.js +564 -0
  13. package/dist/blockchain/ZipKitVerifier.d.ts +69 -0
  14. package/dist/blockchain/ZipKitVerifier.js +289 -0
  15. package/dist/{server/blockchain/WalletAnalyzer.d.ts → blockchain/ZipKitWallet.d.ts} +31 -43
  16. package/dist/{server/blockchain/WalletAnalyzer.js → blockchain/ZipKitWallet.js} +193 -161
  17. package/dist/blockchain/contracts.d.ts +14 -0
  18. package/dist/blockchain/contracts.js +77 -0
  19. package/dist/blockchain/index.d.ts +7 -0
  20. package/dist/blockchain/index.js +50 -0
  21. package/dist/{server/blockchain → blockchain}/types.d.ts +12 -34
  22. package/dist/{server/blockchain → blockchain}/types.js +1 -22
  23. package/dist/browser-index.d.ts +0 -3
  24. package/dist/browser-index.js +4 -5
  25. package/dist/browser.d.ts +0 -3
  26. package/dist/browser.js +4 -5
  27. package/dist/index.d.ts +8 -15
  28. package/dist/index.js +12 -24
  29. package/dist/server/{platform/server/ZipKitServer.d.ts → ZipKitServer.d.ts} +4 -35
  30. package/dist/server/{platform/server/ZipKitServer.js → ZipKitServer.js} +55 -182
  31. package/dist/shared/ZipEntry.js +1 -1
  32. package/dist/shared/ZipKit.d.ts +0 -6
  33. package/dist/shared/ZipKit.js +1 -18
  34. package/dist/shared/types.js +2 -2
  35. package/dist/shared/version.d.ts +2 -4
  36. package/dist/shared/version.js +4 -5
  37. package/package.json +13 -3
  38. package/src/blockchain/README.md +229 -0
  39. package/src/blockchain/ZipKitMinter.ts +470 -0
  40. package/src/blockchain/ZipKitNFT.ts +12 -0
  41. package/src/blockchain/ZipKitOTS.ts +622 -0
  42. package/src/blockchain/ZipKitVerifier.ts +382 -0
  43. package/src/blockchain/ZipKitWallet.ts +338 -0
  44. package/src/blockchain/contracts.ts +88 -0
  45. package/src/blockchain/index.ts +61 -0
  46. package/src/blockchain/types.ts +91 -0
  47. package/src/browser/{TokenVerifierBrowser.ts → TokenVerifierBrowser.ts-remove} +1 -1
  48. package/src/browser-index.ts +3 -3
  49. package/src/index.ts +10 -17
  50. package/src/server/README.md +25 -0
  51. package/src/server/ZipKitServer.ts +305 -0
  52. package/src/shared/ZipEntry.ts +1 -1
  53. package/src/shared/ZipKit.ts +1 -19
  54. package/src/shared/types.ts +3 -3
  55. package/src/shared/version.ts +3 -4
  56. package/src/types/modules.d.ts +11 -1
  57. package/contracts/Lock.sol +0 -34
  58. package/contracts/compile-contract.js +0 -168
  59. package/contracts/deploy/deploy-both-contracts.js +0 -286
  60. package/contracts/deploy/deploy-enhanced-contract.js +0 -197
  61. package/contracts/deploy/deploy-private-contract.js +0 -190
  62. package/contracts/deploy/deploy-public-clean.js +0 -1063
  63. package/contracts/deploy/deploy-public-contract.js +0 -1107
  64. package/contracts/deployment.config.example.js +0 -25
  65. package/contracts/remix-compile.js +0 -222
  66. package/contracts/setup-deployment.js +0 -51
  67. package/contracts/src/ZipFileNFT-DEPRECATED-6field.sol +0 -260
  68. package/contracts/src/ZipFileNFT-DEPRECATED-Enhanced.sol +0 -289
  69. package/dist/browser/CertificateGeneratorBrowser.d.ts +0 -75
  70. package/dist/browser/CertificateGeneratorBrowser.js +0 -433
  71. package/dist/browser/TokenVerifierBrowser.d.ts +0 -76
  72. package/dist/browser/TokenVerifierBrowser.js +0 -299
  73. package/dist/server/blockchain/NFTMinter.d.ts +0 -41
  74. package/dist/server/blockchain/NFTMinter.js +0 -323
  75. package/dist/server/blockchain/TokenQuerier.d.ts +0 -31
  76. package/dist/server/blockchain/TokenQuerier.js +0 -259
  77. package/dist/server/blockchain/TokenVerifier.d.ts +0 -20
  78. package/dist/server/blockchain/TokenVerifier.js +0 -395
  79. package/dist/server/blockchain/WalletFormatter.d.ts +0 -39
  80. package/dist/server/blockchain/WalletFormatter.js +0 -196
  81. package/dist/server/blockchain/WalletManager.d.ts +0 -46
  82. package/dist/server/blockchain/WalletManager.js +0 -294
  83. package/dist/server/blockchain/ZipMetadata.d.ts +0 -27
  84. package/dist/server/blockchain/ZipMetadata.js +0 -131
  85. package/dist/server/blockchain/ZipTokenProcessor.d.ts +0 -44
  86. package/dist/server/blockchain/ZipTokenProcessor.js +0 -204
  87. package/dist/server/blockchain/constants.d.ts +0 -102
  88. package/dist/server/blockchain/constants.js +0 -968
  89. package/dist/server/blockchain/index.d.ts +0 -9
  90. package/dist/server/blockchain/index.js +0 -44
  91. package/dist/server/blockchain/test-certificate.d.ts +0 -8
  92. package/dist/server/blockchain/test-certificate.js +0 -100
  93. package/dist/server/platform/servercomponents/ZipKitOTS.d.ts +0 -91
  94. package/dist/server/platform/servercomponents/ZipKitOTS.js +0 -271
  95. package/examples/unzip-token.ts +0 -488
  96. package/examples/zip-token.ts +0 -604
  97. package/src/server/blockchain/NFTMinter.ts +0 -357
  98. package/src/server/blockchain/TokenQuerier.ts +0 -287
  99. package/src/server/blockchain/TokenVerifier.ts +0 -453
  100. package/src/server/blockchain/WalletAnalyzer.ts +0 -397
  101. package/src/server/blockchain/WalletFormatter.ts +0 -206
  102. package/src/server/blockchain/WalletManager.ts +0 -294
  103. package/src/server/blockchain/ZipMetadata.ts +0 -117
  104. package/src/server/blockchain/ZipTokenProcessor.ts +0 -234
  105. package/src/server/blockchain/index.ts +0 -42
  106. package/src/server/blockchain/test-certificate.ts +0 -137
  107. package/src/server/blockchain/types.ts +0 -134
  108. package/src/server/platform/server/ZipKitServer.ts +0 -459
  109. package/src/server/platform/servercomponents/ZipKitOTS.ts +0 -313
  110. package/src/server/platform/servercomponents/opentimestamps.d.ts +0 -23
  111. /package/contracts/{bytecode.txt → NZIP-NFT-bytecode.txt} +0 -0
  112. /package/dist/{server/blockchain → blockchain}/CertificateToken.d.ts +0 -0
  113. /package/dist/{server/blockchain → blockchain}/CertificateToken.js +0 -0
  114. /package/src/{server/blockchain → blockchain}/CertificateToken.ts +0 -0
  115. /package/src/browser/{CertificateGeneratorBrowser.ts → CertificateGeneratorBrowser.ts-remove} +0 -0
@@ -0,0 +1,229 @@
1
+ ## Blockchain Module APIs
2
+
3
+ This directory provides all blockchain-related functionality for NeoZipKit, including:
4
+ - OpenTimestamps utilities
5
+ - NFT contract interactions (verification, querying, minting)
6
+ - Wallet utilities and token processing
7
+ - Network constants and contract ABI
8
+
9
+ ## 📁 Module Structure
10
+
11
+ ```
12
+ src/blockchain/
13
+ ├── contracts.ts # Contract ABI + network configs + addresses
14
+ ├── ZipKitOTS.ts # OpenTimestamps utilities
15
+ ├── TokenVerifier.ts # ZIP tokenization verification
16
+ ├── TokenQuerier.ts # Blockchain token queries
17
+ ├── NFTMinter.ts # NFT minting operations
18
+ ├── WalletManager.ts # Wallet connection management
19
+ ├── WalletAnalyzer.ts # Wallet token analysis
20
+ ├── (removed) # Token display formatting (deprecated)
21
+ ├── ZipMetadata.ts # ZIP metadata validation
22
+ ├── ZipKitMinter.ts # High-level minting interface
23
+ ├── ZipKitVerifier.ts # High-level verification interface
24
+ ├── ZipKitNFT.ts # Unified NFT facade (minter + verifier)
25
+ ├── ZipKitWallet.ts # Wallet setup + WalletAnalyzer utilities (combined)
26
+ ├── ZipTokenProcessor.ts # Token processing utilities
27
+ ├── types.ts # Shared blockchain types
28
+ └── index.ts # Module exports
29
+ ```
30
+
31
+ ### Package Entry
32
+ Import from the package root or from `src/blockchain` directly:
33
+
34
+ ```ts
35
+ // Yes! You can import directly from the blockchain directory
36
+ import {
37
+ ZipMetadata,
38
+ ZipKitMinter,
39
+ ZipKitVerifier,
40
+ ZipKitWallet,
41
+ WalletAnalyzer,
42
+ CONTRACT_CONFIGS,
43
+ NZIP_CONTRACT_ABI,
44
+ CURRENT_DEPLOYMENT
45
+ } from 'neozipkit/blockchain';
46
+
47
+ // Or from the main package (re-exports everything from blockchain)
48
+ import { ZipMetadata, ZipKitMinter, ZipKitVerifier, ZipKitWallet, WalletAnalyzer } from 'neozipkit';
49
+
50
+ // From source (monorepo/local development)
51
+ import { ZipMetadata, ZipKitMinter, ZipKitVerifier, ZipKitWallet, WalletAnalyzer } from '../src/blockchain';
52
+ ```
53
+
54
+ ### Unified NFT APIs (ZipKitNFT.ts)
55
+
56
+ Prefer the unified entry point for minting and verification:
57
+
58
+ ```ts
59
+ import { ZipKitNFT, ZipKitNFTMinter, ZipKitNFTVerifier } from 'neozipkit/blockchain';
60
+
61
+ // Facade usage
62
+ const nft = new ZipKitNFT({
63
+ archiveName: 'archive.zip',
64
+ merkleRoot: 'abc123...',
65
+ mintingOptions: { walletPrivateKey: '0x...', network: 'base-sepolia' },
66
+ verificationOptions: { debug: false }
67
+ });
68
+
69
+ // Or use classes directly
70
+ const minter = new ZipKitNFTMinter('archive.zip', 'abc123...', { walletPrivateKey: '0x...', network: 'base-sepolia' });
71
+ const verifier = new ZipKitNFTVerifier({ debug: false });
72
+ ```
73
+
74
+ ### OpenTimestamps (ZipKitOTS.ts)
75
+ Bitcoin blockchain timestamping utilities for ZIP file integrity verification.
76
+
77
+ #### Core Functions
78
+
79
+ **Timestamp Creation & Verification:**
80
+ - `createTimestamp(hashDigest: string, options?: { debug?: boolean }): Promise<Buffer | null>`
81
+ - Creates an OpenTimestamps proof for a hash digest. Submits hash to OpenTimestamps servers for Bitcoin blockchain anchoring.
82
+ - `verifyOts(hashDigest: string | null, ots: ArrayBuffer | null, options?: { debug?: boolean }): Promise<TimestampResult | { error: string } | null>`
83
+ - Verifies an OpenTimestamps proof against a hash digest. Returns verification result, error object, or null if inputs invalid.
84
+ - `verifyOtsZip(zip: any): Promise<OtsVerifyResult>`
85
+ - Verifies OpenTimestamps proof within a ZIP file. Extracts merkle root and OTS proof, then verifies against Bitcoin blockchain.
86
+
87
+ **ZIP Integration:**
88
+ - `getOtsEntry(zip: any): any | null`
89
+ - Finds the OpenTimestamps entry in a ZIP file. Searches for TIMESTAMP_METADATA first, then TIMESTAMP_SUBMITTED.
90
+ - `getOtsBuffer(zip: any, otsEntry: any): Promise<Buffer | null>`
91
+ - Extracts OTS proof data from a ZIP entry.
92
+ - `getMerkleRootSafe(zip: any): string | null`
93
+ - Safely extracts merkle root from a ZIP file.
94
+
95
+ **Data Processing:**
96
+ - `deserializeOts(tsResult: TimestampResult, options?: { debug?: boolean }): Promise<string | null>`
97
+ - Deserializes OpenTimestamps verification result into JSON format. Extracts blockchain attestation data and transaction details.
98
+ - `parseVerifyResult(verifyResult: TimestampResult): Promise<TimestampInfo>`
99
+ - Parses timestamp verification result into readable information. Formats blockchain attestation data with human-readable messages and dates.
100
+
101
+ **Certificate & Upgrade:**
102
+ - `createCertificateOts(fileName: string, zipEntries: ZipEntry[], timestampResult: TimestampResult): Promise<string>`
103
+ - Creates an HTML certificate for OpenTimestamps verification. Generates a certificate file documenting the timestamp verification results.
104
+ - `upgradeOTS(zipFilePath: string, upgradedOts: Buffer): Promise<void>`
105
+ - Upgrades OpenTimestamps proof in an existing ZIP file. Replaces old timestamp metadata with upgraded OTS proof data.
106
+ - `createOtsMetadataEntry(zipKit: any, ots: Buffer | null): any | null`
107
+ - Creates a ZIP metadata entry containing OpenTimestamps proof. Creates a special ZIP entry marked as metadata that stores OTS proof data.
108
+
109
+ **Utility Functions:**
110
+ - `bufferToArrayBuffer(buf: Buffer): ArrayBuffer`
111
+ - Converts a Node.js Buffer to an ArrayBuffer.
112
+
113
+ #### Types & Interfaces
114
+
115
+ ```typescript
116
+ export interface TimestampResult {
117
+ merkleRoot: string | null;
118
+ ots: ArrayBuffer | null;
119
+ verified: boolean;
120
+ results: any | null;
121
+ error: string | null;
122
+ attestations: any | null;
123
+ upgradedOts: ArrayBuffer | null;
124
+ }
125
+
126
+ export interface TimestampInfo {
127
+ message: string;
128
+ results: string[];
129
+ attestDate: Date | null;
130
+ attestHeight: number | null;
131
+ submittedUri: string | null;
132
+ otsUpgraded: boolean;
133
+ }
134
+
135
+ export interface OtsVerifyResult {
136
+ status: 'none' | 'valid' | 'pending' | 'error';
137
+ message?: string;
138
+ blockHeight?: number;
139
+ attestedAt?: Date;
140
+ upgraded?: boolean;
141
+ upgradedOts?: Buffer;
142
+ }
143
+
144
+ export interface DeserializeOtsResult {
145
+ attestStr: string | null;
146
+ needsUpdateMsg: string | null;
147
+ attestationValues: any[];
148
+ }
149
+ ```
150
+
151
+ #### Usage Example
152
+
153
+ ```typescript
154
+ import { createTimestamp, verifyOtsZip, upgradeOTS } from 'neozipkit/blockchain';
155
+
156
+ // Create timestamp for a file's hash
157
+ const otsProof = await createTimestamp(merkleRoot);
158
+
159
+ // Verify a loaded ZIP file
160
+ const result = await verifyOtsZip(zipInstance);
161
+ if (result.status === 'valid') {
162
+ console.log(`Verified! Block: ${result.blockHeight}`);
163
+
164
+ // Upgrade proof if available
165
+ if (result.upgradedOts) {
166
+ await upgradeOTS(zipPath, result.upgradedOts);
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### Contract Configuration (contracts.ts)
172
+ All contract-related constants and configurations in one place:
173
+
174
+ - `CONTRACT_CONFIGS`: Network configurations with contract addresses, RPC URLs, and explorer URLs
175
+ - `NZIP_CONTRACT_ABI`: Full ABI for the NZIP‑NFT contract
176
+ - `CURRENT_DEPLOYMENT`: Current default deployment (Base Sepolia)
177
+ - `DEFAULT_NETWORK`: Default network chain ID (84532)
178
+ - Helper functions: `getContractConfig()`, `getSupportedNetworks()`, `isNetworkSupported()`
179
+
180
+ **Supported Networks**:
181
+ - Base Sepolia (84532) - Primary testnet
182
+ - Base Mainnet (8453) - Production
183
+
184
+ ### Token Verification (ZipKitVerifier.ts)
185
+ - High-level verification API for NZIP‑NFT contract and on-chain checks.
186
+
187
+ ### Token Query (TokenQuerier.ts)
188
+ - `queryBlockchainForExistingToken(merkleRoot: string, networkName: string): Promise<ExistingTokenInfo | null>`
189
+ - `queryWalletTokens(address: string, networkName: string, options?: TokenQueryOptions): Promise<ExistingTokenInfo[]>`
190
+ - `TokenQueryOptions` include pagination/filters as implemented in the module.
191
+
192
+ Re‑exports (index.ts):
193
+ - `queryBlockchainForExistingToken`, `queryWalletTokens`, `ExistingTokenInfo`, `TokenQueryOptions`.
194
+
195
+ ### Wallet Manager (WalletManager.ts)
196
+ - `class WalletManager`
197
+ - Handles provider, signer, and basic transaction flows for the library’s contract interactions.
198
+
199
+ Re‑exports (index.ts):
200
+ - `WalletManager`.
201
+
202
+ ### NFT Minting (ZipKitMinter.ts)
203
+ - High‑level minting API for NZIP‑NFT contract.
204
+
205
+ ### Wallets (ZipKitWallet.ts)
206
+ - `class ZipKitWallet`: Create/load/connect wallets and providers.
207
+ - `class WalletAnalyzer`: Analyze balances, scan NZIP tokens, ERC‑20s and NFTs.
208
+ - Types re‑exported: `TokenInfo`, `NZipTokenDetails`, `WalletBasicInfo`, `TokenScanResult`, `CommonTokenConfig`.
209
+
210
+ - Helpers to format token and wallet data for display.
211
+
212
+ Re‑exports (index.ts):
213
+ Wallet formatting helpers have been removed. Use your app's UI layer for presentation formatting.
214
+
215
+ ### ZIP Metadata Helpers (ZipMetadata.ts)
216
+ - `class ZipMetadata`
217
+ - Validation and rendering helpers for token metadata embedded in ZIPs.
218
+
219
+ Re‑exports (index.ts):
220
+ - `ZipMetadata`.
221
+
222
+ ### Module Types (types.ts)
223
+ Exports shared types used across blockchain operations, including:
224
+ - `NZipTokenInfo`, `NZipTokenDetails`, `ZipFileInfo`, `WalletInfo`, `BlockchainVerification`, and others used by certificate/token helpers.
225
+
226
+ ### Notes
227
+ - All OTS utilities suppress verbose logs by default. Pass `{ debug: true }` to see OpenTimestamps logs.
228
+ - Contract addresses vary per network; see `CONTRACT_ADDRESSES` and keep them updated after deployments.
229
+
@@ -0,0 +1,470 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ZipKitMinter - Handles NFT token minting for ZIP files
5
+ * Minter API for NZIP-NFT smart contract.
6
+ */
7
+
8
+ import { ethers } from 'ethers';
9
+ import { NZIP_CONTRACT_ABI, CONTRACT_CONFIGS } from './contracts';
10
+ import type { TokenMetadata } from './types';
11
+
12
+ // Network configurations
13
+ const NETWORK_CONFIGS = {
14
+ 'base-sepolia': {
15
+ name: 'Base Sepolia',
16
+ rpcUrl: 'https://sepolia.base.org',
17
+ contractAddress: CONTRACT_CONFIGS[84532].address, // Use real contract address
18
+ explorerUrl: 'https://sepolia.basescan.org',
19
+ chainId: 84532
20
+ },
21
+ 'base-mainnet': {
22
+ name: 'Base Mainnet',
23
+ rpcUrl: 'https://mainnet.base.org',
24
+ contractAddress: CONTRACT_CONFIGS[8453].address, // Use real contract address
25
+ explorerUrl: 'https://basescan.org',
26
+ chainId: 8453
27
+ }
28
+ };
29
+
30
+ export interface MintingOptions {
31
+ walletPrivateKey: string;
32
+ network: string;
33
+ verbose?: boolean;
34
+ debug?: boolean;
35
+ }
36
+
37
+ export interface MintingResult {
38
+ success: boolean;
39
+ message: string;
40
+ tokenId?: string;
41
+ transactionHash?: string;
42
+ contractAddress?: string;
43
+ blockNumber?: number;
44
+ walletAddress?: string;
45
+ gasUsed?: string;
46
+ gasCost?: string;
47
+ }
48
+
49
+ export interface TokenInfo {
50
+ tokenId: string;
51
+ owner: string;
52
+ isOwnedByUser: boolean;
53
+ tokenData?: any;
54
+ }
55
+
56
+ export interface DuplicateCheckResult {
57
+ hasExistingTokens: boolean;
58
+ allTokens: TokenInfo[];
59
+ userOwnedTokens: TokenInfo[];
60
+ othersTokens: TokenInfo[];
61
+ }
62
+
63
+ export interface WalletInfo {
64
+ address: string;
65
+ balance: string;
66
+ networkName: string;
67
+ }
68
+
69
+ /**
70
+ * Blockchain Token Minter for ZIP files
71
+ */
72
+ export class ZipKitMinter {
73
+ private provider: ethers.JsonRpcProvider;
74
+ private wallet: ethers.Wallet;
75
+ private contract: ethers.Contract;
76
+ private merkleRoot: string;
77
+ private archiveName: string;
78
+ private networkConfig: any;
79
+ private debug: boolean;
80
+
81
+ constructor(archiveName: string, merkleRoot: string, options: MintingOptions) {
82
+ this.archiveName = archiveName;
83
+ this.merkleRoot = merkleRoot;
84
+ this.debug = options.debug || false;
85
+
86
+ // Get network configuration
87
+ this.networkConfig = NETWORK_CONFIGS[options.network as keyof typeof NETWORK_CONFIGS];
88
+ if (!this.networkConfig) {
89
+ throw new Error(`Unsupported network: ${options.network}`);
90
+ }
91
+
92
+ // Initialize provider for the specified network
93
+ this.provider = new ethers.JsonRpcProvider(this.networkConfig.rpcUrl);
94
+
95
+ // Initialize wallet from private key
96
+ this.wallet = new ethers.Wallet(options.walletPrivateKey, this.provider);
97
+
98
+ // Initialize contract instance
99
+ this.contract = new ethers.Contract(
100
+ this.networkConfig.contractAddress,
101
+ NZIP_CONTRACT_ABI,
102
+ this.wallet
103
+ );
104
+
105
+ if (this.debug) {
106
+ console.log(`[DEBUG] ZipKitMinter initialized for ${this.networkConfig.name}`);
107
+ console.log(`[DEBUG] Archive: ${archiveName}, Merkle: ${merkleRoot.substring(0, 10)}...`);
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Get wallet information
113
+ */
114
+ async getWalletInfo(): Promise<WalletInfo> {
115
+ const balance = await this.provider.getBalance(this.wallet.address);
116
+ const balanceInEth = ethers.formatEther(balance);
117
+
118
+ if (this.debug) {
119
+ console.log(`[DEBUG] Wallet ${this.wallet.address} balance: ${balanceInEth} ETH`);
120
+ }
121
+
122
+ return {
123
+ address: this.wallet.address,
124
+ balance: balanceInEth,
125
+ networkName: this.networkConfig.name
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Check for existing tokens with same merkle root and verify ownership
131
+ */
132
+ async checkForDuplicates(): Promise<DuplicateCheckResult> {
133
+ try {
134
+ if (this.debug) {
135
+ console.log(`[DEBUG] Checking for existing tokens with merkle root: ${this.merkleRoot}`);
136
+ console.log(`[DEBUG] User wallet address: ${this.wallet.address}`);
137
+ }
138
+
139
+ // Call contract method to check if merkle root already exists
140
+ const existingTokenIds = await this.contract.getTokensByMerkleRoot(this.merkleRoot);
141
+
142
+ if (!existingTokenIds || existingTokenIds.length === 0) {
143
+ if (this.debug) {
144
+ console.log(`[DEBUG] No existing tokens found for this merkle root`);
145
+ }
146
+ return {
147
+ hasExistingTokens: false,
148
+ allTokens: [],
149
+ userOwnedTokens: [],
150
+ othersTokens: []
151
+ };
152
+ }
153
+
154
+ if (this.debug) {
155
+ console.log(`[DEBUG] Found ${existingTokenIds.length} existing token(s)`);
156
+ }
157
+
158
+ // Check ownership and get token details for each token
159
+ const allTokens: TokenInfo[] = [];
160
+ const userOwnedTokens: TokenInfo[] = [];
161
+ const othersTokens: TokenInfo[] = [];
162
+
163
+ for (const tokenId of existingTokenIds) {
164
+ const tokenIdStr = tokenId.toString();
165
+
166
+ try {
167
+ // Get token owner
168
+ const owner = await this.contract.ownerOf(tokenId);
169
+ const isOwnedByUser = owner.toLowerCase() === this.wallet.address.toLowerCase();
170
+
171
+ // Get token data
172
+ let tokenData = null;
173
+ try {
174
+ tokenData = await this.contract.getZipFileInfo(tokenId);
175
+ } catch (e) {
176
+ if (this.debug) {
177
+ console.log(`[DEBUG] Could not get token data for ${tokenIdStr}: ${e}`);
178
+ }
179
+ }
180
+
181
+ const tokenInfo: TokenInfo = {
182
+ tokenId: tokenIdStr,
183
+ owner: owner,
184
+ isOwnedByUser: isOwnedByUser,
185
+ tokenData: tokenData
186
+ };
187
+
188
+ allTokens.push(tokenInfo);
189
+
190
+ if (isOwnedByUser) {
191
+ userOwnedTokens.push(tokenInfo);
192
+ if (this.debug) {
193
+ console.log(`[DEBUG] Token ${tokenIdStr} is owned by user`);
194
+ }
195
+ } else {
196
+ othersTokens.push(tokenInfo);
197
+ if (this.debug) {
198
+ console.log(`[DEBUG] Token ${tokenIdStr} is owned by ${owner}`);
199
+ }
200
+ }
201
+
202
+ } catch (e) {
203
+ if (this.debug) {
204
+ console.log(`[DEBUG] Error checking ownership for token ${tokenIdStr}: ${e}`);
205
+ }
206
+ }
207
+ }
208
+
209
+ return {
210
+ hasExistingTokens: true,
211
+ allTokens,
212
+ userOwnedTokens,
213
+ othersTokens
214
+ };
215
+
216
+ } catch (error) {
217
+ if (this.debug) {
218
+ console.log(`[DEBUG] Error checking duplicates: ${error instanceof Error ? error.message : 'Unknown error'}`);
219
+ }
220
+
221
+ // If the contract method doesn't exist or fails, assume no duplicates
222
+ return {
223
+ hasExistingTokens: false,
224
+ allTokens: [],
225
+ userOwnedTokens: [],
226
+ othersTokens: []
227
+ };
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Estimate gas costs for minting
233
+ */
234
+ async estimateGasCosts(): Promise<{ gasLimit: bigint; gasPrice: bigint; estimatedCost: string }> {
235
+ const creationTimestamp = Math.floor(Date.now() / 1000);
236
+ const metadata = this.createTokenMetadataString();
237
+
238
+ // Estimate gas for the minting transaction
239
+ const gasLimit = await this.contract.publicMintZipFile.estimateGas(
240
+ this.archiveName,
241
+ this.merkleRoot,
242
+ creationTimestamp,
243
+ '', // ipfsHash
244
+ metadata
245
+ );
246
+
247
+ const feeData = await this.provider.getFeeData();
248
+ const gasPrice = feeData.gasPrice || BigInt(0);
249
+ const estimatedCost = ethers.formatEther(gasLimit * gasPrice);
250
+
251
+ if (this.debug) {
252
+ console.log(`[DEBUG] Gas estimate - Limit: ${gasLimit}, Price: ${gasPrice}, Cost: ${estimatedCost} ETH`);
253
+ }
254
+
255
+ return { gasLimit, gasPrice, estimatedCost };
256
+ }
257
+
258
+ /**
259
+ * Create token metadata string
260
+ */
261
+ private createTokenMetadataString(): string {
262
+ const now = new Date();
263
+ return JSON.stringify({
264
+ name: `NeoZip Archive: ${this.archiveName}`,
265
+ description: `Tokenized ZIP archive with cryptographic proof of integrity`,
266
+ image: '', // Could be a thumbnail or icon
267
+ archiveName: this.archiveName,
268
+ merkleRoot: this.merkleRoot,
269
+ network: this.networkConfig.name,
270
+ createdAt: now.toISOString(),
271
+ timestamp: Math.floor(now.getTime() / 1000)
272
+ });
273
+ }
274
+
275
+ /**
276
+ * Create TokenMetadata object from minting result
277
+ */
278
+ private createTokenMetadata(tokenId: string, transactionHash: string, blockNumber?: number): TokenMetadata {
279
+ const now = new Date();
280
+
281
+ return {
282
+ tokenId,
283
+ network: this.networkConfig.name,
284
+ contractAddress: this.networkConfig.contractAddress,
285
+ merkleRoot: this.merkleRoot,
286
+ mintDate: now.toLocaleDateString('en-US') + ' at ' + now.toLocaleTimeString('en-US'),
287
+ creationTimestamp: Math.floor(now.getTime() / 1000),
288
+ archiveName: this.archiveName,
289
+ transactionHash,
290
+ blockNumber
291
+ };
292
+ }
293
+
294
+ /**
295
+ * Mint new token on blockchain
296
+ */
297
+ async mintToken(): Promise<MintingResult> {
298
+ try {
299
+ if (this.debug) {
300
+ console.log(`[DEBUG] Starting token minting process`);
301
+ }
302
+
303
+ // Generate token ID (could be random or sequential)
304
+ const tokenId = Math.floor(Math.random() * 1000000).toString();
305
+ const metadata = this.createTokenMetadataString();
306
+ const creationTimestamp = Math.floor(Date.now() / 1000);
307
+
308
+ if (this.debug) {
309
+ console.log(`[DEBUG] Generated token ID: ${tokenId}`);
310
+ console.log(`[DEBUG] Metadata: ${metadata.substring(0, 100)}...`);
311
+ }
312
+
313
+ // Call the contract publicMintZipFile function
314
+ const tx = await this.contract.publicMintZipFile(
315
+ this.archiveName,
316
+ this.merkleRoot,
317
+ creationTimestamp,
318
+ '', // ipfsHash (empty since we store in ZIP)
319
+ metadata
320
+ );
321
+
322
+ if (this.debug) {
323
+ console.log(`[DEBUG] Transaction submitted: ${tx.hash}`);
324
+ }
325
+
326
+ // Wait for transaction confirmation
327
+ const receipt = await tx.wait();
328
+
329
+ if (this.debug) {
330
+ console.log(`[DEBUG] Transaction confirmed in block: ${receipt.blockNumber}`);
331
+ console.log(`[DEBUG] Gas used: ${receipt.gasUsed}`);
332
+ }
333
+
334
+ // Extract actual token ID from contract events
335
+ let actualTokenId = tokenId; // fallback
336
+
337
+ if (receipt.logs && receipt.logs.length > 0) {
338
+ try {
339
+ const iface = new ethers.Interface(NZIP_CONTRACT_ABI);
340
+ for (const log of receipt.logs) {
341
+ try {
342
+ const parsed = iface.parseLog(log);
343
+ if (parsed?.name === 'ZipFileTokenized') {
344
+ actualTokenId = parsed.args.tokenId.toString();
345
+ if (this.debug) {
346
+ console.log(`[DEBUG] Actual token ID from contract event: ${actualTokenId}`);
347
+ }
348
+ break;
349
+ }
350
+ } catch (e) {
351
+ // Ignore parsing errors for non-matching logs
352
+ }
353
+ }
354
+ } catch (e) {
355
+ if (this.debug) {
356
+ console.log(`[DEBUG] Could not parse token ID from logs: ${e}`);
357
+ }
358
+ }
359
+ }
360
+
361
+ const gasCost = ethers.formatEther(receipt.gasUsed * (receipt.gasPrice || BigInt(0)));
362
+
363
+ return {
364
+ success: true,
365
+ message: `Token successfully minted`,
366
+ tokenId: actualTokenId,
367
+ transactionHash: tx.hash,
368
+ contractAddress: this.networkConfig.contractAddress,
369
+ blockNumber: receipt.blockNumber,
370
+ walletAddress: this.wallet.address,
371
+ gasUsed: receipt.gasUsed.toString(),
372
+ gasCost
373
+ };
374
+
375
+ } catch (error) {
376
+ const errorMessage = error instanceof Error ? error.message : 'Unknown minting error';
377
+
378
+ if (this.debug) {
379
+ console.log(`[DEBUG] Minting failed: ${errorMessage}`);
380
+ }
381
+
382
+ return {
383
+ success: false,
384
+ message: errorMessage
385
+ };
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Main minting process - checks for duplicates, then mints if needed
391
+ */
392
+ async processMinting(): Promise<{
393
+ walletInfo: WalletInfo;
394
+ duplicateCheck: DuplicateCheckResult;
395
+ gasCosts?: { gasLimit: bigint; gasPrice: bigint; estimatedCost: string };
396
+ mintingResult?: MintingResult;
397
+ tokenMetadata?: TokenMetadata;
398
+ }> {
399
+ try {
400
+ // Get wallet information
401
+ const walletInfo = await this.getWalletInfo();
402
+
403
+ // Check for duplicates first (free operation)
404
+ const duplicateCheck = await this.checkForDuplicates();
405
+
406
+ if (duplicateCheck.hasExistingTokens) {
407
+ if (this.debug) {
408
+ console.log(`[DEBUG] Existing tokens found, user will choose`);
409
+ }
410
+
411
+ return {
412
+ walletInfo,
413
+ duplicateCheck
414
+ };
415
+ }
416
+
417
+ // Estimate gas costs
418
+ const gasCosts = await this.estimateGasCosts();
419
+
420
+ // This is where the user would be prompted for confirmation in the calling code
421
+ // The actual minting happens in a separate call to mintToken()
422
+
423
+ return {
424
+ walletInfo,
425
+ duplicateCheck,
426
+ gasCosts
427
+ };
428
+
429
+ } catch (error) {
430
+ throw new Error(`Minting process failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Complete the minting after user confirmation
436
+ */
437
+ async completeMinting(): Promise<{
438
+ mintingResult: MintingResult;
439
+ tokenMetadata?: TokenMetadata;
440
+ }> {
441
+ const mintingResult = await this.mintToken();
442
+
443
+ if (mintingResult.success && mintingResult.tokenId && mintingResult.transactionHash) {
444
+ const tokenMetadata = this.createTokenMetadata(
445
+ mintingResult.tokenId,
446
+ mintingResult.transactionHash,
447
+ mintingResult.blockNumber
448
+ );
449
+
450
+ return {
451
+ mintingResult,
452
+ tokenMetadata
453
+ };
454
+ }
455
+
456
+ return { mintingResult };
457
+ }
458
+ }
459
+
460
+ /**
461
+ * Utility function to validate Ethereum private key
462
+ */
463
+ export function validatePrivateKey(privateKey: string): boolean {
464
+ try {
465
+ new ethers.Wallet(privateKey);
466
+ return true;
467
+ } catch {
468
+ return false;
469
+ }
470
+ }
@@ -0,0 +1,12 @@
1
+ // Re-export NFT classes and types without aliases
2
+ export { ZipKitMinter, ZipKitVerifier } from '.';
3
+ export type {
4
+ MintingOptions,
5
+ MintingResult,
6
+ DuplicateCheckResult,
7
+ TokenInfo,
8
+ WalletInfo,
9
+ VerificationOptions,
10
+ VerificationResult,
11
+ } from '.';
12
+ export type { TokenMetadata } from './types';