diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthAddNetworkUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthAddNetworkUseCase.kt index 5c988f8a8e..bf9f6674f9 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthAddNetworkUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthAddNetworkUseCase.kt @@ -3,7 +3,11 @@ package com.tangem.data.walletconnect.network.ethereum import arrow.core.Either import arrow.core.left import arrow.core.right +import com.reown.walletkit.client.Wallet +import com.reown.walletkit.client.Wallet.Model +import com.reown.walletkit.client.WalletKit import com.tangem.blockchain.extensions.hexToInt +import com.tangem.data.walletconnect.model.CAIP10 import com.tangem.data.walletconnect.model.CAIP2 import com.tangem.data.walletconnect.network.ethereum.WcEthNetwork.NamespaceConverter.Companion.ETH_NAMESPACE_KEY import com.tangem.data.walletconnect.respond.WcRespondService @@ -21,9 +25,12 @@ import com.tangem.domain.walletconnect.usecase.method.WcNetworkDerivationState import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume internal class WcEthAddNetworkUseCase @AssistedInject constructor( private val respondService: WcRespondService, + private val networksConverter: WcNetworksConverter, addSwitchCommonDelegateFactory: WcEthAddSwitchCommonDelegate.Factory, @Assisted val context: WcMethodUseCaseContext, @Assisted override val method: WcEthMethod.AddEthereumChain, @@ -45,13 +52,58 @@ internal class WcEthAddNetworkUseCase @AssistedInject constructor( override suspend fun invoke(): Either { return addSwitchCommonDelegate .commonChecks(method.rawChain.chainId) - .map { addedNetwork -> WcAddNetworkUseCase.AddNetwork(addedNetwork) } + .map { addedNetwork -> + WcAddNetworkUseCase.AddNetwork( + network = addedNetwork, + isExistInWcSession = addSwitchCommonDelegate.existInWcSession(addedNetwork), + ) + } } override suspend fun approve(): Either { + fun illegalState() = WcRequestError.UnknownError(IllegalStateException("IllegalStateException")).left() + val requestedNetworkCAIP2 = CAIP2.fromRaw(rawSdkRequest.chainId.orEmpty()) ?: return illegalState() + val networkToAddCAIP2 = addSwitchCommonDelegate.hexChainIdToCAIP2(method.rawChain.chainId) + ?: return illegalState() + val namespaces = session.sdkModel.namespaces[requestedNetworkCAIP2.namespace] + ?: return illegalState() + // find and add all derivation + val networkToAddCAIP10 = networksConverter + .allAddressForChain(networkToAddCAIP2.raw, wallet) + .map { address -> CAIP10(networkToAddCAIP2, address).raw } + val newNamespaces = namespaces.copy( + chains = namespaces.chains.plus(networkToAddCAIP2.raw), + accounts = namespaces.accounts.plus(networkToAddCAIP10), + ) + val sdkNewNamespaces = session.sdkModel.namespaces + .plus(requestedNetworkCAIP2.namespace to newNamespaces) + .mapValues { (_, session) -> + Model.Namespace.Session( + chains = session.chains, + accounts = session.accounts, + methods = session.methods, + events = session.events, + ) + } + + val sessionUpdate = Wallet.Params.SessionUpdate( + sessionTopic = context.session.sdkModel.topic, + namespaces = sdkNewNamespaces, + ) + sdkUpdateSession(sessionUpdate) // ignore result for now return respondService.respond(rawSdkRequest, "") } + private suspend fun sdkUpdateSession(sessionUpdate: Wallet.Params.SessionUpdate): Either { + return suspendCancellableCoroutine { continuation -> + WalletKit.updateSession( + params = sessionUpdate, + onSuccess = { if (continuation.isActive) continuation.resume(Unit.right()) }, + onError = { if (continuation.isActive) continuation.resume(it.throwable.left()) }, + ) + } + } + override fun reject() { respondService.rejectRequestNonBlock(rawSdkRequest) } @@ -69,8 +121,14 @@ internal class WcEthAddSwitchCommonDelegate @AssistedInject constructor( private val wallet: UserWallet get() = context.session.wallet + fun hexChainIdToCAIP2(hexChainId: String): CAIP2? = CAIP2.fromRaw("$ETH_NAMESPACE_KEY:${hexChainId.hexToInt()}") + + fun existInWcSession(network: Network): Boolean { + return context.session.networks.any { it.rawId == network.rawId } + } + suspend fun commonChecks(hexChainId: String): Either { - val caip2 = CAIP2.fromRaw("$ETH_NAMESPACE_KEY:${hexChainId.hexToInt()}") + val caip2 = hexChainIdToCAIP2(hexChainId) ?: return HandleMethodError.UnknownError("Failed to parse CAIP2").left() val generalNetwork = networksConverter.createNetwork(caip2.raw, wallet) if (generalNetwork == null) { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSwitchNetworkUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSwitchNetworkUseCase.kt index 0835594dfe..5b94908fa8 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSwitchNetworkUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSwitchNetworkUseCase.kt @@ -37,7 +37,12 @@ internal class WcEthSwitchNetworkUseCase @AssistedInject constructor( override suspend fun invoke(): Either { return addSwitchCommonDelegate .commonChecks(method.rawChain.chainId) - .map { addedNetwork -> WcSwitchNetworkUseCase.SwitchNetwork(addedNetwork) } + .map { addedNetwork -> + WcSwitchNetworkUseCase.SwitchNetwork( + network = addedNetwork, + isExistInWcSession = addSwitchCommonDelegate.existInWcSession(addedNetwork), + ) + } } override fun reject() { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNetworksConverter.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNetworksConverter.kt index 4b49445c7f..a7d1d285fb 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNetworksConverter.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNetworksConverter.kt @@ -53,6 +53,11 @@ internal class WcNetworksConverter @Inject constructor( return networks.firstOrNull { !isCustomCoin(it) } ?: networks.firstOrNull() } + suspend fun allAddressForChain(rawChainId: String, wallet: UserWallet): List { + return filterWalletNetworkForRequest(rawChainId, wallet) + .mapNotNull { walletManagersFacade.getDefaultAddress(wallet.walletId, it)?.lowercase() } + } + /** * return all exist derivation networks */ diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcSdkSessionConverter.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcSdkSessionConverter.kt index 0f2e570acd..f588c4f171 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcSdkSessionConverter.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcSdkSessionConverter.kt @@ -10,6 +10,14 @@ internal object WcSdkSessionConverter : Converter + WcSdkSession.Session( + chains = session.chains ?: listOf(), + accounts = session.accounts, + methods = session.methods, + events = session.events, + ) + }, ) } } \ No newline at end of file diff --git a/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt b/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt index e68555c7c1..15049820a7 100644 --- a/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt +++ b/data/wallet-connect/src/test/kotlin/com/tangem/domain/walletconnect/WcSignUseCaseDelegateTest.kt @@ -62,6 +62,7 @@ internal class WcSignUseCaseDelegateTest { connectingTime = 0L, sdkModel = WcSdkSession( topic = "", + namespaces = mapOf(), appMetaData = WcAppMetaData( name = "", description = "", diff --git a/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/sdkcopy/WcSdkSession.kt b/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/sdkcopy/WcSdkSession.kt index 9b2d6c45b7..63ea82098f 100644 --- a/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/sdkcopy/WcSdkSession.kt +++ b/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/sdkcopy/WcSdkSession.kt @@ -6,4 +6,12 @@ package com.tangem.domain.walletconnect.model.sdkcopy data class WcSdkSession( val topic: String, val appMetaData: WcAppMetaData, -) \ No newline at end of file + val namespaces: Map, +) { + data class Session( + val chains: List, + val accounts: List, + val methods: List, + val events: List, + ) +} \ No newline at end of file diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcAddNetworkUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcAddNetworkUseCase.kt index 35223ba040..7573141b6d 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcAddNetworkUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcAddNetworkUseCase.kt @@ -15,5 +15,6 @@ interface WcAddNetworkUseCase : data class AddNetwork( val network: Network, + val isExistInWcSession: Boolean, ) } \ No newline at end of file diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcSwitchNetworkUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcSwitchNetworkUseCase.kt index 5c2066049a..b7980f5500 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcSwitchNetworkUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcSwitchNetworkUseCase.kt @@ -13,5 +13,6 @@ interface WcSwitchNetworkUseCase : data class SwitchNetwork( val network: Network, + val isExistInWcSession: Boolean, ) } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/AlertsModalBottomSheet.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/AlertsModalBottomSheet.kt index c7ff306829..30370ab112 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/AlertsModalBottomSheet.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/AlertsModalBottomSheet.kt @@ -177,7 +177,7 @@ private fun AlertContentDescription(alert: AlertsComponent.AlertType, modifier: R.string.wc_alert_unsupported_method_description, ) is AlertsComponent.AlertType.RequiredAddNetwork -> stringResourceSafe( - R.string.wc_alert_unsupported_method_description, + R.string.wc_alert_add_network_to_portfolio_description, alert.network, ) is AlertsComponent.AlertType.RequiredReconnectWithNetwork -> stringResourceSafe( 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 f85c7a6003..ab284df37a 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 @@ -60,7 +60,9 @@ internal class WcAddNetworkModel @Inject constructor( val either = useCase.invoke() either .onLeft { router.push(WcHandleMethodErrorConverter.convert(it)) } - .map { showUI() } + .map { + if (it.isExistInWcSession) cancel(useCase) else showUI() + } } } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSwitchNetworkModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSwitchNetworkModel.kt index 65b63ae8b6..d8c49a7508 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSwitchNetworkModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSwitchNetworkModel.kt @@ -35,7 +35,13 @@ internal class WcSwitchNetworkModel @Inject constructor( useCase.reject() either .onLeft { showErrorDialog(it) } - .map { showErrorDialog(HandleMethodError.RequiredNetwork(it.network.name)) } + .map { + if (it.isExistInWcSession) { + router.pop() + } else { + showErrorDialog(HandleMethodError.RequiredNetwork(it.network.name)) + } + } } }