Updated on 2026-08-14
This commit is contained in:
commit
8444c7aaae
13 changed files with 145 additions and 72 deletions
|
|
@ -77,7 +77,7 @@ dependencies {
|
|||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation 'com.tangem:blockchain:develop-22'
|
||||
implementation 'com.tangem:blockchain:develop-24'
|
||||
implementation 'com.tangem:core:develop-36'
|
||||
implementation 'com.tangem:sdk:develop-36'
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.tap.common.redux.global.GlobalState
|
|||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.*
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class DialogManager : StoreSubscriber<GlobalState> {
|
||||
|
|
@ -38,7 +39,18 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
|
||||
when (state.dialog) {
|
||||
is WalletConnectDialog.UnsupportedCard ->
|
||||
dialog = UnsupportedCardDialog.create(context)
|
||||
dialog = SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect,
|
||||
messageRes = R.string.wallet_connect_scanner_error_no_ethereum_wallet,
|
||||
context = context
|
||||
)
|
||||
is WalletConnectDialog.OpeningSessionRejected -> {
|
||||
dialog = SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect,
|
||||
messageRes = R.string.wallet_connect_same_wcuri,
|
||||
context = context
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.ApproveWcSession ->
|
||||
dialog = ApproveWcSessionDialog.create(state.dialog.session, context)
|
||||
is WalletConnectDialog.ClipboardOrScanQr ->
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ class CurrenciesRepository(val context: Application) {
|
|||
|
||||
fun getBlockchains(cardFirmware: FirmwareVersion?): List<Blockchain> {
|
||||
return if (cardFirmware == null || cardFirmware.major < 4) {
|
||||
secp256k1Blochcains
|
||||
secp256k1Blockchains
|
||||
} else {
|
||||
secp256k1Blochcains + ed25519Blockchains
|
||||
secp256k1Blockchains + ed25519Blockchains
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,10 +115,19 @@ class CurrenciesRepository(val context: Application) {
|
|||
fun getFileNameForBlockchains(cardId: String): String =
|
||||
"${FILE_NAME_PREFIX_BLOCKCHAINS}_$cardId"
|
||||
|
||||
private val secp256k1Blochcains = listOf(
|
||||
Blockchain.Bitcoin, Blockchain.BitcoinCash, Blockchain.Binance, Blockchain.Litecoin,
|
||||
Blockchain.XRP, Blockchain.Tezos,
|
||||
Blockchain.Ethereum, Blockchain.RSK)
|
||||
private val secp256k1Blockchains = listOf(
|
||||
Blockchain.Bitcoin,
|
||||
Blockchain.BitcoinCash,
|
||||
Blockchain.Binance,
|
||||
Blockchain.BSC,
|
||||
Blockchain.Litecoin,
|
||||
Blockchain.XRP,
|
||||
Blockchain.Tezos,
|
||||
Blockchain.Ethereum,
|
||||
Blockchain.RSK,
|
||||
Blockchain.Polygon,
|
||||
Blockchain.Dogecoin,
|
||||
)
|
||||
private val ed25519Blockchains = listOf(Blockchain.CardanoShelley, Blockchain.Stellar)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ class WalletConnectManager {
|
|||
|
||||
fun connect(wcUri: String, wallet: WalletForSession) {
|
||||
val session = WCSession.from(wcUri) ?: return
|
||||
if (sessions[session] != null) {
|
||||
store.dispatchOnMain(WalletConnectAction.RefuseOpeningSession)
|
||||
return
|
||||
}
|
||||
val client = WCClient(httpClient = okHttpClient)
|
||||
setListeners(client)
|
||||
val peerId = UUID.randomUUID().toString()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ sealed class WalletConnectAction : Action {
|
|||
val wallet: WalletForSession,
|
||||
) : WalletConnectAction()
|
||||
|
||||
object RefuseOpeningSession : WalletConnectAction()
|
||||
|
||||
data class AcceptOpeningSession(val session: WalletConnectSession) : WalletConnectAction()
|
||||
|
||||
data class ApproveSession(
|
||||
|
|
@ -37,7 +39,7 @@ sealed class WalletConnectAction : Action {
|
|||
data class Success(val session: WalletConnectSession) : WalletConnectAction()
|
||||
}
|
||||
|
||||
object FailureEstablishingSession : WalletConnectAction()
|
||||
data class FailureEstablishingSession(val session: WCSession?) : WalletConnectAction()
|
||||
|
||||
|
||||
data class SetSessionsRestored(val sessions: List<WalletConnectSession>) :
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.details.redux.walletconnect
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.tap.*
|
||||
|
|
@ -14,6 +15,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
|
|||
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
|
||||
import com.tangem.tap.domain.isMultiwalletAllowed
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectManager
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -55,52 +57,12 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
|
||||
is WalletConnectAction.ScanCard -> {
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.scanNote(
|
||||
FirebaseAnalyticsHandler,
|
||||
R.string.wallet_connect_scan_card_message
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val card = result.data.card
|
||||
val factory =
|
||||
store.state.globalState.tapWalletManager.walletManagerFactory
|
||||
handleScanCard(action.wcUri)
|
||||
}
|
||||
|
||||
val walletManager = if (card.isMultiwalletAllowed) {
|
||||
if (currenciesRepository.loadCardCurrencies(card.cardId)?.blockchains?.contains(
|
||||
Blockchain.Ethereum) == true
|
||||
) {
|
||||
factory.makeWalletManagerForApp(result.data.card,
|
||||
Blockchain.Ethereum)
|
||||
} else {
|
||||
factory.makeWalletManagerForApp(result.data.card,
|
||||
Blockchain.Ethereum)?.also {
|
||||
currenciesRepository.saveAddedBlockchain(card.cardId,
|
||||
Blockchain.Ethereum)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (walletManager == null) {
|
||||
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
|
||||
return@withContext
|
||||
};
|
||||
|
||||
val key = walletManager.wallet.publicKey
|
||||
store.dispatchOnMain(WalletConnectAction.OpenSession(
|
||||
wcUri = action.wcUri,
|
||||
wallet = WalletForSession(
|
||||
card.cardId, key.toHexString(),
|
||||
isTestNet = false
|
||||
),
|
||||
))
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession)
|
||||
}
|
||||
}
|
||||
is WalletConnectAction.FailureEstablishingSession -> {
|
||||
if (action.session != null) {
|
||||
walletConnectManager.disconnect(action.session)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +77,12 @@ class WalletConnectMiddleware {
|
|||
)
|
||||
}
|
||||
|
||||
is WalletConnectAction.RefuseOpeningSession -> {
|
||||
store.dispatch(GlobalAction.ShowDialog(
|
||||
WalletConnectDialog.OpeningSessionRejected
|
||||
))
|
||||
}
|
||||
|
||||
is WalletConnectAction.AcceptOpeningSession -> {
|
||||
store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.ApproveWcSession(
|
||||
action.session)))
|
||||
|
|
@ -157,4 +125,69 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleScanCard(wcUri: String) {
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.scanNote(
|
||||
FirebaseAnalyticsHandler,
|
||||
R.string.wallet_connect_scan_card_message
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val card = result.data.card
|
||||
|
||||
if (!card.isMultiwalletAllowed) {
|
||||
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
|
||||
return@withContext
|
||||
}
|
||||
|
||||
val walletManager = getWalletManager(card)
|
||||
if (walletManager == null) {
|
||||
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
|
||||
return@withContext
|
||||
}
|
||||
|
||||
val key = walletManager.wallet.publicKey
|
||||
store.dispatchOnMain(WalletConnectAction.OpenSession(
|
||||
wcUri = wcUri,
|
||||
wallet = WalletForSession(
|
||||
card.cardId, key.toHexString(),
|
||||
isTestNet = false
|
||||
),
|
||||
))
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(
|
||||
null
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWalletManager(card: Card): WalletManager? {
|
||||
val factory = store.state.globalState.tapWalletManager.walletManagerFactory
|
||||
|
||||
return if (store.state.globalState.scanNoteResponse?.card?.cardId == card.cardId) {
|
||||
store.state.walletState.getWalletManager(Blockchain.Ethereum)
|
||||
?: factory.makeWalletManagerForApp(card, Blockchain.Ethereum)
|
||||
?.also { walletManager ->
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchain(walletManager.wallet.blockchain))
|
||||
}
|
||||
} else {
|
||||
if (currenciesRepository.loadCardCurrencies(card.cardId)?.blockchains?.contains(
|
||||
Blockchain.Ethereum) == true
|
||||
) {
|
||||
factory.makeWalletManagerForApp(card, Blockchain.Ethereum)
|
||||
} else {
|
||||
factory.makeWalletManagerForApp(card,
|
||||
Blockchain.Ethereum)
|
||||
?.also {
|
||||
currenciesRepository.saveAddedBlockchain(card.cardId, Blockchain.Ethereum)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,8 +25,9 @@ class WalletConnectReducer {
|
|||
state.copy(sessions = sessions)
|
||||
}
|
||||
is WalletConnectAction.ScanCard -> state.copy(loading = true)
|
||||
is WalletConnectAction.UnsupportedCard -> state.copy(loading = false)
|
||||
|
||||
is WalletConnectAction.UnsupportedCard -> state.copy(loading = false)
|
||||
is WalletConnectAction.RefuseOpeningSession -> state.copy(loading = false)
|
||||
is WalletConnectAction.FailureEstablishingSession -> state.copy(loading = false)
|
||||
|
||||
else -> state
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ data class WalletForSession(
|
|||
sealed class WalletConnectDialog : StateDialog {
|
||||
data class ClipboardOrScanQr(val clipboardUri: String) : WalletConnectDialog()
|
||||
object UnsupportedCard : WalletConnectDialog()
|
||||
object OpeningSessionRejected : WalletConnectDialog()
|
||||
data class ApproveWcSession(val session: WalletConnectSession) : WalletConnectDialog()
|
||||
data class RequestTransaction(val dialogData: TransactionRequestDialogData) :
|
||||
WalletConnectDialog()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ class ApproveWcSessionDialog {
|
|||
session.session
|
||||
))
|
||||
}
|
||||
setNegativeButton(context.getText(R.string.common_reject)) { _, _ -> }
|
||||
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
|
||||
store.dispatch(WalletConnectAction.FailureEstablishingSession(session.session))
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,19 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class UnsupportedCardDialog {
|
||||
class SimpleAlertDialog {
|
||||
companion object {
|
||||
fun create(context: Context): AlertDialog {
|
||||
fun create(
|
||||
titleRes: Int,
|
||||
messageRes: Int,
|
||||
buttonRes: Int = R.string.common_ok,
|
||||
context: Context,
|
||||
): AlertDialog {
|
||||
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(context.getString(R.string.wallet_connect))
|
||||
setMessage(context.getText(R.string.wallet_connect_scanner_error_no_ethereum_wallet))
|
||||
setPositiveButton(context.getText(R.string.common_ok)) { _, _ -> }
|
||||
// setNegativeButton(context.getText(R.string.common_reject)) { _, _ -> }
|
||||
setTitle(context.getString(titleRes))
|
||||
setMessage(context.getText(messageRes))
|
||||
setPositiveButton(context.getText(buttonRes)) { _, _ -> }
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
|
|
@ -14,9 +14,9 @@ import com.tangem.Log
|
|||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.wallet.WalletStatus
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.domain.TapWorkarounds
|
||||
import com.tangem.tap.domain.extensions.signedHashesCount
|
||||
import com.tangem.tap.store
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
|
@ -173,7 +173,9 @@ class AdditionalEmailInfo {
|
|||
fun setCardInfo(card: Card) {
|
||||
cardId = card.cardId
|
||||
cardFirmwareVersion = card.firmwareVersion.version
|
||||
signedHashesCount = card.signedHashesCount().toString()
|
||||
signedHashesCount = card.wallets
|
||||
.filter { it.status == WalletStatus.Loaded }
|
||||
.joinToString(";") { "${it.curve?.curve} - ${it.signedHashes}" }
|
||||
}
|
||||
|
||||
fun setWalletsInfo(walletManagers: List<WalletManager>) {
|
||||
|
|
@ -289,6 +291,7 @@ class SendTransactionFailedEmail(private val error: String) : EmailData {
|
|||
appendKeyValue("OS version", infoHolder.osVersion)
|
||||
appendKeyValue("App version", infoHolder.appVersion)
|
||||
appendKeyValue("Firmware version", infoHolder.cardFirmwareVersion)
|
||||
appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
// appendKeyValue("Transaction HEX", infoHolder.transactionHex)
|
||||
}.toString()
|
||||
}
|
||||
|
|
@ -301,6 +304,7 @@ class FeedbackEmail : EmailData {
|
|||
val builder = StringBuilder()
|
||||
builder.appendKeyValue("Card ID", infoHolder.cardId)
|
||||
builder.appendKeyValue("Firmware version", infoHolder.cardFirmwareVersion)
|
||||
builder.appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
|
||||
infoHolder.walletsInfo.forEach {
|
||||
builder.appendKeyValue("Blockchain", it.blockchain.fullName)
|
||||
|
|
|
|||
|
|
@ -31,14 +31,6 @@
|
|||
android:layout_marginTop="16dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/pb_wallet_connect"
|
||||
android:indeterminate="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_no_sessions_title"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
@ -71,6 +63,13 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/pb_wallet_connect"
|
||||
android:indeterminate="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_open_session"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
|||
|
|
@ -154,4 +154,6 @@ this wallet.
|
|||
<string name="wallet_connect_paste_from_clipboard" translatable="false">Paste from clipboard</string>
|
||||
<string name="wallet_connect_scan_new_code" translatable="false">Scan new code</string>
|
||||
<string name="wallet_connect_scanner_error_no_ethereum_wallet" translatable="false">This card can’t be used to establish WalletConnect session</string>
|
||||
<string name="wallet_connect_could_not_complete" translatable="false">The operation couldn\'t be completed</string>
|
||||
<string name="wallet_connect_same_wcuri" translatable="false">The operation couldn\'t be completed. \n\nYou have already established a WalletConnect session with this parameters.</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue