Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-03 15:51:03 +07:00
parent 3bbdbbb5a3
commit de6683b57a
11 changed files with 94 additions and 55 deletions

View file

@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.Flow
internal typealias WcSessionCollection = Set<WcSessionDTO>
class DefaultWalletConnectStore(
internal class DefaultWalletConnectStore(
private val persistenceStore: DataStore<WcSessionCollection>,
) : WalletConnectStore {

View file

@ -17,7 +17,6 @@ import com.tangem.domain.walletconnect.usecase.ethereum.WcEthMethod.SignMessage
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
@Suppress("UnusedPrivateClass") // todo(wc) remove later
internal class WcEthNetwork(
private val moshi: Moshi,
private val respondService: WcRespondService,

View file

@ -6,7 +6,7 @@ import arrow.core.right
import com.reown.walletkit.client.Wallet
import com.reown.walletkit.client.WalletKit
import com.tangem.data.walletconnect.utils.WcSdkObserver
import com.tangem.data.walletconnect.utils.toOurModel
import com.tangem.data.walletconnect.utils.WcSdkSessionConverter
import com.tangem.domain.walletconnect.model.WcPairError
import com.tangem.domain.walletconnect.model.WcSession
import com.tangem.domain.walletconnect.model.WcSessionApprove
@ -15,7 +15,6 @@ 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 com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
@ -28,7 +27,6 @@ import kotlin.coroutines.resume
val unsupportedDApps = listOf("dYdX", "dYdX v4", "Apex Pro", "The Sandbox")
@Suppress("UnusedPrivateMember") // todo(wc) remove after add mapping
internal class DefaultWcPairUseCase(
private val sessionsManager: WcSessionsManager,
private val associateNetworksDelegate: AssociateNetworksDelegate,
@ -40,8 +38,8 @@ internal class DefaultWcPairUseCase(
Channel<Pair<Wallet.Model.SessionProposal, Wallet.Model.VerifyContext>>(Channel.BUFFERED)
private val onSessionSettleResponse = Channel<Wallet.Model.SettledSessionResponse>(Channel.BUFFERED)
override fun pairFlow(uri: String, source: WcPairUseCase.Source, selectedWallet: UserWallet): Flow<WcPairState> =
flow {
override fun pairFlow(uri: String, source: WcPairUseCase.Source): Flow<WcPairState> {
return flow {
emit(WcPairState.Loading)
// call sdk.pair and wait result, finish flow on error
@ -63,7 +61,7 @@ internal class DefaultWcPairUseCase(
return@flow
}
val proposalState = buildProposalState(sdkSessionProposal, verifyContext)
val proposalState = buildProposalState(sdkSessionProposal)
.fold(ifLeft = { WcPairState.Error(it) }, ifRight = { it })
emit(proposalState)
@ -104,6 +102,7 @@ internal class DefaultWcPairUseCase(
)
emit(WcPairState.Approving.Result(sessionForApprove, either))
}
}
override fun approve(sessionForApprove: WcSessionApprove) {
onCallTerminalAction.trySend(TerminalAction.Approve(sessionForApprove))
@ -188,7 +187,6 @@ internal class DefaultWcPairUseCase(
private suspend fun buildProposalState(
sessionProposal: Wallet.Model.SessionProposal,
verifyContext: Wallet.Model.VerifyContext,
): Either<WcPairError, WcPairState.Proposal> = runCatching {
val proposalNetwork = associateNetworksDelegate.associate(sessionProposal)
val appMetaData = WcAppMetaData(
@ -213,7 +211,7 @@ internal class DefaultWcPairUseCase(
private fun Wallet.Model.Session.toDomain(walletId: UserWalletId): WcSession = WcSession(
userWalletId = walletId,
sdkModel = this.toOurModel(),
sdkModel = WcSdkSessionConverter.convert(this),
)
private sealed interface TerminalAction {

View file

@ -2,7 +2,7 @@ package com.tangem.data.walletconnect.request
import com.reown.walletkit.client.Wallet
import com.tangem.data.walletconnect.utils.WcSdkObserver
import com.tangem.data.walletconnect.utils.toOurModel
import com.tangem.data.walletconnect.utils.WcSdkSessionRequestConverter
import com.tangem.domain.walletconnect.model.WcMethod
import com.tangem.domain.walletconnect.model.WcRequest
import com.tangem.domain.walletconnect.repository.WcSessionsManager
@ -16,7 +16,7 @@ internal class DefaultWcRequestService(
private val sessionsManager: WcSessionsManager,
private val respondService: WcRespondService,
private val requestAdapters: Set<WcMethodHandler<WcMethod>>,
private val scope: CoroutineScope, // todo(wc) is ok inject scope? featureScope like Decompose Model scope
private val scope: CoroutineScope,
) : WcRequestService, WcSdkObserver {
override val requests: MutableSharedFlow<WcRequest<*>> = MutableSharedFlow()
@ -26,7 +26,7 @@ internal class DefaultWcRequestService(
verifyContext: Wallet.Model.VerifyContext,
) {
// Triggered when a Dapp sends SessionRequest to sign a transaction or a message
val sr = sessionRequest.toOurModel()
val sr = WcSdkSessionRequestConverter.convert(sessionRequest)
val method = sr.request.method
val params = sr.request.params
scope.launch {

View file

@ -3,7 +3,7 @@ package com.tangem.data.walletconnect.sessions
import com.reown.walletkit.client.Wallet
import com.reown.walletkit.client.WalletKit
import com.tangem.data.walletconnect.utils.WcSdkObserver
import com.tangem.data.walletconnect.utils.toOurModel
import com.tangem.data.walletconnect.utils.WcSdkSessionConverter
import com.tangem.datasource.local.walletconnect.WalletConnectStore
import com.tangem.domain.walletconnect.model.WcSession
import com.tangem.domain.walletconnect.model.WcSessionDTO
@ -44,7 +44,7 @@ internal class DefaultWcSessionsManager constructor(
override suspend fun findSessionByTopic(topic: String): WcSession? = withContext(dispatchers.io) {
val storedSessions = store.findSessionByTopic(topic) ?: return@withContext null
val sdkSession = WalletKit.getActiveSessionByTopic(topic) ?: return@withContext null
WcSession(userWalletId = storedSessions.walletId, sdkModel = sdkSession.toOurModel())
WcSession(userWalletId = storedSessions.walletId, sdkModel = WcSdkSessionConverter.convert(sdkSession))
}
override fun onSessionDelete(sessionDelete: Wallet.Model.SessionDelete) {
@ -74,7 +74,7 @@ internal class DefaultWcSessionsManager constructor(
val wcSessions = sdkSessions.mapNotNull { sdkSession ->
val storedSessions = storeSessions.find { it.topic == sdkSession.topic }
?: return@mapNotNull null
WcSession(userWalletId = storedSessions.walletId, sdkModel = sdkSession.toOurModel())
WcSession(userWalletId = storedSessions.walletId, sdkModel = WcSdkSessionConverter.convert(sdkSession))
}
val unknownStoredSessions = storeSessions

View file

@ -0,0 +1,15 @@
package com.tangem.data.walletconnect.utils
import com.reown.walletkit.client.Wallet
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest.JSONRPCRequest
import com.tangem.utils.converter.Converter
internal object JSONRPCRequestConverter : Converter<Wallet.Model.SessionRequest.JSONRPCRequest, JSONRPCRequest> {
override fun convert(value: Wallet.Model.SessionRequest.JSONRPCRequest): JSONRPCRequest {
return JSONRPCRequest(
id = value.id,
method = value.method,
params = value.params,
)
}
}

View file

@ -1,36 +0,0 @@
package com.tangem.data.walletconnect.utils
import com.reown.android.Core
import com.reown.walletkit.client.Wallet
import com.tangem.domain.walletconnect.model.sdkcopy.WcAppMetaData
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSession
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest.JSONRPCRequest
internal fun Wallet.Model.Session.toOurModel(): WcSdkSession = WcSdkSession(
topic = topic,
appMetaData = metaData.toOurModel(),
)
internal fun Wallet.Model.SessionRequest.toOurModel(): WcSdkSessionRequest = WcSdkSessionRequest(
topic = this.topic,
chainId = this.chainId,
request = this.request.toOurModel(),
)
internal fun Wallet.Model.SessionRequest.JSONRPCRequest.toOurModel(): JSONRPCRequest = JSONRPCRequest(
id = this.id,
method = this.method,
params = this.params,
)
internal fun Core.Model.AppMetaData?.toOurModel(): WcAppMetaData = WcAppMetaData(
name = this?.name.orEmpty(),
description = this?.description.orEmpty(),
url = this?.url.orEmpty(),
icons = this?.icons.orEmpty(),
redirect = this?.redirect,
appLink = this?.appLink,
linkMode = this?.linkMode ?: false,
verifyUrl = this?.verifyUrl,
)

View file

@ -0,0 +1,33 @@
package com.tangem.data.walletconnect.utils
import com.reown.android.Core
import com.tangem.domain.walletconnect.model.sdkcopy.WcAppMetaData
import com.tangem.utils.converter.Converter
internal object WcAppMetaDataConverter : Converter<Core.Model.AppMetaData, WcAppMetaData> {
val empty
get() = WcAppMetaData(
name = "",
description = "",
url = "",
icons = listOf(),
redirect = null,
appLink = null,
linkMode = false,
verifyUrl = null,
)
override fun convert(value: Core.Model.AppMetaData): WcAppMetaData {
return WcAppMetaData(
name = value.name,
description = value.description,
url = value.url,
icons = value.icons,
redirect = value.redirect,
appLink = value.appLink,
linkMode = value.linkMode,
verifyUrl = value.verifyUrl,
)
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.data.walletconnect.utils
import com.reown.walletkit.client.Wallet
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSession
import com.tangem.utils.converter.Converter
internal object WcSdkSessionConverter : Converter<Wallet.Model.Session, WcSdkSession> {
override fun convert(value: Wallet.Model.Session): WcSdkSession {
return WcSdkSession(
topic = value.topic,
appMetaData = value.metaData?.let { WcAppMetaDataConverter.convert(it) } ?: WcAppMetaDataConverter.empty,
)
}
}

View file

@ -0,0 +1,16 @@
package com.tangem.data.walletconnect.utils
import com.reown.walletkit.client.Wallet
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
import com.tangem.utils.converter.Converter
internal object WcSdkSessionRequestConverter : Converter<Wallet.Model.SessionRequest, WcSdkSessionRequest> {
override fun convert(value: Wallet.Model.SessionRequest): WcSdkSessionRequest {
return WcSdkSessionRequest(
topic = value.topic,
chainId = value.chainId,
request = JSONRPCRequestConverter.convert(value.request),
)
}
}

View file

@ -1,15 +1,14 @@
package com.tangem.domain.walletconnect.usecase.pair
import com.tangem.domain.walletconnect.model.WcSessionApprove
import com.tangem.domain.wallets.models.UserWallet
import kotlinx.coroutines.flow.Flow
interface WcPairUseCase {
fun pairFlow(uri: String, source: Source, selectedWallet: UserWallet): Flow<WcPairState>
fun pairFlow(uri: String, source: Source): Flow<WcPairState>
fun approve(sessionForApprove: WcSessionApprove)
fun reject()
enum class Source { QR, DEEPLINK, ETC }
enum class Source { QR, DEEPLINK, CLIPBOARD, ETC }
}