diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt index e30556434c..6992564847 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt @@ -43,6 +43,7 @@ internal object WalletConnectInteractorModule { currenciesRepository: CurrenciesRepository, walletManagersFacade: WalletManagersFacade, userWalletsListManager: UserWalletsListManager, + walletConnectFeatureToggles: WalletConnectFeatureToggles, coroutineDispatcherProvider: CoroutineDispatcherProvider, ): WalletConnectInteractor { return WalletConnectInteractor( @@ -55,6 +56,7 @@ internal object WalletConnectInteractorModule { walletManagersFacade = walletManagersFacade, userWalletsListManager = userWalletsListManager, dispatchers = coroutineDispatcherProvider, + walletConnectFeatureToggles = walletConnectFeatureToggles, ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index 0487bee8ce..069e6089e9 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -16,6 +16,7 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.isMultiCurrency import com.tangem.domain.wallets.models.requireColdWallet import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase +import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper @@ -39,8 +40,10 @@ class WalletConnectInteractor( private val walletManagersFacade: WalletManagersFacade, private val currenciesRepository: CurrenciesRepository, private val userWalletsListManager: UserWalletsListManager, + private val walletConnectFeatureToggles: WalletConnectFeatureToggles, val blockchainHelper: WcBlockchainHelper, ) { + private val isNewWc by lazy { walletConnectFeatureToggles.isRedesignedWalletConnectEnabled } private var isWalletConnectReadyForDeepLinks = false @@ -88,6 +91,7 @@ class WalletConnectInteractor( } private fun initWithWallet(userWallet: UserWallet) { + if (isNewWc) return if (userWallet.isMultiCurrency) { Timber.i("WalletConnect: initialize and setup networks for ${userWallet.walletId}") startListeningWc(userWallet.walletId.stringValue, getCardId(userWallet)) @@ -243,6 +247,7 @@ class WalletConnectInteractor( } fun approveSessionProposal(accounts: List) { + if (isNewWc) return Timber.i("Approve session proposal: $accounts") val userNamespaces: Map> = accounts .groupBy { account -> @@ -259,16 +264,19 @@ class WalletConnectInteractor( } fun rejectSessionProposal() { + if (isNewWc) return Timber.i("Reject session proposal") walletConnectRepository.reject() } fun disconnectSession(topic: String) { + if (isNewWc) return Timber.i("Disconnect session: $topic") walletConnectRepository.disconnect(topic) } fun cancelRequest(topic: String, id: Long) { + if (isNewWc) return Timber.i("Cancel request: $topic, $id") walletConnectRepository.cancelRequest(topic, id) } @@ -323,6 +331,7 @@ class WalletConnectInteractor( } suspend fun continueWithRequest(request: WcPreparedRequest) { + if (isNewWc) return val currentRequest = this.currentRequest if (currentRequest == null || request.topic != currentRequest.topic) return @@ -386,6 +395,7 @@ class WalletConnectInteractor( * @param deeplink deeplink to handle */ fun addDeeplink(deeplink: String) { + if (isNewWc) return val deeplinkRegex = Regex(WC_PARAM_REGEX) val matched = deeplinkRegex.findAll(deeplink) val sessionTopic = matched.firstOrNull { it.value.contains(WC_TOPIC_QUERY_NAME) }?.groupValues?.lastOrNull() diff --git a/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt index 02afc7ecfe..798ad3a70f 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt @@ -108,6 +108,7 @@ internal class DeepLinkFactory @Inject constructor( } } + @Suppress("CyclomaticComplexMethod") private fun handleTangemDeepLinks(deeplinkUri: Uri, coroutineScope: CoroutineScope, isFromOnNewIntent: Boolean) { val queryParams = getQueryParams(deeplinkUri) when (deeplinkUri.host) { @@ -127,6 +128,7 @@ internal class DeepLinkFactory @Inject constructor( DeepLinkRoute.Buy.host -> buyDeepLink.create() DeepLinkRoute.Sell.host -> sellDeepLink.create() DeepLinkRoute.Swap.host -> swapDeepLink.create() + DeepLinkRoute.WalletConnect.host -> walletConnectDeepLink.create(deeplinkUri) else -> { Timber.i( """ diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt index b16393478e..78a4ad85ea 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt @@ -51,6 +51,10 @@ sealed class DeepLinkRoute { data object Swap : DeepLinkRoute() { override val host: String = "swap" } + + data object WalletConnect : DeepLinkRoute() { + override val host: String = "wc" + } } enum class DeepLinkScheme(val scheme: String) { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt index c495325ca3..6bcb815d18 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt @@ -110,15 +110,11 @@ internal class WcEthNetwork( } internal class NamespaceConverter( - private val excludedBlockchains: ExcludedBlockchains, + override val excludedBlockchains: ExcludedBlockchains, ) : WcNamespaceConverter { override val namespaceKey: NamespaceKey = NamespaceKey("eip155") - override fun toNetwork(chainId: String, wallet: UserWallet): Network? { - return toNetwork(chainId, wallet, excludedBlockchains) - } - override fun toBlockchain(chainId: CAIP2): Blockchain? { if (chainId.namespace != namespaceKey.key) return null val ethChainId = chainId.reference.toIntOrNull() ?: return null diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt index 2612c60f22..4a310d86d3 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt @@ -18,7 +18,6 @@ import com.tangem.domain.walletconnect.model.WcSolanaMethodName import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest import com.tangem.domain.walletconnect.repository.WcSessionsManager import com.tangem.domain.walletconnect.usecase.method.WcMethodUseCase -import com.tangem.domain.wallets.models.UserWallet import com.tangem.lib.crypto.UserWalletManager import jakarta.inject.Inject import timber.log.Timber @@ -66,7 +65,7 @@ internal class WcSolanaNetwork( } internal class NamespaceConverter @Inject constructor( - private val excludedBlockchains: ExcludedBlockchains, + override val excludedBlockchains: ExcludedBlockchains, ) : WcNamespaceConverter { override val namespaceKey: NamespaceKey = NamespaceKey("solana") @@ -80,10 +79,6 @@ internal class WcSolanaNetwork( } } - override fun toNetwork(chainId: String, wallet: UserWallet): Network? { - return toNetwork(chainId, wallet, excludedBlockchains) - } - override fun toCAIP2(network: Network): CAIP2? { val blockchain = network.toBlockchain() val chainId = when (blockchain) { 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 77b7c18e93..6b60b36eca 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 @@ -105,6 +105,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( newSession }.onLeft { analytics.send(WcAnalyticEvents.DAppConnectionFailed(it.code)) + sdkDelegate.rejectSession(sdkSessionProposal.proposerPublicKey) Timber.tag(WC_TAG).e(it, "Failed to approve session ${sdkSessionProposal.name}") } emit(WcPairState.Approving.Result(sessionForApprove, either)) 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 1a72488035..0b83809241 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 @@ -13,7 +13,9 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withTimeout import kotlin.coroutines.resume +import kotlin.time.Duration.Companion.seconds internal class WcPairSdkDelegate : WcSdkObserver { @@ -26,7 +28,7 @@ internal class WcPairSdkDelegate : WcSdkObserver { .first() val pairCall = async { sdkPair(url) } - val proposal = async { proposalCallback() } + val proposal = async { withTimeout(20.seconds) { proposalCallback() } } pairCall.await().onLeft { proposal.cancel() return@coroutineScope it.left() @@ -42,7 +44,7 @@ internal class WcPairSdkDelegate : WcSdkObserver { .first() val approveCall = async { sdkApprove(sessionApprove) } - val approveCallback = async { approveCallback() } + val approveCallback = async { withTimeout(20.seconds) { approveCallback() } } approveCall.await() .onLeft { approveCallback.cancel() diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt index 258733919d..b1a98f54da 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt @@ -12,6 +12,7 @@ import com.tangem.domain.wallets.models.requireColdWallet internal interface WcNamespaceConverter { val namespaceKey: NamespaceKey + val excludedBlockchains: ExcludedBlockchains fun toBlockchain(chainId: CAIP2): Blockchain? fun toBlockchain(chainId: String): Blockchain? = toCAIP2(chainId)?.let { caip2 -> toBlockchain(caip2) } @@ -19,9 +20,9 @@ internal interface WcNamespaceConverter { fun toCAIP2(network: Network): CAIP2? fun toCAIP2(chainId: String): CAIP2? = CAIP2.fromRaw(chainId) - fun toNetwork(chainId: String, wallet: UserWallet): Network? - fun toNetwork(chainId: String, wallet: UserWallet, excludedBlockchains: ExcludedBlockchains): Network? { + fun toNetwork(chainId: String, wallet: UserWallet): Network? { val blockchain = toBlockchain(chainId) ?: return null + if (blockchain.isTestnet()) return null return NetworkFactory(excludedBlockchains).create( blockchain = blockchain, 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 e493e6b602..47778833c3 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 @@ -232,6 +232,7 @@ internal class DefaultWcPairUseCaseTest { val error = WcPairError.ApprovalFailed("error").left() coEvery { sdkDelegate.pair(url) } returns sdkProposal.right() coEvery { sdkDelegate.approve(sdkApprove) } returns error + coEvery { sdkDelegate.rejectSession(sdkApprove.proposerPublicKey) } returns Unit coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE } val errorResult = WcPairState.Approving.Result(sessionForApprove, error) @@ -250,8 +251,8 @@ internal class DefaultWcPairUseCaseTest { assertEquals(approveLoading, awaitItem()) coVerifyOrder { sdkDelegate.approve(sdkApprove) + sdkDelegate.rejectSession(sdkApprove.proposerPublicKey) } - assertEquals(errorResult, awaitItem()) awaitComplete() }