Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-17 22:28:06 +04:00
parent 7bd584c261
commit 568e735d23
10 changed files with 43 additions and 314 deletions

View file

@ -101,10 +101,6 @@ internal class DefaultStakingRepository(
private val yieldBalanceConverter = YieldBalanceConverter()
private val yieldBalanceListConverter = YieldBalanceListConverter(yieldBalanceConverter)
private val isYieldBalanceFetching = MutableStateFlow(
value = emptyMap<UserWalletId, Boolean>(),
)
private val tronStakeKitTransactionAdapter by lazy { moshi.adapter(TronStakeKitTransaction::class.java) }
override fun getIntegrationKey(cryptoCurrencyId: CryptoCurrency.ID): String = with(cryptoCurrencyId) {
@ -384,79 +380,48 @@ internal class DefaultStakingRepository(
) = withContext(dispatchers.io) {
if (!stakingFeatureToggle.isStakingEnabled) return@withContext
try {
cacheRegistry.invokeOnExpire(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
block = {
isYieldBalanceFetching.update {
it + (userWalletId to true)
}
cacheRegistry.invokeOnExpire(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
block = {
val yields = getEnabledYields().ifEmpty {
Timber.i("No enabled yields for $userWalletId")
stakingBalanceStore.store(userWalletId, emptySet())
val yields = getEnabledYields().ifEmpty {
Timber.i("No enabled yields for $userWalletId")
return@invokeOnExpire
}
val availableCurrencies = cryptoCurrencies
.mapNotNull { currency ->
val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network)
val integrationId = integrationIdMap[getIntegrationKey(currency.id)]
if (integrationId != null && yields.any { it.id == integrationId }) {
addresses to integrationId
} else {
null
}
}
.flatMap { (addresses, integrationId) ->
addresses.map { address -> address to integrationId }
}
.map { getBalanceRequestData(it.first.value, it.second) }
.ifEmpty {
Timber.i("No yield balances available for $userWalletId")
stakingBalanceStore.store(userWalletId, emptySet())
return@invokeOnExpire
}
val availableCurrencies = cryptoCurrencies
.mapNotNull { currency ->
val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network)
val integrationId = integrationIdMap[getIntegrationKey(currency.id)]
if (integrationId != null && yields.any { it.id == integrationId }) {
addresses to integrationId
} else {
null
}
}
.flatMap { (addresses, integrationId) ->
addresses.map { address -> address to integrationId }
}
.map { getBalanceRequestData(it.first.value, it.second) }
.ifEmpty {
Timber.i("No yield balances available for $userWalletId")
stakingBalanceStore.store(userWalletId, emptySet())
val result = stakeKitApi
.getMultipleYieldBalances(availableCurrencies)
.getOrThrow()
return@invokeOnExpire
}
val result = stakeKitApi
.getMultipleYieldBalances(availableCurrencies)
.getOrThrow()
stakingBalanceStore.store(userWalletId, result)
},
)
} finally {
isYieldBalanceFetching.update {
it - userWalletId
}
}
stakingBalanceStore.store(userWalletId, result)
},
)
}
override fun getMultiYieldBalanceFlow(
userWalletId: UserWalletId,
cryptoCurrencies: List<CryptoCurrency>,
): Flow<YieldBalanceList> = channelFlow {
if (!stakingFeatureToggle.isStakingEnabled) {
send(YieldBalanceList.Empty)
} else {
launch(dispatchers.io) {
stakingBalanceStore.get(userWalletId)
.collectLatest { send(yieldBalanceListConverter.convert(it)) }
}
withContext(dispatchers.io) {
fetchMultiYieldBalance(
userWalletId,
cryptoCurrencies,
)
}
}
}.cancellable()
override fun getMultiYieldBalance(
override fun getMultiYieldBalanceUpdates(
userWalletId: UserWalletId,
cryptoCurrencies: List<CryptoCurrency>,
): Flow<YieldBalanceList> = channelFlow {

View file

@ -1,6 +1,5 @@
package com.tangem.data.tokens.repository
import arrow.core.raise.catch
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.compatibility.getL2CompatibilityTokenComparison
import com.tangem.blockchainsdk.utils.toCoinId
@ -27,8 +26,6 @@ import com.tangem.datasource.local.preferences.utils.storeObject
import com.tangem.datasource.local.token.ExpressAssetsStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.core.error.DataError
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.lce.lceFlow
import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
@ -67,10 +64,6 @@ internal class DefaultCurrenciesRepository(
private val userTokensBackwardCompatibility = UserTokensBackwardCompatibility()
private val customTokensMerger = CustomTokensMerger(tangemTechApi, dispatchers)
private val isMultiCurrencyWalletCurrenciesFetching = MutableStateFlow(
value = emptyMap<UserWalletId, Boolean>(),
)
override suspend fun saveTokens(
userWalletId: UserWalletId,
currencies: List<CryptoCurrency>,
@ -267,30 +260,6 @@ internal class DefaultCurrenciesRepository(
}
}
override fun getMultiCurrencyWalletCurrenciesUpdatesLce(
userWalletId: UserWalletId,
): LceFlow<Throwable, List<CryptoCurrency>> = lceFlow {
val userWallet = getUserWallet(userWalletId)
catch({ ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true) }) {
raise(it)
}
launch(dispatchers.io) {
combine(
getMultiCurrencyWalletCurrencies(userWallet),
isMultiCurrencyWalletCurrenciesFetching.map { it.getOrElse(userWallet.walletId) { false } },
) { currencies, isFetching ->
send(currencies, isStillLoading = isFetching)
}.collect()
}
withContext(dispatchers.io) {
catch({ fetchTokensIfCacheExpired(userWallet, refresh = false) }) {
raise(it)
}
}
}
override suspend fun getMultiCurrencyWalletCurrenciesSync(
userWalletId: UserWalletId,
refresh: Boolean,
@ -540,19 +509,7 @@ internal class DefaultCurrenciesRepository(
cacheRegistry.invokeOnExpire(
key = getTokensCacheKey(userWallet.walletId),
skipCache = refresh,
block = {
isMultiCurrencyWalletCurrenciesFetching.update {
it + (userWallet.walletId to true)
}
try {
fetchTokens(userWallet)
} finally {
isMultiCurrencyWalletCurrenciesFetching.update {
it - userWallet.walletId
}
}
},
block = { fetchTokens(userWallet) },
)
}

View file

@ -1,6 +1,5 @@
package com.tangem.data.tokens.repository
import arrow.core.raise.catch
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.address.AddressType
import com.tangem.blockchainsdk.utils.fromNetworkId
@ -15,8 +14,6 @@ import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.lce.lceFlow
import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
@ -28,7 +25,10 @@ import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
@Suppress("LongParameterList")
@ -46,10 +46,6 @@ internal class DefaultNetworksRepository(
private val responseCurrenciesFactory by lazy { ResponseCryptoCurrenciesFactory() }
private val networkStatusFactory by lazy { NetworkStatusFactory() }
private val isNetworkStatusesFetching = MutableStateFlow(
value = emptyMap<UserWalletId, Boolean>(),
)
override fun getNetworkStatusesUpdates(
userWalletId: UserWalletId,
networks: Set<Network>,
@ -63,24 +59,6 @@ internal class DefaultNetworksRepository(
}
}
override fun getNetworkStatusesUpdatesLce(
userWalletId: UserWalletId,
networks: Set<Network>,
): LceFlow<Throwable, Set<NetworkStatus>> = lceFlow {
combine(
networksStatusesStore.get(userWalletId),
isNetworkStatusesFetching.map { it.getOrElse(userWalletId) { false } },
) { statuses, isFetching ->
send(statuses, isStillLoading = isFetching || networks.size != statuses.size)
}.launchIn(scope = this + dispatchers.io)
withContext(dispatchers.io) {
catch({ fetchNetworksStatusesIfCacheExpired(userWalletId, networks, refresh = false) }) {
raise(it)
}
}
}
override suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set<Network>) {
val currencies = getCurrencies(userWalletId, networks)
withContext(dispatchers.io) {
@ -123,67 +101,13 @@ internal class DefaultNetworksRepository(
}
}
override suspend fun getNetworkAddress(
userWalletId: UserWalletId,
currency: CryptoCurrency,
): CryptoCurrencyAddress = withContext(dispatchers.io) {
CryptoCurrencyAddress(
cryptoCurrency = currency,
address = walletManagersFacade.getAddresses(userWalletId, currency.network)
.firstOrNull { it.type == AddressType.Default }
?.value.orEmpty(),
)
}
override fun getNetworkAddressFlow(
userWalletId: UserWalletId,
currency: CryptoCurrency,
): Flow<CryptoCurrencyAddress> = channelFlow {
launch(dispatchers.io) {
send(getNetworkAddress(userWalletId, currency))
}
}
override suspend fun getNetworkAddresses(userWalletId: UserWalletId): List<CryptoCurrencyAddress> =
withContext(dispatchers.io) {
// Get list of currencies matching [network]
val currencies = getCurrencies(userWalletId)
// There is no currencies matching given [networks] in [userWalletId]
if (currencies.toList().isEmpty()) return@withContext emptyList()
currencies.toList().map { currency ->
CryptoCurrencyAddress(
cryptoCurrency = currency,
address = walletManagersFacade.getAddresses(userWalletId, currency.network)
.firstOrNull { it.type == AddressType.Default }
?.value.orEmpty(),
)
}
}
override fun getNetworkAddressesFlow(
userWalletId: UserWalletId,
network: Network,
): Flow<List<CryptoCurrencyAddress>> = channelFlow {
launch(dispatchers.io) {
send(getNetworkAddresses(userWalletId, network))
}
}
override fun getNetworkAddressesFlow(userWalletId: UserWalletId): Flow<List<CryptoCurrencyAddress>> = channelFlow {
launch(dispatchers.io) {
send(getNetworkAddresses(userWalletId))
}
}
private suspend fun fetchNetworksStatusesIfCacheExpired(
userWalletId: UserWalletId,
networks: Set<Network>,
refresh: Boolean,
) = coroutineScope {
if (refresh) {
val statusesToRefresh = networks.map { NetworkStatus(it, NetworkStatus.Loading) }
val statusesToRefresh = networks.map { NetworkStatus(it, NetworkStatus.Refreshing) }
networksStatusesStore.storeAll(userWalletId, statusesToRefresh)
}
@ -230,8 +154,6 @@ internal class DefaultNetworksRepository(
network: Network,
currencies: Sequence<CryptoCurrency>,
) {
networksStatusesStore.store(userWalletId, NetworkStatus(network, NetworkStatus.Loading))
val result = walletManagersFacade.update(
userWalletId = userWalletId,
network = network,