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