@solana-mobile/seed-vault-lib 0.1.0 → 0.2.0

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.
@@ -5,12 +5,13 @@ import android.content.Intent;
5
5
  import android.database.ContentObserver
6
6
  import android.net.Uri
7
7
  import android.os.Bundle
8
+ import android.os.CountDownTimer
8
9
  import android.os.Handler
10
+ import android.util.Base64
9
11
  import android.util.Log
10
12
  import com.facebook.react.bridge.*
11
13
  import com.facebook.react.modules.core.DeviceEventManagerModule
12
14
  import com.solanamobile.seedvault.*
13
- import kotlinx.serialization.Serializable
14
15
  import kotlinx.serialization.builtins.ListSerializer
15
16
  import kotlinx.serialization.builtins.serializer
16
17
  import kotlinx.serialization.json.Json
@@ -37,12 +38,22 @@ class SolanaMobileSeedVaultLibModule(val reactContext: ReactApplicationContext)
37
38
  }
38
39
  }
39
40
 
41
+ private var activityResultTimeout: Long? = DEFAULT_ACTIVITY_RESULT_TIMEOUT_MS
42
+
40
43
  init {
41
44
  reactContext.addActivityEventListener(mActivityEventListener)
42
45
 
43
46
  observeSeedVaultContentChanges()
44
47
  }
45
48
 
49
+ @ReactMethod
50
+ fun setActivtyResultTimeout(timeout: Long) {
51
+ activityResultTimeout =
52
+ if (timeout > MINIMUM_ACTIVITY_RESULT_TIMEOUT_MS) timeout
53
+ else if (timeout == 0L) null
54
+ else MINIMUM_ACTIVITY_RESULT_TIMEOUT_MS
55
+ }
56
+
46
57
  @ReactMethod
47
58
  fun isSeedVaultAvailable(allowSimulated: Boolean = false, promise: Promise) {
48
59
  val seedVaultAvailable = SeedVault.isAvailable(reactContext, allowSimulated)
@@ -122,24 +133,87 @@ class SolanaMobileSeedVaultLibModule(val reactContext: ReactApplicationContext)
122
133
  }
123
134
 
124
135
  @ReactMethod
125
- fun authorizeNewSeed() {
136
+ fun requestAuthorizeNewSeed() {
137
+ Log.d(TAG, "Requesting authorization for a new seed...")
138
+ val intent = Wallet.authorizeSeed(WalletContractV1.PURPOSE_SIGN_SOLANA_TRANSACTION)
139
+ reactContext.currentActivity?.startActivityForResult(intent, REQUEST_AUTHORIZE_SEED_ACCESS)
140
+ }
141
+
142
+ @ReactMethod
143
+ fun authorizeNewSeed(promise: Promise) {
126
144
  Log.d(TAG, "Requesting authorization for a new seed...")
127
145
  val intent = Wallet.authorizeSeed(WalletContractV1.PURPOSE_SIGN_SOLANA_TRANSACTION)
128
- reactContext.currentActivity?.startActivityForResult(intent, REQUEST_AUTHORIZE_SEED_ACCESS);
146
+ registerForActivityResult(intent, REQUEST_AUTHORIZE_SEED_ACCESS) { resultCode, data ->
147
+ try {
148
+ val authToken = Wallet.onAuthorizeSeedResult(resultCode, data)
149
+ Log.d(TAG, "Seed authorized, AuthToken=$authToken")
150
+
151
+ promise.resolve(
152
+ Arguments.createMap().apply {
153
+ putString("authToken", authToken.toString())
154
+ }
155
+ )
156
+ } catch (e: Wallet.ActionFailedException) {
157
+ Log.e(TAG, "Seed authorization failed", e)
158
+ promise.reject(e)
159
+ }
160
+ }
161
+ }
162
+
163
+ @ReactMethod
164
+ fun requestCreateNewSeed() {
165
+ Log.d(TAG, "Requesting creation of a new seed...")
166
+ val intent = Wallet.createSeed(WalletContractV1.PURPOSE_SIGN_SOLANA_TRANSACTION)
167
+ reactContext.currentActivity?.startActivityForResult(intent, REQUEST_CREATE_NEW_SEED)
129
168
  }
130
169
 
131
170
  @ReactMethod
132
- fun createNewSeed() {
171
+ fun createNewSeed(promise: Promise) {
133
172
  Log.d(TAG, "Requesting creation of a new seed...")
134
173
  val intent = Wallet.createSeed(WalletContractV1.PURPOSE_SIGN_SOLANA_TRANSACTION)
135
- reactContext.currentActivity?.startActivityForResult(intent, REQUEST_CREATE_NEW_SEED);
174
+ registerForActivityResult(intent, REQUEST_CREATE_NEW_SEED) { resultCode, data ->
175
+ try {
176
+ val authToken = Wallet.onCreateSeedResult(resultCode, data)
177
+ Log.d(TAG, "Seed created, AuthToken=$authToken")
178
+
179
+ promise.resolve(
180
+ Arguments.createMap().apply {
181
+ putString("authToken", authToken.toString())
182
+ }
183
+ )
184
+ } catch (e: Wallet.ActionFailedException) {
185
+ Log.e(TAG, "Seed creation failed", e)
186
+ promise.reject(e)
187
+ }
188
+ }
136
189
  }
137
190
 
138
191
  @ReactMethod
139
- fun importExistingSeed() {
192
+ fun requestImportExistingSeed() {
140
193
  Log.d(TAG, "Requesting import of an existing seed...")
141
194
  val intent = Wallet.importSeed(WalletContractV1.PURPOSE_SIGN_SOLANA_TRANSACTION)
142
- reactContext.currentActivity?.startActivityForResult(intent, REQUEST_IMPORT_EXISTING_SEED);
195
+ reactContext.currentActivity?.startActivityForResult(intent, REQUEST_IMPORT_EXISTING_SEED)
196
+ }
197
+
198
+ @ReactMethod
199
+ fun importExistingSeed(promise: Promise) {
200
+ Log.d(TAG, "Requesting import of an existing seed...")
201
+ val intent = Wallet.importSeed(WalletContractV1.PURPOSE_SIGN_SOLANA_TRANSACTION)
202
+ registerForActivityResult(intent, REQUEST_IMPORT_EXISTING_SEED) { resultCode, data ->
203
+ try {
204
+ val authToken = Wallet.onImportSeedResult(resultCode, data)
205
+ Log.d(TAG, "Seed imported, AuthToken=$authToken")
206
+
207
+ promise.resolve(
208
+ Arguments.createMap().apply {
209
+ putString("authToken", authToken.toString())
210
+ }
211
+ )
212
+ } catch (e: Wallet.ActionFailedException) {
213
+ Log.e(TAG, "Seed import failed", e)
214
+ promise.reject(e)
215
+ }
216
+ }
143
217
  }
144
218
 
145
219
  @ReactMethod
@@ -155,37 +229,146 @@ class SolanaMobileSeedVaultLibModule(val reactContext: ReactApplicationContext)
155
229
  }
156
230
 
157
231
  @ReactMethod
158
- fun signMessage(authToken: String, derivationPath: String, message: ReadableArray) {
159
- signMessages(authToken, listOf(SigningRequest(message.toByteArray(), arrayListOf(Uri.parse(derivationPath)))))
232
+ fun requestSignMessage(authToken: String, derivationPath: String, message: ReadableArray) {
233
+ requestSignMessages(authToken, listOf(SigningRequest(message.toByteArray(), arrayListOf(Uri.parse(derivationPath)))))
160
234
  }
161
235
 
162
236
  @ReactMethod
163
- fun signMessages(authToken: String, signingRequestsJson: String) {
237
+ fun requestSignMessages(authToken: String, signingRequestsJson: String) {
164
238
  val signingRequests: List<SigningRequest> = json.decodeFromString(ListSerializer(SigningRequestSerializer), signingRequestsJson)
165
- signMessages(authToken, signingRequests)
239
+ requestSignMessages(authToken, signingRequests)
166
240
  }
167
241
 
168
- private fun signMessages(authToken: String, signingRequests: List<SigningRequest>) {
242
+ private fun requestSignMessages(authToken: String, signingRequests: List<SigningRequest>) {
169
243
  Log.d(TAG, "Requesting provided messages to be signed...")
170
244
  val intent = Wallet.signMessages(authToken.toLong(), ArrayList(signingRequests))
171
245
  reactContext.currentActivity?.startActivityForResult(intent, REQUEST_SIGN_MESSAGES);
172
246
  }
173
247
 
174
248
  @ReactMethod
175
- fun signTransaction(authToken: String, derivationPath: String, transaction: ReadableArray) {
176
- signTransactions(authToken, listOf(SigningRequest(transaction.toByteArray(), arrayListOf(Uri.parse(derivationPath)))))
249
+ fun signMessage(authToken: String, derivationPath: String, message: String, promise: Promise) {
250
+ val messageBytes = Base64.decode(message, Base64.DEFAULT);
251
+ signMessagesAsync(authToken, listOf(SigningRequest(messageBytes, arrayListOf(Uri.parse(derivationPath))))) { result, error ->
252
+ result?.let { promise.resolve(Arguments.makeNativeMap(Arguments.toBundle(result.getMap(0)))) }
253
+ ?: promise.reject(error ?: Error("An unkown error occurred"))
254
+ }
177
255
  }
178
256
 
179
257
  @ReactMethod
180
- fun signTransactions(authToken: String, signingRequestsJson: String) {
258
+ fun signMessages(authToken: String, signingRequests: ReadableArray, promise: Promise) {
259
+ val signingRequests: List<SigningRequest> = json.decodeFromJsonElement(ListSerializer(SigningRequestSerializer), signingRequests.toJson())
260
+ signMessagesAsync(authToken, signingRequests) { result, error ->
261
+ result?.let { promise.resolve(result) } ?: promise.reject(error ?: Error("An unkown error occurred"))
262
+ }
263
+ }
264
+
265
+ private fun signMessagesAsync(authToken: String, signingRequests: List<SigningRequest>, callback: (result: ReadableArray?, error: Throwable?) -> Unit) {
266
+ Log.d(TAG, "Requesting provided messages to be signed...")
267
+ val intent = Wallet.signMessages(authToken.toLong(), ArrayList(signingRequests))
268
+ registerForActivityResult(intent, REQUEST_SIGN_MESSAGES) { resultCode, data ->
269
+ try {
270
+ val result = Wallet.onSignMessagesResult(resultCode, data)
271
+ Log.d(TAG, "Message signed: signatures=$result")
272
+
273
+ callback(
274
+ Arguments.makeNativeArray(result.map { response ->
275
+ Arguments.createMap().apply {
276
+ putArray("signatures", Arguments.makeNativeArray(response.signatures.map { Base64.encodeToString(it, Base64.NO_WRAP) }))
277
+ putArray("resolvedDerivationPaths", Arguments.makeNativeArray(response.resolvedDerivationPaths.map { it.toString() }))
278
+ }
279
+ }), null
280
+ )
281
+ } catch (e: Wallet.ActionFailedException) {
282
+ Log.e(TAG, "Message signing failed", e)
283
+ callback(null, e)
284
+ }
285
+ }
286
+ }
287
+
288
+ @ReactMethod
289
+ fun requestSignTransaction(authToken: String, derivationPath: String, transaction: ReadableArray) {
290
+ requestSignTransactions(authToken, listOf(SigningRequest(transaction.toByteArray(), arrayListOf(Uri.parse(derivationPath)))))
291
+ }
292
+
293
+ @ReactMethod
294
+ fun requestSignTransactions(authToken: String, signingRequestsJson: String) {
181
295
  val signingRequests: List<SigningRequest> = json.decodeFromString(ListSerializer(SigningRequestSerializer), signingRequestsJson)
182
- signTransactions(authToken, signingRequests)
296
+ requestSignTransactions(authToken, signingRequests)
297
+ }
298
+
299
+ private fun requestSignTransactions(authToken: String, signingRequests: List<SigningRequest>) {
300
+ Log.d(TAG, "Requesting provided transactions to be signed...")
301
+ val intent = Wallet.signTransactions(authToken.toLong(), ArrayList(signingRequests))
302
+ reactContext.currentActivity?.startActivityForResult(intent, REQUEST_SIGN_TRANSACTIONS)
303
+ }
304
+
305
+ @ReactMethod
306
+ fun signTransaction(authToken: String, derivationPath: String, transaction: String, promise: Promise) {
307
+ val txBytes = Base64.decode(transaction, Base64.DEFAULT);
308
+ signTransactionsAsync(authToken, listOf(SigningRequest(txBytes, arrayListOf(Uri.parse(derivationPath))))) { result, error ->
309
+ result?.let { promise.resolve(Arguments.makeNativeMap(Arguments.toBundle(result.getMap(0)))) }
310
+ ?: promise.reject(error ?: Error("An unkown error occurred"))
311
+ }
312
+ }
313
+
314
+ @ReactMethod
315
+ fun signTransactions(authToken: String, signingRequests: ReadableArray, promise: Promise) {
316
+ val signingRequests: List<SigningRequest> = json.decodeFromJsonElement(ListSerializer(SigningRequestSerializer), signingRequests.toJson())
317
+ signTransactionsAsync(authToken, signingRequests) { result, error ->
318
+ result?.let { promise.resolve(result) } ?: promise.reject(error ?: Error("An unkown error occurred"))
319
+ }
183
320
  }
184
321
 
185
- private fun signTransactions(authToken: String, signingRequests: List<SigningRequest>) {
322
+ private fun signTransactionsAsync(authToken: String, signingRequests: List<SigningRequest>, callback: (result: ReadableArray?, error: Throwable?) -> Unit) {
186
323
  Log.d(TAG, "Requesting provided transactions to be signed...")
187
324
  val intent = Wallet.signTransactions(authToken.toLong(), ArrayList(signingRequests))
188
- reactContext.currentActivity?.startActivityForResult(intent, REQUEST_SIGN_TRANSACTIONS);
325
+ registerForActivityResult(intent, REQUEST_SIGN_TRANSACTIONS) { resultCode, data ->
326
+ try {
327
+ val result = Wallet.onSignTransactionsResult(resultCode, data)
328
+ Log.d(TAG, "Transactions signed: signatures=$result")
329
+
330
+ callback(
331
+ Arguments.makeNativeArray(result.map { response ->
332
+ Arguments.createMap().apply {
333
+ putArray("signatures", Arguments.makeNativeArray(response.signatures.map { Base64.encodeToString(it, Base64.NO_WRAP) }))
334
+ putArray("resolvedDerivationPaths", Arguments.makeNativeArray(response.resolvedDerivationPaths.map { it.toString() }))
335
+ }
336
+ }), null
337
+ )
338
+ } catch (e: Wallet.ActionFailedException) {
339
+ Log.e(TAG, "Transaction signing failed", e)
340
+ callback(null, e)
341
+ }
342
+ }
343
+ }
344
+
345
+ private fun registerForActivityResult(intent: Intent, requestCode: Int, callback: (resultCode: Int, data: Intent?) -> Unit) {
346
+ val timeout = activityResultTimeout?.let { timeout ->
347
+ object : CountDownTimer(timeout, timeout) {
348
+ override fun onTick(millisUntilFinished: Long) {}
349
+ override fun onFinish() {
350
+ reactContext.currentActivity?.finishActivity(requestCode)
351
+ }
352
+ }
353
+ }
354
+
355
+ reactContext.addActivityEventListener(object : BaseActivityEventListener() {
356
+ override fun onActivityResult(
357
+ activity: Activity?,
358
+ receivedRequestCode: Int,
359
+ resultCode: Int,
360
+ data: Intent?
361
+ ) {
362
+ if (receivedRequestCode == requestCode) {
363
+ reactContext.removeActivityEventListener(this)
364
+ callback(resultCode, data)
365
+ timeout?.cancel()
366
+ }
367
+ }
368
+ })
369
+
370
+ reactContext.currentActivity?.startActivityForResult(intent, requestCode)
371
+ timeout?.start()
189
372
  }
190
373
 
191
374
  @ReactMethod
@@ -204,6 +387,49 @@ class SolanaMobileSeedVaultLibModule(val reactContext: ReactApplicationContext)
204
387
  reactContext.currentActivity?.startActivityForResult(intent, REQUEST_GET_PUBLIC_KEYS);
205
388
  }
206
389
 
390
+ @ReactMethod
391
+ fun getPublicKey(authToken: String, derivationPath: String, promise: Promise) {
392
+ getPublicKeysAsync(authToken, Arguments.createArray().apply {
393
+ pushString(derivationPath)
394
+ }) { result, error ->
395
+ result?.let { promise.resolve(Arguments.makeNativeMap(Arguments.toBundle(result.getMap(0)))) }
396
+ ?: promise.reject(error ?: Error("An unkown error occurred"))
397
+ }
398
+ }
399
+
400
+ @ReactMethod
401
+ fun getPublicKeys(authToken: String, derivationPaths: ReadableArray, promise: Promise) {
402
+ getPublicKeysAsync(authToken, derivationPaths) { result, error ->
403
+ result?.let { promise.resolve(result) } ?: promise.reject(error ?: Error("An unkown error occurred"))
404
+ }
405
+ }
406
+
407
+ private fun getPublicKeysAsync(authToken: String, derivationPaths: ReadableArray, callback: (result: ReadableArray?, error: Throwable?) -> Unit) {
408
+ Log.d(TAG, "Requesting public keys for provided derviation paths...")
409
+ val intent = Wallet.requestPublicKeys(authToken.toLong(), Arguments.toList(derivationPaths)?.mapNotNull {
410
+ (it as? String)?.let { uriString -> Uri.parse(uriString) }
411
+ } as ArrayList ?: arrayListOf())
412
+ registerForActivityResult(intent, REQUEST_GET_PUBLIC_KEYS) { resultCode, data ->
413
+ try {
414
+ val result = Wallet.onRequestPublicKeysResult(resultCode, data)
415
+ Log.d(TAG, "Public key retrieved: publicKey=$result")
416
+
417
+ callback(
418
+ Arguments.makeNativeArray(result.map { response ->
419
+ Arguments.createMap().apply {
420
+ putArray("publicKey", response.publicKey.toWritableArray())
421
+ putString("publicKeyEncoded", response.publicKeyEncoded)
422
+ putString("resolvedDerviationPath", response.resolvedDerivationPath.toString())
423
+ }
424
+ }), null
425
+ )
426
+ } catch (e: Wallet.ActionFailedException) {
427
+ Log.e(TAG, "Public Key retrieval failed", e)
428
+ callback(null, e)
429
+ }
430
+ }
431
+ }
432
+
207
433
  private fun sendEvent(reactContext: ReactContext, eventName: String, params: WritableMap? = null) {
208
434
  reactContext
209
435
  .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
@@ -313,80 +539,7 @@ class SolanaMobileSeedVaultLibModule(val reactContext: ReactApplicationContext)
313
539
  private const val REQUEST_SIGN_MESSAGES = 4
314
540
  private const val REQUEST_GET_PUBLIC_KEYS = 5
315
541
  private const val KEY_PENDING_EVENT = "pendingEvent"
542
+ private const val DEFAULT_ACTIVITY_RESULT_TIMEOUT_MS = 300000L
543
+ private const val MINIMUM_ACTIVITY_RESULT_TIMEOUT_MS = 30000L
316
544
  }
317
- }
318
-
319
- interface RNWritable {
320
- fun toWritableMap(): WritableMap
321
- }
322
-
323
- data class Account(
324
- @WalletContractV1.AccountId val id: Long,
325
- val name: String,
326
- val derivationPath: Uri,
327
- val publicKeyEncoded: String
328
- ) : RNWritable {
329
- override fun toWritableMap() = Arguments.createMap().apply {
330
- putString("id", "$id")
331
- putString("name", name)
332
- putString("derivationPath", "$derivationPath")
333
- putString("publicKeyEncoded", publicKeyEncoded)
334
- }
335
- }
336
-
337
- data class Seed(
338
- @WalletContractV1.AuthToken val authToken: Long,
339
- val name: String,
340
- @WalletContractV1.Purpose val purpose: Int,
341
- // val accounts: List<Account> = listOf()
342
- ) : RNWritable {
343
- override fun toWritableMap() = Arguments.createMap().apply {
344
- putString("authToken", "$authToken")
345
- putString("name", name)
346
- putInt("purpose", purpose)
347
- }
348
- }
349
-
350
- fun List<RNWritable>.toWritableArray() = Arguments.createArray().apply {
351
- forEach { writable ->
352
- pushMap(writable.toWritableMap())
353
- }
354
- }
355
-
356
- @Serializable
357
- sealed interface SeedVaultEvent {
358
- sealed class SeedEvent(val authToken: Long) : SeedVaultEvent
359
- class SeedAuthorized(authToken: Long) : SeedEvent(authToken)
360
- class NewSeedCreated(authToken: Long) : SeedEvent(authToken)
361
- class ExistingSeedImported(authToken: Long) : SeedEvent(authToken)
362
-
363
- data class PayloadsSigned(val result: List<SigningResponse>) : SeedVaultEvent
364
-
365
- data class PublicKeysEvent(val result: List<PublicKeyResponse>) : SeedVaultEvent
366
- }
367
-
368
- internal fun SeedVaultEvent.toWritableMap() : WritableMap = Arguments.createMap().apply {
369
- putString("__type", this@toWritableMap::class.simpleName)
370
- when (this@toWritableMap) {
371
- is SeedVaultEvent.SeedEvent -> {
372
- putString("authToken", authToken.toString())
373
- }
374
- is SeedVaultEvent.PayloadsSigned -> {
375
- putArray("result", Arguments.makeNativeArray(result.map { response ->
376
- Arguments.createMap().apply {
377
- putArray("signatures", Arguments.makeNativeArray(response.signatures.map { it.toWritableArray() }))
378
- putArray("resolvedDerivationPaths", Arguments.makeNativeArray(response.resolvedDerivationPaths.map { it.toString() }))
379
- }
380
- }))
381
- }
382
- is SeedVaultEvent.PublicKeysEvent -> {
383
- putArray("result", Arguments.makeNativeArray(result.map { response ->
384
- Arguments.createMap().apply {
385
- putArray("publicKey", response.publicKey.toWritableArray())
386
- putString("publicKeyEncoded", response.publicKeyEncoded)
387
- putString("resolvedDerviationPath", response.resolvedDerivationPath.toString())
388
- }
389
- }))
390
- }
391
- }
392
- }
545
+ }
@@ -0,0 +1,111 @@
1
+ import { useRef, useEffect } from 'react';
2
+ import { Platform, NativeModules, PermissionsAndroid, NativeEventEmitter } from 'react-native';
3
+
4
+ // EVENTS
5
+ // Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
6
+ const SeedVaultEventType = {
7
+ AuthorizeSeedAccess: "SeedAuthorized",
8
+ CreateNewSeed: "NewSeedCreated",
9
+ ImportExistingSeed: "ExistingSeedImported",
10
+ PayloadsSigned: "PayloadsSigned",
11
+ GetPublicKeys: "PublicKeysEvent",
12
+ ContentChange: "SeedVaultContentChange"
13
+ };
14
+
15
+ const SeedPurpose = {
16
+ SignSolanaTransaction: 0,
17
+ };
18
+
19
+ /******************************************************************************
20
+ Copyright (c) Microsoft Corporation.
21
+
22
+ Permission to use, copy, modify, and/or distribute this software for any
23
+ purpose with or without fee is hereby granted.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
26
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
27
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
28
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
29
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
30
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31
+ PERFORMANCE OF THIS SOFTWARE.
32
+ ***************************************************************************** */
33
+
34
+ function __awaiter(thisArg, _arguments, P, generator) {
35
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
36
+ return new (P || (P = Promise))(function (resolve, reject) {
37
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
38
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
39
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
40
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
41
+ });
42
+ }
43
+
44
+ const LINKING_ERROR = `The package 'solana-mobile-seed-vault-lib' doesn't seem to be linked. Make sure: \n\n` +
45
+ '- You rebuilt the app after installing the package\n' +
46
+ '- If you are using Lerna workspaces\n' +
47
+ ' - You have added `@solana-mobile/seed-vault-lib` as an explicit dependency, and\n' +
48
+ ' - You have added `@solana-mobile/seed-vault-lib` to the `nohoist` section of your package.json\n' +
49
+ '- You are not using Expo managed workflow\n';
50
+ const SolanaMobileSeedVaultLib = Platform.OS === 'android' && NativeModules.SolanaMobileSeedVaultLib
51
+ ? NativeModules.SolanaMobileSeedVaultLib
52
+ : new Proxy({}, {
53
+ get() {
54
+ throw new Error(Platform.OS !== 'android'
55
+ ? 'The package `solana-mobile-seed-vault-lib` is only compatible with React Native Android'
56
+ : LINKING_ERROR);
57
+ },
58
+ });
59
+ const SeedVaultPermissionAndroid = 'com.solanamobile.seedvault.ACCESS_SEED_VAULT';
60
+ const checkSeedVaultPermission = () => __awaiter(void 0, void 0, void 0, function* () {
61
+ const granted = yield PermissionsAndroid.check(SeedVaultPermissionAndroid);
62
+ if (!granted) {
63
+ throw new Error('You do not have permission to access Seed Vault. You must request permission to use Seed Vault.');
64
+ }
65
+ });
66
+ const checkIsSeedVaultAvailable = (allowSimulated = false) => __awaiter(void 0, void 0, void 0, function* () {
67
+ const seedVaultAvailable = yield SolanaMobileSeedVaultLib.isSeedVaultAvailable(allowSimulated);
68
+ if (!seedVaultAvailable) {
69
+ throw new Error(allowSimulated
70
+ ? 'Seed Vault is not available on this device, please install the Seed Vault Simulator'
71
+ : 'Seed Vault is not available on this device');
72
+ }
73
+ });
74
+ const SEED_VAULT_EVENT_BRIDGE_NAME = 'SeedVaultEventBridge';
75
+ function useSeedVault(handleSeedVaultEvent, handleContentChange) {
76
+ const seedVaultEventHandler = useRef(handleSeedVaultEvent);
77
+ const contentChangeHandler = useRef(handleContentChange);
78
+ useEffect(() => {
79
+ seedVaultEventHandler.current = handleSeedVaultEvent;
80
+ contentChangeHandler.current = handleContentChange;
81
+ });
82
+ checkIsSeedVaultAvailable(true);
83
+ checkSeedVaultPermission();
84
+ // Start native event listener
85
+ useEffect(() => {
86
+ const seedVaultEventEmitter = new NativeEventEmitter();
87
+ const listener = seedVaultEventEmitter.addListener(SEED_VAULT_EVENT_BRIDGE_NAME, (nativeEvent) => {
88
+ if (isContentChangeEvent(nativeEvent)) {
89
+ contentChangeHandler.current(nativeEvent);
90
+ }
91
+ else if (isSeedVaultEvent(nativeEvent)) {
92
+ seedVaultEventHandler.current(nativeEvent);
93
+ }
94
+ else {
95
+ console.warn('Unexpected native event type');
96
+ }
97
+ });
98
+ return () => {
99
+ listener.remove();
100
+ };
101
+ }, []);
102
+ }
103
+ function isSeedVaultEvent(nativeEvent) {
104
+ return Object.values(SeedVaultEventType).includes(nativeEvent.__type);
105
+ }
106
+ function isContentChangeEvent(nativeEvent) {
107
+ return nativeEvent.__type == SeedVaultEventType.ContentChange;
108
+ }
109
+ const SeedVault = SolanaMobileSeedVaultLib;
110
+
111
+ export { SeedPurpose, SeedVault, SeedVaultEventType, SeedVaultPermissionAndroid, useSeedVault };
@@ -12,6 +12,10 @@ const SeedVaultEventType = {
12
12
  ContentChange: "SeedVaultContentChange"
13
13
  };
14
14
 
15
+ const SeedPurpose = {
16
+ SignSolanaTransaction: 0,
17
+ };
18
+
15
19
  /******************************************************************************
16
20
  Copyright (c) Microsoft Corporation.
17
21
 
@@ -83,10 +87,8 @@ function useSeedVault(handleSeedVaultEvent, handleContentChange) {
83
87
  const listener = seedVaultEventEmitter.addListener(SEED_VAULT_EVENT_BRIDGE_NAME, (nativeEvent) => {
84
88
  if (isContentChangeEvent(nativeEvent)) {
85
89
  contentChangeHandler.current(nativeEvent);
86
- handleContentChange(nativeEvent);
87
90
  }
88
91
  else if (isSeedVaultEvent(nativeEvent)) {
89
- handleSeedVaultEvent(nativeEvent);
90
92
  seedVaultEventHandler.current(nativeEvent);
91
93
  }
92
94
  else {
@@ -104,5 +106,6 @@ function isSeedVaultEvent(nativeEvent) {
104
106
  function isContentChangeEvent(nativeEvent) {
105
107
  return nativeEvent.__type == SeedVaultEventType.ContentChange;
106
108
  }
109
+ const SeedVault = SolanaMobileSeedVaultLib;
107
110
 
108
- export { SeedVaultEventType, SeedVaultPermissionAndroid, useSeedVault };
111
+ export { SeedPurpose, SeedVault, SeedVaultEventType, SeedVaultPermissionAndroid, useSeedVault };