neozipkit 0.2.1 → 0.3.0

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 (301) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +410 -186
  3. package/contracts/ABI.txt +889 -0
  4. package/contracts/Bytecode.txt +1 -0
  5. package/contracts/COMPILATION_NOTES.md +59 -0
  6. package/contracts/QUICK_DEPLOY.md +286 -0
  7. package/contracts/README.md +235 -131
  8. package/contracts/VERIFICATION.md +308 -0
  9. package/contracts/deploy-interactive.js +448 -0
  10. package/contracts/deployment-arbitrum-sepolia.json +12 -0
  11. package/contracts/deployment-arbitrum.json +12 -0
  12. package/contracts/deployment-eth-sepolia.json +12 -0
  13. package/contracts/hardhat.config.js +114 -0
  14. package/contracts/package.json +20 -0
  15. package/contracts/scripts/compile-and-extract.js +119 -0
  16. package/contracts/scripts/verify-contract.js +223 -0
  17. package/contracts/src/{NZIP-NFT-Private.sol → NZIP-NFT-v2.0.sol} +66 -151
  18. package/contracts/src/NZIP-NFT.sol +9 -15
  19. package/dist/blockchain/browser/TokenVerifierBrowser.d.ts +67 -0
  20. package/dist/blockchain/browser/TokenVerifierBrowser.d.ts.map +1 -0
  21. package/dist/blockchain/browser/TokenVerifierBrowser.js +313 -0
  22. package/dist/blockchain/browser/TokenVerifierBrowser.js.map +1 -0
  23. package/dist/blockchain/browser/WalletManagerBrowser.d.ts +98 -0
  24. package/dist/blockchain/browser/WalletManagerBrowser.d.ts.map +1 -0
  25. package/dist/blockchain/browser/WalletManagerBrowser.js +434 -0
  26. package/dist/blockchain/browser/WalletManagerBrowser.js.map +1 -0
  27. package/dist/blockchain/browser/ZipkitMinterBrowser.d.ts +58 -0
  28. package/dist/blockchain/browser/ZipkitMinterBrowser.d.ts.map +1 -0
  29. package/dist/blockchain/browser/ZipkitMinterBrowser.js +317 -0
  30. package/dist/blockchain/browser/ZipkitMinterBrowser.js.map +1 -0
  31. package/dist/blockchain/browser/index.d.ts +11 -0
  32. package/dist/blockchain/browser/index.d.ts.map +1 -0
  33. package/dist/blockchain/browser/index.js +16 -0
  34. package/dist/blockchain/browser/index.js.map +1 -0
  35. package/dist/blockchain/core/WalletManager.d.ts +124 -0
  36. package/dist/blockchain/core/WalletManager.d.ts.map +1 -0
  37. package/dist/blockchain/{ZipKitWallet.js → core/WalletManager.js} +157 -177
  38. package/dist/blockchain/core/WalletManager.js.map +1 -0
  39. package/dist/blockchain/{ZipKitMinter.d.ts → core/ZipkitMinter.d.ts} +46 -11
  40. package/dist/blockchain/core/ZipkitMinter.d.ts.map +1 -0
  41. package/dist/blockchain/core/ZipkitMinter.js +548 -0
  42. package/dist/blockchain/core/ZipkitMinter.js.map +1 -0
  43. package/dist/blockchain/{ZipKitOTS.d.ts → core/ZipkitOTS.d.ts} +6 -15
  44. package/dist/blockchain/core/ZipkitOTS.d.ts.map +1 -0
  45. package/dist/blockchain/{ZipKitOTS.js → core/ZipkitOTS.js} +26 -84
  46. package/dist/blockchain/core/ZipkitOTS.js.map +1 -0
  47. package/dist/blockchain/core/ZipkitVerifier.d.ts +177 -0
  48. package/dist/blockchain/core/ZipkitVerifier.d.ts.map +1 -0
  49. package/dist/blockchain/core/ZipkitVerifier.js +632 -0
  50. package/dist/blockchain/core/ZipkitVerifier.js.map +1 -0
  51. package/dist/blockchain/core/contracts.d.ts +83 -0
  52. package/dist/blockchain/core/contracts.d.ts.map +1 -0
  53. package/dist/blockchain/core/contracts.js +341 -0
  54. package/dist/blockchain/core/contracts.js.map +1 -0
  55. package/dist/blockchain/core/index.d.ts +12 -0
  56. package/dist/blockchain/core/index.d.ts.map +1 -0
  57. package/dist/blockchain/core/index.js +59 -0
  58. package/dist/blockchain/core/index.js.map +1 -0
  59. package/dist/blockchain/index.d.ts +11 -7
  60. package/dist/blockchain/index.d.ts.map +1 -0
  61. package/dist/blockchain/index.js +18 -34
  62. package/dist/blockchain/index.js.map +1 -0
  63. package/dist/blockchain/node/WalletManagerNode.d.ts +47 -0
  64. package/dist/blockchain/node/WalletManagerNode.d.ts.map +1 -0
  65. package/dist/blockchain/node/WalletManagerNode.js +203 -0
  66. package/dist/blockchain/node/WalletManagerNode.js.map +1 -0
  67. package/dist/blockchain/node/index.d.ts +12 -0
  68. package/dist/blockchain/node/index.d.ts.map +1 -0
  69. package/dist/blockchain/node/index.js +24 -0
  70. package/dist/blockchain/node/index.js.map +1 -0
  71. package/dist/browser/ZipkitBrowser.d.ts +27 -0
  72. package/dist/browser/ZipkitBrowser.d.ts.map +1 -0
  73. package/dist/browser/{ZipKitBrowser.js → ZipkitBrowser.js} +96 -43
  74. package/dist/browser/ZipkitBrowser.js.map +1 -0
  75. package/dist/browser/index.d.ts +12 -0
  76. package/dist/browser/index.d.ts.map +1 -0
  77. package/dist/browser/index.js +42 -0
  78. package/dist/browser/index.js.map +1 -0
  79. package/dist/browser-esm/index.d.ts +12 -0
  80. package/dist/browser-esm/index.js +59559 -0
  81. package/dist/browser-esm/index.js.map +7 -0
  82. package/dist/browser-umd/index.d.ts +12 -0
  83. package/dist/browser-umd/index.js +59576 -0
  84. package/dist/browser-umd/index.js.map +7 -0
  85. package/dist/browser-umd/index.min.js +63 -0
  86. package/dist/browser.d.ts +8 -14
  87. package/dist/browser.js +13 -28
  88. package/dist/core/ZipCompress.d.ts +99 -0
  89. package/dist/core/ZipCompress.d.ts.map +1 -0
  90. package/dist/core/ZipCompress.js +309 -0
  91. package/dist/core/ZipCompress.js.map +1 -0
  92. package/dist/core/ZipDecompress.d.ts +58 -0
  93. package/dist/core/ZipDecompress.d.ts.map +1 -0
  94. package/dist/core/ZipDecompress.js +172 -0
  95. package/dist/core/ZipDecompress.js.map +1 -0
  96. package/dist/{shared → core}/ZipEntry.d.ts +8 -1
  97. package/dist/core/ZipEntry.d.ts.map +1 -0
  98. package/dist/{shared → core}/ZipEntry.js +225 -82
  99. package/dist/core/ZipEntry.js.map +1 -0
  100. package/dist/core/Zipkit.d.ts +315 -0
  101. package/dist/core/Zipkit.d.ts.map +1 -0
  102. package/dist/core/Zipkit.js +647 -0
  103. package/dist/core/Zipkit.js.map +1 -0
  104. package/dist/core/components/HashCalculator.d.ts +138 -0
  105. package/dist/core/components/HashCalculator.d.ts.map +1 -0
  106. package/dist/core/components/HashCalculator.js +360 -0
  107. package/dist/core/components/HashCalculator.js.map +1 -0
  108. package/dist/core/components/Logger.d.ts +73 -0
  109. package/dist/core/components/Logger.d.ts.map +1 -0
  110. package/dist/core/components/Logger.js +156 -0
  111. package/dist/core/components/Logger.js.map +1 -0
  112. package/dist/core/components/ProgressTracker.d.ts +43 -0
  113. package/dist/core/components/ProgressTracker.d.ts.map +1 -0
  114. package/dist/core/components/ProgressTracker.js +112 -0
  115. package/dist/core/components/ProgressTracker.js.map +1 -0
  116. package/dist/{shared → core}/components/Support.d.ts +1 -0
  117. package/dist/core/components/Support.d.ts.map +1 -0
  118. package/dist/{shared → core}/components/Support.js +1 -0
  119. package/dist/core/components/Support.js.map +1 -0
  120. package/dist/{shared → core}/components/Util.d.ts +7 -2
  121. package/dist/core/components/Util.d.ts.map +1 -0
  122. package/dist/{shared → core}/components/Util.js +14 -34
  123. package/dist/core/components/Util.js.map +1 -0
  124. package/dist/{shared → core}/constants/Errors.d.ts +1 -2
  125. package/dist/core/constants/Errors.d.ts.map +1 -0
  126. package/dist/{shared → core}/constants/Errors.js +1 -3
  127. package/dist/core/constants/Errors.js.map +1 -0
  128. package/dist/{shared → core}/constants/Headers.d.ts +3 -0
  129. package/dist/core/constants/Headers.d.ts.map +1 -0
  130. package/dist/{shared → core}/constants/Headers.js +20 -17
  131. package/dist/core/constants/Headers.js.map +1 -0
  132. package/dist/core/encryption/Manager.d.ts +58 -0
  133. package/dist/core/encryption/Manager.d.ts.map +1 -0
  134. package/dist/core/encryption/Manager.js +121 -0
  135. package/dist/core/encryption/Manager.js.map +1 -0
  136. package/dist/core/encryption/ZipCrypto.d.ts +172 -0
  137. package/dist/core/encryption/ZipCrypto.d.ts.map +1 -0
  138. package/dist/core/encryption/ZipCrypto.js +554 -0
  139. package/dist/core/encryption/ZipCrypto.js.map +1 -0
  140. package/dist/core/encryption/index.d.ts +9 -0
  141. package/dist/core/encryption/index.d.ts.map +1 -0
  142. package/dist/core/encryption/index.js +17 -0
  143. package/dist/core/encryption/index.js.map +1 -0
  144. package/dist/core/encryption/types.d.ts +29 -0
  145. package/dist/core/encryption/types.d.ts.map +1 -0
  146. package/dist/core/encryption/types.js +12 -0
  147. package/dist/core/encryption/types.js.map +1 -0
  148. package/dist/core/index.d.ts +24 -0
  149. package/dist/core/index.d.ts.map +1 -0
  150. package/dist/core/index.js +57 -0
  151. package/dist/core/index.js.map +1 -0
  152. package/dist/core/version.d.ts +5 -0
  153. package/dist/core/version.d.ts.map +1 -0
  154. package/dist/core/version.js +31 -0
  155. package/dist/core/version.js.map +1 -0
  156. package/dist/index.d.ts +8 -18
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +29 -35
  159. package/dist/index.js.map +1 -0
  160. package/dist/node/ZipCompressNode.d.ts +123 -0
  161. package/dist/node/ZipCompressNode.d.ts.map +1 -0
  162. package/dist/node/ZipCompressNode.js +576 -0
  163. package/dist/node/ZipCompressNode.js.map +1 -0
  164. package/dist/node/ZipDecompressNode.d.ts +120 -0
  165. package/dist/node/ZipDecompressNode.d.ts.map +1 -0
  166. package/dist/node/ZipDecompressNode.js +461 -0
  167. package/dist/node/ZipDecompressNode.js.map +1 -0
  168. package/dist/node/ZipkitNode.d.ts +406 -0
  169. package/dist/node/ZipkitNode.d.ts.map +1 -0
  170. package/dist/node/ZipkitNode.js +1305 -0
  171. package/dist/node/ZipkitNode.js.map +1 -0
  172. package/dist/node/index.d.ts +26 -0
  173. package/dist/node/index.d.ts.map +1 -0
  174. package/dist/node/index.js +65 -0
  175. package/dist/node/index.js.map +1 -0
  176. package/dist/types/index.d.ts +59 -0
  177. package/dist/types/index.d.ts.map +1 -0
  178. package/dist/types/index.js +36 -1
  179. package/dist/types/index.js.map +1 -0
  180. package/examples/README.md +269 -0
  181. package/examples/blockchain-tokenize.ts +354 -0
  182. package/examples/create-zip.ts +172 -0
  183. package/examples/extract-zip.ts +158 -0
  184. package/examples/list-zip.ts +161 -0
  185. package/examples/test-files/data.json +116 -0
  186. package/examples/test-files/document.md +80 -0
  187. package/examples/test-files/document.txt +2 -0
  188. package/examples/test-files/file1.txt +48 -0
  189. package/examples/test-files/file2.txt +80 -0
  190. package/examples/tsconfig.json +44 -0
  191. package/examples/unzip-token.ts +491 -0
  192. package/examples/verify-tokenized-zip.ts +305 -0
  193. package/examples/zip-token.ts +604 -0
  194. package/package.json +108 -24
  195. package/src/blockchain/README.md +59 -66
  196. package/src/{browser/TokenVerifierBrowser.ts-remove → blockchain/browser/TokenVerifierBrowser.ts} +125 -79
  197. package/src/blockchain/browser/WalletManagerBrowser.ts +486 -0
  198. package/src/blockchain/browser/ZipkitMinterBrowser.ts +400 -0
  199. package/src/blockchain/browser/index.ts +13 -0
  200. package/src/blockchain/{ZipKitWallet.ts → core/WalletManager.ts} +241 -143
  201. package/src/blockchain/core/ZipkitMinter.ts +716 -0
  202. package/src/blockchain/{ZipKitOTS.ts → core/ZipkitOTS.ts} +28 -62
  203. package/src/blockchain/core/ZipkitVerifier.ts +853 -0
  204. package/src/blockchain/core/contracts.ts +370 -0
  205. package/src/blockchain/core/index.ts +71 -0
  206. package/src/blockchain/index.ts +21 -55
  207. package/src/blockchain/node/WalletManagerNode.ts +171 -0
  208. package/src/blockchain/node/index.ts +40 -0
  209. package/src/browser/{ZipKitBrowser.ts → ZipkitBrowser.ts} +104 -41
  210. package/src/browser/index.esm.ts +37 -0
  211. package/src/browser/index.ts +25 -0
  212. package/src/core/ZipCompress.ts +398 -0
  213. package/src/core/ZipDecompress.ts +212 -0
  214. package/src/{shared → core}/ZipEntry.ts +240 -90
  215. package/src/core/Zipkit.ts +794 -0
  216. package/src/core/components/HashCalculator.ts +384 -0
  217. package/src/core/components/Logger.ts +180 -0
  218. package/src/core/components/ProgressTracker.ts +134 -0
  219. package/src/{shared → core}/components/Util.ts +12 -34
  220. package/src/{shared → core}/constants/Errors.ts +0 -4
  221. package/src/{shared → core}/constants/Headers.ts +19 -17
  222. package/src/core/encryption/Manager.ts +137 -0
  223. package/src/core/encryption/ZipCrypto.ts +650 -0
  224. package/src/core/encryption/index.ts +15 -0
  225. package/src/core/encryption/types.ts +33 -0
  226. package/src/core/index.ts +34 -0
  227. package/src/core/version.ts +33 -0
  228. package/src/index.ts +54 -25
  229. package/src/node/ZipCompressNode.ts +632 -0
  230. package/src/node/ZipDecompressNode.ts +508 -0
  231. package/src/node/ZipkitNode.ts +1559 -0
  232. package/src/node/index.ts +69 -0
  233. package/src/types/index.ts +131 -1
  234. package/src/types/modules.d.ts +1 -11
  235. package/src/types/opentimestamps.d.ts +1 -23
  236. package/contracts/INTEGRATION.md +0 -338
  237. package/contracts/NETWORKS.md +0 -156
  238. package/contracts/NZIP-NFT-bytecode.txt +0 -1
  239. package/contracts/constants.ts +0 -952
  240. package/contracts/deploy-bytecode.mjs +0 -94
  241. package/dist/blockchain/CertificateToken.d.ts +0 -48
  242. package/dist/blockchain/CertificateToken.js +0 -386
  243. package/dist/blockchain/ZipKitMinter.js +0 -347
  244. package/dist/blockchain/ZipKitNFT.d.ts +0 -3
  245. package/dist/blockchain/ZipKitNFT.js +0 -7
  246. package/dist/blockchain/ZipKitVerifier.d.ts +0 -69
  247. package/dist/blockchain/ZipKitVerifier.js +0 -289
  248. package/dist/blockchain/ZipKitWallet.d.ts +0 -69
  249. package/dist/blockchain/contracts.d.ts +0 -14
  250. package/dist/blockchain/contracts.js +0 -77
  251. package/dist/blockchain/types.d.ts +0 -47
  252. package/dist/blockchain/types.js +0 -30
  253. package/dist/browser/ZipKitBrowser.d.ts +0 -18
  254. package/dist/browser/ZipKitStampBrowser.d.ts +0 -2
  255. package/dist/browser/ZipKitStampBrowser.js +0 -12
  256. package/dist/browser-index.d.ts +0 -18
  257. package/dist/browser-index.js +0 -57
  258. package/dist/server/ZipKitServer.d.ts +0 -74
  259. package/dist/server/ZipKitServer.js +0 -310
  260. package/dist/shared/ZipKit.d.ts +0 -243
  261. package/dist/shared/ZipKit.js +0 -772
  262. package/dist/shared/components/CertificateOTS.d.ts +0 -15
  263. package/dist/shared/components/CertificateOTS.js +0 -116
  264. package/dist/shared/components/FileSys.d.ts +0 -2
  265. package/dist/shared/components/FileSys.js +0 -113
  266. package/dist/shared/components/HashAccumulator.d.ts +0 -55
  267. package/dist/shared/components/HashAccumulator.js +0 -100
  268. package/dist/shared/components/ZipCrypto.d.ts +0 -3
  269. package/dist/shared/components/ZipCrypto.js +0 -78
  270. package/dist/shared/components/merkleTree.d.ts +0 -66
  271. package/dist/shared/components/merkleTree.js +0 -136
  272. package/dist/shared/types/index.d.ts +0 -21
  273. package/dist/shared/types/index.js +0 -3
  274. package/dist/shared/types.d.ts +0 -33
  275. package/dist/shared/types.js +0 -8
  276. package/dist/shared/version.d.ts +0 -2
  277. package/dist/shared/version.js +0 -6
  278. package/src/blockchain/CertificateToken.ts +0 -444
  279. package/src/blockchain/ZipKitMinter.ts +0 -470
  280. package/src/blockchain/ZipKitNFT.ts +0 -12
  281. package/src/blockchain/ZipKitVerifier.ts +0 -382
  282. package/src/blockchain/contracts.ts +0 -88
  283. package/src/blockchain/types.ts +0 -91
  284. package/src/browser/CertificateGeneratorBrowser.ts-remove +0 -498
  285. package/src/browser/ZipKitStampBrowser.ts +0 -9
  286. package/src/browser-index.ts +0 -36
  287. package/src/server/README.md +0 -25
  288. package/src/server/ZipKitServer.ts +0 -305
  289. package/src/shared/ZipKit.ts +0 -881
  290. package/src/shared/components/CertificateOTS.ts +0 -132
  291. package/src/shared/components/FileSys.ts +0 -87
  292. package/src/shared/components/HashAccumulator.ts +0 -113
  293. package/src/shared/components/ZipCrypto.ts +0 -91
  294. package/src/shared/components/merkleTree.ts +0 -162
  295. package/src/shared/types/index.ts +0 -25
  296. package/src/shared/types/modules.d.ts +0 -22
  297. package/src/shared/types/opentimestamps.d.ts +0 -23
  298. package/src/shared/types.d.ts +0 -8
  299. package/src/shared/types.ts +0 -43
  300. package/src/shared/version.ts +0 -3
  301. /package/src/{shared → core}/components/Support.ts +0 -0
@@ -0,0 +1,486 @@
1
+ /**
2
+ * WalletManagerBrowser - Handles browser-specific wallet operations
3
+ * Manages MetaMask, Coinbase Wallet, and other browser providers
4
+ * Extends CoreWalletManager with browser-specific functionality
5
+ */
6
+
7
+ import { ethers } from 'ethers';
8
+ import { CoreWalletManager } from '../core/WalletManager';
9
+ import { CONTRACT_CONFIGS, getContractConfig, isNetworkSupported, NZIP_CONTRACT_ABI } from '../core/contracts';
10
+ import { Logger } from '../../core/components/Logger';
11
+
12
+ // Extend Window interface for Ethereum provider
13
+ declare global {
14
+ interface Window {
15
+ ethereum?: any
16
+ }
17
+ }
18
+
19
+ export interface WalletConfigBrowser {
20
+ chainId: number
21
+ network: string
22
+ address: string
23
+ rpcUrls: string[]
24
+ explorerUrl: string
25
+ }
26
+
27
+ export class WalletManagerBrowser extends CoreWalletManager {
28
+ private browserProvider: ethers.BrowserProvider | null = null
29
+ private readProvider: ethers.JsonRpcProvider | null = null
30
+ private contract: ethers.Contract | null = null
31
+ private currentConfig: WalletConfigBrowser
32
+ private targetChainId: number | null = null
33
+
34
+ // Dedicated RPC endpoints for read operations (to avoid rate limiting)
35
+ private RPC_ENDPOINTS: Record<number, string> = {
36
+ 1: getContractConfig(1).rpcUrls[0],
37
+ 11155111: getContractConfig(11155111).rpcUrls[0],
38
+ 84532: getContractConfig(84532).rpcUrls[0],
39
+ 8453: getContractConfig(8453).rpcUrls[0]
40
+ }
41
+
42
+ constructor(initialChainId: number = 84532) {
43
+ super();
44
+ this.currentConfig = getContractConfig(initialChainId)
45
+ }
46
+
47
+ /**
48
+ * Cleanup method to dispose of providers and stop background processes
49
+ */
50
+ public cleanup(): void {
51
+ Logger.log('🧹 Cleaning up browser wallet manager providers...')
52
+
53
+ try {
54
+ // Clear providers to stop any ongoing background processes
55
+ if (this.readProvider) {
56
+ try {
57
+ (this.readProvider as any).destroy?.()
58
+ } catch (error) {
59
+ Logger.warn('Could not destroy read provider:', error)
60
+ }
61
+ this.readProvider = null
62
+ }
63
+
64
+ if (this.browserProvider) {
65
+ this.browserProvider = null
66
+ }
67
+
68
+ if (this.contract) {
69
+ this.contract = null
70
+ }
71
+
72
+ Logger.log('✅ Browser wallet manager cleanup completed')
73
+ } catch (error) {
74
+ Logger.warn('Error during browser wallet manager cleanup:', error)
75
+ }
76
+ }
77
+
78
+ private getNetworkName(chainId: number): string {
79
+ const networkNames: Record<number, string> = {
80
+ 1: "homestead",
81
+ 11155111: "sepolia",
82
+ 84532: "base-sepolia",
83
+ 8453: "base"
84
+ }
85
+ return networkNames[chainId] || `chain-${chainId}`
86
+ }
87
+
88
+ /**
89
+ * Set the target network for wallet operations
90
+ */
91
+ public setTargetNetwork(chainId: number): void {
92
+ if (!isNetworkSupported(chainId)) {
93
+ throw new Error(`Network ${chainId} is not supported for tokenization`)
94
+ }
95
+
96
+ this.targetChainId = chainId
97
+ this.currentConfig = getContractConfig(chainId)
98
+
99
+ Logger.log(`🎯 Target network set to: ${this.currentConfig.network} (${chainId})`)
100
+ Logger.log(`📍 Contract address: ${this.currentConfig.address}`)
101
+ }
102
+
103
+ /**
104
+ * Get the current target network configuration
105
+ */
106
+ public getCurrentConfig(): WalletConfigBrowser {
107
+ return this.currentConfig
108
+ }
109
+
110
+ /**
111
+ * Initialize wallet with browser provider
112
+ */
113
+ async initialize(walletAddress: string, existingProvider?: any): Promise<boolean> {
114
+ try {
115
+ // Use existing provider if available, otherwise create new one
116
+ if (existingProvider) {
117
+ Logger.log("🔄 Using existing wallet provider for tokenization")
118
+
119
+ try {
120
+ this.browserProvider = new ethers.BrowserProvider(existingProvider)
121
+ await this.testProviderConnection(existingProvider)
122
+ } catch (providerError) {
123
+ Logger.warn("❌ Existing provider failed, falling back to window.ethereum:", providerError)
124
+
125
+ if (window.ethereum) {
126
+ this.browserProvider = new ethers.BrowserProvider(window.ethereum)
127
+ await this.testProviderConnection(window.ethereum)
128
+ } else {
129
+ throw new Error("No wallet provider available")
130
+ }
131
+ }
132
+ } else if (window.ethereum) {
133
+ Logger.log("🔄 Creating new provider from window.ethereum")
134
+
135
+ try {
136
+ this.browserProvider = new ethers.BrowserProvider(window.ethereum)
137
+ await this.testProviderConnection(window.ethereum)
138
+ } catch (windowEthError: any) {
139
+ throw new Error(`Failed to connect to wallet: ${windowEthError.message}`)
140
+ }
141
+ } else {
142
+ throw new Error("No wallet provider found")
143
+ }
144
+
145
+ // Get chain ID with rate limit protection
146
+ let chainId: number | null = null
147
+
148
+ Logger.log("🔍 Starting network detection...")
149
+
150
+ try {
151
+ Logger.log("📡 Attempting single eth_chainId call...")
152
+ const hexChainId = await this.browserProvider.send("eth_chainId", [])
153
+ chainId = parseInt(hexChainId, 16)
154
+ Logger.log(`✅ Network detected: Chain ${chainId}`)
155
+ } catch (chainIdError) {
156
+ Logger.warn("❌ Chain ID detection failed:", chainIdError)
157
+ chainId = this.currentConfig.chainId
158
+ Logger.log(`⚠️ Using default chain ID: ${chainId}`)
159
+ }
160
+
161
+ Logger.log(`🎯 Final detected chain ID: ${chainId}`)
162
+ Logger.log(`🎯 Required chain ID: ${this.currentConfig.chainId}`)
163
+
164
+ // If no explicit target was set, adopt the detected network
165
+ if (!this.targetChainId && chainId) {
166
+ this.currentConfig = getContractConfig(chainId)
167
+ Logger.log(`🎛 Adopted current network: ${this.currentConfig.network} (${chainId})`)
168
+ }
169
+
170
+ // Set up dedicated read provider to avoid rate limiting
171
+ if (chainId && this.RPC_ENDPOINTS[chainId]) {
172
+ try {
173
+ Logger.log(`🔗 Testing RPC endpoint before creating provider for chain ${chainId}...`)
174
+ const rpcUrl = this.RPC_ENDPOINTS[chainId]
175
+
176
+ // Test RPC endpoint with fetch first
177
+ const controller = new AbortController();
178
+ const timeout = setTimeout(() => controller.abort(), 2500)
179
+ const testResponse = await fetch(rpcUrl, {
180
+ method: 'POST',
181
+ headers: { 'Content-Type': 'application/json' },
182
+ body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 1 }),
183
+ signal: controller.signal,
184
+ }).catch(() => null as any)
185
+ clearTimeout(timeout)
186
+
187
+ if (!testResponse || !testResponse.ok) {
188
+ throw new Error('RPC endpoint did not respond in time')
189
+ }
190
+
191
+ const testData = await testResponse.json().catch(() => null as any)
192
+ const actualChainId = testData && testData.result ? parseInt(testData.result, 16) : undefined
193
+ if (actualChainId !== chainId) {
194
+ throw new Error(`Chain ID mismatch: expected ${chainId}, got ${actualChainId}`)
195
+ }
196
+
197
+ Logger.log(`✅ RPC endpoint test passed for chain ${chainId}`)
198
+
199
+ const networkConfig = {
200
+ name: this.getNetworkName(chainId),
201
+ chainId: chainId
202
+ }
203
+
204
+ this.readProvider = new ethers.JsonRpcProvider(rpcUrl, networkConfig)
205
+ Logger.log(`✅ Read provider initialized successfully for ${rpcUrl}`)
206
+
207
+ } catch (readProviderError) {
208
+ Logger.warn("❌ Failed to set up read provider:", readProviderError)
209
+ this.readProvider = null
210
+ }
211
+ }
212
+
213
+ // Verify chain ID if we were able to detect it
214
+ if (chainId && chainId !== this.currentConfig.chainId) {
215
+ Logger.log(`❌ Wrong network detected. Current: Chain ${chainId}, Required: Chain ${this.currentConfig.chainId}`)
216
+
217
+ try {
218
+ Logger.log(`🔄 Attempting to switch to ${this.currentConfig.network}...`)
219
+ await this.addAndSwitchNetwork()
220
+ Logger.log(`✅ Successfully switched to ${this.currentConfig.network}`)
221
+
222
+ // Re-verify the network after switching
223
+ await new Promise(resolve => setTimeout(resolve, 1000))
224
+
225
+ try {
226
+ const newNetwork = await this.browserProvider.getNetwork()
227
+ const newChainId = Number(newNetwork.chainId)
228
+ Logger.log(`🔍 Post-switch verification: Chain ${newChainId}`)
229
+ if (newChainId !== this.currentConfig.chainId) {
230
+ throw new Error(`Network switch failed. Still on Chain ${newChainId}`)
231
+ }
232
+ chainId = newChainId
233
+
234
+ // Recreate read provider for the new network
235
+ try {
236
+ if (this.readProvider) {
237
+ try { (this.readProvider as any).destroy?.() } catch {}
238
+ this.readProvider = null
239
+ }
240
+ const rpcUrl = this.RPC_ENDPOINTS[newChainId]
241
+ if (rpcUrl) {
242
+ const networkConfig = { name: this.getNetworkName(newChainId), chainId: newChainId }
243
+ this.readProvider = new ethers.JsonRpcProvider(rpcUrl, networkConfig)
244
+ Logger.log(`🔁 Read provider switched to ${rpcUrl}`)
245
+ }
246
+ } catch (rpErr) {
247
+ Logger.warn('Could not recreate read provider after switch:', rpErr)
248
+ }
249
+ } catch (verifyError) {
250
+ Logger.warn("Could not verify network after switch:", verifyError)
251
+ chainId = this.currentConfig.chainId
252
+ }
253
+
254
+ } catch (switchError) {
255
+ Logger.error("Failed to switch network:", switchError)
256
+
257
+ throw new Error(
258
+ `Please manually switch to ${this.currentConfig.network} in your wallet.\n\n` +
259
+ `Current network: Chain ${chainId}\n` +
260
+ `Required network: ${this.currentConfig.network} (Chain ID: ${this.currentConfig.chainId})\n\n` +
261
+ `In MetaMask:\n` +
262
+ `1. Click the network dropdown at the top\n` +
263
+ `2. Select "Add network" or "Custom networks"\n` +
264
+ `3. Add ${this.currentConfig.network} network details\n` +
265
+ `4. Switch to ${this.currentConfig.network}\n\n` +
266
+ `Network Details:\n` +
267
+ `• Network Name: ${this.currentConfig.network}\n` +
268
+ `• RPC URL: ${this.currentConfig.rpcUrls[0]}\n` +
269
+ `• Chain ID: ${this.currentConfig.chainId}\n` +
270
+ `• Currency Symbol: ETH\n` +
271
+ `• Block Explorer: ${this.currentConfig.explorerUrl}`
272
+ )
273
+ }
274
+ }
275
+
276
+ Logger.log(`🔗 Browser wallet manager initialized`)
277
+ Logger.log(`📡 Connected to ${this.currentConfig.network} (Chain ${chainId || 'unknown'})`)
278
+ Logger.log(`📍 Contract Address: ${this.currentConfig.address}`)
279
+ Logger.log(`👛 Wallet Address: ${walletAddress}`)
280
+
281
+ // Initialize contract with the actual contract address
282
+ try {
283
+ const signer = await this.browserProvider.getSigner()
284
+ this.contract = new ethers.Contract(this.currentConfig.address, NZIP_CONTRACT_ABI, signer)
285
+
286
+ // Test the contract connection by checking if it has code
287
+ try {
288
+ const providerForRead = this.readProvider || this.browserProvider
289
+ const code = await providerForRead.getCode(this.currentConfig.address)
290
+ if (code === '0x') {
291
+ Logger.warn(`⚠️ No contract code found at ${this.currentConfig.address}. Contract may not be deployed on this network.`)
292
+ } else {
293
+ Logger.log(`✅ Contract verified at ${this.currentConfig.address}`)
294
+ }
295
+ } catch (codeError) {
296
+ Logger.warn("Could not verify contract code:", codeError)
297
+ }
298
+
299
+ } catch (signerError) {
300
+ Logger.error("Failed to get signer or initialize contract:", signerError)
301
+ throw new Error("Could not connect to wallet. Please ensure your wallet is unlocked and connected.")
302
+ }
303
+
304
+ return true
305
+ } catch (error) {
306
+ Logger.error("Browser wallet manager initialization failed:", error)
307
+
308
+ if (error instanceof Error) {
309
+ if (error.message.includes("No wallet provider found")) {
310
+ throw new Error("No crypto wallet detected. Please install MetaMask, Coinbase Wallet, or another Web3 wallet.")
311
+ } else if (error.message.includes("Please switch to")) {
312
+ throw error
313
+ } else if (error.message.includes("Could not connect to wallet")) {
314
+ throw error
315
+ } else {
316
+ throw new Error(`Wallet connection failed: ${error.message}`)
317
+ }
318
+ }
319
+
320
+ throw error
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Get the contract instance
326
+ */
327
+ public getContract(): ethers.Contract | null {
328
+ return this.contract
329
+ }
330
+
331
+ /**
332
+ * Get the browser provider instance
333
+ */
334
+ public getBrowserProvider(): ethers.BrowserProvider | null {
335
+ return this.browserProvider
336
+ }
337
+
338
+ /**
339
+ * Override parent method to return browser provider
340
+ */
341
+ public getWallet(): ethers.Wallet | null {
342
+ // Browser doesn't have direct wallet access, return null
343
+ return null
344
+ }
345
+
346
+ /**
347
+ * Get the read provider instance
348
+ */
349
+ public getReadProvider(): ethers.JsonRpcProvider | null {
350
+ return this.readProvider
351
+ }
352
+
353
+ /**
354
+ * Override parent method to check browser provider
355
+ */
356
+ public isReady(): boolean {
357
+ return this.browserProvider !== null
358
+ }
359
+
360
+ /**
361
+ * Override parent method to check read provider
362
+ */
363
+ public isOnline(): boolean {
364
+ return this.readProvider !== null || this.browserProvider !== null
365
+ }
366
+
367
+ private async addAndSwitchNetwork(): Promise<void> {
368
+ if (!window.ethereum) {
369
+ throw new Error("Ethereum provider not found")
370
+ }
371
+
372
+ try {
373
+ // First try to switch to the network (in case it already exists)
374
+ await window.ethereum.request({
375
+ method: "wallet_switchEthereumChain",
376
+ params: [
377
+ {
378
+ chainId: `0x${this.currentConfig.chainId.toString(16)}`,
379
+ },
380
+ ],
381
+ })
382
+
383
+ Logger.log(`✅ Successfully switched to existing ${this.currentConfig.network}`)
384
+
385
+ } catch (switchError: any) {
386
+ // If switching failed, the network might not exist, so try to add it
387
+ if (switchError.code === 4902) {
388
+ Logger.log(`➕ Network not found, adding ${this.currentConfig.network}...`)
389
+
390
+ try {
391
+ await window.ethereum.request({
392
+ method: "wallet_addEthereumChain",
393
+ params: [
394
+ {
395
+ chainId: `0x${this.currentConfig.chainId.toString(16)}`,
396
+ chainName: this.currentConfig.network,
397
+ nativeCurrency: {
398
+ name: "ETH",
399
+ symbol: "ETH",
400
+ decimals: 18,
401
+ },
402
+ rpcUrls: this.currentConfig.rpcUrls,
403
+ blockExplorerUrls: [
404
+ this.currentConfig.explorerUrl,
405
+ ],
406
+ },
407
+ ],
408
+ })
409
+
410
+ Logger.log(`✅ Successfully added and switched to ${this.currentConfig.network}`)
411
+
412
+ } catch (addError: any) {
413
+ Logger.error("Failed to add network:", addError)
414
+
415
+ if (addError.code === 4001) {
416
+ throw new Error("User rejected the network addition request. Please manually add Base Sepolia network to your wallet.")
417
+ } else {
418
+ throw new Error(`Failed to add ${this.currentConfig.network} network: ${addError.message}`)
419
+ }
420
+ }
421
+ } else if (switchError.code === 4001) {
422
+ throw new Error("User rejected the network switch request. Please manually switch to Base Sepolia in your wallet.")
423
+ } else {
424
+ Logger.error("Network switch failed:", switchError)
425
+ throw new Error(`Failed to switch to ${this.currentConfig.network}: ${switchError.message}`)
426
+ }
427
+ }
428
+ }
429
+
430
+ private async testProviderConnection(provider: any): Promise<void> {
431
+ try {
432
+ await provider.request({ method: 'eth_chainId' })
433
+ Logger.log("✅ Provider connection successful (eth_chainId)")
434
+ } catch (error: any) {
435
+ Logger.warn("❌ Provider connection failed (eth_chainId):", error)
436
+ throw new Error(`Could not establish connection to wallet: ${error.message}`)
437
+ }
438
+ }
439
+
440
+ // ===== Explorer URL Generation Methods =====
441
+
442
+ /**
443
+ * Generate block explorer URL for a transaction
444
+ */
445
+ public getExplorerUrl(transactionHash: string): string {
446
+ return `${this.currentConfig.explorerUrl}/tx/${transactionHash}`
447
+ }
448
+
449
+ /**
450
+ * Generate block explorer URL for a contract
451
+ */
452
+ public getContractExplorerUrl(): string {
453
+ return `${this.currentConfig.explorerUrl}/address/${this.currentConfig.address}`
454
+ }
455
+
456
+ /**
457
+ * Generate block explorer URL for a token
458
+ * Uses the contract address page where users can search for specific token IDs
459
+ */
460
+ public getTokenExplorerUrl(tokenId: string): string {
461
+ return `${this.currentConfig.explorerUrl}/address/${this.currentConfig.address}#readContract`
462
+ }
463
+
464
+ /**
465
+ * Generate block explorer URL for a specific token ID
466
+ * Some explorers support direct token URLs
467
+ */
468
+ public getTokenDirectUrl(tokenId: string): string {
469
+ // This varies by explorer, but most support this pattern
470
+ return `${this.currentConfig.explorerUrl}/token/${this.currentConfig.address}?a=${tokenId}`
471
+ }
472
+
473
+ /**
474
+ * Generate block explorer URL for an address
475
+ */
476
+ public getAddressExplorerUrl(address: string): string {
477
+ return `${this.currentConfig.explorerUrl}/address/${address}`
478
+ }
479
+
480
+ /**
481
+ * Generate block explorer URL for a block
482
+ */
483
+ public getBlockExplorerUrl(blockNumber: string | number): string {
484
+ return `${this.currentConfig.explorerUrl}/block/${blockNumber}`
485
+ }
486
+ }