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 6e51e63915..39863e9d02 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 @@ -39,13 +39,11 @@ internal class WcEthNetwork( } @Suppress("CyclomaticComplexMethod") - override suspend fun toUseCase( - request: WcSdkSessionRequest, - ): Either { - fun error(message: String) = WcRequestError.HandleMethodError(message).left() + override suspend fun toUseCase(request: WcSdkSessionRequest): Either { + fun error(message: String) = HandleMethodError.UnknownError(message).left() val name = toWcMethodName(request) ?: return error("Unknown method name") val session = sessionsManager.findSessionByTopic(request.topic) - ?: return error("Failed to find session for topic ${request.topic}") + ?: return HandleMethodError.UnknownSession.left() val wallet = session.wallet val chainId = request.chainId.orEmpty() val method: WcEthMethod = name.toMethod(request, wallet) 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 e640f5cb36..df7e9839f8 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,7 @@ import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext import com.tangem.data.walletconnect.utils.WcNamespaceConverter import com.tangem.data.walletconnect.utils.WcNetworksConverter import com.tangem.domain.models.network.Network -import com.tangem.domain.walletconnect.model.WcRequestError +import com.tangem.domain.walletconnect.model.HandleMethodError import com.tangem.domain.walletconnect.model.WcSolanaMethod import com.tangem.domain.walletconnect.model.WcSolanaMethodName import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest @@ -42,16 +42,14 @@ internal class WcSolanaNetwork( } @Suppress("CyclomaticComplexMethod") - override suspend fun toUseCase( - request: WcSdkSessionRequest, - ): Either { - fun error(message: String) = WcRequestError.HandleMethodError(message).left() + override suspend fun toUseCase(request: WcSdkSessionRequest): Either { + fun error(message: String) = HandleMethodError.UnknownError(message).left() val name = toWcMethodName(request) ?: return error("Unknown method name") val method: WcSolanaMethod = name.toMethod(request) .getOrElse { return error(it.message.orEmpty()) } ?: return error("Failed to parse $name") val session = sessionsManager.findSessionByTopic(request.topic) - ?: return error("Failed to find session for topic ${request.topic}") + ?: return HandleMethodError.UnknownSession.left() val wallet = session.wallet val chainId = request.chainId.orEmpty() suspend fun anyExistNetwork() = networksConverter.mainOrAnyWalletNetworkForRequest(chainId, wallet) diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/DefaultWcRequestUseCaseFactory.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/DefaultWcRequestUseCaseFactory.kt index dfcecb1a92..53ad5c917a 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/DefaultWcRequestUseCaseFactory.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/DefaultWcRequestUseCaseFactory.kt @@ -5,8 +5,8 @@ import arrow.core.left import arrow.core.right import com.tangem.data.walletconnect.utils.WC_TAG import com.tangem.domain.walletconnect.WcRequestUseCaseFactory +import com.tangem.domain.walletconnect.model.HandleMethodError import com.tangem.domain.walletconnect.model.WcMethod -import com.tangem.domain.walletconnect.model.WcRequestError import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest import com.tangem.domain.walletconnect.usecase.method.WcMethodUseCase import timber.log.Timber @@ -19,18 +19,18 @@ internal class DefaultWcRequestUseCaseFactory @Inject constructor( @Suppress("UNCHECKED_CAST") override suspend fun createUseCase( request: WcSdkSessionRequest, - ): Either { + ): Either { val useCase = requestConverters .find { it.toWcMethodName(request) != null } ?.toUseCase(request) - ?: WcRequestError.HandleMethodError("Failed to create WcUseCase").left() + ?: HandleMethodError.UnknownError("Failed to create WcUseCase").left() return useCase.fold( ifLeft = { Timber.tag(WC_TAG).e("$it") - WcMethod.Unsupported(request).left() + it.left() }, - ifRight = { (it as? T)?.right() ?: WcMethod.Unsupported(request).left() }, + ifRight = { (it as? T)?.right() ?: HandleMethodError.Unsupported(WcMethod.Unsupported(request)).left() }, ) } } \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/WcRequestToUseCaseConverter.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/WcRequestToUseCaseConverter.kt index 4f7f8e7ad3..a12726f192 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/WcRequestToUseCaseConverter.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/request/WcRequestToUseCaseConverter.kt @@ -5,14 +5,14 @@ import arrow.core.left import arrow.core.right import com.squareup.moshi.Moshi import com.squareup.moshi.adapter +import com.tangem.domain.walletconnect.model.HandleMethodError import com.tangem.domain.walletconnect.model.WcMethodName -import com.tangem.domain.walletconnect.model.WcRequestError import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest import com.tangem.domain.walletconnect.usecase.method.WcMethodUseCase interface WcRequestToUseCaseConverter { fun toWcMethodName(request: WcSdkSessionRequest): WcMethodName? - suspend fun toUseCase(request: WcSdkSessionRequest): Either + suspend fun toUseCase(request: WcSdkSessionRequest): Either companion object { @OptIn(ExperimentalStdlibApi::class) diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt index fe6825d6e8..614d12dc9c 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt @@ -151,7 +151,22 @@ internal class DefaultWcSessionsManager( Timber.tag(WC_TAG).i("removeUnknownSessions $unknownStoredSessions") store.removeSessions(unknownStoredSessions.toSet()) } - return haveSomeUnknown + + val emptyNetworkSessions = wcSessions.filter { it.networks.isEmpty() } + val emptyNetworksDto = storeSessions + .filter { dto -> emptyNetworkSessions.find { it.sdkModel.topic == dto.topic } != null } + .toSet() + val haveEmptySessions = emptyNetworkSessions.isNotEmpty() + val haveEmptyDto = emptyNetworksDto.isNotEmpty() + + if (haveEmptyDto) { + Timber.tag(WC_TAG).i("remove sessions without networks $emptyNetworksDto") + store.removeSessions(emptyNetworksDto) + } + if (haveEmptySessions) { + emptyNetworkSessions.map { scope.launch { sdkDisconnectSession(it.sdkModel.topic) } } + } + return haveSomeUnknown || haveEmptyDto } private fun extendSessions() { diff --git a/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcRequestError.kt b/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcRequestError.kt index 58cc9cd17a..3c1cfe610a 100644 --- a/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcRequestError.kt +++ b/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcRequestError.kt @@ -13,10 +13,6 @@ sealed class WcRequestError { val message: String, ) : WcRequestError() - data class HandleMethodError( - val message: String, - ) : WcRequestError() - data class UnknownError(val ex: Throwable? = null) : WcRequestError() companion object { @@ -60,4 +56,17 @@ sealed class WcRequestError { -> null } } +} + +sealed class HandleMethodError( + open val message: String, +) : WcRequestError() { + + data class Unsupported( + val method: WcMethod.Unsupported, + ) : HandleMethodError(message = "Unsupported method ${method.request.request.method}") + + data object UnknownSession : HandleMethodError(message = "WalletConnect session was disconnected") + + data class UnknownError(override val message: String) : HandleMethodError(message) } \ No newline at end of file diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcRequestUseCaseFactory.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcRequestUseCaseFactory.kt index c8dac7cf04..0437576346 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcRequestUseCaseFactory.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcRequestUseCaseFactory.kt @@ -1,11 +1,11 @@ package com.tangem.domain.walletconnect import arrow.core.Either -import com.tangem.domain.walletconnect.model.WcMethod +import com.tangem.domain.walletconnect.model.HandleMethodError import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest import com.tangem.domain.walletconnect.usecase.method.WcMethodUseCase interface WcRequestUseCaseFactory { - suspend fun createUseCase(request: WcSdkSessionRequest): Either + suspend fun createUseCase(request: WcSdkSessionRequest): Either } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/DefaultWcRoutingComponent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/DefaultWcRoutingComponent.kt index 12f96545e8..42b336932f 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/DefaultWcRoutingComponent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/DefaultWcRoutingComponent.kt @@ -91,6 +91,12 @@ internal class DefaultWcRoutingComponent @AssistedInject constructor( alertType = AlertsComponent.AlertType.UnsupportedMethod { model.innerRouter.pop() }, ), ) + is WcInnerRoute.WcDappDisconnected -> AlertsComponent( + childContext, + AlertsComponent.Params( + alertType = AlertsComponent.AlertType.WcDisconnected { model.innerRouter.pop() }, + ), + ) } } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcInnerRoute.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcInnerRoute.kt index 879db0d3bc..4cabfc0547 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcInnerRoute.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcInnerRoute.kt @@ -26,5 +26,8 @@ internal sealed interface WcInnerRoute : Route { data class Pair(val request: WcPairRequest) : WcInnerRoute @Serializable - data class UnsupportedMethodAlert(override val rawRequest: WcSdkSessionRequest) : Method + data object UnsupportedMethodAlert : WcInnerRoute + + @Serializable + data object WcDappDisconnected : WcInnerRoute } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcRoutingModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcRoutingModel.kt index d929e0f386..3c320faab7 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcRoutingModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routing/WcRoutingModel.kt @@ -57,7 +57,7 @@ internal class WcRoutingModel @Inject constructor( WcSolanaMethodName.SendAllTransaction, -> WcInnerRoute.Send(rawRequest) is WcMethodName.Unsupported, - -> WcInnerRoute.UnsupportedMethodAlert(rawRequest) + -> WcInnerRoute.UnsupportedMethodAlert } } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcHandleMethodErrorConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcHandleMethodErrorConverter.kt new file mode 100644 index 0000000000..6c6d317053 --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcHandleMethodErrorConverter.kt @@ -0,0 +1,16 @@ +package com.tangem.features.walletconnect.transaction.converter + +import com.tangem.domain.walletconnect.model.HandleMethodError +import com.tangem.features.walletconnect.connections.routing.WcInnerRoute +import com.tangem.utils.converter.Converter + +internal object WcHandleMethodErrorConverter : + Converter { + + override fun convert(value: HandleMethodError): WcInnerRoute = when (value) { + is HandleMethodError.Unsupported, + is HandleMethodError.UnknownError, + -> WcInnerRoute.UnsupportedMethodAlert + HandleMethodError.UnknownSession -> WcInnerRoute.WcDappDisconnected + } +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt index 911d108202..aadda1804d 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt @@ -10,9 +10,9 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase -import com.tangem.features.walletconnect.connections.routing.WcInnerRoute import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams import com.tangem.features.walletconnect.transaction.converter.WcAddEthereumChainUMConverter +import com.tangem.features.walletconnect.transaction.converter.WcHandleMethodErrorConverter import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainUM import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM @@ -45,7 +45,7 @@ internal class WcAddNetworkModel @Inject constructor( init { modelScope.launch { val useCase: WcAddNetworkUseCase = useCaseFactory.createUseCase(params.rawRequest) - .onLeft { router.push(WcInnerRoute.UnsupportedMethodAlert(params.rawRequest)) } + .onLeft { router.push(WcHandleMethodErrorConverter.convert(it)) } .getOrNull() ?: return@launch _uiState.emit( wcAddEthereumChainUMConverter.convert( diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt index 8db2220da8..f374a016fb 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt @@ -36,6 +36,7 @@ import com.tangem.features.send.v2.api.params.FeeSelectorParams import com.tangem.features.walletconnect.connections.routing.WcInnerRoute import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter +import com.tangem.features.walletconnect.transaction.converter.WcHandleMethodErrorConverter import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM @@ -84,9 +85,9 @@ internal class WcSendTransactionModel @Inject constructor( init { @Suppress("UnusedPrivateMember") modelScope.launch { - val unknownMethodRunnable = { router.push(WcInnerRoute.UnsupportedMethodAlert(params.rawRequest)) } + val unknownMethodRunnable = { router.push(WcInnerRoute.UnsupportedMethodAlert) } val useCase = useCaseFactory.createUseCase>(params.rawRequest) - .onLeft { unknownMethodRunnable() } + .onLeft { router.push(WcHandleMethodErrorConverter.convert(it)) } .getOrNull() ?: return@launch when (useCase) { is WcListTransactionUseCase, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt index 34252a2a2e..941a5ae3e9 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt @@ -14,9 +14,9 @@ import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase import com.tangem.domain.walletconnect.usecase.method.WcSignState import com.tangem.domain.walletconnect.usecase.method.WcSignStep import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase -import com.tangem.features.walletconnect.connections.routing.WcInnerRoute import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter +import com.tangem.features.walletconnect.transaction.converter.WcHandleMethodErrorConverter import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM @@ -50,7 +50,7 @@ internal class WcSignTransactionModel @Inject constructor( init { modelScope.launch { val useCase = useCaseFactory.createUseCase(params.rawRequest) - .onLeft { router.push(WcInnerRoute.UnsupportedMethodAlert(params.rawRequest)) } + .onLeft { router.push(WcHandleMethodErrorConverter.convert(it)) } .getOrNull() ?: return@launch useCase.invoke() .onEach { signState ->