From 4f499f41c7fd3f8d1d9ec87fd2e3fa2a750898dc Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Jul 2025 13:43:28 +0700 Subject: [PATCH] Updated on 2026-08-14 --- .../network/ethereum/WcEthNetwork.kt | 12 ---- .../ethereum/WcEthSendTransactionUseCase.kt | 15 +++-- .../ethereum/WcEthSignTransactionUseCase.kt | 15 +++-- .../network/solana/WcSolanaNetwork.kt | 25 ++------ .../pair/AssociateNetworksDelegate.kt | 8 ++- .../pair/CaipNamespaceDelegate.kt | 29 ++++++--- .../pair/DefaultWcPairUseCase.kt | 8 ++- .../walletconnect/pair/WcPairSdkDelegate.kt | 2 +- .../sessions/DefaultWcSessionsManager.kt | 18 ++++-- .../utils/WcNamespaceConverter.kt | 1 - .../usecase/method/WcTransactionUseCase.kt | 2 +- .../WcCommonTransactionUMConverter.kt | 62 ------------------- .../converter/WcSendTransactionUMConverter.kt | 30 ++++----- .../converter/WcSignTransactionUMConverter.kt | 13 ++-- .../converter/WcSignTypedDataUMConverter.kt | 13 ++-- .../model/WcSendTransactionModel.kt | 33 ++++++---- .../model/WcSignTransactionModel.kt | 52 +++++++++++----- 17 files changed, 159 insertions(+), 179 deletions(-) delete mode 100644 features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt index 7b7823fd7f..0f9e21543f 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt @@ -7,7 +7,6 @@ import arrow.core.right import com.squareup.moshi.Moshi import com.tangem.blockchain.common.Blockchain import com.tangem.blockchainsdk.utils.ExcludedBlockchains -import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.data.walletconnect.model.CAIP2 import com.tangem.data.walletconnect.model.NamespaceKey import com.tangem.data.walletconnect.request.WcRequestToUseCaseConverter @@ -15,7 +14,6 @@ import com.tangem.data.walletconnect.request.WcRequestToUseCaseConverter.Compani 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.network.Network import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.walletconnect.model.* import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest @@ -156,16 +154,6 @@ internal class WcEthNetwork( val ethChainId = chainId.reference.toIntOrNull() ?: return null return Blockchain.fromChainId(ethChainId) } - - override fun toCAIP2(network: Network): CAIP2? { - val blockchain = network.toBlockchain() - if (!blockchain.isEvm()) return null - val chainId = blockchain.getChainId() ?: return null - return CAIP2( - namespace = namespaceKey.key, - reference = chainId.toString(), - ) - } } internal class Factories @Inject constructor( diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSendTransactionUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSendTransactionUseCase.kt index 0621f51855..5358c3a317 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSendTransactionUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSendTransactionUseCase.kt @@ -41,6 +41,9 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor( WcMutableFee { private var approvalAmount: WcApprovedAmount? = null + // in case of change TransactionExtras + // change approvalAmount for example + private var isIgnoreDAppFee: Boolean = false private var dAppFee: Fee? = null override val securityStatus: LceFlow = @@ -102,7 +105,7 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor( }, ) approvalAmount = action.amount - dAppFee = null + isIgnoreDAppFee = true uncompiled.copy(extras = extras.copy(callData = callData)) } is WcEthTxAction.UpdateFee -> uncompiled.copy(fee = action.fee) @@ -111,8 +114,11 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor( emit(newState) } - override fun dAppFee(): Fee? { - return dAppFee + override suspend fun dAppFee(): Fee? { + if (isIgnoreDAppFee) return null + if (dAppFee != null) return dAppFee + return ethTxHelper.getDAppFee(method.transaction, wallet, network) + .also { dAppFee = it } } override fun updateFee(fee: Fee) { @@ -120,9 +126,8 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor( } override fun invoke(): Flow> = flow { - dAppFee = ethTxHelper.getDAppFee(method.transaction, wallet, network) val transactionData = ethTxHelper.createTransactionData( - dAppFee = dAppFee, + dAppFee = dAppFee(), network = context.network, txParams = method.transaction, ) ?: return@flow diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSignTransactionUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSignTransactionUseCase.kt index eda9598750..b6795bf29b 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSignTransactionUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthSignTransactionUseCase.kt @@ -41,6 +41,9 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor( WcMutableFee { private var approvalAmount: WcApprovedAmount? = null + // in case of change TransactionExtras + // change approvalAmount for example + private var isIgnoreDAppFee: Boolean = false private var dAppFee: Fee? = null override val securityStatus = blockAidDelegate.getSecurityStatus( @@ -101,7 +104,7 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor( }, ) approvalAmount = action.amount - dAppFee = null + isIgnoreDAppFee = true uncompiled.copy(extras = extras.copy(callData = callData)) } is WcEthTxAction.UpdateFee -> uncompiled.copy(fee = action.fee) @@ -115,17 +118,19 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor( } override fun invoke(): Flow> = flow { - dAppFee = ethTxHelper.getDAppFee(method.transaction, wallet, network) val transactionData = ethTxHelper.createTransactionData( - dAppFee = dAppFee, + dAppFee = dAppFee(), network = context.network, txParams = method.transaction, ) ?: return@flow emitAll(delegate.invoke(transactionData)) } - override fun dAppFee(): Fee? { - return dAppFee + override suspend fun dAppFee(): Fee? { + if (isIgnoreDAppFee) return null + if (dAppFee != null) return dAppFee + return ethTxHelper.getDAppFee(method.transaction, wallet, network) + .also { dAppFee = it } } override fun getAmount(): WcApprovedAmount? { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt index 8fa3aa5469..0b47155291 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/solana/WcSolanaNetwork.kt @@ -8,7 +8,6 @@ import com.squareup.moshi.Moshi import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.extensions.decodeBase58 import com.tangem.blockchainsdk.utils.ExcludedBlockchains -import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.common.extensions.toHexString import com.tangem.data.walletconnect.model.CAIP2 import com.tangem.data.walletconnect.model.NamespaceKey @@ -17,7 +16,6 @@ import com.tangem.data.walletconnect.request.WcRequestToUseCaseConverter.Compani 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.network.Network import com.tangem.domain.walletconnect.model.HandleMethodError import com.tangem.domain.walletconnect.model.WcSolanaMethod import com.tangem.domain.walletconnect.model.WcSolanaMethodName @@ -88,27 +86,14 @@ internal class WcSolanaNetwork( override val namespaceKey: NamespaceKey = NamespaceKey("solana") override fun toBlockchain(chainId: CAIP2): Blockchain? { + val isMainNet = MAINNET_CHAIN_ID.any { it.lowercase() == chainId.reference.lowercase() } if (chainId.namespace != namespaceKey.key) return null - return when (chainId.reference) { - MAINNET_CHAIN_ID -> Blockchain.Solana - TESTNET_CHAIN_ID -> Blockchain.SolanaTestnet + return when { + isMainNet -> Blockchain.Solana + chainId.reference.lowercase() == TESTNET_CHAIN_ID -> Blockchain.SolanaTestnet else -> null } } - - override fun toCAIP2(network: Network): CAIP2? { - val blockchain = network.toBlockchain() - val chainId = when (blockchain) { - Blockchain.Solana -> MAINNET_CHAIN_ID - Blockchain.SolanaTestnet -> TESTNET_CHAIN_ID - else -> null - } - chainId ?: return null - return CAIP2( - namespace = namespaceKey.key, - reference = chainId, - ) - } } private fun WcSolanaMethodName.toMethod(request: WcSdkSessionRequest): Either { @@ -140,7 +125,7 @@ internal class WcSolanaNetwork( ) companion object { - private const val MAINNET_CHAIN_ID = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" + private val MAINNET_CHAIN_ID = listOf("5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ") private const val TESTNET_CHAIN_ID = "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z" } } \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/AssociateNetworksDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/AssociateNetworksDelegate.kt index 7ecdf54de9..d0f06c74b2 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/AssociateNetworksDelegate.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/AssociateNetworksDelegate.kt @@ -110,8 +110,10 @@ internal class AssociateNetworksDelegate( .distinctBy { it.rawId } } - private fun Map.setOfChainId(): Set = - this.values.flatMap { proposal -> proposal.chains ?: listOf() }.toSet() - private fun missingNetworkName(chainId: String): String = chainId.replaceFirstChar(Char::titlecase) + + companion object { + internal fun Map.setOfChainId(): Set = + this.values.flatMap { proposal -> proposal.chains ?: listOf() }.toSet() + } } \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/CaipNamespaceDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/CaipNamespaceDelegate.kt index 82c921611a..4b5d2c336a 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/CaipNamespaceDelegate.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/CaipNamespaceDelegate.kt @@ -2,6 +2,8 @@ package com.tangem.data.walletconnect.pair import com.reown.walletkit.client.Wallet import com.tangem.data.walletconnect.model.CAIP10 +import com.tangem.data.walletconnect.model.CAIP2 +import com.tangem.data.walletconnect.pair.AssociateNetworksDelegate.Companion.setOfChainId import com.tangem.data.walletconnect.utils.WcNamespaceConverter import com.tangem.data.walletconnect.utils.WcNetworksConverter import com.tangem.domain.models.network.Network @@ -22,6 +24,26 @@ internal class CaipNamespaceDelegate( val userWallet = sessionForApprove.wallet val result = mutableMapOf() + val requiredNamespaces = sessionProposal.requiredNamespaces.setOfChainId() + val optionalNamespaces = sessionProposal.optionalNamespaces.setOfChainId() + val allWcNetworks = (requiredNamespaces + optionalNamespaces) + .mapNotNull { chainId -> + val network = namespaceConverters + .firstNotNullOfOrNull { it.toNetwork(chainId, userWallet) } + ?: return@mapNotNull null + val caip2 = CAIP2.fromRaw(chainId) ?: return@mapNotNull null + network to caip2 + } + + suspend fun createCAIP10(userWalletId: UserWalletId, network: Network): CAIP10? { + val address = walletManagersFacade.getDefaultAddress(userWalletId, network) + val chainId = allWcNetworks + .find { (wcNetwork, _) -> network.rawId == wcNetwork.rawId } + ?.second + if (chainId == null || address == null) return null + return CAIP10(chainId = chainId, accountAddress = address) + } + wcNetworksConverter.convertNetworksForApprove(sessionForApprove) .mapNotNull { createCAIP10(userWallet.walletId, it) } .forEach { account -> @@ -52,13 +74,6 @@ internal class CaipNamespaceDelegate( } } - private suspend fun createCAIP10(userWalletId: UserWalletId, network: Network): CAIP10? { - val address = walletManagersFacade.getDefaultAddress(userWalletId, network) - val chainId = namespaceConverters.firstNotNullOfOrNull { it.toCAIP2(network) } - if (chainId == null || address == null) return null - return CAIP10(chainId = chainId, accountAddress = address) - } - private data class Session( val chains: MutableSet = mutableSetOf(), val accounts: MutableSet = mutableSetOf(), diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt index 91951d8f48..b12a31a1c0 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/DefaultWcPairUseCase.kt @@ -115,6 +115,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( }.onCompletion { if (it != null) { Timber.tag(WC_TAG).e(it, "Completed with error $pairRequest") + emit(WcPairState.Error(WcPairError.Unknown(it.message.orEmpty()))) } else { Timber.tag(WC_TAG).i("Completed successfully $pairRequest") } @@ -134,7 +135,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( private suspend fun walletKitApproveSession( sessionForApprove: WcSessionApprove, sdkSessionProposal: Wallet.Model.SessionProposal, - ): Either { + ): Either = try { val namespaces = caipNamespaceDelegate.associate( sdkSessionProposal, sessionForApprove, @@ -143,7 +144,10 @@ internal class DefaultWcPairUseCase @AssistedInject constructor( proposerPublicKey = sdkSessionProposal.proposerPublicKey, namespaces = namespaces, ) - return sdkDelegate.approve(sessionApprove) + sdkDelegate.approve(sessionApprove) + } catch (e: Throwable) { + Timber.tag(WC_TAG).e(e, "Failed to sdk approve session $pairRequest") + WcPairError.ApprovalFailed(e.message.orEmpty()).left() } private suspend fun buildProposalState( diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt index e115bb7807..e9665c0673 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/pair/WcPairSdkDelegate.kt @@ -150,7 +150,7 @@ internal class WcPairSdkDelegate : WcSdkObserver { private fun Throwable.toApproveError() = WcPairError.ApprovalFailed(this.localizedMessage.orEmpty()).left() companion object { - private const val CALLBACK_TIMEOUT = 30 + private const val CALLBACK_TIMEOUT = 60 // com.reown.android.pairing.engine.domain.PairingEngine.pair private val pairingExpiredMessages = listOf( "Pairing URI expired", diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt index 614d12dc9c..38ed978e2d 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sessions/DefaultWcSessionsManager.kt @@ -52,7 +52,7 @@ internal class DefaultWcSessionsManager( if (someMigrated) return@transform // ignore emit, wait next one } val associatedSessions: List = associate(inSdk, inStore, wallets) - val someRemove = removeUnknownSessions(inStore, associatedSessions) + val someRemove = removeUnknownSessions(inStore, inSdk, associatedSessions) if (someRemove) return@transform // ignore emit, wait next one emit(associatedSessions.groupBy { it.wallet }) } @@ -79,7 +79,7 @@ internal class DefaultWcSessionsManager( override suspend fun removeSession(session: WcSession): Either { val topic = session.sdkModel.topic val sdkCall = sdkDisconnectSession(topic) - .onRight { onSessionDelete.trySend(Wallet.Model.SessionDelete.Success(topic = topic, reason = "")) } + onSessionDelete.trySend(Wallet.Model.SessionDelete.Success(topic = topic, reason = "")) analytics.send(WcAnalyticEvents.SessionDisconnected(session.sdkModel.appMetaData)) return sdkCall } @@ -142,10 +142,17 @@ internal class DefaultWcSessionsManager( return wcSessions } - private suspend fun removeUnknownSessions(storeSessions: Set, wcSessions: List): Boolean { + private suspend fun removeUnknownSessions( + storeSessions: Set, + inSdkSessions: List, + wcSessions: List, + ): Boolean { val unknownStoredSessions = storeSessions .filterNot { dto -> wcSessions.any { it.sdkModel.topic == dto.topic } } val haveSomeUnknown = unknownStoredSessions.isNotEmpty() + val unknownSdkSessions = inSdkSessions + .filterNot { sdkSession -> wcSessions.any { it.sdkModel.topic == sdkSession.topic } } + val haveSomeUnknownSdkSessions = unknownSdkSessions.isNotEmpty() if (haveSomeUnknown) { Timber.tag(WC_TAG).i("removeUnknownSessions $unknownStoredSessions") @@ -164,7 +171,10 @@ internal class DefaultWcSessionsManager( store.removeSessions(emptyNetworksDto) } if (haveEmptySessions) { - emptyNetworkSessions.map { scope.launch { sdkDisconnectSession(it.sdkModel.topic) } } + emptyNetworkSessions.forEach { scope.launch { sdkDisconnectSession(it.sdkModel.topic) } } + } + if (haveSomeUnknownSdkSessions) { + unknownSdkSessions.forEach { scope.launch { sdkDisconnectSession(it.topic) } } } return haveSomeUnknown || haveEmptyDto } diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt index 5d12294eed..a65c47d3df 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/WcNamespaceConverter.kt @@ -16,7 +16,6 @@ internal interface WcNamespaceConverter { fun toBlockchain(chainId: CAIP2): Blockchain? fun toBlockchain(chainId: String): Blockchain? = toCAIP2(chainId)?.let { caip2 -> toBlockchain(caip2) } - fun toCAIP2(network: Network): CAIP2? fun toCAIP2(chainId: String): CAIP2? = CAIP2.fromRaw(chainId) fun toNetwork(chainId: String, wallet: UserWallet): Network? { diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcTransactionUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcTransactionUseCase.kt index acc4686c4d..af7e9c585f 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcTransactionUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcTransactionUseCase.kt @@ -34,7 +34,7 @@ interface WcListTransactionUseCase : * [updateFee] triggered a new [TransactionData] emit */ interface WcMutableFee { - fun dAppFee(): Fee? + suspend fun dAppFee(): Fee? fun updateFee(fee: Fee) } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt deleted file mode 100644 index 84d4f29ebc..0000000000 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.tangem.features.walletconnect.transaction.converter - -import com.tangem.domain.walletconnect.model.WcEthMethod -import com.tangem.domain.walletconnect.model.WcSolanaMethod -import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase -import com.tangem.domain.walletconnect.usecase.method.WcSignState -import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase -import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase -import com.tangem.features.send.v2.api.entity.FeeSelectorUM -import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM -import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM -import com.tangem.utils.converter.Converter -import javax.inject.Inject - -internal class WcCommonTransactionUMConverter @Inject constructor( - private val signTypedDataUMConverter: WcSignTypedDataUMConverter, - private val signTransactionUMConverter: WcSignTransactionUMConverter, - private val sendTransactionUMConverter: WcSendTransactionUMConverter, -) : Converter { - - override fun convert(value: Input): WcCommonTransactionUM? { - return when (value.useCase) { - is WcMessageSignUseCase -> { - when (value.useCase.method) { - is WcEthMethod.SignTypedData -> signTypedDataUMConverter.convert( - WcSignTypedDataUMConverter.Input( - useCase = value.useCase, - signState = value.signState, - signModel = value.signState.signModel as WcMessageSignUseCase.SignModel, - actions = value.actions, - ), - ) - is WcEthMethod.MessageSign, is WcSolanaMethod.SignMessage -> signTransactionUMConverter.convert( - WcSignTransactionUMConverter.Input( - useCase = value.useCase, - signState = value.signState, - signModel = value.signState.signModel as WcMessageSignUseCase.SignModel, - actions = value.actions, - ), - ) - else -> null - } - } - is WcTransactionUseCase -> sendTransactionUMConverter.convert( - WcSendTransactionUMConverter.Input( - useCase = value.useCase, - signState = value.signState, - actions = value.actions, - feeSelectorUM = value.feeSelectorUM, - ), - ) - else -> null - } - } - - data class Input( - val useCase: WcSignUseCase<*>, - val signState: WcSignState<*>, - val actions: WcTransactionActionsUM, - val feeSelectorUM: FeeSelectorUM? = null, - ) -} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt index 9a2275f2d4..a41cf14c7d 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt @@ -2,7 +2,9 @@ package com.tangem.features.walletconnect.transaction.converter import com.tangem.domain.walletconnect.model.WcEthMethod import com.tangem.domain.walletconnect.model.WcSolanaMethod -import com.tangem.domain.walletconnect.usecase.method.* +import com.tangem.domain.walletconnect.usecase.method.WcMethodContext +import com.tangem.domain.walletconnect.usecase.method.WcSignState +import com.tangem.domain.walletconnect.usecase.method.WcSignStep import com.tangem.features.send.v2.api.entity.FeeSelectorUM import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM @@ -20,7 +22,7 @@ internal class WcSendTransactionUMConverter @Inject constructor( private val requestBlockUMConverter: WcTransactionRequestBlockUMConverter, ) : Converter { - override fun convert(value: Input): WcSendTransactionUM? = when (value.useCase.method) { + override fun convert(value: Input): WcSendTransactionUM? = when (value.context.method) { is WcEthMethod.SendTransaction, is WcEthMethod.SignTransaction, is WcSolanaMethod.SignAllTransaction, @@ -31,23 +33,23 @@ internal class WcSendTransactionUMConverter @Inject constructor( onSend = value.actions.onSign, appInfo = appInfoContentUMConverter.convert( WcTransactionAppInfoContentUMConverter.Input( - session = value.useCase.session, + session = value.context.session, onShowVerifiedAlert = value.actions.onShowVerifiedAlert, ), ), - feeState = constructFeeState(useCase = value.useCase, actions = value.actions), - walletName = value.useCase.session.wallet.name.takeIf { value.useCase.session.showWalletInfo }, - networkInfo = networkInfoUMConverter.convert(value.useCase.network), + feeState = value.feeState, + walletName = value.context.session.wallet.name.takeIf { value.context.session.showWalletInfo }, + networkInfo = networkInfoUMConverter.convert(value.context.network), estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM(), isLoading = value.signState.domainStep == WcSignStep.Signing, - address = WcAddressConverter.convert(value.useCase.derivationState), + address = WcAddressConverter.convert(value.context.derivationState), ), feeSelectorUM = value.feeSelectorUM ?: FeeSelectorUM.Loading, transactionRequestInfo = WcTransactionRequestInfoUM( blocks = buildList { addAll( requestBlockUMConverter.convert( - WcTransactionRequestBlockUMConverter.Input(value.useCase.rawSdkRequest), + WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest), ), ) }.toImmutableList(), @@ -57,17 +59,9 @@ internal class WcSendTransactionUMConverter @Inject constructor( else -> null } - private fun constructFeeState( - useCase: WcTransactionUseCase, - actions: WcTransactionActionsUM, - ): WcTransactionFeeState { - val mutableFee = useCase as? WcMutableFee ?: return WcTransactionFeeState.None - val dAppFee = mutableFee.dAppFee() - return WcTransactionFeeState.Success(dAppFee = dAppFee, onClick = actions.onShowFeeBottomSheet) - } - data class Input( - val useCase: WcTransactionUseCase, + val context: WcMethodContext, + val feeState: WcTransactionFeeState, val signState: WcSignState<*>, val actions: WcTransactionActionsUM, val feeSelectorUM: FeeSelectorUM?, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTransactionUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTransactionUMConverter.kt index a1e30fdfad..28368845c9 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTransactionUMConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTransactionUMConverter.kt @@ -1,6 +1,7 @@ package com.tangem.features.walletconnect.transaction.converter import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase +import com.tangem.domain.walletconnect.usecase.method.WcMethodContext import com.tangem.domain.walletconnect.usecase.method.WcSignState import com.tangem.domain.walletconnect.usecase.method.WcSignStep import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM @@ -23,25 +24,25 @@ internal class WcSignTransactionUMConverter @Inject constructor( onSign = value.actions.onSign, appInfo = appInfoContentUMConverter.convert( WcTransactionAppInfoContentUMConverter.Input( - session = value.useCase.session, + session = value.context.session, onShowVerifiedAlert = value.actions.onShowVerifiedAlert, ), ), - walletName = value.useCase.session.wallet.name.takeIf { value.useCase.session.showWalletInfo }, - networkInfo = networkInfoUMConverter.convert(value.useCase.network), + walletName = value.context.session.wallet.name.takeIf { value.context.session.showWalletInfo }, + networkInfo = networkInfoUMConverter.convert(value.context.network), isLoading = value.signState.domainStep == WcSignStep.Signing, - address = WcAddressConverter.convert(value.useCase.derivationState), + address = WcAddressConverter.convert(value.context.derivationState), ), transactionRequestInfo = WcTransactionRequestInfoUM( requestBlockUMConverter.convert( - WcTransactionRequestBlockUMConverter.Input(value.useCase.rawSdkRequest, value.signModel), + WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest, value.signModel), ).toImmutableList(), onCopy = value.actions.onCopy, ), ) data class Input( - val useCase: WcMessageSignUseCase, + val context: WcMethodContext, val signState: WcSignState<*>, val signModel: WcMessageSignUseCase.SignModel, val actions: WcTransactionActionsUM, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt index df8661fc77..faef1ed164 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt @@ -1,6 +1,7 @@ package com.tangem.features.walletconnect.transaction.converter import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase +import com.tangem.domain.walletconnect.usecase.method.WcMethodContext import com.tangem.domain.walletconnect.usecase.method.WcSignState import com.tangem.domain.walletconnect.usecase.method.WcSignStep import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM @@ -23,20 +24,20 @@ internal class WcSignTypedDataUMConverter @Inject constructor( onSign = value.actions.onSign, appInfo = appInfoContentUMConverter.convert( WcTransactionAppInfoContentUMConverter.Input( - session = value.useCase.session, + session = value.context.session, onShowVerifiedAlert = value.actions.onShowVerifiedAlert, ), ), - walletName = value.useCase.session.wallet.name.takeIf { value.useCase.session.showWalletInfo }, - networkInfo = networkInfoUMConverter.convert(value.useCase.network), - address = WcAddressConverter.convert(value.useCase.derivationState), + walletName = value.context.session.wallet.name.takeIf { value.context.session.showWalletInfo }, + networkInfo = networkInfoUMConverter.convert(value.context.network), + address = WcAddressConverter.convert(value.context.derivationState), isLoading = value.signState.domainStep == WcSignStep.Signing, ), transactionRequestInfo = WcTransactionRequestInfoUM( blocks = buildList { addAll( requestBlockUMConverter.convert( - WcTransactionRequestBlockUMConverter.Input(value.useCase.rawSdkRequest, value.signModel), + WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest, value.signModel), ), ) }.toImmutableList(), @@ -45,7 +46,7 @@ internal class WcSignTypedDataUMConverter @Inject constructor( ) data class Input( - val useCase: WcMessageSignUseCase, + val context: WcMethodContext, val signState: WcSignState<*>, val signModel: WcMessageSignUseCase.SignModel, val actions: WcTransactionActionsUM, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt index 463c89fc5a..396be3dd59 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt @@ -36,11 +36,12 @@ import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorRelo import com.tangem.features.send.v2.api.subcomponents.feeSelector.entity.FeeSelectorData import com.tangem.features.walletconnect.connections.routing.WcInnerRoute import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams -import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter import com.tangem.features.walletconnect.transaction.converter.WcHandleMethodErrorConverter +import com.tangem.features.walletconnect.transaction.converter.WcSendTransactionUMConverter import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM +import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionFeeState import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes import com.tangem.features.walletconnect.transaction.ui.blockaid.WcSendAndReceiveBlockAidUiConverter @@ -62,7 +63,7 @@ internal class WcSendTransactionModel @Inject constructor( private val router: Router, private val clipboardManager: ClipboardManager, private val useCaseFactory: WcRequestUseCaseFactory, - private val converter: WcCommonTransactionUMConverter, + private val converter: WcSendTransactionUMConverter, private val blockAidUiConverter: WcSendAndReceiveBlockAidUiConverter, private val getFeeUseCase: GetFeeUseCase, private val getNetworkCoinUseCase: GetNetworkCoinStatusUseCase, @@ -198,20 +199,28 @@ internal class WcSendTransactionModel @Inject constructor( is Lce.Error -> WcSendReceiveTransactionCheckResultsUM(isLoading = false) is Lce.Loading -> WcSendReceiveTransactionCheckResultsUM(isLoading = true) } + + val feeState = when { + useCase is WcMutableFee -> + WcTransactionFeeState + .Success(dAppFee = useCase.dAppFee(), onClick = { onShowFeeBottomSheet() }) + else -> WcTransactionFeeState.None + } + val actions = WcTransactionActionsUM( + onShowVerifiedAlert = ::showVerifiedAlert, + onDismiss = { cancel(useCase) }, + onSign = { onSign(securityCheck.getOrNull()) }, + onCopy = { copyData(useCase.rawSdkRequest.request.params) }, + ) var transactionUM = converter.convert( - WcCommonTransactionUMConverter.Input( - useCase = useCase, + WcSendTransactionUMConverter.Input( + context = useCase, + feeState = feeState, signState = signState, - actions = WcTransactionActionsUM( - onShowVerifiedAlert = ::showVerifiedAlert, - onDismiss = { cancel(useCase) }, - onSign = { onSign(securityCheck.getOrNull()) }, - onCopy = { copyData(useCase.rawSdkRequest.request.params) }, - onShowFeeBottomSheet = ::onShowFeeBottomSheet, - ), + actions = actions, feeSelectorUM = uiState.value?.feeSelectorUM, ), - ) as? WcSendTransactionUM + ) transactionUM = transactionUM?.copy( transaction = transactionUM.transaction.copy(estimatedWalletChanges = blockAidState), spendAllowance = blockAidState.spendAllowance, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt index 4738a1abaa..cdcb80f9f4 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt @@ -11,13 +11,16 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.domain.walletconnect.WcRequestUseCaseFactory +import com.tangem.domain.walletconnect.model.WcEthMethod +import com.tangem.domain.walletconnect.model.WcSolanaMethod import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase import com.tangem.domain.walletconnect.usecase.method.WcSignState import com.tangem.domain.walletconnect.usecase.method.WcSignStep import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams -import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter import com.tangem.features.walletconnect.transaction.converter.WcHandleMethodErrorConverter +import com.tangem.features.walletconnect.transaction.converter.WcSignTransactionUMConverter +import com.tangem.features.walletconnect.transaction.converter.WcSignTypedDataUMConverter import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM @@ -40,7 +43,8 @@ internal class WcSignTransactionModel @Inject constructor( private val router: Router, private val clipboardManager: ClipboardManager, private val useCaseFactory: WcRequestUseCaseFactory, - private val converter: WcCommonTransactionUMConverter, + private val signTypedDataUMConverter: WcSignTypedDataUMConverter, + private val signTransactionUMConverter: WcSignTransactionUMConverter, ) : Model(), WcCommonTransactionModel { private val params = paramsContainer.require() @@ -58,24 +62,44 @@ internal class WcSignTransactionModel @Inject constructor( useCase.invoke() .onEach { signState -> if (signingIsDone(signState)) return@onEach - val signTransactionUM = converter.convert( - WcCommonTransactionUMConverter.Input( - useCase = useCase, - signState = signState, - actions = WcTransactionActionsUM( - onShowVerifiedAlert = ::showVerifiedAlert, - onDismiss = { cancel(useCase) }, - onSign = useCase::sign, - onCopy = { copyData(useCase.rawSdkRequest.request.params) }, - ), - ), - ) as? WcSignTransactionUM + val signTransactionUM = convertToUI(useCase, signState) _uiState.emit(signTransactionUM) } .launchIn(this) } } + private fun convertToUI( + useCase: WcMessageSignUseCase, + signState: WcSignState, + ): WcSignTransactionUM? { + val actions = WcTransactionActionsUM( + onShowVerifiedAlert = ::showVerifiedAlert, + onDismiss = { cancel(useCase) }, + onSign = useCase::sign, + onCopy = { copyData(useCase.rawSdkRequest.request.params) }, + ) + return when (useCase.method) { + is WcEthMethod.SignTypedData -> signTypedDataUMConverter.convert( + WcSignTypedDataUMConverter.Input( + context = useCase, + signState = signState, + signModel = signState.signModel, + actions = actions, + ), + ) + is WcEthMethod.MessageSign, is WcSolanaMethod.SignMessage -> signTransactionUMConverter.convert( + WcSignTransactionUMConverter.Input( + context = useCase, + signState = signState, + signModel = signState.signModel, + actions = actions, + ), + ) + else -> null + } + } + override fun dismiss() { _uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop() }