gun-eth 1.4.36 → 1.5.0

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