Updated on 2026-08-14
This commit is contained in:
parent
99a5efd7e2
commit
00171d2276
11 changed files with 102 additions and 7 deletions
|
|
@ -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<HandleMethodError, WcAddNetworkUseCase.AddNetwork> {
|
||||
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<WcRequestError, String> {
|
||||
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<Throwable, Unit> {
|
||||
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<HandleMethodError, Network> {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,12 @@ internal class WcEthSwitchNetworkUseCase @AssistedInject constructor(
|
|||
override suspend fun invoke(): Either<HandleMethodError, WcSwitchNetworkUseCase.SwitchNetwork> {
|
||||
return addSwitchCommonDelegate
|
||||
.commonChecks(method.rawChain.chainId)
|
||||
.map { addedNetwork -> WcSwitchNetworkUseCase.SwitchNetwork(addedNetwork) }
|
||||
.map { addedNetwork ->
|
||||
WcSwitchNetworkUseCase.SwitchNetwork(
|
||||
network = addedNetwork,
|
||||
isExistInWcSession = addSwitchCommonDelegate.existInWcSession(addedNetwork),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun reject() {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ internal class WcNetworksConverter @Inject constructor(
|
|||
return networks.firstOrNull { !isCustomCoin(it) } ?: networks.firstOrNull()
|
||||
}
|
||||
|
||||
suspend fun allAddressForChain(rawChainId: String, wallet: UserWallet): List<String> {
|
||||
return filterWalletNetworkForRequest(rawChainId, wallet)
|
||||
.mapNotNull { walletManagersFacade.getDefaultAddress(wallet.walletId, it)?.lowercase() }
|
||||
}
|
||||
|
||||
/**
|
||||
* return all exist derivation networks
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -10,6 +10,14 @@ internal object WcSdkSessionConverter : Converter<Wallet.Model.Session, WcSdkSes
|
|||
return WcSdkSession(
|
||||
topic = value.topic,
|
||||
appMetaData = value.metaData?.let { WcAppMetaDataConverter.convert(it) } ?: WcAppMetaDataConverter.empty,
|
||||
namespaces = value.namespaces.mapValues { (_, session) ->
|
||||
WcSdkSession.Session(
|
||||
chains = session.chains ?: listOf(),
|
||||
accounts = session.accounts,
|
||||
methods = session.methods,
|
||||
events = session.events,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -62,6 +62,7 @@ internal class WcSignUseCaseDelegateTest {
|
|||
connectingTime = 0L,
|
||||
sdkModel = WcSdkSession(
|
||||
topic = "",
|
||||
namespaces = mapOf(),
|
||||
appMetaData = WcAppMetaData(
|
||||
name = "",
|
||||
description = "",
|
||||
|
|
|
|||
|
|
@ -6,4 +6,12 @@ package com.tangem.domain.walletconnect.model.sdkcopy
|
|||
data class WcSdkSession(
|
||||
val topic: String,
|
||||
val appMetaData: WcAppMetaData,
|
||||
)
|
||||
val namespaces: Map<String, Session>,
|
||||
) {
|
||||
data class Session(
|
||||
val chains: List<String>,
|
||||
val accounts: List<String>,
|
||||
val methods: List<String>,
|
||||
val events: List<String>,
|
||||
)
|
||||
}
|
||||
|
|
@ -15,5 +15,6 @@ interface WcAddNetworkUseCase :
|
|||
|
||||
data class AddNetwork(
|
||||
val network: Network,
|
||||
val isExistInWcSession: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
@ -13,5 +13,6 @@ interface WcSwitchNetworkUseCase :
|
|||
|
||||
data class SwitchNetwork(
|
||||
val network: Network,
|
||||
val isExistInWcSession: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue