Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-24 09:27:57 +03:00
parent c120acae62
commit 1ab4cdd170
10 changed files with 69 additions and 43 deletions

View file

@ -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<String> {
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<String>,
derivationPath: String?,
): List<Account> {
return chainIds.map { chainId ->
Account(chainId, walletAddress, derivationPath)
}
}
private fun Blockchain.getCaip2ChainIds(): List<String> {
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()
}
}

View file

@ -102,7 +102,7 @@ class WalletConnectInteractor(
private suspend fun setupUserChains(userWallet: UserWallet, currencies: List<CryptoCurrency>) {
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,
)
}
}
}

View file

@ -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<String>
fun getNamespaceFromFullChainIdOrNull(chainId: String): String?
fun chainIdToFullNameOrNull(chainId: String): String?
fun chainIdsToAccounts(walletAddress: String, chainIds: List<String>, derivationPath: String?): List<Account>
}

View file

@ -223,14 +223,14 @@ internal class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private
WcRequest.AddChain(data = deserializedParams)
}
WcJrpcMethods.SOLANA_SIGN_TX -> {
val tx = moshi.adapter<SolanaTransactionRequest>(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>(SolanaSignMessage::class.java)
val signMessage = moshi.adapter(SolanaSignMessage::class.java)
.fromJsonOrNull(params)
?: return customRequest
val data = WcSignMessage(

View file

@ -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
}
}

View file

@ -14,6 +14,9 @@ data class SolanaTransactionRequest(
@Json(name = "instructions")
val instructions: List<Instruction>,
@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<Byte>,
val data: String,
@Json(name = "keys")
val keys: List<Key>,

View file

@ -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)
}