1
- import {
2
- RNAlchemySigner ,
3
- type ExportWalletResult ,
4
- } from "@account-kit/react-native-signer" ;
1
+ import { RNAlchemySigner , type ExportWalletResult } from "@account-kit/react-native-signer" ;
5
2
import { Alert } from "react-native" ;
6
3
7
- // Example usage of wallet export in React Native
8
-
4
+ /**
5
+ * Example: Export private key using the local storage approach
6
+ *
7
+ * This implementation uses Turnkey's recommended approach for mobile:
8
+ * 1. Generate a P256 key pair locally
9
+ * 2. Request export encrypted to the public key
10
+ * 3. Decrypt the bundle using HPKE with the private key
11
+ * 4. Clean up the key from storage
12
+ */
9
13
async function exportPrivateKey ( ) {
10
- // Initialize the signer
11
14
const signer = RNAlchemySigner ( {
12
15
client : {
13
16
connection : {
@@ -18,59 +21,124 @@ async function exportPrivateKey() {
18
21
} ) ;
19
22
20
23
try {
21
- // Method 1: Basic export (returns boolean)
22
- // This is compatible with the base class interface
23
- const success = await signer . exportWallet ( ) ;
24
- if ( success ) {
25
- console . log ( "Wallet export initiated successfully" ) ;
26
- // Note: This doesn't return the actual export bundle
27
- }
28
-
29
- // Method 2: Export with result (recommended for React Native)
30
- // This returns the encrypted export bundle that needs to be decrypted
31
- const exportResult : ExportWalletResult =
32
- await signer . exportWalletWithResult ( ) ;
33
-
34
- // The export bundle is encrypted and needs to be decrypted
35
- // using the stamper's private key
36
- console . log ( "Export bundle received:" , exportResult . exportBundle ) ;
37
- console . log ( "Wallet address:" , exportResult . address ) ;
38
- console . log ( "Organization ID:" , exportResult . orgId ) ;
39
-
40
- // IMPORTANT: Handle the export bundle securely
41
- // Options for handling the export bundle:
42
- // 1. Display in a secure modal/screen that prevents screenshots
43
- // 2. Store in secure device storage (iOS Keychain, Android Keystore)
44
- // 3. Allow user to copy to clipboard with security warnings
45
-
46
- // Example: Show alert with security warning
24
+ // Export as private key
25
+ const result : ExportWalletResult = await signer . exportWalletWithResult ( {
26
+ exportAs : "PRIVATE_KEY"
27
+ } ) ;
28
+
29
+ console . log ( "Private key exported successfully" ) ;
30
+ console . log ( "Address:" , result . address ) ;
31
+ console . log ( "Private key:" , result . privateKey ) ;
32
+
33
+ // IMPORTANT: Handle the private key securely
47
34
Alert . alert (
48
- "⚠️ Private Key Export" ,
49
- "Your private key export bundle has been generated. This is encrypted data that contains your private key.\n\n" +
50
- "Keep this information secure and never share it with anyone." ,
35
+ "⚠️ Private Key Exported" ,
36
+ "Your private key has been exported. Keep this information extremely secure:\n\n" +
37
+ `Address: ${ result . address } \n\n` +
38
+ "Never share your private key with anyone!" ,
51
39
[
52
40
{
53
41
text : "I Understand" ,
54
42
style : "default" ,
43
+ onPress : ( ) => {
44
+ // Optionally copy to secure clipboard or save securely
45
+ }
55
46
} ,
56
- ] ,
47
+ ]
57
48
) ;
58
49
59
- return exportResult ;
50
+ return result ;
60
51
} catch ( error ) {
61
- console . error ( "Failed to export wallet :" , error ) ;
52
+ console . error ( "Failed to export private key :" , error ) ;
62
53
Alert . alert (
63
54
"Export Failed" ,
64
- "Unable to export wallet. Please ensure you are authenticated and try again." ,
55
+ "Unable to export wallet. Please ensure you are authenticated and try again."
65
56
) ;
66
57
throw error ;
67
58
}
68
59
}
69
60
70
- // Example of using the client directly
61
+ /**
62
+ * Example: Export seed phrase
63
+ */
64
+ async function exportSeedPhrase ( ) {
65
+ const signer = RNAlchemySigner ( {
66
+ client : {
67
+ connection : {
68
+ apiKey : "YOUR_API_KEY" ,
69
+ } ,
70
+ rpId : "your-app.com" ,
71
+ } ,
72
+ } ) ;
73
+
74
+ try {
75
+ // Export as seed phrase
76
+ const result : ExportWalletResult = await signer . exportWalletWithResult ( {
77
+ exportAs : "SEED_PHRASE"
78
+ } ) ;
79
+
80
+ console . log ( "Seed phrase exported successfully" ) ;
81
+ console . log ( "Address:" , result . address ) ;
82
+ console . log ( "Seed phrase:" , result . seedPhrase ) ;
83
+
84
+ Alert . alert (
85
+ "🔐 Seed Phrase Exported" ,
86
+ "Your recovery phrase has been exported. This is the ONLY way to recover your wallet:\n\n" +
87
+ "• Write it down on paper\n" +
88
+ "• Store it in a secure location\n" +
89
+ "• Never share it with anyone\n" +
90
+ "• Never store it digitally unless encrypted" ,
91
+ [
92
+ {
93
+ text : "I've Secured My Phrase" ,
94
+ style : "default" ,
95
+ } ,
96
+ ]
97
+ ) ;
98
+
99
+ return result ;
100
+ } catch ( error ) {
101
+ console . error ( "Failed to export seed phrase:" , error ) ;
102
+ throw error ;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Example: Using the base exportWallet method (returns boolean)
108
+ */
109
+ async function exportWalletBasic ( ) {
110
+ const signer = RNAlchemySigner ( {
111
+ client : {
112
+ connection : {
113
+ apiKey : "YOUR_API_KEY" ,
114
+ } ,
115
+ rpId : "your-app.com" ,
116
+ } ,
117
+ } ) ;
118
+
119
+ try {
120
+ // This method returns true/false but doesn't give you the actual key
121
+ // Use exportWalletWithResult() to get the decrypted data
122
+ const success = await signer . exportWallet ( { exportAs : "PRIVATE_KEY" } ) ;
123
+
124
+ if ( success ) {
125
+ console . log ( "Export completed successfully" ) ;
126
+ // Note: You don't get the actual key with this method
127
+ }
128
+
129
+ return success ;
130
+ } catch ( error ) {
131
+ console . error ( "Export failed:" , error ) ;
132
+ throw error ;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Example: Direct client usage
138
+ */
71
139
async function exportWithClient ( ) {
72
140
const { RNSignerClient } = await import ( "@account-kit/react-native-signer" ) ;
73
-
141
+
74
142
const client = new RNSignerClient ( {
75
143
connection : {
76
144
apiKey : "YOUR_API_KEY" ,
@@ -82,11 +150,34 @@ async function exportWithClient() {
82
150
await client . initEmailAuth ( {
83
151
email : "user@example.com" ,
84
152
} ) ;
85
-
86
- // After authentication...
87
- const exportResult = await client . exportWalletWithResult ( ) ;
88
-
89
- return exportResult ;
153
+
154
+ // After authentication, export the wallet
155
+ const result = await client . exportWalletWithResult ( {
156
+ exportAs : "PRIVATE_KEY"
157
+ } ) ;
158
+
159
+ return result ;
90
160
}
91
161
92
- export { exportPrivateKey , exportWithClient } ;
162
+ /**
163
+ * Security Best Practices:
164
+ *
165
+ * 1. Never log private keys in production
166
+ * 2. Use secure storage if you need to persist keys
167
+ * 3. Implement screenshot prevention during export
168
+ * 4. Add user authentication before allowing export
169
+ * 5. Consider using biometric authentication
170
+ * 6. Warn users about the risks of exporting keys
171
+ * 7. Clear clipboard after copying sensitive data
172
+ *
173
+ * The export uses HPKE encryption with a locally generated P256 key pair,
174
+ * ensuring that neither Turnkey nor your app backend can access the
175
+ * decrypted private key - only the user's device has access.
176
+ */
177
+
178
+ export {
179
+ exportPrivateKey ,
180
+ exportSeedPhrase ,
181
+ exportWalletBasic ,
182
+ exportWithClient
183
+ } ;
0 commit comments