Updated on 2026-08-14
This commit is contained in:
commit
e2d1147b5c
45 changed files with 600 additions and 232 deletions
|
|
@ -5,6 +5,8 @@ import android.content.pm.ActivityInfo
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.TangemSdk
|
||||
|
|
@ -27,11 +29,11 @@ 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
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
lateinit var tangemSdk: TangemSdk
|
||||
lateinit var tangemSdkManager: TangemSdkManager
|
||||
|
|
@ -83,8 +85,10 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
}
|
||||
|
||||
private fun systemActions() {
|
||||
// makes the status bar text dark
|
||||
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
WindowInsetsControllerCompat(window, binding.root)
|
||||
.isAppearanceLightStatusBars = true
|
||||
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
dAppName = state.dialog.dAppName,
|
||||
context = context
|
||||
)
|
||||
is WalletConnectDialog.UnsupportedNetwork ->
|
||||
SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect,
|
||||
messageRes = R.string.wallet_connect_scanner_error_unsupported_network,
|
||||
context = context
|
||||
)
|
||||
is BackupDialog.AddMoreBackupCards -> AddMoreBackupCardsDialog.create(context)
|
||||
is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context)
|
||||
is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,11 @@ fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) {
|
|||
}
|
||||
|
||||
fun FragmentActivity.getPreviousScreen(): AppScreen? {
|
||||
val indexOfLastFragment = this.supportFragmentManager.backStackEntryCount - 1
|
||||
val indexOfLastFragment = if (this.supportFragmentManager.backStackEntryCount > 0) {
|
||||
this.supportFragmentManager.backStackEntryCount - 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
val tag = if (indexOfLastFragment < this.supportFragmentManager.backStackEntryCount)
|
||||
this.supportFragmentManager.getBackStackEntryAt(indexOfLastFragment).name
|
||||
else null
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.tap.common.TestActions
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
import com.tangem.tap.features.demo.isDemoWallet
|
||||
import com.tangem.tap.features.demo.isDemoCard
|
||||
import com.tangem.tap.features.wallet.redux.AddressData
|
||||
import com.tangem.tap.features.wallet.redux.reducers.createAddressesData
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
|
|
@ -21,7 +21,10 @@ import timber.log.Timber
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
suspend fun WalletManager.safeUpdate(): Result<Wallet> = try {
|
||||
if (isDemoWallet() || TestActions.testAmountInjectionForWalletManagerEnabled) {
|
||||
val scanResponse = store.state.globalState.scanResponse
|
||||
?: error("Scan response must not be null")
|
||||
|
||||
if (scanResponse.isDemoCard() || TestActions.testAmountInjectionForWalletManagerEnabled) {
|
||||
delay(500)
|
||||
TestActions.testAmountInjectionForWalletManagerEnabled = false
|
||||
Result.Success(wallet)
|
||||
|
|
|
|||
|
|
@ -5,44 +5,25 @@ import com.tangem.TangemSdk
|
|||
import com.tangem.blockchain.common.TransactionSigner
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.domain.tasks.SignHashTask
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.tap.domain.tasks.SignHashesTask
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class TangemSigner(
|
||||
private val card: Card,
|
||||
private val tangemSdk: TangemSdk,
|
||||
private val initialMessage: Message,
|
||||
private val signerCallback: (TangemSignerResponse) -> Unit,
|
||||
) : TransactionSigner {
|
||||
|
||||
override suspend fun sign(hash: ByteArray, cardId: String, publicKey: Wallet.PublicKey): CompletionResult<ByteArray> {
|
||||
override suspend fun sign(
|
||||
hashes: List<ByteArray>,
|
||||
publicKey: Wallet.PublicKey
|
||||
): CompletionResult<List<ByteArray>> {
|
||||
return suspendCoroutine { continuation ->
|
||||
val command = SignHashTask(hash, publicKey)
|
||||
tangemSdk.startSessionWithRunnable(
|
||||
runnable = command,
|
||||
cardId = cardId,
|
||||
initialMessage = initialMessage,
|
||||
) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
signerCallback(
|
||||
TangemSignerResponse(
|
||||
result.data.totalSignedHashes,
|
||||
result.data.remainingSignatures
|
||||
)
|
||||
)
|
||||
continuation.resume(CompletionResult.Success(result.data.signature))
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
continuation.resume(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val cardId = if (card.backupStatus?.isActive == true) null else card.cardId
|
||||
|
||||
override suspend fun sign(hashes: List<ByteArray>, cardId: String, publicKey: Wallet.PublicKey): CompletionResult<List<ByteArray>> {
|
||||
return suspendCoroutine { continuation ->
|
||||
val task = SignHashesTask(hashes, publicKey)
|
||||
tangemSdk.startSessionWithRunnable(
|
||||
runnable = task,
|
||||
|
|
@ -65,6 +46,21 @@ class TangemSigner(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sign(
|
||||
hash: ByteArray,
|
||||
publicKey: Wallet.PublicKey
|
||||
): CompletionResult<ByteArray> {
|
||||
val result = sign(
|
||||
hashes = listOf(hash),
|
||||
publicKey = publicKey
|
||||
)
|
||||
|
||||
return when (result) {
|
||||
is CompletionResult.Success -> CompletionResult.Success(result.data.first())
|
||||
is CompletionResult.Failure -> CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class TangemSignerResponse(
|
||||
|
|
|
|||
|
|
@ -32,9 +32,10 @@ fun WalletManagerFactory.makeWalletManagerForApp(
|
|||
return when {
|
||||
scanResponse.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> {
|
||||
makeTwinWalletManager(
|
||||
card.cardId,
|
||||
wallet.publicKey, scanResponse.secondTwinPublicKey!!.hexToBytes(),
|
||||
environmentBlockchain, wallet.curve
|
||||
walletPublicKey = wallet.publicKey,
|
||||
pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(),
|
||||
blockchain = environmentBlockchain,
|
||||
curve = wallet.curve
|
||||
)
|
||||
}
|
||||
seedKey != null && derivationParams != null -> {
|
||||
|
|
@ -47,7 +48,6 @@ fun WalletManagerFactory.makeWalletManagerForApp(
|
|||
?: return null
|
||||
|
||||
makeWalletManager(
|
||||
cardId = card.cardId,
|
||||
blockchain = environmentBlockchain,
|
||||
seedKey = wallet.publicKey,
|
||||
derivedKey = derivedKey,
|
||||
|
|
@ -56,7 +56,6 @@ fun WalletManagerFactory.makeWalletManagerForApp(
|
|||
}
|
||||
else -> {
|
||||
makeWalletManager(
|
||||
cardId = card.cardId,
|
||||
blockchain = environmentBlockchain,
|
||||
walletPublicKey = wallet.publicKey,
|
||||
curve = wallet.curve
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ class WalletStateConverter : StringStateConverter<AppState> {
|
|||
walletMap["publicKey"] = publicKeyMap
|
||||
walletMap["amounts"] = amounts
|
||||
walletMap["addresses"] = wallet.addresses.toString()
|
||||
walletMap["cardId"] = wallet.cardId
|
||||
|
||||
return walletMap
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,17 @@ import android.content.res.Resources
|
|||
import android.net.Uri
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import com.tangem.common.card.Card
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class CardTou {
|
||||
private val locale: Locale = ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)
|
||||
private val locale: Locale =
|
||||
ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)!!
|
||||
|
||||
fun getUrl(card: Card): Uri? {
|
||||
val issuerName = card.issuer.name ?: return null
|
||||
val issuerName = card.issuer.name
|
||||
if (issuerName.lowercase(Locale.getDefault()) != "start2coin") return null
|
||||
|
||||
val baseUrl = "https://app.tangem.com/tou/"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package com.tangem.tap.domain.walletconnect
|
||||
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.github.salomonbrys.kotson.toMap
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.trustwallet.walletconnect.JSONRPC_VERSION
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
|
||||
|
||||
|
|
@ -18,9 +20,11 @@ class EthSignHelper {
|
|||
.create()
|
||||
}
|
||||
|
||||
fun tryToParseEthTypedMessage(data: String): WCEthereumSignMessage? {
|
||||
val request =
|
||||
gson.fromJson<CustomJsonRpcRequests>(data)
|
||||
fun parseCustomRequest(data: String): CustomJsonRpcRequest {
|
||||
return gson.fromJson<CustomJsonRpcRequest>(data)
|
||||
}
|
||||
|
||||
fun tryToParseEthTypedMessage(request: CustomJsonRpcRequest): WCEthereumSignMessage? {
|
||||
return if (request.method == WCMethodExtended.ETH_SIGN_TYPE_DATA_V4) {
|
||||
WCEthereumSignMessage(
|
||||
listOf(
|
||||
|
|
@ -53,12 +57,26 @@ class EthSignHelper {
|
|||
}
|
||||
}
|
||||
|
||||
data class CustomJsonRpcRequests(
|
||||
data class CustomJsonRpcRequest(
|
||||
val id: Long,
|
||||
val jsonrpc: String = JSONRPC_VERSION,
|
||||
val method: WCMethodExtended?,
|
||||
val params: JsonArray
|
||||
)
|
||||
) {
|
||||
|
||||
fun blockchainFromChainId(): Blockchain? {
|
||||
return try {
|
||||
val hex = params[0].asJsonObject.toMap()[CHAIN_ID_KEY]?.asString ?: ""
|
||||
Blockchain.fromChainId(Integer.decode(hex))
|
||||
} catch (exception: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CHAIN_ID_KEY = "chainId"
|
||||
}
|
||||
}
|
||||
|
||||
enum class WCMethodExtended {
|
||||
@SerializedName("wc_sessionRequest")
|
||||
|
|
@ -95,5 +113,10 @@ enum class WCMethodExtended {
|
|||
GET_ACCOUNTS,
|
||||
|
||||
@SerializedName("trust_signTransaction")
|
||||
SIGN_TRANSACTION;
|
||||
SIGN_TRANSACTION,
|
||||
|
||||
@SerializedName("wallet_switchEthereumChain")
|
||||
SWITCH_CHAIN,
|
||||
|
||||
;
|
||||
}
|
||||
|
|
@ -11,14 +11,20 @@ import com.tangem.tap.store
|
|||
import com.tangem.tap.walletConnectRepository
|
||||
import com.trustwallet.walletconnect.WCClient
|
||||
import com.trustwallet.walletconnect.models.WCPeerMeta
|
||||
import com.trustwallet.walletconnect.models.binance.*
|
||||
import com.trustwallet.walletconnect.models.binance.WCBinanceCancelOrder
|
||||
import com.trustwallet.walletconnect.models.binance.WCBinanceTradeOrder
|
||||
import com.trustwallet.walletconnect.models.binance.WCBinanceTransferOrder
|
||||
import com.trustwallet.walletconnect.models.binance.WCBinanceTxConfirmParam
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
|
||||
import com.trustwallet.walletconnect.models.session.WCSession
|
||||
import com.trustwallet.walletconnect.models.session.WCSessionUpdate
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.*
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
|
@ -71,6 +77,22 @@ class WalletConnectManager {
|
|||
}
|
||||
}
|
||||
|
||||
fun updateBlockchain(session: WalletConnectSession) {
|
||||
sessions[session.session]?.client?.updateSession(
|
||||
accounts = listOfNotNull(session.getAddress()),
|
||||
chainId = session.wallet.blockchain?.getChainId(),
|
||||
approved = true
|
||||
)
|
||||
|
||||
|
||||
val updatedSession = sessions[session.session]?.copy(
|
||||
wallet = session.wallet
|
||||
)
|
||||
if (updatedSession != null) {
|
||||
sessions[session.session] = updatedSession
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupConnectionTimeoutCheck(session: WCSession) {
|
||||
scope.launch {
|
||||
delay(20_000)
|
||||
|
|
@ -409,23 +431,43 @@ class WalletConnectManager {
|
|||
Timber.d("Custom Request")
|
||||
Timber.d(data)
|
||||
|
||||
val message = EthSignHelper.tryToParseEthTypedMessage(data)
|
||||
if (message != null) {
|
||||
Timber.d("onEthSign_v4: $message")
|
||||
store.state.globalState.analyticsHandlers?.logWcEvent(
|
||||
Analytics.WcAnalyticsEvent.Action(
|
||||
Analytics.WcAction.PersonalSign
|
||||
val request = EthSignHelper.parseCustomRequest(data)
|
||||
|
||||
when (request.method) {
|
||||
WCMethodExtended.ETH_SIGN_TYPE_DATA_V4 -> handleTypedDataV4(request, client, id)
|
||||
WCMethodExtended.SWITCH_CHAIN -> {
|
||||
val blockchain = request.blockchainFromChainId()
|
||||
Timber.d("WC switch chainID\nNew Blockchain: $blockchain")
|
||||
val session = sessions[client.session]?.toWalletConnectSession()
|
||||
if (session != null) {
|
||||
store.dispatchOnMain(WalletConnectAction.SwitchBlockchain(blockchain, session))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Timber.d("WC: unrecognized custom request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun handleTypedDataV4(request: CustomJsonRpcRequest, client: WCClient, id: Long) {
|
||||
val message = EthSignHelper.tryToParseEthTypedMessage(request)
|
||||
if (message != null) {
|
||||
Timber.d("onEthSign_v4: $message")
|
||||
store.state.globalState.analyticsHandlers?.logWcEvent(
|
||||
Analytics.WcAnalyticsEvent.Action(
|
||||
Analytics.WcAction.PersonalSign
|
||||
)
|
||||
)
|
||||
sessions[client.session]?.toWalletConnectSession()?.let { sessionData ->
|
||||
store.dispatchOnMain(
|
||||
WalletConnectAction.HandlePersonalSignRequest(
|
||||
message,
|
||||
sessionData,
|
||||
id
|
||||
)
|
||||
)
|
||||
sessions[client.session]?.toWalletConnectSession()?.let { sessionData ->
|
||||
store.dispatchOnMain(
|
||||
WalletConnectAction.HandlePersonalSignRequest(
|
||||
message,
|
||||
sessionData,
|
||||
id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,17 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumGasLoader
|
|||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.Companion.toKeccak
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.extensions.*
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.CommonSigner
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
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.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
|
|
@ -17,7 +26,11 @@ import com.tangem.operations.sign.SignHashCommand
|
|||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.features.details.redux.walletconnect.*
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletForSession
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WcPersonalSignData
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WcTransactionData
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WcTransactionType
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionRequestDialogData
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -25,8 +38,8 @@ import com.tangem.tap.tangemSdk
|
|||
import com.tangem.tap.tangemSdkManager
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import timber.log.Timber
|
||||
|
||||
class WalletConnectSdkHelper {
|
||||
|
||||
|
|
@ -108,9 +121,8 @@ class WalletConnectSdkHelper {
|
|||
)
|
||||
val blockchain = session.wallet.getBlockchainForSession()
|
||||
return factory.makeWalletManager(
|
||||
session.wallet.cardId,
|
||||
blockchain,
|
||||
publicKey
|
||||
blockchain = blockchain,
|
||||
publicKey = publicKey
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +136,7 @@ class WalletConnectSdkHelper {
|
|||
private suspend fun sendTransaction(data: WcTransactionData): String? {
|
||||
val result = (data.walletManager as TransactionSender).send(
|
||||
transactionData = data.transaction,
|
||||
signer = Signer(tangemSdk)
|
||||
signer = CommonSigner(tangemSdk)
|
||||
)
|
||||
return when (result) {
|
||||
SimpleResult.Success -> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
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
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletForSession
|
||||
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
|
||||
): WalletManager? {
|
||||
val blockchainToMake = if (blockchain == Blockchain.Ethereum && wallet.isTestNet) {
|
||||
Blockchain.EthereumTestnet
|
||||
} else {
|
||||
blockchain
|
||||
}
|
||||
|
||||
val blockchainNetwork = BlockchainNetwork(
|
||||
blockchain = blockchainToMake,
|
||||
derivationPath = wallet.derivationPath?.rawPath,
|
||||
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(
|
||||
cardId = wallet.cardId,
|
||||
blockchain = blockchainToMake,
|
||||
publicKey = Wallet.PublicKey(
|
||||
wallet.walletPublicKey!!,
|
||||
wallet.derivedPublicKey,
|
||||
wallet.derivationPath
|
||||
),
|
||||
tokens = blockchainNetworkWithTokens.tokens,
|
||||
curve = blockchainToMake.getPrimaryCurve() ?: EllipticCurve.Secp256k1
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getWalletManager(
|
||||
scanResponse: ScanResponse, blockchain: Blockchain, walletState: WalletState
|
||||
): WalletManager? {
|
||||
val card = scanResponse.card
|
||||
val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) {
|
||||
Blockchain.EthereumTestnet
|
||||
} else {
|
||||
blockchain
|
||||
}
|
||||
|
||||
val blockchainNetwork = BlockchainNetwork(
|
||||
blockchain = blockchainToMake,
|
||||
card = card
|
||||
)
|
||||
|
||||
return if (walletState.cardId == card.cardId) {
|
||||
walletState.getWalletManager(blockchainNetwork)
|
||||
} else {
|
||||
if (currenciesRepository
|
||||
.loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed)
|
||||
.contains(blockchainNetwork)
|
||||
) {
|
||||
factory.makeWalletManagerForApp(
|
||||
scanResponse = scanResponse,
|
||||
blockchainNetwork = blockchainNetwork
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ class DemoConfig {
|
|||
testDemoCardIds).distinct()
|
||||
}
|
||||
|
||||
private val releaseDemoCardIds = mutableListOf<String>(
|
||||
private val releaseDemoCardIds = mutableListOf(
|
||||
// Tangem Wallet:
|
||||
"AC01000000041100",
|
||||
"AC01000000042462",
|
||||
|
|
@ -284,7 +284,10 @@ class DemoTransactionSender(
|
|||
|
||||
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
|
||||
val dataToSign = randomString(32).toByteArray()
|
||||
val signerResponse = signer.sign(dataToSign, walletManager.wallet.cardId, walletManager.wallet.publicKey)
|
||||
val signerResponse = signer.sign(
|
||||
hash = dataToSign,
|
||||
publicKey = walletManager.wallet.publicKey
|
||||
)
|
||||
return when (signerResponse) {
|
||||
is CompletionResult.Success -> SimpleResult.Failure(Exception(ID))
|
||||
is CompletionResult.Failure -> SimpleResult.fromTangemSdkError(signerResponse.error)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun ScanResponse.isDemoCard(): Boolean = DemoHelper.isDemoCardId(card.cardId)
|
||||
fun WalletManager.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(wallet.cardId)
|
||||
fun Card.isDemoCard(): Boolean = DemoHelper.isDemoCardId(cardId)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.details.redux.walletconnect
|
||||
|
||||
import android.app.Activity
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.redux.NotificationAction
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -47,6 +48,16 @@ sealed class WalletConnectAction : Action {
|
|||
data class Success(val session: WalletConnectSession) : WalletConnectAction()
|
||||
}
|
||||
|
||||
data class SwitchBlockchain(
|
||||
val blockchain: Blockchain?,
|
||||
val session: WalletConnectSession
|
||||
) : WalletConnectAction()
|
||||
|
||||
data class UpdateBlockchain(
|
||||
val updatedSession: WalletConnectSession
|
||||
) : WalletConnectAction()
|
||||
|
||||
|
||||
data class FailureEstablishingSession(val session: WCSession?) : WalletConnectAction()
|
||||
|
||||
data class SetSessionsRestored(val sessions: List<WalletConnectSession>) :
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package com.tangem.tap.features.details.redux.walletconnect
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.getFromClipboard
|
||||
|
|
@ -14,11 +12,10 @@ import com.tangem.tap.common.redux.navigation.AppScreen
|
|||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.currenciesRepository
|
||||
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
|
||||
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
|
||||
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
|
||||
import com.tangem.tap.domain.walletconnect.BnbHelper
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectManager
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectNetworkUtils
|
||||
import com.tangem.tap.domain.walletconnect.WcWalletManagerFactory
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -159,6 +156,45 @@ class WalletConnectMiddleware {
|
|||
action.id, action.data, action.sessionData
|
||||
)
|
||||
}
|
||||
is WalletConnectAction.SwitchBlockchain -> {
|
||||
val blockchain = action.blockchain.guard {
|
||||
store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork))
|
||||
return
|
||||
}
|
||||
|
||||
val factory = WcWalletManagerFactory(
|
||||
factory = store.state.globalState.tapWalletManager.walletManagerFactory,
|
||||
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 updatedSession = action.session.copy(wallet = updatedWallet)
|
||||
store.dispatchOnMain(WalletConnectAction.UpdateBlockchain(updatedSession))
|
||||
}
|
||||
}
|
||||
is WalletConnectAction.UpdateBlockchain -> {
|
||||
walletConnectManager.updateBlockchain(action.updatedSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,8 +225,13 @@ class WalletConnectMiddleware {
|
|||
return
|
||||
}
|
||||
|
||||
val factory = WcWalletManagerFactory(
|
||||
factory = store.state.globalState.tapWalletManager.walletManagerFactory,
|
||||
currenciesRepository = currenciesRepository
|
||||
)
|
||||
val walletState = store.state.walletState
|
||||
scope.launch {
|
||||
val walletManager = getWalletManager(scanResponse, blockchain).guard {
|
||||
val walletManager = factory.getWalletManager(scanResponse, blockchain, walletState).guard {
|
||||
store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(session.session))
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.ShowDialog(
|
||||
|
|
@ -232,37 +273,4 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
private suspend fun getWalletManager(
|
||||
scanResponse: ScanResponse, blockchain: Blockchain
|
||||
): WalletManager? {
|
||||
val card = scanResponse.card
|
||||
val factory = store.state.globalState.tapWalletManager.walletManagerFactory
|
||||
val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) {
|
||||
Blockchain.EthereumTestnet
|
||||
} else {
|
||||
blockchain
|
||||
}
|
||||
|
||||
val blockchainNetwork = BlockchainNetwork(
|
||||
blockchain = blockchainToMake,
|
||||
card = card
|
||||
)
|
||||
|
||||
return if (store.state.globalState.scanResponse?.card?.cardId == card.cardId) {
|
||||
store.state.walletState.getWalletManager(blockchainNetwork)
|
||||
} else {
|
||||
if (currenciesRepository
|
||||
.loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed)
|
||||
.contains(blockchainNetwork)
|
||||
) {
|
||||
factory.makeWalletManagerForApp(
|
||||
scanResponse = scanResponse,
|
||||
blockchainNetwork = blockchainNetwork
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,11 @@ class WalletConnectReducer {
|
|||
is WalletConnectAction.RefuseOpeningSession -> state.copy(loading = false)
|
||||
is WalletConnectAction.OpeningSessionTimeout -> state.copy(loading = false)
|
||||
is WalletConnectAction.FailureEstablishingSession -> state.copy(loading = false)
|
||||
is WalletConnectAction.UpdateBlockchain -> state.copy(
|
||||
sessions = state.sessions
|
||||
.filterNot { it.peerId == action.updatedSession.peerId }
|
||||
+ action.updatedSession
|
||||
)
|
||||
|
||||
else -> state
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ data class WalletForSession(
|
|||
sealed class WalletConnectDialog : StateDialog {
|
||||
data class ClipboardOrScanQr(val clipboardUri: String) : WalletConnectDialog()
|
||||
object UnsupportedCard : WalletConnectDialog()
|
||||
object UnsupportedNetwork : WalletConnectDialog()
|
||||
data class AddNetwork(val network: String) : WalletConnectDialog()
|
||||
object OpeningSessionRejected : WalletConnectDialog()
|
||||
object SessionTimeout : WalletConnectDialog()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.accompanist.appcompattheme.AppCompatTheme
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
|
|
@ -15,12 +19,12 @@ import com.tangem.tap.features.home.redux.HomeState
|
|||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState> {
|
||||
class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
|
||||
|
||||
var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||
private var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||
private var composeView: ComposeView? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -29,6 +33,13 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
val context = container?.context ?: return null
|
||||
|
||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||
getView()?.findViewById<ComposeView>(R.id.cv_stories)?.setContent {
|
||||
AppCompatTheme {
|
||||
|
|
@ -46,16 +57,16 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
store.dispatch(TokensAction.LoadCurrencies())
|
||||
}
|
||||
)
|
||||
composeView = ComposeView(context).apply {
|
||||
setContent {
|
||||
AppCompatTheme {
|
||||
ScreenContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRegionProvider(): RegionProvider = RegionService(
|
||||
listOf(
|
||||
// TelephonyManagerRegionProvider(requireContext()),
|
||||
LocaleRegionProvider()
|
||||
)
|
||||
)
|
||||
return composeView
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
|
@ -71,6 +82,11 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
rollbackStatusBarIconsColor()
|
||||
composeView = null
|
||||
}
|
||||
|
||||
override fun newState(state: HomeState) {
|
||||
if (activity == null || view == null) return
|
||||
|
|
@ -78,4 +94,32 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
homeState.value = state
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScreenContent() {
|
||||
StoriesScreen(
|
||||
homeState,
|
||||
onScanButtonClick = { store.dispatch(HomeAction.ReadCard) },
|
||||
onShopButtonClick = {
|
||||
store.dispatch(
|
||||
HomeAction.GoToShop(store.state.globalState.userCountryCode)
|
||||
)
|
||||
},
|
||||
onSearchTokensClick = {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
|
||||
store.dispatch(TokensAction.AllowToAddTokens(false))
|
||||
store.dispatch(TokensAction.LoadCurrencies())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* !!! Workaround !!!
|
||||
* Used to roll back the color of icons in the status bar after the stories screen
|
||||
* */
|
||||
private fun rollbackStatusBarIconsColor() {
|
||||
WindowInsetsControllerCompat(
|
||||
activity?.window ?: return,
|
||||
view ?: return,
|
||||
).isAppearanceLightStatusBars = true
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,25 @@ package com.tangem.tap.features.home.compose
|
|||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -25,8 +38,13 @@ import androidx.compose.ui.text.style.TextAlign
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.tap.common.compose.SpacerS24
|
||||
import com.tangem.tap.features.home.compose.content.*
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.tangem.tap.features.home.compose.content.FirstStoriesContent
|
||||
import com.tangem.tap.features.home.compose.content.StoriesCurrencies
|
||||
import com.tangem.tap.features.home.compose.content.StoriesRevolutionaryWallet
|
||||
import com.tangem.tap.features.home.compose.content.StoriesUltraSecureBackup
|
||||
import com.tangem.tap.features.home.compose.content.StoriesWalletForEveryone
|
||||
import com.tangem.tap.features.home.compose.content.StoriesWeb3
|
||||
import com.tangem.tap.features.home.compose.views.HomeButtons
|
||||
import com.tangem.tap.features.home.compose.views.StoriesProgressBar
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
|
|
@ -43,6 +61,7 @@ fun StoriesScreen(
|
|||
) {
|
||||
val steps = 6
|
||||
val currentStep = remember { mutableStateOf(1) }
|
||||
val systemUiController = rememberSystemUiController()
|
||||
|
||||
val isDarkBackground = currentStep.value !in 3..5
|
||||
|
||||
|
|
@ -58,13 +77,20 @@ fun StoriesScreen(
|
|||
|
||||
val hideContent = remember { mutableStateOf(true) }
|
||||
|
||||
SideEffect {
|
||||
systemUiController.setSystemBarsColor(
|
||||
color = Color.Transparent,
|
||||
darkIcons = false,
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
Modifier
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color(0xFF090E13))
|
||||
) {
|
||||
Row(
|
||||
Modifier.fillMaxSize()
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
|
|
@ -105,19 +131,23 @@ fun StoriesScreen(
|
|||
}
|
||||
if (!isDarkBackground) {
|
||||
Image(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
painter = painterResource(id = R.drawable.ic_overlay),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
}
|
||||
|
||||
val insets = WindowInsets.systemBars
|
||||
.union(WindowInsets(top = 32.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.windowInsetsPadding(insets)
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
SpacerS24()
|
||||
StoriesProgressBar(
|
||||
steps = steps,
|
||||
currentStep = currentStep.value,
|
||||
|
|
@ -7,7 +7,7 @@ import com.tangem.blockchain.extensions.Result
|
|||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.demo.DemoTransactionSender
|
||||
import com.tangem.tap.features.demo.isDemoWallet
|
||||
import com.tangem.tap.features.demo.isDemoCard
|
||||
import com.tangem.tap.features.send.redux.AmountActionUi
|
||||
import com.tangem.tap.features.send.redux.FeeAction
|
||||
import com.tangem.tap.features.send.redux.ReceiptAction
|
||||
|
|
@ -28,6 +28,7 @@ class RequestFeeMiddleware {
|
|||
fun handle(appState: AppState?, dispatch: DispatchFunction) {
|
||||
val sendState = appState?.sendState ?: return
|
||||
val walletManager = sendState.walletManager ?: return
|
||||
val scanResponse = appState.globalState.scanResponse ?: return
|
||||
|
||||
if (!SendState.isReadyToRequestFee()) {
|
||||
dispatch(FeeAction.FeeCalculation.SetFeeError(FeeAction.Error.ADDRESS_OR_AMOUNT_IS_EMPTY))
|
||||
|
|
@ -40,7 +41,7 @@ class RequestFeeMiddleware {
|
|||
|
||||
val destinationAddress = sendState.addressPayIdState.destinationWalletAddress!!
|
||||
val destinationAmount = Amount(typedAmount, sendState.amountState.amountToSendCrypto)
|
||||
val txSender = if (walletManager.isDemoWallet()) {
|
||||
val txSender = if (scanResponse.isDemoCard()) {
|
||||
DemoTransactionSender(walletManager)
|
||||
} else {
|
||||
walletManager as TransactionSender
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|||
import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.TransactionError
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
|
|
@ -15,7 +19,11 @@ import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
|||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -26,9 +34,15 @@ import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
|||
import com.tangem.tap.domain.extensions.minimalAmount
|
||||
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
|
||||
import com.tangem.tap.features.demo.DemoTransactionSender
|
||||
import com.tangem.tap.features.demo.isDemoWallet
|
||||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.demo.isDemoCard
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUi
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction
|
||||
import com.tangem.tap.features.send.redux.AmountAction
|
||||
import com.tangem.tap.features.send.redux.AmountActionUi
|
||||
import com.tangem.tap.features.send.redux.FeeAction.RequestFee
|
||||
import com.tangem.tap.features.send.redux.PrepareSendScreen
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.features.send.redux.SendActionUi
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import com.tangem.tap.features.send.redux.states.ExternalTransactionData
|
||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||
|
|
@ -38,6 +52,7 @@ import com.tangem.tap.scope
|
|||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdk
|
||||
import com.tangem.wallet.R
|
||||
import java.util.EnumSet
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -45,7 +60,6 @@ import kotlinx.coroutines.withContext
|
|||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -161,7 +175,11 @@ private fun sendTransaction(
|
|||
tangemSdk.config.linkedTerminal = false
|
||||
}
|
||||
|
||||
val signer = TangemSigner(tangemSdk, action.messageForSigner) { signResponse ->
|
||||
val signer = TangemSigner(
|
||||
card = card,
|
||||
tangemSdk = tangemSdk,
|
||||
initialMessage = action.messageForSigner
|
||||
) { signResponse ->
|
||||
store.dispatch(
|
||||
GlobalAction.UpdateWalletSignedHashes(
|
||||
walletSignedHashes = signResponse.totalSignedHashes,
|
||||
|
|
@ -171,7 +189,7 @@ private fun sendTransaction(
|
|||
)
|
||||
}
|
||||
val sendResult = try {
|
||||
if (walletManager.isDemoWallet()) {
|
||||
if (card.isDemoCard()) {
|
||||
DemoTransactionSender(walletManager).send(txData, signer)
|
||||
} else {
|
||||
(walletManager as TransactionSender).send(txData, signer)
|
||||
|
|
@ -340,5 +358,4 @@ private fun updateWarnings(dispatch: (Action) -> Unit) {
|
|||
|
||||
val warnings = warningsManager.getWarnings(WarningMessage.Location.SendScreen, listOf(blockchain))
|
||||
dispatch(SendAction.Warnings.Set(warnings))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -73,6 +73,9 @@ data class WalletState(
|
|||
val walletManagers: List<WalletManager>
|
||||
get() = wallets.mapNotNull { it.walletManager }
|
||||
|
||||
val cardId: String?
|
||||
get() = wallets.firstOrNull()?.walletManager?.wallet?.cardId
|
||||
|
||||
fun getWalletManager(currency: Currency?): WalletManager? {
|
||||
if (currency?.blockchain == null) return null
|
||||
return getWalletStore(currency)?.walletManager
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class TradeCryptoMiddleware {
|
|||
|
||||
val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return
|
||||
val exchangeManager = store.state.globalState.exchangeManager ?: return
|
||||
val card = store.state.globalState.scanResponse?.card ?: return
|
||||
val appCurrency = store.state.globalState.appCurrency
|
||||
|
||||
val addresses = selectedWalletData.walletAddresses?.list.orEmpty()
|
||||
|
|
@ -59,7 +60,13 @@ class TradeCryptoMiddleware {
|
|||
return
|
||||
}
|
||||
|
||||
scope.launch { exchangeManager.buyErc20TestnetTokens(walletManager, currency.token) }
|
||||
scope.launch {
|
||||
exchangeManager.buyErc20TestnetTokens(
|
||||
card = card,
|
||||
walletManager = walletManager,
|
||||
token = currency.token
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package com.tangem.tap.features.wallet.redux.middlewares
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tangem.blockchain.blockchains.solana.RentProvider
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
|
|
@ -15,12 +12,7 @@ import com.tangem.domain.common.extensions.withMainContext
|
|||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.extensions.copyToClipboard
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.onCardScanned
|
||||
import com.tangem.tap.common.extensions.shareText
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
|
|
@ -233,9 +225,7 @@ class WalletMiddleware {
|
|||
action.context.shareText(action.address)
|
||||
}
|
||||
is WalletAction.ExploreAddress -> {
|
||||
val uri = Uri.parse(action.exploreUrl)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
ContextCompat.startActivity(action.context, intent, null)
|
||||
store.dispatchOpenUrl(action.exploreUrl)
|
||||
}
|
||||
is WalletAction.Send -> {
|
||||
val newAction = prepareSendAction(action.amount, store.state.walletState)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.widget.TextView
|
|||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.IconsUtil
|
||||
import com.tangem.blockchain.common.Token
|
||||
|
|
@ -21,13 +20,13 @@ private const val QCX = "QCX"
|
|||
private const val VOYR = "VOYRME"
|
||||
|
||||
fun loadCurrencyIcon(
|
||||
currencyImageView: ImageFilterView,
|
||||
currencyImageView: CurrencyIconView,
|
||||
currencyTextView: TextView,
|
||||
token: Token?,
|
||||
blockchain: Blockchain,
|
||||
) {
|
||||
CurrencyIconLoader(
|
||||
currencyImageView = currencyImageView,
|
||||
currencyImageView = currencyImageView.imageView,
|
||||
currencyTextView = currencyTextView,
|
||||
token = token,
|
||||
blockchain = blockchain
|
||||
|
|
@ -135,14 +134,6 @@ private inline fun ImageView.loadIcon(
|
|||
.placeholder(placeholderRes)
|
||||
.error(placeholderRes)
|
||||
.fallback(placeholderRes)
|
||||
.transformations(
|
||||
RoundedCornersTransformation(
|
||||
topLeft = 32f,
|
||||
topRight = 32f,
|
||||
bottomLeft = 32f,
|
||||
bottomRight = 32f
|
||||
)
|
||||
)
|
||||
.listener(
|
||||
onStart = { onStart() },
|
||||
onSuccess = { _, _ -> onSuccess() },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.tap.features.wallet.ui.images
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.wallet.databinding.ViewCurrencyIconBinding
|
||||
|
||||
class CurrencyIconView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : MaterialCardView(context, attrs, defStyleAttr) {
|
||||
private val binding = ViewCurrencyIconBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
this
|
||||
)
|
||||
|
||||
val imageView: ImageFilterView
|
||||
get() = binding.iv
|
||||
|
||||
init {
|
||||
elevation = 0f
|
||||
cardElevation = 0f
|
||||
radius = dpToPx(8f)
|
||||
background = null
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.blockchain.common.AmountType
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -68,7 +69,11 @@ class CurrencyExchangeManager(
|
|||
enum class Action { Buy, Sell }
|
||||
}
|
||||
|
||||
suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(walletManager: EthereumWalletManager, token: Token) {
|
||||
suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(
|
||||
card: Card,
|
||||
walletManager: EthereumWalletManager,
|
||||
token: Token,
|
||||
) {
|
||||
walletManager.safeUpdate()
|
||||
|
||||
val amountToSend = Amount(walletManager.wallet.blockchain)
|
||||
|
|
@ -85,7 +90,9 @@ suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(walletManager: Ethereu
|
|||
val transaction = walletManager.createTransaction(amountToSend, fee, destinationAddress)
|
||||
|
||||
val signer = TangemSigner(
|
||||
tangemSdk = tangemSdk, Message()
|
||||
card = card,
|
||||
tangemSdk = tangemSdk,
|
||||
initialMessage = Message(),
|
||||
) { signResponse ->
|
||||
store.dispatch(
|
||||
GlobalAction.UpdateWalletSignedHashes(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue