Updated on 2026-08-14
This commit is contained in:
parent
4f4e0a19fc
commit
0f9ba0ce7e
13 changed files with 101 additions and 42 deletions
|
|
@ -9,6 +9,7 @@ import com.tangem.data.walletconnect.network.ethereum.WcEthNetwork
|
|||
import com.tangem.data.walletconnect.network.solana.WcSolanaNetwork
|
||||
import com.tangem.data.walletconnect.pair.AssociateNetworksDelegate
|
||||
import com.tangem.data.walletconnect.pair.CaipNamespaceDelegate
|
||||
import com.tangem.data.walletconnect.pair.DefaultWcPairService
|
||||
import com.tangem.data.walletconnect.pair.DefaultWcPairUseCase
|
||||
import com.tangem.data.walletconnect.pair.WcPairSdkDelegate
|
||||
import com.tangem.data.walletconnect.request.DefaultWcRequestService
|
||||
|
|
@ -18,10 +19,11 @@ import com.tangem.data.walletconnect.respond.WcRespondService
|
|||
import com.tangem.data.walletconnect.sessions.DefaultWcSessionsManager
|
||||
import com.tangem.data.walletconnect.utils.WcNamespaceConverter
|
||||
import com.tangem.datasource.di.SdkMoshi
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||
import com.tangem.domain.blockaid.BlockAidVerifier
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.walletconnect.WcPairService
|
||||
import com.tangem.domain.walletconnect.model.legacy.WalletConnectSessionsRepository
|
||||
import com.tangem.domain.walletconnect.repository.WalletConnectRepository
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
|
|
@ -58,32 +60,24 @@ internal object WalletConnectDataModule {
|
|||
sessionsManager: DefaultWcSessionsManager,
|
||||
networkService: DefaultWcRequestService,
|
||||
pairSdkDelegate: WcPairSdkDelegate,
|
||||
environmentConfigStorage: EnvironmentConfigStorage,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): WcInitializeUseCase = DefaultWcInitializeUseCase(
|
||||
application = application,
|
||||
sessionsManager = sessionsManager,
|
||||
networkService = networkService,
|
||||
pairSdkDelegate = pairSdkDelegate,
|
||||
environmentConfigStorage = environmentConfigStorage,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun defaultWcPairUseCase(
|
||||
sessionsManager: WcSessionsManager,
|
||||
associateNetworksDelegate: AssociateNetworksDelegate,
|
||||
caipNamespaceDelegate: CaipNamespaceDelegate,
|
||||
sdkDelegate: WcPairSdkDelegate,
|
||||
blockAidVerifier: BlockAidVerifier,
|
||||
): DefaultWcPairUseCase = DefaultWcPairUseCase(
|
||||
sessionsManager = sessionsManager,
|
||||
associateNetworksDelegate = associateNetworksDelegate,
|
||||
caipNamespaceDelegate = caipNamespaceDelegate,
|
||||
sdkDelegate = sdkDelegate,
|
||||
blockAidVerifier = blockAidVerifier,
|
||||
)
|
||||
fun defaultWcPairUseCase(): WcPairService = DefaultWcPairService()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun wcPairUseCase(default: DefaultWcPairUseCase): WcPairUseCase = default
|
||||
fun wcPairUseCaseFactory(default: DefaultWcPairUseCase.Factory): WcPairUseCase.Factory = default
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ import com.tangem.data.walletconnect.pair.WcPairSdkDelegate
|
|||
import com.tangem.data.walletconnect.request.DefaultWcRequestService
|
||||
import com.tangem.data.walletconnect.sessions.DefaultWcSessionsManager
|
||||
import com.tangem.data.walletconnect.utils.WcSdkObserver
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.domain.walletconnect.usecase.initialize.WcInitializeUseCase
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultWcInitializeUseCase(
|
||||
|
|
@ -18,6 +21,8 @@ internal class DefaultWcInitializeUseCase(
|
|||
private val sessionsManager: DefaultWcSessionsManager,
|
||||
private val networkService: DefaultWcRequestService,
|
||||
private val pairSdkDelegate: WcPairSdkDelegate,
|
||||
private val environmentConfigStorage: EnvironmentConfigStorage,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : WcInitializeUseCase {
|
||||
|
||||
private val wcSdkObservers = mutableSetOf<WcSdkObserver>(
|
||||
|
|
@ -26,7 +31,8 @@ internal class DefaultWcInitializeUseCase(
|
|||
pairSdkDelegate,
|
||||
)
|
||||
|
||||
override fun init(projectId: String) {
|
||||
override suspend fun init() = withContext(dispatchers.io) {
|
||||
val projectId = environmentConfigStorage.getConfigSync().walletConnectProjectId
|
||||
val relayUrl = "relay.walletconnect.com"
|
||||
val serverUrl = "wss://$relayUrl?projectId=$projectId"
|
||||
val connectionType = ConnectionType.AUTOMATIC
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.data.walletconnect.pair
|
||||
|
||||
import com.tangem.domain.walletconnect.WcPairService
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
class DefaultWcPairService @Inject constructor() : WcPairService {
|
||||
private val _pairFlow: Channel<WcPairRequest> = Channel(Channel.BUFFERED)
|
||||
override val pairFlow: Flow<WcPairRequest> = _pairFlow.receiveAsFlow()
|
||||
|
||||
override fun pair(request: WcPairRequest) {
|
||||
_pairFlow.trySend(request)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,15 +9,15 @@ import com.domain.blockaid.models.dapp.DAppData
|
|||
import com.reown.walletkit.client.Wallet
|
||||
import com.tangem.data.walletconnect.utils.WcSdkSessionConverter
|
||||
import com.tangem.domain.blockaid.BlockAidVerifier
|
||||
import com.tangem.domain.walletconnect.model.WcPairError
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.WcSessionApprove
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.walletconnect.model.*
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcAppMetaData
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairState
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
|
@ -27,17 +27,19 @@ import timber.log.Timber
|
|||
|
||||
val unsupportedDApps = listOf("dYdX", "dYdX v4", "Apex Pro", "The Sandbox")
|
||||
|
||||
internal class DefaultWcPairUseCase(
|
||||
internal class DefaultWcPairUseCase @AssistedInject constructor(
|
||||
private val sessionsManager: WcSessionsManager,
|
||||
private val associateNetworksDelegate: AssociateNetworksDelegate,
|
||||
private val caipNamespaceDelegate: CaipNamespaceDelegate,
|
||||
private val sdkDelegate: WcPairSdkDelegate,
|
||||
private val blockAidVerifier: BlockAidVerifier,
|
||||
@Assisted private val pairRequest: WcPairRequest,
|
||||
) : WcPairUseCase {
|
||||
|
||||
private val onCallTerminalAction = Channel<TerminalAction>()
|
||||
|
||||
override fun pairFlow(uri: String, source: WcPairUseCase.Source): Flow<WcPairState> {
|
||||
override operator fun invoke(): Flow<WcPairState> {
|
||||
val (uri: String, source: WcPairRequest.Source) = pairRequest
|
||||
return flow {
|
||||
emit(WcPairState.Loading)
|
||||
|
||||
|
|
@ -151,4 +153,9 @@ internal class DefaultWcPairUseCase(
|
|||
data class Approve(val sessionForApprove: WcSessionApprove) : TerminalAction
|
||||
data object Reject : TerminalAction
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : WcPairUseCase.Factory {
|
||||
override fun create(pairRequest: WcPairRequest): DefaultWcPairUseCase
|
||||
}
|
||||
}
|
||||
|
|
@ -15,11 +15,11 @@ import com.tangem.data.walletconnect.pair.WcPairSdkDelegate
|
|||
import com.tangem.data.walletconnect.utils.WcSdkSessionConverter
|
||||
import com.tangem.domain.blockaid.BlockAidVerifier
|
||||
import com.tangem.domain.walletconnect.model.WcPairError
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.WcSessionApprove
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairState
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerifyOrder
|
||||
import io.mockk.mockk
|
||||
|
|
@ -37,7 +37,7 @@ internal class DefaultWcPairUseCaseTest {
|
|||
private val blockAidVerifier: BlockAidVerifier = mockk<BlockAidVerifier>()
|
||||
|
||||
private val url = "testUrl"
|
||||
private val source = WcPairUseCase.Source.QR
|
||||
private val source = WcPairRequest.Source.QR
|
||||
private val loading = WcPairState.Loading
|
||||
private val sdkProposal: Wallet.Model.SessionProposal
|
||||
get() = Wallet.Model.SessionProposal(
|
||||
|
|
@ -93,12 +93,13 @@ internal class DefaultWcPairUseCaseTest {
|
|||
securityStatus = CheckDAppResult.SAFE,
|
||||
)
|
||||
|
||||
private val useCase = DefaultWcPairUseCase(
|
||||
private fun useCaseFactory() = DefaultWcPairUseCase(
|
||||
sessionsManager = sessionsManager,
|
||||
associateNetworksDelegate = associateNetworksDelegate,
|
||||
caipNamespaceDelegate = caipNamespaceDelegate,
|
||||
sdkDelegate = sdkDelegate,
|
||||
blockAidVerifier = blockAidVerifier,
|
||||
pairRequest = WcPairRequest(url, source),
|
||||
)
|
||||
|
||||
@Before
|
||||
|
|
@ -118,7 +119,8 @@ internal class DefaultWcPairUseCaseTest {
|
|||
coEvery { sdkDelegate.pair(url) } returns sdkProposal.right()
|
||||
coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE }
|
||||
|
||||
useCase.pairFlow(url, source).test {
|
||||
val useCase = useCaseFactory()
|
||||
useCase.invoke().test {
|
||||
assertEquals(loading, awaitItem())
|
||||
coVerifyOrder {
|
||||
sdkDelegate.pair(url)
|
||||
|
|
@ -140,7 +142,8 @@ internal class DefaultWcPairUseCaseTest {
|
|||
coEvery { sessionsManager.saveSession(sessionForSave) } returns Unit
|
||||
coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE }
|
||||
|
||||
useCase.pairFlow(url, source).test {
|
||||
val useCase = useCaseFactory()
|
||||
useCase.invoke().test {
|
||||
assertEquals(loading, awaitItem())
|
||||
coVerifyOrder {
|
||||
sdkDelegate.pair(url)
|
||||
|
|
@ -169,7 +172,8 @@ internal class DefaultWcPairUseCaseTest {
|
|||
coEvery { sdkDelegate.rejectSession(proposerPublicKey) } returns Unit
|
||||
coEvery { blockAidVerifier.verifyDApp(any()) } returns Either.catch { CheckDAppResult.SAFE }
|
||||
|
||||
useCase.pairFlow(url, source).test {
|
||||
val useCase = useCaseFactory()
|
||||
useCase.invoke().test {
|
||||
assertEquals(loading, awaitItem())
|
||||
coVerifyOrder {
|
||||
sdkDelegate.pair(url)
|
||||
|
|
@ -189,7 +193,8 @@ internal class DefaultWcPairUseCaseTest {
|
|||
coEvery { sdkDelegate.pair(url) } returns unsupportedSdkProposal.right()
|
||||
val unsupportedDAppError = WcPairState.Error(WcPairError.UnsupportedDApp)
|
||||
|
||||
useCase.pairFlow(url, source).test {
|
||||
val useCase = useCaseFactory()
|
||||
useCase.invoke().test {
|
||||
assertEquals(loading, awaitItem())
|
||||
coVerifyOrder {
|
||||
sdkDelegate.pair(url)
|
||||
|
|
@ -205,7 +210,8 @@ internal class DefaultWcPairUseCaseTest {
|
|||
coEvery { sdkDelegate.pair(url) } returns error.left()
|
||||
val errorState = WcPairState.Error(error)
|
||||
|
||||
useCase.pairFlow(url, source).test {
|
||||
val useCase = useCaseFactory()
|
||||
useCase.invoke().test {
|
||||
assertEquals(loading, awaitItem())
|
||||
coVerifyOrder {
|
||||
sdkDelegate.pair(url)
|
||||
|
|
@ -225,7 +231,8 @@ internal class DefaultWcPairUseCaseTest {
|
|||
|
||||
val errorResult = WcPairState.Approving.Result(sessionForApprove, error)
|
||||
|
||||
useCase.pairFlow(url, source).test {
|
||||
val useCase = useCaseFactory()
|
||||
useCase.invoke().test {
|
||||
assertEquals(loading, awaitItem())
|
||||
coVerifyOrder {
|
||||
sdkDelegate.pair(url)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.ksp)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
dependencies {
|
||||
|
|
@ -13,4 +14,7 @@ dependencies {
|
|||
/* Other */
|
||||
implementation(deps.moshi)
|
||||
ksp(deps.moshi.kotlin.codegen)
|
||||
|
||||
/* Utils */
|
||||
implementation(deps.kotlin.serialization)
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.walletconnect.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class WcPairRequest(
|
||||
val uri: String,
|
||||
val source: Source,
|
||||
) {
|
||||
enum class Source { QR, DEEPLINK, CLIPBOARD, ETC }
|
||||
}
|
||||
|
|
@ -1,14 +1,18 @@
|
|||
package com.tangem.domain.walletconnect.model.sdkcopy
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* copy of [com.reown.walletkit.client.Wallet.Model.SessionRequest]
|
||||
*/
|
||||
@Serializable
|
||||
data class WcSdkSessionRequest(
|
||||
val topic: String,
|
||||
val chainId: String?,
|
||||
val request: JSONRPCRequest,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class JSONRPCRequest(
|
||||
val id: Long,
|
||||
val method: String,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.domain.walletconnect
|
||||
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface WcPairService {
|
||||
val pairFlow: Flow<WcPairRequest>
|
||||
|
||||
fun pair(request: WcPairRequest)
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
package com.tangem.domain.walletconnect.usecase.initialize
|
||||
|
||||
interface WcInitializeUseCase {
|
||||
fun init(projectId: String)
|
||||
suspend fun init()
|
||||
}
|
||||
|
|
@ -1,20 +1,19 @@
|
|||
package com.tangem.domain.walletconnect.usecase.pair
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.walletconnect.model.WcPairError
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.WcSessionApprove
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.walletconnect.model.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface WcPairUseCase {
|
||||
|
||||
fun pairFlow(uri: String, source: Source): Flow<WcPairState>
|
||||
operator fun invoke(): Flow<WcPairState>
|
||||
|
||||
fun approve(sessionForApprove: WcSessionApprove)
|
||||
fun reject()
|
||||
|
||||
enum class Source { QR, DEEPLINK, CLIPBOARD, ETC }
|
||||
interface Factory {
|
||||
fun create(pairRequest: WcPairRequest): WcPairUseCase
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface WcPairState {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.features.walletconnect.connections.model.WcConnectionsModel
|
||||
import com.tangem.features.walletconnect.connections.routes.WcConnectionsBottomSheetRoutes
|
||||
import com.tangem.features.walletconnect.connections.ui.WcConnectionsContent
|
||||
|
|
@ -48,7 +48,7 @@ internal class ConnectionsComponent(
|
|||
appComponentContext = childByContext(componentContext),
|
||||
params = WcAppInfoContainerComponent.Params(
|
||||
wcUrl = config.wcUrl,
|
||||
source = WcPairUseCase.Source.QR,
|
||||
source = WcPairRequest.Source.QR,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
|||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.features.walletconnect.connections.model.WcAppInfoModel
|
||||
import com.tangem.features.walletconnect.connections.routes.WcAppInfoRoutes
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
|
|
@ -103,5 +103,5 @@ internal class WcAppInfoContainerComponent(
|
|||
WcAppInfoRoutes.SelectWallet -> TODO()
|
||||
}
|
||||
|
||||
data class Params(val wcUrl: String, val source: WcPairUseCase.Source, val onDismiss: () -> Unit)
|
||||
data class Params(val wcUrl: String, val source: WcPairRequest.Source, val onDismiss: () -> Unit)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue