diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt index feae6d0a15..91951d8f48 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt @@ -46,13 +46,14 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( analytics.send(WcAnalyticEvents.NewPairInitiated(source)) emit(WcPairState.Loading) - val sdkSessionProposal = sdkDelegate.pair(uri) + val pairResult = sdkDelegate.pair(uri) .onLeft { Timber.tag(WC_TAG).e(it, "Failed to call pair $pairRequest") analytics.send(WcAnalyticEvents.PairFailed) emit(WcPairState.Error(it)) } .getOrNull() ?: return@flow + val (sdkSessionProposal, sdkVerifyContext) = pairResult // check unsupported dApps, just local constant for now, finish if unsupported if (UnsupportedDApps.list.any { sdkSessionProposal.url.contains(it, ignoreCase = true) }) { @@ -62,7 +63,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( return@flow } - val proposalState = buildProposalState(sdkSessionProposal) + val proposalState = buildProposalState(sdkSessionProposal, sdkVerifyContext) .onLeft { analytics.send(WcAnalyticEvents.PairFailed) emit(WcPairState.Error(it)) @@ -147,11 +148,16 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( private suspend fun buildProposalState( sessionProposal: Wallet.Model.SessionProposal, + verifyContext: Wallet.Model.VerifyContext, ): Either = runCatching { val proposalNetwork = associateNetworksDelegate.associate(sessionProposal) - val verificationInfo = blockAidVerifier.verifyDApp(DAppData(sessionProposal.url)).getOrElse { - Timber.tag(WC_TAG).e(it, "Failed to verify DApp ${sessionProposal.name}") - CheckDAppResult.FAILED_TO_VERIFY + val verificationInfo = when { + verifyContext.validation == Wallet.Model.Validation.INVALID -> CheckDAppResult.UNSAFE + verifyContext.isScam == true -> CheckDAppResult.UNSAFE + else -> blockAidVerifier.verifyDApp(DAppData(sessionProposal.url)).getOrElse { + Timber.tag(WC_TAG).e(it, "Failed to verify DApp ${sessionProposal.name}") + CheckDAppResult.FAILED_TO_VERIFY + } } val requestedNetworks = proposalNetwork .values.map { it.available.plus(it.required) }.flatten().toSet() @@ -174,12 +180,15 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( securityStatus = verificationInfo, ) WcPairState.Proposal(dAppSession) - }.fold(onSuccess = { it.right() }, onFailure = { - when (it) { - is WcPairError -> it.left() - else -> WcPairError.Unknown(it.localizedMessage.orEmpty()).left() - } - },) + }.fold( + onSuccess = { it.right() }, + onFailure = { + when (it) { + is WcPairError -> it.left() + else -> WcPairError.Unknown(it.localizedMessage.orEmpty()).left() + } + }, + ) private sealed interface TerminalAction { data class Approve(val sessionForApprove: WcSessionApprove) : TerminalAction diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt index 52df62becd..e115bb7807 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt @@ -21,11 +21,13 @@ import kotlin.time.Duration.Companion.seconds internal class WcPairSdkDelegate : WcSdkObserver { - private val onSessionProposal = Channel() + private val onSessionProposal = Channel>() private val onSdkErrorCallback = Channel() private val onSessionSettleResponse = Channel() - suspend fun pair(url: String): Either = coroutineScope { + suspend fun pair( + url: String, + ): Either> = coroutineScope { val proposalCallback = async { withTimeout(CALLBACK_TIMEOUT.seconds) { proposalCallback() } } val pairCall = async { sdkPair(url) } pairCall.await().onLeft { @@ -112,7 +114,7 @@ internal class WcPairSdkDelegate : WcSdkObserver { verifyContext: Wallet.Model.VerifyContext, ) { // Triggered when wallet receives the session proposal sent by a Dapp - onSessionProposal.trySend(sessionProposal) + onSessionProposal.trySend(sessionProposal to verifyContext) } override fun onSessionSettleResponse(settleSessionResponse: Wallet.Model.SettledSessionResponse) { diff --git a/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/DefaultWcPairUseCaseTest.kt b/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/DefaultWcPairUseCaseTest.kt index 23f8086138..df3b560b15 100644 --- a/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/DefaultWcPairUseCaseTest.kt +++ b/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/DefaultWcPairUseCaseTest.kt @@ -57,6 +57,14 @@ internal class DefaultWcPairUseCaseTest { relayProtocol = "", relayData = "", ) + private val sdkVerifyContext: Wallet.Model.VerifyContext + get() = Wallet.Model.VerifyContext( + id = 9259, + origin = "vituperata", + validation = Wallet.Model.Validation.VALID, + verifyUrl = "https://search.yahoo.com/search?p=id", + isScam = false, + ) private val unsupportedDAppUrl = "dydx.trade" private val unsupportedSdkProposal get() = sdkProposal.copy(url = unsupportedDAppUrl) @@ -122,7 +130,7 @@ internal class DefaultWcPairUseCaseTest { @Test fun `pair, emmit proposal state and wait actions`() = runTest { - coEvery { sdkDelegate.pair(url) } returns sdkProposal.right() + coEvery { sdkDelegate.pair(url) } returns (sdkProposal to sdkVerifyContext).right() coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE } val useCase = useCaseFactory() @@ -143,7 +151,7 @@ internal class DefaultWcPairUseCaseTest { val sessionForSave = sdkSession.sessionForSave val result = WcPairState.Approving.Result(sessionForApprove, sessionForSave.right()) - coEvery { sdkDelegate.pair(url) } returns sdkProposal.right() + coEvery { sdkDelegate.pair(url) } returns (sdkProposal to sdkVerifyContext).right() coEvery { sdkDelegate.approve(sdkApprove) } returns sdkApproveSuccess.right() coEvery { sessionsManager.saveSession(any()) } returns Unit coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE } @@ -177,7 +185,7 @@ internal class DefaultWcPairUseCaseTest { fun `success pair and reject approving`() = runTest { val proposerPublicKey = sdkProposal.proposerPublicKey - coEvery { sdkDelegate.pair(url) } returns sdkProposal.right() + coEvery { sdkDelegate.pair(url) } returns (sdkProposal to sdkVerifyContext).right() coEvery { sdkDelegate.rejectSession(proposerPublicKey) } returns Unit coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE } @@ -199,7 +207,7 @@ internal class DefaultWcPairUseCaseTest { @Test fun `success pair and reject unsupported dApp`() = runTest { - coEvery { sdkDelegate.pair(url) } returns unsupportedSdkProposal.right() + coEvery { sdkDelegate.pair(url) } returns (unsupportedSdkProposal to sdkVerifyContext).right() val unsupportedDAppError = WcPairState.Error(WcPairError.UnsupportedDApp(unsupportedSdkProposal.name)) val useCase = useCaseFactory() @@ -234,7 +242,7 @@ internal class DefaultWcPairUseCaseTest { fun `complete on approve error`() = runTest { val approveLoading = WcPairState.Approving.Loading(sessionForApprove) val error = WcPairError.ApprovalFailed("error").left() - coEvery { sdkDelegate.pair(url) } returns sdkProposal.right() + coEvery { sdkDelegate.pair(url) } returns (sdkProposal to sdkVerifyContext).right() coEvery { sdkDelegate.approve(sdkApprove) } returns error coEvery { sdkDelegate.rejectSession(sdkApprove.proposerPublicKey) } returns Unit coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE }