Updated on 2026-08-14
This commit is contained in:
parent
c8a163fd0a
commit
65ace6c5f2
21 changed files with 349 additions and 39 deletions
|
|
@ -1,9 +1,17 @@
|
|||
package com.tangem.data.walletconnect.network.ethereum
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.blockchain.extensions.hexToInt
|
||||
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
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.data.walletconnect.utils.WcNetworksConverter
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.walletconnect.model.HandleMethodError
|
||||
import com.tangem.domain.walletconnect.model.WcEthMethod
|
||||
import com.tangem.domain.walletconnect.model.WcRequestError
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
|
|
@ -16,6 +24,7 @@ import dagger.assisted.AssistedInject
|
|||
|
||||
internal class WcEthAddNetworkUseCase @AssistedInject constructor(
|
||||
private val respondService: WcRespondService,
|
||||
addSwitchCommonDelegateFactory: WcEthAddSwitchCommonDelegate.Factory,
|
||||
@Assisted val context: WcMethodUseCaseContext,
|
||||
@Assisted override val method: WcEthMethod.AddEthereumChain,
|
||||
) : WcAddNetworkUseCase {
|
||||
|
|
@ -31,6 +40,14 @@ internal class WcEthAddNetworkUseCase @AssistedInject constructor(
|
|||
else -> WcNetworkDerivationState.Single
|
||||
}
|
||||
|
||||
private val addSwitchCommonDelegate = addSwitchCommonDelegateFactory.create(context)
|
||||
|
||||
override suspend fun invoke(): Either<HandleMethodError, WcAddNetworkUseCase.AddNetwork> {
|
||||
return addSwitchCommonDelegate
|
||||
.commonChecks(method.rawChain.chainId)
|
||||
.map { addedNetwork -> WcAddNetworkUseCase.AddNetwork(addedNetwork) }
|
||||
}
|
||||
|
||||
override suspend fun approve(): Either<WcRequestError, String> {
|
||||
return respondService.respond(rawSdkRequest, "")
|
||||
}
|
||||
|
|
@ -43,4 +60,31 @@ internal class WcEthAddNetworkUseCase @AssistedInject constructor(
|
|||
interface Factory {
|
||||
fun create(context: WcMethodUseCaseContext, method: WcEthMethod.AddEthereumChain): WcEthAddNetworkUseCase
|
||||
}
|
||||
}
|
||||
|
||||
internal class WcEthAddSwitchCommonDelegate @AssistedInject constructor(
|
||||
private val networksConverter: WcNetworksConverter,
|
||||
@Assisted val context: WcMethodUseCaseContext,
|
||||
) {
|
||||
|
||||
private val wallet: UserWallet get() = context.session.wallet
|
||||
|
||||
suspend fun commonChecks(hexChainId: String): Either<HandleMethodError, Network> {
|
||||
val caip2 = CAIP2.fromRaw("$ETH_NAMESPACE_KEY:${hexChainId.hexToInt()}")
|
||||
?: return HandleMethodError.UnknownError("Failed to parse CAIP2").left()
|
||||
val generalNetwork = networksConverter.createNetwork(caip2.raw, wallet)
|
||||
if (generalNetwork == null) {
|
||||
return HandleMethodError.TangemUnsupportedNetwork(caip2.raw).left()
|
||||
}
|
||||
val addedNetwork = networksConverter.mainOrAnyWalletNetworkForRequest(caip2.raw, wallet)
|
||||
if (addedNetwork == null) {
|
||||
return HandleMethodError.NotAddedNetwork(generalNetwork.name).left()
|
||||
}
|
||||
return addedNetwork.right()
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(context: WcMethodUseCaseContext): WcEthAddSwitchCommonDelegate
|
||||
}
|
||||
}
|
||||
|
|
@ -6,17 +6,14 @@ import arrow.core.left
|
|||
import arrow.core.right
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.extensions.hexToInt
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.walletconnect.model.CAIP2
|
||||
import com.tangem.data.walletconnect.model.NamespaceKey
|
||||
import com.tangem.data.walletconnect.network.ethereum.WcEthNetwork.NamespaceConverter.Companion.ETH_NAMESPACE_KEY
|
||||
import com.tangem.data.walletconnect.request.WcRequestToUseCaseConverter
|
||||
import com.tangem.data.walletconnect.request.WcRequestToUseCaseConverter.Companion.fromJson
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.data.walletconnect.utils.WcNamespaceConverter
|
||||
import com.tangem.data.walletconnect.utils.WcNetworksConverter
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.walletconnect.model.*
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
|
|
@ -46,7 +43,7 @@ internal class WcEthNetwork(
|
|||
?: return HandleMethodError.UnknownSession.left()
|
||||
val wallet = session.wallet
|
||||
val chainId = request.chainId.orEmpty()
|
||||
val method: WcEthMethod = name.toMethod(request, wallet)
|
||||
val method: WcEthMethod = name.toMethod(request)
|
||||
.getOrElse { return error(it.message.orEmpty()) }
|
||||
?: return error("Failed to parse $name")
|
||||
suspend fun anyExistNetwork() = networksConverter.mainOrAnyWalletNetworkForRequest(chainId, wallet)
|
||||
|
|
@ -56,7 +53,9 @@ internal class WcEthNetwork(
|
|||
is WcEthMethod.SendTransaction -> method.transaction.from
|
||||
is WcEthMethod.SignTransaction -> method.transaction.from
|
||||
is WcEthMethod.SignTypedData -> method.account
|
||||
is WcEthMethod.AddEthereumChain ->
|
||||
is WcEthMethod.AddEthereumChain,
|
||||
is WcEthMethod.SwitchEthereumChain,
|
||||
->
|
||||
anyExistNetwork()
|
||||
?.let { network -> walletManagersFacade.getDefaultAddress(wallet.walletId, network).orEmpty() }
|
||||
.orEmpty()
|
||||
|
|
@ -67,7 +66,9 @@ internal class WcEthNetwork(
|
|||
is WcEthMethod.SendTransaction,
|
||||
is WcEthMethod.SignTransaction,
|
||||
-> networksConverter.findWalletNetworkForRequest(request, session, accountAddress)
|
||||
is WcEthMethod.AddEthereumChain -> anyExistNetwork()
|
||||
is WcEthMethod.AddEthereumChain,
|
||||
is WcEthMethod.SwitchEthereumChain,
|
||||
-> anyExistNetwork()
|
||||
} ?: return error("Failed to find walletNetwork for accountAddress $accountAddress")
|
||||
|
||||
val context = WcMethodUseCaseContext(
|
||||
|
|
@ -83,13 +84,11 @@ internal class WcEthNetwork(
|
|||
is WcEthMethod.SignTransaction -> factories.signTransaction.create(context, method)
|
||||
is WcEthMethod.SignTypedData -> factories.signTypedData.create(context, method)
|
||||
is WcEthMethod.AddEthereumChain -> factories.addNetwork.create(context, method)
|
||||
is WcEthMethod.SwitchEthereumChain -> factories.switchNetwork.create(context, method)
|
||||
}.right()
|
||||
}
|
||||
|
||||
private suspend fun WcEthMethodName.toMethod(
|
||||
request: WcSdkSessionRequest,
|
||||
wallet: UserWallet,
|
||||
): Either<Throwable, WcEthMethod?> {
|
||||
private fun WcEthMethodName.toMethod(request: WcSdkSessionRequest): Either<Throwable, WcEthMethod?> {
|
||||
val rawParams = request.request.params
|
||||
return when (this) {
|
||||
WcEthMethodName.EthSign,
|
||||
|
|
@ -111,16 +110,17 @@ internal class WcEthNetwork(
|
|||
}
|
||||
}
|
||||
?: return null.right()
|
||||
WcEthMethodName.AddEthereumChain -> moshi.fromJson<List<WcEthAddChain>>(rawParams)
|
||||
WcEthMethodName.AddEthereumChain,
|
||||
WcEthMethodName.SwitchEthereumChain,
|
||||
-> moshi.fromJson<List<WcEthAddChain>>(rawParams)
|
||||
.getOrElse { return it.left() }
|
||||
?.firstOrNull()
|
||||
?.let {
|
||||
val caip2 = CAIP2.fromRaw("$ETH_NAMESPACE_KEY:${it.chainId.hexToInt()}")
|
||||
?: return null.right()
|
||||
val newNetwork = networksConverter
|
||||
.mainOrAnyWalletNetworkForRequest(caip2.raw, wallet)
|
||||
?: return null.right()
|
||||
WcEthMethod.AddEthereumChain(rawChain = it, network = newNetwork).right()
|
||||
if (this == WcEthMethodName.AddEthereumChain) {
|
||||
WcEthMethod.AddEthereumChain(rawChain = it).right()
|
||||
} else {
|
||||
WcEthMethod.SwitchEthereumChain(rawChain = it).right()
|
||||
}
|
||||
}
|
||||
?: null.right()
|
||||
}
|
||||
|
|
@ -170,5 +170,6 @@ internal class WcEthNetwork(
|
|||
val sendTransaction: WcEthSendTransactionUseCase.Factory,
|
||||
val signTransaction: WcEthSignTransactionUseCase.Factory,
|
||||
val addNetwork: WcEthAddNetworkUseCase.Factory,
|
||||
val switchNetwork: WcEthSwitchNetworkUseCase.Factory,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.data.walletconnect.network.ethereum
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.data.walletconnect.respond.WcRespondService
|
||||
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.walletconnect.model.HandleMethodError
|
||||
import com.tangem.domain.walletconnect.model.WcEthMethod
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcNetworkDerivationState
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSwitchNetworkUseCase
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class WcEthSwitchNetworkUseCase @AssistedInject constructor(
|
||||
private val respondService: WcRespondService,
|
||||
@Assisted val context: WcMethodUseCaseContext,
|
||||
@Assisted override val method: WcEthMethod.SwitchEthereumChain,
|
||||
addSwitchCommonDelegateFactory: WcEthAddSwitchCommonDelegate.Factory,
|
||||
) : WcSwitchNetworkUseCase {
|
||||
|
||||
override val session: WcSession
|
||||
get() = context.session
|
||||
override val rawSdkRequest: WcSdkSessionRequest
|
||||
get() = context.rawSdkRequest
|
||||
override val network: Network
|
||||
get() = context.network
|
||||
override val derivationState: WcNetworkDerivationState = when {
|
||||
context.networkDerivationsCount > 1 -> WcNetworkDerivationState.Multiple(walletAddress = context.accountAddress)
|
||||
else -> WcNetworkDerivationState.Single
|
||||
}
|
||||
|
||||
private val addSwitchCommonDelegate = addSwitchCommonDelegateFactory.create(context)
|
||||
|
||||
override suspend fun invoke(): Either<HandleMethodError, WcSwitchNetworkUseCase.SwitchNetwork> {
|
||||
return addSwitchCommonDelegate
|
||||
.commonChecks(method.rawChain.chainId)
|
||||
.map { addedNetwork -> WcSwitchNetworkUseCase.SwitchNetwork(addedNetwork) }
|
||||
}
|
||||
|
||||
override fun reject() {
|
||||
respondService.rejectRequestNonBlock(rawSdkRequest)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(context: WcMethodUseCaseContext, method: WcEthMethod.SwitchEthereumChain): WcEthSwitchNetworkUseCase
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ internal class DefaultWcRequestService(
|
|||
Timber.tag(WC_TAG).i("handle request name $name")
|
||||
if (name is WcMethodName.Unsupported) {
|
||||
respondService.rejectRequestNonBlock(sr)
|
||||
if (name.raw.startsWith("wallet_")) return
|
||||
}
|
||||
_wcRequest.trySend(name to sr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ internal class WcNetworksConverter @Inject constructor(
|
|||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
fun createNetwork(chainId: String, wallet: UserWallet): Network? {
|
||||
return namespaceConverters
|
||||
.firstNotNullOfOrNull { it.toNetwork(chainId, wallet) }
|
||||
}
|
||||
|
||||
suspend fun findWalletNetworkForRequest(
|
||||
request: WcSdkSessionRequest,
|
||||
session: WcSession,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue