Updated on 2026-08-14
This commit is contained in:
parent
41d216b4a8
commit
7503c2817c
30 changed files with 86 additions and 1172 deletions
|
|
@ -7,7 +7,6 @@ import com.tangem.domain.managetokens.repository.ManageTokensRepository
|
|||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -72,7 +71,6 @@ internal object ManageTokensDomainModule {
|
|||
walletManagersFacade: WalletManagersFacade,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
derivationsRepository: DerivationsRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
|
|
@ -84,7 +82,6 @@ internal object ManageTokensDomainModule {
|
|||
walletManagersFacade = walletManagersFacade,
|
||||
currenciesRepository = currenciesRepository,
|
||||
derivationsRepository = derivationsRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
|||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import dagger.Module
|
||||
|
|
@ -62,21 +60,17 @@ object MarketsDomainModule {
|
|||
derivationsRepository: DerivationsRepository,
|
||||
marketsTokenRepository: MarketsTokenRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): SaveMarketTokensUseCase {
|
||||
return SaveMarketTokensUseCase(
|
||||
derivationsRepository = derivationsRepository,
|
||||
marketsTokenRepository = marketsTokenRepository,
|
||||
currenciesRepository = currenciesRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,12 +94,10 @@ internal object StakingDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideFetchStakingYieldBalanceUseCase(
|
||||
stakingRepository: StakingRepository,
|
||||
stakingErrorResolver: StakingErrorResolver,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
): FetchStakingYieldBalanceUseCase {
|
||||
return FetchStakingYieldBalanceUseCase(
|
||||
stakingRepository = stakingRepository,
|
||||
stakingErrorResolver = stakingErrorResolver,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideAddCryptoCurrenciesUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
|
|
@ -50,7 +49,6 @@ internal object TokensDomainModule {
|
|||
): AddCryptoCurrenciesUseCase {
|
||||
return AddCryptoCurrenciesUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
|
|
@ -63,19 +61,15 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideFetchTokenListUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): FetchTokenListUseCase {
|
||||
return FetchTokenListUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +167,6 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideFetchCurrencyStatusUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
|
|
@ -182,7 +175,6 @@ internal object TokensDomainModule {
|
|||
): FetchCurrencyStatusUseCase {
|
||||
return FetchCurrencyStatusUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
|
|
@ -195,19 +187,15 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideFetchCardTokenListUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): FetchCardTokenListUseCase {
|
||||
return FetchCardTokenListUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,6 @@ internal class DefaultTokensFeatureToggles(
|
|||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) : TokensFeatureToggles {
|
||||
|
||||
override val isStakingLoadingRefactoringEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(name = "STAKING_LOADING_REFACTORING_ENABLED")
|
||||
|
||||
override val isWalletBalanceFetcherEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(name = "WALLET_BALANCE_FETCHER_ENABLED")
|
||||
}
|
||||
|
|
@ -23,10 +23,6 @@
|
|||
"name": "WALLET_CONNECT_REDESIGN_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "STAKING_LOADING_REFACTORING_ENABLED",
|
||||
"version": "5.25.0"
|
||||
},
|
||||
{
|
||||
"name": "PUSH_NOTIFICATIONS_ENABLED",
|
||||
"version": "undefined"
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ import com.squareup.moshi.Moshi
|
|||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
|
||||
import com.tangem.datasource.local.datastore.RuntimeDataStore
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.token.*
|
||||
import com.tangem.datasource.local.token.DefaultStakingActionsStore
|
||||
import com.tangem.datasource.local.token.DefaultStakingYieldsStore
|
||||
import com.tangem.datasource.local.token.StakingActionsStore
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.utils.MoshiDataStoreSerializer
|
||||
import com.tangem.datasource.utils.listTypes
|
||||
import com.tangem.datasource.utils.mapWithStringKeyTypes
|
||||
|
|
@ -66,17 +68,6 @@ internal object StakingStoreModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingBalanceStore(
|
||||
persistenceStore: DataStore<Map<String, Set<YieldBalanceWrapperDTO>>>,
|
||||
): StakingBalanceStore {
|
||||
return DefaultStakingBalanceStore(
|
||||
persistenceStore = persistenceStore,
|
||||
runtimeStore = RuntimeSharedStore(),
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingActionsStore(): StakingActionsStore {
|
||||
|
|
|
|||
|
|
@ -1,269 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.token.StakingBalanceStore.StakingID
|
||||
import com.tangem.datasource.local.token.converter.YieldBalanceConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal typealias YieldBalanceWrappersDTO = Map<String, Set<YieldBalanceWrapperDTO>>
|
||||
internal typealias YieldBalanceListByWalletId = Map<UserWalletId, Set<YieldBalance>>
|
||||
|
||||
/**
|
||||
* Default implementation of [StakingBalanceStore]
|
||||
*
|
||||
* @property persistenceStore persistence store
|
||||
* @property runtimeStore runtime store
|
||||
*/
|
||||
internal class DefaultStakingBalanceStore(
|
||||
private val persistenceStore: DataStore<YieldBalanceWrappersDTO>,
|
||||
private val runtimeStore: RuntimeSharedStore<YieldBalanceListByWalletId>,
|
||||
) : StakingBalanceStore {
|
||||
|
||||
override fun get(userWalletId: UserWalletId, stakingIds: List<StakingID>): Flow<Set<YieldBalance>> = channelFlow {
|
||||
val cachedBalances = persistenceStore.data
|
||||
.map {
|
||||
val wrappers = it[userWalletId.stringValue].orEmpty()
|
||||
.filter { wrapper ->
|
||||
stakingIds.any { id ->
|
||||
id.address == wrapper.addresses.address && id.integrationId == wrapper.integrationId
|
||||
}
|
||||
}
|
||||
|
||||
YieldBalanceConverter(isCached = true).convertSet(input = wrappers)
|
||||
}
|
||||
.firstOrNull()
|
||||
.orEmpty()
|
||||
|
||||
if (cachedBalances.isNotEmpty()) {
|
||||
send(cachedBalances)
|
||||
}
|
||||
|
||||
runtimeStore.get()
|
||||
.map {
|
||||
it[userWalletId].orEmpty().filter { balance ->
|
||||
stakingIds.any { id ->
|
||||
id.address == balance.address && id.integrationId == balance.integrationId
|
||||
}
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
.onEach {
|
||||
val mergedBalances = mergeYieldBalances(
|
||||
stakingIds = stakingIds,
|
||||
cachedBalances = cachedBalances,
|
||||
runtimeBalances = it,
|
||||
)
|
||||
|
||||
send(mergedBalances)
|
||||
}
|
||||
.launchIn(scope = this)
|
||||
}
|
||||
|
||||
override fun get(userWalletId: UserWalletId, stakingID: StakingID): Flow<YieldBalance?> {
|
||||
return get(userWalletId = userWalletId, stakingIds = listOf(stakingID)).map { balances ->
|
||||
balances.getBalance(stakingID = stakingID)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>? {
|
||||
val runtimeBalances = runtimeStore.getSyncOrNull()?.getValue(userWalletId).orEmpty()
|
||||
val cachedBalances = persistenceStore.data.firstOrNull()?.get(userWalletId.stringValue).orEmpty()
|
||||
|
||||
if (runtimeBalances.isEmpty() && cachedBalances.isEmpty()) return null
|
||||
|
||||
return cachedBalances.mapTo(hashSetOf()) {
|
||||
val cached = YieldBalanceConverter(source = StatusSource.ONLY_CACHE).convert(value = it)
|
||||
val runtime = runtimeBalances.getBalance(address = cached.address, integrationId = cached.integrationId)
|
||||
|
||||
if (runtime == null || runtime is YieldBalance.Error) cached else runtime
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingIds: List<StakingID>): Set<YieldBalance>? {
|
||||
val runtime = runtimeStore.getSyncOrNull()?.getValue(userWalletId)
|
||||
val cached = persistenceStore.data.firstOrNull()?.get(userWalletId.stringValue)
|
||||
|
||||
if (runtime.isNullOrEmpty() && cached.isNullOrEmpty()) return null
|
||||
|
||||
return mergeYieldBalances(
|
||||
cachedBalances = YieldBalanceConverter(source = StatusSource.ONLY_CACHE)
|
||||
.convertSet(input = cached.orEmpty()),
|
||||
runtimeBalances = runtime.orEmpty(),
|
||||
stakingIds = stakingIds,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingID: StakingID): YieldBalance? {
|
||||
val balances = getSyncOrNull(userWalletId = userWalletId, stakingIds = listOf(stakingID)) ?: return null
|
||||
|
||||
return balances.getBalance(stakingID = stakingID)
|
||||
}
|
||||
|
||||
override suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>) {
|
||||
coroutineScope {
|
||||
launch {
|
||||
val newBalances = YieldBalanceConverter(isCached = false).convertSet(input = items)
|
||||
|
||||
runtimeStore.update(default = emptyMap()) { saved ->
|
||||
saved.toMutableMap().apply {
|
||||
this[userWalletId] = saved[userWalletId]
|
||||
?.addOrReplace(newBalances) { old, new ->
|
||||
old.integrationId == new.integrationId && old.address == new.address
|
||||
}
|
||||
?: newBalances
|
||||
}
|
||||
}
|
||||
}
|
||||
launch { storeInPersistenceStore(userWalletId = userWalletId, items = items) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun refresh(userWalletId: UserWalletId, stakingIds: List<StakingID>) {
|
||||
updateRuntimeStore(userWalletId = userWalletId) { saved ->
|
||||
saved.mapTo(hashSetOf()) {
|
||||
val yieldBalance = it.takeIf { balance ->
|
||||
stakingIds.any { id -> balance.integrationId == id.integrationId && balance.address == id.address }
|
||||
}
|
||||
|
||||
yieldBalance?.copySealed(source = StatusSource.CACHE) ?: it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun store(userWalletId: UserWalletId, stakingID: StakingID, item: YieldBalanceWrapperDTO) {
|
||||
coroutineScope {
|
||||
launch {
|
||||
storeInRuntimeStore(
|
||||
userWalletId = userWalletId,
|
||||
integrationId = stakingID.integrationId,
|
||||
address = stakingID.address,
|
||||
item = item,
|
||||
)
|
||||
|
||||
storeInPersistenceStore(
|
||||
userWalletId = userWalletId,
|
||||
integrationId = stakingID.integrationId,
|
||||
address = stakingID.address,
|
||||
item = item,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeSingleYieldBalance(userWalletId: UserWalletId, item: YieldBalance) {
|
||||
runtimeStore.update(default = emptyMap()) { saved ->
|
||||
saved.toMutableMap().apply {
|
||||
this[userWalletId] = saved[userWalletId]
|
||||
?.addOrReplace(item) { it.integrationId == item.integrationId && it.address == item.address }
|
||||
?: setOf(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun storeInRuntimeStore(
|
||||
userWalletId: UserWalletId,
|
||||
integrationId: String,
|
||||
address: String,
|
||||
item: YieldBalanceWrapperDTO,
|
||||
) {
|
||||
val newBalance = YieldBalanceConverter(isCached = false).convert(value = item)
|
||||
|
||||
runtimeStore.update(default = emptyMap()) { saved ->
|
||||
saved.toMutableMap().apply {
|
||||
this[userWalletId] = saved[userWalletId]
|
||||
?.addOrReplace(newBalance) { it.integrationId == integrationId && it.address == address }
|
||||
?: setOf(newBalance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateRuntimeStore(
|
||||
userWalletId: UserWalletId,
|
||||
function: (Set<YieldBalance>) -> Set<YieldBalance>,
|
||||
) {
|
||||
runtimeStore.update(default = emptyMap()) { saved ->
|
||||
saved.toMutableMap().apply {
|
||||
this[userWalletId] = function(this[userWalletId].orEmpty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun storeInPersistenceStore(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>) {
|
||||
persistenceStore.updateData { current ->
|
||||
current.toMutableMap().apply {
|
||||
this[userWalletId.stringValue] = current[userWalletId.stringValue]
|
||||
?.addOrReplace(items = items) { old, new ->
|
||||
old.integrationId == new.integrationId && old.addresses.address == new.addresses.address
|
||||
}
|
||||
?: items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun storeInPersistenceStore(
|
||||
userWalletId: UserWalletId,
|
||||
integrationId: String,
|
||||
address: String,
|
||||
item: YieldBalanceWrapperDTO,
|
||||
) {
|
||||
persistenceStore.updateData { current ->
|
||||
current.toMutableMap().apply {
|
||||
this[userWalletId.stringValue] = current[userWalletId.stringValue]
|
||||
?.addOrReplace(item) { it.integrationId == integrationId && it.addresses.address == address }
|
||||
?: setOf(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun mergeYieldBalances(
|
||||
cachedBalances: Set<YieldBalance>,
|
||||
runtimeBalances: Set<YieldBalance>,
|
||||
stakingIds: List<StakingID>,
|
||||
): Set<YieldBalance> {
|
||||
return stakingIds.mapTo(hashSetOf()) { id ->
|
||||
val runtime = runtimeBalances.getBalance(stakingID = id)
|
||||
|
||||
if (runtime == null || runtime is YieldBalance.Error) {
|
||||
getCachedBalanceIfPossible(cachedBalances = cachedBalances, stakingID = id)
|
||||
} else {
|
||||
runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCachedBalanceIfPossible(cachedBalances: Set<YieldBalance>, stakingID: StakingID): YieldBalance {
|
||||
val cached = cachedBalances.getBalance(stakingID)
|
||||
?: return YieldBalance.Error(integrationId = stakingID.address, address = stakingID.integrationId)
|
||||
|
||||
val updatedCached = when (cached) {
|
||||
is YieldBalance.Data -> cached.copy(source = StatusSource.ONLY_CACHE)
|
||||
is YieldBalance.Empty -> cached.copy(source = StatusSource.ONLY_CACHE)
|
||||
is YieldBalance.Error,
|
||||
is YieldBalance.Unsupported,
|
||||
-> null
|
||||
}
|
||||
|
||||
return updatedCached ?: YieldBalance.Error(integrationId = stakingID.address, address = stakingID.integrationId)
|
||||
}
|
||||
|
||||
private fun Set<YieldBalance>.getBalance(stakingID: StakingID): YieldBalance? {
|
||||
return getBalance(address = stakingID.address, integrationId = stakingID.integrationId)
|
||||
}
|
||||
|
||||
private fun Set<YieldBalance>.getBalance(address: String?, integrationId: String?): YieldBalance? {
|
||||
return firstOrNull { yieldBalance ->
|
||||
val isCorrectAddress = address != null && address == yieldBalance.address
|
||||
val isCorrectIntegration = integrationId != null && yieldBalance.integrationId == integrationId
|
||||
|
||||
isCorrectIntegration && isCorrectAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/** Staking balance store */
|
||||
interface StakingBalanceStore {
|
||||
|
||||
/** Get flow of [YieldBalanceList] by [userWalletId] and [stakingIds] */
|
||||
fun get(userWalletId: UserWalletId, stakingIds: List<StakingID>): Flow<Set<YieldBalance>>
|
||||
|
||||
/** Get flow of [YieldBalance] by [userWalletId] and [stakingID] */
|
||||
fun get(userWalletId: UserWalletId, stakingID: StakingID): Flow<YieldBalance?>
|
||||
|
||||
/** Get all [YieldBalance] synchronously or null by [userWalletId] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>?
|
||||
|
||||
/** Get [YieldBalanceList] synchronously or null by [userWalletId] and [stakingIds] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingIds: List<StakingID>): Set<YieldBalance>?
|
||||
|
||||
/** Get [YieldBalance] synchronously or null by [userWalletId] and [stakingID] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingID: StakingID): YieldBalance?
|
||||
|
||||
/** Store [items] by [userWalletId] */
|
||||
suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>)
|
||||
|
||||
/** Store [item] by [userWalletId] and [stakingID] */
|
||||
suspend fun store(userWalletId: UserWalletId, stakingID: StakingID, item: YieldBalanceWrapperDTO)
|
||||
|
||||
/** Store [item] by [userWalletId] */
|
||||
suspend fun storeSingleYieldBalance(userWalletId: UserWalletId, item: YieldBalance)
|
||||
|
||||
/** Refresh balances of [stakingIds] by [userWalletId] */
|
||||
suspend fun refresh(userWalletId: UserWalletId, stakingIds: List<StakingID>)
|
||||
|
||||
data class StakingID(val integrationId: String, val address: String)
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package com.tangem.data.staking
|
|||
|
||||
import android.util.Base64
|
||||
import arrow.core.getOrElse
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
|
@ -15,8 +14,6 @@ import com.tangem.blockchainsdk.utils.toCoinId
|
|||
import com.tangem.blockchainsdk.utils.toMigratedCoinId
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toCompressedPublicKey
|
||||
import com.tangem.data.common.api.safeApiCall
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.staking.converters.YieldBalanceListConverter
|
||||
import com.tangem.data.staking.converters.YieldConverter
|
||||
import com.tangem.data.staking.converters.action.ActionStatusConverter
|
||||
|
|
@ -27,16 +24,13 @@ import com.tangem.data.staking.converters.transaction.StakingTransactionStatusCo
|
|||
import com.tangem.data.staking.converters.transaction.StakingTransactionTypeConverter
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.data.staking.utils.StakingIdFactory.Companion.integrationIdMap
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.api.stakekit.models.request.*
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionStatusDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.transaction.tron.TronStakeKitTransaction
|
||||
import com.tangem.datasource.local.token.StakingBalanceStore
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.token.converter.StakingNetworkTypeConverter
|
||||
import com.tangem.datasource.local.token.converter.TokenConverter
|
||||
|
|
@ -68,9 +62,7 @@ import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
|
@ -79,9 +71,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
internal class DefaultStakingRepository(
|
||||
private val stakeKitApi: StakeKitApi,
|
||||
private val stakingYieldsStore: StakingYieldsStore,
|
||||
private val stakingBalanceStore: StakingBalanceStore,
|
||||
private val stakingBalanceStoreV2: YieldsBalancesStore,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
|
|
@ -107,12 +97,8 @@ internal class DefaultStakingRepository(
|
|||
private val networkTypeAdapter by lazy { moshi.adapter(NetworkTypeDTO::class.java) }
|
||||
private val stakingActionStatusAdapter by lazy { moshi.adapter(StakingActionStatusDTO::class.java) }
|
||||
|
||||
override fun getIntegrationKey(cryptoCurrencyId: CryptoCurrency.ID): String = with(cryptoCurrencyId) {
|
||||
rawNetworkId.plus(rawCurrencyId)
|
||||
}
|
||||
|
||||
override fun getSupportedIntegrationId(cryptoCurrencyId: CryptoCurrency.ID): String? {
|
||||
return integrationIdMap.getOrDefault(getIntegrationKey(cryptoCurrencyId), null)
|
||||
return stakingIdFactory.createIntegrationId(currencyId = cryptoCurrencyId)
|
||||
}
|
||||
|
||||
override suspend fun fetchEnabledYields() {
|
||||
|
|
@ -398,107 +384,6 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) = withContext(dispatchers.io) {
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getYieldBalancesKey(userWalletId),
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
|
||||
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network)
|
||||
|
||||
if (integrationId == null || address.isNullOrBlank()) {
|
||||
cacheRegistry.invalidate(getYieldBalancesKey(userWalletId))
|
||||
Timber.w(
|
||||
"IntegrationId or address is null fetching ${cryptoCurrency.name} staking balance",
|
||||
)
|
||||
return@invokeOnExpire
|
||||
}
|
||||
|
||||
val requestBody = getBalanceRequestData(address, integrationId)
|
||||
|
||||
safeApiCall(
|
||||
call = {
|
||||
val result = stakeKitApi.getSingleYieldBalance(
|
||||
integrationId = requestBody.integrationId,
|
||||
body = requestBody,
|
||||
).bind()
|
||||
|
||||
stakingBalanceStore.store(
|
||||
userWalletId = userWalletId,
|
||||
stakingID = StakingBalanceStore.StakingID(
|
||||
integrationId = requestBody.integrationId,
|
||||
address = address,
|
||||
),
|
||||
item = YieldBalanceWrapperDTO(
|
||||
balances = result,
|
||||
integrationId = requestBody.integrationId,
|
||||
addresses = requestBody.addresses,
|
||||
),
|
||||
)
|
||||
},
|
||||
onError = {
|
||||
stakingBalanceStore.storeSingleYieldBalance(
|
||||
userWalletId = userWalletId,
|
||||
item = YieldBalance.Error(integrationId = requestBody.integrationId, address = address),
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSingleYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Flow<YieldBalance> = channelFlow {
|
||||
launch(dispatchers.io) {
|
||||
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
|
||||
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
|
||||
?: error("Could not get integrationId")
|
||||
|
||||
stakingBalanceStore.get(
|
||||
userWalletId = userWalletId,
|
||||
stakingID = StakingBalanceStore.StakingID(integrationId = integrationId, address = address),
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest {
|
||||
if (it != null) {
|
||||
send(it)
|
||||
} else {
|
||||
FirebaseCrashlytics.getInstance()
|
||||
.log("No yield balance available for currency ${cryptoCurrency.id.value}")
|
||||
send(YieldBalance.Error(integrationId, address))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
fetchSingleYieldBalance(userWalletId = userWalletId, cryptoCurrency = cryptoCurrency)
|
||||
}
|
||||
}.cancellable()
|
||||
|
||||
override suspend fun getSingleYieldBalanceSyncLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance = withContext(dispatchers.io) {
|
||||
fetchSingleYieldBalance(userWalletId, cryptoCurrency)
|
||||
|
||||
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
|
||||
|
||||
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
|
||||
?: error("Could not get integrationId")
|
||||
|
||||
stakingBalanceStore.getSyncOrNull(
|
||||
userWalletId = userWalletId,
|
||||
stakingID = StakingBalanceStore.StakingID(integrationId = integrationId, address = address),
|
||||
)
|
||||
?: YieldBalance.Error(integrationId, address)
|
||||
}
|
||||
|
||||
override suspend fun getSingleYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
|
|
@ -513,129 +398,6 @@ internal class DefaultStakingRepository(
|
|||
?: YieldBalance.Error(integrationId = stakingId.integrationId, address = stakingId.address)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
override suspend fun fetchMultiYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) = withContext(dispatchers.io) {
|
||||
if (refresh) {
|
||||
stakingBalanceStore.refresh(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = cryptoCurrencies.mapStakingId(userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
val yieldDTOs = withTimeoutOrNull(YIELDS_WATITING_TIMEOUT) {
|
||||
runCatching { stakingYieldsStore.get().firstOrNull() }.getOrNull()
|
||||
}
|
||||
|
||||
if (yieldDTOs == null) {
|
||||
Timber.i("No enabled yields for $userWalletId")
|
||||
stakingBalanceStore.store(userWalletId, emptySet())
|
||||
|
||||
return@withContext
|
||||
}
|
||||
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getYieldBalancesKey(userWalletId),
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
val yields = YieldConverter.convertListIgnoreErrors(
|
||||
input = yieldDTOs,
|
||||
onError = { Timber.e("Error converting one of the items in enabled yields: $it") },
|
||||
)
|
||||
|
||||
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 {
|
||||
stakingBalanceStore.store(userWalletId, emptySet())
|
||||
|
||||
cacheRegistry.invalidate(getYieldBalancesKey(userWalletId))
|
||||
|
||||
return@invokeOnExpire
|
||||
}
|
||||
|
||||
val yieldBalances = safeApiCall(
|
||||
call = {
|
||||
stakeKitApi
|
||||
.getMultipleYieldBalances(availableCurrencies)
|
||||
.bind()
|
||||
},
|
||||
onError = {
|
||||
Timber.e(it, "Unable to fetch yield balances")
|
||||
cacheRegistry.invalidate(getYieldBalancesKey(userWalletId))
|
||||
emptySet()
|
||||
},
|
||||
)
|
||||
|
||||
stakingBalanceStore.store(userWalletId, yieldBalances)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun List<CryptoCurrency>.mapStakingId(
|
||||
userWalletId: UserWalletId,
|
||||
): List<StakingBalanceStore.StakingID> {
|
||||
return this
|
||||
.mapNotNull { currency ->
|
||||
val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network)
|
||||
val integrationId = integrationIdMap[getIntegrationKey(currency.id)]
|
||||
|
||||
if (integrationId != null) {
|
||||
addresses to integrationId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.flatMap { (addresses, integrationId) ->
|
||||
addresses.map { address ->
|
||||
StakingBalanceStore.StakingID(
|
||||
integrationId = integrationId,
|
||||
address = address.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMultiYieldBalanceUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList> {
|
||||
return flow {
|
||||
stakingBalanceStore.get(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = cryptoCurrencies.mapStakingId(userWalletId),
|
||||
)
|
||||
.map(YieldBalanceListConverter::convert)
|
||||
.collect { emit(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getMultiYieldBalanceSyncLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList = withContext(dispatchers.io) {
|
||||
fetchMultiYieldBalance(userWalletId, cryptoCurrencies)
|
||||
|
||||
stakingBalanceStore.getSyncOrNull(userWalletId, cryptoCurrencies.mapStakingId(userWalletId))
|
||||
?.let(YieldBalanceListConverter::convert)
|
||||
?: YieldBalanceList.Error
|
||||
}
|
||||
|
||||
override suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
@ -724,7 +486,9 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
|
||||
override fun getStakingApproval(cryptoCurrency: CryptoCurrency): StakingApproval {
|
||||
return when (getIntegrationKey(cryptoCurrency.id)) {
|
||||
val integrationId = stakingIdFactory.createIntegrationId(currencyId = cryptoCurrency.id)
|
||||
|
||||
return when (integrationId) {
|
||||
Blockchain.Ethereum.id + Blockchain.Polygon.toCoinId(),
|
||||
Blockchain.Ethereum.id + Blockchain.Polygon.toMigratedCoinId(),
|
||||
-> StakingApproval.Needed(ETHEREUM_POLYGON_APPROVE_SPENDER)
|
||||
|
|
@ -773,22 +537,6 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getBalanceRequestData(address: String, integrationId: String): YieldBalanceRequestBody {
|
||||
return YieldBalanceRequestBody(
|
||||
addresses = Address(
|
||||
address = address,
|
||||
additionalAddresses = null, // todo fill additional addresses metadata if needed
|
||||
explorerUrl = "", // todo fill exporer url [REDACTED_JIRA]
|
||||
),
|
||||
args = YieldBalanceRequestBody.YieldBalanceRequestArgs(
|
||||
validatorAddresses = listOf(), // todo add validators [REDACTED_JIRA]
|
||||
),
|
||||
integrationId = integrationId,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getYieldBalancesKey(userWalletId: UserWalletId) = "yield_balance_${userWalletId.stringValue}"
|
||||
|
||||
private fun getTronResource(network: Network): TronResource? {
|
||||
val blockchain = Blockchain.fromNetworkId(network.backendId)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.data.staking.di
|
|||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.staking.DefaultStakingActionRepository
|
||||
import com.tangem.data.staking.DefaultStakingErrorResolver
|
||||
import com.tangem.data.staking.DefaultStakingRepository
|
||||
|
|
@ -17,7 +16,6 @@ import com.tangem.datasource.api.stakekit.models.response.model.error.StakeKitEr
|
|||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.token.StakingActionsStore
|
||||
import com.tangem.datasource.local.token.StakingBalanceStore
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.domain.staking.repositories.StakingActionRepository
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
|
|
@ -42,9 +40,7 @@ internal object StakingDataModule {
|
|||
fun provideStakingRepository(
|
||||
stakeKitApi: StakeKitApi,
|
||||
stakingYieldsStore: StakingYieldsStore,
|
||||
stakingBalanceStore: StakingBalanceStore,
|
||||
yieldsBalancesStore: YieldsBalancesStore,
|
||||
cacheRegistry: CacheRegistry,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
|
|
@ -55,9 +51,7 @@ internal object StakingDataModule {
|
|||
return DefaultStakingRepository(
|
||||
stakeKitApi = stakeKitApi,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
stakingBalanceStore = stakingBalanceStore,
|
||||
stakingBalanceStoreV2 = yieldsBalancesStore,
|
||||
cacheRegistry = cacheRegistry,
|
||||
dispatchers = dispatchers,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
getUserWalletUseCase = getUserWalletUseCase,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ internal class StakingIdFactory @Inject constructor(
|
|||
private const val CARDANO_INTEGRATION_ID = "cardano-ada-native-staking"
|
||||
|
||||
// uncomment items as implementation is ready
|
||||
val integrationIdMap = mapOf(
|
||||
private val integrationIdMap = mapOf(
|
||||
Blockchain.TON.toDefaultKey() to TON_INTEGRATION_ID,
|
||||
Blockchain.Solana.toDefaultKey() to SOLANA_INTEGRATION_ID,
|
||||
Blockchain.Cosmos.toDefaultKey() to COSMOS_INTEGRATION_ID,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
|
|
@ -24,7 +23,6 @@ class SaveManagedTokensUseCase(
|
|||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val derivationsRepository: DerivationsRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
|
|
@ -119,20 +117,12 @@ class SaveManagedTokensUseCase(
|
|||
userWalletId: UserWalletId,
|
||||
existingCurrencies: List<CryptoCurrency>,
|
||||
) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = existingCurrencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
stakingRepository.fetchMultiYieldBalance(
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = existingCurrencies,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
currencyIdWithNetworkMap = existingCurrencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun refreshUpdatedQuotes(addedCurrencies: List<CryptoCurrency>) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
|
|
@ -27,11 +25,9 @@ class SaveMarketTokensUseCase(
|
|||
private val derivationsRepository: DerivationsRepository,
|
||||
private val marketsTokenRepository: MarketsTokenRepository,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
|
@ -92,20 +88,12 @@ class SaveMarketTokensUseCase(
|
|||
userWalletId: UserWalletId,
|
||||
existingCurrencies: List<CryptoCurrency>,
|
||||
) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = existingCurrencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
stakingRepository.fetchMultiYieldBalance(
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = existingCurrencies,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
currencyIdWithNetworkMap = existingCurrencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun refreshUpdatedQuotes(addedCurrencies: List<CryptoCurrency>) {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@ import arrow.core.raise.either
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
class FetchStakingYieldBalanceUseCase(
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val stakingErrorResolver: StakingErrorResolver,
|
||||
private val singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
) {
|
||||
|
|
@ -19,27 +17,17 @@ class FetchStakingYieldBalanceUseCase(
|
|||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
isRefactoringEnabled: Boolean,
|
||||
refresh: Boolean = false,
|
||||
): Either<StakingError, Unit> {
|
||||
return either {
|
||||
catch(
|
||||
block = {
|
||||
if (isRefactoringEnabled) {
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
stakingRepository.fetchSingleYieldBalance(
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
refresh = refresh,
|
||||
)
|
||||
}
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
},
|
||||
catch = { stakingErrorResolver.resolve(it) },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ import java.math.BigDecimal
|
|||
@Suppress("TooManyFunctions")
|
||||
interface StakingRepository {
|
||||
|
||||
fun getIntegrationKey(cryptoCurrencyId: CryptoCurrency.ID): String
|
||||
|
||||
fun getSupportedIntegrationId(cryptoCurrencyId: CryptoCurrency.ID): String?
|
||||
|
||||
suspend fun fetchEnabledYields()
|
||||
|
|
@ -51,37 +49,8 @@ interface StakingRepository {
|
|||
stakingActionStatus: StakingActionStatus,
|
||||
): List<StakingAction>
|
||||
|
||||
suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean = false,
|
||||
)
|
||||
|
||||
fun getSingleYieldBalanceFlow(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Flow<YieldBalance>
|
||||
|
||||
suspend fun getSingleYieldBalanceSyncLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance
|
||||
|
||||
suspend fun getSingleYieldBalanceSync(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): YieldBalance
|
||||
|
||||
suspend fun fetchMultiYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
refresh: Boolean = false,
|
||||
)
|
||||
|
||||
fun getMultiYieldBalanceUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList>
|
||||
|
||||
suspend fun getMultiYieldBalanceSyncLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList
|
||||
|
||||
suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -26,7 +25,6 @@ import kotlinx.coroutines.coroutineScope
|
|||
@Suppress("LongParameterList")
|
||||
class AddCryptoCurrenciesUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
|
|
@ -156,21 +154,13 @@ class AddCryptoCurrenciesUseCase(
|
|||
}
|
||||
|
||||
private suspend fun refreshUpdatedYieldBalances(userWalletId: UserWalletId, addedCurrency: CryptoCurrency) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = addedCurrency.id,
|
||||
network = addedCurrency.network,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
stakingRepository.fetchSingleYieldBalance(
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = addedCurrency,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
currencyId = addedCurrency.id,
|
||||
network = addedCurrency.network,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun refreshUpdatedQuotes(currencyToAdd: CryptoCurrency) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -17,14 +16,11 @@ import kotlinx.coroutines.async
|
|||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
class FetchCardTokenListUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, refresh: Boolean = false): Either<TokenListError, Unit> {
|
||||
|
|
@ -47,7 +43,6 @@ class FetchCardTokenListUseCase(
|
|||
fetchYieldBalances(
|
||||
userWalletId = userWalletId,
|
||||
currencies = currencies,
|
||||
refresh = refresh,
|
||||
)
|
||||
}
|
||||
awaitAll(fetchStatuses, fetchQuotes, yieldBalances)
|
||||
|
|
@ -87,23 +82,12 @@ class FetchCardTokenListUseCase(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
catch(
|
||||
block = { stakingRepository.fetchMultiYieldBalance(userWalletId, currencies, refresh) },
|
||||
catch = { /* Ignore error */ },
|
||||
)
|
||||
}
|
||||
private suspend fun fetchYieldBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -29,7 +28,6 @@ import kotlinx.coroutines.coroutineScope
|
|||
@Suppress("LongParameterList")
|
||||
class FetchCurrencyStatusUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
|
|
@ -42,14 +40,9 @@ class FetchCurrencyStatusUseCase(
|
|||
*
|
||||
* @param userWalletId The ID of the user's wallet.
|
||||
* @param id The ID of the cryptocurrency.
|
||||
* @param refresh Indicates whether to force a refresh of the status data.
|
||||
* @return An [Either] representing success (Right) or an error (Left) in fetching the status.
|
||||
*/
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
id: CryptoCurrency.ID,
|
||||
refresh: Boolean = false,
|
||||
): Either<CurrencyStatusError, Unit> {
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, id: CryptoCurrency.ID): Either<CurrencyStatusError, Unit> {
|
||||
return either {
|
||||
val currency = getCurrency(userWalletId, id)
|
||||
|
||||
|
|
@ -61,7 +54,7 @@ class FetchCurrencyStatusUseCase(
|
|||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
val fetchStakingBalance = async {
|
||||
fetchStakingBalance(userWalletId = userWalletId, cryptoCurrency = currency, refresh = refresh)
|
||||
fetchStakingBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
}
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance).summarizeResult()
|
||||
|
|
@ -143,19 +136,14 @@ class FetchCurrencyStatusUseCase(
|
|||
private suspend fun fetchStakingBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
): Either<Throwable, Unit> {
|
||||
return if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Either.catch { stakingRepository.fetchSingleYieldBalance(userWalletId, cryptoCurrency, refresh) }
|
||||
}
|
||||
return singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<Either<Throwable, Unit>>.summarizeResult(): Either<Throwable, Unit> {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -24,17 +23,12 @@ import kotlinx.coroutines.coroutineScope
|
|||
* network statuses, and quotes for tokens associated with a user's wallet.
|
||||
*
|
||||
* @param currenciesRepository The repository for retrieving currency-related data.
|
||||
* @param stakingRepository The repository for retrieving staking-related data.
|
||||
*/
|
||||
// TODO: Add tests
|
||||
@Suppress("LongParameterList")
|
||||
class FetchTokenListUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -42,22 +36,17 @@ class FetchTokenListUseCase(
|
|||
* network statuses, and quotes for associated tokens.
|
||||
*
|
||||
* @param userWalletId The ID of the user's wallet.
|
||||
* @param mode The refresh mode to control the fetching process.
|
||||
* @return An [Either] representing success (Right) or an error (Left) in fetching the token list.
|
||||
*/
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
mode: RefreshMode = RefreshMode.NONE,
|
||||
): Either<TokenListError, Unit> = either {
|
||||
val currencies = fetchCurrencies(userWalletId, refresh = mode.refreshCurrencies)
|
||||
suspend operator fun invoke(userWalletId: UserWalletId): Either<TokenListError, Unit> = either {
|
||||
val currencies = fetchCurrencies(userWalletId)
|
||||
|
||||
invoke(userWalletId = userWalletId, currencies = currencies, mode = mode)
|
||||
invoke(userWalletId = userWalletId, currencies = currencies)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrency>,
|
||||
mode: RefreshMode = RefreshMode.NONE,
|
||||
): Either<TokenListError, Unit> = either {
|
||||
coroutineScope {
|
||||
val fetchStatuses = async {
|
||||
|
|
@ -73,23 +62,16 @@ class FetchTokenListUseCase(
|
|||
}
|
||||
|
||||
val yieldBalances = async {
|
||||
fetchYieldBalances(
|
||||
userWalletId = userWalletId,
|
||||
currencies = currencies,
|
||||
refresh = mode.refreshYieldBalances,
|
||||
)
|
||||
fetchYieldBalances(userWalletId = userWalletId, currencies = currencies)
|
||||
}
|
||||
|
||||
awaitAll(fetchStatuses, fetchQuotes, yieldBalances)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<TokenListError>.fetchCurrencies(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean,
|
||||
): List<CryptoCurrency> {
|
||||
private suspend fun Raise<TokenListError>.fetchCurrencies(userWalletId: UserWalletId): List<CryptoCurrency> {
|
||||
val currencies = catch(
|
||||
block = { currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId, refresh) },
|
||||
block = { currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId, true) },
|
||||
) {
|
||||
raise(TokenListError.DataError(it))
|
||||
}
|
||||
|
|
@ -121,48 +103,12 @@ class FetchTokenListUseCase(
|
|||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun fetchYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
catch(
|
||||
block = { stakingRepository.fetchMultiYieldBalance(userWalletId, currencies, refresh) },
|
||||
catch = { /* Ignore error */ },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the refresh modes available for fetching token list information.
|
||||
*/
|
||||
enum class RefreshMode(
|
||||
internal val refreshCurrencies: Boolean,
|
||||
internal val refreshQuotes: Boolean,
|
||||
internal val refreshYieldBalances: Boolean,
|
||||
) {
|
||||
NONE(
|
||||
refreshCurrencies = false,
|
||||
refreshQuotes = false,
|
||||
refreshYieldBalances = false,
|
||||
),
|
||||
FULL(
|
||||
refreshCurrencies = true,
|
||||
refreshQuotes = true,
|
||||
refreshYieldBalances = true,
|
||||
),
|
||||
SKIP_CURRENCIES(
|
||||
refreshCurrencies = false,
|
||||
refreshQuotes = true,
|
||||
refreshYieldBalances = true,
|
||||
),
|
||||
private suspend fun fetchYieldBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,5 @@ package com.tangem.domain.tokens
|
|||
*/
|
||||
interface TokensFeatureToggles {
|
||||
|
||||
val isStakingLoadingRefactoringEnabled: Boolean
|
||||
|
||||
val isWalletBalanceFetcherEnabled: Boolean
|
||||
}
|
||||
|
|
@ -234,8 +234,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
includeQuotes = includeQuotes,
|
||||
// If toggle is off, then subscribe on yield balance. If toggle is on, then don't
|
||||
subscribeOnYieldBalance = !tokensFeatureToggles.isStakingLoadingRefactoringEnabled,
|
||||
subscribeOnYieldBalance = false,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -340,17 +339,13 @@ abstract class BaseCurrencyStatusOperations(
|
|||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): EitherFlow<Error, YieldBalance> {
|
||||
return if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
singleYieldBalanceSupplier(
|
||||
params = SingleYieldBalanceProducer.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
stakingRepository.getSingleYieldBalanceFlow(userWalletId = userWalletId, cryptoCurrency = cryptoCurrency)
|
||||
}
|
||||
return singleYieldBalanceSupplier(
|
||||
params = SingleYieldBalanceProducer.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
.map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
|
|
@ -404,18 +399,10 @@ abstract class BaseCurrencyStatusOperations(
|
|||
): Either<Error.EmptyYieldBalances, YieldBalanceList> {
|
||||
return catch(
|
||||
block = {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
stakingRepository.getMultiYieldBalanceSync(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
)
|
||||
} else {
|
||||
stakingRepository.getMultiYieldBalanceSyncLegacy(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
)
|
||||
}
|
||||
.right()
|
||||
stakingRepository.getMultiYieldBalanceSync(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
Error.EmptyYieldBalances.left()
|
||||
|
|
@ -428,14 +415,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
cryptoCurrency: CryptoCurrency,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalance> {
|
||||
return catch(
|
||||
block = {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
stakingRepository.getSingleYieldBalanceSync(userWalletId, cryptoCurrency)
|
||||
} else {
|
||||
stakingRepository.getSingleYieldBalanceSyncLegacy(userWalletId, cryptoCurrency)
|
||||
}
|
||||
.right()
|
||||
},
|
||||
block = { stakingRepository.getSingleYieldBalanceSync(userWalletId, cryptoCurrency).right() },
|
||||
catch = {
|
||||
Error.EmptyYieldBalances.left()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
combine(
|
||||
flow = getQuotes(currenciesIds),
|
||||
flow2 = getNetworkStatusesUpdates(userWalletId, networks),
|
||||
flow3 = getYieldBalances(userWalletId, currencies),
|
||||
flow3 = getYieldsBalancesUpdates(userWalletId, currencies),
|
||||
flow4 = fetchingState.map {
|
||||
val state = it[userWalletId] ?: return@map false
|
||||
|
||||
|
|
@ -213,16 +213,12 @@ class CachedCurrenciesStatusesOperations(
|
|||
)
|
||||
},
|
||||
async {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
stakingRepository.fetchMultiYieldBalance(userWalletId, currencies)
|
||||
}
|
||||
multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -308,25 +304,6 @@ class CachedCurrenciesStatusesOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): EitherFlow<TokenListError, YieldBalanceList> {
|
||||
return if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
getYieldsBalancesUpdates(userWalletId, cryptoCurrencies)
|
||||
} else {
|
||||
stakingRepository.getMultiYieldBalanceUpdates(userWalletId, cryptoCurrencies)
|
||||
.map<YieldBalanceList, Either<TokenListError, YieldBalanceList>> { it.right() }
|
||||
.retryWhen { cause, _ ->
|
||||
emit(TokenListError.DataError(cause).left())
|
||||
// adding delay before retry to avoid spam when flow restarted
|
||||
delay(RETRY_DELAY)
|
||||
true
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
}
|
||||
|
||||
// temporary code because token list is built using networks list
|
||||
@OptIn(FlowPreview::class)
|
||||
private fun getNetworkStatusesUpdates(
|
||||
|
|
@ -433,7 +410,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
}
|
||||
|
||||
private fun isFetchingStarted(userWalletId: UserWalletId): Boolean {
|
||||
return fetchingState.value[userWalletId]?.let { it.isStarted() || it.isFinished() } ?: false
|
||||
return fetchingState.value[userWalletId]?.let { it.isStarted() || it.isFinished() } == true
|
||||
}
|
||||
|
||||
private fun setFetchStarted(userWalletId: UserWalletId) {
|
||||
|
|
@ -460,7 +437,6 @@ class CachedCurrenciesStatusesOperations(
|
|||
}
|
||||
|
||||
companion object {
|
||||
internal const val RETRY_DELAY = 2000L
|
||||
|
||||
private val fetchingState = MutableStateFlow(value = emptyMap<UserWalletId, FetchingState>())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,268 +0,0 @@
|
|||
package com.tangem.domain.tokens.repository
|
||||
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.staking.model.StakingApproval
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.model.StakingEntryInfo
|
||||
import com.tangem.domain.staking.model.stakekit.*
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingAction
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.*
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
class MockStakingRepository : StakingRepository {
|
||||
|
||||
override fun getSupportedIntegrationId(cryptoCurrencyId: CryptoCurrency.ID): String? = null
|
||||
|
||||
override fun getIntegrationKey(cryptoCurrencyId: CryptoCurrency.ID): String = ""
|
||||
|
||||
override suspend fun fetchEnabledYields() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
override suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo =
|
||||
StakingEntryInfo(
|
||||
apr = 1.toBigDecimal(),
|
||||
tokenSymbol = "SOL",
|
||||
rewardSchedule = Yield.Metadata.RewardSchedule.DAY,
|
||||
)
|
||||
|
||||
override suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield = yield
|
||||
|
||||
override suspend fun getYield(yieldId: String) = yield
|
||||
|
||||
override fun getStakingAvailability(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Flow<StakingAvailability> = flowOf(StakingAvailability.Unavailable)
|
||||
|
||||
override suspend fun getStakingAvailabilitySync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): StakingAvailability = StakingAvailability.Unavailable
|
||||
|
||||
override suspend fun getActions(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
networkType: NetworkType,
|
||||
stakingActionStatus: StakingActionStatus,
|
||||
): List<StakingAction> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
override fun getSingleYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Flow<YieldBalance> = channelFlow {
|
||||
send(YieldBalance.Error(integrationId = null, address = null))
|
||||
}
|
||||
|
||||
override suspend fun getSingleYieldBalanceSyncLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance = YieldBalance.Error(integrationId = null, address = null)
|
||||
|
||||
override suspend fun getSingleYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance = YieldBalance.Error(integrationId = null, address = null)
|
||||
|
||||
override suspend fun fetchMultiYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
override fun getMultiYieldBalanceUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList> {
|
||||
return flowOf(
|
||||
YieldBalanceList.Data(
|
||||
balances = listOf(YieldBalance.Error(integrationId = null, address = null)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getMultiYieldBalanceSyncLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList = YieldBalanceList.Data(
|
||||
balances = listOf(YieldBalance.Error(integrationId = null, address = null)),
|
||||
)
|
||||
|
||||
override suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList = YieldBalanceList.Data(
|
||||
balances = listOf(YieldBalance.Error(integrationId = null, address = null)),
|
||||
)
|
||||
|
||||
override suspend fun createAction(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
params: ActionParams,
|
||||
): StakingAction {
|
||||
return StakingAction(
|
||||
id = "quis",
|
||||
integrationId = "persequeris",
|
||||
status = StakingActionStatus.PROCESSING,
|
||||
type = StakingActionType.CLAIM_REWARDS,
|
||||
currentStepIndex = 8701,
|
||||
amount = BigDecimal.ZERO,
|
||||
validatorAddress = null,
|
||||
validatorAddresses = listOf(),
|
||||
transactions = listOf(),
|
||||
createdAt = DateTime.now(),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun estimateGas(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
params: ActionParams,
|
||||
): StakingGasEstimate {
|
||||
return StakingGasEstimate(
|
||||
amount = BigDecimal(0.0001),
|
||||
token = Token(
|
||||
name = "Solana",
|
||||
network = NetworkType.SOLANA,
|
||||
symbol = "SOL",
|
||||
decimals = 18,
|
||||
address = null,
|
||||
coinGeckoId = "solana",
|
||||
logoURI = null,
|
||||
isPoints = null,
|
||||
),
|
||||
gasLimit = null,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun constructTransaction(
|
||||
networkId: String,
|
||||
fee: Fee,
|
||||
amount: Amount,
|
||||
transactionId: String,
|
||||
): Pair<StakingTransaction, TransactionData.Compiled> = StakingTransaction(
|
||||
id = "id",
|
||||
network = NetworkType.SOLANA,
|
||||
status = StakingTransactionStatus.SIGNED,
|
||||
type = StakingTransactionType.FREEZE_ENERGY,
|
||||
hash = null,
|
||||
signedTransaction = null,
|
||||
unsignedTransaction = null,
|
||||
stepIndex = 9368,
|
||||
error = null,
|
||||
gasEstimate = null,
|
||||
stakeId = null,
|
||||
explorerUrl = null,
|
||||
ledgerHwAppId = null,
|
||||
isMessage = false,
|
||||
) to TransactionData.Compiled(
|
||||
value = TransactionData.Compiled.Data.RawString(""),
|
||||
status = TransactionStatus.Unconfirmed,
|
||||
)
|
||||
|
||||
override fun getStakingApproval(cryptoCurrency: CryptoCurrency): StakingApproval = StakingApproval.Empty
|
||||
|
||||
override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean = false
|
||||
override fun getActionRequirementAmount(integrationId: String, stakingActionType: StakingActionType): BigDecimal? =
|
||||
null
|
||||
|
||||
private companion object {
|
||||
val yield = Yield(
|
||||
id = "1",
|
||||
token = Token(
|
||||
name = "Solana",
|
||||
network = NetworkType.SOLANA,
|
||||
symbol = "SOL",
|
||||
decimals = 18,
|
||||
address = null,
|
||||
coinGeckoId = "solana",
|
||||
logoURI = null,
|
||||
isPoints = null,
|
||||
),
|
||||
tokens = listOf(),
|
||||
args = Yield.Args(
|
||||
enter = Yield.Args.Enter(
|
||||
addresses = Yield.Args.Enter.Addresses(
|
||||
address = AddressArgument(
|
||||
required = false,
|
||||
network = null,
|
||||
minimum = null,
|
||||
maximum = null,
|
||||
),
|
||||
additionalAddresses = mapOf(),
|
||||
),
|
||||
args = mapOf(),
|
||||
),
|
||||
exit = null,
|
||||
),
|
||||
status = Yield.Status(enter = false, exit = null),
|
||||
apy = 1.toBigDecimal(),
|
||||
rewardRate = 2.3,
|
||||
rewardType = Yield.RewardType.APR,
|
||||
metadata = Yield.Metadata(
|
||||
name = "Yield",
|
||||
logoUri = "",
|
||||
description = "",
|
||||
documentation = null,
|
||||
gasFeeToken = Token(
|
||||
name = "Solana",
|
||||
network = NetworkType.SOLANA,
|
||||
symbol = "SOL",
|
||||
decimals = 18,
|
||||
address = null,
|
||||
coinGeckoId = null,
|
||||
logoURI = null,
|
||||
isPoints = null,
|
||||
),
|
||||
token = Token(
|
||||
name = "Solana",
|
||||
network = NetworkType.SOLANA,
|
||||
symbol = "SOL",
|
||||
decimals = 18,
|
||||
address = null,
|
||||
coinGeckoId = null,
|
||||
logoURI = null,
|
||||
isPoints = null,
|
||||
),
|
||||
tokens = listOf(),
|
||||
type = "auto",
|
||||
rewardSchedule = Yield.Metadata.RewardSchedule.DAY,
|
||||
cooldownPeriod = Yield.Metadata.Period(days = 1),
|
||||
warmupPeriod = Yield.Metadata.Period(days = 1),
|
||||
rewardClaiming = Yield.Metadata.RewardClaiming.AUTO,
|
||||
defaultValidator = null,
|
||||
minimumStake = null,
|
||||
supportsMultipleValidators = false,
|
||||
revshare = Yield.Metadata.Enabled(enabled = false),
|
||||
fee = Yield.Metadata.Enabled(enabled = false),
|
||||
),
|
||||
validators = listOf(),
|
||||
isAvailable = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -65,6 +65,7 @@ dependencies {
|
|||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.txhistory)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.domain.feedback)
|
||||
implementation(projects.domain.feedback.models)
|
||||
implementation(projects.domain.notifications.models)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
fetchStakingYieldBalanceUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
isRefactoringEnabled = true,
|
||||
)
|
||||
},
|
||||
// we should update tx history and network for new balances
|
||||
|
|
@ -82,7 +81,6 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
fetchCurrencyStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
id = cryptoCurrencyStatus.currency.id,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -324,14 +324,14 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
ifRight = { quotes ->
|
||||
quotes.allowanceContract?.let {
|
||||
isAllowedToSpend(networkId, fromToken.currency, amount, it)
|
||||
} ?: true
|
||||
} != false
|
||||
},
|
||||
ifLeft = { false },
|
||||
)
|
||||
|
||||
if (isAllowedToSpend && allowPermissionsHandler.isAddressAllowanceInProgress(fromTokenAddress)) {
|
||||
allowPermissionsHandler.removeAddressFromProgress(fromTokenAddress)
|
||||
fetchCurrencyStatusUseCase(userWalletId, fromToken.currency.id, true)
|
||||
fetchCurrencyStatusUseCase(userWalletId = userWalletId, id = fromToken.currency.id)
|
||||
}
|
||||
return if (isAllowedToSpend && isBalanceWithoutFeeEnough) {
|
||||
provider to loadDexSwapData(
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
|
|||
isMultiCurrency -> fetchCurrencyStatusUseCase.invoke(
|
||||
userWalletId = userWallet.walletId,
|
||||
id = cryptoCurrency.id,
|
||||
refresh = true,
|
||||
)
|
||||
!isMultiCurrency && tokensFeatureToggles.isWalletBalanceFetcherEnabled ->
|
||||
walletBalanceFetcher(params = WalletBalanceFetcher.Params(userWalletId = userWallet.walletId))
|
||||
|
|
|
|||
|
|
@ -777,13 +777,7 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
|
||||
modelScope.launch(dispatchers.main) {
|
||||
listOf(
|
||||
async {
|
||||
fetchCurrencyStatusUseCase(
|
||||
userWalletId = userWalletId,
|
||||
id = cryptoCurrency.id,
|
||||
refresh = true,
|
||||
)
|
||||
},
|
||||
async { fetchCurrencyStatusUseCase(userWalletId = userWalletId, id = cryptoCurrency.id) },
|
||||
async {
|
||||
updateTxHistory(
|
||||
refresh = true,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.tangem.domain.settings.NeverToShowWalletsScrollPreview
|
|||
import com.tangem.domain.tokens.FetchCardTokenListUseCase
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.FetchTokenListUseCase
|
||||
import com.tangem.domain.tokens.FetchTokenListUseCase.RefreshMode
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
|
|
@ -140,7 +139,7 @@ internal class WalletClickIntents @Inject constructor(
|
|||
val maybeFetchResult = if (isSingleWalletWithToken) {
|
||||
fetchCardTokenListUseCase(userWalletId = userWallet.walletId, refresh = true)
|
||||
} else {
|
||||
fetchTokenListUseCase(userWalletId = userWallet.walletId, mode = RefreshMode.FULL)
|
||||
fetchTokenListUseCase(userWalletId = userWallet.walletId)
|
||||
}
|
||||
|
||||
maybeFetchResult.onLeft {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue