holosphere 2.0.0-alpha1 → 2.0.0-alpha4

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 (154) hide show
  1. package/dist/2019-D2OG2idw.js +6680 -0
  2. package/dist/2019-D2OG2idw.js.map +1 -0
  3. package/dist/2019-EION3wKo.cjs +8 -0
  4. package/dist/2019-EION3wKo.cjs.map +1 -0
  5. package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
  6. package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
  7. package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
  8. package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
  9. package/dist/browser-BSniCNqO.js +3058 -0
  10. package/dist/browser-BSniCNqO.js.map +1 -0
  11. package/dist/browser-Cq59Ij19.cjs +2 -0
  12. package/dist/browser-Cq59Ij19.cjs.map +1 -0
  13. package/dist/cjs/holosphere.cjs +2 -0
  14. package/dist/cjs/holosphere.cjs.map +1 -0
  15. package/dist/esm/holosphere.js +53 -0
  16. package/dist/esm/holosphere.js.map +1 -0
  17. package/dist/index-BB_vVJgv.cjs +5 -0
  18. package/dist/index-BB_vVJgv.cjs.map +1 -0
  19. package/dist/index-CBitK71M.cjs +12 -0
  20. package/dist/index-CBitK71M.cjs.map +1 -0
  21. package/dist/index-CV0eOogK.js +37423 -0
  22. package/dist/index-CV0eOogK.js.map +1 -0
  23. package/dist/index-Cz-PLCUR.js +15104 -0
  24. package/dist/index-Cz-PLCUR.js.map +1 -0
  25. package/dist/indexeddb-storage-CRsZyB2f.cjs +2 -0
  26. package/dist/indexeddb-storage-CRsZyB2f.cjs.map +1 -0
  27. package/dist/indexeddb-storage-DZaGlY_a.js +132 -0
  28. package/dist/indexeddb-storage-DZaGlY_a.js.map +1 -0
  29. package/dist/memory-storage-BkUi6sZG.js +51 -0
  30. package/dist/memory-storage-BkUi6sZG.js.map +1 -0
  31. package/dist/memory-storage-C0DuUsdY.cjs +2 -0
  32. package/dist/memory-storage-C0DuUsdY.cjs.map +1 -0
  33. package/dist/secp256k1-0kPdAVkK.cjs +12 -0
  34. package/dist/secp256k1-0kPdAVkK.cjs.map +1 -0
  35. package/dist/secp256k1-DN4FVXcv.js +1890 -0
  36. package/dist/secp256k1-DN4FVXcv.js.map +1 -0
  37. package/docs/CONTRACTS.md +797 -0
  38. package/docs/FOSDEM_PROPOSAL.md +388 -0
  39. package/docs/LOCALFIRST.md +266 -0
  40. package/docs/contracts/api-interface.md +793 -0
  41. package/docs/data-model.md +476 -0
  42. package/docs/gun-async-usage.md +338 -0
  43. package/docs/plan.md +349 -0
  44. package/docs/quickstart.md +674 -0
  45. package/docs/research.md +362 -0
  46. package/docs/spec.md +244 -0
  47. package/docs/storage-backends.md +326 -0
  48. package/docs/tasks.md +947 -0
  49. package/examples/demo.html +47 -0
  50. package/package.json +10 -5
  51. package/src/contracts/abis/Appreciative.json +1280 -0
  52. package/src/contracts/abis/AppreciativeFactory.json +101 -0
  53. package/src/contracts/abis/Bundle.json +1435 -0
  54. package/src/contracts/abis/BundleFactory.json +106 -0
  55. package/src/contracts/abis/Holon.json +881 -0
  56. package/src/contracts/abis/Holons.json +330 -0
  57. package/src/contracts/abis/Managed.json +1262 -0
  58. package/src/contracts/abis/ManagedFactory.json +149 -0
  59. package/src/contracts/abis/Membrane.json +261 -0
  60. package/src/contracts/abis/Splitter.json +1624 -0
  61. package/src/contracts/abis/SplitterFactory.json +220 -0
  62. package/src/contracts/abis/TestToken.json +321 -0
  63. package/src/contracts/abis/Zoned.json +1461 -0
  64. package/src/contracts/abis/ZonedFactory.json +154 -0
  65. package/src/contracts/chain-manager.js +375 -0
  66. package/src/contracts/deployer.js +443 -0
  67. package/src/contracts/event-listener.js +507 -0
  68. package/src/contracts/holon-contracts.js +344 -0
  69. package/src/contracts/index.js +83 -0
  70. package/src/contracts/networks.js +224 -0
  71. package/src/contracts/operations.js +670 -0
  72. package/src/contracts/queries.js +589 -0
  73. package/src/core/holosphere.js +453 -1
  74. package/src/crypto/nostr-utils.js +263 -0
  75. package/src/federation/handshake.js +455 -0
  76. package/src/federation/hologram.js +1 -1
  77. package/src/hierarchical/upcast.js +6 -5
  78. package/src/index.js +463 -1939
  79. package/src/lib/ai-methods.js +308 -0
  80. package/src/lib/contract-methods.js +293 -0
  81. package/src/lib/errors.js +23 -0
  82. package/src/lib/federation-methods.js +238 -0
  83. package/src/lib/index.js +26 -0
  84. package/src/spatial/h3-operations.js +2 -2
  85. package/src/storage/backends/gundb-backend.js +377 -46
  86. package/src/storage/global-tables.js +28 -1
  87. package/src/storage/gun-auth.js +303 -0
  88. package/src/storage/gun-federation.js +776 -0
  89. package/src/storage/gun-references.js +198 -0
  90. package/src/storage/gun-schema.js +291 -0
  91. package/src/storage/gun-wrapper.js +347 -31
  92. package/src/storage/indexeddb-storage.js +49 -11
  93. package/src/storage/memory-storage.js +5 -0
  94. package/src/storage/nostr-async.js +45 -23
  95. package/src/storage/nostr-client.js +11 -5
  96. package/src/storage/persistent-storage.js +6 -1
  97. package/src/storage/unified-storage.js +119 -0
  98. package/src/subscriptions/manager.js +1 -1
  99. package/types/index.d.ts +133 -0
  100. package/tests/unit/ai/aggregation.test.js +0 -295
  101. package/tests/unit/ai/breakdown.test.js +0 -446
  102. package/tests/unit/ai/classifier.test.js +0 -294
  103. package/tests/unit/ai/council.test.js +0 -262
  104. package/tests/unit/ai/embeddings.test.js +0 -384
  105. package/tests/unit/ai/federation-ai.test.js +0 -344
  106. package/tests/unit/ai/h3-ai.test.js +0 -458
  107. package/tests/unit/ai/index.test.js +0 -304
  108. package/tests/unit/ai/json-ops.test.js +0 -307
  109. package/tests/unit/ai/llm-service.test.js +0 -390
  110. package/tests/unit/ai/nl-query.test.js +0 -383
  111. package/tests/unit/ai/relationships.test.js +0 -311
  112. package/tests/unit/ai/schema-extractor.test.js +0 -384
  113. package/tests/unit/ai/spatial.test.js +0 -279
  114. package/tests/unit/ai/tts.test.js +0 -279
  115. package/tests/unit/content.test.js +0 -332
  116. package/tests/unit/contract/core.test.js +0 -88
  117. package/tests/unit/contract/crypto.test.js +0 -198
  118. package/tests/unit/contract/data.test.js +0 -223
  119. package/tests/unit/contract/federation.test.js +0 -181
  120. package/tests/unit/contract/hierarchical.test.js +0 -113
  121. package/tests/unit/contract/schema.test.js +0 -114
  122. package/tests/unit/contract/social.test.js +0 -217
  123. package/tests/unit/contract/spatial.test.js +0 -110
  124. package/tests/unit/contract/subscriptions.test.js +0 -128
  125. package/tests/unit/contract/utils.test.js +0 -159
  126. package/tests/unit/core.test.js +0 -152
  127. package/tests/unit/crypto.test.js +0 -328
  128. package/tests/unit/federation.test.js +0 -234
  129. package/tests/unit/gun-async.test.js +0 -252
  130. package/tests/unit/hierarchical.test.js +0 -399
  131. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  132. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  133. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  134. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  135. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  136. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  137. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  138. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  139. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  140. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  141. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  142. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  143. package/tests/unit/performance/benchmark.test.js +0 -85
  144. package/tests/unit/schema.test.js +0 -213
  145. package/tests/unit/spatial.test.js +0 -158
  146. package/tests/unit/storage.test.js +0 -195
  147. package/tests/unit/subscriptions.test.js +0 -328
  148. package/tests/unit/test-data-permanence-debug.js +0 -197
  149. package/tests/unit/test-data-permanence.js +0 -340
  150. package/tests/unit/test-key-persistence-fixed.js +0 -148
  151. package/tests/unit/test-key-persistence.js +0 -172
  152. package/tests/unit/test-relay-permanence.js +0 -376
  153. package/tests/unit/test-second-node.js +0 -95
  154. package/tests/unit/test-simple-write.js +0 -89
