@solana-mobile/mobile-wallet-adapter-walletlib 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +12 -12
- package/README.md +202 -196
- package/android/build.gradle +151 -151
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -5
- package/android/gradle.properties +5 -5
- package/android/gradlew +185 -185
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/Extensions.kt +98 -98
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/JsonSerializationUtils.kt +156 -156
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/MobileWalletAdapterWalletLibReactNativePackage.kt +18 -18
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/SolanaMobileWalletAdapterWalletLibModule.kt +691 -691
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/model/MobileWalletAdapterConfig.kt +59 -59
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/model/MobileWalletAdapterRequest.kt +97 -97
- package/android/src/main/java/com/solanamobile/mobilewalletadapterwalletlib/reactnative/model/MobileWalletAdapterResponse.kt +68 -68
- package/lib/esm/index.js +119 -194
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/index.native.js +119 -194
- package/lib/esm/index.native.js.map +1 -0
- package/lib/esm/package.json +1 -3
- package/lib/types/index.d.ts +124 -112
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +49 -46
- package/lib/types/index.native.d.ts +0 -226
- package/lib/types/index.native.d.ts.map +0 -1
|
@@ -1,691 +1,691 @@
|
|
|
1
|
-
package com.solanamobile.mobilewalletadapterwalletlib.reactnative
|
|
2
|
-
|
|
3
|
-
import android.net.Uri
|
|
4
|
-
import android.util.Log
|
|
5
|
-
import com.facebook.react.bridge.*
|
|
6
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
7
|
-
import com.solana.mobilewalletadapter.common.ProtocolContract
|
|
8
|
-
import com.solana.mobilewalletadapter.walletlib.association.AssociationUri
|
|
9
|
-
import com.solana.mobilewalletadapter.walletlib.association.LocalAssociationUri
|
|
10
|
-
import com.solana.mobilewalletadapter.walletlib.authorization.AuthIssuerConfig
|
|
11
|
-
import com.solana.mobilewalletadapter.walletlib.scenario.*
|
|
12
|
-
import com.solana.mobilewalletadapter.walletlib.scenario.AuthorizedAccount
|
|
13
|
-
import com.solanamobile.mobilewalletadapterwalletlib.reactnative.model.*
|
|
14
|
-
import java.util.UUID
|
|
15
|
-
import kotlinx.coroutines.*
|
|
16
|
-
import kotlinx.serialization.json.Json
|
|
17
|
-
import kotlinx.serialization.json.JsonObject
|
|
18
|
-
import kotlinx.serialization.json.JsonPrimitive
|
|
19
|
-
import kotlinx.serialization.json.jsonObject
|
|
20
|
-
|
|
21
|
-
enum class ErrorCode(val code: String) {
|
|
22
|
-
ERROR_INTENT_DATA_NOT_FOUND("ERROR_INTENT_DATA_NOT_FOUND"),
|
|
23
|
-
ERROR_SESSION_ALREADY_CREATED("ERROR_SESSION_ALREADY_CREATED"),
|
|
24
|
-
ERROR_UNSUPPORTED_ASSOCIATION_URI("ERROR_UNSUPPORTED_ASSOCIATION_URI"),
|
|
25
|
-
ERROR_UNSUPPORTED_ASSOCIATION_TYPE("ERROR_UNSUPPORTED_ASSOCIATION_TYPE")
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class SolanaMobileWalletAdapterWalletLibModule(val reactContext: ReactApplicationContext) :
|
|
29
|
-
ReactContextBaseJavaModule(reactContext), CoroutineScope {
|
|
30
|
-
|
|
31
|
-
private val json = Json { ignoreUnknownKeys = true }
|
|
32
|
-
|
|
33
|
-
// Sets the name of the module in React, accessible at
|
|
34
|
-
// ReactNative.NativeModules.SolanaMobileWalletAdapterWalletLib
|
|
35
|
-
override fun getName() = "SolanaMobileWalletAdapterWalletLib"
|
|
36
|
-
|
|
37
|
-
override val coroutineContext =
|
|
38
|
-
Dispatchers.IO + CoroutineName("SolanaMobileWalletAdapterWalletLibModuleScope") + SupervisorJob()
|
|
39
|
-
|
|
40
|
-
// Session events that notify about the lifecycle of the Scenario session. We are choosing
|
|
41
|
-
// to go with the naming convention Session rather than Scenario for readability.
|
|
42
|
-
sealed interface MobileWalletAdapterSessionEvent {
|
|
43
|
-
val type: String
|
|
44
|
-
object None : MobileWalletAdapterSessionEvent {
|
|
45
|
-
override val type: String = ""
|
|
46
|
-
}
|
|
47
|
-
object SessionTerminated : MobileWalletAdapterSessionEvent {
|
|
48
|
-
override val type: String = "SESSION_TERMINATED"
|
|
49
|
-
}
|
|
50
|
-
object ScenarioReady : MobileWalletAdapterSessionEvent {
|
|
51
|
-
override val type: String = "SESSION_READY"
|
|
52
|
-
}
|
|
53
|
-
object ScenarioServingClients : MobileWalletAdapterSessionEvent {
|
|
54
|
-
override val type: String = "SESSION_SERVING_CLIENTS"
|
|
55
|
-
}
|
|
56
|
-
object ScenarioServingComplete : MobileWalletAdapterSessionEvent {
|
|
57
|
-
override val type: String = "SESSION_SERVING_COMPLETE"
|
|
58
|
-
}
|
|
59
|
-
object ScenarioComplete : MobileWalletAdapterSessionEvent {
|
|
60
|
-
override val type: String = "SESSION_COMPLETE"
|
|
61
|
-
}
|
|
62
|
-
class ScenarioError(val message: String? = null) : MobileWalletAdapterSessionEvent {
|
|
63
|
-
override val type: String = "SESSION_ERROR"
|
|
64
|
-
}
|
|
65
|
-
object ScenarioTeardownComplete : MobileWalletAdapterSessionEvent {
|
|
66
|
-
override val type: String = "SESSION_TEARDOWN_COMPLETE"
|
|
67
|
-
}
|
|
68
|
-
object LowPowerNoConnection : MobileWalletAdapterSessionEvent {
|
|
69
|
-
override val type: String = "LOW_POWER_NO_CONNECTION"
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Service requests that come from the dApp for Authorization, Signing, Sending, hence
|
|
74
|
-
// "RemoteRequest".
|
|
75
|
-
sealed class MobileWalletAdapterRemoteRequest(
|
|
76
|
-
open val request: ScenarioRequest,
|
|
77
|
-
val id: String = UUID.randomUUID().toString()
|
|
78
|
-
) {
|
|
79
|
-
data class AuthorizeDapp(override val request: AuthorizeRequest) :
|
|
80
|
-
MobileWalletAdapterRemoteRequest(request)
|
|
81
|
-
|
|
82
|
-
data class ReauthorizeDapp(override val request: ReauthorizeRequest) :
|
|
83
|
-
MobileWalletAdapterRemoteRequest(request)
|
|
84
|
-
|
|
85
|
-
data class DeauthorizeDapp(override val request: DeauthorizedEvent) :
|
|
86
|
-
MobileWalletAdapterRemoteRequest(request)
|
|
87
|
-
|
|
88
|
-
sealed class SignPayloads(override val request: SignPayloadsRequest) :
|
|
89
|
-
MobileWalletAdapterRemoteRequest(request)
|
|
90
|
-
|
|
91
|
-
data class SignTransactions(override val request: SignTransactionsRequest) :
|
|
92
|
-
SignPayloads(request)
|
|
93
|
-
|
|
94
|
-
data class SignMessages(override val request: SignMessagesRequest) :
|
|
95
|
-
SignPayloads(request)
|
|
96
|
-
|
|
97
|
-
data class SignAndSendTransactions(
|
|
98
|
-
override val request: SignAndSendTransactionsRequest,
|
|
99
|
-
val endpointUri: Uri,
|
|
100
|
-
) : MobileWalletAdapterRemoteRequest(request)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// currently we only allow a single scenario to exist at a time
|
|
104
|
-
private var scenarioId: String? = null
|
|
105
|
-
private var scenarioUri: Uri? = null
|
|
106
|
-
private var scenario: Scenario? = null
|
|
107
|
-
set(value) {
|
|
108
|
-
value?.let { scenarioId = UUID.randomUUID().toString() }
|
|
109
|
-
?: run {
|
|
110
|
-
scenarioUri = null
|
|
111
|
-
scenarioId = null
|
|
112
|
-
scenario?.close()
|
|
113
|
-
}
|
|
114
|
-
pendingRequests.clear()
|
|
115
|
-
field = value
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// very basic/naive implememtion of request cache.
|
|
119
|
-
// we could replace this with an abstraction that has expiration, persistance, etc.
|
|
120
|
-
private val pendingRequests = mutableMapOf<String, MobileWalletAdapterRemoteRequest>()
|
|
121
|
-
|
|
122
|
-
private fun clusterToRpcUri(cluster: String?): Uri {
|
|
123
|
-
return when (cluster) {
|
|
124
|
-
ProtocolContract.CLUSTER_MAINNET_BETA ->
|
|
125
|
-
Uri.parse("https://api.mainnet-beta.solana.com")
|
|
126
|
-
|
|
127
|
-
ProtocolContract.CLUSTER_DEVNET ->
|
|
128
|
-
Uri.parse("https://api.devnet.solana.com")
|
|
129
|
-
|
|
130
|
-
else -> Uri.parse("https://api.testnet.solana.com")
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
@ReactMethod
|
|
134
|
-
fun createScenario(
|
|
135
|
-
walletName: String,
|
|
136
|
-
config: String,
|
|
137
|
-
promise: Promise,
|
|
138
|
-
) = launch {
|
|
139
|
-
// Get the intent that started this activity
|
|
140
|
-
val intent = reactContext.getCurrentActivity()?.intent
|
|
141
|
-
if (intent == null) {
|
|
142
|
-
Log.e(TAG, "Unable to get intent in current context")
|
|
143
|
-
promise.reject(ErrorCode.ERROR_INTENT_DATA_NOT_FOUND.code, "Unable to get intent in current context")
|
|
144
|
-
return@launch
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Get the data from the intent and parse into URI
|
|
148
|
-
val data = intent.data
|
|
149
|
-
if (data == null) {
|
|
150
|
-
Log.e(TAG, "Unable to get intent data in current context")
|
|
151
|
-
promise.reject(ErrorCode.ERROR_INTENT_DATA_NOT_FOUND.code, "Unable to get intent data in current context")
|
|
152
|
-
return@launch
|
|
153
|
-
}
|
|
154
|
-
val uri = Uri.parse(data.toString())
|
|
155
|
-
|
|
156
|
-
// TODO: this is dirty, need some stateful object/data to know what state we are in.
|
|
157
|
-
// also, should we support multiple simultaneous scenarios?
|
|
158
|
-
if (uri == scenarioUri && scenario != null) {
|
|
159
|
-
Log.w(TAG, "Session already created for uri: $uri")
|
|
160
|
-
promise.reject(ErrorCode.ERROR_SESSION_ALREADY_CREATED.code, "Session already created for uri: $uri")
|
|
161
|
-
return@launch
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
val associationUri = AssociationUri.parse(uri)
|
|
165
|
-
if (associationUri == null) {
|
|
166
|
-
Log.e(TAG, "Unsupported association URI: $uri")
|
|
167
|
-
promise.reject(ErrorCode.ERROR_UNSUPPORTED_ASSOCIATION_URI.code, "Unsupported association URI: $uri")
|
|
168
|
-
return@launch
|
|
169
|
-
} else if (associationUri !is LocalAssociationUri) {
|
|
170
|
-
Log.e(TAG, "Current implementation of fakewallet does not support remote clients")
|
|
171
|
-
promise.reject(ErrorCode.ERROR_UNSUPPORTED_ASSOCIATION_TYPE.code, "Current implementation of fakewallet does not support remote clients")
|
|
172
|
-
return@launch
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
scenarioUri = uri
|
|
176
|
-
|
|
177
|
-
val kotlinConfig =
|
|
178
|
-
json.decodeFromString(MobileWalletAdapterConfigSerializer, config)
|
|
179
|
-
|
|
180
|
-
// created a scenario, told it to start (kicks off some threads in the background)
|
|
181
|
-
// we've kept a reference to it in the global state of this module (scenario)
|
|
182
|
-
// this won't be garbage collected and will just run, sit & wait for an incoming
|
|
183
|
-
// connection
|
|
184
|
-
scenario =
|
|
185
|
-
associationUri.createScenario(
|
|
186
|
-
reactContext,
|
|
187
|
-
kotlinConfig,
|
|
188
|
-
AuthIssuerConfig(walletName),
|
|
189
|
-
MobileWalletAdapterScenarioCallbacks()
|
|
190
|
-
).also {
|
|
191
|
-
it.start()
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
promise.resolve(scenarioId)
|
|
195
|
-
Log.d(TAG, "scenario created: $walletName")
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/* Generic Request functions */
|
|
199
|
-
@ReactMethod
|
|
200
|
-
fun cancelRequest(sessionId: String, requestId: String) {
|
|
201
|
-
Log.d(TAG, "Cancelled request $requestId")
|
|
202
|
-
(pendingRequests.remove(requestId) as? ScenarioRequest)?.let { scenarioRequest ->
|
|
203
|
-
scenarioRequest.cancel()
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
@ReactMethod
|
|
208
|
-
fun resolve(requestJson: String, responseJson: String) = launch {
|
|
209
|
-
val completedRequest =
|
|
210
|
-
json.decodeFromString(
|
|
211
|
-
MobileWalletAdapterRequestSerializer,
|
|
212
|
-
requestJson
|
|
213
|
-
)
|
|
214
|
-
val response =
|
|
215
|
-
json.decodeFromString(
|
|
216
|
-
MobileWalletAdapterResponseSerializer,
|
|
217
|
-
responseJson
|
|
218
|
-
)
|
|
219
|
-
val pendingRequest = pendingRequests[completedRequest.requestId]
|
|
220
|
-
|
|
221
|
-
if (completedRequest.sessionId != scenarioId) {
|
|
222
|
-
sendSessionEventToReact(
|
|
223
|
-
MobileWalletAdapterSessionEvent.ScenarioError(
|
|
224
|
-
"Invalid session (${completedRequest.sessionId}). This session does not exist/is no longer active."
|
|
225
|
-
)
|
|
226
|
-
)
|
|
227
|
-
return@launch
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
fun completeWithInvalidResponse() {
|
|
231
|
-
pendingRequest?.request?.completeWithInternalError(
|
|
232
|
-
Exception("Invalid Response For Request: response = $responseJson")
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
when (completedRequest) {
|
|
237
|
-
is AuthorizeDapp ->
|
|
238
|
-
when (response) {
|
|
239
|
-
is MobileWalletAdapterFailureResponse -> {
|
|
240
|
-
when (response) {
|
|
241
|
-
is UserDeclinedResponse ->
|
|
242
|
-
(pendingRequest as?
|
|
243
|
-
MobileWalletAdapterRemoteRequest.AuthorizeDapp)
|
|
244
|
-
?.request
|
|
245
|
-
?.completeWithDecline()
|
|
246
|
-
|
|
247
|
-
else ->
|
|
248
|
-
completeWithInvalidResponse()
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
is AuthorizeDappResponse ->
|
|
253
|
-
(pendingRequest as?
|
|
254
|
-
MobileWalletAdapterRemoteRequest.AuthorizeDapp)
|
|
255
|
-
?.request
|
|
256
|
-
?.completeWithAuthorize(
|
|
257
|
-
response.accounts
|
|
258
|
-
.first()
|
|
259
|
-
.let { account
|
|
260
|
-
->
|
|
261
|
-
AuthorizedAccount(
|
|
262
|
-
account.publicKey,
|
|
263
|
-
account.accountLabel,
|
|
264
|
-
account.icon
|
|
265
|
-
?.let {
|
|
266
|
-
Uri.parse(
|
|
267
|
-
it
|
|
268
|
-
)
|
|
269
|
-
},
|
|
270
|
-
account.chains
|
|
271
|
-
?.toTypedArray(),
|
|
272
|
-
account.features
|
|
273
|
-
?.toTypedArray()
|
|
274
|
-
)
|
|
275
|
-
},
|
|
276
|
-
response.walletUriBase
|
|
277
|
-
?.let {
|
|
278
|
-
Uri.parse(
|
|
279
|
-
response.walletUriBase
|
|
280
|
-
)
|
|
281
|
-
},
|
|
282
|
-
response.authorizationScope,
|
|
283
|
-
response.signInResult
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
else -> completeWithInvalidResponse()
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
is ReauthorizeDapp ->
|
|
290
|
-
when (response) {
|
|
291
|
-
is MobileWalletAdapterFailureResponse -> {
|
|
292
|
-
when (response) {
|
|
293
|
-
is AuthorizationNotValidResponse ->
|
|
294
|
-
(pendingRequest as?
|
|
295
|
-
MobileWalletAdapterRemoteRequest.ReauthorizeDapp)
|
|
296
|
-
?.request
|
|
297
|
-
?.completeWithDecline()
|
|
298
|
-
|
|
299
|
-
else ->
|
|
300
|
-
completeWithInvalidResponse()
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
is ReauthorizeDappResponse ->
|
|
305
|
-
(pendingRequest as?
|
|
306
|
-
MobileWalletAdapterRemoteRequest.ReauthorizeDapp)
|
|
307
|
-
?.request
|
|
308
|
-
?.completeWithReauthorize()
|
|
309
|
-
|
|
310
|
-
else -> completeWithInvalidResponse()
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
is DeauthorizeDapp ->
|
|
314
|
-
when (response) {
|
|
315
|
-
is DeauthorizeDappResponse ->
|
|
316
|
-
(pendingRequest as?
|
|
317
|
-
MobileWalletAdapterRemoteRequest.DeauthorizeDapp)
|
|
318
|
-
?.request
|
|
319
|
-
?.complete()
|
|
320
|
-
|
|
321
|
-
else -> completeWithInvalidResponse()
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
is SignAndSendTransactions ->
|
|
325
|
-
when (response) {
|
|
326
|
-
is MobileWalletAdapterFailureResponse -> {
|
|
327
|
-
when (response) {
|
|
328
|
-
is UserDeclinedResponse ->
|
|
329
|
-
(pendingRequest as?
|
|
330
|
-
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
331
|
-
?.request
|
|
332
|
-
?.completeWithDecline()
|
|
333
|
-
|
|
334
|
-
is TooManyPayloadsResponse ->
|
|
335
|
-
(pendingRequest as?
|
|
336
|
-
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
337
|
-
?.request
|
|
338
|
-
?.completeWithTooManyPayloads()
|
|
339
|
-
|
|
340
|
-
is AuthorizationNotValidResponse ->
|
|
341
|
-
(pendingRequest as?
|
|
342
|
-
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
343
|
-
?.request
|
|
344
|
-
?.completeWithAuthorizationNotValid()
|
|
345
|
-
|
|
346
|
-
is InvalidSignaturesResponse ->
|
|
347
|
-
(pendingRequest as?
|
|
348
|
-
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
349
|
-
?.request
|
|
350
|
-
?.completeWithInvalidSignatures(
|
|
351
|
-
response.valid
|
|
352
|
-
)
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
is SignedAndSentTransactions ->
|
|
357
|
-
(pendingRequest as?
|
|
358
|
-
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
359
|
-
?.request
|
|
360
|
-
?.completeWithSignatures(
|
|
361
|
-
response.signedTransactions
|
|
362
|
-
.toTypedArray()
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
else -> completeWithInvalidResponse()
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
is SignPayloads ->
|
|
369
|
-
when (response) {
|
|
370
|
-
is MobileWalletAdapterFailureResponse -> {
|
|
371
|
-
when (response) {
|
|
372
|
-
is UserDeclinedResponse ->
|
|
373
|
-
(pendingRequest as?
|
|
374
|
-
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
375
|
-
?.request
|
|
376
|
-
?.completeWithDecline()
|
|
377
|
-
|
|
378
|
-
is TooManyPayloadsResponse ->
|
|
379
|
-
(pendingRequest as?
|
|
380
|
-
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
381
|
-
?.request
|
|
382
|
-
?.completeWithTooManyPayloads()
|
|
383
|
-
|
|
384
|
-
is AuthorizationNotValidResponse ->
|
|
385
|
-
(pendingRequest as?
|
|
386
|
-
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
387
|
-
?.request
|
|
388
|
-
?.completeWithAuthorizationNotValid()
|
|
389
|
-
|
|
390
|
-
is InvalidSignaturesResponse ->
|
|
391
|
-
(pendingRequest as?
|
|
392
|
-
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
393
|
-
?.request
|
|
394
|
-
?.completeWithInvalidPayloads(
|
|
395
|
-
response.valid
|
|
396
|
-
)
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
is SignedPayloads ->
|
|
401
|
-
(pendingRequest as?
|
|
402
|
-
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
403
|
-
?.request
|
|
404
|
-
?.completeWithSignedPayloads(
|
|
405
|
-
response.signedPayloads
|
|
406
|
-
.toTypedArray()
|
|
407
|
-
)
|
|
408
|
-
|
|
409
|
-
else -> completeWithInvalidResponse()
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
private fun checkSessionId(sessionId: String, doIfValid: (() -> Unit)) =
|
|
415
|
-
if (sessionId == scenarioId) doIfValid()
|
|
416
|
-
else
|
|
417
|
-
sendSessionEventToReact(
|
|
418
|
-
MobileWalletAdapterSessionEvent
|
|
419
|
-
.ScenarioError(
|
|
420
|
-
"Invalid session ($sessionId). This session does not exist/is no longer active."
|
|
421
|
-
)
|
|
422
|
-
)
|
|
423
|
-
|
|
424
|
-
private fun sendSessionEventToReact(sessionEvent: MobileWalletAdapterSessionEvent) {
|
|
425
|
-
val eventInfo =
|
|
426
|
-
when (sessionEvent) {
|
|
427
|
-
is MobileWalletAdapterSessionEvent.None -> null
|
|
428
|
-
is MobileWalletAdapterSessionEvent.ScenarioError ->
|
|
429
|
-
Arguments.createMap().apply {
|
|
430
|
-
putString(
|
|
431
|
-
"__type",
|
|
432
|
-
sessionEvent.type
|
|
433
|
-
)
|
|
434
|
-
putString(
|
|
435
|
-
"error",
|
|
436
|
-
sessionEvent.message
|
|
437
|
-
)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
else ->
|
|
441
|
-
Arguments.createMap().apply {
|
|
442
|
-
putString(
|
|
443
|
-
"__type",
|
|
444
|
-
sessionEvent.type
|
|
445
|
-
)
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
eventInfo?.putString("sessionId", scenarioId)
|
|
450
|
-
|
|
451
|
-
eventInfo?.let {
|
|
452
|
-
sendEvent(
|
|
453
|
-
reactContext,
|
|
454
|
-
Companion.MOBILE_WALLET_ADAPTER_SERVICE_REQUEST_BRIDGE_NAME,
|
|
455
|
-
it
|
|
456
|
-
)
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
private fun sendWalletServiceRequestToReact(request: MobileWalletAdapterRemoteRequest) {
|
|
461
|
-
val surrogate =
|
|
462
|
-
when (request) {
|
|
463
|
-
is MobileWalletAdapterRemoteRequest.AuthorizeDapp ->
|
|
464
|
-
AuthorizeDapp(
|
|
465
|
-
scenarioId!!,
|
|
466
|
-
request.request.chain,
|
|
467
|
-
request.request
|
|
468
|
-
.identityName,
|
|
469
|
-
request.request.identityUri
|
|
470
|
-
.toString(),
|
|
471
|
-
request.request
|
|
472
|
-
.iconRelativeUri
|
|
473
|
-
.toString(),
|
|
474
|
-
request.request.features
|
|
475
|
-
?.asList(),
|
|
476
|
-
request.request.addresses
|
|
477
|
-
?.asList(),
|
|
478
|
-
request.request
|
|
479
|
-
.signInPayload
|
|
480
|
-
)
|
|
481
|
-
|
|
482
|
-
is MobileWalletAdapterRemoteRequest.ReauthorizeDapp ->
|
|
483
|
-
ReauthorizeDapp(
|
|
484
|
-
scenarioId!!,
|
|
485
|
-
request.request.chain,
|
|
486
|
-
request.request
|
|
487
|
-
.identityName,
|
|
488
|
-
request.request.identityUri
|
|
489
|
-
.toString(),
|
|
490
|
-
request.request
|
|
491
|
-
.iconRelativeUri
|
|
492
|
-
.toString(),
|
|
493
|
-
request.request
|
|
494
|
-
.authorizationScope
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
is MobileWalletAdapterRemoteRequest.DeauthorizeDapp ->
|
|
498
|
-
DeauthorizeDapp(
|
|
499
|
-
scenarioId!!,
|
|
500
|
-
request.request.chain,
|
|
501
|
-
request.request
|
|
502
|
-
.identityName,
|
|
503
|
-
request.request.identityUri
|
|
504
|
-
.toString(),
|
|
505
|
-
request.request
|
|
506
|
-
.iconRelativeUri
|
|
507
|
-
.toString(),
|
|
508
|
-
request.request
|
|
509
|
-
.authorizationScope
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
is MobileWalletAdapterRemoteRequest.SignMessages ->
|
|
513
|
-
SignMessages(
|
|
514
|
-
scenarioId!!,
|
|
515
|
-
request.request.chain,
|
|
516
|
-
request.request
|
|
517
|
-
.identityName,
|
|
518
|
-
request.request.identityUri
|
|
519
|
-
.toString(),
|
|
520
|
-
request.request
|
|
521
|
-
.iconRelativeUri
|
|
522
|
-
.toString(),
|
|
523
|
-
request.request
|
|
524
|
-
.authorizationScope,
|
|
525
|
-
request.request.payloads
|
|
526
|
-
.toList()
|
|
527
|
-
)
|
|
528
|
-
|
|
529
|
-
is MobileWalletAdapterRemoteRequest.SignTransactions ->
|
|
530
|
-
SignTransactions(
|
|
531
|
-
scenarioId!!,
|
|
532
|
-
request.request.chain,
|
|
533
|
-
request.request
|
|
534
|
-
.identityName,
|
|
535
|
-
request.request.identityUri
|
|
536
|
-
.toString(),
|
|
537
|
-
request.request
|
|
538
|
-
.iconRelativeUri
|
|
539
|
-
.toString(),
|
|
540
|
-
request.request
|
|
541
|
-
.authorizationScope,
|
|
542
|
-
request.request.payloads
|
|
543
|
-
.toList()
|
|
544
|
-
)
|
|
545
|
-
|
|
546
|
-
is MobileWalletAdapterRemoteRequest.SignAndSendTransactions ->
|
|
547
|
-
SignAndSendTransactions(
|
|
548
|
-
scenarioId!!,
|
|
549
|
-
request.request.chain,
|
|
550
|
-
request.request
|
|
551
|
-
.identityName,
|
|
552
|
-
request.request.identityUri
|
|
553
|
-
.toString(),
|
|
554
|
-
request.request
|
|
555
|
-
.iconRelativeUri
|
|
556
|
-
.toString(),
|
|
557
|
-
request.request
|
|
558
|
-
.authorizationScope,
|
|
559
|
-
request.request.payloads
|
|
560
|
-
.toList()
|
|
561
|
-
)
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// this is dirty, the requestId needs to line up so have to manually overwrite here
|
|
565
|
-
// should we change javascript side to accept json?
|
|
566
|
-
val eventInfo =
|
|
567
|
-
JsonObject(
|
|
568
|
-
json.encodeToJsonElement(
|
|
569
|
-
MobileWalletAdapterRequestSerializer,
|
|
570
|
-
surrogate
|
|
571
|
-
)
|
|
572
|
-
.jsonObject
|
|
573
|
-
.toMutableMap()
|
|
574
|
-
.apply {
|
|
575
|
-
put(
|
|
576
|
-
"requestId",
|
|
577
|
-
JsonPrimitive(
|
|
578
|
-
request.id
|
|
579
|
-
)
|
|
580
|
-
)
|
|
581
|
-
}
|
|
582
|
-
)
|
|
583
|
-
.toReadableMap()
|
|
584
|
-
|
|
585
|
-
sendEvent(
|
|
586
|
-
reactContext,
|
|
587
|
-
Companion.MOBILE_WALLET_ADAPTER_SERVICE_REQUEST_BRIDGE_NAME,
|
|
588
|
-
eventInfo
|
|
589
|
-
)
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
private fun sendEvent(
|
|
593
|
-
reactContext: ReactContext,
|
|
594
|
-
eventName: String,
|
|
595
|
-
params: ReadableMap? = null
|
|
596
|
-
) {
|
|
597
|
-
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
598
|
-
.emit(eventName, params)
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
private inner class MobileWalletAdapterScenarioCallbacks : LocalScenario.Callbacks {
|
|
602
|
-
/* Session Events */
|
|
603
|
-
override fun onScenarioReady() {
|
|
604
|
-
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioReady)
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
override fun onScenarioServingClients() {
|
|
608
|
-
sendSessionEventToReact(
|
|
609
|
-
MobileWalletAdapterSessionEvent.ScenarioServingClients
|
|
610
|
-
)
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
override fun onScenarioServingComplete() {
|
|
614
|
-
launch(Dispatchers.Main) {
|
|
615
|
-
scenario = null
|
|
616
|
-
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioServingComplete)
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
override fun onScenarioComplete() {
|
|
621
|
-
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioComplete)
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
override fun onScenarioError() {
|
|
625
|
-
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioError())
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
override fun onScenarioTeardownComplete() {
|
|
629
|
-
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioTeardownComplete)
|
|
630
|
-
sendSessionEventToReact(MobileWalletAdapterSessionEvent.SessionTerminated)
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
override fun onLowPowerAndNoConnection() {
|
|
634
|
-
sendSessionEventToReact(
|
|
635
|
-
MobileWalletAdapterSessionEvent.LowPowerNoConnection
|
|
636
|
-
)
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
/* Remote Requests */
|
|
640
|
-
override fun onAuthorizeRequest(request: AuthorizeRequest) {
|
|
641
|
-
val request = MobileWalletAdapterRemoteRequest.AuthorizeDapp(request)
|
|
642
|
-
pendingRequests.put(request.id, request)
|
|
643
|
-
sendWalletServiceRequestToReact(request)
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
override fun onReauthorizeRequest(request: ReauthorizeRequest) {
|
|
647
|
-
val request = MobileWalletAdapterRemoteRequest.ReauthorizeDapp(request)
|
|
648
|
-
pendingRequests.put(request.id, request)
|
|
649
|
-
sendWalletServiceRequestToReact(request)
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
override fun onSignTransactionsRequest(request: SignTransactionsRequest) {
|
|
653
|
-
val request = MobileWalletAdapterRemoteRequest.SignTransactions(request)
|
|
654
|
-
pendingRequests.put(request.id, request)
|
|
655
|
-
sendWalletServiceRequestToReact(request)
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
override fun onSignMessagesRequest(request: SignMessagesRequest) {
|
|
659
|
-
val request = MobileWalletAdapterRemoteRequest.SignMessages(request)
|
|
660
|
-
pendingRequests.put(request.id, request)
|
|
661
|
-
sendWalletServiceRequestToReact(request)
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
override fun onSignAndSendTransactionsRequest(
|
|
665
|
-
request: SignAndSendTransactionsRequest
|
|
666
|
-
) {
|
|
667
|
-
val endpointUri = clusterToRpcUri(request.cluster)
|
|
668
|
-
val request =
|
|
669
|
-
MobileWalletAdapterRemoteRequest.SignAndSendTransactions(
|
|
670
|
-
request,
|
|
671
|
-
endpointUri
|
|
672
|
-
)
|
|
673
|
-
pendingRequests.put(request.id, request)
|
|
674
|
-
sendWalletServiceRequestToReact(request)
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
override fun onDeauthorizedEvent(event: DeauthorizedEvent) {
|
|
678
|
-
val request = MobileWalletAdapterRemoteRequest.DeauthorizeDapp(event)
|
|
679
|
-
pendingRequests.put(request.id, request)
|
|
680
|
-
sendWalletServiceRequestToReact(request)
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
companion object {
|
|
685
|
-
private val TAG = SolanaMobileWalletAdapterWalletLibModule::class.simpleName
|
|
686
|
-
const val MOBILE_WALLET_ADAPTER_SERVICE_REQUEST_BRIDGE_NAME =
|
|
687
|
-
"MobileWalletAdapterServiceRequestBridge"
|
|
688
|
-
const val MOBILE_WALLET_ADAPTER_SESSION_EVENT_BRIDGE_NAME =
|
|
689
|
-
"MobileWalletAdapterSessionEventBridge"
|
|
690
|
-
}
|
|
691
|
-
}
|
|
1
|
+
package com.solanamobile.mobilewalletadapterwalletlib.reactnative
|
|
2
|
+
|
|
3
|
+
import android.net.Uri
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.facebook.react.bridge.*
|
|
6
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
7
|
+
import com.solana.mobilewalletadapter.common.ProtocolContract
|
|
8
|
+
import com.solana.mobilewalletadapter.walletlib.association.AssociationUri
|
|
9
|
+
import com.solana.mobilewalletadapter.walletlib.association.LocalAssociationUri
|
|
10
|
+
import com.solana.mobilewalletadapter.walletlib.authorization.AuthIssuerConfig
|
|
11
|
+
import com.solana.mobilewalletadapter.walletlib.scenario.*
|
|
12
|
+
import com.solana.mobilewalletadapter.walletlib.scenario.AuthorizedAccount
|
|
13
|
+
import com.solanamobile.mobilewalletadapterwalletlib.reactnative.model.*
|
|
14
|
+
import java.util.UUID
|
|
15
|
+
import kotlinx.coroutines.*
|
|
16
|
+
import kotlinx.serialization.json.Json
|
|
17
|
+
import kotlinx.serialization.json.JsonObject
|
|
18
|
+
import kotlinx.serialization.json.JsonPrimitive
|
|
19
|
+
import kotlinx.serialization.json.jsonObject
|
|
20
|
+
|
|
21
|
+
enum class ErrorCode(val code: String) {
|
|
22
|
+
ERROR_INTENT_DATA_NOT_FOUND("ERROR_INTENT_DATA_NOT_FOUND"),
|
|
23
|
+
ERROR_SESSION_ALREADY_CREATED("ERROR_SESSION_ALREADY_CREATED"),
|
|
24
|
+
ERROR_UNSUPPORTED_ASSOCIATION_URI("ERROR_UNSUPPORTED_ASSOCIATION_URI"),
|
|
25
|
+
ERROR_UNSUPPORTED_ASSOCIATION_TYPE("ERROR_UNSUPPORTED_ASSOCIATION_TYPE")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class SolanaMobileWalletAdapterWalletLibModule(val reactContext: ReactApplicationContext) :
|
|
29
|
+
ReactContextBaseJavaModule(reactContext), CoroutineScope {
|
|
30
|
+
|
|
31
|
+
private val json = Json { ignoreUnknownKeys = true }
|
|
32
|
+
|
|
33
|
+
// Sets the name of the module in React, accessible at
|
|
34
|
+
// ReactNative.NativeModules.SolanaMobileWalletAdapterWalletLib
|
|
35
|
+
override fun getName() = "SolanaMobileWalletAdapterWalletLib"
|
|
36
|
+
|
|
37
|
+
override val coroutineContext =
|
|
38
|
+
Dispatchers.IO + CoroutineName("SolanaMobileWalletAdapterWalletLibModuleScope") + SupervisorJob()
|
|
39
|
+
|
|
40
|
+
// Session events that notify about the lifecycle of the Scenario session. We are choosing
|
|
41
|
+
// to go with the naming convention Session rather than Scenario for readability.
|
|
42
|
+
sealed interface MobileWalletAdapterSessionEvent {
|
|
43
|
+
val type: String
|
|
44
|
+
object None : MobileWalletAdapterSessionEvent {
|
|
45
|
+
override val type: String = ""
|
|
46
|
+
}
|
|
47
|
+
object SessionTerminated : MobileWalletAdapterSessionEvent {
|
|
48
|
+
override val type: String = "SESSION_TERMINATED"
|
|
49
|
+
}
|
|
50
|
+
object ScenarioReady : MobileWalletAdapterSessionEvent {
|
|
51
|
+
override val type: String = "SESSION_READY"
|
|
52
|
+
}
|
|
53
|
+
object ScenarioServingClients : MobileWalletAdapterSessionEvent {
|
|
54
|
+
override val type: String = "SESSION_SERVING_CLIENTS"
|
|
55
|
+
}
|
|
56
|
+
object ScenarioServingComplete : MobileWalletAdapterSessionEvent {
|
|
57
|
+
override val type: String = "SESSION_SERVING_COMPLETE"
|
|
58
|
+
}
|
|
59
|
+
object ScenarioComplete : MobileWalletAdapterSessionEvent {
|
|
60
|
+
override val type: String = "SESSION_COMPLETE"
|
|
61
|
+
}
|
|
62
|
+
class ScenarioError(val message: String? = null) : MobileWalletAdapterSessionEvent {
|
|
63
|
+
override val type: String = "SESSION_ERROR"
|
|
64
|
+
}
|
|
65
|
+
object ScenarioTeardownComplete : MobileWalletAdapterSessionEvent {
|
|
66
|
+
override val type: String = "SESSION_TEARDOWN_COMPLETE"
|
|
67
|
+
}
|
|
68
|
+
object LowPowerNoConnection : MobileWalletAdapterSessionEvent {
|
|
69
|
+
override val type: String = "LOW_POWER_NO_CONNECTION"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Service requests that come from the dApp for Authorization, Signing, Sending, hence
|
|
74
|
+
// "RemoteRequest".
|
|
75
|
+
sealed class MobileWalletAdapterRemoteRequest(
|
|
76
|
+
open val request: ScenarioRequest,
|
|
77
|
+
val id: String = UUID.randomUUID().toString()
|
|
78
|
+
) {
|
|
79
|
+
data class AuthorizeDapp(override val request: AuthorizeRequest) :
|
|
80
|
+
MobileWalletAdapterRemoteRequest(request)
|
|
81
|
+
|
|
82
|
+
data class ReauthorizeDapp(override val request: ReauthorizeRequest) :
|
|
83
|
+
MobileWalletAdapterRemoteRequest(request)
|
|
84
|
+
|
|
85
|
+
data class DeauthorizeDapp(override val request: DeauthorizedEvent) :
|
|
86
|
+
MobileWalletAdapterRemoteRequest(request)
|
|
87
|
+
|
|
88
|
+
sealed class SignPayloads(override val request: SignPayloadsRequest) :
|
|
89
|
+
MobileWalletAdapterRemoteRequest(request)
|
|
90
|
+
|
|
91
|
+
data class SignTransactions(override val request: SignTransactionsRequest) :
|
|
92
|
+
SignPayloads(request)
|
|
93
|
+
|
|
94
|
+
data class SignMessages(override val request: SignMessagesRequest) :
|
|
95
|
+
SignPayloads(request)
|
|
96
|
+
|
|
97
|
+
data class SignAndSendTransactions(
|
|
98
|
+
override val request: SignAndSendTransactionsRequest,
|
|
99
|
+
val endpointUri: Uri,
|
|
100
|
+
) : MobileWalletAdapterRemoteRequest(request)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// currently we only allow a single scenario to exist at a time
|
|
104
|
+
private var scenarioId: String? = null
|
|
105
|
+
private var scenarioUri: Uri? = null
|
|
106
|
+
private var scenario: Scenario? = null
|
|
107
|
+
set(value) {
|
|
108
|
+
value?.let { scenarioId = UUID.randomUUID().toString() }
|
|
109
|
+
?: run {
|
|
110
|
+
scenarioUri = null
|
|
111
|
+
scenarioId = null
|
|
112
|
+
scenario?.close()
|
|
113
|
+
}
|
|
114
|
+
pendingRequests.clear()
|
|
115
|
+
field = value
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// very basic/naive implememtion of request cache.
|
|
119
|
+
// we could replace this with an abstraction that has expiration, persistance, etc.
|
|
120
|
+
private val pendingRequests = mutableMapOf<String, MobileWalletAdapterRemoteRequest>()
|
|
121
|
+
|
|
122
|
+
private fun clusterToRpcUri(cluster: String?): Uri {
|
|
123
|
+
return when (cluster) {
|
|
124
|
+
ProtocolContract.CLUSTER_MAINNET_BETA ->
|
|
125
|
+
Uri.parse("https://api.mainnet-beta.solana.com")
|
|
126
|
+
|
|
127
|
+
ProtocolContract.CLUSTER_DEVNET ->
|
|
128
|
+
Uri.parse("https://api.devnet.solana.com")
|
|
129
|
+
|
|
130
|
+
else -> Uri.parse("https://api.testnet.solana.com")
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
@ReactMethod
|
|
134
|
+
fun createScenario(
|
|
135
|
+
walletName: String,
|
|
136
|
+
config: String,
|
|
137
|
+
promise: Promise,
|
|
138
|
+
) = launch {
|
|
139
|
+
// Get the intent that started this activity
|
|
140
|
+
val intent = reactContext.getCurrentActivity()?.intent
|
|
141
|
+
if (intent == null) {
|
|
142
|
+
Log.e(TAG, "Unable to get intent in current context")
|
|
143
|
+
promise.reject(ErrorCode.ERROR_INTENT_DATA_NOT_FOUND.code, "Unable to get intent in current context")
|
|
144
|
+
return@launch
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Get the data from the intent and parse into URI
|
|
148
|
+
val data = intent.data
|
|
149
|
+
if (data == null) {
|
|
150
|
+
Log.e(TAG, "Unable to get intent data in current context")
|
|
151
|
+
promise.reject(ErrorCode.ERROR_INTENT_DATA_NOT_FOUND.code, "Unable to get intent data in current context")
|
|
152
|
+
return@launch
|
|
153
|
+
}
|
|
154
|
+
val uri = Uri.parse(data.toString())
|
|
155
|
+
|
|
156
|
+
// TODO: this is dirty, need some stateful object/data to know what state we are in.
|
|
157
|
+
// also, should we support multiple simultaneous scenarios?
|
|
158
|
+
if (uri == scenarioUri && scenario != null) {
|
|
159
|
+
Log.w(TAG, "Session already created for uri: $uri")
|
|
160
|
+
promise.reject(ErrorCode.ERROR_SESSION_ALREADY_CREATED.code, "Session already created for uri: $uri")
|
|
161
|
+
return@launch
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
val associationUri = AssociationUri.parse(uri)
|
|
165
|
+
if (associationUri == null) {
|
|
166
|
+
Log.e(TAG, "Unsupported association URI: $uri")
|
|
167
|
+
promise.reject(ErrorCode.ERROR_UNSUPPORTED_ASSOCIATION_URI.code, "Unsupported association URI: $uri")
|
|
168
|
+
return@launch
|
|
169
|
+
} else if (associationUri !is LocalAssociationUri) {
|
|
170
|
+
Log.e(TAG, "Current implementation of fakewallet does not support remote clients")
|
|
171
|
+
promise.reject(ErrorCode.ERROR_UNSUPPORTED_ASSOCIATION_TYPE.code, "Current implementation of fakewallet does not support remote clients")
|
|
172
|
+
return@launch
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
scenarioUri = uri
|
|
176
|
+
|
|
177
|
+
val kotlinConfig =
|
|
178
|
+
json.decodeFromString(MobileWalletAdapterConfigSerializer, config)
|
|
179
|
+
|
|
180
|
+
// created a scenario, told it to start (kicks off some threads in the background)
|
|
181
|
+
// we've kept a reference to it in the global state of this module (scenario)
|
|
182
|
+
// this won't be garbage collected and will just run, sit & wait for an incoming
|
|
183
|
+
// connection
|
|
184
|
+
scenario =
|
|
185
|
+
associationUri.createScenario(
|
|
186
|
+
reactContext,
|
|
187
|
+
kotlinConfig,
|
|
188
|
+
AuthIssuerConfig(walletName),
|
|
189
|
+
MobileWalletAdapterScenarioCallbacks()
|
|
190
|
+
).also {
|
|
191
|
+
it.start()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
promise.resolve(scenarioId)
|
|
195
|
+
Log.d(TAG, "scenario created: $walletName")
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Generic Request functions */
|
|
199
|
+
@ReactMethod
|
|
200
|
+
fun cancelRequest(sessionId: String, requestId: String) {
|
|
201
|
+
Log.d(TAG, "Cancelled request $requestId")
|
|
202
|
+
(pendingRequests.remove(requestId) as? ScenarioRequest)?.let { scenarioRequest ->
|
|
203
|
+
scenarioRequest.cancel()
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@ReactMethod
|
|
208
|
+
fun resolve(requestJson: String, responseJson: String) = launch {
|
|
209
|
+
val completedRequest =
|
|
210
|
+
json.decodeFromString(
|
|
211
|
+
MobileWalletAdapterRequestSerializer,
|
|
212
|
+
requestJson
|
|
213
|
+
)
|
|
214
|
+
val response =
|
|
215
|
+
json.decodeFromString(
|
|
216
|
+
MobileWalletAdapterResponseSerializer,
|
|
217
|
+
responseJson
|
|
218
|
+
)
|
|
219
|
+
val pendingRequest = pendingRequests[completedRequest.requestId]
|
|
220
|
+
|
|
221
|
+
if (completedRequest.sessionId != scenarioId) {
|
|
222
|
+
sendSessionEventToReact(
|
|
223
|
+
MobileWalletAdapterSessionEvent.ScenarioError(
|
|
224
|
+
"Invalid session (${completedRequest.sessionId}). This session does not exist/is no longer active."
|
|
225
|
+
)
|
|
226
|
+
)
|
|
227
|
+
return@launch
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
fun completeWithInvalidResponse() {
|
|
231
|
+
pendingRequest?.request?.completeWithInternalError(
|
|
232
|
+
Exception("Invalid Response For Request: response = $responseJson")
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
when (completedRequest) {
|
|
237
|
+
is AuthorizeDapp ->
|
|
238
|
+
when (response) {
|
|
239
|
+
is MobileWalletAdapterFailureResponse -> {
|
|
240
|
+
when (response) {
|
|
241
|
+
is UserDeclinedResponse ->
|
|
242
|
+
(pendingRequest as?
|
|
243
|
+
MobileWalletAdapterRemoteRequest.AuthorizeDapp)
|
|
244
|
+
?.request
|
|
245
|
+
?.completeWithDecline()
|
|
246
|
+
|
|
247
|
+
else ->
|
|
248
|
+
completeWithInvalidResponse()
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
is AuthorizeDappResponse ->
|
|
253
|
+
(pendingRequest as?
|
|
254
|
+
MobileWalletAdapterRemoteRequest.AuthorizeDapp)
|
|
255
|
+
?.request
|
|
256
|
+
?.completeWithAuthorize(
|
|
257
|
+
response.accounts
|
|
258
|
+
.first()
|
|
259
|
+
.let { account
|
|
260
|
+
->
|
|
261
|
+
AuthorizedAccount(
|
|
262
|
+
account.publicKey,
|
|
263
|
+
account.accountLabel,
|
|
264
|
+
account.icon
|
|
265
|
+
?.let {
|
|
266
|
+
Uri.parse(
|
|
267
|
+
it
|
|
268
|
+
)
|
|
269
|
+
},
|
|
270
|
+
account.chains
|
|
271
|
+
?.toTypedArray(),
|
|
272
|
+
account.features
|
|
273
|
+
?.toTypedArray()
|
|
274
|
+
)
|
|
275
|
+
},
|
|
276
|
+
response.walletUriBase
|
|
277
|
+
?.let {
|
|
278
|
+
Uri.parse(
|
|
279
|
+
response.walletUriBase
|
|
280
|
+
)
|
|
281
|
+
},
|
|
282
|
+
response.authorizationScope,
|
|
283
|
+
response.signInResult
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
else -> completeWithInvalidResponse()
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
is ReauthorizeDapp ->
|
|
290
|
+
when (response) {
|
|
291
|
+
is MobileWalletAdapterFailureResponse -> {
|
|
292
|
+
when (response) {
|
|
293
|
+
is AuthorizationNotValidResponse ->
|
|
294
|
+
(pendingRequest as?
|
|
295
|
+
MobileWalletAdapterRemoteRequest.ReauthorizeDapp)
|
|
296
|
+
?.request
|
|
297
|
+
?.completeWithDecline()
|
|
298
|
+
|
|
299
|
+
else ->
|
|
300
|
+
completeWithInvalidResponse()
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
is ReauthorizeDappResponse ->
|
|
305
|
+
(pendingRequest as?
|
|
306
|
+
MobileWalletAdapterRemoteRequest.ReauthorizeDapp)
|
|
307
|
+
?.request
|
|
308
|
+
?.completeWithReauthorize()
|
|
309
|
+
|
|
310
|
+
else -> completeWithInvalidResponse()
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
is DeauthorizeDapp ->
|
|
314
|
+
when (response) {
|
|
315
|
+
is DeauthorizeDappResponse ->
|
|
316
|
+
(pendingRequest as?
|
|
317
|
+
MobileWalletAdapterRemoteRequest.DeauthorizeDapp)
|
|
318
|
+
?.request
|
|
319
|
+
?.complete()
|
|
320
|
+
|
|
321
|
+
else -> completeWithInvalidResponse()
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
is SignAndSendTransactions ->
|
|
325
|
+
when (response) {
|
|
326
|
+
is MobileWalletAdapterFailureResponse -> {
|
|
327
|
+
when (response) {
|
|
328
|
+
is UserDeclinedResponse ->
|
|
329
|
+
(pendingRequest as?
|
|
330
|
+
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
331
|
+
?.request
|
|
332
|
+
?.completeWithDecline()
|
|
333
|
+
|
|
334
|
+
is TooManyPayloadsResponse ->
|
|
335
|
+
(pendingRequest as?
|
|
336
|
+
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
337
|
+
?.request
|
|
338
|
+
?.completeWithTooManyPayloads()
|
|
339
|
+
|
|
340
|
+
is AuthorizationNotValidResponse ->
|
|
341
|
+
(pendingRequest as?
|
|
342
|
+
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
343
|
+
?.request
|
|
344
|
+
?.completeWithAuthorizationNotValid()
|
|
345
|
+
|
|
346
|
+
is InvalidSignaturesResponse ->
|
|
347
|
+
(pendingRequest as?
|
|
348
|
+
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
349
|
+
?.request
|
|
350
|
+
?.completeWithInvalidSignatures(
|
|
351
|
+
response.valid
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
is SignedAndSentTransactions ->
|
|
357
|
+
(pendingRequest as?
|
|
358
|
+
MobileWalletAdapterRemoteRequest.SignAndSendTransactions)
|
|
359
|
+
?.request
|
|
360
|
+
?.completeWithSignatures(
|
|
361
|
+
response.signedTransactions
|
|
362
|
+
.toTypedArray()
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
else -> completeWithInvalidResponse()
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
is SignPayloads ->
|
|
369
|
+
when (response) {
|
|
370
|
+
is MobileWalletAdapterFailureResponse -> {
|
|
371
|
+
when (response) {
|
|
372
|
+
is UserDeclinedResponse ->
|
|
373
|
+
(pendingRequest as?
|
|
374
|
+
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
375
|
+
?.request
|
|
376
|
+
?.completeWithDecline()
|
|
377
|
+
|
|
378
|
+
is TooManyPayloadsResponse ->
|
|
379
|
+
(pendingRequest as?
|
|
380
|
+
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
381
|
+
?.request
|
|
382
|
+
?.completeWithTooManyPayloads()
|
|
383
|
+
|
|
384
|
+
is AuthorizationNotValidResponse ->
|
|
385
|
+
(pendingRequest as?
|
|
386
|
+
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
387
|
+
?.request
|
|
388
|
+
?.completeWithAuthorizationNotValid()
|
|
389
|
+
|
|
390
|
+
is InvalidSignaturesResponse ->
|
|
391
|
+
(pendingRequest as?
|
|
392
|
+
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
393
|
+
?.request
|
|
394
|
+
?.completeWithInvalidPayloads(
|
|
395
|
+
response.valid
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
is SignedPayloads ->
|
|
401
|
+
(pendingRequest as?
|
|
402
|
+
MobileWalletAdapterRemoteRequest.SignPayloads)
|
|
403
|
+
?.request
|
|
404
|
+
?.completeWithSignedPayloads(
|
|
405
|
+
response.signedPayloads
|
|
406
|
+
.toTypedArray()
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
else -> completeWithInvalidResponse()
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private fun checkSessionId(sessionId: String, doIfValid: (() -> Unit)) =
|
|
415
|
+
if (sessionId == scenarioId) doIfValid()
|
|
416
|
+
else
|
|
417
|
+
sendSessionEventToReact(
|
|
418
|
+
MobileWalletAdapterSessionEvent
|
|
419
|
+
.ScenarioError(
|
|
420
|
+
"Invalid session ($sessionId). This session does not exist/is no longer active."
|
|
421
|
+
)
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
private fun sendSessionEventToReact(sessionEvent: MobileWalletAdapterSessionEvent) {
|
|
425
|
+
val eventInfo =
|
|
426
|
+
when (sessionEvent) {
|
|
427
|
+
is MobileWalletAdapterSessionEvent.None -> null
|
|
428
|
+
is MobileWalletAdapterSessionEvent.ScenarioError ->
|
|
429
|
+
Arguments.createMap().apply {
|
|
430
|
+
putString(
|
|
431
|
+
"__type",
|
|
432
|
+
sessionEvent.type
|
|
433
|
+
)
|
|
434
|
+
putString(
|
|
435
|
+
"error",
|
|
436
|
+
sessionEvent.message
|
|
437
|
+
)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
else ->
|
|
441
|
+
Arguments.createMap().apply {
|
|
442
|
+
putString(
|
|
443
|
+
"__type",
|
|
444
|
+
sessionEvent.type
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
eventInfo?.putString("sessionId", scenarioId)
|
|
450
|
+
|
|
451
|
+
eventInfo?.let {
|
|
452
|
+
sendEvent(
|
|
453
|
+
reactContext,
|
|
454
|
+
Companion.MOBILE_WALLET_ADAPTER_SERVICE_REQUEST_BRIDGE_NAME,
|
|
455
|
+
it
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private fun sendWalletServiceRequestToReact(request: MobileWalletAdapterRemoteRequest) {
|
|
461
|
+
val surrogate =
|
|
462
|
+
when (request) {
|
|
463
|
+
is MobileWalletAdapterRemoteRequest.AuthorizeDapp ->
|
|
464
|
+
AuthorizeDapp(
|
|
465
|
+
scenarioId!!,
|
|
466
|
+
request.request.chain,
|
|
467
|
+
request.request
|
|
468
|
+
.identityName,
|
|
469
|
+
request.request.identityUri
|
|
470
|
+
.toString(),
|
|
471
|
+
request.request
|
|
472
|
+
.iconRelativeUri
|
|
473
|
+
.toString(),
|
|
474
|
+
request.request.features
|
|
475
|
+
?.asList(),
|
|
476
|
+
request.request.addresses
|
|
477
|
+
?.asList(),
|
|
478
|
+
request.request
|
|
479
|
+
.signInPayload
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
is MobileWalletAdapterRemoteRequest.ReauthorizeDapp ->
|
|
483
|
+
ReauthorizeDapp(
|
|
484
|
+
scenarioId!!,
|
|
485
|
+
request.request.chain,
|
|
486
|
+
request.request
|
|
487
|
+
.identityName,
|
|
488
|
+
request.request.identityUri
|
|
489
|
+
.toString(),
|
|
490
|
+
request.request
|
|
491
|
+
.iconRelativeUri
|
|
492
|
+
.toString(),
|
|
493
|
+
request.request
|
|
494
|
+
.authorizationScope
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
is MobileWalletAdapterRemoteRequest.DeauthorizeDapp ->
|
|
498
|
+
DeauthorizeDapp(
|
|
499
|
+
scenarioId!!,
|
|
500
|
+
request.request.chain,
|
|
501
|
+
request.request
|
|
502
|
+
.identityName,
|
|
503
|
+
request.request.identityUri
|
|
504
|
+
.toString(),
|
|
505
|
+
request.request
|
|
506
|
+
.iconRelativeUri
|
|
507
|
+
.toString(),
|
|
508
|
+
request.request
|
|
509
|
+
.authorizationScope
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
is MobileWalletAdapterRemoteRequest.SignMessages ->
|
|
513
|
+
SignMessages(
|
|
514
|
+
scenarioId!!,
|
|
515
|
+
request.request.chain,
|
|
516
|
+
request.request
|
|
517
|
+
.identityName,
|
|
518
|
+
request.request.identityUri
|
|
519
|
+
.toString(),
|
|
520
|
+
request.request
|
|
521
|
+
.iconRelativeUri
|
|
522
|
+
.toString(),
|
|
523
|
+
request.request
|
|
524
|
+
.authorizationScope,
|
|
525
|
+
request.request.payloads
|
|
526
|
+
.toList()
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
is MobileWalletAdapterRemoteRequest.SignTransactions ->
|
|
530
|
+
SignTransactions(
|
|
531
|
+
scenarioId!!,
|
|
532
|
+
request.request.chain,
|
|
533
|
+
request.request
|
|
534
|
+
.identityName,
|
|
535
|
+
request.request.identityUri
|
|
536
|
+
.toString(),
|
|
537
|
+
request.request
|
|
538
|
+
.iconRelativeUri
|
|
539
|
+
.toString(),
|
|
540
|
+
request.request
|
|
541
|
+
.authorizationScope,
|
|
542
|
+
request.request.payloads
|
|
543
|
+
.toList()
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
is MobileWalletAdapterRemoteRequest.SignAndSendTransactions ->
|
|
547
|
+
SignAndSendTransactions(
|
|
548
|
+
scenarioId!!,
|
|
549
|
+
request.request.chain,
|
|
550
|
+
request.request
|
|
551
|
+
.identityName,
|
|
552
|
+
request.request.identityUri
|
|
553
|
+
.toString(),
|
|
554
|
+
request.request
|
|
555
|
+
.iconRelativeUri
|
|
556
|
+
.toString(),
|
|
557
|
+
request.request
|
|
558
|
+
.authorizationScope,
|
|
559
|
+
request.request.payloads
|
|
560
|
+
.toList()
|
|
561
|
+
)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// this is dirty, the requestId needs to line up so have to manually overwrite here
|
|
565
|
+
// should we change javascript side to accept json?
|
|
566
|
+
val eventInfo =
|
|
567
|
+
JsonObject(
|
|
568
|
+
json.encodeToJsonElement(
|
|
569
|
+
MobileWalletAdapterRequestSerializer,
|
|
570
|
+
surrogate
|
|
571
|
+
)
|
|
572
|
+
.jsonObject
|
|
573
|
+
.toMutableMap()
|
|
574
|
+
.apply {
|
|
575
|
+
put(
|
|
576
|
+
"requestId",
|
|
577
|
+
JsonPrimitive(
|
|
578
|
+
request.id
|
|
579
|
+
)
|
|
580
|
+
)
|
|
581
|
+
}
|
|
582
|
+
)
|
|
583
|
+
.toReadableMap()
|
|
584
|
+
|
|
585
|
+
sendEvent(
|
|
586
|
+
reactContext,
|
|
587
|
+
Companion.MOBILE_WALLET_ADAPTER_SERVICE_REQUEST_BRIDGE_NAME,
|
|
588
|
+
eventInfo
|
|
589
|
+
)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
private fun sendEvent(
|
|
593
|
+
reactContext: ReactContext,
|
|
594
|
+
eventName: String,
|
|
595
|
+
params: ReadableMap? = null
|
|
596
|
+
) {
|
|
597
|
+
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
598
|
+
.emit(eventName, params)
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
private inner class MobileWalletAdapterScenarioCallbacks : LocalScenario.Callbacks {
|
|
602
|
+
/* Session Events */
|
|
603
|
+
override fun onScenarioReady() {
|
|
604
|
+
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioReady)
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
override fun onScenarioServingClients() {
|
|
608
|
+
sendSessionEventToReact(
|
|
609
|
+
MobileWalletAdapterSessionEvent.ScenarioServingClients
|
|
610
|
+
)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
override fun onScenarioServingComplete() {
|
|
614
|
+
launch(Dispatchers.Main) {
|
|
615
|
+
scenario = null
|
|
616
|
+
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioServingComplete)
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
override fun onScenarioComplete() {
|
|
621
|
+
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioComplete)
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
override fun onScenarioError() {
|
|
625
|
+
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioError())
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
override fun onScenarioTeardownComplete() {
|
|
629
|
+
sendSessionEventToReact(MobileWalletAdapterSessionEvent.ScenarioTeardownComplete)
|
|
630
|
+
sendSessionEventToReact(MobileWalletAdapterSessionEvent.SessionTerminated)
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
override fun onLowPowerAndNoConnection() {
|
|
634
|
+
sendSessionEventToReact(
|
|
635
|
+
MobileWalletAdapterSessionEvent.LowPowerNoConnection
|
|
636
|
+
)
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* Remote Requests */
|
|
640
|
+
override fun onAuthorizeRequest(request: AuthorizeRequest) {
|
|
641
|
+
val request = MobileWalletAdapterRemoteRequest.AuthorizeDapp(request)
|
|
642
|
+
pendingRequests.put(request.id, request)
|
|
643
|
+
sendWalletServiceRequestToReact(request)
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
override fun onReauthorizeRequest(request: ReauthorizeRequest) {
|
|
647
|
+
val request = MobileWalletAdapterRemoteRequest.ReauthorizeDapp(request)
|
|
648
|
+
pendingRequests.put(request.id, request)
|
|
649
|
+
sendWalletServiceRequestToReact(request)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
override fun onSignTransactionsRequest(request: SignTransactionsRequest) {
|
|
653
|
+
val request = MobileWalletAdapterRemoteRequest.SignTransactions(request)
|
|
654
|
+
pendingRequests.put(request.id, request)
|
|
655
|
+
sendWalletServiceRequestToReact(request)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
override fun onSignMessagesRequest(request: SignMessagesRequest) {
|
|
659
|
+
val request = MobileWalletAdapterRemoteRequest.SignMessages(request)
|
|
660
|
+
pendingRequests.put(request.id, request)
|
|
661
|
+
sendWalletServiceRequestToReact(request)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
override fun onSignAndSendTransactionsRequest(
|
|
665
|
+
request: SignAndSendTransactionsRequest
|
|
666
|
+
) {
|
|
667
|
+
val endpointUri = clusterToRpcUri(request.cluster)
|
|
668
|
+
val request =
|
|
669
|
+
MobileWalletAdapterRemoteRequest.SignAndSendTransactions(
|
|
670
|
+
request,
|
|
671
|
+
endpointUri
|
|
672
|
+
)
|
|
673
|
+
pendingRequests.put(request.id, request)
|
|
674
|
+
sendWalletServiceRequestToReact(request)
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
override fun onDeauthorizedEvent(event: DeauthorizedEvent) {
|
|
678
|
+
val request = MobileWalletAdapterRemoteRequest.DeauthorizeDapp(event)
|
|
679
|
+
pendingRequests.put(request.id, request)
|
|
680
|
+
sendWalletServiceRequestToReact(request)
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
companion object {
|
|
685
|
+
private val TAG = SolanaMobileWalletAdapterWalletLibModule::class.simpleName
|
|
686
|
+
const val MOBILE_WALLET_ADAPTER_SERVICE_REQUEST_BRIDGE_NAME =
|
|
687
|
+
"MobileWalletAdapterServiceRequestBridge"
|
|
688
|
+
const val MOBILE_WALLET_ADAPTER_SESSION_EVENT_BRIDGE_NAME =
|
|
689
|
+
"MobileWalletAdapterSessionEventBridge"
|
|
690
|
+
}
|
|
691
|
+
}
|