@stripe/stripe-react-native 0.69.0 → 0.71.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.
- package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +8 -0
- package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +9 -8
- package/android/src/oldarch/java/com/reactnativestripesdk/NativeOnrampSdkModuleSpec.java +8 -0
- package/android/src/onramp/java/com/reactnativestripesdk/OnrampErrors.kt +22 -8
- package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +48 -0
- package/android/src/onramp/java/com/reactnativestripesdk/OnrampSdkModule.kt +62 -0
- package/android/src/test/java/com/reactnativestripesdk/OnrampErrorsTest.kt +103 -26
- package/android/src/test/java/com/reactnativestripesdk/mappers/MappersTest.kt +10 -0
- package/android/src/test/java/com/reactnativestripesdk/mappers/OnrampMappersTest.kt +37 -0
- package/android/src/test/java/com/reactnativestripesdk/mappers/PaymentMethodMappersTest.kt +110 -0
- package/ios/Mappers.swift +21 -0
- package/ios/OnrampErrors.swift +23 -8
- package/ios/PaymentMethodFactory.swift +9 -0
- package/ios/StripeOnrampSdk.mm +16 -0
- package/ios/StripeSdkImpl.swift +56 -0
- package/jest/setup.js +2 -0
- package/lib/commonjs/components/StripeProvider.js +1 -1
- package/lib/commonjs/components/StripeProvider.js.map +1 -1
- package/lib/commonjs/hooks/useOnramp.js +1 -1
- package/lib/commonjs/hooks/useOnramp.js.map +1 -1
- package/lib/commonjs/specs/NativeOnrampSdkModule.js.map +1 -1
- package/lib/commonjs/types/Onramp.js +1 -1
- package/lib/commonjs/types/Onramp.js.map +1 -1
- package/lib/commonjs/types/PaymentIntent.js.map +1 -1
- package/lib/module/components/StripeProvider.js +1 -1
- package/lib/module/components/StripeProvider.js.map +1 -1
- package/lib/module/hooks/useOnramp.js +1 -1
- package/lib/module/hooks/useOnramp.js.map +1 -1
- package/lib/module/specs/NativeOnrampSdkModule.js.map +1 -1
- package/lib/module/types/Onramp.js +1 -1
- package/lib/module/types/Onramp.js.map +1 -1
- package/lib/module/types/PaymentIntent.js.map +1 -1
- package/lib/typescript/src/components/StripeProvider.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useOnramp.d.ts +18 -0
- package/lib/typescript/src/hooks/useOnramp.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts +2 -0
- package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts.map +1 -1
- package/lib/typescript/src/types/Onramp.d.ts +84 -10
- package/lib/typescript/src/types/Onramp.d.ts.map +1 -1
- package/lib/typescript/src/types/PaymentIntent.d.ts +9 -1
- package/lib/typescript/src/types/PaymentIntent.d.ts.map +1 -1
- package/lib/typescript/src/types/PaymentMethod.d.ts +1 -1
- package/lib/typescript/src/types/PaymentMethod.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/StripeProvider.tsx +0 -2
- package/src/hooks/useOnramp.tsx +50 -83
- package/src/specs/NativeOnrampSdkModule.ts +8 -0
- package/src/types/Onramp.ts +100 -9
- package/src/types/PaymentIntent.ts +11 -1
- package/src/types/PaymentMethod.ts +1 -0
- package/lib/commonjs/internal/stripeConfig.js +0 -2
- package/lib/commonjs/internal/stripeConfig.js.map +0 -1
- package/lib/module/internal/stripeConfig.js +0 -2
- package/lib/module/internal/stripeConfig.js.map +0 -1
- package/lib/typescript/src/internal/stripeConfig.d.ts +0 -3
- package/lib/typescript/src/internal/stripeConfig.d.ts.map +0 -1
- package/src/internal/stripeConfig.ts +0 -9
|
@@ -56,6 +56,7 @@ class PaymentMethodCreateParamsFactory(
|
|
|
56
56
|
PaymentMethod.Type.Affirm -> createAffirmParams()
|
|
57
57
|
PaymentMethod.Type.CashAppPay -> createCashAppParams()
|
|
58
58
|
PaymentMethod.Type.RevolutPay -> createRevolutPayParams()
|
|
59
|
+
PaymentMethod.Type.PayByBank -> createPayByBankParams()
|
|
59
60
|
else -> {
|
|
60
61
|
throw Exception("This paymentMethodType is not supported yet")
|
|
61
62
|
}
|
|
@@ -258,6 +259,12 @@ class PaymentMethodCreateParamsFactory(
|
|
|
258
259
|
metadata = metadataParams,
|
|
259
260
|
)
|
|
260
261
|
|
|
262
|
+
private fun createPayByBankParams(): PaymentMethodCreateParams =
|
|
263
|
+
PaymentMethodCreateParams.createPayByBank(
|
|
264
|
+
billingDetails = billingDetailsParams,
|
|
265
|
+
metadata = metadataParams,
|
|
266
|
+
)
|
|
267
|
+
|
|
261
268
|
@Throws(PaymentMethodCreateParamsException::class)
|
|
262
269
|
fun createParams(
|
|
263
270
|
clientSecret: String,
|
|
@@ -289,6 +296,7 @@ class PaymentMethodCreateParamsFactory(
|
|
|
289
296
|
PaymentMethod.Type.PayPal,
|
|
290
297
|
PaymentMethod.Type.CashAppPay,
|
|
291
298
|
PaymentMethod.Type.RevolutPay,
|
|
299
|
+
PaymentMethod.Type.PayByBank,
|
|
292
300
|
-> {
|
|
293
301
|
val params = createPaymentMethodParams(paymentMethodType)
|
|
294
302
|
|
|
@@ -151,6 +151,7 @@ internal fun mapPaymentMethodType(type: PaymentMethod.Type?): String =
|
|
|
151
151
|
PaymentMethod.Type.Affirm -> "Affirm"
|
|
152
152
|
PaymentMethod.Type.CashAppPay -> "CashApp"
|
|
153
153
|
PaymentMethod.Type.RevolutPay -> "RevolutPay"
|
|
154
|
+
PaymentMethod.Type.PayByBank -> "PayByBank"
|
|
154
155
|
PaymentMethod.Type.Link -> "Link"
|
|
155
156
|
else -> "Unknown"
|
|
156
157
|
}
|
|
@@ -182,6 +183,7 @@ internal fun mapToPaymentMethodType(type: String?): PaymentMethod.Type? =
|
|
|
182
183
|
"Affirm" -> PaymentMethod.Type.Affirm
|
|
183
184
|
"CashApp" -> PaymentMethod.Type.CashAppPay
|
|
184
185
|
"RevolutPay" -> PaymentMethod.Type.RevolutPay
|
|
186
|
+
"PayByBank" -> PaymentMethod.Type.PayByBank
|
|
185
187
|
"Link" -> PaymentMethod.Type.Link
|
|
186
188
|
else -> null
|
|
187
189
|
}
|
|
@@ -360,6 +362,11 @@ internal fun mapFromToken(token: Token): WritableMap {
|
|
|
360
362
|
return tokenMap
|
|
361
363
|
}
|
|
362
364
|
|
|
365
|
+
private fun mapFromStringList(list: Collection<String>?): WritableArray? =
|
|
366
|
+
list?.let { networks ->
|
|
367
|
+
Arguments.createArray().also { arr -> networks.forEach { arr.pushString(it) } }
|
|
368
|
+
}
|
|
369
|
+
|
|
363
370
|
internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
|
|
364
371
|
val pm: WritableMap = Arguments.createMap()
|
|
365
372
|
|
|
@@ -379,13 +386,7 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
|
|
|
379
386
|
it.putString("last4", paymentMethod.card?.last4)
|
|
380
387
|
it.putString("fingerprint", paymentMethod.card?.fingerprint)
|
|
381
388
|
it.putString("preferredNetwork", paymentMethod.card?.networks?.preferred)
|
|
382
|
-
it.putArray(
|
|
383
|
-
"availableNetworks",
|
|
384
|
-
paymentMethod.card
|
|
385
|
-
?.networks
|
|
386
|
-
?.available
|
|
387
|
-
?.toList() as? ReadableArray,
|
|
388
|
-
)
|
|
389
|
+
it.putArray("availableNetworks", mapFromStringList(paymentMethod.card?.networks?.available))
|
|
389
390
|
it.putMap(
|
|
390
391
|
"threeDSecureUsage",
|
|
391
392
|
Arguments.createMap().also { threeDSecureUsageMap ->
|
|
@@ -455,7 +456,7 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
|
|
|
455
456
|
it.putString("preferredNetworks", paymentMethod.usBankAccount?.networks?.preferred)
|
|
456
457
|
it.putArray(
|
|
457
458
|
"supportedNetworks",
|
|
458
|
-
paymentMethod.usBankAccount?.networks?.supported
|
|
459
|
+
mapFromStringList(paymentMethod.usBankAccount?.networks?.supported),
|
|
459
460
|
)
|
|
460
461
|
},
|
|
461
462
|
)
|
|
@@ -55,6 +55,14 @@ public abstract class NativeOnrampSdkModuleSpec extends ReactContextBaseJavaModu
|
|
|
55
55
|
@DoNotStrip
|
|
56
56
|
public abstract void registerWalletAddress(String walletAddress, String network, Promise promise);
|
|
57
57
|
|
|
58
|
+
@ReactMethod
|
|
59
|
+
@DoNotStrip
|
|
60
|
+
public abstract void getWalletOwnershipChallenge(String walletAddress, String network, Promise promise);
|
|
61
|
+
|
|
62
|
+
@ReactMethod
|
|
63
|
+
@DoNotStrip
|
|
64
|
+
public abstract void submitWalletOwnershipSignature(String challengeId, String signature, Promise promise);
|
|
65
|
+
|
|
58
66
|
@ReactMethod
|
|
59
67
|
@DoNotStrip
|
|
60
68
|
public abstract void attachKycInfo(ReadableMap kycInfo, Promise promise);
|
|
@@ -7,7 +7,6 @@ import com.facebook.react.bridge.WritableMap
|
|
|
7
7
|
import com.reactnativestripesdk.utils.ErrorType
|
|
8
8
|
import com.stripe.android.core.exception.StripeException
|
|
9
9
|
import com.stripe.android.crypto.onramp.ExperimentalCryptoOnramp
|
|
10
|
-
import com.stripe.android.crypto.onramp.exception.AppAttestationException
|
|
11
10
|
import com.stripe.android.crypto.onramp.exception.CryptoOnrampApiException
|
|
12
11
|
import com.stripe.android.crypto.onramp.exception.StripeCryptoOnrampError
|
|
13
12
|
|
|
@@ -40,16 +39,13 @@ private fun createOnrampError(
|
|
|
40
39
|
type = apiErrorContext.apiErrorType ?: stripeError?.type,
|
|
41
40
|
stripeErrorCode = apiException.code,
|
|
42
41
|
) {
|
|
43
|
-
|
|
44
|
-
putString("developerMessage", apiException.developerMessage)
|
|
45
|
-
putString("userMessage", apiException.userMessage)
|
|
42
|
+
putCommonOnrampFields(apiException, onrampErrorType)
|
|
46
43
|
putString("reason", apiErrorContext.reason)
|
|
47
44
|
putString("requestId", apiErrorContext.requestId)
|
|
48
45
|
putString("apiErrorCode", apiErrorContext.apiErrorCode)
|
|
49
46
|
putString("apiErrorType", apiErrorContext.apiErrorType)
|
|
50
47
|
putString("apiErrorMessage", apiErrorContext.apiErrorMessage)
|
|
51
48
|
putString("apiUserMessage", apiErrorContext.apiUserMessage)
|
|
52
|
-
putString("docUrl", apiErrorContext.docUrl)
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
|
|
@@ -67,11 +63,22 @@ private fun createNonApiOnrampError(
|
|
|
67
63
|
localizedMessage = error.localizedMessage,
|
|
68
64
|
stripeErrorCode = onrampError.code,
|
|
69
65
|
) {
|
|
70
|
-
|
|
71
|
-
putString("userMessage", onrampError.userMessage)
|
|
66
|
+
putCommonOnrampFields(onrampError, onrampError.toOnrampErrorType())
|
|
72
67
|
}
|
|
73
68
|
}
|
|
74
69
|
|
|
70
|
+
private fun WritableMap.putCommonOnrampFields(
|
|
71
|
+
error: StripeCryptoOnrampError,
|
|
72
|
+
onrampErrorType: String? = null,
|
|
73
|
+
) {
|
|
74
|
+
onrampErrorType?.let {
|
|
75
|
+
putString("onrampErrorType", it)
|
|
76
|
+
}
|
|
77
|
+
putString("developerMessage", error.developerMessage)
|
|
78
|
+
putString("userMessage", error.userMessage)
|
|
79
|
+
putString("docUrl", error.docUrl)
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
private fun createOnrampMessageError(
|
|
76
83
|
code: String,
|
|
77
84
|
message: String?,
|
|
@@ -79,12 +86,19 @@ private fun createOnrampMessageError(
|
|
|
79
86
|
createOnrampErrorMap(code = code, message = message)
|
|
80
87
|
|
|
81
88
|
private fun CryptoOnrampApiException.toOnrampErrorType(): String =
|
|
82
|
-
if (
|
|
89
|
+
if (code == "link_failed_to_attest_request") {
|
|
83
90
|
"AppAttestationError"
|
|
84
91
|
} else {
|
|
85
92
|
"UncategorizedApiError"
|
|
86
93
|
}
|
|
87
94
|
|
|
95
|
+
private fun StripeCryptoOnrampError.toOnrampErrorType(): String? =
|
|
96
|
+
if (code == "app_attestation_unavailable") {
|
|
97
|
+
"AppAttestationUnavailableError"
|
|
98
|
+
} else {
|
|
99
|
+
null
|
|
100
|
+
}
|
|
101
|
+
|
|
88
102
|
private fun createGenericError(
|
|
89
103
|
code: String,
|
|
90
104
|
error: Throwable,
|
|
@@ -10,10 +10,13 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
10
10
|
import com.facebook.react.bridge.WritableArray
|
|
11
11
|
import com.stripe.android.core.model.CountryCode
|
|
12
12
|
import com.stripe.android.crypto.onramp.ExperimentalCryptoOnramp
|
|
13
|
+
import com.stripe.android.crypto.onramp.model.CryptoConsumerWallet
|
|
14
|
+
import com.stripe.android.crypto.onramp.model.CryptoNetwork
|
|
13
15
|
import com.stripe.android.crypto.onramp.exception.SDKVersion
|
|
14
16
|
import com.stripe.android.crypto.onramp.model.KycInfo
|
|
15
17
|
import com.stripe.android.crypto.onramp.model.OnrampConfiguration
|
|
16
18
|
import com.stripe.android.crypto.onramp.model.PaymentMethodDisplayData
|
|
19
|
+
import com.stripe.android.crypto.onramp.model.WalletOwnershipChallenge
|
|
17
20
|
import com.stripe.android.crypto.onramp.model.compliance.ComplianceIdentifier
|
|
18
21
|
import com.stripe.android.crypto.onramp.model.compliance.ComplianceIdentifierAlternativeGroup
|
|
19
22
|
import com.stripe.android.crypto.onramp.model.compliance.ComplianceIdentifierRequirement
|
|
@@ -203,6 +206,51 @@ internal fun mapFromKycInfo(kycInfo: KycInfo): ReadableMap {
|
|
|
203
206
|
return result
|
|
204
207
|
}
|
|
205
208
|
|
|
209
|
+
internal fun mapFromWalletOwnershipChallenge(challenge: WalletOwnershipChallenge) =
|
|
210
|
+
mapFromWalletOwnershipChallenge(
|
|
211
|
+
challengeId = challenge.challengeId,
|
|
212
|
+
walletAddress = challenge.walletAddress,
|
|
213
|
+
network = challenge.network,
|
|
214
|
+
message = challenge.message,
|
|
215
|
+
expiresAt = challenge.expiresAt,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
internal fun mapFromWalletOwnershipChallenge(
|
|
219
|
+
challengeId: String,
|
|
220
|
+
walletAddress: String,
|
|
221
|
+
network: CryptoNetwork,
|
|
222
|
+
message: String,
|
|
223
|
+
expiresAt: String,
|
|
224
|
+
) =
|
|
225
|
+
Arguments.createMap().apply {
|
|
226
|
+
putString("challengeId", challengeId)
|
|
227
|
+
putString("walletAddress", walletAddress)
|
|
228
|
+
putString("network", network.value)
|
|
229
|
+
putString("message", message)
|
|
230
|
+
putString("expiresAt", expiresAt)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
internal fun mapFromCryptoConsumerWallet(wallet: CryptoConsumerWallet) =
|
|
234
|
+
mapFromCryptoConsumerWallet(
|
|
235
|
+
id = wallet.id,
|
|
236
|
+
network = wallet.network,
|
|
237
|
+
walletAddress = wallet.walletAddress,
|
|
238
|
+
verifiedOwnership = wallet.verifiedOwnership,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
internal fun mapFromCryptoConsumerWallet(
|
|
242
|
+
id: String,
|
|
243
|
+
network: CryptoNetwork,
|
|
244
|
+
walletAddress: String,
|
|
245
|
+
verifiedOwnership: Boolean,
|
|
246
|
+
) =
|
|
247
|
+
Arguments.createMap().apply {
|
|
248
|
+
putString("id", id)
|
|
249
|
+
putString("walletAddress", walletAddress)
|
|
250
|
+
putString("network", network.value)
|
|
251
|
+
putBoolean("verifiedOwnership", verifiedOwnership)
|
|
252
|
+
}
|
|
253
|
+
|
|
206
254
|
internal fun mapToComplianceIdentifiers(identifiers: ReadableArray): List<ComplianceIdentifier> {
|
|
207
255
|
val complianceIdentifiers = mutableListOf<ComplianceIdentifier>()
|
|
208
256
|
|
|
@@ -39,6 +39,7 @@ import com.stripe.android.crypto.onramp.model.OnrampCheckoutResult
|
|
|
39
39
|
import com.stripe.android.crypto.onramp.model.OnrampCollectPaymentMethodResult
|
|
40
40
|
import com.stripe.android.crypto.onramp.model.OnrampConfigurationResult
|
|
41
41
|
import com.stripe.android.crypto.onramp.model.OnrampCreateCryptoPaymentTokenResult
|
|
42
|
+
import com.stripe.android.crypto.onramp.model.OnrampGetWalletOwnershipChallengeResult
|
|
42
43
|
import com.stripe.android.crypto.onramp.model.OnrampUserAttestationResult
|
|
43
44
|
import com.stripe.android.crypto.onramp.model.OnrampHasLinkAccountResult
|
|
44
45
|
import com.stripe.android.crypto.onramp.model.OnrampLogOutResult
|
|
@@ -46,6 +47,7 @@ import com.stripe.android.crypto.onramp.model.OnrampRegisterLinkUserResult
|
|
|
46
47
|
import com.stripe.android.crypto.onramp.model.OnrampRegisterWalletAddressResult
|
|
47
48
|
import com.stripe.android.crypto.onramp.model.OnrampRetrieveMissingIdentifiersResult
|
|
48
49
|
import com.stripe.android.crypto.onramp.model.OnrampSubmitIdentifiersResult
|
|
50
|
+
import com.stripe.android.crypto.onramp.model.OnrampSubmitWalletOwnershipSignatureResult
|
|
49
51
|
import com.stripe.android.crypto.onramp.model.OnrampTokenAuthenticationResult
|
|
50
52
|
import com.stripe.android.crypto.onramp.model.OnrampUpdatePhoneNumberResult
|
|
51
53
|
import com.stripe.android.crypto.onramp.model.OnrampVerifyIdentityResult
|
|
@@ -297,6 +299,66 @@ class OnrampSdkModule(
|
|
|
297
299
|
}
|
|
298
300
|
}
|
|
299
301
|
|
|
302
|
+
@ReactMethod
|
|
303
|
+
override fun getWalletOwnershipChallenge(
|
|
304
|
+
walletAddress: String,
|
|
305
|
+
network: String,
|
|
306
|
+
promise: Promise,
|
|
307
|
+
) {
|
|
308
|
+
val coordinator =
|
|
309
|
+
onrampCoordinator ?: run {
|
|
310
|
+
promise.resolve(createOnrampNotConfiguredError())
|
|
311
|
+
return
|
|
312
|
+
}
|
|
313
|
+
CoroutineScope(Dispatchers.IO).launch {
|
|
314
|
+
val cryptoNetwork = enumValues<CryptoNetwork>().firstOrNull { it.value == network }
|
|
315
|
+
if (cryptoNetwork == null) {
|
|
316
|
+
promise.resolve(createError(ErrorType.Unknown.toString(), "Invalid network: $network"))
|
|
317
|
+
return@launch
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
when (val result = coordinator.getWalletOwnershipChallenge(walletAddress, cryptoNetwork)) {
|
|
321
|
+
is OnrampGetWalletOwnershipChallengeResult.Completed -> {
|
|
322
|
+
promise.resolve(
|
|
323
|
+
WritableNativeMap().apply {
|
|
324
|
+
putMap("challenge", mapFromWalletOwnershipChallenge(result.challenge))
|
|
325
|
+
},
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
is OnrampGetWalletOwnershipChallengeResult.Failed -> {
|
|
329
|
+
promise.resolve(createOnrampFailedError(result.error))
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
@ReactMethod
|
|
336
|
+
override fun submitWalletOwnershipSignature(
|
|
337
|
+
challengeId: String,
|
|
338
|
+
signature: String,
|
|
339
|
+
promise: Promise,
|
|
340
|
+
) {
|
|
341
|
+
val coordinator =
|
|
342
|
+
onrampCoordinator ?: run {
|
|
343
|
+
promise.resolve(createOnrampNotConfiguredError())
|
|
344
|
+
return
|
|
345
|
+
}
|
|
346
|
+
CoroutineScope(Dispatchers.IO).launch {
|
|
347
|
+
when (val result = coordinator.submitWalletOwnershipSignature(challengeId, signature)) {
|
|
348
|
+
is OnrampSubmitWalletOwnershipSignatureResult.Completed -> {
|
|
349
|
+
promise.resolve(
|
|
350
|
+
WritableNativeMap().apply {
|
|
351
|
+
putMap("consumerWallet", mapFromCryptoConsumerWallet(result.consumerWallet))
|
|
352
|
+
},
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
is OnrampSubmitWalletOwnershipSignatureResult.Failed -> {
|
|
356
|
+
promise.resolve(createOnrampFailedError(result.error))
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
300
362
|
@ReactMethod
|
|
301
363
|
override fun attachKycInfo(
|
|
302
364
|
kycInfo: ReadableMap,
|
|
@@ -17,9 +17,9 @@ import org.robolectric.RobolectricTestRunner
|
|
|
17
17
|
@RunWith(RobolectricTestRunner::class)
|
|
18
18
|
class OnrampErrorsTest {
|
|
19
19
|
@Test
|
|
20
|
-
fun
|
|
20
|
+
fun createOnrampFailedError_withAppAttestationException_preservesApiFields() {
|
|
21
21
|
val error =
|
|
22
|
-
|
|
22
|
+
createApiOnrampException(
|
|
23
23
|
className = "com.stripe.android.crypto.onramp.exception.AppAttestationException",
|
|
24
24
|
reason = "android_package_name_mismatch",
|
|
25
25
|
operation = "configure",
|
|
@@ -67,9 +67,9 @@ class OnrampErrorsTest {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
@Test
|
|
70
|
-
fun
|
|
70
|
+
fun createOnrampFailedError_withUncategorizedApiError_preservesApiFields() {
|
|
71
71
|
val error =
|
|
72
|
-
|
|
72
|
+
createApiOnrampException(
|
|
73
73
|
className = "com.stripe.android.crypto.onramp.exception.UncategorizedException",
|
|
74
74
|
reason = "consumer_session_expired",
|
|
75
75
|
operation = "authorize",
|
|
@@ -93,11 +93,50 @@ class OnrampErrorsTest {
|
|
|
93
93
|
assertEquals("authentication_error", details.getString("type"))
|
|
94
94
|
assertEquals("Session expired. Please sign in again.", details.getString("message"))
|
|
95
95
|
assertEquals("Session expired. Please sign in again.", details.getString("userMessage"))
|
|
96
|
+
assertEquals("consumer_session_expired", details.getString("reason"))
|
|
96
97
|
assertEquals("req_auth", details.getString("requestId"))
|
|
97
98
|
assertTrue(details.getString("developerMessage")!!.contains("Code: consumer_session_expired"))
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
@Test
|
|
102
|
+
fun createOnrampFailedError_withAppAttestationUnavailableException_preservesSdkErrorFields() {
|
|
103
|
+
val underlyingError = IllegalStateException("Native Link is not available")
|
|
104
|
+
val error =
|
|
105
|
+
createAppAttestationUnavailableException(
|
|
106
|
+
underlyingError = underlyingError,
|
|
107
|
+
operation = "configure",
|
|
108
|
+
appPackageName = "com.example.app",
|
|
109
|
+
mode = "test",
|
|
110
|
+
sdkVersions =
|
|
111
|
+
listOf(
|
|
112
|
+
SDKVersion(name = "stripe-android", version = "23.10.0"),
|
|
113
|
+
SDKVersion(name = "stripe-react-native", version = "0.67.0"),
|
|
114
|
+
),
|
|
115
|
+
userMessage = "This app couldn't be verified. Contact the app developer for help.",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
val details = createOnrampFailedError(error).getMap("error")
|
|
119
|
+
|
|
120
|
+
assertNotNull(details)
|
|
121
|
+
assertEquals("Failed", details!!.getString("code"))
|
|
122
|
+
assertEquals("AppAttestationUnavailableError", details.getString("onrampErrorType"))
|
|
123
|
+
assertEquals(
|
|
124
|
+
"This app couldn't be verified. Contact the app developer for help.",
|
|
125
|
+
details.getString("message"),
|
|
126
|
+
)
|
|
127
|
+
assertEquals(
|
|
128
|
+
"This app couldn't be verified. Contact the app developer for help.",
|
|
129
|
+
details.getString("localizedMessage"),
|
|
130
|
+
)
|
|
131
|
+
assertEquals(
|
|
132
|
+
"This app couldn't be verified. Contact the app developer for help.",
|
|
133
|
+
details.getString("userMessage"),
|
|
134
|
+
)
|
|
135
|
+
assertEquals("app_attestation_unavailable", details.getString("stripeErrorCode"))
|
|
136
|
+
assertTrue(details.getString("developerMessage")!!.contains("operation: configure"))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private fun createApiOnrampException(
|
|
101
140
|
className: String,
|
|
102
141
|
reason: String,
|
|
103
142
|
operation: String,
|
|
@@ -120,7 +159,7 @@ class OnrampErrorsTest {
|
|
|
120
159
|
docUrl = docUrl,
|
|
121
160
|
)
|
|
122
161
|
val cause = APIException(stripeError = stripeError, requestId = requestId)
|
|
123
|
-
val
|
|
162
|
+
val apiErrorContext =
|
|
124
163
|
APIErrorContext(
|
|
125
164
|
reason = reason,
|
|
126
165
|
apiErrorCode = apiErrorCode,
|
|
@@ -130,41 +169,79 @@ class OnrampErrorsTest {
|
|
|
130
169
|
docUrl = docUrl,
|
|
131
170
|
underlyingError = cause,
|
|
132
171
|
)
|
|
133
|
-
val diagnosticContextClass =
|
|
134
|
-
Class.forName("com.stripe.android.crypto.onramp.exception.DiagnosticContext")
|
|
135
172
|
val diagnosticContext =
|
|
136
|
-
|
|
137
|
-
.getDeclaredConstructor(
|
|
138
|
-
List::class.java,
|
|
139
|
-
String::class.java,
|
|
140
|
-
String::class.java,
|
|
141
|
-
String::class.java,
|
|
142
|
-
).apply {
|
|
143
|
-
isAccessible = true
|
|
144
|
-
}.newInstance(
|
|
145
|
-
sdkVersions,
|
|
146
|
-
operation,
|
|
147
|
-
appPackageName,
|
|
148
|
-
mode,
|
|
149
|
-
)
|
|
173
|
+
createDiagnosticContext(sdkVersions, operation, appPackageName, mode)
|
|
150
174
|
|
|
151
|
-
// The exception classes in the `com.stripe.android.crypto.onramp.exception` package
|
|
152
|
-
// don't have public constructors, so we use reflection to create instances for testing.
|
|
153
175
|
val constructor =
|
|
154
176
|
Class
|
|
155
177
|
.forName(className)
|
|
156
178
|
.getDeclaredConstructor(
|
|
157
179
|
APIErrorContext::class.java,
|
|
158
|
-
|
|
180
|
+
diagnosticContext.javaClass,
|
|
159
181
|
String::class.java,
|
|
160
182
|
).apply {
|
|
161
183
|
isAccessible = true
|
|
162
184
|
}
|
|
163
185
|
|
|
164
186
|
return constructor.newInstance(
|
|
165
|
-
|
|
187
|
+
apiErrorContext,
|
|
166
188
|
diagnosticContext,
|
|
167
189
|
userMessage,
|
|
168
190
|
) as Exception
|
|
169
191
|
}
|
|
192
|
+
|
|
193
|
+
private fun createAppAttestationUnavailableException(
|
|
194
|
+
underlyingError: Throwable,
|
|
195
|
+
operation: String,
|
|
196
|
+
appPackageName: String,
|
|
197
|
+
mode: String,
|
|
198
|
+
sdkVersions: List<SDKVersion>,
|
|
199
|
+
userMessage: String,
|
|
200
|
+
): Exception {
|
|
201
|
+
val diagnosticContext =
|
|
202
|
+
createDiagnosticContext(sdkVersions, operation, appPackageName, mode)
|
|
203
|
+
val exceptionClass =
|
|
204
|
+
Class.forName(
|
|
205
|
+
"com.stripe.android.crypto.onramp.exception.AppAttestationUnavailableException",
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
val constructor =
|
|
209
|
+
exceptionClass
|
|
210
|
+
.getDeclaredConstructor(
|
|
211
|
+
Throwable::class.java,
|
|
212
|
+
diagnosticContext.javaClass,
|
|
213
|
+
String::class.java,
|
|
214
|
+
)
|
|
215
|
+
.apply {
|
|
216
|
+
isAccessible = true
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return constructor.newInstance(
|
|
220
|
+
underlyingError,
|
|
221
|
+
diagnosticContext,
|
|
222
|
+
userMessage,
|
|
223
|
+
) as Exception
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private fun createDiagnosticContext(
|
|
227
|
+
sdkVersions: List<SDKVersion>,
|
|
228
|
+
operation: String,
|
|
229
|
+
appPackageName: String,
|
|
230
|
+
mode: String,
|
|
231
|
+
): Any {
|
|
232
|
+
val diagnosticContextClass =
|
|
233
|
+
Class.forName("com.stripe.android.crypto.onramp.exception.DiagnosticContext")
|
|
234
|
+
val constructor =
|
|
235
|
+
diagnosticContextClass
|
|
236
|
+
.getDeclaredConstructor(
|
|
237
|
+
List::class.java,
|
|
238
|
+
String::class.java,
|
|
239
|
+
String::class.java,
|
|
240
|
+
String::class.java,
|
|
241
|
+
).apply {
|
|
242
|
+
isAccessible = true
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return constructor.newInstance(sdkVersions, operation, appPackageName, mode)
|
|
246
|
+
}
|
|
170
247
|
}
|
|
@@ -96,6 +96,16 @@ class MappersTest {
|
|
|
96
96
|
assertEquals(PaymentMethod.Type.Multibanco, mapToPaymentMethodType("Multibanco"))
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
@Test
|
|
100
|
+
fun mapPaymentMethodType_PayByBank_ReturnsString() {
|
|
101
|
+
assertEquals("PayByBank", mapPaymentMethodType(PaymentMethod.Type.PayByBank))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Test
|
|
105
|
+
fun mapToPaymentMethodType_PayByBank_ReturnsType() {
|
|
106
|
+
assertEquals(PaymentMethod.Type.PayByBank, mapToPaymentMethodType("PayByBank"))
|
|
107
|
+
}
|
|
108
|
+
|
|
99
109
|
@Test
|
|
100
110
|
fun mapNextAction_DisplayMultibancoDetails_ReturnsVoucherUrl() {
|
|
101
111
|
val result =
|
|
@@ -8,7 +8,9 @@ import com.reactnativestripesdk.ComplianceIdentifierFieldException
|
|
|
8
8
|
import com.reactnativestripesdk.InvalidIdentifiersArrayException
|
|
9
9
|
import com.reactnativestripesdk.mapAppearance
|
|
10
10
|
import com.reactnativestripesdk.mapConfig
|
|
11
|
+
import com.reactnativestripesdk.mapFromCryptoConsumerWallet
|
|
11
12
|
import com.reactnativestripesdk.mapFromKycInfo
|
|
13
|
+
import com.reactnativestripesdk.mapFromWalletOwnershipChallenge
|
|
12
14
|
import com.reactnativestripesdk.mapGooglePayConfig
|
|
13
15
|
import com.reactnativestripesdk.mapPaymentDetailsType
|
|
14
16
|
import com.reactnativestripesdk.mapToComplianceIdentifiers
|
|
@@ -16,6 +18,7 @@ import com.reactnativestripesdk.utils.readableArrayOf
|
|
|
16
18
|
import com.reactnativestripesdk.utils.readableMapOf
|
|
17
19
|
import com.stripe.android.core.model.CountryCode
|
|
18
20
|
import com.stripe.android.crypto.onramp.ExperimentalCryptoOnramp
|
|
21
|
+
import com.stripe.android.crypto.onramp.model.CryptoNetwork
|
|
19
22
|
import com.stripe.android.crypto.onramp.model.KycInfo
|
|
20
23
|
import com.stripe.android.crypto.onramp.model.PaymentMethodDisplayData
|
|
21
24
|
import com.stripe.android.googlepaylauncher.GooglePayEnvironment
|
|
@@ -593,6 +596,40 @@ class OnrampMappersTest {
|
|
|
593
596
|
assertFalse(address.hasKey("state"))
|
|
594
597
|
}
|
|
595
598
|
|
|
599
|
+
@Test
|
|
600
|
+
fun mapFromWalletOwnershipChallenge_MapsAllFields() {
|
|
601
|
+
val result =
|
|
602
|
+
mapFromWalletOwnershipChallenge(
|
|
603
|
+
challengeId = "cwoc_123",
|
|
604
|
+
walletAddress = "0x1234",
|
|
605
|
+
network = CryptoNetwork.Solana,
|
|
606
|
+
message = "Sign this exact message",
|
|
607
|
+
expiresAt = "2026-07-15T16:00:00Z",
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
assertEquals("cwoc_123", result.getString("challengeId"))
|
|
611
|
+
assertEquals("0x1234", result.getString("walletAddress"))
|
|
612
|
+
assertEquals("solana", result.getString("network"))
|
|
613
|
+
assertEquals("Sign this exact message", result.getString("message"))
|
|
614
|
+
assertEquals("2026-07-15T16:00:00Z", result.getString("expiresAt"))
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
@Test
|
|
618
|
+
fun mapFromCryptoConsumerWallet_MapsAllFields() {
|
|
619
|
+
val result =
|
|
620
|
+
mapFromCryptoConsumerWallet(
|
|
621
|
+
id = "ccw_123",
|
|
622
|
+
network = CryptoNetwork.Ethereum,
|
|
623
|
+
walletAddress = "0xabcd",
|
|
624
|
+
verifiedOwnership = true,
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
assertEquals("ccw_123", result.getString("id"))
|
|
628
|
+
assertEquals("0xabcd", result.getString("walletAddress"))
|
|
629
|
+
assertEquals("ethereum", result.getString("network"))
|
|
630
|
+
assertTrue(result.getBoolean("verifiedOwnership"))
|
|
631
|
+
}
|
|
632
|
+
|
|
596
633
|
@Test
|
|
597
634
|
fun mapToComplianceIdentifiers_ValidIdentifiers_ReturnsIdentifiers() {
|
|
598
635
|
val identifiers =
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
package com.reactnativestripesdk.mappers
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import com.reactnativestripesdk.utils.mapFromPaymentMethod
|
|
5
|
+
import com.stripe.android.model.CardBrand
|
|
6
|
+
import com.stripe.android.model.PaymentMethod
|
|
7
|
+
import org.junit.Assert.assertEquals
|
|
8
|
+
import org.junit.Assert.assertNotNull
|
|
9
|
+
import org.junit.Assert.assertNull
|
|
10
|
+
import org.junit.Test
|
|
11
|
+
import org.junit.runner.RunWith
|
|
12
|
+
import org.robolectric.RobolectricTestRunner
|
|
13
|
+
|
|
14
|
+
@SuppressLint("RestrictedApi")
|
|
15
|
+
@RunWith(RobolectricTestRunner::class)
|
|
16
|
+
class PaymentMethodMappersTest {
|
|
17
|
+
@Test
|
|
18
|
+
fun mapFromPaymentMethod_CardWithNetworks_MapsAvailableNetworks() {
|
|
19
|
+
val paymentMethod =
|
|
20
|
+
PaymentMethod
|
|
21
|
+
.Builder()
|
|
22
|
+
.setId("pm_test123")
|
|
23
|
+
.setType(PaymentMethod.Type.Card)
|
|
24
|
+
.setCard(
|
|
25
|
+
PaymentMethod.Card(
|
|
26
|
+
brand = CardBrand.Discover,
|
|
27
|
+
networks = PaymentMethod.Card.Networks(available = setOf("discover")),
|
|
28
|
+
),
|
|
29
|
+
).build()
|
|
30
|
+
|
|
31
|
+
val result = mapFromPaymentMethod(paymentMethod)
|
|
32
|
+
val availableNetworks = result.getMap("Card")?.getArray("availableNetworks")
|
|
33
|
+
|
|
34
|
+
assertNotNull(availableNetworks)
|
|
35
|
+
assertEquals(1, availableNetworks!!.size())
|
|
36
|
+
assertEquals("discover", availableNetworks.getString(0))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Test
|
|
40
|
+
fun mapFromPaymentMethod_CardWithoutNetworks_AvailableNetworksIsNull() {
|
|
41
|
+
val paymentMethod =
|
|
42
|
+
PaymentMethod
|
|
43
|
+
.Builder()
|
|
44
|
+
.setId("pm_test123")
|
|
45
|
+
.setType(PaymentMethod.Type.Card)
|
|
46
|
+
.setCard(PaymentMethod.Card(brand = CardBrand.Visa))
|
|
47
|
+
.build()
|
|
48
|
+
|
|
49
|
+
val result = mapFromPaymentMethod(paymentMethod)
|
|
50
|
+
|
|
51
|
+
assertNull(result.getMap("Card")?.getArray("availableNetworks"))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Test
|
|
55
|
+
fun mapFromPaymentMethod_USBankAccountWithNetworks_MapsSupportedNetworks() {
|
|
56
|
+
val paymentMethod =
|
|
57
|
+
PaymentMethod
|
|
58
|
+
.Builder()
|
|
59
|
+
.setId("pm_test123")
|
|
60
|
+
.setType(PaymentMethod.Type.USBankAccount)
|
|
61
|
+
.setUSBankAccount(
|
|
62
|
+
PaymentMethod.USBankAccount(
|
|
63
|
+
accountHolderType = PaymentMethod.USBankAccount.USBankAccountHolderType.INDIVIDUAL,
|
|
64
|
+
accountType = PaymentMethod.USBankAccount.USBankAccountType.CHECKING,
|
|
65
|
+
bankName = null,
|
|
66
|
+
fingerprint = null,
|
|
67
|
+
last4 = null,
|
|
68
|
+
financialConnectionsAccount = null,
|
|
69
|
+
networks =
|
|
70
|
+
PaymentMethod.USBankAccount.USBankNetworks(
|
|
71
|
+
preferred = "ach",
|
|
72
|
+
supported = listOf("ach"),
|
|
73
|
+
),
|
|
74
|
+
routingNumber = null,
|
|
75
|
+
),
|
|
76
|
+
).build()
|
|
77
|
+
|
|
78
|
+
val result = mapFromPaymentMethod(paymentMethod)
|
|
79
|
+
val supportedNetworks = result.getMap("USBankAccount")?.getArray("supportedNetworks")
|
|
80
|
+
|
|
81
|
+
assertNotNull(supportedNetworks)
|
|
82
|
+
assertEquals(1, supportedNetworks!!.size())
|
|
83
|
+
assertEquals("ach", supportedNetworks.getString(0))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@Test
|
|
87
|
+
fun mapFromPaymentMethod_USBankAccountWithoutNetworks_SupportedNetworksIsNull() {
|
|
88
|
+
val paymentMethod =
|
|
89
|
+
PaymentMethod
|
|
90
|
+
.Builder()
|
|
91
|
+
.setId("pm_test123")
|
|
92
|
+
.setType(PaymentMethod.Type.USBankAccount)
|
|
93
|
+
.setUSBankAccount(
|
|
94
|
+
PaymentMethod.USBankAccount(
|
|
95
|
+
accountHolderType = PaymentMethod.USBankAccount.USBankAccountHolderType.INDIVIDUAL,
|
|
96
|
+
accountType = PaymentMethod.USBankAccount.USBankAccountType.CHECKING,
|
|
97
|
+
bankName = null,
|
|
98
|
+
fingerprint = null,
|
|
99
|
+
last4 = null,
|
|
100
|
+
financialConnectionsAccount = null,
|
|
101
|
+
networks = null,
|
|
102
|
+
routingNumber = null,
|
|
103
|
+
),
|
|
104
|
+
).build()
|
|
105
|
+
|
|
106
|
+
val result = mapFromPaymentMethod(paymentMethod)
|
|
107
|
+
|
|
108
|
+
assertNull(result.getMap("USBankAccount")?.getArray("supportedNetworks"))
|
|
109
|
+
}
|
|
110
|
+
}
|