Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-02 20:30:44 +05:00
parent 0c9e739c7f
commit 843a192a82
9 changed files with 89 additions and 34 deletions

View file

@ -100,7 +100,12 @@ internal class DefaultWcPairUseCase @AssistedInject constructor(
).map { settledSession ->
val newSession = WcSession(
wallet = sessionForApprove.wallet,
sdkModel = WcSdkSessionConverter.convert(settledSession.session),
sdkModel = WcSdkSessionConverter.convert(
value = WcSdkSessionConverter.Input(
originUrl = sdkVerifyContext.origin,
session = settledSession.session,
),
),
securityStatus = proposalState.dAppSession.securityStatus,
networks = sessionForApprove.network.toSet(),
connectingTime = DateTime.now().millis,

View file

@ -112,8 +112,9 @@ internal class WcPairSdkDelegate : WcSdkObserver {
sessionProposal: Wallet.Model.SessionProposal,
verifyContext: Wallet.Model.VerifyContext,
) {
val sessionProposalWithRealUrl = sessionProposal.copy(url = verifyContext.origin)
// Triggered when wallet receives the session proposal sent by a Dapp
onSessionProposal.trySend(sessionProposal to verifyContext)
onSessionProposal.trySend(sessionProposalWithRealUrl to verifyContext)
}
override fun onSessionSettleResponse(settleSessionResponse: Wallet.Model.SettledSessionResponse) {

View file

@ -26,7 +26,12 @@ internal class DefaultWcRequestService(
verifyContext: Wallet.Model.VerifyContext,
) {
// Triggered when a Dapp sends SessionRequest to sign a transaction or a message
val sr = WcSdkSessionRequestConverter.convert(sessionRequest)
val sr = WcSdkSessionRequestConverter.convert(
WcSdkSessionRequestConverter.Input(
originUrl = verifyContext.origin,
sessionRequest = sessionRequest,
),
)
Timber.tag(WC_TAG).i("handle request $sr")
val name = requestConverters.firstNotNullOfOrNull { it.toWcMethodName(sr) }
?: WcMethodName.Unsupported(sr.request.method)

View file

@ -70,6 +70,7 @@ internal class DefaultWcSessionsManager(
WcSessionDTO(
topic = session.sdkModel.topic,
walletId = session.wallet.walletId,
url = session.sdkModel.appMetaData.url,
securityStatus = session.securityStatus,
connectingTime = session.connectingTime ?: DateTime.now().millis,
),
@ -105,8 +106,15 @@ internal class DefaultWcSessionsManager(
.map { walletId ->
flow {
emit(
legacyStore.loadSessions(walletId.stringValue).map {
WcSessionDTO(it.topic, walletId, CheckDAppResult.FAILED_TO_VERIFY)
legacyStore.loadSessions(walletId.stringValue).mapNotNull { legacySession ->
val url =
inSdk.find { it.topic == legacySession.topic }?.metaData?.url ?: return@mapNotNull null
WcSessionDTO(
topic = legacySession.topic,
walletId = walletId,
url = url,
securityStatus = CheckDAppResult.FAILED_TO_VERIFY,
)
},
)
}
@ -130,9 +138,15 @@ internal class DefaultWcSessionsManager(
val wallet = wallets.find { it.walletId == storeSession.walletId } ?: return@mapNotNull null
val sdkSession = inSdk.find { it.topic == storeSession.topic } ?: return@mapNotNull null
val networks = wcNetworksConverter.findWalletNetworks(wallet, sdkSession)
val originUrl = storeSession.url ?: sdkSession.metaData?.url ?: ""
WcSession(
wallet = wallet,
sdkModel = WcSdkSessionConverter.convert(sdkSession),
sdkModel = WcSdkSessionConverter.convert(
value = WcSdkSessionConverter.Input(
originUrl = originUrl,
session = sdkSession,
),
),
securityStatus = storeSession.securityStatus,
networks = networks,
connectingTime = storeSession.connectingTime,

View file

@ -4,7 +4,7 @@ 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> {
internal object WcAppMetaDataConverter : Converter<WcAppMetaDataConverter.Input, WcAppMetaData> {
val empty
get() = WcAppMetaData(
@ -18,16 +18,18 @@ internal object WcAppMetaDataConverter : Converter<Core.Model.AppMetaData, WcApp
verifyUrl = null,
)
override fun convert(value: Core.Model.AppMetaData): WcAppMetaData {
override fun convert(value: Input): 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,
name = value.peerMetaData.name,
description = value.peerMetaData.description,
url = value.originUrl,
icons = value.peerMetaData.icons,
redirect = value.peerMetaData.redirect,
appLink = value.peerMetaData.appLink,
linkMode = value.peerMetaData.linkMode,
verifyUrl = value.peerMetaData.verifyUrl,
)
}
internal data class Input(val originUrl: String, val peerMetaData: Core.Model.AppMetaData)
}

View file

@ -4,13 +4,22 @@ 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> {
internal object WcSdkSessionConverter : Converter<WcSdkSessionConverter.Input, WcSdkSession> {
override fun convert(value: Wallet.Model.Session): WcSdkSession {
override fun convert(value: Input): WcSdkSession {
return WcSdkSession(
topic = value.topic,
appMetaData = value.metaData?.let { WcAppMetaDataConverter.convert(it) } ?: WcAppMetaDataConverter.empty,
namespaces = value.namespaces.mapValues { (_, session) ->
topic = value.session.topic,
appMetaData = value.session.metaData
?.let {
WcAppMetaDataConverter.convert(
value = WcAppMetaDataConverter.Input(
originUrl = value.originUrl,
peerMetaData = it,
),
)
}
?: WcAppMetaDataConverter.empty,
namespaces = value.session.namespaces.mapValues { (_, session) ->
WcSdkSession.Session(
chains = session.chains ?: listOf(),
accounts = session.accounts,
@ -20,4 +29,6 @@ internal object WcSdkSessionConverter : Converter<Wallet.Model.Session, WcSdkSes
},
)
}
internal data class Input(val originUrl: String, val session: Wallet.Model.Session)
}

View file

@ -4,15 +4,25 @@ 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> {
internal object WcSdkSessionRequestConverter : Converter<WcSdkSessionRequestConverter.Input, WcSdkSessionRequest> {
override fun convert(value: Wallet.Model.SessionRequest): WcSdkSessionRequest {
override fun convert(value: Input): WcSdkSessionRequest {
return WcSdkSessionRequest(
topic = value.topic,
chainId = value.chainId,
dAppMetaData = value.peerMetaData?.let { WcAppMetaDataConverter.convert(it) }
topic = value.sessionRequest.topic,
chainId = value.sessionRequest.chainId,
dAppMetaData = value.sessionRequest.peerMetaData
?.let {
WcAppMetaDataConverter.convert(
value = WcAppMetaDataConverter.Input(
originUrl = value.originUrl,
peerMetaData = it,
),
)
}
?: WcAppMetaDataConverter.empty,
request = JSONRPCRequestConverter.convert(value.request),
request = JSONRPCRequestConverter.convert(value.sessionRequest.request),
)
}
internal data class Input(val originUrl: String, val sessionRequest: Wallet.Model.SessionRequest)
}

View file

@ -60,7 +60,7 @@ internal class DefaultWcPairUseCaseTest {
private val sdkVerifyContext: Wallet.Model.VerifyContext
get() = Wallet.Model.VerifyContext(
id = 9259,
origin = "vituperata",
origin = "https://react-app.walletconnect.com/",
validation = Wallet.Model.Validation.VALID,
verifyUrl = "https://search.yahoo.com/search?p=id",
isScam = false,
@ -68,6 +68,7 @@ internal class DefaultWcPairUseCaseTest {
private val unsupportedDAppUrl = "dydx.trade"
private val unsupportedSdkProposal get() = sdkProposal.copy(url = unsupportedDAppUrl)
private val unsupportedSdkVerifyContext get() = sdkVerifyContext.copy(origin = unsupportedDAppUrl)
private val sessionForApprove: WcSessionApprove
get() = WcSessionApprove(
@ -100,7 +101,12 @@ internal class DefaultWcPairUseCaseTest {
private val Wallet.Model.Session.sessionForSave: WcSession
get() = WcSession(
wallet = sessionForApprove.wallet,
sdkModel = WcSdkSessionConverter.convert(this),
sdkModel = WcSdkSessionConverter.convert(
value = WcSdkSessionConverter.Input(
originUrl = sdkVerifyContext.origin,
session = this,
),
),
securityStatus = CheckDAppResult.SAFE,
networks = setOf(),
connectingTime = null,
@ -138,7 +144,7 @@ internal class DefaultWcPairUseCaseTest {
assertEquals(loading, awaitItem())
coVerifyOrder {
sdkDelegate.pair(url)
blockAidVerifier.verifyDApp(DAppData(sdkProposal.url))
blockAidVerifier.verifyDApp(DAppData(sdkVerifyContext.origin))
}
assert(awaitItem() is WcPairState.Proposal)
expectNoEvents()
@ -161,7 +167,7 @@ internal class DefaultWcPairUseCaseTest {
assertEquals(loading, awaitItem())
coVerifyOrder {
sdkDelegate.pair(url)
blockAidVerifier.verifyDApp(DAppData(sdkProposal.url))
blockAidVerifier.verifyDApp(DAppData(sdkVerifyContext.origin))
}
assert(awaitItem() is WcPairState.Proposal)
useCase.approve(sessionForApprove)
@ -194,7 +200,7 @@ internal class DefaultWcPairUseCaseTest {
assertEquals(loading, awaitItem())
coVerifyOrder {
sdkDelegate.pair(url)
blockAidVerifier.verifyDApp(DAppData(sdkProposal.url))
blockAidVerifier.verifyDApp(DAppData(sdkVerifyContext.origin))
}
assert(awaitItem() is WcPairState.Proposal)
useCase.reject()
@ -207,7 +213,7 @@ internal class DefaultWcPairUseCaseTest {
@Test
fun `success pair and reject unsupported dApp`() = runTest {
coEvery { sdkDelegate.pair(url) } returns (unsupportedSdkProposal to sdkVerifyContext).right()
coEvery { sdkDelegate.pair(url) } returns (unsupportedSdkProposal to unsupportedSdkVerifyContext).right()
val unsupportedDAppError = WcPairState.Error(WcPairError.UnsupportedDApp(unsupportedSdkProposal.name))
val useCase = useCaseFactory()
@ -255,7 +261,7 @@ internal class DefaultWcPairUseCaseTest {
coVerifyOrder {
sdkDelegate.pair(url)
associateNetworksDelegate.associate(sdkProposal)
blockAidVerifier.verifyDApp(DAppData(sdkProposal.url))
blockAidVerifier.verifyDApp(DAppData(sdkVerifyContext.origin))
}
assert(awaitItem() is WcPairState.Proposal)
useCase.approve(sessionForApprove)

View file

@ -8,6 +8,7 @@ import com.tangem.domain.models.wallet.UserWalletId
data class WcSessionDTO(
val topic: String,
val walletId: UserWalletId,
val url: String?,
val securityStatus: CheckDAppResult = CheckDAppResult.FAILED_TO_VERIFY,
val connectingTime: Long? = null,
)