Updated on 2026-08-14
This commit is contained in:
parent
2c739e2a4f
commit
70eda1b6e7
24 changed files with 445 additions and 140 deletions
|
|
@ -121,6 +121,10 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
onReject = state.dialog.onReject,
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.SignTransactionDialog -> SignTransactionDialog.create(
|
||||
preparedData = state.dialog.data,
|
||||
context = context,
|
||||
)
|
||||
is BackupDialog.AttestationFailed -> AttestationFailedDialog.create(context)
|
||||
is BackupDialog.AddMoreBackupCards -> AddMoreBackupCardsDialog.create(context)
|
||||
is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class WalletConnect(
|
||||
internal sealed class WalletConnect(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
error: Throwable? = null,
|
||||
|
|
@ -65,7 +65,7 @@ sealed class WalletConnect(
|
|||
FAIL("Fail"),
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SUCCESS_CODE = "0"
|
||||
private companion object {
|
||||
const val SUCCESS_CODE = "0"
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,8 @@ import com.trustwallet.walletconnect.models.binance.WCBinanceTradeOrder
|
|||
import com.trustwallet.walletconnect.models.binance.WCBinanceTransferOrder
|
||||
import timber.log.Timber
|
||||
|
||||
object BnbHelper {
|
||||
internal object BnbHelper {
|
||||
|
||||
fun createMessageData(order: WCBinanceTransferOrder): BinanceMessageData.Transfer {
|
||||
val input = order.msgs.first().inputs.first()
|
||||
val output = order.msgs.first().inputs.first()
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit
|
|||
import kotlin.collections.set
|
||||
|
||||
@Suppress("LargeClass")
|
||||
class WalletConnectManager {
|
||||
internal class WalletConnectManager {
|
||||
|
||||
private var cardId: String? = null
|
||||
|
||||
|
|
@ -348,6 +348,7 @@ class WalletConnectManager {
|
|||
val hash = WalletConnectSdkHelper().signPersonalMessage(
|
||||
hashToSign = data.hash,
|
||||
networkId = activeData.wallet.blockchain?.toNetworkId() ?: "",
|
||||
type = data.type,
|
||||
derivationPath = activeData.wallet.derivationPath?.rawPath,
|
||||
cardId = cardId,
|
||||
)
|
||||
|
|
@ -522,9 +523,9 @@ class WalletConnectManager {
|
|||
}
|
||||
}
|
||||
|
||||
typealias Topic = String
|
||||
internal typealias Topic = String
|
||||
|
||||
data class WalletConnectActiveData(
|
||||
internal data class WalletConnectActiveData(
|
||||
val peerId: String,
|
||||
val remotePeerId: String?,
|
||||
val client: WCClient,
|
||||
|
|
@ -547,7 +548,7 @@ data class WalletConnectActiveData(
|
|||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
class RetryInterceptor : Interceptor {
|
||||
internal class RetryInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request: Request = chain.request()
|
||||
val response = chain.proceed(request)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
|
|||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.toKeccak
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.blockchain.extensions.hexToBigDecimal
|
||||
import com.tangem.blockchain.extensions.isAscii
|
||||
import com.tangem.blockchain.extensions.*
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toDecompressedPublicKey
|
||||
|
|
@ -25,8 +22,9 @@ import com.tangem.tap.common.extensions.safeUpdate
|
|||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.domain.walletconnect.BnbHelper.toWCBinanceTradeOrder
|
||||
import com.tangem.tap.domain.walletconnect.BnbHelper.toWCBinanceTransferOrder
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcEthereumSignMessage
|
||||
import com.tangem.tap.domain.walletconnect2.domain.TransactionType
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcEthereumTransaction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcSignMessage
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.EthTransactionData
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTradeOrder
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTransferOrder
|
||||
|
|
@ -45,6 +43,7 @@ import timber.log.Timber
|
|||
import java.math.BigDecimal
|
||||
import com.tangem.core.analytics.models.AnalyticsParam as CoreAnalyticsParam
|
||||
|
||||
@Suppress("LargeClass")
|
||||
class WalletConnectSdkHelper {
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
|
|
@ -206,8 +205,7 @@ class WalletConnectSdkHelper {
|
|||
walletPublicKey = data.walletManager.wallet.publicKey.seedKey,
|
||||
derivationPath = data.walletManager.wallet.publicKey.derivationPath,
|
||||
)
|
||||
val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId)
|
||||
return when (result) {
|
||||
return when (val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId)) {
|
||||
is CompletionResult.Success -> {
|
||||
val hash = EthereumUtils.prepareTransactionToSend(
|
||||
signature = result.data.signature,
|
||||
|
|
@ -250,8 +248,7 @@ class WalletConnectSdkHelper {
|
|||
walletPublicKey = wallet.publicKey.seedKey,
|
||||
derivationPath = wallet.publicKey.derivationPath,
|
||||
)
|
||||
val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId)
|
||||
return when (result) {
|
||||
return when (val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId)) {
|
||||
is CompletionResult.Success -> {
|
||||
val key = wallet.publicKey.blockchainKey.toDecompressedPublicKey()
|
||||
getBnbResultString(
|
||||
|
|
@ -267,16 +264,17 @@ class WalletConnectSdkHelper {
|
|||
}
|
||||
|
||||
fun prepareDataForPersonalSign(
|
||||
message: WcEthereumSignMessage,
|
||||
message: WcSignMessage,
|
||||
topic: String,
|
||||
metaName: String,
|
||||
id: Long,
|
||||
): WcPersonalSignData {
|
||||
val messageData = when (message.type) {
|
||||
WcEthereumSignMessage.WCSignType.MESSAGE,
|
||||
WcEthereumSignMessage.WCSignType.PERSONAL_MESSAGE,
|
||||
WcSignMessage.WCSignType.MESSAGE,
|
||||
WcSignMessage.WCSignType.PERSONAL_MESSAGE,
|
||||
-> createMessageData(message)
|
||||
WcEthereumSignMessage.WCSignType.TYPED_MESSAGE -> EthereumUtils.makeTypedDataHash(message.data)
|
||||
WcSignMessage.WCSignType.TYPED_MESSAGE -> EthereumUtils.makeTypedDataHash(message.data)
|
||||
WcSignMessage.WCSignType.SOLANA_MESSAGE -> message.data.decodeBase58()
|
||||
}
|
||||
|
||||
val messageString = message.data.hexToAscii()
|
||||
|
|
@ -290,7 +288,7 @@ class WalletConnectSdkHelper {
|
|||
id = id,
|
||||
)
|
||||
return WcPersonalSignData(
|
||||
hash = messageData,
|
||||
hash = requireNotNull(messageData) { "Message data must not be null" },
|
||||
topic = topic,
|
||||
id = id,
|
||||
dialogData = dialogData,
|
||||
|
|
@ -298,7 +296,7 @@ class WalletConnectSdkHelper {
|
|||
)
|
||||
}
|
||||
|
||||
private fun createMessageData(message: WcEthereumSignMessage): ByteArray {
|
||||
private fun createMessageData(message: WcSignMessage): ByteArray {
|
||||
val messageData = try {
|
||||
message.data.removePrefix(HEX_PREFIX).hexToBytes()
|
||||
} catch (exception: Exception) {
|
||||
|
|
@ -332,6 +330,7 @@ class WalletConnectSdkHelper {
|
|||
suspend fun signPersonalMessage(
|
||||
hashToSign: ByteArray,
|
||||
networkId: String,
|
||||
type: WcSignMessage.WCSignType,
|
||||
derivationPath: String?,
|
||||
cardId: String?,
|
||||
): String? {
|
||||
|
|
@ -345,12 +344,16 @@ class WalletConnectSdkHelper {
|
|||
)
|
||||
return when (val result = tangemSdkManager.runTaskAsync(command, cardId)) {
|
||||
is CompletionResult.Success -> {
|
||||
val hash = result.data.signature
|
||||
return EthereumUtils.prepareSignedMessageData(
|
||||
signedHash = hash,
|
||||
hashToSign = hashToSign,
|
||||
publicKey = wallet.publicKey.blockchainKey.toDecompressedPublicKey(),
|
||||
)
|
||||
val signedHash = result.data.signature
|
||||
|
||||
return when (type) {
|
||||
WcSignMessage.WCSignType.SOLANA_MESSAGE -> getSolanaResultString(signedHash)
|
||||
else -> EthereumUtils.prepareSignedMessageData(
|
||||
signedHash = signedHash,
|
||||
hashToSign = hashToSign,
|
||||
publicKey = wallet.publicKey.blockchainKey.toDecompressedPublicKey(),
|
||||
)
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.e(result.error.customMessage)
|
||||
|
|
@ -359,12 +362,46 @@ class WalletConnectSdkHelper {
|
|||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ETH_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n"
|
||||
private const val HEX_PREFIX = "0x"
|
||||
private const val DEFAULT_MAX_GASLIMIT = 350000
|
||||
fun getBnbResultString(publicKey: String, signature: String): String {
|
||||
return "{\"signature\":\"$signature\",\"publicKey\":\"$publicKey\"}"
|
||||
suspend fun signTransaction(
|
||||
hashToSign: ByteArray,
|
||||
networkId: String,
|
||||
type: TransactionType,
|
||||
derivationPath: String?,
|
||||
cardId: String?,
|
||||
): String? {
|
||||
val blockchain = Blockchain.fromNetworkId(networkId) ?: return null
|
||||
val wallet = getWalletManager(blockchain, derivationPath)?.wallet ?: return null
|
||||
|
||||
val command = SignHashCommand(
|
||||
hash = hashToSign,
|
||||
walletPublicKey = wallet.publicKey.seedKey,
|
||||
derivationPath = wallet.publicKey.derivationPath,
|
||||
)
|
||||
return when (val result = tangemSdkManager.runTaskAsync(command, cardId)) {
|
||||
is CompletionResult.Success -> {
|
||||
val signedHash = result.data.signature
|
||||
|
||||
when (type) {
|
||||
TransactionType.SOLANA_TX -> {
|
||||
getSolanaResultString(signedHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.e(result.error.customMessage)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSolanaResultString(signedHash: ByteArray) = "{ signature: \"${signedHash.encodeBase58()}\" }"
|
||||
|
||||
private fun getBnbResultString(publicKey: String, signature: String) =
|
||||
"{\"signature\":\"$signature\",\"publicKey\":\"$publicKey\"}"
|
||||
|
||||
private companion object {
|
||||
const val ETH_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n"
|
||||
const val HEX_PREFIX = "0x"
|
||||
const val DEFAULT_MAX_GASLIMIT = 350000
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
package com.tangem.tap.domain.walletconnect.extensions
|
||||
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcEthereumSignMessage
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcEthereumTransaction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcSignMessage
|
||||
import com.trustwallet.walletconnect.models.WCPeerMeta
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
|
||||
|
||||
fun WCPeerMeta.isDappSupported(): Boolean {
|
||||
internal fun WCPeerMeta.isDappSupported(): Boolean {
|
||||
return !unsupportedDappsList.any { this.url.contains(it) }
|
||||
}
|
||||
|
||||
private val unsupportedDappsList: List<String> = listOf("dydx.exchange")
|
||||
|
||||
fun WCEthereumTransaction.toWcEthTransaction(): WcEthereumTransaction {
|
||||
internal fun WCEthereumTransaction.toWcEthTransaction(): WcEthereumTransaction {
|
||||
return WcEthereumTransaction(
|
||||
from = from,
|
||||
to = to,
|
||||
|
|
@ -27,13 +27,13 @@ fun WCEthereumTransaction.toWcEthTransaction(): WcEthereumTransaction {
|
|||
)
|
||||
}
|
||||
|
||||
fun WCEthereumSignMessage.toWcEthereumSignMessage(): WcEthereumSignMessage {
|
||||
return WcEthereumSignMessage(
|
||||
internal fun WCEthereumSignMessage.toWcEthereumSignMessage(): WcSignMessage {
|
||||
return WcSignMessage(
|
||||
raw = raw,
|
||||
type = when (type) {
|
||||
WCEthereumSignMessage.WCSignType.MESSAGE -> WcEthereumSignMessage.WCSignType.MESSAGE
|
||||
WCEthereumSignMessage.WCSignType.PERSONAL_MESSAGE -> WcEthereumSignMessage.WCSignType.PERSONAL_MESSAGE
|
||||
WCEthereumSignMessage.WCSignType.TYPED_MESSAGE -> WcEthereumSignMessage.WCSignType.TYPED_MESSAGE
|
||||
WCEthereumSignMessage.WCSignType.MESSAGE -> WcSignMessage.WCSignType.MESSAGE
|
||||
WCEthereumSignMessage.WCSignType.PERSONAL_MESSAGE -> WcSignMessage.WCSignType.PERSONAL_MESSAGE
|
||||
WCEthereumSignMessage.WCSignType.TYPED_MESSAGE -> WcSignMessage.WCSignType.TYPED_MESSAGE
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -4,8 +4,18 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcBlockchainHelper
|
||||
import com.tangem.tap.domain.walletconnect2.toggles.WalletConnectFeatureToggles
|
||||
|
||||
internal class TangemWcBlockchainHelper(
|
||||
private val featureToggles: WalletConnectFeatureToggles,
|
||||
) : WcBlockchainHelper {
|
||||
|
||||
private val supportedNonEvmBlockchains = if (featureToggles.isSolanaTxSignEnabled) {
|
||||
setOf(Blockchain.Solana, Blockchain.SolanaTestnet)
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
class TangemWcBlockchainHelper : WcBlockchainHelper {
|
||||
override fun chainIdToNetworkIdOrNull(chainId: String): String? {
|
||||
val parsedId = chainId.parseId() ?: return null
|
||||
val blockchain = parsedId.chainIdToBlockchain()
|
||||
|
|
@ -41,48 +51,57 @@ class TangemWcBlockchainHelper : WcBlockchainHelper {
|
|||
val networkId = chainIdToNetworkIdOrNull(chainId) ?: return null
|
||||
return Blockchain.fromNetworkId(networkId)?.fullName
|
||||
}
|
||||
}
|
||||
|
||||
private fun Blockchain.getCaip2ChainId(): String? {
|
||||
if (this.isEvm()) return this.getChainId()?.toString()
|
||||
private fun Blockchain.getCaip2ChainId(): String? {
|
||||
if (this.isEvm()) return this.getChainId()?.toString()
|
||||
|
||||
return when (this) {
|
||||
Blockchain.Solana -> "4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ"
|
||||
Blockchain.Polkadot -> "91b171bb158e2d3848fa23a9f1c25182"
|
||||
Blockchain.Tron -> "0x2b6653dc"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun Blockchain.getCaip2Namespace(): String? {
|
||||
return when {
|
||||
this.isEvm() -> EVM_NAMESPACE
|
||||
supportedNonEvmBlockchains.contains(this) -> this.toNetworkId()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.parseId(): Pair<String, String>? {
|
||||
val parsed = this.split(CHAIN_SEPARATOR)
|
||||
if (parsed.size != 2) return null
|
||||
|
||||
return parsed[0] to parsed[1]
|
||||
}
|
||||
|
||||
private fun Pair<String, String>.chainIdToBlockchain(): Blockchain? {
|
||||
return when (first) {
|
||||
EVM_NAMESPACE -> {
|
||||
second.toIntOrNull()
|
||||
?.let(Blockchain::fromChainId)
|
||||
}
|
||||
else -> {
|
||||
Blockchain.fromNetworkId(networkId = first)
|
||||
.takeIf(supportedNonEvmBlockchains::contains)
|
||||
return when (this) {
|
||||
/*
|
||||
* The WC sample application and documentation use a commented out chain ID. However, in real dApps
|
||||
* 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val supportedNonEvmBlockchains = emptySet<Blockchain>() // TODO: add supported networks
|
||||
private fun Blockchain.getCaip2Namespace(): String? {
|
||||
return when {
|
||||
this.isEvm() -> EVM_NAMESPACE
|
||||
supportedNonEvmBlockchains.contains(this) -> this.toNetworkId().substringBefore(TESTNET_SEPARATOR)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private const val EVM_NAMESPACE = "eip155"
|
||||
private const val CHAIN_SEPARATOR = ":"
|
||||
private fun String.parseId(): Pair<String, String>? {
|
||||
val parsed = this.split(CHAIN_SEPARATOR)
|
||||
if (parsed.size != 2) return null
|
||||
|
||||
return parsed[0] to parsed[1]
|
||||
}
|
||||
|
||||
private fun Pair<String, String>.chainIdToBlockchain(): Blockchain? {
|
||||
return when (first) {
|
||||
EVM_NAMESPACE -> {
|
||||
second.toIntOrNull()
|
||||
?.let(Blockchain::fromChainId)
|
||||
}
|
||||
else -> {
|
||||
Blockchain.fromNetworkId(networkId = first)
|
||||
.takeIf(supportedNonEvmBlockchains::contains)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EVM_NAMESPACE = "eip155"
|
||||
const val CHAIN_SEPARATOR = ":"
|
||||
const val TESTNET_SEPARATOR = "/"
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import com.tangem.tap.features.details.ui.walletconnect.WcSessionForScreen
|
|||
import com.tangem.tap.store
|
||||
import timber.log.Timber
|
||||
|
||||
class WalletConnectEventsHandlerImpl : WalletConnectEventsHandler {
|
||||
internal class WalletConnectEventsHandlerImpl : WalletConnectEventsHandler {
|
||||
override fun onProposalReceived(proposal: WalletConnectEvents.SessionProposal, networksFormatted: String) {
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.ShowDialog(
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@ import kotlinx.coroutines.*
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class WalletConnectRepositoryImpl @Inject constructor(
|
||||
internal class DefaultWalletConnectRepository(
|
||||
private val application: Application,
|
||||
private val wcRequestDeserializer: WcJrpcRequestsDeserializer,
|
||||
private val analyticsHandler: AnalyticsEventHandler,
|
||||
|
|
@ -95,11 +94,11 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
) {
|
||||
// Triggered when wallet receives the session proposal sent by a Dapp
|
||||
Timber.d("sessionProposal: $sessionProposal")
|
||||
this@WalletConnectRepositoryImpl.sessionProposal = sessionProposal
|
||||
this@DefaultWalletConnectRepository.sessionProposal = sessionProposal
|
||||
|
||||
val missingNetworks = findMissingNetworks(
|
||||
namespaces = sessionProposal.requiredNamespaces,
|
||||
userNamespaces = this@WalletConnectRepositoryImpl.userNamespaces ?: emptyMap(),
|
||||
userNamespaces = this@DefaultWalletConnectRepository.userNamespaces ?: emptyMap(),
|
||||
)
|
||||
|
||||
if (missingNetworks.isNotEmpty()) {
|
||||
|
|
@ -116,7 +115,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
|
||||
val optionalWithoutMissingNetworks = removeMissingNetworks(
|
||||
namespaces = sessionProposal.optionalNamespaces,
|
||||
userNamespaces = this@WalletConnectRepositoryImpl.userNamespaces ?: emptyMap(),
|
||||
userNamespaces = this@DefaultWalletConnectRepository.userNamespaces ?: emptyMap(),
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
|
|
@ -334,6 +333,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
Web3Wallet.respondSessionRequest(
|
||||
params = Wallet.Params.SessionRequestResponse(
|
||||
sessionTopic = requestData.topic,
|
||||
|
|
@ -342,15 +342,19 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
result = result,
|
||||
),
|
||||
),
|
||||
onSuccess = {},
|
||||
onError = {
|
||||
onSuccess = { response ->
|
||||
Timber.d("Session request responded successfully: $response")
|
||||
},
|
||||
onError = { error ->
|
||||
Timber.d(error.throwable, "Error while responging session request")
|
||||
|
||||
WalletConnect.RequestHandledParams(
|
||||
dAppName = session?.name ?: "",
|
||||
dAppUrl = session?.url ?: "",
|
||||
methodName = requestData.method,
|
||||
blockchain = requestData.blockchain,
|
||||
errorCode = WalletConnectError.ValidationError.error,
|
||||
errorDescription = it.throwable.message,
|
||||
errorDescription = error.throwable.message,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -3,15 +3,13 @@ package com.tangem.tap.domain.walletconnect2.data
|
|||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import com.tangem.datasource.di.SdkMoshi
|
||||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.Session
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class WalletConnectSessionsRepositoryImpl @Inject constructor(
|
||||
@SdkMoshi private val moshi: Moshi,
|
||||
internal class DefaultWalletConnectSessionsRepository(
|
||||
private val moshi: Moshi,
|
||||
private val fileReader: FileReader,
|
||||
) :
|
||||
WalletConnectSessionsRepository {
|
||||
|
|
@ -1,15 +1,22 @@
|
|||
package com.tangem.tap.domain.walletconnect2.di
|
||||
|
||||
import android.app.Application
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||
import com.tangem.datasource.di.SdkMoshi
|
||||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper
|
||||
import com.tangem.tap.domain.walletconnect2.app.TangemWcBlockchainHelper
|
||||
import com.tangem.tap.domain.walletconnect2.app.WalletConnectEventsHandlerImpl
|
||||
import com.tangem.tap.domain.walletconnect2.data.WalletConnectRepositoryImpl
|
||||
import com.tangem.tap.domain.walletconnect2.data.WalletConnectSessionsRepositoryImpl
|
||||
import com.tangem.tap.domain.walletconnect2.data.DefaultWalletConnectRepository
|
||||
import com.tangem.tap.domain.walletconnect2.data.DefaultWalletConnectSessionsRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer
|
||||
import com.tangem.tap.domain.walletconnect2.toggles.WalletConnectFeatureToggles
|
||||
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -20,19 +27,21 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(ActivityComponent::class)
|
||||
class WalletConnectInteractorModule {
|
||||
internal object WalletConnectInteractorModule {
|
||||
|
||||
@Provides
|
||||
@ActivityScoped
|
||||
fun provideWalletConnectInteractor(
|
||||
wcRepository: WalletConnectRepository,
|
||||
wcSessionsRepository: WalletConnectSessionsRepository,
|
||||
walletConnectFeatureToggles: WalletConnectFeatureToggles,
|
||||
): WalletConnectInteractor {
|
||||
return WalletConnectInteractor(
|
||||
handler = WalletConnectEventsHandlerImpl(),
|
||||
walletConnectRepository = wcRepository,
|
||||
sessionsRepository = wcSessionsRepository,
|
||||
sdkHelper = WalletConnectSdkHelper(),
|
||||
blockchainHelper = TangemWcBlockchainHelper(),
|
||||
blockchainHelper = TangemWcBlockchainHelper(walletConnectFeatureToggles),
|
||||
dispatcher = AppCoroutineDispatcherProvider(),
|
||||
)
|
||||
}
|
||||
|
|
@ -40,15 +49,37 @@ class WalletConnectInteractorModule {
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface WalletConnectModule {
|
||||
internal object WalletConnectModule {
|
||||
|
||||
@Binds
|
||||
@Provides
|
||||
@Singleton
|
||||
fun bindWalletConnectRepository(repository: WalletConnectRepositoryImpl): WalletConnectRepository
|
||||
fun provideWalletConnectFeatureToggles(featureTogglesManager: FeatureTogglesManager): WalletConnectFeatureToggles {
|
||||
return WalletConnectFeatureToggles(featureTogglesManager)
|
||||
}
|
||||
|
||||
@Binds
|
||||
@Provides
|
||||
@Singleton
|
||||
fun bindWalletConnectSessionsRepository(
|
||||
repository: WalletConnectSessionsRepositoryImpl,
|
||||
): WalletConnectSessionsRepository
|
||||
fun provideWalletConnectRepository(
|
||||
application: Application,
|
||||
wcRequestDeserializer: WcJrpcRequestsDeserializer,
|
||||
analyticsHandler: AnalyticsEventHandler,
|
||||
): WalletConnectRepository {
|
||||
return DefaultWalletConnectRepository(
|
||||
application = application,
|
||||
wcRequestDeserializer = wcRequestDeserializer,
|
||||
analyticsHandler = analyticsHandler,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideWalletConnectSessionsRepository(
|
||||
@SdkMoshi moshi: Moshi,
|
||||
fileReader: FileReader,
|
||||
): WalletConnectSessionsRepository {
|
||||
return DefaultWalletConnectSessionsRepository(
|
||||
moshi = moshi,
|
||||
fileReader = fileReader,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -209,7 +209,7 @@ class WalletConnectInteractor(
|
|||
val currentRequest = this.currentRequest
|
||||
if (currentRequest == null || request.topic != currentRequest.topic) return
|
||||
|
||||
val networkId = blockchainHelper.chainIdToNetworkIdOrNull(currentRequest.chainId ?: "") ?: return
|
||||
val networkId = blockchainHelper.chainIdToNetworkIdOrNull(currentRequest.chainId.orEmpty()) ?: return
|
||||
val signedHash = when (request) {
|
||||
is WcPreparedRequest.BnbTransaction -> sdkHelper.signBnbTransaction(
|
||||
data = request.preparedRequestData.data.data,
|
||||
|
|
@ -224,13 +224,19 @@ class WalletConnectInteractor(
|
|||
is WcPreparedRequest.EthSign -> sdkHelper.signPersonalMessage(
|
||||
hashToSign = request.preparedRequestData.hash,
|
||||
networkId = networkId,
|
||||
type = request.preparedRequestData.type,
|
||||
derivationPath = request.derivationPath,
|
||||
cardId = cardId,
|
||||
)
|
||||
is WcPreparedRequest.SignTransaction -> sdkHelper.signTransaction(
|
||||
hashToSign = request.preparedRequestData.hashToSign,
|
||||
networkId = networkId,
|
||||
type = request.preparedRequestData.type,
|
||||
derivationPath = request.derivationPath,
|
||||
cardId = cardId,
|
||||
)
|
||||
}
|
||||
|
||||
Timber.d("Signed hash: $signedHash")
|
||||
|
||||
val requestData = RequestData(
|
||||
topic = request.topic,
|
||||
requestId = request.requestId,
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@ package com.tangem.tap.domain.walletconnect2.domain
|
|||
|
||||
import com.squareup.moshi.*
|
||||
import com.tangem.datasource.di.SdkMoshi
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WCBinanceTxConfirmParam
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceCancelOrder
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTradeOrder
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTransferOrder
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTxConfirmParam
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.solana.SolanaSignMessage
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.solana.SolanaTransactionRequest
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
enum class WcJrpcMethods(val code: String) {
|
||||
internal enum class WcJrpcMethods(val code: String) {
|
||||
|
||||
ETH_SIGN("eth_sign"),
|
||||
ETH_PERSONAL_SIGN("personal_sign"),
|
||||
|
|
@ -18,10 +20,14 @@ enum class WcJrpcMethods(val code: String) {
|
|||
ETH_SIGN_TYPE_DATA_V4("eth_signTypedData_v4"),
|
||||
ETH_SIGN_TRANSACTION("eth_signTransaction"),
|
||||
ETH_SEND_TRANSACTION("eth_sendTransaction"),
|
||||
|
||||
BNB_SIGN("bnb_sign"),
|
||||
BNB_TRANSACTION_CONFIRM("bnb_tx_confirmation"),
|
||||
SIGN_TRANSACTION("trust_signTransaction"),
|
||||
WALLET_ADD_ETHEREUM_CHAIN("wallet_addEthereumChain"),
|
||||
|
||||
SOLANA_SIGN_TX("solana_signTransaction"),
|
||||
SOLANA_SIGN_MESSAGE("solana_signMessage"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
|
@ -30,7 +36,7 @@ enum class WcJrpcMethods(val code: String) {
|
|||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WCSignTransaction(
|
||||
data class WcSignTransaction(
|
||||
@Json(name = "network")
|
||||
val network: Int,
|
||||
|
||||
|
|
@ -39,13 +45,7 @@ data class WCSignTransaction(
|
|||
) : WcRequestData
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WcAddChain(
|
||||
@Json(name = "chainId")
|
||||
val chainId: String,
|
||||
) : WcRequestData
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WcEthereumSignMessage(
|
||||
data class WcSignMessage(
|
||||
@Json(name = "raw")
|
||||
val raw: List<String>,
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ data class WcEthereumSignMessage(
|
|||
val type: WCSignType,
|
||||
) : WcRequestData {
|
||||
enum class WCSignType {
|
||||
MESSAGE, PERSONAL_MESSAGE, TYPED_MESSAGE
|
||||
MESSAGE, PERSONAL_MESSAGE, TYPED_MESSAGE, SOLANA_MESSAGE,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -63,6 +63,7 @@ data class WcEthereumSignMessage(
|
|||
* - MESSAGE: `[address, data ]`
|
||||
* - TYPED_MESSAGE: `[address, data]`
|
||||
* - PERSONAL_MESSAGE: `[data, address]`
|
||||
* - SOLANA_MESSAGE: `[publicKey (address), message]`
|
||||
*
|
||||
* reference: https://docs.walletconnect.org/json-rpc/ethereum#eth_signtypeddata
|
||||
*/
|
||||
|
|
@ -79,6 +80,21 @@ data class WcEthereumSignMessage(
|
|||
}
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WcSignMessageData(
|
||||
@Json(name = "address")
|
||||
val address: String,
|
||||
|
||||
@Json(name = "message")
|
||||
val message: String,
|
||||
) : WcRequestData
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WcAddChain(
|
||||
@Json(name = "chainId")
|
||||
val chainId: String,
|
||||
) : WcRequestData
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WcEthereumTransaction(
|
||||
@Json(name = "from")
|
||||
|
|
@ -117,20 +133,21 @@ interface WcRequestData
|
|||
data class WcCustomRequestData(val data: String) : WcRequestData
|
||||
|
||||
sealed class WcRequest(open val data: WcRequestData) {
|
||||
data class EthSign(override val data: WcEthereumSignMessage) : WcRequest(data)
|
||||
data class EthSign(override val data: WcSignMessage) : WcRequest(data)
|
||||
data class EthSignTransaction(override val data: WcEthereumTransaction) : WcRequest(data)
|
||||
data class EthSendTransaction(override val data: WcEthereumTransaction) : WcRequest(data)
|
||||
data class BnbTrade(override val data: WcBinanceTradeOrder) : WcRequest(data)
|
||||
data class BnbCancel(override val data: WcBinanceCancelOrder) : WcRequest(data)
|
||||
data class BnbTransfer(override val data: WcBinanceTransferOrder) : WcRequest(data)
|
||||
data class BnbTxConfirm(override val data: WCBinanceTxConfirmParam) : WcRequest(data)
|
||||
data class SignTransaction(override val data: WCSignTransaction) : WcRequest(data)
|
||||
data class BnbTxConfirm(override val data: WcBinanceTxConfirmParam) : WcRequest(data)
|
||||
data class SignTransaction(override val data: WcSignTransaction) : WcRequest(data)
|
||||
data class AddChain(override val data: WcAddChain) : WcRequest(data)
|
||||
data class CustomRequest(override val data: WcCustomRequestData) : WcRequest(data)
|
||||
data class SolanaSignRequest(override val data: SolanaTransactionRequest) : WcRequest(data)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi: Moshi) {
|
||||
internal class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi: Moshi) {
|
||||
|
||||
@Suppress("ComplexMethod", "LongMethod")
|
||||
fun deserialize(method: String, params: String): WcRequest {
|
||||
|
|
@ -154,9 +171,9 @@ class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi
|
|||
val deserializedParams = moshi.adapter<List<String>>(
|
||||
Types.newParameterizedType(List::class.java, String::class.java),
|
||||
).fromJsonOrNull(params) ?: return customRequest
|
||||
val data = WcEthereumSignMessage(
|
||||
val data = WcSignMessage(
|
||||
raw = deserializedParams,
|
||||
type = WcEthereumSignMessage.WCSignType.MESSAGE,
|
||||
type = WcSignMessage.WCSignType.MESSAGE,
|
||||
)
|
||||
WcRequest.EthSign(data = data)
|
||||
}
|
||||
|
|
@ -164,9 +181,9 @@ class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi
|
|||
val deserializedParams = moshi.adapter<List<String>>(
|
||||
Types.newParameterizedType(List::class.java, String::class.java),
|
||||
).fromJsonOrNull(params) ?: return customRequest
|
||||
val data = WcEthereumSignMessage(
|
||||
val data = WcSignMessage(
|
||||
raw = deserializedParams,
|
||||
type = WcEthereumSignMessage.WCSignType.PERSONAL_MESSAGE,
|
||||
type = WcSignMessage.WCSignType.PERSONAL_MESSAGE,
|
||||
)
|
||||
WcRequest.EthSign(data = data)
|
||||
}
|
||||
|
|
@ -175,9 +192,9 @@ class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi
|
|||
params.substring(params.indexOf("\"") + 1, params.indexOf("\"", startIndex = 2)),
|
||||
params.substring(params.indexOfFirst { it == '{' }, params.indexOfLast { it == '}' } + 1),
|
||||
)
|
||||
val data = WcEthereumSignMessage(
|
||||
val data = WcSignMessage(
|
||||
deserializedParams,
|
||||
WcEthereumSignMessage.WCSignType.TYPED_MESSAGE,
|
||||
WcSignMessage.WCSignType.TYPED_MESSAGE,
|
||||
)
|
||||
Timber.d("TypedData params: $deserializedParams")
|
||||
WcRequest.EthSign(data)
|
||||
|
|
@ -186,23 +203,43 @@ class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi
|
|||
return deserializeBnb(moshi, params) ?: customRequest
|
||||
}
|
||||
WcJrpcMethods.BNB_TRANSACTION_CONFIRM -> {
|
||||
val deserializedParams = moshi.adapter<List<WCBinanceTxConfirmParam>>(
|
||||
Types.newParameterizedType(List::class.java, WCBinanceTxConfirmParam::class.java),
|
||||
val deserializedParams = moshi.adapter<List<WcBinanceTxConfirmParam>>(
|
||||
Types.newParameterizedType(List::class.java, WcBinanceTxConfirmParam::class.java),
|
||||
).fromJsonFirstOrNull(params) ?: return customRequest
|
||||
WcRequest.BnbTxConfirm(data = deserializedParams)
|
||||
}
|
||||
WcJrpcMethods.SIGN_TRANSACTION -> {
|
||||
val deserializedParams = moshi.adapter<List<WCSignTransaction>>(
|
||||
Types.newParameterizedType(List::class.java, WCSignTransaction::class.java),
|
||||
val deserializedParams = moshi.adapter<List<WcSignTransaction>>(
|
||||
Types.newParameterizedType(List::class.java, WcSignTransaction::class.java),
|
||||
).fromJsonFirstOrNull(params) ?: return customRequest
|
||||
|
||||
WcRequest.SignTransaction(data = deserializedParams)
|
||||
}
|
||||
WcJrpcMethods.WALLET_ADD_ETHEREUM_CHAIN -> {
|
||||
val deserializedParams: WcAddChain = moshi.adapter<List<WcAddChain>>(
|
||||
Types.newParameterizedType(List::class.java, WcAddChain::class.java),
|
||||
).fromJsonFirstOrNull(params) ?: return customRequest
|
||||
|
||||
WcRequest.AddChain(data = deserializedParams)
|
||||
}
|
||||
WcJrpcMethods.SOLANA_SIGN_TX -> {
|
||||
val tx = moshi.adapter<SolanaTransactionRequest>(SolanaTransactionRequest::class.java)
|
||||
.fromJsonOrNull(params)
|
||||
?: return customRequest
|
||||
|
||||
WcRequest.SolanaSignRequest(data = tx)
|
||||
}
|
||||
WcJrpcMethods.SOLANA_SIGN_MESSAGE -> {
|
||||
val signMessage = moshi.adapter<SolanaSignMessage>(SolanaSignMessage::class.java)
|
||||
.fromJsonOrNull(params)
|
||||
?: return customRequest
|
||||
val data = WcSignMessage(
|
||||
raw = listOf(signMessage.publicKey, signMessage.message),
|
||||
type = WcSignMessage.WCSignType.SOLANA_MESSAGE,
|
||||
)
|
||||
|
||||
WcRequest.EthSign(data = data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,4 +30,21 @@ sealed class WcPreparedRequest(
|
|||
requestId: Long,
|
||||
derivationPath: String?,
|
||||
) : WcPreparedRequest(preparedRequestData, topic, requestId, derivationPath)
|
||||
|
||||
class SignTransaction(
|
||||
override val preparedRequestData: WcGenericTransactionData,
|
||||
topic: String,
|
||||
requestId: Long,
|
||||
derivationPath: String?,
|
||||
) : WcPreparedRequest(preparedRequestData, topic, requestId, derivationPath)
|
||||
}
|
||||
|
||||
data class WcGenericTransactionData(
|
||||
val hashToSign: ByteArray,
|
||||
val dAppName: String,
|
||||
val type: TransactionType,
|
||||
)
|
||||
|
||||
enum class TransactionType {
|
||||
SOLANA_TX,
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
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.WalletConnectEvents
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WcEthTransactionType
|
||||
|
||||
class WcSessionRequestConverter(
|
||||
internal class WcSessionRequestConverter(
|
||||
private val blockchainHelper: WcBlockchainHelper,
|
||||
private val sessionsRepository: WalletConnectSessionsRepository,
|
||||
private val sdkHelper: WalletConnectSdkHelper,
|
||||
|
|
@ -107,6 +108,20 @@ class WcSessionRequestConverter(
|
|||
derivationPath = derivationPath,
|
||||
)
|
||||
}
|
||||
is WcRequest.SolanaSignRequest -> {
|
||||
val data = request.data.mapToTransaction()
|
||||
|
||||
WcPreparedRequest.SignTransaction(
|
||||
preparedRequestData = WcGenericTransactionData(
|
||||
hashToSign = data.getSerializedMessage(),
|
||||
dAppName = sessionRequest.metaName,
|
||||
type = TransactionType.SOLANA_TX,
|
||||
),
|
||||
topic = sessionRequest.topic,
|
||||
requestId = sessionRequest.id,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +133,7 @@ class WcSessionRequestConverter(
|
|||
is WcRequest.EthSendTransaction -> request.data.from
|
||||
is WcRequest.EthSignTransaction -> request.data.from
|
||||
is WcRequest.EthSign -> request.data.address
|
||||
is WcRequest.SolanaSignRequest -> request.data.feePayer
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain.mapper
|
||||
|
||||
import com.tangem.blockchain.blockchains.solana.solanaj.core.SolanaTransaction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.solana.SolanaTransactionRequest
|
||||
import org.p2p.solanaj.core.AccountMeta
|
||||
import org.p2p.solanaj.core.PublicKey
|
||||
import org.p2p.solanaj.core.TransactionInstruction
|
||||
|
||||
internal fun SolanaTransactionRequest.mapToTransaction(): SolanaTransaction {
|
||||
val from = PublicKey(feePayer)
|
||||
val instructions = instructions.map(SolanaTransactionRequest.Instruction::mapToInstruction)
|
||||
|
||||
return SolanaTransaction(from)
|
||||
.apply {
|
||||
instructions.forEach(::addInstruction)
|
||||
setRecentBlockHash(recentBlockhash)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SolanaTransactionRequest.Instruction.mapToInstruction() = TransactionInstruction(
|
||||
/* programId = */ PublicKey(programId),
|
||||
/* keys = */ keys.map(SolanaTransactionRequest.Key::mapToAccountMeta),
|
||||
/* data = */ data.toByteArray(),
|
||||
)
|
||||
|
||||
private fun SolanaTransactionRequest.Key.mapToAccountMeta() = AccountMeta(
|
||||
/* publicKey = */ PublicKey(publicKey),
|
||||
/* isSigner = */ isSigner,
|
||||
/* isWritable = */ isWritable,
|
||||
)
|
||||
|
|
@ -13,7 +13,7 @@ open class WcBinanceOrder<T>(
|
|||
val msgs: List<T>,
|
||||
) : WcRequestData
|
||||
|
||||
data class WCBinanceTxConfirmParam(
|
||||
data class WcBinanceTxConfirmParam(
|
||||
val ok: Boolean,
|
||||
val errorMsg: String?,
|
||||
) : WcRequestData
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain.models.solana
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class SolanaSignMessage(
|
||||
@Json(name = "pubkey")
|
||||
val publicKey: String,
|
||||
|
||||
@Json(name = "message")
|
||||
val message: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain.models.solana
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcRequestData
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SolanaTransactionRequest(
|
||||
@Json(name = "feePayer")
|
||||
val feePayer: String,
|
||||
|
||||
@Json(name = "recentBlockhash")
|
||||
val recentBlockhash: String,
|
||||
|
||||
@Json(name = "instructions")
|
||||
val instructions: List<Instruction>,
|
||||
) : WcRequestData {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Instruction(
|
||||
@Json(name = "programId")
|
||||
val programId: String,
|
||||
|
||||
@Json(name = "data")
|
||||
val data: List<Byte>,
|
||||
|
||||
@Json(name = "keys")
|
||||
val keys: List<Key>,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Key(
|
||||
@Json(name = "isSigner")
|
||||
val isSigner: Boolean,
|
||||
|
||||
@Json(name = "isWritable")
|
||||
val isWritable: Boolean,
|
||||
|
||||
@Json(name = "pubkey")
|
||||
val publicKey: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.tap.domain.walletconnect2.toggles
|
||||
|
||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||
|
||||
internal class WalletConnectFeatureToggles(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) {
|
||||
|
||||
val isSolanaTxSignEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(name = "WC_SOLANA_TX_SIGN_ENABLED")
|
||||
}
|
||||
|
|
@ -375,6 +375,7 @@ class WalletConnectMiddleware {
|
|||
is WcPreparedRequest.BnbTransaction -> WalletConnectDialog.BnbTransactionDialog(request)
|
||||
is WcPreparedRequest.EthTransaction -> WalletConnectDialog.RequestTransaction(request)
|
||||
is WcPreparedRequest.EthSign -> WalletConnectDialog.PersonalSign(request)
|
||||
is WcPreparedRequest.SignTransaction -> WalletConnectDialog.SignTransactionDialog(request)
|
||||
}
|
||||
store.dispatch(GlobalAction.ShowDialog(dialog))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import com.tangem.blockchain.common.derivation.DerivationStyle
|
|||
import com.tangem.core.navigation.StateDialog
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcEthereumSignMessage
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcSignMessage
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents
|
||||
import com.tangem.tap.features.details.ui.walletconnect.WcSessionForScreen
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData
|
||||
|
|
@ -117,6 +117,10 @@ sealed class WalletConnectDialog : StateDialog {
|
|||
data class BnbTransactionDialog(
|
||||
val data: WcPreparedRequest.BnbTransaction,
|
||||
) : WalletConnectDialog()
|
||||
|
||||
data class SignTransactionDialog(
|
||||
val data: WcPreparedRequest.SignTransaction,
|
||||
) : WalletConnectDialog()
|
||||
}
|
||||
|
||||
data class WcTransactionData(
|
||||
|
|
@ -138,7 +142,7 @@ data class WcPersonalSignData(
|
|||
val topic: String,
|
||||
val id: Long,
|
||||
val dialogData: PersonalSignDialogData,
|
||||
val type: WcEthereumSignMessage.WCSignType,
|
||||
val type: WcSignMessage.WCSignType,
|
||||
)
|
||||
|
||||
sealed class BinanceMessageData(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
internal object SignTransactionDialog {
|
||||
|
||||
fun create(preparedData: WcPreparedRequest.SignTransaction, context: Context): AlertDialog {
|
||||
val message = context.getString(R.string.wallet_connect_alert_sign_message, "")
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(context.getString(R.string.wallet_connect_title))
|
||||
setMessage(message)
|
||||
setPositiveButton(context.getText(R.string.common_sign)) { _, _ ->
|
||||
store.dispatch(WalletConnectAction.PerformRequestedAction(preparedData))
|
||||
}
|
||||
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
|
||||
store.dispatch(WalletConnectAction.RejectRequest(preparedData.topic, preparedData.requestId))
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue