From 4ae680e1c4566b6bbf27742b44f25bb50da09163 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 29 Jan 2025 16:56:12 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../visa/VisaCustomerWalletApproveTask.kt | 13 ++++++-- .../domain/visa/model/VisaDataForApprove.kt | 1 + .../model/OnboardingVisaAccessCodeModel.kt | 32 +++++++++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt index c9fb9dc1d0..541f367b08 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt @@ -33,8 +33,17 @@ class VisaCustomerWalletApproveTask( return } - if (VisaUtilities.isVisaCard(card.firmwareVersion.doubleValue, card.batchId).not()) { - callback(CompletionResult.Failure(TangemSdkError.Underlying("Card is identified as not Visa"))) + if (VisaUtilities.isVisaCard(card.firmwareVersion.doubleValue, card.batchId)) { + callback(CompletionResult.Failure(TangemSdkError.Underlying("Can't use Visa card for approve"))) + return + } + + if (visaDataForApprove.customerWalletCardId != null && card.cardId != visaDataForApprove.customerWalletCardId) { + callback( + CompletionResult.Failure( + TangemSdkError.Underlying("Use tangem wallet specified during visa registration"), + ), + ) return } diff --git a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaDataForApprove.kt b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaDataForApprove.kt index 5a5fe7cb4d..93ec3d29d8 100644 --- a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaDataForApprove.kt +++ b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaDataForApprove.kt @@ -5,6 +5,7 @@ import kotlinx.serialization.Serializable @Serializable data class VisaDataForApprove( + @SerialName("customerWalletCardId") val customerWalletCardId: String?, @SerialName("targetAddress") val targetAddress: String, @SerialName("approveHash") val approveHash: String, ) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt index 5c78636e38..0778d05cbe 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt @@ -7,9 +7,12 @@ import com.tangem.common.extensions.toHexString import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.domain.common.visa.VisaUtilities +import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility import com.tangem.domain.visa.model.VisaCardActivationStatus import com.tangem.domain.visa.model.VisaDataForApprove import com.tangem.domain.visa.repository.VisaAuthRepository +import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.OnboardingVisaAccessCodeComponent import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state.OnboardingVisaAccessCodeUM import com.tangem.sdk.api.TangemSdkManager @@ -29,6 +32,7 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor( @Suppress("UnusedPrivateMember") private val tangemSdkManager: TangemSdkManager, private val visaAuthRepository: VisaAuthRepository, + private val getWalletsUseCase: GetWalletsUseCase, ) : Model() { private val params: OnboardingVisaAccessCodeComponent.Config = paramsContainer.require() @@ -139,16 +143,18 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor( when (result) { is CompletionResult.Success -> { // TODO load approve data from backend - // TODO try to find wallet in the app + val targetAddress = "x9F65354e595284956599F2892fA4A4a87653D6E6" + val foundCardId = tryToFindExistingWalletCardId(targetAddress) modelScope.launch { onDone.emit( OnboardingVisaAccessCodeComponent.DoneEvent( visaDataForApprove = VisaDataForApprove( - targetAddress = "x9F65354e595284956599F2892fA4A4a87653D6E6", + targetAddress = targetAddress, approveHash = "48b55c482123a10ad9022f9f4c5dd95c", + customerWalletCardId = foundCardId, ), - walletFound = false, // TODO + walletFound = foundCardId != null, newScanResponse = params.scanResponse.copy( card = result.data.newCardDTO, ), @@ -164,6 +170,26 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor( } } + private fun tryToFindExistingWalletCardId(targetAddress: String): String? { + val wallets = getWalletsUseCase.invokeSync().filter { it.isLocked.not() } + + return wallets.firstOrNull { wallet -> + wallet.scanResponse.card.wallets.any { + val derivedKey = it.derivedKeys[VisaUtilities.visaDefaultDerivationPath] ?: return@any false + + VisaWalletPublicKeyUtility.validateExtendedPublicKey( + targetAddress = targetAddress, + extendedPublicKey = derivedKey, + ).onLeft { + return@any VisaWalletPublicKeyUtility.findKeyWithoutDerivation( + targetAddress = targetAddress, + card = wallet.scanResponse.card, + ).isRight() + }.isRight() + } + }?.cardId + } + private fun loading(state: Boolean) { _uiState.update { it.copy(buttonLoading = state) } }