Updated on 2026-08-14

This commit is contained in:
Tangem 2023-02-28 19:22:37 +03:00
parent 13ef9b4242
commit 8b81f309c8
10 changed files with 30 additions and 179 deletions

View file

@ -26,7 +26,6 @@ import com.tangem.tap.domain.userWalletList.UserWalletsListManager
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation
import com.tangem.tap.domain.userWalletList.isLockedSync
import com.tangem.tap.domain.userWalletList.lockIfLockable
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
@ -141,7 +140,6 @@ class DetailsMiddleware {
store.onUserWalletSelected(selectedUserWallet)
}
} else {
userWalletsListManager.lockIfLockable()
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home))
}
}

View file

@ -33,7 +33,6 @@ import com.tangem.tap.domain.TangemSigner
import com.tangem.tap.domain.TapError
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.isDemoCard
import com.tangem.tap.features.send.redux.AddressPayIdActionUi
@ -61,6 +60,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.Middleware
import timber.log.Timber
import java.util.*
/**
@ -344,6 +344,6 @@ private suspend fun updateWallet(walletManager: WalletManager) {
),
)
} else {
store.dispatchOnMain(WalletAction.LoadWallet(BlockchainNetwork.fromWalletManager(walletManager)))
Timber.e("Unable to update wallet, no user wallet selected")
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.tap.features.tokens.redux
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationParams
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.common.CompletionResult
import com.tangem.common.card.EllipticCurve
@ -30,11 +29,8 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.tokens.LoadAvailableCoinsService
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
@ -44,6 +40,7 @@ import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
@Suppress("LargeClass")
class TokensMiddleware {
@ -191,7 +188,7 @@ class TokensMiddleware {
}
}
fun deriveMissingBlockchains(
private fun deriveMissingBlockchains(
scanResponse: ScanResponse,
currencyList: List<Currency>,
onSuccess: (ScanResponse) -> Unit,
@ -268,15 +265,11 @@ class TokensMiddleware {
return DerivationData(
derivations = mapKeyOfWalletPublicKey to toDerive,
alreadyDerivedKeys = alreadyDerivedKeys,
mapKeyOfWalletPublicKey = mapKeyOfWalletPublicKey,
)
}
private class DerivationData(
val derivations: Pair<ByteArrayKey, List<DerivationPath>>,
val alreadyDerivedKeys: ExtendedPublicKeysMap,
val mapKeyOfWalletPublicKey: ByteArrayKey,
)
private fun submitAdd(scanResponse: ScanResponse, currencyList: List<Currency>) {
@ -297,59 +290,17 @@ class TokensMiddleware {
}
}
} else {
val factory = store.state.globalState.tapWalletManager.walletManagerFactory
val derivationStyle = scanResponse.card.derivationStyle
val addActions = currencyList.mapIndexedNotNull { index, currency ->
when (currency) {
is Currency.Blockchain -> {
val derivationPath = currency.derivationPath?.let { DerivationPath(it) }
val derivationParams = derivationStyle?.let {
when (derivationPath) {
null -> DerivationParams.Default(derivationStyle)
else -> DerivationParams.Custom(derivationPath)
}
}
val walletManager = factory.makeWalletManagerForApp(
scanResponse = scanResponse,
blockchain = currency.blockchain,
derivationParams = derivationParams,
) ?: return@mapIndexedNotNull null
WalletAction.MultiWallet.AddBlockchain(
blockchain = BlockchainNetwork.fromWalletManager(walletManager),
walletManager = walletManager,
save = index == currencyList.lastIndex,
)
}
is Currency.Token -> {
val rawDerivationPath = currency.derivationPath
?: currency.blockchain.derivationPath(derivationStyle)?.rawPath
val blockchainNetwork =
BlockchainNetwork(currency.blockchain, rawDerivationPath, listOf(currency.token))
WalletAction.MultiWallet.AddToken(
token = currency.token,
blockchain = blockchainNetwork,
save = index == currencyList.lastIndex,
)
}
}
}
addActions.forEach { store.dispatchOnMain(it) }
Timber.e("Unable to add currencies, no user wallet selected")
}
}
private suspend fun removeCurrenciesIfNeeded(currencies: List<Currency>) {
when {
currencies.isEmpty() -> Unit
userWalletsListManager.hasUserWallets -> {
walletCurrenciesManager.removeCurrencies(
userWallet = userWalletsListManager.selectedUserWalletSync!!,
currenciesToRemove = currencies,
)
}
else -> {
store.dispatch(WalletAction.MultiWallet.RemoveWallets(currencies))
}
if (currencies.isEmpty()) return
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync
if (selectedUserWallet != null) {
walletCurrenciesManager.removeCurrencies(selectedUserWallet, currencies)
} else {
Timber.e("Unable to remove currencies, no user wallet selected")
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.tap.features.wallet.redux.middlewares
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
import com.tangem.core.analytics.Analytics
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.entities.FiatCurrency
@ -18,6 +18,7 @@ import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
import kotlinx.coroutines.launch
import timber.log.Timber
class AppCurrencyMiddleware(
private val walletRepository: WalletRepository,
@ -72,8 +73,7 @@ class AppCurrencyMiddleware(
tapWalletManager.loadData(selectedUserWallet, refresh = true)
}
} else {
tapWalletManager.rates.clear()
store.dispatch(WalletAction.LoadFiatRate())
Timber.e("Unable to select currency, no user wallet selected")
}
}

View file

@ -38,6 +38,7 @@ import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletCurrenciesManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber
import java.math.BigDecimal
class MultiWalletMiddleware {
@ -139,20 +140,7 @@ class MultiWalletMiddleware {
)
}
} else {
val currency = action.currency
val card = globalState.scanResponse?.card.guard {
store.dispatchErrorNotification(TapError.UnsupportedState("card is NULL"))
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
return
}
var currencies = walletState?.currencies ?: emptyList()
currencies = currencies.filterNot { it == currency }
if (currency.isBlockchain()) {
currencies.filter {
it.blockchain == currency.blockchain && it.derivationPath == currency.derivationPath
}
}
scope.launch { userTokensRepository.saveUserTokens(card, currencies) }
Timber.e("Unable to remove wallet, no user wallet selected")
}
}
is WalletAction.MultiWallet.RemoveWallets -> {
@ -178,11 +166,11 @@ class MultiWalletMiddleware {
scope.launch { handleBasicAnalyticsEvent() }
}
is WalletAction.MultiWallet.ScanToGetDerivations -> {
val selectedWallet = userWalletsListManager.selectedUserWalletSync
if (selectedWallet != null) {
scanAndUpdateCard(selectedWallet, walletState)
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync
if (selectedUserWallet != null) {
scanAndUpdateCard(selectedUserWallet, walletState)
} else {
store.dispatch(WalletAction.Scan(onScanSuccessEvent = null))
Timber.e("Unable to scan to get derivations, no user wallet selected")
}
}
else -> {}

View file

@ -239,13 +239,7 @@ class WalletMiddleware {
refresh = action is WalletAction.LoadData.Refresh,
)
} else {
val scanResponse = globalState.scanResponse ?: return@launch
if (walletState.walletsDataFromStores.isNotEmpty()) {
globalState.tapWalletManager.reloadData(scanResponse)
} else {
globalState.tapWalletManager.loadData(scanResponse)
}
Timber.e("Unable to load/refresh wallets data, no user wallet selected")
}
}
}
@ -257,9 +251,7 @@ class WalletMiddleware {
if (selectedUserWallet != null) {
scope.launch { globalState.tapWalletManager.loadData(selectedUserWallet) }
} else {
globalState.scanResponse?.let { scanNoteResponse ->
scope.launch { globalState.tapWalletManager.loadData(scanNoteResponse) }
}
Timber.e("Unable to proceed with changed network state, no user wallet selected")
}
}
is WalletAction.CopyAddress -> {

View file

@ -30,7 +30,6 @@ import com.tangem.tap.common.analytics.events.DetailsScreen
import com.tangem.tap.common.analytics.events.Token
import com.tangem.tap.common.extensions.appendIfNotNull
import com.tangem.tap.common.extensions.beginDelayedTransition
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.fitChipsByGroupWidth
import com.tangem.tap.common.extensions.getColor
import com.tangem.tap.common.extensions.getString
@ -39,7 +38,6 @@ import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.extensions.toQrCode
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.PendingTransaction
import com.tangem.tap.features.wallet.models.PendingTransactionType
@ -65,6 +63,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.rekotlin.StoreSubscriber
import timber.log.Timber
import javax.inject.Inject
@Suppress("LargeClass", "MagicNumber")
@ -257,14 +256,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
}
}
} else {
val blockchainNetwork = BlockchainNetwork(
blockchain = currency.blockchain,
derivationPath = currency.derivationPath,
tokens = emptyList(),
)
store.dispatchOnMain(WalletAction.LoadWallet(blockchainNetwork))
store.dispatchOnMain(WalletAction.LoadFiatRate(coinsList = listOf(currency)))
Timber.e("Unable to refresh wallet details screen, no user wallet selected")
}
}
}

View file

@ -29,7 +29,7 @@ class DerivationManagerImpl(
private val appStateHolder: AppStateHolder,
) : DerivationManager {
override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine<Boolean> { continuation ->
override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation ->
val blockchain = Blockchain.fromNetworkId(currency.networkId)
val card = appStateHolder.getActualCard()
if (blockchain != null && card != null) {
@ -89,7 +89,7 @@ class DerivationManagerImpl(
}
scope.launch {
val selectedWallet = appStateHolder.userWalletsListManager?.selectedUserWalletSync
val selectedUserWallet = appStateHolder.userWalletsListManager?.selectedUserWalletSync
val result = appStateHolder.tangemSdkManager?.derivePublicKeys(
scanResponse.card.cardId,
@ -110,8 +110,8 @@ class DerivationManagerImpl(
val updatedScanResponse = scanResponse.copy(
derivedKeys = updatedDerivedKeys,
)
if (selectedWallet != null) {
val userWallet = selectedWallet.copy(
if (selectedUserWallet != null) {
val userWallet = selectedUserWallet.copy(
scanResponse = updatedScanResponse,
)
@ -166,14 +166,10 @@ class DerivationManagerImpl(
return DerivationData(
derivations = mapKeyOfWalletPublicKey to toDerive,
alreadyDerivedKeys = alreadyDerivedKeys,
mapKeyOfWalletPublicKey = mapKeyOfWalletPublicKey,
)
}
private class DerivationData(
val derivations: Pair<ByteArrayKey, List<DerivationPath>>,
val alreadyDerivedKeys: ExtendedPublicKeysMap,
val mapKeyOfWalletPublicKey: ByteArrayKey,
)
}

View file

@ -2,13 +2,8 @@ package com.tangem.tap.proxy
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationParams
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.toCoinId
import com.tangem.domain.common.extensions.toNetworkId
@ -19,20 +14,17 @@ import com.tangem.lib.crypto.models.Currency.NonNativeToken
import com.tangem.lib.crypto.models.ProxyAmount
import com.tangem.lib.crypto.models.ProxyFiatCurrency
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletCurrenciesManager
import kotlinx.coroutines.delay
import org.rekotlin.Action
import timber.log.Timber
import java.math.BigDecimal
import com.tangem.tap.features.wallet.models.Currency as WalletCurrency
class UserWalletManagerImpl(
private val appStateHolder: AppStateHolder,
private val walletManagerFactory: WalletManagerFactory,
) : UserWalletManager {
override suspend fun getUserTokens(networkId: String, isExcludeCustom: Boolean): List<Currency> {
@ -117,13 +109,7 @@ class UserWalletManagerImpl(
currenciesToAdd = listOf(currency.toWalletCurrency(blockchainNetwork)),
)
} else {
val walletManager = getOrCreateBlockchain(blockchainNetwork, blockchain)
if (currency is NonNativeToken && !walletManager.cardTokens.contains(currency.toSdkToken())) {
val action = addNonNativeTokenToWalletAction(currency, card, blockchain)
val mainStore = requireNotNull(appStateHolder.mainStore) { "mainStore is null" }
mainStore.dispatchOnMain(action)
delay(DELAY_UPDATE_WALLET)
}
Timber.e("Unable to add token, selected user wallet is null")
}
}
@ -207,60 +193,11 @@ class UserWalletManagerImpl(
)
}
private suspend fun getOrCreateBlockchain(
blockchainNetwork: BlockchainNetwork,
blockchain: Blockchain,
): WalletManager {
val card = requireNotNull(appStateHolder.getActualCard()) { "card not found" }
val scanResponse = requireNotNull(appStateHolder.scanResponse) { "scanResponse not found" }
var walletManager = appStateHolder.walletState?.getWalletManager(blockchainNetwork)
if (walletManager == null) {
walletManager = walletManagerFactory.makeWalletManagerForApp(
scanResponse = scanResponse,
blockchain = blockchain,
derivationParams = createDerivationParams(card.derivationStyle),
)
val action = WalletAction.MultiWallet.AddBlockchain(
blockchain = blockchainNetwork,
walletManager = walletManager,
save = true,
)
val mainStore = requireNotNull(appStateHolder.mainStore) { "mainStore is null" }
mainStore.dispatchOnMain(action)
// workaround to wait until blockchain adds to walletStores and update appStateHolder.walletState
delay(DELAY_UPDATE_WALLET)
}
return requireNotNull(walletManager) { "cant create walletManager" }
}
private fun addNonNativeTokenToWalletAction(token: NonNativeToken, card: CardDTO, blockchain: Blockchain): Action {
return WalletAction.MultiWallet.AddToken(
token = Token(
id = token.id,
name = token.name,
symbol = token.symbol,
contractAddress = token.contractAddress,
decimals = token.decimalCount,
),
blockchain = BlockchainNetwork(
blockchain,
card,
),
save = true,
)
}
override fun refreshWallet() {
// workaround, should update wallet after transaction
appStateHolder.mainStore?.dispatchOnMain(WalletAction.LoadData.Refresh)
}
private fun createDerivationParams(derivationStyle: DerivationStyle?): DerivationParams? {
// todo clarify if its need to add Custom
return derivationStyle?.let { DerivationParams.Default(derivationStyle) }
}
private fun getActualWalletManager(blockchain: Blockchain): WalletManager {
val card = requireNotNull(appStateHolder.getActualCard()) { "card not found" }
val blockchainNetwork = BlockchainNetwork(blockchain, card)
@ -271,7 +208,6 @@ class UserWalletManagerImpl(
companion object {
private const val HEX_PREFIX = "0x"
private const val DELAY_UPDATE_WALLET = 500L
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.tap.proxy.di
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.lib.crypto.DerivationManager
import com.tangem.lib.crypto.TransactionManager
import com.tangem.lib.crypto.UserWalletManager
@ -29,7 +28,6 @@ class ProxyModule {
fun provideUserWalletManager(appStateHolder: AppStateHolder): UserWalletManager {
return UserWalletManagerImpl(
appStateHolder = appStateHolder,
walletManagerFactory = WalletManagerFactory(),
)
}