@@ -0,0 +1,154 @@
1
+ [
2
+ {
3
+ "type": "constructor",
4
+ "inputs": [
5
+ {
6
+ "name": "_botAddress",
7
+ "type": "address",
8
+ "internalType": "address"
9
+ }
10
+ ],
11
+ "stateMutability": "nonpayable"
12
+ },
13
+ {
14
+ "type": "function",
15
+ "name": "botAddress",
16
+ "inputs": [],
17
+ "outputs": [
18
+ {
19
+ "name": "",
20
+ "type": "address",
21
+ "internalType": "address"
22
+ }
23
+ ],
24
+ "stateMutability": "view"
25
+ },
26
+ {
27
+ "type": "function",
28
+ "name": "createZoned",
29
+ "inputs": [
30
+ {
31
+ "name": "_creatorUserId",
32
+ "type": "string",
33
+ "internalType": "string"
34
+ },
35
+ {
36
+ "name": "_name",
37
+ "type": "string",
38
+ "internalType": "string"
39
+ },
40
+ {
41
+ "name": "_parameter",
42
+ "type": "uint256",
43
+ "internalType": "uint256"
44
+ }
45
+ ],
46
+ "outputs": [
47
+ {
48
+ "name": "",
49
+ "type": "address",
50
+ "internalType": "address"
51
+ }
52
+ ],
53
+ "stateMutability": "nonpayable"
54
+ },
55
+ {
56
+ "type": "function",
57
+ "name": "listHolons",
58
+ "inputs": [],
59
+ "outputs": [
60
+ {
61
+ "name": "",
62
+ "type": "address[]",
63
+ "internalType": "address[]"
64
+ }
65
+ ],
66
+ "stateMutability": "view"
67
+ },
68
+ {
69
+ "type": "function",
70
+ "name": "listHolonsOf",
71
+ "inputs": [
72
+ {
73
+ "name": "_address",
74
+ "type": "address",
75
+ "internalType": "address"
76
+ }
77
+ ],
78
+ "outputs": [
79
+ {
80
+ "name": "",
81
+ "type": "address[]",
82
+ "internalType": "address[]"
83
+ }
84
+ ],
85
+ "stateMutability": "view"
86
+ },
87
+ {
88
+ "type": "function",
89
+ "name": "newHolon",
90
+ "inputs": [
91
+ {
92
+ "name": "creatorUserId",
93
+ "type": "string",
94
+ "internalType": "string"
95
+ },
96
+ {
97
+ "name": "_name",
98
+ "type": "string",
99
+ "internalType": "string"
100
+ },
101
+ {
102
+ "name": "_parameter",
103
+ "type": "uint256",
104
+ "internalType": "uint256"
105
+ }
106
+ ],
107
+ "outputs": [
108
+ {
109
+ "name": "",
110
+ "type": "address",
111
+ "internalType": "address"
112
+ }
113
+ ],
114
+ "stateMutability": "nonpayable"
115
+ },
116
+ {
117
+ "type": "function",
118
+ "name": "toAddress",
119
+ "inputs": [
120
+ {
121
+ "name": "",
122
+ "type": "string",
123
+ "internalType": "string"
124
+ }
125
+ ],
126
+ "outputs": [
127
+ {
128
+ "name": "",
129
+ "type": "address",
130
+ "internalType": "address"
131
+ }
132
+ ],
133
+ "stateMutability": "view"
134
+ },
135
+ {
136
+ "type": "event",
137
+ "name": "NewHolon",
138
+ "inputs": [
139
+ {
140
+ "name": "name",
141
+ "type": "string",
142
+ "indexed": false,
143
+ "internalType": "string"
144
+ },
145
+ {
146
+ "name": "addr",
147
+ "type": "address",
148
+ "indexed": false,
149
+ "internalType": "address"
150
+ }
151
+ ],
152
+ "anonymous": false
153
+ }
154
+ ]
@@ -0,0 +1,375 @@
1
+ /**
2
+ * ChainManager - Multi-chain connection management for Holosphere contracts
3
+ * Handles provider/signer setup, network switching, and wallet management
4
+ */
5
+
6
+ import { NETWORKS, getNetwork, isNetworkSupported } from './networks.js';
7
+
8
+ export class ChainManager {
9
+ constructor(config = {}) {
10
+ this.config = config;
11
+ this.provider = null;
12
+ this.signer = null;
13
+ this.network = null;
14
+ this.networkName = null;
15
+ this.ethers = null;
16
+ this._initialized = false;
17
+ }
18
+
19
+ /**
20
+ * Initialize ethers.js (lazy load)
21
+ * @private
22
+ */
23
+ async _loadEthers() {
24
+ if (!this.ethers) {
25
+ // Dynamic import for ethers
26
+ const ethersModule = await import('ethers');
27
+ this.ethers = ethersModule;
28
+ }
29
+ return this.ethers;
30
+ }
31
+
32
+ /**
33
+ * Connect to a network
34
+ * @param {string} networkName - Network name (e.g., 'sepolia', 'polygon')
35
+ * @param {string} [privateKey] - Private key for signing transactions
36
+ * @param {string} [rpcUrl] - Custom RPC URL (overrides default)
37
+ * @returns {Promise<{provider, signer, network}>}
38
+ */
39
+ async connect(networkName, privateKey, rpcUrl) {
40
+ const ethers = await this._loadEthers();
41
+
42
+ if (!isNetworkSupported(networkName) && !rpcUrl) {
43
+ throw new Error(`Unsupported network: ${networkName}. Use a custom rpcUrl or choose from: ${Object.keys(NETWORKS).join(', ')}`);
44
+ }
45
+
46
+ const networkConfig = getNetwork(networkName) || { chainId: 0, name: networkName };
47
+ const url = rpcUrl || networkConfig.rpc;
48
+
49
+ // Create provider
50
+ this.provider = new ethers.JsonRpcProvider(url, {
51
+ chainId: networkConfig.chainId,
52
+ name: networkConfig.name
53
+ });
54
+
55
+ // Wait for provider to be ready
56
+ await this.provider.ready;
57
+
58
+ // Get actual network info
59
+ this.network = await this.provider.getNetwork();
60
+ this.networkName = networkName;
61
+
62
+ // Create signer if private key provided
63
+ if (privateKey) {
64
+ // Remove 0x prefix if present
65
+ const cleanKey = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`;
66
+ this.signer = new ethers.Wallet(cleanKey, this.provider);
67
+ }
68
+
69
+ this._initialized = true;
70
+
71
+ return {
72
+ provider: this.provider,
73
+ signer: this.signer,
74
+ network: this.network,
75
+ networkName: this.networkName,
76
+ config: networkConfig
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Connect using browser wallet (MetaMask, etc.)
82
+ * @param {string} [networkName] - Optionally switch to this network
83
+ * @returns {Promise<{provider, signer, network, address}>}
84
+ */
85
+ async connectBrowser(networkName) {
86
+ const ethers = await this._loadEthers();
87
+
88
+ if (typeof window === 'undefined' || !window.ethereum) {
89
+ throw new Error('No browser wallet detected. Please install MetaMask or another Web3 wallet.');
90
+ }
91
+
92
+ // Request account access
93
+ await window.ethereum.request({ method: 'eth_requestAccounts' });
94
+
95
+ // Create provider from browser
96
+ this.provider = new ethers.BrowserProvider(window.ethereum);
97
+ this.signer = await this.provider.getSigner();
98
+ this.network = await this.provider.getNetwork();
99
+
100
+ // Switch network if requested
101
+ if (networkName && isNetworkSupported(networkName)) {
102
+ const targetConfig = getNetwork(networkName);
103
+ if (this.network.chainId !== BigInt(targetConfig.chainId)) {
104
+ await this.switchNetwork(networkName);
105
+ }
106
+ }
107
+
108
+ const address = await this.signer.getAddress();
109
+ this._initialized = true;
110
+
111
+ return {
112
+ provider: this.provider,
113
+ signer: this.signer,
114
+ network: this.network,
115
+ address
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Switch to a different network (browser wallet only)
121
+ * @param {string} networkName - Target network name
122
+ */
123
+ async switchNetwork(networkName) {
124
+ if (typeof window === 'undefined' || !window.ethereum) {
125
+ throw new Error('Network switching requires a browser wallet');
126
+ }
127
+
128
+ const config = getNetwork(networkName);
129
+ if (!config) {
130
+ throw new Error(`Unknown network: ${networkName}`);
131
+ }
132
+
133
+ const chainIdHex = '0x' + config.chainId.toString(16);
134
+
135
+ try {
136
+ // Try to switch to the network
137
+ await window.ethereum.request({
138
+ method: 'wallet_switchEthereumChain',
139
+ params: [{ chainId: chainIdHex }]
140
+ });
141
+ } catch (switchError) {
142
+ // If the network doesn't exist, add it
143
+ if (switchError.code === 4902) {
144
+ await window.ethereum.request({
145
+ method: 'wallet_addEthereumChain',
146
+ params: [{
147
+ chainId: chainIdHex,
148
+ chainName: config.name,
149
+ nativeCurrency: config.currency,
150
+ rpcUrls: [config.rpc],
151
+ blockExplorerUrls: config.explorer ? [config.explorer] : []
152
+ }]
153
+ });
154
+ } else {
155
+ throw switchError;
156
+ }
157
+ }
158
+
159
+ // Refresh provider/signer after network switch
160
+ const ethers = await this._loadEthers();
161
+ this.provider = new ethers.BrowserProvider(window.ethereum);
162
+ this.signer = await this.provider.getSigner();
163
+ this.network = await this.provider.getNetwork();
164
+ this.networkName = networkName;
165
+ }
166
+
167
+ /**
168
+ * Get the current provider
169
+ * @returns {Provider}
170
+ */
171
+ getProvider() {
172
+ this._requireInitialized();
173
+ return this.provider;
174
+ }
175
+
176
+ /**
177
+ * Get the current signer
178
+ * @returns {Signer}
179
+ */
180
+ getSigner() {
181
+ this._requireInitialized();
182
+ if (!this.signer) {
183
+ throw new Error('No signer available. Connect with a private key or use connectBrowser().');
184
+ }
185
+ return this.signer;
186
+ }
187
+
188
+ /**
189
+ * Get the connected address
190
+ * @returns {Promise<string>}
191
+ */
192
+ async getAddress() {
193
+ const signer = this.getSigner();
194
+ return signer.getAddress();
195
+ }
196
+
197
+ /**
198
+ * Get ETH balance of an address
199
+ * @param {string} [address] - Address to check (defaults to signer)
200
+ * @returns {Promise<string>} Balance in ETH
201
+ */
202
+ async getBalance(address) {
203
+ this._requireInitialized();
204
+ const ethers = await this._loadEthers();
205
+ const addr = address || (this.signer ? await this.signer.getAddress() : null);
206
+ if (!addr) {
207
+ throw new Error('No address provided and no signer available');
208
+ }
209
+ const balance = await this.provider.getBalance(addr);
210
+ return ethers.formatEther(balance);
211
+ }
212
+
213
+ /**
214
+ * Get current network configuration
215
+ * @returns {Object}
216
+ */
217
+ getNetworkConfig() {
218
+ this._requireInitialized();
219
+ return getNetwork(this.networkName);
220
+ }
221
+
222
+ /**
223
+ * Get current chain ID
224
+ * @returns {number}
225
+ */
226
+ getChainId() {
227
+ this._requireInitialized();
228
+ return Number(this.network.chainId);
229
+ }
230
+
231
+ /**
232
+ * Check if connected to the expected network
233
+ * @param {string} expectedNetwork - Expected network name
234
+ * @returns {boolean}
235
+ */
236
+ isOnNetwork(expectedNetwork) {
237
+ if (!this._initialized) return false;
238
+ const expected = getNetwork(expectedNetwork);
239
+ if (!expected) return false;
240
+ return this.getChainId() === expected.chainId;
241
+ }
242
+
243
+ /**
244
+ * Create a contract instance
245
+ * @param {string} address - Contract address
246
+ * @param {Array} abi - Contract ABI
247
+ * @param {boolean} [useSigner=true] - Use signer for write operations
248
+ * @returns {Contract}
249
+ */
250
+ async getContract(address, abi, useSigner = true) {
251
+ this._requireInitialized();
252
+ const ethers = await this._loadEthers();
253
+ const signerOrProvider = useSigner && this.signer ? this.signer : this.provider;
254
+ return new ethers.Contract(address, abi, signerOrProvider);
255
+ }
256
+
257
+ /**
258
+ * Deploy a contract
259
+ * @param {Array} abi - Contract ABI
260
+ * @param {string} bytecode - Contract bytecode
261
+ * @param {Array} [constructorArgs=[]] - Constructor arguments
262
+ * @returns {Promise<{contract, address, deployTx}>}
263
+ */
264
+ async deployContract(abi, bytecode, constructorArgs = []) {
265
+ this._requireInitialized();
266
+ if (!this.signer) {
267
+ throw new Error('Signer required for contract deployment');
268
+ }
269
+
270
+ const ethers = await this._loadEthers();
271
+ const factory = new ethers.ContractFactory(abi, bytecode, this.signer);
272
+ const contract = await factory.deploy(...constructorArgs);
273
+
274
+ // Wait for deployment
275
+ await contract.waitForDeployment();
276
+ const address = await contract.getAddress();
277
+ const deployTx = contract.deploymentTransaction();
278
+
279
+ return {
280
+ contract,
281
+ address,
282
+ deployTx,
283
+ txHash: deployTx?.hash
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Wait for a transaction to be mined
289
+ * @param {string} txHash - Transaction hash
290
+ * @param {number} [confirmations=1] - Number of confirmations to wait for
291
+ * @returns {Promise<TransactionReceipt>}
292
+ */
293
+ async waitForTransaction(txHash, confirmations = 1) {
294
+ this._requireInitialized();
295
+ return this.provider.waitForTransaction(txHash, confirmations);
296
+ }
297
+
298
+ /**
299
+ * Estimate gas for a transaction
300
+ * @param {Object} tx - Transaction object
301
+ * @returns {Promise<bigint>}
302
+ */
303
+ async estimateGas(tx) {
304
+ this._requireInitialized();
305
+ return this.provider.estimateGas(tx);
306
+ }
307
+
308
+ /**
309
+ * Get current gas price
310
+ * @returns {Promise<{gasPrice: string, maxFeePerGas: string, maxPriorityFeePerGas: string}>}
311
+ */
312
+ async getGasPrice() {
313
+ this._requireInitialized();
314
+ const ethers = await this._loadEthers();
315
+ const feeData = await this.provider.getFeeData();
316
+ return {
317
+ gasPrice: feeData.gasPrice ? ethers.formatUnits(feeData.gasPrice, 'gwei') : null,
318
+ maxFeePerGas: feeData.maxFeePerGas ? ethers.formatUnits(feeData.maxFeePerGas, 'gwei') : null,
319
+ maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ? ethers.formatUnits(feeData.maxPriorityFeePerGas, 'gwei') : null
320
+ };
321
+ }
322
+
323
+ /**
324
+ * Parse units (e.g., ETH to wei)
325
+ * @param {string|number} value - Value to parse
326
+ * @param {string|number} [unit='ether'] - Unit name or decimals
327
+ * @returns {bigint}
328
+ */
329
+ async parseUnits(value, unit = 'ether') {
330
+ const ethers = await this._loadEthers();
331
+ return ethers.parseUnits(value.toString(), unit);
332
+ }
333
+
334
+ /**
335
+ * Format units (e.g., wei to ETH)
336
+ * @param {bigint|string} value - Value to format
337
+ * @param {string|number} [unit='ether'] - Unit name or decimals
338
+ * @returns {string}
339
+ */
340
+ async formatUnits(value, unit = 'ether') {
341
+ const ethers = await this._loadEthers();
342
+ return ethers.formatUnits(value, unit);
343
+ }
344
+
345
+ /**
346
+ * Check if manager is initialized
347
+ * @private
348
+ */
349
+ _requireInitialized() {
350
+ if (!this._initialized) {
351
+ throw new Error('ChainManager not initialized. Call connect() or connectBrowser() first.');
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Check if connected
357
+ * @returns {boolean}
358
+ */
359
+ isConnected() {
360
+ return this._initialized && this.provider !== null;
361
+ }
362
+
363
+ /**
364
+ * Disconnect and clean up
365
+ */
366
+ disconnect() {
367
+ this.provider = null;
368
+ this.signer = null;
369
+ this.network = null;
370
+ this.networkName = null;
371
+ this._initialized = false;
372
+ }
373
+ }
374
+
375
+ export default ChainManager;