Updated on 2026-08-14
This commit is contained in:
parent
c039057700
commit
47ba4043a3
10 changed files with 30 additions and 16 deletions
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Account>) {
|
||||
if (isNewWc) return
|
||||
Timber.i("Approve session proposal: $accounts")
|
||||
val userNamespaces: Map<NetworkNamespace, List<Account>> = 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()
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue