Updated on 2026-08-14

This commit is contained in:
Tangem 2022-08-31 11:10:38 +04:00
parent d79b1d9457
commit 2621bad76b
20 changed files with 100 additions and 203 deletions

View file

@ -4,7 +4,6 @@ import android.content.Intent
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.view.View
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
@ -26,7 +25,6 @@ import com.tangem.tap.common.shop.GooglePayService
import com.tangem.tap.common.shop.GooglePayService.Companion.LOAD_PAYMENT_DATA_REQUEST_CODE
import com.tangem.tap.common.shop.googlepay.GooglePayUtil.createPaymentsClient
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.shop.redux.ShopAction
import com.tangem.wallet.R
import com.tangem.wallet.databinding.ActivityMainBinding
@ -67,7 +65,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
backupService = BackupService.init(tangemSdk, this)
store.dispatch(GlobalAction.SetResources(getAndroidResources()))
store.dispatch(WalletConnectAction.RestoreSessions)
store.dispatch(
ShopAction.CheckIfGooglePayAvailable(
GooglePayService(createPaymentsClient(this), this)

View file

@ -113,7 +113,6 @@ class DialogManager : StoreSubscriber<GlobalState> {
data = state.dialog.data,
session = state.dialog.session,
sessionId = state.dialog.sessionId,
cardId = state.dialog.cardId,
dAppName = state.dialog.dAppName,
context = context,
)

View file

@ -23,6 +23,7 @@ import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.domain.extensions.makeWalletManagersForApp
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.demo.isDemoCard
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.NetworkConnectivity
import com.tangem.tap.store
@ -88,14 +89,16 @@ class TapWalletManager {
withMainContext {
store.dispatch(WalletAction.ResetState(data.card.cardId))
store.dispatch(WalletConnectAction.ResetState)
store.dispatch(GlobalAction.SaveScanNoteResponse(data))
store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard))
store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed))
store.dispatch(WalletConnectAction.RestoreSessions(data))
store.dispatch(
WalletAction.MultiWallet.ShowWalletBackupWarning(
show = data.card.settings.isBackupAllowed
&& data.card.backupStatus == Card.BackupStatus.NoBackup
)
&& data.card.backupStatus == Card.BackupStatus.NoBackup,
),
)
loadData(data)
}

View file

@ -1,7 +1,9 @@
package com.tangem.tap.domain.walletconnect
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.guard
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.global.GlobalAction
@ -69,7 +71,7 @@ class WalletConnectManager {
remotePeerId = null,
session = session,
client = client,
wallet = WalletForSession(cardId = "")
wallet = WalletForSession(),
)
setupConnectionTimeoutCheck(session)
}
@ -110,8 +112,12 @@ class WalletConnectManager {
}
}
fun restoreSessions() {
fun restoreSessions(scanResponse: ScanResponse) {
val walletPublicKey = scanResponse.card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 }?.publicKey
?: return
val sessions = walletConnectRepository.loadSavedSessions()
// filter sessions for this particular card
.filter { it.wallet.walletPublicKey.contentEquals(walletPublicKey) }
this.sessions = sessions
.map { session ->
WalletConnectActiveData(
@ -126,8 +132,8 @@ class WalletConnectManager {
setListeners(it.client)
it.client.connect(it.session, tangemPeerMeta, it.peerId, it.remotePeerId)
}
}
.map { it.session to it }.toMap().toMutableMap()
}.associateBy { it.session }.toMutableMap()
store.dispatchOnMain(WalletConnectAction.SetSessionsRestored(sessions))
}

View file

@ -92,7 +92,6 @@ class WalletConnectSdkHelper {
)
)
val dialogData = TransactionRequestDialogData(
cardId = session.wallet.cardId,
dAppName = session.peerMeta.name,
dAppUrl = session.peerMeta.url,
amount = value.toFormattedString(decimals),
@ -235,7 +234,6 @@ class WalletConnectSdkHelper {
val dialogData = PersonalSignDialogData(
cardId = session.wallet.cardId,
dAppName = session.peerMeta.name,
message = messageString,
session = session.session,
@ -272,11 +270,11 @@ class WalletConnectSdkHelper {
suspend fun signPersonalMessage(hashToSign: ByteArray, wallet: WalletForSession): String? {
val key = wallet.derivedPublicKey ?: wallet.walletPublicKey
val command = SignHashCommand(hashToSign, wallet.walletPublicKey!!, wallet.derivationPath)
return when (val result = tangemSdkManager.runTaskAsync(command, wallet.cardId)) {
return when (val result = tangemSdkManager.runTaskAsync(command)) {
is CompletionResult.Success -> {
val hash = result.data.signature
return EthereumUtils.prepareSignedMessageData(
hash, hashToSign, CryptoUtils.decompressPublicKey(key!!)
hash, hashToSign, CryptoUtils.decompressPublicKey(key!!),
)
}
is CompletionResult.Failure -> {

View file

@ -1,13 +1,10 @@
package com.tangem.tap.domain.walletconnect
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.card.EllipticCurve
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.tap.domain.extensions.getPrimaryCurve
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.tokens.CurrenciesRepository
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
@ -17,51 +14,25 @@ import com.tangem.tap.features.wallet.redux.WalletState
class WcWalletManagerFactory(
private val factory: WalletManagerFactory,
private val currenciesRepository: CurrenciesRepository,
) {
suspend fun getWalletManager(
wallet: WalletForSession, blockchain: Blockchain, walletState: WalletState
) {
fun getWalletManager(
wallet: WalletForSession, blockchain: Blockchain, walletState: WalletState,
): WalletManager? {
val blockchainToMake = if (blockchain == Blockchain.Ethereum && wallet.isTestNet) {
Blockchain.EthereumTestnet
} else {
blockchain
}
val blockchainNetwork = BlockchainNetwork(
blockchain = blockchainToMake,
derivationPath = wallet.derivationPath?.rawPath,
tokens = emptyList()
tokens = emptyList(),
)
return if (walletState.cardId == wallet.cardId) {
walletState.getWalletManager(blockchainNetwork)
} else {
val blockchainNetworkWithTokens = currenciesRepository
.loadSavedCurrencies(
cardId = wallet.cardId,
isHdWalletSupported = wallet.derivationPath != null
).firstOrNull { it == blockchainNetwork }
if (blockchainNetworkWithTokens != null) {
factory.makeWalletManager(
blockchain = blockchainToMake,
publicKey = Wallet.PublicKey(
wallet.walletPublicKey!!,
wallet.derivedPublicKey,
wallet.derivationPath
),
tokens = blockchainNetworkWithTokens.tokens,
curve = blockchainToMake.getPrimaryCurve() ?: EllipticCurve.Secp256k1
)
} else {
null
}
}
return walletState.getWalletManager(blockchainNetwork)
}
suspend fun getWalletManager(
scanResponse: ScanResponse, blockchain: Blockchain, walletState: WalletState
scanResponse: ScanResponse, blockchain: Blockchain, walletState: WalletState,
): WalletManager? {
val card = scanResponse.card
val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) {
@ -69,14 +40,13 @@ class WcWalletManagerFactory(
} else {
blockchain
}
val blockchainNetwork = BlockchainNetwork(
blockchain = blockchainToMake,
card = card
card = card,
)
return if (walletState.cardId == card.cardId) {
walletState.getWalletManager(blockchainNetwork)
walletState.getWalletManager(blockchainNetwork)
} else {
if (currenciesRepository
.loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed)
@ -84,7 +54,7 @@ class WcWalletManagerFactory(
) {
factory.makeWalletManagerForApp(
scanResponse = scanResponse,
blockchainNetwork = blockchainNetwork
blockchainNetwork = blockchainNetwork,
)
} else {
null

View file

@ -1,6 +1,7 @@
package com.tangem.tap.features.details.redux.walletconnect
import com.tangem.blockchain.common.Blockchain
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.wallet.R
import com.trustwallet.walletconnect.models.binance.WCBinanceTradeOrder
@ -11,11 +12,9 @@ import com.trustwallet.walletconnect.models.session.WCSession
import org.rekotlin.Action
sealed class WalletConnectAction : Action {
object ResetState : WalletConnectAction()
data class HandleDeepLink(val wcUri: String?) : WalletConnectAction()
object RestoreSessions : WalletConnectAction()
data class RestoreSessions(val scanResponse: ScanResponse) : WalletConnectAction()
data class StartWalletConnect(
val copiedUri: String?,
) : WalletConnectAction()

View file

@ -22,14 +22,13 @@ import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.Middleware
import timber.log.Timber
class WalletConnectMiddleware {
private val walletConnectManager = WalletConnectManager()
private var walletConnectManager = WalletConnectManager()
val walletConnectMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
@ -43,8 +42,9 @@ class WalletConnectMiddleware {
if (DemoHelper.tryHandle(state, action)) return
when (action) {
is WalletConnectAction.ResetState -> walletConnectManager = WalletConnectManager()
is WalletConnectAction.RestoreSessions -> {
walletConnectManager.restoreSessions()
walletConnectManager.restoreSessions(action.scanResponse)
}
is WalletConnectAction.HandleDeepLink -> {
if (!action.wcUri.isNullOrBlank()) {
@ -74,7 +74,13 @@ class WalletConnectMiddleware {
is WalletConnectAction.ChooseNetwork -> {
val data = state()?.walletConnectState?.newSessionData ?: return
scope.launch {
prepareWalletManager(data.scanResponse, store.state.walletState, action.blockchain, data.session)
prepareWalletManager(
scanResponse = data.scanResponse,
walletState = store.state.walletState,
blockchain = action.blockchain,
session = data.session,
walletConnectManager = walletConnectManager,
)
}
}
is WalletConnectAction.ShowClipboardOrScanQrDialog -> {
@ -110,7 +116,8 @@ class WalletConnectMiddleware {
)
}
is WalletConnectAction.ScanCard -> {
scanCard(action.session, action.chainId)
val scanResponse = store.state.globalState.scanResponse ?: return
scanCard(scanResponse, action.session, action.chainId)
}
is WalletConnectAction.ApproveSession -> {
walletConnectManager.approve(action.session)
@ -150,7 +157,6 @@ class WalletConnectMiddleware {
data = messageData,
session = action.sessionData.session,
sessionId = action.id,
cardId = action.sessionData.wallet.cardId,
dAppName = action.sessionData.peerMeta.name,
),
),
@ -164,7 +170,6 @@ class WalletConnectMiddleware {
data = messageData,
session = action.sessionData.session,
sessionId = action.id,
cardId = action.sessionData.wallet.cardId,
dAppName = action.sessionData.peerMeta.name,
),
),
@ -189,28 +194,26 @@ class WalletConnectMiddleware {
currenciesRepository = currenciesRepository,
)
val walletState = store.state.walletState
scope.launch {
val walletManager = factory.getWalletManager(
wallet = action.session.wallet,
blockchain = blockchain,
walletState = walletState,
).guard {
store.dispatchOnMain(
GlobalAction.ShowDialog(
WalletConnectDialog.AddNetwork(blockchain.fullName),
),
)
return@launch
}
val updatedWallet = action.session.wallet.copy(
walletPublicKey = walletManager.wallet.publicKey.seedKey,
derivedPublicKey = walletManager.wallet.publicKey.derivedKey,
derivationPath = walletManager.wallet.publicKey.derivationPath,
blockchain = action.blockchain,
val walletManager = factory.getWalletManager(
wallet = action.session.wallet,
blockchain = blockchain,
walletState = walletState,
).guard {
store.dispatchOnMain(
GlobalAction.ShowDialog(
WalletConnectDialog.AddNetwork(blockchain.fullName),
),
)
val updatedSession = action.session.copy(wallet = updatedWallet)
store.dispatchOnMain(WalletConnectAction.UpdateBlockchain(updatedSession))
return
}
val updatedWallet = action.session.wallet.copy(
walletPublicKey = walletManager.wallet.publicKey.seedKey,
derivedPublicKey = walletManager.wallet.publicKey.derivedKey,
derivationPath = walletManager.wallet.publicKey.derivationPath,
blockchain = action.blockchain,
)
val updatedSession = action.session.copy(wallet = updatedWallet)
store.dispatchOnMain(WalletConnectAction.UpdateBlockchain(updatedSession))
}
is WalletConnectAction.UpdateBlockchain -> {
walletConnectManager.updateBlockchain(action.updatedSession)
@ -218,24 +221,13 @@ class WalletConnectMiddleware {
}
}
private fun scanCard(session: WalletConnectSession, chainId: Int?) {
private fun scanCard(scanResponse: ScanResponse, session: WalletConnectSession, chainId: Int?) {
val blockchain = WalletConnectNetworkUtils.parseBlockchain(
chainId = chainId,
peer = session.peerMeta,
) ?: Blockchain.Ethereum
store.dispatch(
GlobalAction.ScanCard(
additionalBlockchainsToDerive = listOf(blockchain),
onSuccess = { scanResponse ->
handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain)
},
onFailure = {
store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(null))
},
R.string.wallet_connect_scan_card_message,
),
)
handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain)
}
private suspend fun getAvailableBlockchains(card: Card, walletState: WalletState): List<Blockchain> {
@ -259,6 +251,7 @@ class WalletConnectMiddleware {
walletState: WalletState,
blockchain: Blockchain,
session: WalletConnectSession,
walletConnectManager: WalletConnectManager,
) {
val factory = WcWalletManagerFactory(
factory = store.state.globalState.tapWalletManager.walletManagerFactory,
@ -273,21 +266,20 @@ class WalletConnectMiddleware {
)
return
}
val wallet = walletManager.wallet
val derivedKey =
if (wallet.publicKey.blockchainKey.contentEquals(wallet.publicKey.seedKey)) {
null
} else {
walletManager.wallet.publicKey.blockchainKey
}
val walletForSession = WalletForSession(
cardId = scanResponse.card.cardId,
walletPublicKey = wallet.publicKey.seedKey,
derivedPublicKey = derivedKey,
derivationPath = wallet.publicKey.derivationPath,
derivationStyle = scanResponse.card.derivationStyle,
blockchain = wallet.blockchain,
)
val wallet = walletManager.wallet
val derivedKey =
if (wallet.publicKey.blockchainKey.contentEquals(wallet.publicKey.seedKey)) {
null
} else {
walletManager.wallet.publicKey.blockchainKey
}
val walletForSession = WalletForSession(
walletPublicKey = wallet.publicKey.seedKey,
derivedPublicKey = derivedKey,
derivationPath = wallet.publicKey.derivationPath,
derivationStyle = scanResponse.card.derivationStyle,
blockchain = wallet.blockchain,
)
withMainContext {
val updatedSession = session.copy(wallet = walletForSession)

View file

@ -10,6 +10,7 @@ class WalletConnectReducer {
if (action !is WalletConnectAction) return state
return when (action) {
is WalletConnectAction.ResetState -> return WalletConnectState()
is WalletConnectAction.ApproveSession.Success -> {
state.copy(
loading = false,

View file

@ -40,7 +40,6 @@ data class WalletConnectSession(
@JsonClass(generateAdapter = true)
data class WalletForSession(
val cardId: String,
val walletPublicKey: ByteArray? = null,
val derivedPublicKey: ByteArray? = null,
val derivationPath: DerivationPath? = null,
@ -59,7 +58,6 @@ data class WalletForSession(
other as WalletForSession
if (cardId != other.cardId) return false
if (walletPublicKey != null) {
if (other.walletPublicKey == null) return false
if (!walletPublicKey.contentEquals(other.walletPublicKey)) return false
@ -76,8 +74,7 @@ data class WalletForSession(
}
override fun hashCode(): Int {
var result = cardId.hashCode()
result = 31 * result + (walletPublicKey?.contentHashCode() ?: 0)
var result = (walletPublicKey?.contentHashCode() ?: 0)
result = 31 * result + (derivedPublicKey?.contentHashCode() ?: 0)
result = 31 * result + (derivationPath?.hashCode() ?: 0)
result = 31 * result + isTestNet.hashCode()
@ -112,7 +109,6 @@ sealed class WalletConnectDialog : StateDialog {
val data: BinanceMessageData,
val session: WCSession,
val sessionId: Long,
val cardId: String,
val dAppName: String,
) : WalletConnectDialog()
}

View file

@ -1,55 +0,0 @@
package com.tangem.tap.features.details.ui.walletconnect
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
import com.tangem.tap.store
import com.tangem.wallet.R
class WalletConnectSessionsAdapter
: ListAdapter<WalletConnectSession, WalletConnectSessionsAdapter.SessionsViewHolder>(
DiffUtilCallback
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SessionsViewHolder {
val layout = LayoutInflater.from(parent.context)
.inflate(R.layout.item_wallet_connect_session, parent, false)
return SessionsViewHolder(layout)
}
override fun onBindViewHolder(holder: SessionsViewHolder, position: Int) {
holder.bind(currentList[position])
}
object DiffUtilCallback : DiffUtil.ItemCallback<WalletConnectSession>() {
override fun areContentsTheSame(
oldItem: WalletConnectSession, newItem: WalletConnectSession,
) = oldItem == newItem
override fun areItemsTheSame(
oldItem: WalletConnectSession, newItem: WalletConnectSession,
) = oldItem == newItem
}
class SessionsViewHolder(val view: View) :
RecyclerView.ViewHolder(view) {
fun bind(session: WalletConnectSession) {
view.findViewById<TextView>(R.id.tv_card_id).text = view.context.getString(
R.string.wallet_connect_card_number, session.wallet.cardId
)
view.findViewById<TextView>(R.id.tv_d_app_name).text = session.peerMeta.name
view.findViewById<Chip>(R.id.btn_disconnect).setOnClickListener {
store.dispatch(WalletConnectAction.DisconnectSession(session.session))
}
}
}
}

View file

@ -169,7 +169,6 @@ fun WalletConnectScreenPreview() {
sessions = listOf(
WcSessionForScreen(
description = "session from some dApp",
cardId = "12312312321",
sessionId = "",
),
),

View file

@ -11,14 +11,12 @@ data class WalletConnectScreenState(
data class WcSessionForScreen(
val description: String,
val cardId: String,
val sessionId: String,
) {
companion object {
fun fromSession(session: WalletConnectSession): WcSessionForScreen {
return WcSessionForScreen(
description = session.peerMeta.name,
cardId = session.wallet.cardId,
sessionId = session.session.toUri(),
)
}

View file

@ -14,7 +14,6 @@ class ApproveWcSessionDialog {
fun create(session: WalletConnectSession, networks: List<Blockchain>, context: Context): AlertDialog {
val message = context.getString(
R.string.wallet_connect_request_session_start,
session.wallet.cardId,
session.peerMeta.name,
session.peerMeta.url,
)

View file

@ -15,7 +15,6 @@ class BnbTransactionDialog {
data: BinanceMessageData,
session: WCSession,
sessionId: Long,
cardId: String,
dAppName: String,
context: Context,
): AlertDialog {
@ -40,7 +39,7 @@ class BnbTransactionDialog {
val fullMessage = context.getString(
R.string.wallet_connect_bnb_sign_message,
dAppName, cardId, message
dAppName, message,
)
val positiveButtonTitle = context.getText(R.string.common_sign)

View file

@ -15,10 +15,12 @@ class PersonalSignDialog {
context: Context,
): AlertDialog {
val message =
context.getString(R.string.wallet_connect_alert_sign_message, data.cardId) +
context.getString(R.string.wallet_connect_personal_sign_message,
data.dAppName,
data.message)
context.getString(R.string.wallet_connect_alert_sign_message) +
context.getString(
R.string.wallet_connect_personal_sign_message,
data.dAppName,
data.message,
)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect))
setMessage(message)
@ -37,7 +39,6 @@ class PersonalSignDialog {
}
data class PersonalSignDialogData(
val cardId: String,
val dAppName: String,
val message: String,
val session: WCSession,

View file

@ -17,7 +17,6 @@ class TransactionDialog {
): AlertDialog {
val message = context.getString(
R.string.wallet_connect_create_tx_message,
data.cardId,
data.dAppName,
data.dAppUrl,
data.amount,
@ -53,7 +52,6 @@ class TransactionDialog {
}
data class TransactionRequestDialogData(
val cardId: String,
val dAppName: String,
val dAppUrl: String,
val amount: String,

View file

@ -45,7 +45,6 @@ data class ButtonData(
interface DialogMessageData
data class WcTransactionDialogMessageData(
val cardId: String,
val dAppName: String,
val dAppUrl: String,
val amount: String,

View file

@ -328,8 +328,8 @@
<string name="token_symbol_address_format">%1s (%2s)</string>
<string name="alert_signed_hashes_message">Эта карта не является векселем на предъявителя. В настоящее время мы не можем сопоставить количество подписей на карте с информацией в блокчейне. Это нормально, но в редких случаях может означать, что предыдущий владелец скрывает автономную подпись, что является проблемой безопасности.\n\nНе принимайте эту карту в качестве физического платежа от кого-то, кому Вы не доверяете.\n\nВо всех остальных отношениях - это совершенно безопасно.\n\nTangem — единственный аппаратный кошелек, предлагающий защиту от подсчета подписей.</string>
<string name="wallet_connect">WalletConnect</string>
<string name="wallet_connect_create_tx_message">Карта %1s\nЗапрос на создание транзакции для %2s\n%3s\n\nСумма: %4s\nКомиссия: %5s\nВсего: %6s\nБаланс: %7s</string>
<string name="wallet_connect_request_session_start">Запрос на запуск сеанса для карты с идентификатором %1s\nдля %2s\n\nURL: %3s</string>
<string name="wallet_connect_create_tx_message">Запрос на создание транзакции для %1s\n%2s\n\nСумма: %3s\nКомиссия: %4s\nВсего: %5s\nБаланс: %6s</string>
<string name="wallet_connect_request_session_start">Запрос на запуск сеанса для %1s\n\nURL: %2s</string>
<string name="wallet_connect_sessions_title">Сессии WalletConnect</string>
<string name="wallet_connect_session_opened">Сеанс WalletConnect открыт с %s</string>
<string name="wallet_connect_no_sessions_title">Упс. Нет сессий.</string>
@ -338,7 +338,7 @@
<string name="wallet_connect_card_number">Карта: %s</string>
<string name="wallet_connect_scan_card_message">Коснитесь карты, чтобы привязать ее WalletConnect</string>
<string name="wallet_connect_create_tx_not_enough_funds">Не удается отправить транзакцию. Недостаточно средств.</string>
<string name="wallet_connect_alert_sign_message">Просьба подписать сообщение\nкартой %s\n\n</string>
<string name="wallet_connect_alert_sign_message">Просьба подписать сообщение\n</string>
<string name="wallet_connect_personal_sign_message">Сообщение для %s:\n%s</string>
<string name="wallet_connect_clipboard_alert">Буфер обмена содержит код WalletConnect. Использовать скопированное значение или отсканировать QR-код</string>
<string name="wallet_connect_paste_from_clipboard">Вставить из буфера обмена</string>
@ -348,7 +348,7 @@
<string name="wallet_connect_same_wcuri">Операция не может быть завершена. \n\nВы уже установили сеанс WalletConnect с этими параметрами.</string>
<string name="wallet_connect_error_timeout">Не удалось установить сеанс WalletConnect: ошибка времени выполнения. Пожалуйста, повторите попытку позже.</string>
<string name="wallet_connect_bnb_transaction_signed">Транзакция BNB успешно подписана и отправлена в DApp</string>
<string name="wallet_connect_bnb_sign_message">DApp %s, запрашивает\nподпись транзакции BNB с\nкартой: %s\n\n%s</string>
<string name="wallet_connect_bnb_sign_message">DApp %s, запрашивает\nподпись транзакции BNB с\n%s</string>
<string name="wallet_connect_bnb_transaction_message">Сведения о транзакции:\nОт: %s\nКому: %s\nСумма: %s</string>
<string name="wallet_connect_bnb_trade_order_message">Торговый ордер на %s\nЦена: %s\nСумма к получению: %s\nСумма к оплате: %s</string>
<string name="feedback_subject_rate_negative">Мои предложения</string>

View file

@ -140,24 +140,23 @@
<string name="wallet_connect_card_number" translatable="false">Card: %s</string>
<string name="wallet_connect_scan_card_message" translatable="false">Tap card to bind to wallet connect</string>
<string name="wallet_connect_create_tx_message" translatable="false">Card: %1s\n
Request to create transaction for %2s
\n%3s
<string name="wallet_connect_create_tx_message" translatable="false">
Request to create transaction for %1s
\n%2s
\n\nAmount: %4s
\nFee: %5s
\nTotal: %6s
\nBalance: %7s</string>
\n\nAmount: %3s
\nFee: %4s
\nTotal: %5s
\nBalance: %6s</string>
<string name="wallet_connect_create_tx_not_enough_funds" translatable="false">Can\'t send transaction. Not enough funds.</string>
<string name="wallet_connect_request_session_start" translatable="false">Request to start a session for card with ID %1s\n
for %2s\n\n
<string name="wallet_connect_request_session_start" translatable="false">Request to start a session for %1s\n\n
URL: %3s</string>
URL: %2s</string>
<string name="wallet_connect_alert_sign_message" translatable="false">Requesting to sign a message\nwith card %s\n\n</string>
<string name="wallet_connect_alert_sign_message" translatable="false">Requesting to sign a message\n</string>
<string name="wallet_connect_personal_sign_message" translatable="false">Message for %s:\n%s</string>
@ -305,8 +304,7 @@
<string name="wallet_connect_bnb_transaction_signed" translatable="false">The BNB transaction has been successfully signed and sent to the Dapp</string>
<string name="wallet_connect_bnb_sign_message" translatable="false">Dapp %s, requesting to\n
sign BNB transaction with\n
Card: %s\n
sign BNB transaction
\n
%s</string>
<string name="wallet_connect_bnb_transaction_message" translatable="false">Transaction details:\n