Updated on 2026-08-14
This commit is contained in:
parent
6558188794
commit
bf3a15c114
11 changed files with 46 additions and 801 deletions
|
|
@ -1,87 +0,0 @@
|
|||
package com.tangem.tap.domain.walletCurrencies
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
||||
interface WalletCurrenciesManager {
|
||||
/**
|
||||
* Update [UserWallet] currencies with same blockchain as provided [Currency] blockchain
|
||||
* [UserWallet] currencies updates can be observed
|
||||
* with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
|
||||
* or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
|
||||
*
|
||||
* @param userWallet [UserWallet] which currencies will be updated
|
||||
* @param currency [Currency] to find other currencies to update
|
||||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun update(userWallet: UserWallet, currency: Currency): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Add list of [Currency] to [UserWallet].
|
||||
* [UserWallet] currencies updates can be observed
|
||||
* with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
|
||||
* or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
|
||||
*
|
||||
* @param userWallet [UserWallet] to add currencies
|
||||
* @param currenciesToAdd list of [Currency] to add [UserWallet]
|
||||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun addCurrencies(userWallet: UserWallet, currenciesToAdd: List<Currency>): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Remove [Currency] from [UserWallet]
|
||||
* [UserWallet] currencies updates can be observed
|
||||
* with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
|
||||
* or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
|
||||
*
|
||||
* @param userWallet [UserWallet] which currency will be removed
|
||||
* @param currencyToRemove [Currency] to remove from [UserWallet]
|
||||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun removeCurrency(userWallet: UserWallet, currencyToRemove: Currency): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Remove list of [Currency] from [UserWallet]
|
||||
* [UserWallet] currencies updates can be observed
|
||||
* with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
|
||||
* or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
|
||||
*
|
||||
* @param userWallet [UserWallet] which currency will be removed
|
||||
* @param currenciesToRemove list of [Currency] to remove from [UserWallet]
|
||||
*
|
||||
* @return [CompletionResult] of operation
|
||||
* */
|
||||
suspend fun removeCurrencies(userWallet: UserWallet, currenciesToRemove: List<Currency>): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Add a callback [Listener]
|
||||
*
|
||||
* @param listener The callback that will add
|
||||
*/
|
||||
fun addListener(listener: Listener)
|
||||
|
||||
/**
|
||||
* Remove a callback [Listener]
|
||||
*
|
||||
* @param listener The callback that will removed
|
||||
*/
|
||||
fun removeListener(listener: Listener)
|
||||
|
||||
/**
|
||||
* Interface definition for a callbacks
|
||||
*/
|
||||
interface Listener {
|
||||
fun willUpdate(userWallet: UserWallet, currency: Currency) {}
|
||||
fun didUpdate(userWallet: UserWallet, currency: Currency) {}
|
||||
fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List<Currency>) {}
|
||||
fun willCurrenciesRemove(userWallet: UserWallet, currenciesToRemove: List<Currency>) {}
|
||||
fun willCurrencyRemove(userWallet: UserWallet, currencyToRemove: Currency) {}
|
||||
}
|
||||
|
||||
// For provider
|
||||
companion object
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.tap.domain.walletCurrencies.di
|
||||
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.domain.tokens.UserTokensRepository
|
||||
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
|
||||
import com.tangem.tap.domain.walletCurrencies.implementation.DefaultWalletCurrenciesManager
|
||||
import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository
|
||||
import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
|
||||
|
||||
fun WalletCurrenciesManager.Companion.provideDefaultImplementation(
|
||||
userTokensRepository: UserTokensRepository,
|
||||
walletStoresRepository: WalletStoresRepository,
|
||||
walletAmountsRepository: WalletAmountsRepository,
|
||||
walletManagersRepository: WalletManagersRepository,
|
||||
appCurrencyProvider: () -> FiatCurrency,
|
||||
): WalletCurrenciesManager {
|
||||
return DefaultWalletCurrenciesManager(
|
||||
userTokensRepository = userTokensRepository,
|
||||
walletStoresRepository = walletStoresRepository,
|
||||
walletAmountsRepository = walletAmountsRepository,
|
||||
walletManagersRepository = walletManagersRepository,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
package com.tangem.tap.domain.walletCurrencies.implementation
|
||||
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.*
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.domain.model.builders.WalletStoreBuilder
|
||||
import com.tangem.tap.domain.tokens.UserTokensRepository
|
||||
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
|
||||
import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository
|
||||
import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.models.toBlockchainNetworks
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class DefaultWalletCurrenciesManager(
|
||||
private val userTokensRepository: UserTokensRepository,
|
||||
private val walletStoresRepository: WalletStoresRepository,
|
||||
private val walletAmountsRepository: WalletAmountsRepository,
|
||||
private val walletManagersRepository: WalletManagersRepository,
|
||||
private val appCurrencyProvider: () -> FiatCurrency,
|
||||
) : WalletCurrenciesManager {
|
||||
|
||||
private val listeners = mutableListOf<WalletCurrenciesManager.Listener>()
|
||||
|
||||
override suspend fun update(userWallet: UserWallet, currency: Currency): CompletionResult<Unit> =
|
||||
withContext(Dispatchers.Default) {
|
||||
listeners.forEach { it.willUpdate(userWallet, currency) }
|
||||
val walletStore = walletStoresRepository.getSync(userWallet.walletId)
|
||||
.find {
|
||||
it.blockchain == currency.blockchain &&
|
||||
it.derivationPath?.rawPath == currency.derivationPath
|
||||
}
|
||||
|
||||
val updateResult = if (walletStore == null) {
|
||||
CompletionResult.Success(Unit)
|
||||
} else {
|
||||
walletAmountsRepository.updateAmountsForWalletStore(
|
||||
walletStore = walletStore,
|
||||
userWallet = userWallet,
|
||||
fiatCurrency = appCurrencyProvider(),
|
||||
)
|
||||
}
|
||||
listeners.forEach { it.didUpdate(userWallet, currency) }
|
||||
updateResult
|
||||
}
|
||||
|
||||
override suspend fun addCurrencies(
|
||||
userWallet: UserWallet,
|
||||
currenciesToAdd: List<Currency>,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
if (currenciesToAdd.isEmpty()) {
|
||||
return@withContext CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
val card = userWallet.scanResponse.card
|
||||
val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(
|
||||
userWallet.scanResponse.derivationStyleProvider,
|
||||
)
|
||||
listeners.forEach { it.willCurrenciesAdd(userWallet, currenciesToAddWithMissingBlockchains) }
|
||||
|
||||
updateWalletStores(
|
||||
userWallet = userWallet,
|
||||
blockchainNetworks = currenciesToAddWithMissingBlockchains
|
||||
.toBlockchainNetworks()
|
||||
.addSameBlockchainTokens(userWallet.walletId),
|
||||
)
|
||||
.map {
|
||||
saveUserCurrencies(card, getSavedCurrencies(userWallet.walletId))
|
||||
}
|
||||
.flatMap {
|
||||
updateWalletStoresAmounts(
|
||||
userWallet = userWallet,
|
||||
updatedCurrencies = currenciesToAddWithMissingBlockchains,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeCurrencies(
|
||||
userWallet: UserWallet,
|
||||
currenciesToRemove: List<Currency>,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
if (currenciesToRemove.isEmpty()) {
|
||||
return@withContext CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
listeners.forEach { it.willCurrenciesRemove(userWallet, currenciesToRemove) }
|
||||
val card = userWallet.scanResponse.card
|
||||
val remainingCurrencies = getSavedCurrencies(userWallet.walletId)
|
||||
.filter { it !in currenciesToRemove }
|
||||
val remainingBlockchains = remainingCurrencies
|
||||
.filterIsInstance<Currency.Blockchain>()
|
||||
|
||||
walletStoresRepository.deleteDifference(userWallet.walletId, remainingBlockchains)
|
||||
.flatMap {
|
||||
updateWalletStores(userWallet, remainingCurrencies.toBlockchainNetworks())
|
||||
}
|
||||
.doOnResult {
|
||||
saveUserCurrencies(card, remainingCurrencies)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeCurrency(userWallet: UserWallet, currencyToRemove: Currency): CompletionResult<Unit> {
|
||||
listeners.forEach { it.willCurrencyRemove(userWallet, currencyToRemove) }
|
||||
return removeCurrencies(userWallet, listOf(currencyToRemove))
|
||||
}
|
||||
|
||||
override fun addListener(listener: WalletCurrenciesManager.Listener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
override fun removeListener(listener: WalletCurrenciesManager.Listener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
private suspend fun getSavedCurrencies(userWalletId: UserWalletId): List<Currency> {
|
||||
return withContext(Dispatchers.Default) {
|
||||
walletStoresRepository.getSync(userWalletId)
|
||||
.flatMap { walletStore ->
|
||||
walletStore.walletsData.map { it.currency }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveUserCurrencies(card: CardDTO, currencies: List<Currency>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
userTokensRepository.saveUserTokens(
|
||||
card = card,
|
||||
tokens = currencies,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Need refactoring
|
||||
private suspend fun List<BlockchainNetwork>.addSameBlockchainTokens(
|
||||
userWalletId: UserWalletId,
|
||||
): List<BlockchainNetwork> {
|
||||
val networks = arrayListOf<BlockchainNetwork>()
|
||||
val savedWalletStores = withContext(Dispatchers.Default) {
|
||||
walletStoresRepository.getSync(userWalletId)
|
||||
}
|
||||
|
||||
this.forEach { network ->
|
||||
val walletStore = savedWalletStores.firstOrNull {
|
||||
it.blockchain == network.blockchain && it.derivationPath?.rawPath == network.derivationPath
|
||||
}
|
||||
|
||||
if (walletStore != null) {
|
||||
val tokens = walletStore.walletsData
|
||||
.asSequence()
|
||||
.map { it.currency }
|
||||
.filterIsInstance<Currency.Token>()
|
||||
.map { it.token }
|
||||
.toList()
|
||||
|
||||
networks.add(network.copy(tokens = tokens + network.tokens.toSet()))
|
||||
} else {
|
||||
networks.add(network)
|
||||
}
|
||||
}
|
||||
|
||||
return networks
|
||||
}
|
||||
|
||||
private fun List<Currency>.addMissingBlockchainsIfNeeded(
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<Currency> {
|
||||
if (this.isEmpty()) return this
|
||||
val currencies = this.asSequence()
|
||||
|
||||
return currencies
|
||||
.groupBy { currency ->
|
||||
findBlockchainCurrency(currency, currencies, derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
.mapValues { (blockchainCurrency, blockchainCurrencies) ->
|
||||
findBlockchainTokens(blockchainCurrency, blockchainCurrencies)
|
||||
}
|
||||
.flatMap { (blockchainCurrency, blockchainTokens) ->
|
||||
arrayListOf(blockchainCurrency) + blockchainTokens
|
||||
}
|
||||
}
|
||||
|
||||
private fun findBlockchainCurrency(
|
||||
currency: Currency,
|
||||
currencies: Sequence<Currency>,
|
||||
cardDerivationStyle: DerivationStyle?,
|
||||
): Currency.Blockchain {
|
||||
return currencies
|
||||
.filterIsInstance<Currency.Blockchain>()
|
||||
.firstOrNull {
|
||||
it.blockchain == currency.blockchain &&
|
||||
it.derivationPath == currency.derivationPath
|
||||
}
|
||||
?: Currency.Blockchain(
|
||||
blockchain = currency.blockchain,
|
||||
derivationPath = currency.derivationPath
|
||||
?: currency.blockchain.derivationPath(cardDerivationStyle)?.rawPath,
|
||||
)
|
||||
}
|
||||
|
||||
private fun findBlockchainTokens(
|
||||
blockchainCurrency: Currency.Blockchain,
|
||||
blockchainCurrencies: List<Currency>,
|
||||
): List<Currency.Token> {
|
||||
return blockchainCurrencies
|
||||
.filterIsInstance<Currency.Token>()
|
||||
.map { token ->
|
||||
token.copy(
|
||||
derivationPath = token.derivationPath ?: blockchainCurrency.derivationPath,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStores(
|
||||
userWallet: UserWallet,
|
||||
blockchainNetworks: List<BlockchainNetwork>,
|
||||
): CompletionResult<Unit> {
|
||||
return blockchainNetworks
|
||||
.map { blockchainNetwork ->
|
||||
walletManagersRepository.findOrMakeMultiCurrencyWalletManager(
|
||||
userWallet = userWallet,
|
||||
blockchainNetwork = blockchainNetwork,
|
||||
)
|
||||
.flatMap { walletManager ->
|
||||
walletStoresRepository.storeOrUpdate(
|
||||
userWalletId = userWallet.walletId,
|
||||
walletStore = WalletStoreBuilder(userWallet, blockchainNetwork)
|
||||
.walletManager(walletManager)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
}
|
||||
.fold()
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoresAmounts(
|
||||
userWallet: UserWallet,
|
||||
updatedCurrencies: List<Currency>,
|
||||
): CompletionResult<Unit> {
|
||||
val updatedBlockchains = updatedCurrencies
|
||||
.filterIsInstance<Currency.Blockchain>()
|
||||
val updatedWalletStores = walletStoresRepository.get(userWallet.walletId)
|
||||
.firstOrNull()
|
||||
?.filter { it.blockchainWalletData.currency in updatedBlockchains }
|
||||
?: return CompletionResult.Success(Unit)
|
||||
|
||||
return walletAmountsRepository.updateAmountsForWalletStores(
|
||||
walletStores = updatedWalletStores,
|
||||
userWallet = userWallet,
|
||||
fiatCurrency = appCurrencyProvider(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue