gun-eth 1.4.22 → 1.4.23

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