From 1ab4cdd170be92b72bf2518f94bd04e37f4fef31 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 24 Oct 2024 09:27:57 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../app/TangemWcBlockchainHelper.kt | 35 ++++++++++++------- .../domain/WalletConnectInteractor.kt | 18 ++++------ .../domain/WcBlockchainHelper.kt | 6 +++- .../walletconnect2/domain/WcJrpcMethods.kt | 4 +-- .../domain/WcSessionRequestConverter.kt | 20 +++++++++-- .../models/solana/SolanaTransactionRequest.kt | 5 ++- .../walletconnect/WalletConnectMiddleware.kt | 17 ++++----- .../configs/feature_toggles_config.json | 2 +- .../DefaultBlockchainSDKFactory.kt | 3 +- version.properties | 2 +- 10 files changed, 69 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/app/TangemWcBlockchainHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/app/TangemWcBlockchainHelper.kt index edddd1a886..8ed86f9fa2 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/app/TangemWcBlockchainHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/app/TangemWcBlockchainHelper.kt @@ -4,6 +4,7 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.blockchainsdk.utils.fromNetworkId import com.tangem.blockchainsdk.utils.toNetworkId import com.tangem.tap.domain.walletconnect2.domain.WcBlockchainHelper +import com.tangem.tap.domain.walletconnect2.domain.models.Account import com.tangem.tap.domain.walletconnect2.toggles.WalletConnectFeatureToggles internal class TangemWcBlockchainHelper( @@ -35,11 +36,12 @@ internal class TangemWcBlockchainHelper( } } - override fun networkIdToChainIdOrNull(networkId: String): String? { + override fun networkIdToChainIdOrNull(networkId: String): List { val blockchain = Blockchain.fromNetworkId(networkId) - val namespace = blockchain?.getCaip2Namespace() ?: return null - val chainId = blockchain.getCaip2ChainId() ?: return null - return "$namespace$CHAIN_SEPARATOR$chainId" + val namespace = blockchain?.getCaip2Namespace() ?: return emptyList() + return blockchain.getCaip2ChainIds().map { + "$namespace$CHAIN_SEPARATOR$it" + } } override fun getNamespaceFromFullChainIdOrNull(chainId: String): String? { @@ -52,8 +54,18 @@ internal class TangemWcBlockchainHelper( return Blockchain.fromNetworkId(networkId)?.fullName } - private fun Blockchain.getCaip2ChainId(): String? { - if (this.isEvm()) return this.getChainId()?.toString() + override fun chainIdsToAccounts( + walletAddress: String, + chainIds: List, + derivationPath: String?, + ): List { + return chainIds.map { chainId -> + Account(chainId, walletAddress, derivationPath) + } + } + + private fun Blockchain.getCaip2ChainIds(): List { + if (this.isEvm()) return listOfNotNull(this.getChainId()?.toString()) return when (this) { /* @@ -61,13 +73,12 @@ internal class TangemWcBlockchainHelper( * uncommented is used. * Docs: https://docs.walletconnect.com/advanced/multichain/chain-list * - * Blockchain.Solana -> "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" * */ - Blockchain.Solana -> "4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ" - Blockchain.SolanaTestnet -> "z4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z" - Blockchain.Polkadot -> "91b171bb158e2d3848fa23a9f1c25182" - Blockchain.Tron -> "0x2b6653dc" - else -> null + Blockchain.Solana -> listOf("5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ") + Blockchain.SolanaTestnet -> listOf("z4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z") + Blockchain.Polkadot -> listOf("91b171bb158e2d3848fa23a9f1c25182") + Blockchain.Tron -> listOf("0x2b6653dc") + else -> emptyList() } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index 122a9ed76f..9d3e956799 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -102,7 +102,7 @@ class WalletConnectInteractor( private suspend fun setupUserChains(userWallet: UserWallet, currencies: List) { val accounts = getAccountsForWc( userWallet = userWallet, - networks = currencies.map { it.network }, + networks = currencies.map { it.network }.distinct(), ) setUserChains(accounts) handleDeeplinkStack(accounts) @@ -403,18 +403,14 @@ class WalletConnectInteractor( derivationPath = it.derivationPath.value, ) } - return walletManagers.mapNotNull { + return walletManagers.flatMap { val wallet = it.wallet - val chainId = blockchainHelper.networkIdToChainIdOrNull( - wallet.blockchain.toNetworkId(), + val chainIds = blockchainHelper.networkIdToChainIdOrNull(wallet.blockchain.toNetworkId()) + blockchainHelper.chainIdsToAccounts( + walletAddress = wallet.address, + chainIds = chainIds, + derivationPath = wallet.publicKey.derivationPath?.rawPath, ) - chainId?.let { - Account( - chainId, - wallet.address, - wallet.publicKey.derivationPath?.rawPath, - ) - } } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcBlockchainHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcBlockchainHelper.kt index 489d086af0..111c5c3d6f 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcBlockchainHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcBlockchainHelper.kt @@ -1,13 +1,17 @@ package com.tangem.tap.domain.walletconnect2.domain +import com.tangem.tap.domain.walletconnect2.domain.models.Account + interface WcBlockchainHelper { fun chainIdToNetworkIdOrNull(chainId: String): String? fun chainIdToMissingNetworkNameOrNull(chainId: String): String? - fun networkIdToChainIdOrNull(networkId: String): String? + fun networkIdToChainIdOrNull(networkId: String): List fun getNamespaceFromFullChainIdOrNull(chainId: String): String? fun chainIdToFullNameOrNull(chainId: String): String? + + fun chainIdsToAccounts(walletAddress: String, chainIds: List, derivationPath: String?): List } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcJrpcMethods.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcJrpcMethods.kt index 3cb1187509..7c937b3772 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcJrpcMethods.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcJrpcMethods.kt @@ -223,14 +223,14 @@ internal class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private WcRequest.AddChain(data = deserializedParams) } WcJrpcMethods.SOLANA_SIGN_TX -> { - val tx = moshi.adapter(SolanaTransactionRequest::class.java) + val tx = moshi.adapter(SolanaTransactionRequest::class.java) .fromJsonOrNull(params) ?: return customRequest WcRequest.SolanaSignRequest(data = tx) } WcJrpcMethods.SOLANA_SIGN_MESSAGE -> { - val signMessage = moshi.adapter(SolanaSignMessage::class.java) + val signMessage = moshi.adapter(SolanaSignMessage::class.java) .fromJsonOrNull(params) ?: return customRequest val data = WcSignMessage( diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt index e02d7cc679..367d7b6a9e 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt @@ -1,12 +1,12 @@ package com.tangem.tap.domain.walletconnect2.domain import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper -import com.tangem.tap.domain.walletconnect2.domain.mapper.mapToTransaction import com.tangem.tap.domain.walletconnect2.domain.models.BnbData import com.tangem.tap.domain.walletconnect2.domain.models.EthTransactionData import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents import com.tangem.tap.features.details.redux.walletconnect.WcEthTransactionType +import okio.ByteString.Companion.decodeBase64 internal class WcSessionRequestConverter( private val blockchainHelper: WcBlockchainHelper, @@ -115,11 +115,11 @@ internal class WcSessionRequestConverter( ) } is WcRequest.SolanaSignRequest -> { - val data = request.data.mapToTransaction() + val transaction = request.data.transaction WcPreparedRequest.SignTransaction( preparedRequestData = WcGenericTransactionData( - hashToSign = data.getSerializedMessage(), + hashToSign = transaction.prepareSolanaTransaction(), dAppName = sessionRequest.metaName, type = TransactionType.SOLANA_TX, ), @@ -132,6 +132,16 @@ internal class WcSessionRequestConverter( } } + /** + * Input transaction in Base64 string + */ + private fun String.prepareSolanaTransaction(): ByteArray { + return this.decodeBase64() + ?.toByteArray() + ?.drop(SOLANA_SIGNATURE_PLACEHOLDER_LENGTH) + ?.toByteArray() ?: ByteArray(0) + } + private fun getWalletAddress(request: WcRequest): String? { return when (request) { is WcRequest.BnbTrade -> request.data.accountNumber @@ -156,4 +166,8 @@ internal class WcSessionRequestConverter( it.chainId == sessionRequest.chainId && it.walletAddress.lowercase() == walletAddress?.lowercase() }?.derivationPath } + + companion object { + private const val SOLANA_SIGNATURE_PLACEHOLDER_LENGTH = 65 + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/solana/SolanaTransactionRequest.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/solana/SolanaTransactionRequest.kt index 7ea66042f4..b77ecffae0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/solana/SolanaTransactionRequest.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/solana/SolanaTransactionRequest.kt @@ -14,6 +14,9 @@ data class SolanaTransactionRequest( @Json(name = "instructions") val instructions: List, + + @Json(name = "transaction") + val transaction: String, ) : WcRequestData { @JsonClass(generateAdapter = true) @@ -22,7 +25,7 @@ data class SolanaTransactionRequest( val programId: String, @Json(name = "data") - val data: List, + val data: String, @Json(name = "keys") val keys: List, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 6b0e0898ec..27df30674a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -13,7 +13,6 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest -import com.tangem.tap.domain.walletconnect2.domain.models.Account import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.proxy.redux.DaggerGraphState @@ -87,18 +86,16 @@ class WalletConnectMiddleware { is WalletConnectAction.ApproveProposal -> { scope.launch { val accounts = getWalletManagers() - .mapNotNull { + .flatMap { val wallet = it.wallet - val chainId = walletConnectInteractor.blockchainHelper.networkIdToChainIdOrNull( + val chainIds = walletConnectInteractor.blockchainHelper.networkIdToChainIdOrNull( wallet.blockchain.toNetworkId(), ) - chainId?.let { - Account( - chainId, - wallet.address, - wallet.publicKey.derivationPath?.rawPath, - ) - } + walletConnectInteractor.blockchainHelper.chainIdsToAccounts( + walletAddress = wallet.address, + chainIds = chainIds, + derivationPath = wallet.publicKey.derivationPath?.rawPath, + ) } walletConnectInteractor.approveSessionProposal(accounts) } diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index 97119cabb4..b906e0ce74 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -5,7 +5,7 @@ }, { "name": "WC_SOLANA_TX_SIGN_ENABLED", - "version": "undefined" + "version": "5.18.0" }, { "name": "STAKING_ENABLED", diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/DefaultBlockchainSDKFactory.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/DefaultBlockchainSDKFactory.kt index 9e5dbd53c8..741f900b6d 100644 --- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/DefaultBlockchainSDKFactory.kt +++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/DefaultBlockchainSDKFactory.kt @@ -55,7 +55,8 @@ internal class DefaultBlockchainSDKFactory( // flow3 = subscribe on feature toggles changes, TODO: [REDACTED_JIRA] transform = walletManagerFactoryCreator::create, ) - .stateIn(scope = mainScope, started = SharingStarted.Lazily, initialValue = null) + // don't use Lazily because some features (WC) require initialized factory on app started + .stateIn(scope = mainScope, started = SharingStarted.Eagerly, initialValue = null) } private fun CoroutineScope.updateBlockchainProviderTypes() { diff --git a/version.properties b/version.properties index e7ffe36363..3a969ad8fe 100644 --- a/version.properties +++ b/version.properties @@ -1 +1 @@ -versionName=5.17.0 \ No newline at end of file +versionName=5.18.0 \ No newline at end of file