dop-wallet-v6 1.2.12 → 1.2.14

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,2174 @@
1
+ # DOP Wallet v6 React Native Integration Guide
2
+
3
+ This comprehensive guide covers the integration of DOP Wallet v6 (dop-wallet-v6) into React Native applications, providing privacy-focused features for both ERC-20 tokens and ERC-721 NFTs on Ethereum, Polygon, and BNB Chain.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Prerequisites](#prerequisites)
8
+ 2. [Installation](#installation)
9
+ 3. [Initialize Engine](#initialize-engine)
10
+ 4. [Wallet Management](#wallet-management)
11
+ - [Wallet Creation Functions](#wallet-creation-functions)
12
+ - [Input Requirements](#input-requirements)
13
+ - [React Native Wallet Creation](#react-native-wallet-creation)
14
+ - [Complete Examples](#complete-examples)
15
+ - [Error Handling](#error-handling)
16
+ - [Best Practices for React Native](#best-practices-for-react-native)
17
+ - [Migration from Old API](#migration-from-old-api)
18
+ 5. [ERC-20 Token Features](#erc-20-token-features)
19
+ - [Balances](#erc-20-balances)
20
+ - [Syncing](#erc-20-syncing)
21
+ - [Encrypt, Send, Decrypt](#erc-20-encrypt-send-decrypt)
22
+ - [Transaction History](#erc-20-transaction-history)
23
+ - [Selective Transparency and Proof Verification](#erc-20-selective-transparency)
24
+ 6. [ERC-721 NFT Features](#erc-721-nft-features)
25
+ - [Balances](#erc-721-balances)
26
+ - [Syncing](#erc-721-syncing)
27
+ - [Encrypt, Send, Decrypt](#erc-721-encrypt-send-decrypt)
28
+ - [Transaction History](#erc-721-transaction-history)
29
+ - [Selective Transparency and Proof Verification](#erc-721-selective-transparency)
30
+ 7. [Advanced Features](#advanced-features)
31
+ - [Transaction History with Wallet Visibility](#transaction-history-visibility)
32
+ 8. [Complete Example](#complete-example)
33
+ 9. [Testing](#testing)
34
+ 10. [Troubleshooting](#troubleshooting)
35
+
36
+ ## Prerequisites
37
+
38
+ - React Native 0.65+
39
+ - Node.js 16+
40
+ - TypeScript support
41
+ - React Native async storage or compatible storage solution
42
+ - LevelDB compatible database for React Native
43
+
44
+ ## Installation
45
+
46
+ ### 1. Install the DOP Wallet SDK
47
+
48
+ ```bash
49
+ npm install dop-wallet-v6
50
+ # or
51
+ yarn add dop-wallet-v6
52
+ ```
53
+
54
+ ### 2. Install Required Peer Dependencies
55
+
56
+ The SDK requires AsyncStorage for React Native persistence:
57
+
58
+ ```bash
59
+ npm install @react-native-async-storage/async-storage
60
+ # or
61
+ yarn add @react-native-async-storage/async-storage
62
+ ```
63
+
64
+ **Note**: If you encounter issues with `startDopEngineReactNative` being undefined, ensure all dependencies are properly installed:
65
+
66
+ ```bash
67
+ # Force reinstall dependencies if needed
68
+ npm install --legacy-peer-deps
69
+ # or
70
+ yarn install
71
+ ```
72
+
73
+ ### 3. Install React Native Dependencies
74
+
75
+ Install the required React Native-specific dependencies:
76
+
77
+ ```bash
78
+ npm install @react-native-async-storage/async-storage
79
+ ```
80
+
81
+ **Or with Yarn:**
82
+
83
+ ```bash
84
+ yarn add @react-native-async-storage/async-storage
85
+ ```
86
+
87
+ > **Important**: The SDK now uses an in-memory database (memdown) for React Native compatibility. AsyncStorage is used only for artifact caching and user preferences.
88
+
89
+ > **Important**: These polyfills are essential for the SDK to function properly. Missing them will cause errors like "Cannot read property 'call' of undefined" or other runtime failures.
90
+
91
+ ### 3. Metro Configuration
92
+
93
+ Create or update your `metro.config.js` file to include Node.js core module aliases:
94
+
95
+ ```javascript
96
+ const { getDefaultConfig } = require('expo/metro-config');
97
+
98
+ const config = getDefaultConfig(__dirname);
99
+
100
+ // Add Node.js core module aliases
101
+ config.resolver.alias = {
102
+ ...config.resolver.alias,
103
+ 'stream': require.resolve('stream-browserify'),
104
+ 'crypto': require.resolve('crypto-browserify'),
105
+ 'http': require.resolve('stream-http'),
106
+ 'https': require.resolve('https-browserify'),
107
+ 'url': require.resolve('url'),
108
+ 'util': require.resolve('util'),
109
+ 'zlib': require.resolve('browserify-zlib'),
110
+ 'path': require.resolve('path-browserify'),
111
+ };
112
+
113
+ // Add required packages to Metro's resolver
114
+ config.resolver.extraNodeModules = {
115
+ ...config.resolver.extraNodeModules,
116
+ 'stream': require.resolve('stream-browserify'),
117
+ 'crypto': require.resolve('crypto-browserify'),
118
+ 'http': require.resolve('stream-http'),
119
+ 'https': require.resolve('https-browserify'),
120
+ 'url': require.resolve('url'),
121
+ 'util': require.resolve('util'),
122
+ 'zlib': require.resolve('browserify-zlib'),
123
+ 'path': require.resolve('path-browserify'),
124
+ };
125
+
126
+ module.exports = config;
127
+ ```
128
+
129
+ **Install the additional browserify modules:**
130
+
131
+ ```bash
132
+ npm install stream-browserify crypto-browserify stream-http https-browserify url util browserify-zlib path-browserify
133
+
134
+ # or with yarn
135
+ yarn add stream-browserify crypto-browserify stream-http https-browserify url util browserify-zlib path-browserify
136
+ ```
137
+
138
+ > **Note**: We removed `react-native-level-fs` from Metro aliases as the SDK now uses `asyncstorage-down` directly for better React Native compatibility.
139
+
140
+ ### 4. Essential Polyfills Setup
141
+
142
+ Import the required polyfills at the **very top** of your app's entry point (usually `App.js` or `index.js`) **before** importing the DOP Wallet SDK:
143
+
144
+ ```typescript
145
+ // CRITICAL: These imports must come FIRST, before any other imports
146
+ import 'react-native-get-random-values';
147
+ import 'react-native-url-polyfill/auto';
148
+ import { Buffer } from 'buffer';
149
+
150
+ // Make Buffer available globally
151
+ global.Buffer = global.Buffer || Buffer;
152
+
153
+ // Now import the DOP Wallet shims
154
+ import 'dop-wallet-v6/react-native-shims';
155
+
156
+ // Your other imports...
157
+ import React from 'react';
158
+ import { AppRegistry } from 'react-native';
159
+ // ... rest of your app
160
+ ```
161
+
162
+ > **⚠️ Critical Order**: The polyfills must be imported in this exact order before any other imports, including the DOP Wallet SDK imports. This prevents "Cannot read property 'call' of undefined" and similar errors.
163
+
164
+ ### 5. Complete Dependencies List
165
+
166
+ Your `package.json` should include all these dependencies. Here's a complete reference:
167
+
168
+ ```json
169
+ {
170
+ "dependencies": {
171
+ "dop-wallet-v6": "^1.2.10",
172
+ "asyncstorage-down": "^4.2.0",
173
+ "@react-native-async-storage/async-storage": "^1.19.0",
174
+ "react-native-get-random-values": "^1.9.0",
175
+ "react-native-url-polyfill": "^2.0.0",
176
+ "buffer": "^6.0.3",
177
+ "util": "^0.12.5",
178
+ "stream-browserify": "^3.0.0",
179
+ "crypto-browserify": "^3.12.0",
180
+ "stream-http": "^3.2.0",
181
+ "https-browserify": "^1.0.0",
182
+ "url": "^0.11.3",
183
+ "browserify-zlib": "^0.2.0",
184
+ "path-browserify": "^1.0.1"
185
+ },
186
+ "devDependencies": {
187
+ "metro-config": "^0.76.0"
188
+ }
189
+ }
190
+ ```
191
+
192
+ **Install all at once:**
193
+ ```bash
194
+ npm install dop-wallet-v6 asyncstorage-down @react-native-async-storage/async-storage react-native-get-random-values react-native-url-polyfill buffer util stream-browserify crypto-browserify stream-http https-browserify url browserify-zlib path-browserify
195
+
196
+ npm install --save-dev metro-config
197
+ ```
198
+
199
+ ### 6. React Native Shims
200
+
201
+ The SDK provides additional shims that handle crypto operations and other Node.js specific functionality. These are automatically loaded when you import the polyfill above.
202
+
203
+ ### 7. Platform-specific Setup
204
+
205
+ #### iOS
206
+ Add to `ios/Podfile`:
207
+
208
+ ```ruby
209
+ pod 'RNFS', :path => '../node_modules/react-native-fs'
210
+ ```
211
+
212
+ Then run:
213
+ ```bash
214
+ cd ios && pod install && cd ..
215
+ ```
216
+
217
+ #### Android
218
+ Add to `android/app/build.gradle` in the `android` section:
219
+
220
+ ```gradle
221
+ android {
222
+ ...
223
+ packagingOptions {
224
+ pickFirst '**/libc++_shared.so'
225
+ pickFirst '**/libjsc.so'
226
+ }
227
+ }
228
+ ```
229
+
230
+ ### 8. Verification Setup
231
+
232
+ You can verify your setup is working by creating a simple test:
233
+
234
+ ```typescript
235
+ // TestSetup.js
236
+ import 'react-native-get-random-values';
237
+ import 'react-native-url-polyfill/auto';
238
+ import { Buffer } from 'buffer';
239
+
240
+ global.Buffer = global.Buffer || Buffer;
241
+
242
+ import 'dop-wallet-v6/react-native-shims';
243
+
244
+ console.log('✓ Polyfills loaded successfully');
245
+ console.log('✓ Buffer available:', typeof Buffer !== 'undefined');
246
+ console.log('✓ Crypto available:', typeof global.crypto !== 'undefined');
247
+
248
+ export const testSetup = () => {
249
+ try {
250
+ // Test crypto.getRandomValues
251
+ const array = new Uint8Array(16);
252
+ crypto.getRandomValues(array);
253
+ console.log('✓ crypto.getRandomValues working');
254
+
255
+ // Test Buffer
256
+ const buffer = Buffer.from('test');
257
+ console.log('✓ Buffer working');
258
+
259
+ return true;
260
+ } catch (error) {
261
+ console.error('❌ Setup verification failed:', error);
262
+ return false;
263
+ }
264
+ };
265
+ ```
266
+
267
+ Import and run this test in your App component to verify everything is working.
268
+
269
+ ## Initialize Engine
270
+
271
+ The DOP Engine must be initialized before any wallet operations can be performed.
272
+
273
+ ```typescript
274
+ import { startDopEngineReactNative, ArtifactStore } from 'dop-wallet-v6';
275
+ import AsyncStorage from '@react-native-async-storage/async-storage';
276
+
277
+ // Configure artifact store for React Native
278
+ class ReactNativeArtifactStore implements ArtifactStore {
279
+ async getItem(key: string): Promise<string | null> {
280
+ return AsyncStorage.getItem(`artifact_${key}`);
281
+ }
282
+
283
+ async setItem(key: string, value: string): Promise<void> {
284
+ await AsyncStorage.setItem(`artifact_${key}`, value);
285
+ }
286
+
287
+ async removeItem(key: string): Promise<void> {
288
+ await AsyncStorage.removeItem(`artifact_${key}`);
289
+ }
290
+
291
+ async clear(): Promise<void> {
292
+ const keys = await AsyncStorage.getAllKeys();
293
+ const artifactKeys = keys.filter(key => key.startsWith('artifact_'));
294
+ await AsyncStorage.multiRemove(artifactKeys);
295
+ }
296
+ }
297
+
298
+ export const initializeDopEngine = async () => {
299
+ try {
300
+ const walletSource = 'myapp'; // Your app identifier (max 16 chars, lowercase)
301
+ const shouldDebug = __DEV__; // Enable debug in development
302
+ const artifactStore = new ReactNativeArtifactStore();
303
+ const useNativeArtifacts = true; // TRUE for mobile
304
+ const skipMerkletreeScans = false; // FALSE to enable full functionality
305
+ const verboseScanLogging = __DEV__;
306
+
307
+ // Simplified React Native initialization - database handled internally
308
+ await startDopEngineReactNative(
309
+ walletSource,
310
+ shouldDebug,
311
+ artifactStore,
312
+ useNativeArtifacts,
313
+ skipMerkletreeScans,
314
+ verboseScanLogging
315
+ );
316
+
317
+ console.log('DOP Engine initialized successfully');
318
+ } catch (error) {
319
+ console.error('Failed to initialize DOP Engine:', error);
320
+ throw error;
321
+ }
322
+ };
323
+ ```
324
+
325
+ > **Note**: The `startDopEngineReactNative` function automatically handles database setup with persistence using AsyncStorage. Data is stored in memory for fast access and automatically persisted to AsyncStorage for data retention between app sessions.
326
+
327
+ ## Wallet Management
328
+
329
+ This section covers all wallet creation and management options available in DOP Wallet v6, including automatic mnemonic generation and importing existing mnemonics.
330
+
331
+ ### Wallet Creation Functions
332
+
333
+ #### 1. `createOrImportDopWallet` - **Recommended** ⭐
334
+
335
+ This is the most comprehensive and user-friendly function that supports both creating new wallets and importing existing ones with React Native compatibility.
336
+
337
+ ```typescript
338
+ import { createOrImportDopWallet, testCircomlibjs } from 'dop-wallet-v6';
339
+ import { NetworkName } from 'dop-sharedmodels-v3';
340
+
341
+ // Create a new wallet with auto-generated mnemonic
342
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey);
343
+
344
+ // Create a new wallet with 24-word mnemonic
345
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
346
+ mnemonicStrength: 256 // 256 bits = 24 words
347
+ });
348
+
349
+ // Import an existing wallet
350
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
351
+ mnemonic: 'your existing twelve word mnemonic phrase goes here like this example'
352
+ });
353
+ ```
354
+
355
+ **Parameters:**
356
+ - `encryptionKey`: string | Buffer | Uint8Array (32 bytes)
357
+ - `options.mnemonic?`: string - Import this mnemonic (if undefined, generates new)
358
+ - `options.creationBlockNumbers?`: Optional block numbers for faster sync
359
+ - `options.dopWalletDerivationIndex?`: number (default: 0)
360
+ - `options.timeout?`: number (default: 60000ms, recommended: 90000ms for React Native)
361
+ - `options.mnemonicStrength?`: 128 | 192 | 256 (default: 128 = 12 words)
362
+
363
+ **Returns:**
364
+ ```typescript
365
+ {
366
+ walletInfo: DopWalletInfo, // Wallet details (ID, address, etc.)
367
+ mnemonic: string // The mnemonic (generated or imported)
368
+ }
369
+ ```
370
+
371
+ #### 2. `createDopWalletSafe` - Safe Creation with Timeout
372
+
373
+ For when you already have a mnemonic and want safe creation with React Native compatibility.
374
+
375
+ ```typescript
376
+ import { createDopWalletSafe } from 'dop-wallet-v6';
377
+
378
+ const walletInfo = await createDopWalletSafe(
379
+ encryptionKey,
380
+ mnemonic,
381
+ creationBlockNumbers,
382
+ derivationIndex,
383
+ timeout // Recommended: 90000ms for React Native
384
+ );
385
+ ```
386
+
387
+ #### 3. `createDopWallet` - Basic Creation
388
+
389
+ The original function for creating wallets from existing mnemonics.
390
+
391
+ ```typescript
392
+ import { createDopWallet } from 'dop-wallet-v6';
393
+
394
+ const walletInfo = await createDopWallet(
395
+ encryptionKey,
396
+ mnemonic,
397
+ creationBlockNumbers,
398
+ derivationIndex
399
+ );
400
+ ```
401
+
402
+ ### Input Requirements
403
+
404
+ #### Encryption Key
405
+ The encryption key must be a **32-byte** value in one of these formats:
406
+ - `string`: Hex string (64 characters)
407
+ - `Buffer`: 32-byte buffer
408
+ - `Uint8Array`: 32-byte array
409
+
410
+ ```typescript
411
+ import { randomBytes } from 'crypto';
412
+
413
+ // Examples of valid encryption keys
414
+ const encryptionKey1 = randomBytes(32).toString('hex'); // string
415
+ const encryptionKey2 = randomBytes(32); // Buffer
416
+ const encryptionKey3 = new Uint8Array(32); // Uint8Array
417
+ ```
418
+
419
+ #### Mnemonic Options
420
+
421
+ | Strength | Bits | Words | Security Level |
422
+ |----------|------|-------|----------------|
423
+ | 128 | 128 | 12 | Standard ✅ |
424
+ | 192 | 192 | 18 | High |
425
+ | 256 | 256 | 24 | Maximum 🔒 |
426
+
427
+ ```typescript
428
+ // Generate different mnemonic lengths
429
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
430
+ mnemonicStrength: 128 // 12 words (default)
431
+ });
432
+
433
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
434
+ mnemonicStrength: 192 // 18 words
435
+ });
436
+
437
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
438
+ mnemonicStrength: 256 // 24 words (most secure)
439
+ });
440
+ ```
441
+
442
+ ### React Native Wallet Creation
443
+
444
+ For React Native apps, use these functions which include circomlibjs compatibility testing:
445
+
446
+ ```typescript
447
+ import { createOrImportDopWallet, testCircomlibjs } from 'dop-wallet-v6';
448
+ import AsyncStorage from '@react-native-async-storage/async-storage';
449
+ import { NetworkName } from 'dop-sharedmodels-v3';
450
+
451
+ // Test compatibility first (optional but recommended)
452
+ const isCompatible = await testCircomlibjs();
453
+ if (!isCompatible) {
454
+ throw new Error('Cryptography not compatible with this environment');
455
+ }
456
+
457
+ // Create wallet with React Native optimizations
458
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
459
+ timeout: 90000, // Increase timeout for React Native
460
+ mnemonicStrength: 256 // 24 words for maximum security
461
+ });
462
+ ```
463
+
464
+ ### Complete Examples
465
+
466
+ #### Example 1: Create New Wallet (Auto-Generate Mnemonic)
467
+
468
+ ```typescript
469
+ import { createOrImportDopWallet } from 'dop-wallet-v6';
470
+ import AsyncStorage from '@react-native-async-storage/async-storage';
471
+ import { randomBytes } from 'crypto';
472
+ import { NetworkName } from 'dop-sharedmodels-v3';
473
+
474
+ export const createNewWallet = async () => {
475
+ try {
476
+ // Generate encryption key
477
+ const encryptionKey = randomBytes(32);
478
+
479
+ // Optional: Specify creation block numbers for faster initial sync
480
+ const creationBlockNumbers = {
481
+ [NetworkName.Ethereum]: 18000000, // Recent block number
482
+ [NetworkName.Polygon]: 45000000,
483
+ [NetworkName.BNBChain]: 30000000,
484
+ };
485
+
486
+ // Create wallet with auto-generated mnemonic
487
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
488
+ creationBlockNumbers,
489
+ mnemonicStrength: 256, // 24 words for maximum security
490
+ timeout: 90000 // 90 seconds timeout for React Native
491
+ });
492
+
493
+ console.log('✅ New wallet created!');
494
+ console.log('Wallet ID:', walletInfo.id);
495
+ console.log('Address:', walletInfo.dopAddress);
496
+ console.log('Mnemonic (SAVE THIS!):', mnemonic);
497
+
498
+ // Store securely in AsyncStorage
499
+ await AsyncStorage.multiSet([
500
+ ['encryption_key', encryptionKey.toString('hex')],
501
+ ['wallet_mnemonic', mnemonic],
502
+ ['wallet_id', walletInfo.id],
503
+ ['wallet_address', walletInfo.dopAddress]
504
+ ]);
505
+
506
+ return walletInfo;
507
+ } catch (error) {
508
+ console.error('Failed to create wallet:', error);
509
+ throw error;
510
+ }
511
+ };
512
+ ```
513
+
514
+ #### Example 2: Import Existing Wallet
515
+
516
+ ```typescript
517
+ import { createOrImportDopWallet } from 'dop-wallet-v6';
518
+ import AsyncStorage from '@react-native-async-storage/async-storage';
519
+
520
+ export const importWalletFromMnemonic = async (userMnemonic: string) => {
521
+ try {
522
+ // Get stored encryption key or create new one
523
+ let encryptionKey = await AsyncStorage.getItem('encryption_key');
524
+ if (!encryptionKey) {
525
+ encryptionKey = randomBytes(32).toString('hex');
526
+ await AsyncStorage.setItem('encryption_key', encryptionKey);
527
+ }
528
+
529
+ // Import wallet from mnemonic
530
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
531
+ mnemonic: userMnemonic.trim().toLowerCase(),
532
+ timeout: 90000 // Increase timeout for React Native
533
+ });
534
+
535
+ console.log('✅ Wallet imported successfully!');
536
+ console.log('Wallet ID:', walletInfo.id);
537
+ console.log('Address:', walletInfo.dopAddress);
538
+
539
+ // Store wallet info
540
+ await AsyncStorage.multiSet([
541
+ ['wallet_mnemonic', mnemonic],
542
+ ['wallet_id', walletInfo.id],
543
+ ['wallet_address', walletInfo.dopAddress]
544
+ ]);
545
+
546
+ return walletInfo;
547
+ } catch (error) {
548
+ if (error.message.includes('Invalid mnemonic')) {
549
+ throw new Error('Please check your mnemonic phrase and try again');
550
+ }
551
+ throw error;
552
+ }
553
+ };
554
+ ```
555
+
556
+ #### Example 3: Export Wallet Mnemonic
557
+
558
+ ```typescript
559
+ import { getWalletMnemonic } from 'dop-wallet-v6';
560
+ import AsyncStorage from '@react-native-async-storage/async-storage';
561
+
562
+ export const exportWalletMnemonic = async (walletId: string) => {
563
+ try {
564
+ const encryptionKey = await AsyncStorage.getItem('encryption_key');
565
+ if (!encryptionKey) {
566
+ throw new Error('No encryption key found');
567
+ }
568
+
569
+ const mnemonic = await getWalletMnemonic(encryptionKey, walletId);
570
+ return mnemonic;
571
+ } catch (error) {
572
+ console.error('Failed to export mnemonic:', error);
573
+ throw error;
574
+ }
575
+ };
576
+ ```
577
+
578
+ ### Error Handling
579
+
580
+ ```typescript
581
+ try {
582
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
583
+ mnemonic: userInputMnemonic,
584
+ timeout: 90000
585
+ });
586
+
587
+ console.log('Wallet created:', walletInfo.id);
588
+ console.log('Address:', walletInfo.dopAddress);
589
+
590
+ // IMPORTANT: Securely store the mnemonic
591
+ await AsyncStorage.setItem('wallet_mnemonic', mnemonic);
592
+
593
+ } catch (error) {
594
+ if (error.message.includes('Invalid mnemonic')) {
595
+ // Handle invalid mnemonic input
596
+ console.error('The provided mnemonic is invalid');
597
+ } else if (error.message.includes('timed out')) {
598
+ // Handle timeout (usually circomlibjs hanging)
599
+ console.error('Wallet creation timed out, try restarting the app');
600
+ } else if (error.message.includes('Cryptography not compatible')) {
601
+ // Handle circomlibjs compatibility issues
602
+ console.error('Crypto library not compatible, check shims and polyfills');
603
+ } else {
604
+ // Handle other errors
605
+ console.error('Wallet creation failed:', error);
606
+ }
607
+ }
608
+ ```
609
+
610
+ ### Best Practices for React Native
611
+
612
+ 1. **Always test circomlibjs compatibility** before wallet creation:
613
+ ```typescript
614
+ const isCompatible = await testCircomlibjs();
615
+ if (!isCompatible) {
616
+ throw new Error('Cryptography not compatible');
617
+ }
618
+ ```
619
+
620
+ 2. **Use increased timeouts** for React Native (90+ seconds):
621
+ ```typescript
622
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
623
+ timeout: 90000
624
+ });
625
+ ```
626
+
627
+ 3. **Handle timeout errors gracefully** - suggest app restart:
628
+ ```typescript
629
+ if (error.message.includes('timed out')) {
630
+ Alert.alert(
631
+ 'Wallet Creation Timeout',
632
+ 'Please restart the app and try again.',
633
+ [{ text: 'OK' }]
634
+ );
635
+ }
636
+ ```
637
+
638
+ 4. **Use secure storage** for encryption keys and mnemonics:
639
+ ```typescript
640
+ import AsyncStorage from '@react-native-async-storage/async-storage';
641
+
642
+ // Store securely
643
+ await AsyncStorage.multiSet([
644
+ ['encryption_key', encryptionKey.toString('hex')],
645
+ ['wallet_mnemonic', mnemonic]
646
+ ]);
647
+ ```
648
+
649
+ 5. **Validate user input mnemonics** before importing:
650
+ ```typescript
651
+ if (userMnemonic && !Mnemonic.validate(userMnemonic)) {
652
+ throw new Error('Invalid mnemonic phrase');
653
+ }
654
+ ```
655
+
656
+ 6. **Use 24-word mnemonics** for maximum security:
657
+ ```typescript
658
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
659
+ mnemonicStrength: 256 // 24 words
660
+ });
661
+ ```
662
+
663
+ ### Migration from Old API
664
+
665
+ If you're upgrading from older wallet creation methods:
666
+
667
+ ```typescript
668
+ // OLD WAY ❌
669
+ const walletInfo = await createDopWallet(encryptionKey, mnemonic, creationBlockNumbers);
670
+
671
+ // NEW WAY ✅
672
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
673
+ mnemonic: existingMnemonic, // or leave undefined to generate
674
+ creationBlockNumbers,
675
+ timeout: 90000 // Add timeout for React Native
676
+ });
677
+ ```
678
+
679
+ The new API provides the mnemonic in the response, making it easier to handle both wallet creation and mnemonic storage in one step.
680
+
681
+ ## ERC-20 Token Features
682
+
683
+ ### ERC-20 Balances
684
+
685
+ ```typescript
686
+ import {
687
+ refreshBalances,
688
+ getSerializedERC20Balances,
689
+ getSerializedNFTBalances
690
+ } from 'dop-wallet-v6';
691
+ import { NetworkName, NETWORK_CONFIG, Chain } from 'dop-sharedmodels-v3';
692
+
693
+ export const refreshERC20Balances = async (
694
+ walletId: string,
695
+ networkName: NetworkName
696
+ ) => {
697
+ try {
698
+ const network = NETWORK_CONFIG[networkName];
699
+ const chain: Chain = network.chain;
700
+
701
+ // Refresh balances for the wallet
702
+ await refreshBalances(chain, [walletId]);
703
+
704
+ console.log('Balance refresh initiated successfully');
705
+ return true;
706
+ } catch (error) {
707
+ console.error('Failed to refresh balances:', error);
708
+ throw error;
709
+ }
710
+ };
711
+
712
+ export const getERC20Balances = async (tokenBalances: any) => {
713
+ try {
714
+ // Get serialized ERC20 balances from wallet token balances
715
+ const erc20Balances = getSerializedERC20Balances(tokenBalances);
716
+
717
+ return erc20Balances.map(balance => ({
718
+ tokenAddress: balance.tokenAddress,
719
+ amount: balance.amount.toString(),
720
+ symbol: balance.symbol,
721
+ decimals: balance.decimals,
722
+ }));
723
+ } catch (error) {
724
+ console.error('Failed to get ERC20 balances:', error);
725
+ throw error;
726
+ }
727
+ };
728
+ networkName: NetworkName
729
+ ) => {
730
+ try {
731
+ const network = NETWORK_CONFIG[networkName];
732
+ const chain = network.chain;
733
+
734
+ await refreshBalances(chain, [walletId]);
735
+ console.log('Balance refresh initiated');
736
+ } catch (error) {
737
+ console.error('Failed to refresh balances:', error);
738
+ throw error;
739
+ }
740
+ };
741
+ ```
742
+
743
+ ### ERC-20 Syncing
744
+
745
+ ```typescript
746
+ import {
747
+ setOnUTXOMerkletreeScanCallback,
748
+ setOnTXIDMerkletreeScanCallback,
749
+ rescanFullUTXOMerkletreesAndWallets
750
+ } from 'dop-wallet-v6';
751
+ import { MerkletreeScanUpdateEvent } from 'dop-sharedmodels-v3';
752
+
753
+ export const setupSyncCallbacks = () => {
754
+ // Monitor UTXO scan progress
755
+ setOnUTXOMerkletreeScanCallback((scanData: MerkletreeScanUpdateEvent) => {
756
+ console.log('UTXO Scan Progress:', {
757
+ chain: scanData.chain,
758
+ status: scanData.scanStatus,
759
+ progress: scanData.progress,
760
+ });
761
+
762
+ // Update UI with scan progress
763
+ // Example: setScanProgress(scanData.progress);
764
+ });
765
+
766
+ // Monitor TXID scan progress
767
+ setOnTXIDMerkletreeScanCallback((scanData: MerkletreeScanUpdateEvent) => {
768
+ console.log('TXID Scan Progress:', {
769
+ chain: scanData.chain,
770
+ status: scanData.scanStatus,
771
+ progress: scanData.progress,
772
+ });
773
+ });
774
+ };
775
+
776
+ export const performFullSync = async (
777
+ walletId: string,
778
+ networkName: NetworkName
779
+ ) => {
780
+ try {
781
+ const network = NETWORK_CONFIG[networkName];
782
+ const chain = network.chain;
783
+
784
+ await rescanFullUTXOMerkletreesAndWallets(chain, [walletId]);
785
+ console.log('Full sync initiated');
786
+ } catch (error) {
787
+ console.error('Failed to perform full sync:', error);
788
+ throw error;
789
+ }
790
+ };
791
+ ```
792
+
793
+ ### ERC-20 Encrypt, Send, Decrypt
794
+
795
+ ```typescript
796
+ import {
797
+ generateTransferProofInternal,
798
+ populateEncrypt,
799
+ generateDecryptToOriginProof,
800
+ populateProvedTransfer,
801
+ gasEstimateForEncrypt,
802
+ gasEstimateForUnprovenTransfer,
803
+ mnemonicTo0xPKey
804
+ } from 'dop-wallet-v6';
805
+ import {
806
+ NetworkName,
807
+ NETWORK_CONFIG,
808
+ TXIDVersion,
809
+ DopERC20AmountRecipient,
810
+ TransactionGasDetails,
811
+ EVMGasType
812
+ } from 'dop-sharedmodels-v3';
813
+ import { Wallet, JsonRpcProvider } from 'ethers';
814
+
815
+ export const encryptERC20Token = async (
816
+ walletId: string,
817
+ networkName: NetworkName,
818
+ tokenAddress: string,
819
+ amount: string,
820
+ mnemonic: string
821
+ ) => {
822
+ try {
823
+ const network = NETWORK_CONFIG[networkName];
824
+ const txidVersion = TXIDVersion.V2_PoseidonMerkle; // or V3_PoseidonMerkle
825
+
826
+ const erc20AmountRecipients: DopERC20AmountRecipient[] = [
827
+ {
828
+ tokenAddress,
829
+ amount: BigInt(amount),
830
+ recipientAddress: walletId, // Self-encrypt
831
+ }
832
+ ];
833
+
834
+ // Get encrypt private key (simplified - in practice this should be derived securely)
835
+ const encryptPrivateKey = mnemonicTo0xPKey(mnemonic);
836
+
837
+ // Generate encrypt transaction
838
+ const encryptResponse = await populateEncrypt(
839
+ txidVersion,
840
+ networkName,
841
+ encryptPrivateKey,
842
+ erc20AmountRecipients,
843
+ [], // nftAmountRecipients
844
+ undefined // gasDetails - add if needed
845
+ );
846
+
847
+ // Broadcast using ethers (you'll need to implement this based on your provider setup)
848
+ const provider = new JsonRpcProvider(network.rpcUrl);
849
+ const wallet = new Wallet(encryptPrivateKey, provider);
850
+ const txResponse = await wallet.sendTransaction(encryptResponse.transaction);
851
+
852
+ console.log('Encryption transaction:', txResponse.hash);
853
+ return txResponse;
854
+ } catch (error) {
855
+ console.error('Failed to encrypt token:', error);
856
+ throw error;
857
+ }
858
+ };
859
+
860
+ export const sendERC20Token = async (
861
+ walletId: string,
862
+ networkName: NetworkName,
863
+ tokenAddress: string,
864
+ amount: string,
865
+ recipientAddress: string,
866
+ encryptionKey: string,
867
+ mnemonic: string,
868
+ memoText?: string
869
+ ) => {
870
+ try {
871
+ const network = NETWORK_CONFIG[networkName];
872
+ const txidVersion = TXIDVersion.V2_PoseidonMerkle; // or V3_PoseidonMerkle
873
+
874
+ const erc20AmountRecipients: DopERC20AmountRecipient[] = [
875
+ {
876
+ tokenAddress,
877
+ amount: BigInt(amount),
878
+ recipientAddress,
879
+ }
880
+ ];
881
+
882
+ // First generate the proof
883
+ await generateTransferProofInternal(
884
+ txidVersion,
885
+ networkName,
886
+ walletId,
887
+ encryptionKey,
888
+ false, // showSenderAddressToRecipient
889
+ memoText,
890
+ erc20AmountRecipients,
891
+ [], // nftAmountRecipients
892
+ undefined, // broadcasterFeeERC20AmountRecipient
893
+ true, // sendWithPublicWallet
894
+ undefined, // overallBatchMinGasPrice
895
+ (progress) => console.log('Proof generation progress:', progress)
896
+ );
897
+
898
+ // Get gas details
899
+ const gasDetails: TransactionGasDetails = {
900
+ evmGasType: EVMGasType.Type2,
901
+ gasEstimate: 200000n,
902
+ gasPrice: 20000000000n, // 20 gwei
903
+ maxFeePerGas: 30000000000n, // 30 gwei
904
+ maxPriorityFeePerGas: 2000000000n, // 2 gwei
905
+ };
906
+
907
+ // Populate the proved transaction
908
+ const populateResponse = await populateProvedTransfer(
909
+ txidVersion,
910
+ networkName,
911
+ walletId,
912
+ false, // showSenderAddressToRecipient
913
+ memoText,
914
+ erc20AmountRecipients,
915
+ [], // nftAmountRecipients
916
+ undefined, // broadcasterFeeERC20AmountRecipient
917
+ true, // sendWithPublicWallet
918
+ undefined, // overallBatchMinGasPrice
919
+ gasDetails
920
+ );
921
+
922
+ // Broadcast using ethers
923
+ const privateKey = mnemonicTo0xPKey(mnemonic);
924
+ const provider = new JsonRpcProvider(network.rpcUrl);
925
+ const wallet = new Wallet(privateKey, provider);
926
+ const txResponse = await wallet.sendTransaction(populateResponse.transaction);
927
+
928
+ console.log('Transfer transaction:', txResponse.hash);
929
+ return txResponse;
930
+ } catch (error) {
931
+ console.error('Failed to send token:', error);
932
+ throw error;
933
+ }
934
+ };
935
+
936
+ export const decryptERC20Token = async (
937
+ walletId: string,
938
+ networkName: NetworkName,
939
+ originalEncryptTxid: string,
940
+ encryptionKey: string,
941
+ mnemonic: string,
942
+ tokenAddress: string,
943
+ amount: string
944
+ ) => {
945
+ try {
946
+ const network = NETWORK_CONFIG[networkName];
947
+ const txidVersion = TXIDVersion.V2_PoseidonMerkle;
948
+
949
+ const erc20AmountRecipients: DopERC20AmountRecipient[] = [
950
+ {
951
+ tokenAddress,
952
+ amount: BigInt(amount),
953
+ recipientAddress: walletId, // Decrypt to self
954
+ }
955
+ ];
956
+
957
+ // Generate decrypt proof
958
+ await generateDecryptToOriginProof(
959
+ originalEncryptTxid,
960
+ txidVersion,
961
+ networkName,
962
+ walletId,
963
+ encryptionKey,
964
+ erc20AmountRecipients,
965
+ [], // nftAmountRecipients
966
+ (progress) => console.log('Decrypt proof generation progress:', progress),
967
+ BigInt(amount)
968
+ );
969
+
970
+ // Note: You'll need to implement the transaction broadcasting part
971
+ // similar to the above examples using ethers and the cached proved transaction
972
+
973
+ console.log('Decrypt proof generated successfully');
974
+ return { success: true };
975
+ } catch (error) {
976
+ console.error('Failed to decrypt token:', error);
977
+ throw error;
978
+ }
979
+ };
980
+ ```
981
+
982
+ ### ERC-20 Transaction History
983
+
984
+ ```typescript
985
+ import { getWalletTransactionHistory } from 'dop-wallet-v6';
986
+ import {
987
+ TransactionHistoryItem,
988
+ TransactionHistoryItemCategory,
989
+ NetworkName,
990
+ NETWORK_CONFIG,
991
+ Chain
992
+ } from 'dop-sharedmodels-v3';
993
+
994
+ export const getERC20TransactionHistory = async (
995
+ walletId: string,
996
+ networkName: NetworkName,
997
+ startIndex = 0
998
+ ) => {
999
+ try {
1000
+ const network = NETWORK_CONFIG[networkName];
1001
+ const chain: Chain = network.chain;
1002
+
1003
+ const history = await getWalletTransactionHistory(
1004
+ chain,
1005
+ walletId,
1006
+ startIndex
1007
+ );
1008
+
1009
+ return history;
1010
+ const chain = network.chain;
1011
+
1012
+ const history = await getTransactionHistory(
1013
+ walletId,
1014
+ chain,
1015
+ startIndex,
1016
+ maxCount
1017
+ );
1018
+
1019
+ // Filter for ERC20 transactions
1020
+ const erc20History = history.filter(item =>
1021
+ item.category === TransactionHistoryItemCategory.TransferERC20Send ||
1022
+ item.category === TransactionHistoryItemCategory.TransferERC20Receive ||
1023
+ item.category === TransactionHistoryItemCategory.EncryptERC20 ||
1024
+ item.category === TransactionHistoryItemCategory.DecryptERC20
1025
+ );
1026
+
1027
+ return erc20History.map(item => ({
1028
+ id: item.id,
1029
+ timestamp: item.timestamp,
1030
+ category: item.category,
1031
+ txHash: item.txHash,
1032
+ blockNumber: item.blockNumber,
1033
+ tokenAddress: item.tokenAddress,
1034
+ amount: item.amount,
1035
+ recipientAddress: item.recipientAddress,
1036
+ senderAddress: item.senderAddress,
1037
+ memoText: item.memoText,
1038
+ status: item.status,
1039
+ }));
1040
+ } catch (error) {
1041
+ console.error('Failed to get transaction history:', error);
1042
+ throw error;
1043
+ }
1044
+ };
1045
+ ```
1046
+
1047
+ ### ERC-20 Selective Transparency
1048
+
1049
+ ```typescript
1050
+ import {
1051
+ getDopWalletPrivateViewingKey,
1052
+ getWalletShareableViewingKey,
1053
+ createViewOnlyDopWallet,
1054
+ signWithWalletViewingKey
1055
+ } from 'dop-wallet-v6';
1056
+
1057
+ export const generateViewingKey = async (walletId: string) => {
1058
+ try {
1059
+ const shareableViewingKey = await getWalletShareableViewingKey(walletId);
1060
+ return shareableViewingKey;
1061
+ } catch (error) {
1062
+ console.error('Failed to generate viewing key:', error);
1063
+ throw error;
1064
+ }
1065
+ };
1066
+
1067
+ export const createViewOnlyWallet = async (
1068
+ encryptionKey: string,
1069
+ shareableViewingKey: string
1070
+ ) => {
1071
+ try {
1072
+ const walletInfo = await createViewOnlyDopWallet(
1073
+ encryptionKey,
1074
+ shareableViewingKey,
1075
+ undefined
1076
+ );
1077
+
1078
+ console.log('View-only wallet created:', walletInfo);
1079
+ return walletInfo;
1080
+ } catch (error) {
1081
+ console.error('Failed to create view-only wallet:', error);
1082
+ throw error;
1083
+ }
1084
+ };
1085
+
1086
+ export const verifyTransactionProof = async (
1087
+ walletId: string,
1088
+ message: string
1089
+ ) => {
1090
+ try {
1091
+ const signature = await signWithWalletViewingKey(walletId, message);
1092
+ return signature;
1093
+ } catch (error) {
1094
+ console.error('Failed to verify proof:', error);
1095
+ throw error;
1096
+ }
1097
+ };
1098
+ ```
1099
+
1100
+ ## ERC-721 NFT Features
1101
+
1102
+ ### ERC-721 Balances
1103
+
1104
+ ```typescript
1105
+ export const getERC721Balances = async (tokenBalances: any) => {
1106
+ try {
1107
+ // Get serialized NFT balances from wallet token balances
1108
+ const nftBalances = getSerializedNFTBalances(tokenBalances);
1109
+
1110
+ return nftBalances.map(balance => ({
1111
+ contractAddress: balance.nftAddress,
1112
+ tokenId: balance.tokenSubID,
1113
+ tokenURI: balance.tokenURI,
1114
+ }));
1115
+ } catch (error) {
1116
+ console.error('Failed to get NFT balances:', error);
1117
+ throw error;
1118
+ }
1119
+ };
1120
+ amount: balance.amount.toString(),
1121
+ nftTokenType: balance.nftTokenType,
1122
+ }));
1123
+ } catch (error) {
1124
+ console.error('Failed to get NFT balances:', error);
1125
+ throw error;
1126
+ }
1127
+ };
1128
+ ```
1129
+
1130
+ ### ERC-721 Syncing
1131
+
1132
+ ```typescript
1133
+ export const refreshNFTBalances = async (
1134
+ walletId: string,
1135
+ networkName: NetworkName
1136
+ ) => {
1137
+ try {
1138
+ const network = NETWORK_CONFIG[networkName];
1139
+ const chain = network.chain;
1140
+
1141
+ await refreshBalances(chain, [walletId]);
1142
+ console.log('NFT balance refresh initiated');
1143
+ } catch (error) {
1144
+ console.error('Failed to refresh NFT balances:', error);
1145
+ throw error;
1146
+ }
1147
+ };
1148
+ ```
1149
+
1150
+ ### ERC-721 Encrypt, Send, Decrypt
1151
+
1152
+ ```typescript
1153
+ export const encryptNFT = async (
1154
+ walletId: string,
1155
+ networkName: NetworkName,
1156
+ contractAddress: string,
1157
+ tokenId: string
1158
+ ) => {
1159
+ try {
1160
+ const network = NETWORK_CONFIG[networkName];
1161
+
1162
+ const encryptTxRequest = {
1163
+ walletId,
1164
+ tokenAddress: contractAddress,
1165
+ tokenId,
1166
+ recipientAddress: null, // Self-encrypt
1167
+ };
1168
+
1169
+ const proof = await generateEncryptProof(
1170
+ network.chain,
1171
+ encryptTxRequest
1172
+ );
1173
+
1174
+ const txResponse = await broadcastTransaction(
1175
+ network.chain,
1176
+ proof.transaction
1177
+ );
1178
+
1179
+ console.log('NFT encryption transaction:', txResponse.hash);
1180
+ return txResponse;
1181
+ } catch (error) {
1182
+ console.error('Failed to encrypt NFT:', error);
1183
+ throw error;
1184
+ }
1185
+ };
1186
+
1187
+ export const sendNFT = async (
1188
+ walletId: string,
1189
+ networkName: NetworkName,
1190
+ contractAddress: string,
1191
+ tokenId: string,
1192
+ recipientAddress: string,
1193
+ memoText?: string
1194
+ ) => {
1195
+ try {
1196
+ const network = NETWORK_CONFIG[networkName];
1197
+
1198
+ const transferTxRequest = {
1199
+ walletId,
1200
+ tokenAddress: contractAddress,
1201
+ tokenId,
1202
+ recipientAddress,
1203
+ memoText,
1204
+ };
1205
+
1206
+ const proof = await generateTransferProof(
1207
+ network.chain,
1208
+ transferTxRequest
1209
+ );
1210
+
1211
+ const txResponse = await broadcastTransaction(
1212
+ network.chain,
1213
+ proof.transaction
1214
+ );
1215
+
1216
+ console.log('NFT transfer transaction:', txResponse.hash);
1217
+ return txResponse;
1218
+ } catch (error) {
1219
+ console.error('Failed to send NFT:', error);
1220
+ throw error;
1221
+ }
1222
+ };
1223
+ ```
1224
+
1225
+ ### ERC-721 Transaction History
1226
+
1227
+ ```typescript
1228
+ export const getNFTTransactionHistory = async (
1229
+ walletId: string,
1230
+ networkName: NetworkName,
1231
+ startIndex = 0,
1232
+ maxCount = 50
1233
+ ) => {
1234
+ try {
1235
+ const network = NETWORK_CONFIG[networkName];
1236
+ const chain = network.chain;
1237
+
1238
+ const history = await getTransactionHistory(
1239
+ walletId,
1240
+ chain,
1241
+ startIndex,
1242
+ maxCount
1243
+ );
1244
+
1245
+ // Filter for NFT transactions
1246
+ const nftHistory = history.filter(item =>
1247
+ item.category === TransactionHistoryItemCategory.TransferNFTSend ||
1248
+ item.category === TransactionHistoryItemCategory.TransferNFTReceive ||
1249
+ item.category === TransactionHistoryItemCategory.EncryptNFT ||
1250
+ item.category === TransactionHistoryItemCategory.DecryptNFT
1251
+ );
1252
+
1253
+ return nftHistory.map(item => ({
1254
+ id: item.id,
1255
+ timestamp: item.timestamp,
1256
+ category: item.category,
1257
+ txHash: item.txHash,
1258
+ blockNumber: item.blockNumber,
1259
+ contractAddress: item.tokenAddress,
1260
+ tokenId: item.tokenId,
1261
+ recipientAddress: item.recipientAddress,
1262
+ senderAddress: item.senderAddress,
1263
+ memoText: item.memoText,
1264
+ status: item.status,
1265
+ }));
1266
+ } catch (error) {
1267
+ console.error('Failed to get NFT transaction history:', error);
1268
+ throw error;
1269
+ }
1270
+ };
1271
+ ```
1272
+
1273
+ ### ERC-721 Selective Transparency
1274
+
1275
+ NFT selective transparency works the same way as ERC-20 tokens, using the same viewing key mechanisms described in the ERC-20 section.
1276
+
1277
+ ## Advanced Features
1278
+
1279
+ ### Transaction History with Wallet Visibility
1280
+
1281
+ ```typescript
1282
+ export const getAllTransactionHistory = async (
1283
+ walletId: string,
1284
+ networkName: NetworkName,
1285
+ includeVisible = false,
1286
+ startIndex = 0,
1287
+ maxCount = 100
1288
+ ) => {
1289
+ try {
1290
+ const network = NETWORK_CONFIG[networkName];
1291
+ const chain = network.chain;
1292
+
1293
+ const history = await getTransactionHistory(
1294
+ walletId,
1295
+ chain,
1296
+ startIndex,
1297
+ maxCount
1298
+ );
1299
+
1300
+ // Option to filter visible transactions
1301
+ const filteredHistory = includeVisible
1302
+ ? history
1303
+ : history.filter(item => !item.isVisible);
1304
+
1305
+ return filteredHistory.map(item => ({
1306
+ id: item.id,
1307
+ timestamp: item.timestamp,
1308
+ category: item.category,
1309
+ txHash: item.txHash,
1310
+ blockNumber: item.blockNumber,
1311
+ tokenType: item.tokenType,
1312
+ tokenAddress: item.tokenAddress,
1313
+ tokenId: item.tokenId,
1314
+ amount: item.amount,
1315
+ recipientAddress: item.recipientAddress,
1316
+ senderAddress: item.senderAddress,
1317
+ memoText: item.memoText,
1318
+ status: item.status,
1319
+ isVisible: item.isVisible,
1320
+ gasFee: item.gasFee,
1321
+ }));
1322
+ } catch (error) {
1323
+ console.error('Failed to get transaction history:', error);
1324
+ throw error;
1325
+ }
1326
+ };
1327
+
1328
+ export const makeWalletVisible = async (
1329
+ walletId: string,
1330
+ networkName: NetworkName
1331
+ ) => {
1332
+ try {
1333
+ // Implementation depends on specific visibility requirements
1334
+ // This might involve generating proofs or updating wallet settings
1335
+ console.log('Making wallet visible for network:', networkName);
1336
+
1337
+ // Add specific implementation based on DOP requirements
1338
+ } catch (error) {
1339
+ console.error('Failed to make wallet visible:', error);
1340
+ throw error;
1341
+ }
1342
+ };
1343
+ ```
1344
+
1345
+ ## Complete Example
1346
+
1347
+ Here's a complete setup showing the proper import order and React Native component:
1348
+
1349
+ ### App.js (Entry Point)
1350
+
1351
+ ```typescript
1352
+ // CRITICAL: Import polyfills FIRST, in this exact order
1353
+ import 'react-native-get-random-values';
1354
+ import 'react-native-url-polyfill/auto';
1355
+ import { Buffer } from 'buffer';
1356
+
1357
+ // Make Buffer available globally
1358
+ global.Buffer = global.Buffer || Buffer;
1359
+
1360
+ // Import DOP Wallet shims
1361
+ import 'dop-wallet-v6/react-native-shims';
1362
+
1363
+ // Now safe to import React and other modules
1364
+ import React from 'react';
1365
+ import { AppRegistry } from 'react-native';
1366
+ import DopWalletExample from './DopWalletExample';
1367
+
1368
+ const App = () => {
1369
+ return <DopWalletExample />;
1370
+ };
1371
+
1372
+ AppRegistry.registerComponent('YourAppName', () => App);
1373
+ ```
1374
+
1375
+ ### DopWalletExample.js (Main Component)
1376
+
1377
+ ```typescript
1378
+ import React, { useState, useEffect } from 'react';
1379
+ import { View, Text, Button, Alert, StyleSheet } from 'react-native';
1380
+ import { NetworkName } from 'dop-sharedmodels-v3';
1381
+ import {
1382
+ initializeDopEngine,
1383
+ createNewWallet,
1384
+ getERC20Balances,
1385
+ sendERC20Token,
1386
+ setupSyncCallbacks,
1387
+ getAllTransactionHistory
1388
+ } from './dopWalletService'; // Your service file
1389
+
1390
+ const DopWalletExample = () => {
1391
+ const [walletId, setWalletId] = useState<string | null>(null);
1392
+ const [balances, setBalances] = useState<any[]>([]);
1393
+ const [isLoading, setIsLoading] = useState(false);
1394
+ const [syncProgress, setSyncProgress] = useState(0);
1395
+
1396
+ useEffect(() => {
1397
+ initializeWallet();
1398
+ setupSyncCallbacks();
1399
+ }, []);
1400
+
1401
+ const initializeWallet = async () => {
1402
+ try {
1403
+ setIsLoading(true);
1404
+
1405
+ // Initialize DOP Engine
1406
+ await initializeDopEngine();
1407
+
1408
+ // Create or load wallet
1409
+ const encryptionKey = 'your-secure-encryption-key';
1410
+ const wallet = await createNewWallet(encryptionKey);
1411
+ setWalletId(wallet.id);
1412
+
1413
+ console.log('Wallet initialized:', wallet.dopAddress);
1414
+ } catch (error) {
1415
+ Alert.alert('Error', 'Failed to initialize wallet');
1416
+ console.error(error);
1417
+ } finally {
1418
+ setIsLoading(false);
1419
+ }
1420
+ };
1421
+
1422
+ const loadBalances = async () => {
1423
+ if (!walletId) return;
1424
+
1425
+ try {
1426
+ setIsLoading(true);
1427
+ const erc20Balances = await getERC20Balances(walletId, NetworkName.Ethereum);
1428
+ setBalances(erc20Balances);
1429
+ } catch (error) {
1430
+ Alert.alert('Error', 'Failed to load balances');
1431
+ console.error(error);
1432
+ } finally {
1433
+ setIsLoading(false);
1434
+ }
1435
+ };
1436
+
1437
+ const handleSendToken = async () => {
1438
+ if (!walletId) return;
1439
+
1440
+ try {
1441
+ setIsLoading(true);
1442
+
1443
+ const result = await sendERC20Token(
1444
+ walletId,
1445
+ NetworkName.Ethereum,
1446
+ '0x...', // Token contract address
1447
+ '1000000000000000000', // 1 token (18 decimals)
1448
+ '0x...', // Recipient address
1449
+ 'Hello from DOP!'
1450
+ );
1451
+
1452
+ Alert.alert('Success', `Transaction sent: ${result.hash}`);
1453
+ } catch (error) {
1454
+ Alert.alert('Error', 'Failed to send token');
1455
+ console.error(error);
1456
+ } finally {
1457
+ setIsLoading(false);
1458
+ }
1459
+ };
1460
+
1461
+ return (
1462
+ <View style={styles.container}>
1463
+ <Text style={styles.title}>DOP Wallet Integration</Text>
1464
+
1465
+ {walletId && (
1466
+ <Text style={styles.walletId}>Wallet ID: {walletId}</Text>
1467
+ )}
1468
+
1469
+ {syncProgress > 0 && (
1470
+ <Text style={styles.progress}>
1471
+ Sync Progress: {(syncProgress * 100).toFixed(1)}%
1472
+ </Text>
1473
+ )}
1474
+
1475
+ <Button
1476
+ title="Load Balances"
1477
+ onPress={loadBalances}
1478
+ disabled={isLoading || !walletId}
1479
+ />
1480
+
1481
+ <Button
1482
+ title="Send Token"
1483
+ onPress={handleSendToken}
1484
+ disabled={isLoading || !walletId}
1485
+ />
1486
+
1487
+ {balances.length > 0 && (
1488
+ <View style={styles.balanceContainer}>
1489
+ <Text style={styles.balanceTitle}>Balances:</Text>
1490
+ {balances.map((balance, index) => (
1491
+ <Text key={index} style={styles.balanceItem}>
1492
+ {balance.tokenAddress}: {balance.spendable}
1493
+ </Text>
1494
+ ))}
1495
+ </View>
1496
+ )}
1497
+ </View>
1498
+ );
1499
+ };
1500
+
1501
+ const styles = StyleSheet.create({
1502
+ container: {
1503
+ flex: 1,
1504
+ padding: 20,
1505
+ justifyContent: 'center',
1506
+ },
1507
+ title: {
1508
+ fontSize: 24,
1509
+ fontWeight: 'bold',
1510
+ marginBottom: 20,
1511
+ textAlign: 'center',
1512
+ },
1513
+ walletId: {
1514
+ fontSize: 12,
1515
+ marginBottom: 10,
1516
+ textAlign: 'center',
1517
+ },
1518
+ progress: {
1519
+ fontSize: 14,
1520
+ marginBottom: 10,
1521
+ textAlign: 'center',
1522
+ },
1523
+ balanceContainer: {
1524
+ marginTop: 20,
1525
+ },
1526
+ balanceTitle: {
1527
+ fontSize: 18,
1528
+ fontWeight: 'bold',
1529
+ marginBottom: 10,
1530
+ },
1531
+ balanceItem: {
1532
+ fontSize: 14,
1533
+ marginBottom: 5,
1534
+ },
1535
+ });
1536
+
1537
+ export default DopWalletExample;
1538
+ ```
1539
+
1540
+ ## Testing
1541
+
1542
+ ### Unit Testing
1543
+
1544
+ Create test files to validate each integration step:
1545
+
1546
+ ```typescript
1547
+ // __tests__/dopWallet.test.ts
1548
+ import { initializeDopEngine, createNewWallet } from '../dopWalletService';
1549
+
1550
+ describe('DOP Wallet Integration', () => {
1551
+ beforeAll(async () => {
1552
+ await initializeDopEngine();
1553
+ });
1554
+
1555
+ test('should create a new wallet', async () => {
1556
+ const encryptionKey = 'test-encryption-key';
1557
+ const wallet = await createNewWallet(encryptionKey);
1558
+
1559
+ expect(wallet.id).toBeDefined();
1560
+ expect(wallet.dopAddress).toBeDefined();
1561
+ });
1562
+
1563
+ test('should load balances', async () => {
1564
+ // Add balance loading tests
1565
+ });
1566
+
1567
+ test('should handle transactions', async () => {
1568
+ // Add transaction tests
1569
+ });
1570
+ });
1571
+ ```
1572
+
1573
+ ### Integration Testing
1574
+
1575
+ 1. Test wallet creation and import
1576
+ 2. Verify balance loading and syncing
1577
+ 3. Test ERC-20 token operations
1578
+ 4. Test ERC-721 NFT operations
1579
+ 5. Verify transaction history
1580
+ 6. Test selective transparency features
1581
+
1582
+ ## Troubleshooting
1583
+
1584
+ ### Wallet Creation Issues
1585
+
1586
+ #### ⚠️ **MOST COMMON ISSUE**: Wallet Creation Hangs Indefinitely
1587
+
1588
+ **Problem**: `createDopWallet()` hangs without errors, never completes in React Native.
1589
+
1590
+ **Root Cause**: `circomlibjs` (cryptographic library) hangs when trying to use Web Workers or WebAssembly in React Native.
1591
+
1592
+ **✅ SOLUTION**: Use the new safe wallet creation functions:
1593
+
1594
+ ```typescript
1595
+ import { testCircomlibjs, createOrImportDopWallet } from 'dop-wallet-v6';
1596
+
1597
+ export const createNewWalletSafely = async (encryptionKey: string) => {
1598
+ try {
1599
+ // First test if circomlibjs is working
1600
+ const isCompatible = await testCircomlibjs();
1601
+ if (!isCompatible) {
1602
+ throw new Error('Cryptography not compatible with this environment');
1603
+ }
1604
+ console.log('✅ CircomLibJS test passed');
1605
+
1606
+ // Use the comprehensive creation method with timeout
1607
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
1608
+ timeout: 90000, // 90 second timeout for React Native
1609
+ mnemonicStrength: 256 // 24 words for maximum security
1610
+ });
1611
+
1612
+ console.log('✅ Wallet created successfully');
1613
+ console.log('Generated mnemonic:', mnemonic);
1614
+ return { walletInfo, mnemonic };
1615
+ } catch (error) {
1616
+ console.error('❌ Safe wallet creation failed:', error);
1617
+
1618
+ if (error.message.includes('timed out')) {
1619
+ throw new Error('Wallet creation timed out. This indicates circomlibjs compatibility issues. Please restart the app and try again.');
1620
+ }
1621
+
1622
+ throw error;
1623
+ }
1624
+ };
1625
+ ```
1626
+
1627
+ #### "Invalid mnemonic phrase" Errors
1628
+
1629
+ **Problem**: Getting "Invalid mnemonic phrase provided" when importing wallet.
1630
+
1631
+ **Solutions**:
1632
+ 1. **Check word count**: Ensure mnemonic has exactly 12, 18, or 24 words
1633
+ 2. **Remove extra spaces**: Trim and normalize the mnemonic
1634
+ 3. **Verify BIP39 wordlist**: Check if all words are valid BIP39 words
1635
+
1636
+ ```typescript
1637
+ import { createOrImportDopWallet } from 'dop-wallet-v6';
1638
+
1639
+ const importWalletSafely = async (userMnemonic: string, encryptionKey: string) => {
1640
+ try {
1641
+ // Clean and validate the mnemonic
1642
+ const cleanMnemonic = userMnemonic.trim().toLowerCase();
1643
+ const words = cleanMnemonic.split(/\s+/);
1644
+
1645
+ if (![12, 18, 24].includes(words.length)) {
1646
+ throw new Error(`Invalid mnemonic: expected 12, 18, or 24 words, got ${words.length}`);
1647
+ }
1648
+
1649
+ // Import with validation
1650
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
1651
+ mnemonic: cleanMnemonic,
1652
+ timeout: 90000
1653
+ });
1654
+
1655
+ return { walletInfo, mnemonic };
1656
+ } catch (error) {
1657
+ if (error.message.includes('Invalid mnemonic')) {
1658
+ throw new Error('Please check your mnemonic phrase. Ensure it has 12, 18, or 24 valid words with no typos.');
1659
+ }
1660
+ throw error;
1661
+ }
1662
+ };
1663
+ ```
1664
+
1665
+ #### "Wallet creation timed out" Errors
1666
+
1667
+ **Problem**: Wallet creation times out after 60-90 seconds.
1668
+
1669
+ **Causes & Solutions**:
1670
+
1671
+ 1. **CircomLibJS hanging** (most common):
1672
+ ```typescript
1673
+ // Solution: Test circomlibjs first
1674
+ const isCompatible = await testCircomlibjs();
1675
+ if (!isCompatible) {
1676
+ // Restart the app and try again
1677
+ Alert.alert('Compatibility Issue', 'Please restart the app and try again.');
1678
+ return;
1679
+ }
1680
+ ```
1681
+
1682
+ 2. **Insufficient timeout for React Native**:
1683
+ ```typescript
1684
+ // Solution: Increase timeout
1685
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
1686
+ timeout: 120000 // 2 minutes for slower devices
1687
+ });
1688
+ ```
1689
+
1690
+ 3. **Missing shims or polyfills**:
1691
+ ```typescript
1692
+ // Solution: Ensure proper import order in App.js/index.js
1693
+ import 'react-native-get-random-values';
1694
+ import 'react-native-url-polyfill/auto';
1695
+ import { Buffer } from 'buffer';
1696
+ global.Buffer = global.Buffer || Buffer;
1697
+ import 'dop-wallet-v6/react-native-shims'; // Critical!
1698
+ ```
1699
+
1700
+ #### "Cryptography not compatible" Errors
1701
+
1702
+ **Problem**: `testCircomlibjs()` returns false or throws an error.
1703
+
1704
+ **Solutions**:
1705
+
1706
+ 1. **Check shim loading**:
1707
+ ```typescript
1708
+ // Ensure react-native-shims.js is imported BEFORE any wallet operations
1709
+ import 'dop-wallet-v6/react-native-shims';
1710
+ import { testCircomlibjs } from 'dop-wallet-v6';
1711
+ ```
1712
+
1713
+ 2. **Verify Metro configuration**:
1714
+ ```javascript
1715
+ // metro.config.js
1716
+ config.resolver.alias = {
1717
+ 'crypto': require.resolve('crypto-browserify'),
1718
+ 'stream': require.resolve('stream-browserify'),
1719
+ // ... other aliases
1720
+ };
1721
+ ```
1722
+
1723
+ 3. **Force restart Metro**:
1724
+ ```bash
1725
+ npx react-native start --reset-cache
1726
+ ```
1727
+
1728
+ #### "Cannot read property 'call' of undefined" Errors
1729
+
1730
+ **Problem**: Getting undefined property errors during wallet operations.
1731
+
1732
+ **Root Cause**: Missing or incorrectly loaded polyfills.
1733
+
1734
+ **Solution**: Ensure correct polyfill order:
1735
+
1736
+ ```typescript
1737
+ // At the very top of App.js or index.js (FIRST imports)
1738
+ import 'react-native-get-random-values';
1739
+ import 'react-native-url-polyfill/auto';
1740
+ import { Buffer } from 'buffer';
1741
+
1742
+ // Make Buffer global
1743
+ global.Buffer = global.Buffer || Buffer;
1744
+
1745
+ // Load DOP Wallet shims
1746
+ import 'dop-wallet-v6/react-native-shims';
1747
+
1748
+ // Then your app imports
1749
+ import React from 'react';
1750
+ import { AppRegistry } from 'react-native';
1751
+ // ... rest of app
1752
+ ```
1753
+
1754
+ #### Performance Issues (Slow Wallet Creation)
1755
+
1756
+ **Problem**: Wallet creation takes 30+ seconds but eventually succeeds.
1757
+
1758
+ **Solutions**:
1759
+
1760
+ 1. **Use creation block numbers** for faster sync:
1761
+ ```typescript
1762
+ import { NetworkName } from 'dop-sharedmodels-v3';
1763
+
1764
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
1765
+ creationBlockNumbers: {
1766
+ [NetworkName.Ethereum]: 18500000, // Recent block
1767
+ [NetworkName.Polygon]: 50000000,
1768
+ [NetworkName.BNBChain]: 35000000,
1769
+ }
1770
+ });
1771
+ ```
1772
+
1773
+ 2. **Show loading UI** with progress indication:
1774
+ ```typescript
1775
+ const [creationProgress, setCreationProgress] = useState('Initializing...');
1776
+
1777
+ const createWallet = async () => {
1778
+ try {
1779
+ setCreationProgress('Testing cryptography...');
1780
+ await testCircomlibjs();
1781
+
1782
+ setCreationProgress('Creating wallet...');
1783
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
1784
+ timeout: 120000
1785
+ });
1786
+
1787
+ setCreationProgress('Wallet created successfully!');
1788
+ return { walletInfo, mnemonic };
1789
+ } catch (error) {
1790
+ setCreationProgress('Creation failed');
1791
+ throw error;
1792
+ }
1793
+ };
1794
+ ```
1795
+
1796
+ #### Debug Mode for Wallet Creation
1797
+
1798
+ When troubleshooting wallet creation issues, use this debug approach:
1799
+
1800
+ ```typescript
1801
+ import { testCircomlibjs, createOrImportDopWallet } from 'dop-wallet-v6';
1802
+
1803
+ const debugWalletCreation = async (encryptionKey: string) => {
1804
+ console.log('🔍 Starting wallet creation debug...');
1805
+
1806
+ try {
1807
+ // Step 1: Test environment
1808
+ console.log('Step 1: Testing React Native environment...');
1809
+ console.log('- Buffer available:', typeof Buffer !== 'undefined');
1810
+ console.log('- Crypto available:', typeof crypto !== 'undefined');
1811
+ console.log('- TextEncoder available:', typeof TextEncoder !== 'undefined');
1812
+
1813
+ // Step 2: Test circomlibjs
1814
+ console.log('Step 2: Testing circomlibjs...');
1815
+ const startTime = Date.now();
1816
+ const isCompatible = await testCircomlibjs();
1817
+ const testDuration = Date.now() - startTime;
1818
+ console.log(`- CircomLibJS test: ${isCompatible ? '✅ PASS' : '❌ FAIL'} (${testDuration}ms)`);
1819
+
1820
+ if (!isCompatible) {
1821
+ throw new Error('CircomLibJS compatibility test failed');
1822
+ }
1823
+
1824
+ // Step 3: Create wallet with debug logging
1825
+ console.log('Step 3: Creating wallet...');
1826
+ const creationStart = Date.now();
1827
+
1828
+ const { walletInfo, mnemonic } = await createOrImportDopWallet(encryptionKey, {
1829
+ timeout: 120000, // 2 minute timeout
1830
+ mnemonicStrength: 128 // Start with 12 words for faster creation
1831
+ });
1832
+
1833
+ const creationDuration = Date.now() - creationStart;
1834
+ console.log(`✅ Wallet created successfully in ${creationDuration}ms`);
1835
+ console.log('- Wallet ID:', walletInfo.id);
1836
+ console.log('- Address:', walletInfo.dopAddress);
1837
+ console.log('- Mnemonic words:', mnemonic.split(' ').length);
1838
+
1839
+ return { walletInfo, mnemonic };
1840
+
1841
+ } catch (error) {
1842
+ console.error('❌ Debug wallet creation failed:', error);
1843
+ console.error('Error details:', {
1844
+ message: error.message,
1845
+ stack: error.stack
1846
+ });
1847
+ throw error;
1848
+ }
1849
+ };
1850
+ ```
1851
+
1852
+ ### General React Native Issues
1853
+
1854
+ #### Missing Dependencies
1855
+
1856
+ **Error**: `Module not found` or `Cannot resolve module`
1857
+
1858
+ **Solution**: Install all required dependencies:
1859
+ ```bash
1860
+ npm install dop-wallet-v6 @react-native-async-storage/async-storage react-native-get-random-values react-native-url-polyfill buffer util stream-browserify crypto-browserify
1861
+ ```
1862
+
1863
+ #### Metro Bundle Issues
1864
+
1865
+ **Error**: Bundle transformation errors or module resolution failures
1866
+
1867
+ **Solution**: Update Metro configuration and clear cache:
1868
+ ```bash
1869
+ # Clear Metro cache
1870
+ npx react-native start --reset-cache
1871
+
1872
+ # Clean project
1873
+ cd ios && xcodebuild clean && cd ..
1874
+ cd android && ./gradlew clean && cd ..
1875
+ ```
1876
+
1877
+ #### iOS Build Issues
1878
+
1879
+ **Error**: Build failures on iOS
1880
+
1881
+ **Solution**:
1882
+ 1. Install pods: `cd ios && pod install && cd ..`
1883
+ 2. Clean build folder in Xcode
1884
+ 3. Ensure iOS deployment target is 11.0+
1885
+
1886
+ #### Android Build Issues
1887
+
1888
+ **Error**: Build failures on Android
1889
+
1890
+ **Solution**:
1891
+ 1. Ensure `minSdkVersion` is 21+
1892
+ 2. Enable Hermes if disabled
1893
+ 3. Add proguard rules if using release builds
1894
+
1895
+ ```typescript
1896
+ import { testCircomlibjs } from 'dop-wallet-v6';
1897
+
1898
+ // Test circomlibjs in isolation first
1899
+ export const debugCircomlibjs = async () => {
1900
+ try {
1901
+ console.log('🔍 Testing circomlibjs components...');
1902
+
1903
+ // Test individual operations with timeout
1904
+ const timeoutPromise = new Promise((_, reject) =>
1905
+ setTimeout(() => reject(new Error('Operation timed out')), 30000)
1906
+ );
1907
+
1908
+ await Promise.race([
1909
+ testCircomlibjs(),
1910
+ timeoutPromise
1911
+ ]);
1912
+
1913
+ console.log('✅ All circomlibjs tests passed');
1914
+ return true;
1915
+ } catch (error) {
1916
+ console.error('❌ CircomLibJS debug failed:', error);
1917
+
1918
+ // Provide specific guidance based on error
1919
+ if (error.message.includes('timed out')) {
1920
+ console.error('⚠️ SOLUTION: Add these to your App.js BEFORE importing dop-wallet-v6:');
1921
+ console.error(`
1922
+ // Add this at the very top of App.js:
1923
+ global.Worker = undefined;
1924
+ global.WebAssembly = undefined;
1925
+ global.navigator = { ...global.navigator, serviceWorker: undefined };
1926
+ `);
1927
+ }
1928
+
1929
+ return false;
1930
+ }
1931
+ };
1932
+ ```
1933
+
1934
+ ### Critical Setup Issues
1935
+
1936
+ #### 1. "startDopEngineReactNative is undefined" Error
1937
+
1938
+ **Cause**: Missing dependencies or failed module loading during import.
1939
+
1940
+ **Solution**:
1941
+ ```bash
1942
+ # Ensure all dependencies are installed
1943
+ npm install --legacy-peer-deps
1944
+ # or
1945
+ yarn install
1946
+
1947
+ # If the issue persists, try installing memdown explicitly
1948
+ npm install memdown@^6.1.1
1949
+ ```
1950
+
1951
+ **Alternative Import** (temporary workaround):
1952
+ ```typescript
1953
+ // If main import fails, use direct import
1954
+ import { startDopEngineReactNative } from 'dop-wallet-v6/dist/services/dop/core/react-native-init';
1955
+ ```
1956
+
1957
+ #### 2. "Cannot read property 'call' of undefined" Error
1958
+
1959
+ **Cause**: Missing required polyfills or incorrect import order.
1960
+
1961
+ **Solution**:
1962
+ ```typescript
1963
+ // ❌ WRONG - This will cause the error
1964
+ import { createDopWallet } from 'dop-wallet-v6';
1965
+ import 'react-native-get-random-values';
1966
+
1967
+ // ✅ CORRECT - Polyfills must come FIRST
1968
+ import 'react-native-get-random-values';
1969
+ import 'react-native-url-polyfill/auto';
1970
+ import { Buffer } from 'buffer';
1971
+ global.Buffer = global.Buffer || Buffer;
1972
+ import 'dop-wallet-v6/react-native-shims';
1973
+
1974
+ import { createDopWallet } from 'dop-wallet-v6';
1975
+ ```
1976
+
1977
+ #### 3. "Module not found" Errors for Node.js Core Modules
1978
+
1979
+ **Cause**: Missing Metro configuration for Node.js core modules.
1980
+
1981
+ **Error Examples**:
1982
+ - `Module not found: Can't resolve 'stream'`
1983
+ - `Module not found: Can't resolve 'crypto'`
1984
+ - `Module not found: Can't resolve 'url'`
1985
+
1986
+ **Solution**: Ensure your `metro.config.js` includes all the aliases mentioned in the Metro Configuration section above.
1987
+
1988
+ #### 3. "AsyncStorage has been removed from react-native core"
1989
+
1990
+ **Cause**: This error should no longer occur in the latest version, but if you see it:
1991
+
1992
+ **Solution**:
1993
+ ```bash
1994
+ npm install @react-native-async-storage/async-storage
1995
+ ```
1996
+
1997
+ #### 4. Bundle/Build Failures
1998
+
1999
+ **Cause**: Metro not properly configured or missing browserify dependencies.
2000
+
2001
+ **Solution**:
2002
+ 1. Clear Metro cache: `npx react-native start --reset-cache`
2003
+ 2. Ensure all browserify packages are installed:
2004
+ ```bash
2005
+ npm install stream-browserify crypto-browserify stream-http https-browserify url browserify-zlib path-browserify
2006
+ ```
2007
+ 3. Restart Metro bundler completely
2008
+
2009
+ #### 5. Wallet Initialization Fails
2010
+
2011
+ **Error**: `Error creating wallet: TypeError: Cannot read property 'call' of undefined`
2012
+
2013
+ **Solution Checklist**:
2014
+ - [ ] All polyfills imported in correct order
2015
+ - [ ] Metro config includes Node.js aliases
2016
+ - [ ] All browserify dependencies installed
2017
+ - [ ] React Native shims imported
2018
+ - [ ] Buffer made available globally
2019
+
2020
+ #### 6. Level-FS Database Errors
2021
+
2022
+ **Error Examples**:
2023
+ - `TypeError: LevelFS.level is not a function (it is undefined)`
2024
+ - `TypeError: _reactNativeLevelFs.default is not a function (it is Object)`
2025
+ - `TypeError: 0, _$$_REQUIRE(...).level is not a function (it is undefined)`
2026
+
2027
+ **Root Cause**: `react-native-level-fs` is a filesystem shim, not a LevelDB constructor. The DOP Engine requires an `AbstractLevelDOWN` compatible database instance.
2028
+
2029
+ **Incorrect Approach** (causes the error):
2030
+ ```typescript
2031
+ // ❌ Wrong - this returns a filesystem interface, not a database
2032
+ import level from 'react-native-level-fs';
2033
+ const db = level('./path'); // This is NOT a valid LevelDB instance
2034
+ ```
2035
+
2036
+ **Correct Solution**:
2037
+ ```typescript
2038
+ // ✅ Correct - use startDopEngineReactNative (SDK v1.2.10+)
2039
+ import { startDopEngineReactNative } from 'dop-wallet-v6';
2040
+ await startDopEngineReactNative(walletSource, shouldDebug, artifactStore, ...);
2041
+ ```
2042
+
2043
+ **Migration Steps**:
2044
+ 1. **Update imports**: Replace database imports with `startDopEngineReactNative`
2045
+ 2. **Update initialization**: Use the new React Native-specific function
2046
+ 3. **Remove database code**: No need to manage LevelDB instances manually
2047
+ 4. **Test persistence**: Data now automatically persists between app sessions
2048
+
2049
+ ### Common Runtime Issues
2050
+
2051
+ #### 1. Engine Initialization Fails
2052
+ - Ensure all dependencies are properly installed
2053
+ - Check that React Native shims are imported
2054
+ - Verify database path is writable
2055
+ - Confirm ArtifactStore implementation is correct
2056
+
2057
+ #### 2. Balance Loading Issues
2058
+ - Ensure network is properly configured
2059
+ - Check wallet is properly synced
2060
+ - Verify token contracts are supported
2061
+ - Check internet connectivity
2062
+
2063
+ #### 3. Transaction Failures
2064
+ - Check gas settings and network fees
2065
+ - Ensure sufficient balance for transactions
2066
+ - Verify recipient addresses are valid
2067
+ - Confirm network supports the transaction type
2068
+
2069
+ #### 4. Performance Issues
2070
+ - Use native artifacts on mobile (`useNativeArtifacts: true`)
2071
+ - Implement proper caching strategies
2072
+ - Optimize sync frequency
2073
+ - Consider using creation block numbers for faster initial sync
2074
+
2075
+ ### Debug Mode
2076
+
2077
+ Enable debug mode during development for detailed logging:
2078
+
2079
+ ```typescript
2080
+ const shouldDebug = __DEV__;
2081
+ const verboseScanLogging = __DEV__;
2082
+
2083
+ await startDopEngine(
2084
+ walletSource,
2085
+ db,
2086
+ shouldDebug, // Enable debug logging
2087
+ artifactStore,
2088
+ useNativeArtifacts,
2089
+ skipMerkletreeScans,
2090
+ verboseScanLogging // Enable verbose scan logging
2091
+ );
2092
+ ```
2093
+
2094
+ ### Complete Dependency Checklist
2095
+
2096
+ Ensure you have all these dependencies installed:
2097
+
2098
+ **Core Dependencies**:
2099
+ - ✅ `dop-wallet-v6`
2100
+ - ✅ `asyncstorage-down`
2101
+ - ✅ `@react-native-async-storage/async-storage`
2102
+
2103
+ **Polyfills**:
2104
+ - ✅ `react-native-get-random-values`
2105
+ - ✅ `react-native-url-polyfill`
2106
+ - ✅ `buffer`
2107
+ - ✅ `util`
2108
+
2109
+ **Browserify Modules**:
2110
+ - ✅ `stream-browserify`
2111
+ - ✅ `crypto-browserify`
2112
+ - ✅ `stream-http`
2113
+ - ✅ `https-browserify`
2114
+ - ✅ `url`
2115
+ - ✅ `util`
2116
+ - ✅ `browserify-zlib`
2117
+ - ✅ `path-browserify`
2118
+
2119
+ **Dev Dependencies**:
2120
+ - ✅ `metro-config` (if using custom Metro config)
2121
+
2122
+ ### Quick Setup Verification Script
2123
+
2124
+ Use this script to verify your setup is correct:
2125
+
2126
+ ```typescript
2127
+ // SetupVerification.js
2128
+ export const verifyDopWalletSetup = () => {
2129
+ const checks = {
2130
+ buffer: typeof Buffer !== 'undefined',
2131
+ crypto: typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function',
2132
+ url: typeof URL !== 'undefined',
2133
+ util: (() => {
2134
+ try {
2135
+ const util = require('util');
2136
+ return typeof util.promisify === 'function';
2137
+ } catch {
2138
+ return false;
2139
+ }
2140
+ })(),
2141
+ randomValues: (() => {
2142
+ try {
2143
+ const array = new Uint8Array(1);
2144
+ crypto.getRandomValues(array);
2145
+ return true;
2146
+ } catch {
2147
+ return false;
2148
+ }
2149
+ })(),
2150
+ };
2151
+
2152
+ console.log('DOP Wallet Setup Verification:');
2153
+ Object.entries(checks).forEach(([check, passed]) => {
2154
+ console.log(`${passed ? '✅' : '❌'} ${check}: ${passed ? 'OK' : 'FAILED'}`);
2155
+ });
2156
+
2157
+ const allPassed = Object.values(checks).every(Boolean);
2158
+ console.log(`\nOverall setup: ${allPassed ? '✅ READY' : '❌ NEEDS FIXES'}`);
2159
+
2160
+ return allPassed;
2161
+ };
2162
+ ```
2163
+
2164
+ Run this before initializing the DOP Wallet SDK to ensure everything is properly configured.
2165
+
2166
+ ## Conclusion
2167
+
2168
+ This guide provides a comprehensive foundation for integrating DOP Wallet v6 into React Native applications. The SDK enables privacy-focused features for both ERC-20 tokens and ERC-721 NFTs across multiple blockchain networks.
2169
+
2170
+ For additional support and advanced features, refer to the official DOP documentation and community resources.
2171
+
2172
+ ---
2173
+
2174
+ **Note**: This integration guide is based on the DOP Wallet v6 SDK. Always refer to the latest documentation for the most up-to-date API references and best practices.