Updated on 2026-08-14
This commit is contained in:
parent
ded577faff
commit
aea7f5f415
21 changed files with 220 additions and 136 deletions
|
|
@ -122,6 +122,7 @@ dependencies {
|
|||
implementation(projects.core.utils)
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.deepLinks)
|
||||
implementation(projects.core.error.ext)
|
||||
implementation(projects.libs.crypto)
|
||||
implementation(projects.libs.auth)
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ import com.tangem.common.card.EllipticCurve
|
|||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.map
|
||||
import com.tangem.common.timemeasure.RealtimeMonotonicTimeSource
|
||||
import com.tangem.core.error.ext.tangemError
|
||||
import com.tangem.crypto.CryptoUtils
|
||||
import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
||||
import com.tangem.datasource.local.visa.VisaOTPStorage
|
||||
|
|
@ -22,6 +24,8 @@ import com.tangem.datasource.local.visa.hasSavedOTP
|
|||
import com.tangem.domain.common.visa.VisaUtilities
|
||||
import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
|
|
@ -68,7 +72,7 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
val card = session.environment.card ?: return CompletionResult.Failure(TangemSdkError.MissingPreflightRead())
|
||||
|
||||
if (card.cardId != activationInput.cardId) {
|
||||
return CompletionResult.Failure(TangemSdkError.Underlying(VisaActivationError.WrongCard.message))
|
||||
return CompletionResult.Failure(VisaActivationError.WrongCard.tangemError)
|
||||
}
|
||||
|
||||
val visaActivationRepository = visaActivationRepositoryFactory.create(
|
||||
|
|
@ -149,7 +153,7 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
|
||||
private suspend fun SessionContext.getDataToSign(
|
||||
signedChallenge: VisaAuthSignedChallenge,
|
||||
): Either<TangemSdkError.Underlying, VisaDataToSignByCardWallet> = either {
|
||||
): Either<TangemError, VisaDataToSignByCardWallet> = either {
|
||||
catch(
|
||||
block = {
|
||||
val tokens = visaAuthRepository.getAccessTokens(signedChallenge)
|
||||
|
|
@ -158,13 +162,13 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
|
||||
val remoteState = visaActivationRepository.getActivationRemoteState()
|
||||
if (remoteState !is VisaActivationRemoteState.CardWalletSignatureRequired) {
|
||||
raise(TangemSdkError.Underlying(VisaActivationError.WrongRemoteState.message))
|
||||
raise(VisaActivationError.WrongRemoteState.tangemError)
|
||||
}
|
||||
|
||||
visaActivationRepository.getCardWalletAcceptanceData(remoteState.request)
|
||||
},
|
||||
catch = {
|
||||
raise(TangemSdkError.Underlying("Underlying network error: ${it.message ?: ""}"))
|
||||
raise(VisaAuthorizationAPIError.tangemError)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -246,10 +250,10 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
?: return CompletionResult.Failure(TangemSdkError.MissingPreflightRead())
|
||||
|
||||
val derivedPublicKey = wallet.derivedKeys[VisaUtilities.visaDefaultDerivationPath]
|
||||
?: return CompletionResult.Failure(TangemSdkError.Underlying(VisaActivationError.MissingWallet.message))
|
||||
?: return CompletionResult.Failure(VisaActivationError.MissingWallet.tangemError)
|
||||
|
||||
val walletAddress = VisaWalletPublicKeyUtility.generateAddressOnSecp256k1(derivedPublicKey.publicKey)
|
||||
.getOrElse { return CompletionResult.Failure(TangemSdkError.Underlying(it.message)) }
|
||||
.getOrElse { return CompletionResult.Failure(it.tangemError) }
|
||||
.value
|
||||
|
||||
val task = SignHashCommand(
|
||||
|
|
@ -291,7 +295,7 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
): CompletionResult<VisaCardActivationResponse> {
|
||||
val otp = otpStorage.getOTP(cardId) ?: run {
|
||||
createOTP()
|
||||
otpStorage.getOTP(cardId) ?: return CompletionResult.Failure(TangemSdkError.Underlying("OTP not found"))
|
||||
otpStorage.getOTP(cardId) ?: return CompletionResult.Failure(VisaActivationError.MissingRootOTP.tangemError)
|
||||
}
|
||||
|
||||
val signedActivationData = dataToSign.sign(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.common.core.CompletionCallback
|
|||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.error.ext.tangemError
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
|
|
@ -18,7 +19,7 @@ import com.tangem.domain.common.visa.VisaUtilities
|
|||
import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility
|
||||
import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility.findKeyWithoutDerivation
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.visa.model.VisaActivationError
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||
import com.tangem.domain.visa.model.sign
|
||||
|
|
@ -37,6 +38,7 @@ class VisaCustomerWalletApproveTask(
|
|||
}
|
||||
|
||||
if (VisaUtilities.isVisaCard(card.firmwareVersion.doubleValue, card.batchId)) {
|
||||
// TODO TVF-21
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying("Can't use Visa card for approve")))
|
||||
return
|
||||
}
|
||||
|
|
@ -44,7 +46,7 @@ class VisaCustomerWalletApproveTask(
|
|||
if (visaDataForApprove.customerWalletCardId != null && card.cardId != visaDataForApprove.customerWalletCardId) {
|
||||
callback(
|
||||
CompletionResult.Failure(
|
||||
TangemSdkError.Underlying("Use tangem wallet specified during visa registration"),
|
||||
TangemSdkError.Underlying("Use tangem wallet specified during visa registration"), // TODO TVF-21
|
||||
),
|
||||
)
|
||||
return
|
||||
|
|
@ -74,16 +76,12 @@ class VisaCustomerWalletApproveTask(
|
|||
}
|
||||
|
||||
val derivationPath = VisaUtilities.visaDefaultDerivationPath(derivationStyle) ?: run {
|
||||
callback(
|
||||
CompletionResult.Failure(
|
||||
TangemSdkError.Underlying("Failed to generate derivation path with provided derivation style"),
|
||||
),
|
||||
)
|
||||
callback(CompletionResult.Failure(VisaActivationError.FailedToCreateAddress.tangemError))
|
||||
return
|
||||
}
|
||||
|
||||
val wallet = card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: run {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying(VisaActivationError.MissingWallet.message)))
|
||||
callback(CompletionResult.Failure(VisaActivationError.MissingWallet.tangemError))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +121,7 @@ class VisaCustomerWalletApproveTask(
|
|||
)
|
||||
|
||||
validationResult.onLeft {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying(it.message)))
|
||||
callback(CompletionResult.Failure(it.tangemError))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +142,7 @@ class VisaCustomerWalletApproveTask(
|
|||
targetAddress = visaDataForApprove.targetAddress,
|
||||
card = CardDTO(card),
|
||||
).getOrElse {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying(it.message)))
|
||||
callback(CompletionResult.Failure(it.tangemError))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,15 @@ import com.tangem.common.core.CardSession
|
|||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.error.ext.tangemError
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
||||
import com.tangem.domain.common.visa.VisaUtilities
|
||||
import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.error.VisaCardScanError
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
|
|
@ -71,9 +75,7 @@ internal class VisaCardScanHandler @Inject constructor(
|
|||
val derivationPath = VisaUtilities.visaDefaultDerivationPath ?: run {
|
||||
Timber.e("Failed to create derivation path while first scan")
|
||||
|
||||
return CompletionResult.Failure(
|
||||
TangemSdkError.Underlying(VisaCardScanHandlerError.FailedToCreateDerivationPath.errorDescription),
|
||||
)
|
||||
return CompletionResult.Failure(VisaCardScanError.FailedToCreateDerivationPath.tangemError)
|
||||
}
|
||||
|
||||
val derivationTask = DeriveWalletPublicKeyTask(wallet.publicKey, derivationPath)
|
||||
|
|
@ -104,32 +106,24 @@ internal class VisaCardScanHandler @Inject constructor(
|
|||
|
||||
val derivationPath = VisaUtilities.visaDefaultDerivationPath ?: run {
|
||||
Timber.e("Failed to create derivation path while handling wallet authorization")
|
||||
return CompletionResult.Failure(
|
||||
TangemSdkError.Underlying(VisaCardScanHandlerError.FailedToCreateDerivationPath.errorDescription),
|
||||
)
|
||||
return CompletionResult.Failure(VisaCardScanError.FailedToCreateDerivationPath.tangemError)
|
||||
}
|
||||
|
||||
val card = session.environment.card ?: return CompletionResult.Failure(TangemSdkError.MissingPreflightRead())
|
||||
|
||||
val wallet = card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: run {
|
||||
Timber.e("Failed to find extended public key while handling wallet authorization")
|
||||
return CompletionResult.Failure(
|
||||
TangemSdkError.Underlying(VisaCardScanHandlerError.FailedToFindDerivedWalletKey.errorDescription),
|
||||
)
|
||||
return CompletionResult.Failure(VisaCardScanError.FailedToFindWallet.tangemError)
|
||||
}
|
||||
|
||||
val extendedPublicKey = wallet.derivedKeys[derivationPath] ?: run {
|
||||
Timber.e("Failed to find extended public key while handling wallet authorization")
|
||||
return CompletionResult.Failure(
|
||||
TangemSdkError.Underlying(VisaCardScanHandlerError.FailedToFindDerivedWalletKey.errorDescription),
|
||||
)
|
||||
return CompletionResult.Failure(VisaCardScanError.FailedToFindDerivedWalletKey.tangemError)
|
||||
}
|
||||
|
||||
val walletAddress = VisaWalletPublicKeyUtility.generateAddressOnSecp256k1(extendedPublicKey.publicKey)
|
||||
.getOrElse {
|
||||
return CompletionResult.Failure(
|
||||
TangemSdkError.Underlying("Cannot generate address on Visa curve"),
|
||||
)
|
||||
return CompletionResult.Failure(it.tangemError)
|
||||
}
|
||||
|
||||
Timber.i("Requesting challenge for wallet authorization")
|
||||
|
|
@ -200,7 +194,7 @@ internal class VisaCardScanHandler @Inject constructor(
|
|||
)
|
||||
}.getOrElse {
|
||||
Timber.e("Failed to get challenge for Card authorization. Plain error: ${it.message}")
|
||||
return CompletionResult.Failure(TangemSdkError.Underlying(it.message ?: "Unknown error"))
|
||||
return CompletionResult.Failure(VisaAuthorizationAPIError.tangemError)
|
||||
}
|
||||
|
||||
Timber.i("Received challenge to sign: ${challengeResponse.challenge}")
|
||||
|
|
@ -230,11 +224,7 @@ internal class VisaCardScanHandler @Inject constructor(
|
|||
)
|
||||
}.getOrElse {
|
||||
Timber.e("Failed to sign challenge with Card public key. Plain error: ${it.message}")
|
||||
return CompletionResult.Failure(
|
||||
TangemSdkError.Underlying(
|
||||
customMessage = it.message ?: "Unknown error",
|
||||
),
|
||||
)
|
||||
return CompletionResult.Failure(VisaAuthorizationAPIError.tangemError)
|
||||
}
|
||||
|
||||
visaAuthTokenStorage.store(
|
||||
|
|
@ -251,7 +241,7 @@ internal class VisaCardScanHandler @Inject constructor(
|
|||
}
|
||||
|
||||
if (error != null) {
|
||||
return CompletionResult.Failure(TangemSdkError.Underlying(error.message))
|
||||
return CompletionResult.Failure(error.tangemError)
|
||||
}
|
||||
|
||||
val activationInput = VisaActivationInput(
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.tap.domain.visa
|
||||
|
||||
private const val COMMON_DESCRIPTION = "Error occurred. Please contact support."
|
||||
|
||||
internal enum class VisaCardScanHandlerError(val errorDescription: String) {
|
||||
FailedToCreateDerivationPath(COMMON_DESCRIPTION),
|
||||
FailedToFindWallet(COMMON_DESCRIPTION),
|
||||
FailedToFindDerivedWalletKey(COMMON_DESCRIPTION),
|
||||
}
|
||||
|
|
@ -1,14 +1,4 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.core.error"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.blockchain)
|
||||
}
|
||||
1
core/error/ext/.gitignore
vendored
Normal file
1
core/error/ext/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
16
core/error/ext/build.gradle.kts
Normal file
16
core/error/ext/build.gradle.kts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.core.error.ext"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.core.error)
|
||||
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.blockchain)
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.core.error.ext
|
||||
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.error.UniversalError
|
||||
|
||||
val TangemError.universalError: UniversalError
|
||||
get() = when (this) {
|
||||
is TangemSdkError -> object : UniversalError {
|
||||
override val errorCode: Int = 101000000 + code
|
||||
}
|
||||
else -> object : UniversalError {
|
||||
override val errorCode: Int = code
|
||||
}
|
||||
}
|
||||
|
||||
val BlockchainSdkError.universalError: UniversalError
|
||||
get() = object : UniversalError {
|
||||
override val errorCode: Int = 102000000 + code
|
||||
}
|
||||
|
||||
val UniversalError.tangemError: TangemError
|
||||
get() = object : TangemError(errorCode) {
|
||||
override var customMessage: String = errorCode.toString()
|
||||
override val messageResId: Int? = null
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.tangem.core.error
|
||||
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
|
||||
val TangemSdkError.universalError: UniversalError
|
||||
get() = object : UniversalError {
|
||||
override val errorCode: Int = 101000000 + code
|
||||
}
|
||||
|
||||
val BlockchainSdkError.universalError: UniversalError
|
||||
get() = object : UniversalError {
|
||||
override val errorCode: Int = 102000000 + code
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ android {
|
|||
dependencies {
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.error)
|
||||
implementation(projects.common)
|
||||
implementation(projects.libs.auth)
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
|
|
|
|||
|
|
@ -8,18 +8,22 @@ import com.tangem.blockchain.common.address.AddressType
|
|||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
|
||||
object VisaWalletPublicKeyUtility {
|
||||
|
||||
fun validateExtendedPublicKey(targetAddress: String, extendedPublicKey: ExtendedPublicKey): Either<Error, Unit> =
|
||||
either {
|
||||
fun validateExtendedPublicKey(
|
||||
targetAddress: String,
|
||||
extendedPublicKey: ExtendedPublicKey,
|
||||
): Either<VisaActivationError, Unit> = either {
|
||||
validatePublicKey(
|
||||
targetAddress = targetAddress,
|
||||
publicKey = extendedPublicKey.publicKey,
|
||||
).bind()
|
||||
}
|
||||
|
||||
fun findKeyWithoutDerivation(targetAddress: String, card: CardDTO): Either<Error, ByteArray> = either {
|
||||
fun findKeyWithoutDerivation(targetAddress: String, card: CardDTO): Either<VisaActivationError, ByteArray> =
|
||||
either {
|
||||
val wallet = findWalletOnSecp256k1(card).bind()
|
||||
|
||||
validatePublicKey(
|
||||
|
|
@ -30,7 +34,7 @@ object VisaWalletPublicKeyUtility {
|
|||
wallet.publicKey
|
||||
}
|
||||
|
||||
fun generateAddressOnSecp256k1(walletPublicKey: ByteArray): Either<Error, Address> = either {
|
||||
fun generateAddressOnSecp256k1(walletPublicKey: ByteArray): Either<VisaActivationError, Address> = either {
|
||||
val addresses = catch(
|
||||
block = {
|
||||
VisaUtilities.visaBlockchain.makeAddresses(
|
||||
|
|
@ -39,27 +43,22 @@ object VisaWalletPublicKeyUtility {
|
|||
curve = EllipticCurve.Secp256k1,
|
||||
)
|
||||
},
|
||||
catch = { raise(Error.FailedToCreateAddress) },
|
||||
catch = { raise(VisaActivationError.FailedToCreateAddress) },
|
||||
)
|
||||
|
||||
addresses.firstOrNull { it.type == AddressType.Default } ?: raise(Error.FailedToCreateAddress)
|
||||
addresses.firstOrNull { it.type == AddressType.Default } ?: raise(VisaActivationError.FailedToCreateAddress)
|
||||
}
|
||||
|
||||
private fun findWalletOnSecp256k1(card: CardDTO): Either<Error, CardDTO.Wallet> = either {
|
||||
card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: raise(Error.MissingWalletOnTargetCurve)
|
||||
private fun findWalletOnSecp256k1(card: CardDTO): Either<VisaActivationError, CardDTO.Wallet> = either {
|
||||
card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: raise(VisaActivationError.MissingWallet)
|
||||
}
|
||||
|
||||
private fun validatePublicKey(targetAddress: String, publicKey: ByteArray): Either<Error, Unit> = either {
|
||||
private fun validatePublicKey(targetAddress: String, publicKey: ByteArray): Either<VisaActivationError, Unit> =
|
||||
either {
|
||||
val address = generateAddressOnSecp256k1(publicKey).bind()
|
||||
|
||||
if (address.value != targetAddress) {
|
||||
raise(Error.AddressNotMatched)
|
||||
raise(VisaActivationError.AddressNotMatched)
|
||||
}
|
||||
}
|
||||
|
||||
enum class Error(val message: String) {
|
||||
AddressNotMatched("ValidationError: Address not matched"),
|
||||
FailedToCreateAddress("ValidationError: Failed to create address"),
|
||||
MissingWalletOnTargetCurve("ValidationError: Missing wallet on target curve"),
|
||||
}
|
||||
}
|
||||
|
|
@ -10,4 +10,5 @@ dependencies {
|
|||
ksp(deps.moshi.kotlin.codegen)
|
||||
implementation(deps.moshi.adapters)
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(projects.core.error)
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
@file:Suppress("MagicNumber")
|
||||
|
||||
package com.tangem.domain.visa.error
|
||||
|
||||
import com.tangem.core.error.UniversalError
|
||||
|
||||
/**
|
||||
* Each error code must follow this format: xxxyyyzzz where
|
||||
* xxx - Feature code
|
||||
* yyy - Subsystem code
|
||||
* zzz - Specific error code
|
||||
* If you need to add new subsystem add it to list below incrementing last code.
|
||||
* `Subsystems`:
|
||||
* `001` - Common API
|
||||
* `002` - First card scan error
|
||||
* `003` - Activation
|
||||
* `004` - Authorization API
|
||||
*/
|
||||
object VisaError : UniversalError {
|
||||
override val errorCode: Int = 104000000
|
||||
}
|
||||
|
||||
object VisaAPIError : UniversalError {
|
||||
override val errorCode: Int = 104001000
|
||||
}
|
||||
|
||||
enum class VisaCardScanError(
|
||||
override val errorCode: Int,
|
||||
) : UniversalError {
|
||||
FailedToCreateDerivationPath(104002001),
|
||||
FailedToFindWallet(104002002),
|
||||
FailedToFindDerivedWalletKey(104002003),
|
||||
}
|
||||
|
||||
enum class VisaActivationError(
|
||||
override val errorCode: Int,
|
||||
) : UniversalError {
|
||||
BlockedForActivation(104003001),
|
||||
InvalidActivationState(104003002),
|
||||
WrongCard(104003003),
|
||||
WrongRemoteState(104003004),
|
||||
MissingWallet(104003005),
|
||||
MissingRootOTP(104003006),
|
||||
FailedToCreateAddress(104003007),
|
||||
AddressNotMatched(104003008),
|
||||
InconsistentRemoteState(104003009),
|
||||
}
|
||||
|
||||
object VisaAuthorizationAPIError : UniversalError {
|
||||
override val errorCode: Int = 104004000
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.domain.visa.model
|
||||
|
||||
enum class VisaActivationError(val message: String) {
|
||||
BlockedForActivation("Card is blocked for activation"),
|
||||
InvalidActivationState("Invalid activation state"),
|
||||
WrongCard("Wrong card tapped"),
|
||||
WrongRemoteState("Wrong remote state"),
|
||||
MissingWallet("Missing wallet"),
|
||||
MissingRootOTP("Missing root OTP"),
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ dependencies {
|
|||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.error.ext)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ import com.tangem.common.extensions.toHexString
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.error.ext.universalError
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.error.VisaAPIError
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.model.VisaCustomerWalletDataToSignRequest
|
||||
|
|
@ -34,6 +39,7 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
@Suppress("UnusedPrivateMember")
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val visaAuthRepository: VisaAuthRepository,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params: OnboardingVisaAccessCodeComponent.Config = paramsContainer.require()
|
||||
|
|
@ -138,7 +144,7 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(VisaAuthorizationAPIError)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
@ -148,17 +154,22 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
authorizationChallenge = challengeToSign,
|
||||
),
|
||||
activationInput = activationStatus.activationInput,
|
||||
) as? CompletionResult.Success ?: run {
|
||||
)
|
||||
|
||||
val resultData = when (result) {
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
|
||||
runCatching {
|
||||
visaActivationRepository.activateCard(result.data.signedActivationData)
|
||||
visaActivationRepository.activateCard(resultData.signedActivationData)
|
||||
}.onFailure {
|
||||
loading(false)
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ import com.tangem.common.extensions.toHexString
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.error.ext.universalError
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.error.VisaAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
|
|
@ -27,6 +31,7 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
visaActivationRepositoryFactory: VisaActivationRepository.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<OnboardingVisaApproveComponent.Config>()
|
||||
|
|
@ -56,7 +61,7 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
visaActivationRepository.getCustomerWalletAcceptanceData(params.preparationDataForApprove.request)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
// TODO show dialog
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
@ -66,17 +71,22 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
targetAddress = params.preparationDataForApprove.customerWalletAddress,
|
||||
dataToSign = dataToSign,
|
||||
),
|
||||
) as? CompletionResult.Success ?: run {
|
||||
)
|
||||
|
||||
val resultData = when (result) {
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
// TODO show dialog
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
|
||||
runCatching {
|
||||
visaActivationRepository.approveByCustomerWallet(result.data)
|
||||
visaActivationRepository.approveByCustomerWallet(resultData)
|
||||
}.onFailure {
|
||||
loading(false)
|
||||
// TODO show dialog
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@ import com.tangem.common.extensions.toHexString
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
||||
import com.tangem.datasource.local.visa.VisaOTPStorage
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
|
|
@ -36,6 +40,7 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
private val otpStorage: VisaOTPStorage,
|
||||
private val userWalletBuilderFactory: UserWalletBuilder.Factory,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<Config>()
|
||||
|
|
@ -58,7 +63,7 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
is VisaActivationRemoteState.CardWalletSignatureRequired,
|
||||
VisaActivationRemoteState.BlockedForActivation,
|
||||
-> {
|
||||
// TODO show alert inconsistent state
|
||||
uiMessageSender.showErrorDialog(VisaActivationError.InconsistentRemoteState)
|
||||
return@launch
|
||||
}
|
||||
is VisaActivationRemoteState.CustomerWalletSignatureRequired,
|
||||
|
|
@ -92,7 +97,7 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
val newTokens = runCatching {
|
||||
visaAuthRepository.refreshAccessTokens(authTokens.refreshToken)
|
||||
}.getOrElse {
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(VisaAuthorizationAPIError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ import com.tangem.common.extensions.toHexString
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.error.ext.universalError
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.error.VisaAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.model.VisaCustomerWalletDataToSignRequest
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
|
|
@ -28,6 +32,7 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val visaActivationRepositoryFactory: VisaActivationRepository.Factory,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<Config>()
|
||||
|
|
@ -68,24 +73,29 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
visaActivationRepository.getCardWalletAcceptanceData(params.dataToSignRequest)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = tangemSdkManager.activateVisaCard(
|
||||
mode = VisaCardActivationTaskMode.SignOnly(dataToSignByCardWallet = dataToSignByCardWallet),
|
||||
activationInput = params.activationInput,
|
||||
) as? CompletionResult.Success ?: run {
|
||||
)
|
||||
|
||||
val resultData = when (result) {
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
|
||||
runCatching {
|
||||
visaActivationRepository.activateCard(result.data.signedActivationData)
|
||||
visaActivationRepository.activateCard(resultData.signedActivationData)
|
||||
}.onFailure {
|
||||
loading(false)
|
||||
// TODO show alert
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ include(":core:deep-links:global")
|
|||
include(":core:decompose")
|
||||
include(":core:pagination")
|
||||
include(":core:error")
|
||||
include(":core:error:ext")
|
||||
// endregion Core modules
|
||||
|
||||
// region Common modules
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue