@treza/react 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1059 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var sdk = require('@treza/sdk');
5
+ var ethers = require('ethers');
6
+
7
+ // Context for compliance SDK
8
+ const ComplianceContext = React.createContext({
9
+ sdk: null,
10
+ isLoading: true,
11
+ error: null
12
+ });
13
+ /**
14
+ * Provider component that initializes the compliance SDK
15
+ */
16
+ const ComplianceProvider = ({ provider, signer, children }) => {
17
+ const [sdk$1, setSdk] = React.useState(null);
18
+ const [isLoading, setIsLoading] = React.useState(true);
19
+ const [error, setError] = React.useState(null);
20
+ React.useEffect(() => {
21
+ try {
22
+ const config = {
23
+ zkPassportDomain: "trezalabs.com",
24
+ zkVerifyEndpoint: "https://api.zkverify.io",
25
+ trezaTokenAddress: process.env.REACT_APP_TREZA_TOKEN_ADDRESS || "0x8278d4FbfaB7dac14eC0295421D0a2733b4504E5",
26
+ complianceVerifierAddress: process.env.REACT_APP_COMPLIANCE_VERIFIER_ADDRESS || "0x8c0C6e0Eaf6bc693745A1A3a722e2c9028BBe874",
27
+ complianceIntegrationAddress: process.env.REACT_APP_COMPLIANCE_INTEGRATION_ADDRESS || "0xf3ecfC409761D715F137Bfe7078Acec6d7F55428",
28
+ provider,
29
+ signer
30
+ };
31
+ const complianceSDK = new sdk.TrezaComplianceSDK(config);
32
+ setSdk(complianceSDK);
33
+ setError(null);
34
+ }
35
+ catch (err) {
36
+ setError(err instanceof Error ? err.message : 'Failed to initialize compliance SDK');
37
+ }
38
+ finally {
39
+ setIsLoading(false);
40
+ }
41
+ }, [provider, signer]);
42
+ return (React.createElement(ComplianceContext.Provider, { value: { sdk: sdk$1, isLoading, error } }, children));
43
+ };
44
+ /**
45
+ * Hook to use compliance context (for use within ComplianceProvider)
46
+ */
47
+ const useComplianceContext = () => {
48
+ const context = React.useContext(ComplianceContext);
49
+ if (!context) {
50
+ throw new Error('useComplianceContext must be used within a ComplianceProvider');
51
+ }
52
+ return context;
53
+ };
54
+ /**
55
+ * Main compliance verification component
56
+ */
57
+ const ComplianceVerification = ({ userAddress, requirements, onVerificationComplete, onError, className = "" }) => {
58
+ const { sdk } = useComplianceContext();
59
+ const [verificationUrl, setVerificationUrl] = React.useState("");
60
+ const [qrCode, setQrCode] = React.useState("");
61
+ const [isGenerating, setIsGenerating] = React.useState(false);
62
+ const [status, setStatus] = React.useState('idle');
63
+ const [error, setError] = React.useState("");
64
+ const initiateVerification = React.useCallback(async () => {
65
+ if (!sdk)
66
+ return;
67
+ setIsGenerating(true);
68
+ setStatus('generating');
69
+ setError("");
70
+ try {
71
+ const url = await sdk.initiateVerification(requirements);
72
+ setVerificationUrl(url);
73
+ const qr = await sdk.generateQRCode(url);
74
+ setQrCode(qr);
75
+ setStatus('waiting');
76
+ }
77
+ catch (err) {
78
+ const errorMessage = err instanceof Error ? err.message : 'Failed to initiate verification';
79
+ setError(errorMessage);
80
+ setStatus('error');
81
+ onError?.(errorMessage);
82
+ }
83
+ finally {
84
+ setIsGenerating(false);
85
+ }
86
+ }, [sdk, requirements, onError]);
87
+ React.useCallback(async (zkPassportResult) => {
88
+ if (!sdk)
89
+ return;
90
+ setStatus('processing');
91
+ try {
92
+ const result = await sdk.processVerificationResult(zkPassportResult, userAddress);
93
+ setStatus('complete');
94
+ onVerificationComplete?.(result);
95
+ }
96
+ catch (err) {
97
+ const errorMessage = err instanceof Error ? err.message : 'Failed to process verification';
98
+ setError(errorMessage);
99
+ setStatus('error');
100
+ onError?.(errorMessage);
101
+ }
102
+ }, [sdk, userAddress, onVerificationComplete, onError]);
103
+ return (React.createElement("div", { className: `treza-compliance-verification ${className}` },
104
+ React.createElement("div", { className: "verification-header" },
105
+ React.createElement("h3", null, "\uD83D\uDEE1\uFE0F Identity Verification"),
106
+ React.createElement("p", null, "Verify your identity to access TREZA features while keeping your personal data private.")),
107
+ status === 'idle' && (React.createElement("div", { className: "verification-start" },
108
+ React.createElement("button", { onClick: initiateVerification, disabled: isGenerating, className: "btn-primary" }, isGenerating ? 'Generating...' : 'Start Verification'))),
109
+ status === 'generating' && (React.createElement("div", { className: "verification-generating" },
110
+ React.createElement("div", { className: "spinner" }),
111
+ React.createElement("p", null, "Generating verification request..."))),
112
+ status === 'waiting' && (React.createElement("div", { className: "verification-waiting" },
113
+ React.createElement("div", { className: "qr-code-section" },
114
+ React.createElement("h4", null, "\uD83D\uDCF1 Scan with ZKPassport App"),
115
+ qrCode && (React.createElement("img", { src: qrCode, alt: "Verification QR Code", className: "qr-code" })),
116
+ React.createElement("p", null, "Scan this QR code with the ZKPassport mobile app to verify your identity."),
117
+ React.createElement("a", { href: verificationUrl, target: "_blank", rel: "noopener noreferrer", className: "verification-link" }, "Or open verification link directly")),
118
+ React.createElement("div", { className: "verification-instructions" },
119
+ React.createElement("h5", null, "Instructions:"),
120
+ React.createElement("ol", null,
121
+ React.createElement("li", null, "Download the ZKPassport app if you haven't already"),
122
+ React.createElement("li", null, "Scan the QR code above"),
123
+ React.createElement("li", null, "Follow the app instructions to verify your government ID"),
124
+ React.createElement("li", null, "Your verification will be processed automatically"))))),
125
+ status === 'processing' && (React.createElement("div", { className: "verification-processing" },
126
+ React.createElement("div", { className: "spinner" }),
127
+ React.createElement("p", null, "Processing your verification..."))),
128
+ status === 'complete' && (React.createElement("div", { className: "verification-complete" },
129
+ React.createElement("div", { className: "success-icon" }, "\u2705"),
130
+ React.createElement("h4", null, "Verification Complete!"),
131
+ React.createElement("p", null, "Your identity has been verified successfully. You now have access to TREZA compliance features."))),
132
+ status === 'error' && (React.createElement("div", { className: "verification-error" },
133
+ React.createElement("div", { className: "error-icon" }, "\u274C"),
134
+ React.createElement("h4", null, "Verification Error"),
135
+ React.createElement("p", null, error),
136
+ React.createElement("button", { onClick: () => setStatus('idle'), className: "btn-secondary" }, "Try Again")))));
137
+ };
138
+ /**
139
+ * Component to display current compliance status
140
+ */
141
+ const ComplianceStatusDisplay = ({ userAddress, showDetails = false, className = "" }) => {
142
+ const { sdk } = useComplianceContext();
143
+ const [status, setStatus] = React.useState(null);
144
+ const [isLoading, setIsLoading] = React.useState(true);
145
+ const [error, setError] = React.useState("");
146
+ React.useEffect(() => {
147
+ const checkStatus = async () => {
148
+ if (!sdk || !userAddress)
149
+ return;
150
+ setIsLoading(true);
151
+ try {
152
+ const complianceStatus = await sdk.checkComplianceStatus(userAddress);
153
+ setStatus(complianceStatus);
154
+ setError("");
155
+ }
156
+ catch (err) {
157
+ setError(err instanceof Error ? err.message : 'Failed to check compliance status');
158
+ }
159
+ finally {
160
+ setIsLoading(false);
161
+ }
162
+ };
163
+ checkStatus();
164
+ }, [sdk, userAddress]);
165
+ if (isLoading) {
166
+ return (React.createElement("div", { className: `compliance-status loading ${className}` },
167
+ React.createElement("div", { className: "spinner" }),
168
+ React.createElement("span", null, "Checking compliance status...")));
169
+ }
170
+ if (error) {
171
+ return (React.createElement("div", { className: `compliance-status error ${className}` },
172
+ React.createElement("span", { className: "status-icon" }, "\u26A0\uFE0F"),
173
+ React.createElement("span", null,
174
+ "Error: ",
175
+ error)));
176
+ }
177
+ if (!status) {
178
+ return (React.createElement("div", { className: `compliance-status unknown ${className}` },
179
+ React.createElement("span", { className: "status-icon" }, "\u2753"),
180
+ React.createElement("span", null, "Status unknown")));
181
+ }
182
+ return (React.createElement("div", { className: `compliance-status ${status.isCompliant ? 'compliant' : 'non-compliant'} ${className}` },
183
+ React.createElement("div", { className: "status-header" },
184
+ React.createElement("span", { className: "status-icon" }, status.isCompliant ? '✅' : '❌'),
185
+ React.createElement("span", { className: "status-text" }, status.isCompliant ? 'Verified' : 'Not Verified')),
186
+ showDetails && status.isCompliant && (React.createElement("div", { className: "status-details" },
187
+ React.createElement("div", { className: "detail-item" },
188
+ React.createElement("span", { className: "label" }, "Level:"),
189
+ React.createElement("span", { className: "value" }, status.verificationLevel)),
190
+ React.createElement("div", { className: "detail-item" },
191
+ React.createElement("span", { className: "label" }, "Expires:"),
192
+ React.createElement("span", { className: "value" }, new Date(status.expirationTime).toLocaleDateString())),
193
+ React.createElement("div", { className: "detail-item" },
194
+ React.createElement("span", { className: "label" }, "Attributes:"),
195
+ React.createElement("div", { className: "attributes" },
196
+ status.attributes.ageVerified && React.createElement("span", { className: "attribute" }, "Age \u2713"),
197
+ status.attributes.nationalityVerified && React.createElement("span", { className: "attribute" }, "Nationality \u2713"),
198
+ status.attributes.uniquenessVerified && React.createElement("span", { className: "attribute" }, "Uniqueness \u2713")))))));
199
+ };
200
+ /**
201
+ * Component to display governance eligibility
202
+ */
203
+ const GovernanceEligibility = ({ userAddress, proposalId, className = "" }) => {
204
+ const { sdk } = useComplianceContext();
205
+ const [eligibility, setEligibility] = React.useState(null);
206
+ const [isLoading, setIsLoading] = React.useState(true);
207
+ React.useEffect(() => {
208
+ const checkEligibility = async () => {
209
+ if (!sdk || !userAddress)
210
+ return;
211
+ setIsLoading(true);
212
+ try {
213
+ const result = await sdk.checkGovernanceEligibility(userAddress, proposalId);
214
+ setEligibility(result);
215
+ }
216
+ catch (err) {
217
+ console.error('Error checking governance eligibility:', err);
218
+ }
219
+ finally {
220
+ setIsLoading(false);
221
+ }
222
+ };
223
+ checkEligibility();
224
+ }, [sdk, userAddress, proposalId]);
225
+ if (isLoading) {
226
+ return (React.createElement("div", { className: `governance-eligibility loading ${className}` },
227
+ React.createElement("div", { className: "spinner" }),
228
+ React.createElement("span", null, "Checking eligibility...")));
229
+ }
230
+ if (!eligibility) {
231
+ return (React.createElement("div", { className: `governance-eligibility error ${className}` },
232
+ React.createElement("span", null, "Unable to check eligibility")));
233
+ }
234
+ return (React.createElement("div", { className: `governance-eligibility ${eligibility.canParticipate ? 'eligible' : 'ineligible'} ${className}` },
235
+ React.createElement("div", { className: "eligibility-status" },
236
+ React.createElement("span", { className: "status-icon" }, eligibility.canParticipate ? '🗳️' : '🚫'),
237
+ React.createElement("span", { className: "status-text" }, eligibility.canParticipate ? 'Eligible to Vote' : 'Not Eligible')),
238
+ eligibility.canParticipate && (React.createElement("div", { className: "voting-details" },
239
+ React.createElement("div", { className: "voting-weight" },
240
+ React.createElement("span", { className: "label" }, "Voting Weight:"),
241
+ React.createElement("span", { className: "value" },
242
+ eligibility.votingWeight,
243
+ "x")),
244
+ React.createElement("div", { className: "compliance-level" },
245
+ React.createElement("span", { className: "label" }, "Compliance Level:"),
246
+ React.createElement("span", { className: "value" }, eligibility.complianceLevel))))));
247
+ };
248
+ // CSS styles (you would typically put this in a separate CSS file)
249
+ const complianceStyles = `
250
+ .treza-compliance-verification {
251
+ max-width: 500px;
252
+ margin: 0 auto;
253
+ padding: 20px;
254
+ border: 1px solid #e0e0e0;
255
+ border-radius: 8px;
256
+ background: #fff;
257
+ }
258
+
259
+ .verification-header h3 {
260
+ margin: 0 0 10px 0;
261
+ color: #333;
262
+ }
263
+
264
+ .verification-header p {
265
+ margin: 0 0 20px 0;
266
+ color: #666;
267
+ font-size: 14px;
268
+ }
269
+
270
+ .btn-primary, .btn-secondary {
271
+ padding: 12px 24px;
272
+ border: none;
273
+ border-radius: 6px;
274
+ font-size: 16px;
275
+ cursor: pointer;
276
+ transition: background-color 0.2s;
277
+ }
278
+
279
+ .btn-primary {
280
+ background: #007bff;
281
+ color: white;
282
+ }
283
+
284
+ .btn-primary:hover {
285
+ background: #0056b3;
286
+ }
287
+
288
+ .btn-primary:disabled {
289
+ background: #ccc;
290
+ cursor: not-allowed;
291
+ }
292
+
293
+ .btn-secondary {
294
+ background: #6c757d;
295
+ color: white;
296
+ }
297
+
298
+ .qr-code {
299
+ max-width: 200px;
300
+ height: auto;
301
+ margin: 10px 0;
302
+ }
303
+
304
+ .spinner {
305
+ width: 20px;
306
+ height: 20px;
307
+ border: 2px solid #f3f3f3;
308
+ border-top: 2px solid #007bff;
309
+ border-radius: 50%;
310
+ animation: spin 1s linear infinite;
311
+ display: inline-block;
312
+ margin-right: 10px;
313
+ }
314
+
315
+ @keyframes spin {
316
+ 0% { transform: rotate(0deg); }
317
+ 100% { transform: rotate(360deg); }
318
+ }
319
+
320
+ .compliance-status {
321
+ display: flex;
322
+ align-items: center;
323
+ padding: 10px;
324
+ border-radius: 6px;
325
+ margin: 10px 0;
326
+ }
327
+
328
+ .compliance-status.compliant {
329
+ background: #d4edda;
330
+ color: #155724;
331
+ border: 1px solid #c3e6cb;
332
+ }
333
+
334
+ .compliance-status.non-compliant {
335
+ background: #f8d7da;
336
+ color: #721c24;
337
+ border: 1px solid #f5c6cb;
338
+ }
339
+
340
+ .status-icon {
341
+ margin-right: 8px;
342
+ font-size: 18px;
343
+ }
344
+
345
+ .status-details {
346
+ margin-top: 10px;
347
+ font-size: 14px;
348
+ }
349
+
350
+ .detail-item {
351
+ margin: 5px 0;
352
+ }
353
+
354
+ .label {
355
+ font-weight: bold;
356
+ margin-right: 8px;
357
+ }
358
+
359
+ .attributes {
360
+ display: flex;
361
+ gap: 8px;
362
+ flex-wrap: wrap;
363
+ }
364
+
365
+ .attribute {
366
+ background: #e9ecef;
367
+ padding: 2px 6px;
368
+ border-radius: 4px;
369
+ font-size: 12px;
370
+ }
371
+ `;
372
+
373
+ class ComplianceService {
374
+ constructor(config = {}) {
375
+ this.sdk = null;
376
+ this.config = {
377
+ zkPassportDomain: "trezalabs.com",
378
+ zkVerifyEndpoint: "https://api.zkverify.io",
379
+ trezaTokenAddress: process.env.REACT_APP_TREZA_TOKEN_ADDRESS || "0x8278d4FbfaB7dac14eC0295421D0a2733b4504E5",
380
+ complianceVerifierAddress: process.env.REACT_APP_COMPLIANCE_VERIFIER_ADDRESS || "0x8c0C6e0Eaf6bc693745A1A3a722e2c9028BBe874",
381
+ complianceIntegrationAddress: process.env.REACT_APP_COMPLIANCE_INTEGRATION_ADDRESS || "0xf3ecfC409761D715F137Bfe7078Acec6d7F55428",
382
+ ...config
383
+ };
384
+ }
385
+ /**
386
+ * Initialize the compliance SDK with provider and signer
387
+ */
388
+ async initialize(provider, signer) {
389
+ try {
390
+ this.sdk = new sdk.TrezaComplianceSDK({
391
+ zkPassportDomain: this.config.zkPassportDomain,
392
+ zkVerifyEndpoint: this.config.zkVerifyEndpoint,
393
+ zkVerifyApiKey: this.config.zkVerifyApiKey,
394
+ trezaTokenAddress: this.config.trezaTokenAddress,
395
+ complianceVerifierAddress: this.config.complianceVerifierAddress,
396
+ complianceIntegrationAddress: this.config.complianceIntegrationAddress,
397
+ provider,
398
+ signer
399
+ });
400
+ }
401
+ catch (error) {
402
+ console.error('Failed to initialize compliance service:', error);
403
+ throw error;
404
+ }
405
+ }
406
+ /**
407
+ * Get the initialized SDK instance
408
+ */
409
+ getSDK() {
410
+ if (!this.sdk) {
411
+ throw new Error('Compliance service not initialized. Call initialize() first.');
412
+ }
413
+ return this.sdk;
414
+ }
415
+ /**
416
+ * Check if the service is initialized
417
+ */
418
+ isInitialized() {
419
+ return this.sdk !== null;
420
+ }
421
+ /**
422
+ * Initiate verification with React-friendly error handling
423
+ */
424
+ async initiateVerification(requirements) {
425
+ try {
426
+ if (!this.sdk) {
427
+ throw new Error('Service not initialized');
428
+ }
429
+ const url = await this.sdk.initiateVerification(requirements);
430
+ return { success: true, url };
431
+ }
432
+ catch (error) {
433
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
434
+ return { success: false, error: errorMessage };
435
+ }
436
+ }
437
+ /**
438
+ * Process verification result with React-friendly error handling
439
+ */
440
+ async processVerificationResult(zkPassportResult, userAddress) {
441
+ try {
442
+ if (!this.sdk) {
443
+ throw new Error('Service not initialized');
444
+ }
445
+ const result = await this.sdk.processVerificationResult(zkPassportResult, userAddress);
446
+ return { success: true, result };
447
+ }
448
+ catch (error) {
449
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
450
+ return { success: false, error: errorMessage };
451
+ }
452
+ }
453
+ /**
454
+ * Check compliance status with React-friendly error handling
455
+ */
456
+ async checkComplianceStatus(userAddress) {
457
+ try {
458
+ if (!this.sdk) {
459
+ throw new Error('Service not initialized');
460
+ }
461
+ const status = await this.sdk.checkComplianceStatus(userAddress);
462
+ return { success: true, status };
463
+ }
464
+ catch (error) {
465
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
466
+ return { success: false, error: errorMessage };
467
+ }
468
+ }
469
+ /**
470
+ * Generate QR code for verification URL
471
+ */
472
+ async generateQRCode(url) {
473
+ try {
474
+ if (!this.sdk) {
475
+ throw new Error('Service not initialized');
476
+ }
477
+ const qrCode = await this.sdk.generateQRCode(url);
478
+ return { success: true, qrCode };
479
+ }
480
+ catch (error) {
481
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
482
+ return { success: false, error: errorMessage };
483
+ }
484
+ }
485
+ /**
486
+ * Batch check compliance for multiple users
487
+ */
488
+ async batchCheckCompliance(userAddresses) {
489
+ try {
490
+ if (!this.sdk) {
491
+ throw new Error('Service not initialized');
492
+ }
493
+ const results = await this.sdk.batchCheckCompliance(userAddresses);
494
+ return { success: true, results };
495
+ }
496
+ catch (error) {
497
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
498
+ return { success: false, error: errorMessage };
499
+ }
500
+ }
501
+ /**
502
+ * Check governance eligibility
503
+ */
504
+ async checkGovernanceEligibility(userAddress, proposalId) {
505
+ try {
506
+ if (!this.sdk) {
507
+ throw new Error('Service not initialized');
508
+ }
509
+ if (!proposalId) {
510
+ throw new Error('Proposal ID is required');
511
+ }
512
+ const proposalIdNum = parseInt(proposalId, 10);
513
+ if (isNaN(proposalIdNum)) {
514
+ throw new Error('Invalid proposal ID: must be a number');
515
+ }
516
+ const eligibility = await this.sdk.checkGovernanceEligibility(userAddress, proposalIdNum);
517
+ return { success: true, eligibility };
518
+ }
519
+ catch (error) {
520
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
521
+ return { success: false, error: errorMessage };
522
+ }
523
+ }
524
+ /**
525
+ * Cleanup resources
526
+ */
527
+ destroy() {
528
+ this.sdk = null;
529
+ }
530
+ }
531
+ // Singleton instance for React apps
532
+ let complianceServiceInstance = null;
533
+ /**
534
+ * Get or create the global compliance service instance
535
+ */
536
+ function getComplianceService(config) {
537
+ if (!complianceServiceInstance) {
538
+ complianceServiceInstance = new ComplianceService(config);
539
+ }
540
+ return complianceServiceInstance;
541
+ }
542
+ /**
543
+ * Reset the global compliance service instance
544
+ */
545
+ function resetComplianceService() {
546
+ if (complianceServiceInstance) {
547
+ complianceServiceInstance.destroy();
548
+ complianceServiceInstance = null;
549
+ }
550
+ }
551
+
552
+ class WalletService {
553
+ constructor() {
554
+ this.provider = null;
555
+ this.signer = null;
556
+ this.currentAddress = null;
557
+ }
558
+ /**
559
+ * Connect to MetaMask or other Web3 wallet
560
+ */
561
+ async connectWallet() {
562
+ try {
563
+ // Check if Web3 is available
564
+ if (typeof window === 'undefined' || !window.ethereum) {
565
+ return {
566
+ success: false,
567
+ error: 'Web3 wallet not found. Please install MetaMask or another Web3 wallet.'
568
+ };
569
+ }
570
+ // Request account access
571
+ await window.ethereum.request({ method: 'eth_requestAccounts' });
572
+ // Create provider and signer
573
+ const provider = new ethers.ethers.BrowserProvider(window.ethereum);
574
+ const signer = await provider.getSigner();
575
+ const address = await signer.getAddress();
576
+ const network = await provider.getNetwork();
577
+ // Store references
578
+ this.provider = provider;
579
+ this.signer = signer;
580
+ this.currentAddress = address;
581
+ return {
582
+ success: true,
583
+ provider,
584
+ signer,
585
+ address,
586
+ chainId: Number(network.chainId)
587
+ };
588
+ }
589
+ catch (error) {
590
+ const errorMessage = error instanceof Error ? error.message : 'Failed to connect wallet';
591
+ return {
592
+ success: false,
593
+ error: errorMessage
594
+ };
595
+ }
596
+ }
597
+ /**
598
+ * Disconnect wallet
599
+ */
600
+ disconnect() {
601
+ this.provider = null;
602
+ this.signer = null;
603
+ this.currentAddress = null;
604
+ }
605
+ /**
606
+ * Get current wallet info
607
+ */
608
+ async getWalletInfo() {
609
+ if (!this.provider || !this.currentAddress) {
610
+ return null;
611
+ }
612
+ try {
613
+ const balance = await this.provider.getBalance(this.currentAddress);
614
+ const network = await this.provider.getNetwork();
615
+ return {
616
+ address: this.currentAddress,
617
+ chainId: Number(network.chainId),
618
+ balance: ethers.ethers.formatEther(balance),
619
+ isConnected: true
620
+ };
621
+ }
622
+ catch (error) {
623
+ console.error('Failed to get wallet info:', error);
624
+ return null;
625
+ }
626
+ }
627
+ /**
628
+ * Switch to a specific network
629
+ */
630
+ async switchNetwork(chainId) {
631
+ try {
632
+ if (!window.ethereum) {
633
+ return { success: false, error: 'Web3 wallet not found' };
634
+ }
635
+ await window.ethereum.request({
636
+ method: 'wallet_switchEthereumChain',
637
+ params: [{ chainId: `0x${chainId.toString(16)}` }],
638
+ });
639
+ return { success: true };
640
+ }
641
+ catch (error) {
642
+ // If the chain hasn't been added to MetaMask
643
+ if (error.code === 4902) {
644
+ return { success: false, error: 'Network not added to wallet' };
645
+ }
646
+ const errorMessage = error instanceof Error ? error.message : 'Failed to switch network';
647
+ return { success: false, error: errorMessage };
648
+ }
649
+ }
650
+ /**
651
+ * Add a custom network to the wallet
652
+ */
653
+ async addNetwork(networkConfig) {
654
+ try {
655
+ if (!window.ethereum) {
656
+ return { success: false, error: 'Web3 wallet not found' };
657
+ }
658
+ await window.ethereum.request({
659
+ method: 'wallet_addEthereumChain',
660
+ params: [{
661
+ chainId: `0x${networkConfig.chainId.toString(16)}`,
662
+ chainName: networkConfig.chainName,
663
+ rpcUrls: networkConfig.rpcUrls,
664
+ nativeCurrency: networkConfig.nativeCurrency,
665
+ blockExplorerUrls: networkConfig.blockExplorerUrls
666
+ }],
667
+ });
668
+ return { success: true };
669
+ }
670
+ catch (error) {
671
+ const errorMessage = error instanceof Error ? error.message : 'Failed to add network';
672
+ return { success: false, error: errorMessage };
673
+ }
674
+ }
675
+ /**
676
+ * Sign a message
677
+ */
678
+ async signMessage(message) {
679
+ try {
680
+ if (!this.signer) {
681
+ return { success: false, error: 'Wallet not connected' };
682
+ }
683
+ const signature = await this.signer.signMessage(message);
684
+ return { success: true, signature };
685
+ }
686
+ catch (error) {
687
+ const errorMessage = error instanceof Error ? error.message : 'Failed to sign message';
688
+ return { success: false, error: errorMessage };
689
+ }
690
+ }
691
+ /**
692
+ * Get current provider
693
+ */
694
+ getProvider() {
695
+ return this.provider;
696
+ }
697
+ /**
698
+ * Get current signer
699
+ */
700
+ getSigner() {
701
+ return this.signer;
702
+ }
703
+ /**
704
+ * Get current address
705
+ */
706
+ getCurrentAddress() {
707
+ return this.currentAddress;
708
+ }
709
+ /**
710
+ * Check if wallet is connected
711
+ */
712
+ isConnected() {
713
+ return this.provider !== null && this.signer !== null && this.currentAddress !== null;
714
+ }
715
+ /**
716
+ * Listen for account changes
717
+ */
718
+ onAccountsChanged(callback) {
719
+ if (window.ethereum) {
720
+ window.ethereum.on('accountsChanged', callback);
721
+ }
722
+ }
723
+ /**
724
+ * Listen for chain changes
725
+ */
726
+ onChainChanged(callback) {
727
+ if (window.ethereum) {
728
+ window.ethereum.on('chainChanged', callback);
729
+ }
730
+ }
731
+ /**
732
+ * Remove event listeners
733
+ */
734
+ removeAllListeners() {
735
+ if (window.ethereum) {
736
+ window.ethereum.removeAllListeners('accountsChanged');
737
+ window.ethereum.removeAllListeners('chainChanged');
738
+ }
739
+ }
740
+ }
741
+ // Singleton instance for React apps
742
+ let walletServiceInstance = null;
743
+ /**
744
+ * Get or create the global wallet service instance
745
+ */
746
+ function getWalletService() {
747
+ if (!walletServiceInstance) {
748
+ walletServiceInstance = new WalletService();
749
+ }
750
+ return walletServiceInstance;
751
+ }
752
+ /**
753
+ * Reset the global wallet service instance
754
+ */
755
+ function resetWalletService() {
756
+ if (walletServiceInstance) {
757
+ walletServiceInstance.removeAllListeners();
758
+ walletServiceInstance.disconnect();
759
+ walletServiceInstance = null;
760
+ }
761
+ }
762
+
763
+ /**
764
+ * Hook for wallet connection and management
765
+ */
766
+ function useWallet() {
767
+ const [isConnected, setIsConnected] = React.useState(false);
768
+ const [isConnecting, setIsConnecting] = React.useState(false);
769
+ const [walletInfo, setWalletInfo] = React.useState(null);
770
+ const [provider, setProvider] = React.useState(null);
771
+ const [signer, setSigner] = React.useState(null);
772
+ const [address, setAddress] = React.useState(null);
773
+ const [error, setError] = React.useState(null);
774
+ const walletService = React.useRef(getWalletService());
775
+ const connect = React.useCallback(async () => {
776
+ setIsConnecting(true);
777
+ setError(null);
778
+ try {
779
+ const result = await walletService.current.connectWallet();
780
+ if (result.success) {
781
+ setIsConnected(true);
782
+ setProvider(result.provider || null);
783
+ setSigner(result.signer || null);
784
+ setAddress(result.address || null);
785
+ // Get wallet info
786
+ const info = await walletService.current.getWalletInfo();
787
+ setWalletInfo(info);
788
+ }
789
+ else {
790
+ setError(result.error || 'Failed to connect wallet');
791
+ }
792
+ }
793
+ catch (err) {
794
+ setError(err instanceof Error ? err.message : 'Failed to connect wallet');
795
+ }
796
+ finally {
797
+ setIsConnecting(false);
798
+ }
799
+ }, []);
800
+ const disconnect = React.useCallback(() => {
801
+ walletService.current.disconnect();
802
+ setIsConnected(false);
803
+ setProvider(null);
804
+ setSigner(null);
805
+ setAddress(null);
806
+ setWalletInfo(null);
807
+ setError(null);
808
+ }, []);
809
+ const switchNetwork = React.useCallback(async (chainId) => {
810
+ setError(null);
811
+ try {
812
+ const result = await walletService.current.switchNetwork(chainId);
813
+ if (!result.success) {
814
+ setError(result.error || 'Failed to switch network');
815
+ }
816
+ }
817
+ catch (err) {
818
+ setError(err instanceof Error ? err.message : 'Failed to switch network');
819
+ }
820
+ }, []);
821
+ // Set up event listeners
822
+ React.useEffect(() => {
823
+ const handleAccountsChanged = (accounts) => {
824
+ if (accounts.length === 0) {
825
+ disconnect();
826
+ }
827
+ else {
828
+ setAddress(accounts[0]);
829
+ }
830
+ };
831
+ const handleChainChanged = () => {
832
+ // Reload wallet info when chain changes
833
+ if (isConnected) {
834
+ walletService.current.getWalletInfo().then(setWalletInfo);
835
+ }
836
+ };
837
+ walletService.current.onAccountsChanged(handleAccountsChanged);
838
+ walletService.current.onChainChanged(handleChainChanged);
839
+ return () => {
840
+ walletService.current.removeAllListeners();
841
+ };
842
+ }, [isConnected, disconnect]);
843
+ return {
844
+ isConnected,
845
+ isConnecting,
846
+ walletInfo,
847
+ provider,
848
+ signer,
849
+ address,
850
+ error,
851
+ connect,
852
+ disconnect,
853
+ switchNetwork
854
+ };
855
+ }
856
+ /**
857
+ * Hook for compliance operations
858
+ */
859
+ function useCompliance(provider, signer) {
860
+ const [isInitialized, setIsInitialized] = React.useState(false);
861
+ const [isLoading, setIsLoading] = React.useState(false);
862
+ const [error, setError] = React.useState(null);
863
+ const complianceService = React.useRef(getComplianceService());
864
+ // Initialize service when provider/signer changes
865
+ React.useEffect(() => {
866
+ if (provider) {
867
+ setIsLoading(true);
868
+ complianceService.current.initialize(provider, signer)
869
+ .then(() => {
870
+ setIsInitialized(true);
871
+ setError(null);
872
+ })
873
+ .catch((err) => {
874
+ setError(err instanceof Error ? err.message : 'Failed to initialize compliance');
875
+ setIsInitialized(false);
876
+ })
877
+ .finally(() => {
878
+ setIsLoading(false);
879
+ });
880
+ }
881
+ else {
882
+ setIsInitialized(false);
883
+ }
884
+ }, [provider, signer]);
885
+ const initiateVerification = React.useCallback(async (requirements) => {
886
+ setError(null);
887
+ const result = await complianceService.current.initiateVerification(requirements);
888
+ if (result.success) {
889
+ return result.url || null;
890
+ }
891
+ else {
892
+ setError(result.error || 'Failed to initiate verification');
893
+ return null;
894
+ }
895
+ }, []);
896
+ const processVerification = React.useCallback(async (zkPassportResult, userAddress) => {
897
+ setError(null);
898
+ const result = await complianceService.current.processVerificationResult(zkPassportResult, userAddress);
899
+ if (result.success) {
900
+ return result.result || null;
901
+ }
902
+ else {
903
+ setError(result.error || 'Failed to process verification');
904
+ return null;
905
+ }
906
+ }, []);
907
+ const checkCompliance = React.useCallback(async (userAddress) => {
908
+ setError(null);
909
+ const result = await complianceService.current.checkComplianceStatus(userAddress);
910
+ if (result.success) {
911
+ return result.status || null;
912
+ }
913
+ else {
914
+ setError(result.error || 'Failed to check compliance');
915
+ return null;
916
+ }
917
+ }, []);
918
+ const generateQRCode = React.useCallback(async (url) => {
919
+ setError(null);
920
+ const result = await complianceService.current.generateQRCode(url);
921
+ if (result.success) {
922
+ return result.qrCode || null;
923
+ }
924
+ else {
925
+ setError(result.error || 'Failed to generate QR code');
926
+ return null;
927
+ }
928
+ }, []);
929
+ return {
930
+ isInitialized,
931
+ isLoading,
932
+ error,
933
+ initiateVerification,
934
+ processVerification,
935
+ checkCompliance,
936
+ generateQRCode
937
+ };
938
+ }
939
+ /**
940
+ * Combined hook for wallet and compliance functionality
941
+ */
942
+ function useTreza() {
943
+ const wallet = useWallet();
944
+ const compliance = useCompliance(wallet.provider || undefined, wallet.signer || undefined);
945
+ const isReady = wallet.isConnected && compliance.isInitialized;
946
+ return {
947
+ wallet,
948
+ compliance,
949
+ isReady
950
+ };
951
+ }
952
+ /**
953
+ * Hook for managing the complete verification flow
954
+ */
955
+ function useVerificationFlow(provider, signer) {
956
+ const [status, setStatus] = React.useState('idle');
957
+ const [verificationUrl, setVerificationUrl] = React.useState(null);
958
+ const [qrCode, setQrCode] = React.useState(null);
959
+ const [result, setResult] = React.useState(null);
960
+ const [error, setError] = React.useState(null);
961
+ const [currentUserAddress, setCurrentUserAddress] = React.useState(null);
962
+ const compliance = useCompliance(provider, signer);
963
+ const startVerification = React.useCallback(async (userAddress, requirements) => {
964
+ setStatus('generating');
965
+ setError(null);
966
+ setResult(null);
967
+ setCurrentUserAddress(userAddress);
968
+ try {
969
+ const url = await compliance.initiateVerification(requirements);
970
+ if (url) {
971
+ setVerificationUrl(url);
972
+ const qr = await compliance.generateQRCode(url);
973
+ if (qr) {
974
+ setQrCode(qr);
975
+ setStatus('waiting');
976
+ }
977
+ else {
978
+ throw new Error('Failed to generate QR code');
979
+ }
980
+ }
981
+ else {
982
+ throw new Error('Failed to initiate verification');
983
+ }
984
+ }
985
+ catch (err) {
986
+ setError(err instanceof Error ? err.message : 'Verification failed');
987
+ setStatus('error');
988
+ }
989
+ }, [compliance]);
990
+ const processResult = React.useCallback(async (zkPassportResult) => {
991
+ if (!currentUserAddress) {
992
+ setError('No user address set');
993
+ setStatus('error');
994
+ return;
995
+ }
996
+ setStatus('processing');
997
+ setError(null);
998
+ try {
999
+ const verificationResult = await compliance.processVerification(zkPassportResult, currentUserAddress);
1000
+ if (verificationResult) {
1001
+ setResult(verificationResult);
1002
+ setStatus('completed');
1003
+ }
1004
+ else {
1005
+ throw new Error('Failed to process verification result');
1006
+ }
1007
+ }
1008
+ catch (err) {
1009
+ setError(err instanceof Error ? err.message : 'Processing failed');
1010
+ setStatus('error');
1011
+ }
1012
+ }, [compliance, currentUserAddress]);
1013
+ const reset = React.useCallback(() => {
1014
+ setStatus('idle');
1015
+ setVerificationUrl(null);
1016
+ setQrCode(null);
1017
+ setResult(null);
1018
+ setError(null);
1019
+ setCurrentUserAddress(null);
1020
+ }, []);
1021
+ return {
1022
+ status,
1023
+ verificationUrl,
1024
+ qrCode,
1025
+ result,
1026
+ error,
1027
+ startVerification,
1028
+ processResult,
1029
+ reset
1030
+ };
1031
+ }
1032
+
1033
+ /**
1034
+ * @treza/react - React components for TREZA SDK
1035
+ *
1036
+ * Privacy-first DeFi UI components with zero-knowledge compliance
1037
+ */
1038
+ // Component exports
1039
+ // Version
1040
+ const VERSION = '1.0.0';
1041
+
1042
+ exports.ComplianceProvider = ComplianceProvider;
1043
+ exports.ComplianceService = ComplianceService;
1044
+ exports.ComplianceStatusDisplay = ComplianceStatusDisplay;
1045
+ exports.ComplianceVerification = ComplianceVerification;
1046
+ exports.GovernanceEligibility = GovernanceEligibility;
1047
+ exports.VERSION = VERSION;
1048
+ exports.WalletService = WalletService;
1049
+ exports.complianceStyles = complianceStyles;
1050
+ exports.getComplianceService = getComplianceService;
1051
+ exports.getWalletService = getWalletService;
1052
+ exports.resetComplianceService = resetComplianceService;
1053
+ exports.resetWalletService = resetWalletService;
1054
+ exports.useCompliance = useCompliance;
1055
+ exports.useComplianceContext = useComplianceContext;
1056
+ exports.useTreza = useTreza;
1057
+ exports.useVerificationFlow = useVerificationFlow;
1058
+ exports.useWallet = useWallet;
1059
+ //# sourceMappingURL=index.js.map