gun-eth 1.4.24 → 1.4.25

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1351 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var Gun = require('gun');
6
- var SEA = require('gun/sea.js');
7
- var ethers = require('ethers');
8
- var require$$0$1 = require('url');
9
- var require$$1 = require('path');
10
- var require$$2 = require('fs');
11
-
12
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
13
- var STEALTH_ANNOUNCER_ADDRESS$1 = "";
14
- var PROOF_OF_INTEGRITY_ADDRESS = "";
15
- var require$$0 = {
16
- STEALTH_ANNOUNCER_ADDRESS: STEALTH_ANNOUNCER_ADDRESS$1,
17
- PROOF_OF_INTEGRITY_ADDRESS: PROOF_OF_INTEGRITY_ADDRESS
18
- };
19
-
20
- let contractAddresses = {
21
- PROOF_OF_INTEGRITY_ADDRESS: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
22
- STEALTH_ANNOUNCER_ADDRESS: "0x5FbDB2315678afecb367f032d93F642f64180aa3"
23
- };
24
-
25
- if (typeof window === 'undefined') {
26
- const { fileURLToPath } = require$$0$1;
27
- const { dirname } = require$$1;
28
- const { readFileSync } = require$$2;
29
- const { join } = require$$1;
30
-
31
- try {
32
- const __filename = fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('gun-eth.node.cjs', document.baseURI).href)));
33
- const __dirname = dirname(__filename);
34
- const rawdata = readFileSync(join(__dirname, 'contract-address.json'), 'utf8');
35
- contractAddresses = JSON.parse(rawdata);
36
- console.log("Loaded contract addresses:", contractAddresses);
37
- } catch (error) {
38
- console.warn("Warning: contract-address.json not found or invalid");
39
- }
40
- }
41
-
42
- const LOCAL_CONFIG = {
43
- CHAIN_ID: 1337,
44
- PROOF_OF_INTEGRITY_ADDRESS: contractAddresses.PROOF_OF_INTEGRITY_ADDRESS,
45
- STEALTH_ANNOUNCER_ADDRESS: contractAddresses.STEALTH_ANNOUNCER_ADDRESS,
46
- RPC_URL: "http://127.0.0.1:8545",
47
- GUN_PEER: "http://localhost:8765/gun"
48
- };
49
-
50
- // Indirizzi di produzione per diverse chain
51
- const CHAIN_CONFIG = {
52
- optimismSepolia: {
53
- STEALTH_ANNOUNCER_ADDRESS: "0xD0F2e9DA59d2DFECFdE67CcF17300BB6093A72f8",
54
- PROOF_OF_INTEGRITY_ADDRESS: "0x...",
55
- RPC_URL: "https://sepolia.optimism.io",
56
- CHAIN_ID: 11155420
57
- },
58
- arbitrumSepolia: {
59
- STEALTH_ANNOUNCER_ADDRESS: "0x...",
60
- PROOF_OF_INTEGRITY_ADDRESS: "0x...",
61
- RPC_URL: "https://sepolia-rollup.arbitrum.io/rpc",
62
- CHAIN_ID: 421614
63
- },
64
- localhost: {
65
- RPC_URL: "http://127.0.0.1:8545",
66
- CHAIN_ID: 1337
67
- }
68
- };
69
-
70
- // Funzione per ottenere gli indirizzi corretti
71
- function getAddressesForChain(chainName) {
72
- let config;
73
-
74
- // Se è localhost, prova a caricare gli indirizzi locali
75
- if (chainName === 'localhost') {
76
- try {
77
- // Carica gli indirizzi dal file generato dal deploy locale
78
- const localAddresses = require$$0;
79
- config = {
80
- ...CHAIN_CONFIG.localhost,
81
- ...localAddresses
82
- };
83
- console.log("Using local addresses:", config);
84
- return config;
85
- } catch (err) {
86
- console.warn('No local addresses found');
87
- throw new Error('No local addresses found. Did you run local deployment?');
88
- }
89
- }
90
-
91
- // Altrimenti usa gli indirizzi di produzione
92
- config = CHAIN_CONFIG[chainName];
93
- if (!config) {
94
- throw new Error(`Chain ${chainName} not supported. Supported chains: ${Object.keys(CHAIN_CONFIG).join(', ')}`);
95
- }
96
-
97
- return config;
98
- }
99
-
100
- const STEALTH_ANNOUNCER_ABI = [
101
- {
102
- "inputs": [
103
- {
104
- "internalType": "address",
105
- "name": "_devAddress",
106
- "type": "address"
107
- }
108
- ],
109
- "stateMutability": "nonpayable",
110
- "type": "constructor"
111
- },
112
- {
113
- "anonymous": false,
114
- "inputs": [
115
- {
116
- "internalType": "string",
117
- "name": "senderPublicKey",
118
- "type": "string"
119
- },
120
- {
121
- "internalType": "string",
122
- "name": "spendingPublicKey",
123
- "type": "string"
124
- },
125
- {
126
- "internalType": "address",
127
- "name": "stealthAddress",
128
- "type": "address"
129
- },
130
- {
131
- "internalType": "uint256",
132
- "name": "timestamp",
133
- "type": "uint256"
134
- }
135
- ],
136
- "name": "StealthPaymentAnnounced",
137
- "type": "event"
138
- },
139
- {
140
- "anonymous": false,
141
- "inputs": [
142
- {
143
- "internalType": "address",
144
- "name": "newAddress",
145
- "type": "address"
146
- }
147
- ],
148
- "name": "DevAddressUpdated",
149
- "type": "event"
150
- },
151
- {
152
- "anonymous": false,
153
- "inputs": [
154
- {
155
- "internalType": "uint256",
156
- "name": "newFee",
157
- "type": "uint256"
158
- }
159
- ],
160
- "name": "DevFeeUpdated",
161
- "type": "event"
162
- },
163
- {
164
- "inputs": [
165
- {
166
- "internalType": "string",
167
- "name": "senderPublicKey",
168
- "type": "string"
169
- },
170
- {
171
- "internalType": "string",
172
- "name": "spendingPublicKey",
173
- "type": "string"
174
- },
175
- {
176
- "internalType": "address",
177
- "name": "stealthAddress",
178
- "type": "address"
179
- }
180
- ],
181
- "name": "announcePayment",
182
- "outputs": [],
183
- "stateMutability": "payable",
184
- "type": "function"
185
- },
186
- {
187
- "inputs": [],
188
- "name": "devAddress",
189
- "outputs": [
190
- {
191
- "internalType": "address",
192
- "name": "",
193
- "type": "address"
194
- }
195
- ],
196
- "stateMutability": "view",
197
- "type": "function"
198
- },
199
- {
200
- "inputs": [],
201
- "name": "devFee",
202
- "outputs": [
203
- {
204
- "internalType": "uint256",
205
- "name": "",
206
- "type": "uint256"
207
- }
208
- ],
209
- "stateMutability": "view",
210
- "type": "function"
211
- },
212
- {
213
- "inputs": [],
214
- "name": "getAnnouncementsCount",
215
- "outputs": [
216
- {
217
- "internalType": "uint256",
218
- "name": "",
219
- "type": "uint256"
220
- }
221
- ],
222
- "stateMutability": "view",
223
- "type": "function"
224
- },
225
- {
226
- "inputs": [
227
- {
228
- "internalType": "uint256",
229
- "name": "fromIndex",
230
- "type": "uint256"
231
- },
232
- {
233
- "internalType": "uint256",
234
- "name": "toIndex",
235
- "type": "uint256"
236
- }
237
- ],
238
- "name": "getAnnouncementsInRange",
239
- "outputs": [
240
- {
241
- "components": [
242
- {
243
- "internalType": "string",
244
- "name": "senderPublicKey",
245
- "type": "string"
246
- },
247
- {
248
- "internalType": "string",
249
- "name": "spendingPublicKey",
250
- "type": "string"
251
- },
252
- {
253
- "internalType": "address",
254
- "name": "stealthAddress",
255
- "type": "address"
256
- },
257
- {
258
- "internalType": "uint256",
259
- "name": "timestamp",
260
- "type": "uint256"
261
- }
262
- ],
263
- "internalType": "struct StealthAnnouncer.StealthAnnouncement[]",
264
- "name": "",
265
- "type": "tuple[]"
266
- }
267
- ],
268
- "stateMutability": "view",
269
- "type": "function"
270
- },
271
- {
272
- "inputs": [
273
- {
274
- "internalType": "uint256",
275
- "name": "_newFee",
276
- "type": "uint256"
277
- }
278
- ],
279
- "name": "updateDevFee",
280
- "outputs": [],
281
- "stateMutability": "nonpayable",
282
- "type": "function"
283
- },
284
- {
285
- "inputs": [
286
- {
287
- "internalType": "address",
288
- "name": "_newAddress",
289
- "type": "address"
290
- }
291
- ],
292
- "name": "updateDevAddress",
293
- "outputs": [],
294
- "stateMutability": "nonpayable",
295
- "type": "function"
296
- },
297
- {
298
- "inputs": [],
299
- "name": "withdrawStuckETH",
300
- "outputs": [],
301
- "stateMutability": "nonpayable",
302
- "type": "function"
303
- }
304
- ];
305
-
306
- const PROOF_OF_INTEGRITY_ABI = [
307
- {
308
- "inputs": [
309
- {
310
- "internalType": "bytes[]",
311
- "name": "nodeIds",
312
- "type": "bytes[]"
313
- },
314
- {
315
- "internalType": "bytes32[]",
316
- "name": "contentHashes",
317
- "type": "bytes32[]"
318
- }
319
- ],
320
- "name": "batchUpdateData",
321
- "outputs": [],
322
- "stateMutability": "nonpayable",
323
- "type": "function"
324
- },
325
- {
326
- "anonymous": false,
327
- "inputs": [
328
- {
329
- "indexed": true,
330
- "internalType": "bytes",
331
- "name": "nodeId",
332
- "type": "bytes"
333
- },
334
- {
335
- "indexed": false,
336
- "internalType": "bytes32",
337
- "name": "contentHash",
338
- "type": "bytes32"
339
- },
340
- {
341
- "indexed": false,
342
- "internalType": "address",
343
- "name": "updater",
344
- "type": "address"
345
- }
346
- ],
347
- "name": "DataUpdated",
348
- "type": "event"
349
- },
350
- {
351
- "inputs": [
352
- {
353
- "internalType": "bytes",
354
- "name": "nodeId",
355
- "type": "bytes"
356
- }
357
- ],
358
- "name": "getLatestRecord",
359
- "outputs": [
360
- {
361
- "internalType": "bytes32",
362
- "name": "",
363
- "type": "bytes32"
364
- },
365
- {
366
- "internalType": "uint256",
367
- "name": "",
368
- "type": "uint256"
369
- },
370
- {
371
- "internalType": "address",
372
- "name": "",
373
- "type": "address"
374
- }
375
- ],
376
- "stateMutability": "view",
377
- "type": "function"
378
- },
379
- {
380
- "inputs": [
381
- {
382
- "internalType": "bytes",
383
- "name": "nodeId",
384
- "type": "bytes"
385
- },
386
- {
387
- "internalType": "bytes32",
388
- "name": "contentHash",
389
- "type": "bytes32"
390
- }
391
- ],
392
- "name": "updateData",
393
- "outputs": [],
394
- "stateMutability": "nonpayable",
395
- "type": "function"
396
- },
397
- {
398
- "inputs": [
399
- {
400
- "internalType": "bytes",
401
- "name": "nodeId",
402
- "type": "bytes"
403
- },
404
- {
405
- "internalType": "bytes32",
406
- "name": "contentHash",
407
- "type": "bytes32"
408
- }
409
- ],
410
- "name": "verifyData",
411
- "outputs": [
412
- {
413
- "internalType": "bool",
414
- "name": "",
415
- "type": "bool"
416
- },
417
- {
418
- "internalType": "uint256",
419
- "name": "",
420
- "type": "uint256"
421
- },
422
- {
423
- "internalType": "address",
424
- "name": "",
425
- "type": "address"
426
- }
427
- ],
428
- "stateMutability": "view",
429
- "type": "function"
430
- }
431
- ];
432
-
433
- // =============================================
434
- // IMPORTS AND GLOBAL VARIABLES
435
- // =============================================
436
-
437
- let rpcUrl = "";
438
- let privateKey = "";
439
-
440
- const MESSAGE_TO_SIGN = "Access GunDB with Ethereum";
441
-
442
- // =============================================
443
- // UTILITY FUNCTIONS
444
- // =============================================
445
- /**
446
- * Generates a random node ID for GunDB
447
- * @returns {string} A random hexadecimal string
448
- */
449
- function generateRandomId() {
450
- return ethers.ethers.hexlify(ethers.ethers.randomBytes(32)).slice(2);
451
- }
452
-
453
- /**
454
- * Generates a password from a signature.
455
- * @param {string} signature - The signature to derive the password from.
456
- * @returns {string|null} The generated password or null if generation fails.
457
- */
458
- function generatePassword(signature) {
459
- try {
460
- const hexSignature = ethers.ethers.hexlify(signature);
461
- const hash = ethers.ethers.keccak256(hexSignature);
462
- console.log("Generated password:", hash);
463
- return hash;
464
- } catch (error) {
465
- console.error("Error generating password:", error);
466
- return null;
467
- }
468
- }
469
-
470
- /**
471
- * Converts a Gun private key to an Ethereum account.
472
- * @param {string} gunPrivateKey - The Gun private key in base64url format.
473
- * @returns {Object} An object containing the Ethereum account and public key.
474
- */
475
- function gunToEthAccount(gunPrivateKey) {
476
- // Function to convert base64url to hex
477
- const base64UrlToHex = (base64url) => {
478
- const padding = "=".repeat((4 - (base64url.length % 4)) % 4);
479
- const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/") + padding;
480
- const binary = atob(base64);
481
- return Array.from(binary, (char) =>
482
- char.charCodeAt(0).toString(16).padStart(2, "0")
483
- ).join("");
484
- };
485
-
486
- // Convert Gun private key to hex format
487
- const hexPrivateKey = "0x" + base64UrlToHex(gunPrivateKey);
488
-
489
- // Create an Ethereum wallet from the private key
490
- const wallet = new ethers.ethers.Wallet(hexPrivateKey);
491
-
492
- // Get the public address (public key)
493
- const publicKey = wallet.address;
494
-
495
- return {
496
- account: wallet,
497
- publicKey: publicKey,
498
- privateKey: hexPrivateKey,
499
- };
500
- }
501
-
502
- /**
503
- * Gets an Ethereum signer based on current configuration
504
- * @returns {Promise<ethers.Signer>} The configured signer
505
- * @throws {Error} If no valid provider is found
506
- */
507
- const getSigner = async () => {
508
- if (rpcUrl && privateKey) {
509
- // Standalone mode with local provider
510
- const provider = new ethers.ethers.JsonRpcProvider(rpcUrl, {
511
- chainId: LOCAL_CONFIG.CHAIN_ID,
512
- name: "localhost"
513
- });
514
- return new ethers.ethers.Wallet(privateKey, provider);
515
- } else if (
516
- typeof window !== "undefined" &&
517
- typeof window.ethereum !== "undefined"
518
- ) {
519
- // Browser mode
520
- await window.ethereum.request({ method: "eth_requestAccounts" });
521
- const provider = new ethers.ethers.BrowserProvider(window.ethereum);
522
- return provider.getSigner();
523
- } else {
524
- throw new Error("No valid Ethereum provider found");
525
- }
526
- };
527
-
528
- /**
529
- * Utility function to generate stealth address
530
- * @param {string} sharedSecret - The shared secret
531
- * @param {string} spendingPublicKey - The spending public key
532
- * @returns {Object} The stealth address and private key
533
- */
534
- function deriveStealthAddress(sharedSecret, spendingPublicKey) {
535
- try {
536
- // Convert shared secret to bytes
537
- const sharedSecretBytes = Buffer.from(sharedSecret, 'base64');
538
-
539
- // Generate stealth private key using shared secret and spending public key
540
- const stealthPrivateKey = ethers.ethers.keccak256(
541
- ethers.ethers.concat([
542
- sharedSecretBytes,
543
- ethers.ethers.getBytes(spendingPublicKey)
544
- ])
545
- );
546
-
547
- // Create stealth wallet
548
- const stealthWallet = new ethers.ethers.Wallet(stealthPrivateKey);
549
-
550
- console.log("Debug deriveStealthAddress:", {
551
- sharedSecretHex: ethers.ethers.hexlify(sharedSecretBytes),
552
- spendingPublicKey,
553
- stealthPrivateKey,
554
- stealthAddress: stealthWallet.address
555
- });
556
-
557
- return {
558
- stealthPrivateKey,
559
- stealthAddress: stealthWallet.address,
560
- wallet: stealthWallet
561
- };
562
- } catch (error) {
563
- console.error("Error in deriveStealthAddress:", error);
564
- throw error;
565
- }
566
- }
567
-
568
- // =============================================
569
- // BASIC GUN-ETH CHAIN METHODS
570
- // =============================================
571
-
572
- // Set the message to sign
573
- Gun.chain.MESSAGE_TO_SIGN = MESSAGE_TO_SIGN;
574
-
575
- /**
576
- * Sets standalone configuration for Gun.
577
- * @param {string} newRpcUrl - The new RPC URL.
578
- * @param {string} newPrivateKey - The new private key.
579
- * @returns {Gun} The Gun instance for chaining.
580
- */
581
- Gun.chain.setSigner = function (newRpcUrl, newPrivateKey) {
582
- rpcUrl = newRpcUrl;
583
- privateKey = newPrivateKey;
584
- console.log("Standalone configuration set");
585
- return this;
586
- };
587
-
588
- Gun.chain.getSigner = getSigner();
589
-
590
- /**
591
- * Verifies an Ethereum signature.
592
- * @param {string} message - The original message that was signed.
593
- * @param {string} signature - The signature to verify.
594
- * @returns {Promise<string|null>} The recovered address or null if verification fails.
595
- */
596
- Gun.chain.verifySignature = async function (message, signature) {
597
- try {
598
- const recoveredAddress = ethers.ethers.verifyMessage(message, signature);
599
- return recoveredAddress;
600
- } catch (error) {
601
- console.error("Error verifying signature:", error);
602
- return null;
603
- }
604
- };
605
-
606
- /**
607
- * Generates a password from a signature.
608
- * @param {string} signature - The signature to derive the password from.
609
- * @returns {string|null} The generated password or null if generation fails.
610
- */
611
- Gun.chain.generatePassword = function (signature) {
612
- return generatePassword(signature);
613
- };
614
-
615
- /**
616
- * Creates an Ethereum signature for a given message.
617
- * @param {string} message - The message to sign.
618
- * @returns {Promise<string|null>} The signature or null if signing fails.
619
- */
620
- Gun.chain.createSignature = async function (message) {
621
- try {
622
- // Check if message matches MESSAGE_TO_SIGN
623
- if (message !== MESSAGE_TO_SIGN) {
624
- throw new Error("Invalid message, valid message is: " + MESSAGE_TO_SIGN);
625
- }
626
- const signer = await getSigner();
627
- const signature = await signer.signMessage(message);
628
- console.log("Signature created:", signature);
629
- return signature;
630
- } catch (error) {
631
- console.error("Error creating signature:", error);
632
- return null;
633
- }
634
- };
635
-
636
- // =============================================
637
- // KEY PAIR MANAGEMENT
638
- // =============================================
639
- /**
640
- * Creates and stores an encrypted key pair for a given address.
641
- * @param {string} address - The Ethereum address to associate with the key pair.
642
- * @param {string} signature - The signature to use for encryption.
643
- * @returns {Promise<void>}
644
- */
645
- Gun.chain.createAndStoreEncryptedPair = async function (address, signature) {
646
- try {
647
- const gun = this;
648
- const pair = await SEA.pair();
649
- const v_pair = await SEA.pair();
650
- const s_pair = await SEA.pair();
651
- const password = generatePassword(signature);
652
-
653
- // Save original SEA pairs
654
- const encryptedPair = await SEA.encrypt(JSON.stringify(pair), password);
655
- const encryptedV_pair = await SEA.encrypt(JSON.stringify(v_pair), password);
656
- const encryptedS_pair = await SEA.encrypt(JSON.stringify(s_pair), password);
657
-
658
- // Convert only to get Ethereum addresses
659
- const viewingAccount = gunToEthAccount(v_pair.priv);
660
- const spendingAccount = gunToEthAccount(s_pair.priv);
661
-
662
- gun.get("gun-eth").get("users").get(address).put({
663
- pair: encryptedPair,
664
- v_pair: encryptedV_pair,
665
- s_pair: encryptedS_pair,
666
- publicKeys: {
667
- viewingPublicKey: v_pair.epub, // Use SEA encryption public key
668
- viewingPublicKey: v_pair.epub, // Use SEA encryption public key
669
- spendingPublicKey: spendingAccount.publicKey, // Use Ethereum address
670
- ethViewingAddress: viewingAccount.publicKey // Also save Ethereum address
671
- }
672
- });
673
-
674
- console.log("Encrypted pairs and public keys stored for:", address);
675
- } catch (error) {
676
- console.error("Error creating and storing encrypted pair:", error);
677
- throw error;
678
- }
679
- };
680
-
681
- /**
682
- * Retrieves and decrypts a stored key pair for a given address.
683
- * @param {string} address - The Ethereum address associated with the key pair.
684
- * @param {string} signature - The signature to use for decryption.
685
- * @returns {Promise<Object|null>} The decrypted key pair or null if retrieval fails.
686
- */
687
- Gun.chain.getAndDecryptPair = async function (address, signature) {
688
- try {
689
- const gun = this;
690
- const encryptedData = await gun
691
- .get("gun-eth")
692
- .get("users")
693
- .get(address)
694
- .get("pair")
695
- .then();
696
- if (!encryptedData) {
697
- throw new Error("No encrypted data found for this address");
698
- }
699
- const password = generatePassword(signature);
700
- const decryptedPair = await SEA.decrypt(encryptedData, password);
701
- console.log(decryptedPair);
702
- return decryptedPair;
703
- } catch (error) {
704
- console.error("Error retrieving and decrypting pair:", error);
705
- return null;
706
- }
707
- };
708
-
709
- // =============================================
710
- // PROOF OF INTEGRITY
711
- // =============================================
712
- /**
713
- * Proof of Integrity
714
- * @param {string} chain - The blockchain to use (e.g., "optimismSepolia").
715
- * @param {string} nodeId - The ID of the node to verify or write.
716
- * @param {Object} data - The data to write (if writing).
717
- * @param {Function} callback - Callback function to handle the result.
718
- * @returns {Gun} The Gun instance for chaining.
719
- */
720
- Gun.chain.proof = function (chain, nodeId, data, callback) {
721
- console.log("Proof plugin called with:", { chain, nodeId, data });
722
-
723
- if (typeof callback !== "function") {
724
- console.error("Callback must be a function");
725
- return this;
726
- }
727
-
728
- try {
729
- // Usa getAddressesForChain per ottenere la configurazione corretta
730
- const chainConfig = getAddressesForChain(chain);
731
- console.log(`Using ${chain} configuration:`, chainConfig);
732
-
733
- // Usa gli indirizzi dalla configurazione
734
- const contract = new ethers.ethers.Contract(
735
- chainConfig.PROOF_OF_INTEGRITY_ADDRESS,
736
- PROOF_OF_INTEGRITY_ABI,
737
- signer
738
- );
739
-
740
- // Funzione per verificare on-chain
741
- const verifyOnChain = async (nodeId, contentHash) => {
742
- console.log("Verifying on chain:", { nodeId, contentHash });
743
- const signer = await getSigner();
744
- const contract = new ethers.ethers.Contract(
745
- PROOF_CONTRACT_ADDRESS,
746
- PROOF_OF_INTEGRITY_ABI,
747
- signer
748
- );
749
- const [isValid, timestamp, updater] = await contract.verifyData(
750
- ethers.ethers.toUtf8Bytes(nodeId),
751
- contentHash
752
- );
753
- console.log("Verification result:", { isValid, timestamp, updater });
754
- return { isValid, timestamp, updater };
755
- };
756
-
757
- // Funzione per scrivere on-chain
758
- const writeOnChain = async (nodeId, contentHash) => {
759
- console.log("Writing on chain:", { nodeId, contentHash });
760
- const signer = await getSigner();
761
- const contract = new ethers.ethers.Contract(
762
- PROOF_CONTRACT_ADDRESS,
763
- PROOF_OF_INTEGRITY_ABI,
764
- signer
765
- );
766
- const tx = await contract.updateData(
767
- ethers.ethers.toUtf8Bytes(nodeId),
768
- contentHash
769
- );
770
- console.log("Transaction sent:", tx.hash);
771
- const receipt = await tx.wait();
772
- console.log("Transaction confirmed:", receipt);
773
- return tx;
774
- };
775
-
776
- // Funzione per ottenere l'ultimo record
777
- const getLatestRecord = async (nodeId) => {
778
- const signer = await getSigner();
779
- const contract = new ethers.ethers.Contract(
780
- PROOF_CONTRACT_ADDRESS,
781
- PROOF_OF_INTEGRITY_ABI,
782
- signer
783
- );
784
- const [contentHash, timestamp, updater] = await contract.getLatestRecord(
785
- ethers.ethers.toUtf8Bytes(nodeId)
786
- );
787
- console.log("Latest record from blockchain:", {
788
- nodeId,
789
- contentHash,
790
- timestamp,
791
- updater,
792
- });
793
- return { contentHash, timestamp, updater };
794
- };
795
-
796
-
797
- if (nodeId && !data) {
798
- // Case 1: User passes only node
799
- gun.get(nodeId).once(async (existingData) => {
800
- if (!existingData) {
801
- if (callback) callback({ err: "Node not found in GunDB" });
802
- return;
803
- }
804
-
805
- console.log("existingData", existingData);
806
-
807
- // Use stored contentHash instead of recalculating
808
- const contentHash = existingData._contentHash;
809
- console.log("contentHash", contentHash);
810
-
811
- if (!contentHash) {
812
- if (callback) callback({ err: "No content hash found for this node" });
813
- return;
814
- }
815
-
816
- try {
817
- const { isValid, timestamp, updater } = await verifyOnChain(
818
- nodeId,
819
- contentHash
820
- );
821
- const latestRecord = await getLatestRecord(nodeId);
822
-
823
- if (isValid) {
824
- if (callback)
825
- callback({
826
- ok: true,
827
- message: "Data verified on blockchain",
828
- timestamp,
829
- updater,
830
- latestRecord,
831
- });
832
- } else {
833
- if (callback)
834
- callback({
835
- ok: false,
836
- message: "Data not verified on blockchain",
837
- latestRecord,
838
- });
839
- }
840
- } catch (error) {
841
- if (callback) callback({ err: error.message });
842
- }
843
- });
844
- } else if (data && !nodeId) {
845
- // Case 2: User passes only text (data)
846
- const newNodeId = generateRandomId();
847
- const dataString = JSON.stringify(data);
848
- const contentHash = ethers.ethers.keccak256(ethers.ethers.toUtf8Bytes(dataString));
849
-
850
- gun
851
- .get(newNodeId)
852
- .put({ ...data, _contentHash: contentHash }, async (ack) => {
853
- console.log("ack", ack);
854
- if (ack.err) {
855
- if (callback) callback({ err: "Error saving data to GunDB" });
856
- return;
857
- }
858
-
859
- try {
860
- const tx = await writeOnChain(newNodeId, contentHash);
861
- if (callback)
862
- callback({
863
- ok: true,
864
- message: "Data written to GunDB and blockchain",
865
- nodeId: newNodeId,
866
- txHash: tx.hash,
867
- });
868
- } catch (error) {
869
- if (callback) callback({ err: error.message });
870
- }
871
- });
872
- } else {
873
- if (callback)
874
- callback({
875
- err: "Invalid input. Provide either nodeId or data, not both.",
876
- });
877
- }
878
-
879
- return gun;
880
- } catch (error) {
881
- callback({ err: error.message });
882
- return this;
883
- }
884
- };
885
-
886
- // =============================================
887
- // STEALTH ADDRESS CORE FUNCTIONS
888
- // =============================================
889
- /**
890
- * Converts a Gun private key to an Ethereum account.
891
- * @param {string} gunPrivateKey - The Gun private key in base64url format.
892
- * @returns {Object} An object containing the Ethereum account and public key.
893
- */
894
- Gun.chain.gunToEthAccount = function (gunPrivateKey) {
895
- return gunToEthAccount(gunPrivateKey);
896
- };
897
-
898
- /**
899
- * Generate a stealth key and related key pairs
900
- * @param {string} recipientAddress - The recipient's Ethereum address
901
- * @param {string} signature - The sender's signature to access their keys
902
- * @returns {Promise<Object>} Object containing stealth addresses and keys
903
- */
904
- Gun.chain.generateStealthAddress = async function (recipientAddress, signature) {
905
- try {
906
- const gun = this;
907
-
908
- // Get recipient's public keys
909
- const recipientData = await gun
910
- .get("gun-eth")
911
- .get("users")
912
- .get(recipientAddress)
913
- .get("publicKeys")
914
- .then();
915
-
916
- if (!recipientData || !recipientData.viewingPublicKey || !recipientData.spendingPublicKey) {
917
- throw new Error("Recipient's public keys not found");
918
- }
919
-
920
- // Get sender's keys
921
- const senderAddress = await this.verifySignature(MESSAGE_TO_SIGN, signature);
922
- const password = generatePassword(signature);
923
-
924
- const senderData = await gun
925
- .get("gun-eth")
926
- .get("users")
927
- .get(senderAddress)
928
- .then();
929
-
930
- if (!senderData || !senderData.s_pair) {
931
- throw new Error("Sender's keys not found");
932
- }
933
-
934
- // Decrypt sender's spending pair
935
- let spendingKeyPair;
936
- try {
937
- const decryptedData = await SEA.decrypt(senderData.s_pair, password);
938
- spendingKeyPair = typeof decryptedData === 'string' ?
939
- JSON.parse(decryptedData) :
940
- decryptedData;
941
- } catch (error) {
942
- console.error("Error decrypting spending pair:", error);
943
- throw new Error("Unable to decrypt spending pair");
944
- }
945
-
946
- // Generate shared secret using SEA ECDH with encryption public key
947
- const sharedSecret = await SEA.secret(recipientData.viewingPublicKey, spendingKeyPair);
948
-
949
- if (!sharedSecret) {
950
- throw new Error("Unable to generate shared secret");
951
- }
952
-
953
- console.log("Generate shared secret:", sharedSecret);
954
-
955
- const { stealthAddress } = deriveStealthAddress(
956
- sharedSecret,
957
- recipientData.spendingPublicKey
958
- );
959
-
960
- return {
961
- stealthAddress,
962
- senderPublicKey: spendingKeyPair.epub, // Use encryption public key
963
- spendingPublicKey: recipientData.spendingPublicKey
964
- };
965
-
966
- } catch (error) {
967
- console.error("Error generating stealth address:", error);
968
- throw error;
969
- }
970
- };
971
-
972
- /**
973
- * Publish public keys needed to receive stealth payments
974
- * @param {string} signature - The signature to authenticate the user
975
- * @returns {Promise<void>}
976
- */
977
- Gun.chain.publishStealthKeys = async function (signature) {
978
- try {
979
- const gun = this;
980
- const address = await this.verifySignature(MESSAGE_TO_SIGN, signature);
981
- const password = generatePassword(signature);
982
-
983
- // Get encrypted key pairs
984
- const encryptedData = await gun
985
- .get("gun-eth")
986
- .get("users")
987
- .get(address)
988
- .then();
989
-
990
- if (!encryptedData || !encryptedData.v_pair || !encryptedData.s_pair) {
991
- throw new Error("Keys not found");
992
- }
993
-
994
- // Decrypt viewing and spending pairs
995
- const viewingKeyPair = JSON.parse(
996
- await SEA.decrypt(encryptedData.v_pair, password)
997
- );
998
- const spendingKeyPair = JSON.parse(
999
- await SEA.decrypt(encryptedData.s_pair, password)
1000
- );
1001
-
1002
- const viewingAccount = gunToEthAccount(viewingKeyPair.priv);
1003
- const spendingAccount = gunToEthAccount(spendingKeyPair.priv);
1004
-
1005
- // Publish only public keys
1006
- gun.get("gun-eth").get("users").get(address).get("publicKeys").put({
1007
- viewingPublicKey: viewingAccount.publicKey,
1008
- spendingPublicKey: spendingAccount.publicKey,
1009
- });
1010
-
1011
- console.log("Stealth public keys published successfully");
1012
- } catch (error) {
1013
- console.error("Error publishing stealth keys:", error);
1014
- throw error;
1015
- }
1016
- };
1017
-
1018
- // =============================================
1019
- // STEALTH PAYMENT FUNCTIONS
1020
- // =============================================
1021
- /**
1022
- * Recover funds from a stealth address
1023
- * @param {string} stealthAddress - The stealth address to recover funds from
1024
- * @param {string} senderPublicKey - The sender's public key used to generate the address
1025
- * @param {string} signature - The signature to decrypt private keys
1026
- * @returns {Promise<Object>} Object containing wallet to access funds
1027
- */
1028
- Gun.chain.recoverStealthFunds = async function (
1029
- stealthAddress,
1030
- senderPublicKey,
1031
- signature,
1032
- spendingPublicKey
1033
- ) {
1034
- try {
1035
- const gun = this;
1036
- const password = generatePassword(signature);
1037
-
1038
- // Get own key pairs
1039
- const myAddress = await this.verifySignature(MESSAGE_TO_SIGN, signature);
1040
- const encryptedData = await gun
1041
- .get("gun-eth")
1042
- .get("users")
1043
- .get(myAddress)
1044
- .then();
1045
-
1046
- if (!encryptedData || !encryptedData.v_pair || !encryptedData.s_pair) {
1047
- throw new Error("Keys not found");
1048
- }
1049
-
1050
- // Decrypt viewing and spending pairs
1051
- let viewingKeyPair;
1052
- try {
1053
- const decryptedViewingData = await SEA.decrypt(encryptedData.v_pair, password);
1054
- viewingKeyPair = typeof decryptedViewingData === 'string' ?
1055
- JSON.parse(decryptedViewingData) :
1056
- decryptedViewingData;
1057
- } catch (error) {
1058
- console.error("Error decrypting keys:", error);
1059
- throw new Error("Unable to decrypt keys");
1060
- }
1061
-
1062
- // Generate shared secret using SEA ECDH
1063
- const sharedSecret = await SEA.secret(senderPublicKey, viewingKeyPair);
1064
-
1065
- if (!sharedSecret) {
1066
- throw new Error("Unable to generate shared secret");
1067
- }
1068
-
1069
- console.log("Recover shared secret:", sharedSecret);
1070
-
1071
- const { wallet, stealthAddress: recoveredAddress } = deriveStealthAddress(
1072
- sharedSecret,
1073
- spendingPublicKey
1074
- );
1075
-
1076
- // Verify address matches
1077
- if (recoveredAddress.toLowerCase() !== stealthAddress.toLowerCase()) {
1078
- console.error("Mismatch:", {
1079
- recovered: recoveredAddress,
1080
- expected: stealthAddress,
1081
- sharedSecret
1082
- });
1083
- throw new Error("Recovered stealth address does not match");
1084
- }
1085
-
1086
- return {
1087
- wallet,
1088
- address: recoveredAddress,
1089
- };
1090
- } catch (error) {
1091
- console.error("Error recovering stealth funds:", error);
1092
- throw error;
1093
- }
1094
- };
1095
-
1096
- /**
1097
- * Announce a stealth payment
1098
- * @param {string} stealthAddress - The generated stealth address
1099
- * @param {string} senderPublicKey - The sender's public key
1100
- * @param {string} spendingPublicKey - The spending public key
1101
- * @param {string} signature - The sender's signature
1102
- * @returns {Promise<void>}
1103
- */
1104
- Gun.chain.announceStealthPayment = async function (
1105
- stealthAddress,
1106
- senderPublicKey,
1107
- spendingPublicKey,
1108
- signature,
1109
- options = { onChain: false, chain: 'optimismSepolia' }
1110
- ) {
1111
- try {
1112
- const gun = this;
1113
- const senderAddress = await this.verifySignature(MESSAGE_TO_SIGN, signature);
1114
-
1115
- if (options.onChain) {
1116
- const signer = await getSigner();
1117
- const chainConfig = getAddressesForChain(options.chain);
1118
-
1119
- const contract = new ethers.ethers.Contract(
1120
- chainConfig.STEALTH_ANNOUNCER_ADDRESS,
1121
- STEALTH_ANNOUNCER_ABI,
1122
- signer
1123
- );
1124
-
1125
- // Get dev fee from contract
1126
- const devFee = await contract.devFee();
1127
- console.log("Dev fee:", devFee.toString());
1128
-
1129
- // Call contract
1130
- const tx = await contract.announcePayment(
1131
- senderPublicKey,
1132
- spendingPublicKey,
1133
- stealthAddress,
1134
- { value: devFee }
1135
- );
1136
-
1137
- console.log("Transaction sent:", tx.hash);
1138
- const receipt = await tx.wait();
1139
- console.log("Transaction confirmed:", receipt.hash);
1140
-
1141
- console.log("Stealth payment announced on-chain (dev fee paid)");
1142
- } else {
1143
- // Off-chain announcement (GunDB)
1144
- gun
1145
- .get("gun-eth")
1146
- .get("stealth-payments")
1147
- .set({
1148
- stealthAddress,
1149
- senderAddress,
1150
- senderPublicKey,
1151
- spendingPublicKey,
1152
- timestamp: Date.now(),
1153
- });
1154
- console.log("Stealth payment announced off-chain");
1155
- }
1156
- } catch (error) {
1157
- console.error("Error announcing stealth payment:", error);
1158
- console.error("Error details:", error.stack);
1159
- throw error;
1160
- }
1161
- };
1162
-
1163
- /**
1164
- * Get all stealth payments for an address
1165
- * @param {string} signature - The signature to authenticate the user
1166
- * @returns {Promise<Array>} List of stealth payments
1167
- */
1168
- Gun.chain.getStealthPayments = async function (signature, options = { source: 'both' }) {
1169
- try {
1170
- const payments = [];
1171
-
1172
- if (options.source === 'onChain' || options.source === 'both') {
1173
- // Get on-chain payments
1174
- const signer = await getSigner();
1175
- const contractAddress = process.env.NODE_ENV === 'development'
1176
- ? LOCAL_CONFIG.STEALTH_ANNOUNCER_ADDRESS
1177
- : STEALTH_ANNOUNCER_ADDRESS;
1178
-
1179
- const contract = new ethers.ethers.Contract(
1180
- contractAddress,
1181
- STEALTH_ANNOUNCER_ABI,
1182
- signer
1183
- );
1184
-
1185
- try {
1186
- // Get total number of announcements
1187
- const totalAnnouncements = await contract.getAnnouncementsCount();
1188
- const totalCount = Number(totalAnnouncements.toString());
1189
- console.log("Total on-chain announcements:", totalCount);
1190
-
1191
- if (totalCount > 0) {
1192
- // Get announcements in batches of 100
1193
- const batchSize = 100;
1194
- const lastIndex = totalCount - 1;
1195
-
1196
- for(let i = 0; i <= lastIndex; i += batchSize) {
1197
- const toIndex = Math.min(i + batchSize - 1, lastIndex);
1198
- const batch = await contract.getAnnouncementsInRange(i, toIndex);
1199
-
1200
- // For each announcement, try to decrypt
1201
- for(const announcement of batch) {
1202
- try {
1203
- // Verify announcement is valid
1204
- if (!announcement || !announcement.stealthAddress ||
1205
- !announcement.senderPublicKey || !announcement.spendingPublicKey) {
1206
- console.log("Invalid announcement:", announcement);
1207
- continue;
1208
- }
1209
-
1210
- // Try to recover funds to verify if announcement is for us
1211
- const recoveredWallet = await this.recoverStealthFunds(
1212
- announcement.stealthAddress,
1213
- announcement.senderPublicKey,
1214
- signature,
1215
- announcement.spendingPublicKey
1216
- );
1217
-
1218
- // If no errors thrown, announcement is for us
1219
- payments.push({
1220
- stealthAddress: announcement.stealthAddress,
1221
- senderPublicKey: announcement.senderPublicKey,
1222
- spendingPublicKey: announcement.spendingPublicKey,
1223
- timestamp: Number(announcement.timestamp),
1224
- source: 'onChain',
1225
- wallet: recoveredWallet
1226
- });
1227
-
1228
- } catch (e) {
1229
- // Not for us, continue
1230
- console.log(`Announcement not for us: ${announcement.stealthAddress}`);
1231
- continue;
1232
- }
1233
- }
1234
- }
1235
- }
1236
- } catch (error) {
1237
- console.error("Error retrieving on-chain announcements:", error);
1238
- }
1239
- }
1240
-
1241
- if (options.source === 'offChain' || options.source === 'both') {
1242
- // Get off-chain payments
1243
- const gun = this;
1244
- const offChainPayments = await new Promise((resolve) => {
1245
- const p = [];
1246
- gun
1247
- .get("gun-eth")
1248
- .get("stealth-payments")
1249
- .get(recipientAddress)
1250
- .map()
1251
- .once((payment, id) => {
1252
- if (payment?.stealthAddress) {
1253
- p.push({ ...payment, id, source: 'offChain' });
1254
- }
1255
- });
1256
- setTimeout(() => resolve(p), 2000);
1257
- });
1258
-
1259
- payments.push(...offChainPayments);
1260
- }
1261
-
1262
- console.log(`Found ${payments.length} stealth payments`);
1263
- return payments;
1264
- } catch (error) {
1265
- console.error("Error retrieving stealth payments:", error);
1266
- throw error;
1267
- }
1268
- };
1269
-
1270
- /**
1271
- * Clean up old stealth payments
1272
- * @param {string} recipientAddress - The recipient's address
1273
- * @returns {Promise<void>}
1274
- */
1275
- Gun.chain.cleanStealthPayments = async function(recipientAddress) {
1276
- try {
1277
- const gun = this;
1278
- const payments = await gun
1279
- .get("gun-eth")
1280
- .get("stealth-payments")
1281
- .get(recipientAddress)
1282
- .map()
1283
- .once()
1284
- .then();
1285
-
1286
- // Remove empty or invalid nodes
1287
- if (payments) {
1288
- Object.keys(payments).forEach(async (key) => {
1289
- const payment = payments[key];
1290
- if (!payment || !payment.stealthAddress || !payment.senderPublicKey || !payment.spendingPublicKey) {
1291
- await gun
1292
- .get("gun-eth")
1293
- .get("stealth-payments")
1294
- .get(recipientAddress)
1295
- .get(key)
1296
- .put(null);
1297
- }
1298
- });
1299
- }
1300
- } catch (error) {
1301
- console.error("Error cleaning stealth payments:", error);
1302
- }
1303
- };
1304
-
1305
- // =============================================
1306
- // EXPORTS
1307
- // =============================================
1308
-
1309
- // Crea una classe GunEth che contiene tutti i metodi e le utility
1310
- class GunEth {
1311
- // Static utility methods
1312
- static generateRandomId = generateRandomId;
1313
- static generatePassword = generatePassword;
1314
- static gunToEthAccount = gunToEthAccount;
1315
- static getSigner = getSigner;
1316
- static deriveStealthAddress = deriveStealthAddress;
1317
-
1318
- // Chain methods
1319
- static chainMethods = {
1320
- setSigner: Gun.chain.setSigner,
1321
- getSigner: Gun.chain.getSigner,
1322
- verifySignature: Gun.chain.verifySignature,
1323
- generatePassword: Gun.chain.generatePassword,
1324
- createSignature: Gun.chain.createSignature,
1325
- createAndStoreEncryptedPair: Gun.chain.createAndStoreEncryptedPair,
1326
- getAndDecryptPair: Gun.chain.getAndDecryptPair,
1327
- proof: Gun.chain.proof,
1328
- gunToEthAccount: Gun.chain.gunToEthAccount,
1329
- generateStealthAddress: Gun.chain.generateStealthAddress,
1330
- publishStealthKeys: Gun.chain.publishStealthKeys,
1331
- recoverStealthFunds: Gun.chain.recoverStealthFunds,
1332
- announceStealthPayment: Gun.chain.announceStealthPayment,
1333
- getStealthPayments: Gun.chain.getStealthPayments,
1334
- cleanStealthPayments: Gun.chain.cleanStealthPayments
1335
- };
1336
-
1337
- // Constants
1338
- static MESSAGE_TO_SIGN = MESSAGE_TO_SIGN;
1339
- static PROOF_CONTRACT_ADDRESS = PROOF_CONTRACT_ADDRESS;
1340
- static LOCAL_CONFIG = LOCAL_CONFIG;
1341
- }
1342
-
1343
- exports.default = Gun;
1344
- exports.GunEth = GunEth;
1345
- exports.MESSAGE_TO_SIGN = MESSAGE_TO_SIGN;
1346
- exports.deriveStealthAddress = deriveStealthAddress;
1347
- exports.generatePassword = generatePassword;
1348
- exports.generateRandomId = generateRandomId;
1349
- exports.getSigner = getSigner;
1350
- exports.gunToEthAccount = gunToEthAccount;
1351
- //# sourceMappingURL=gun-eth.node.cjs.map