From bb32493ab0cc85a46537eb2ced39b4bb33a05cfe Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 16 Sep 2024 19:14:30 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/StakingDomainModule.kt | 12 ------ .../local/token/DefaultStakingBalanceStore.kt | 21 +++++++--- .../local/token/StakingBalanceStore.kt | 10 +++-- .../data/staking/DefaultStakingRepository.kt | 22 ++++++---- .../model/stakekit/YieldBalanceList.kt | 11 +++-- .../staking/GetStakingYieldBalanceUseCase.kt | 31 -------------- .../tokens/GetCurrencyStatusUpdatesUseCase.kt | 4 +- .../domain/tokens/GetNodlTokenListUseCase.kt | 2 +- .../domain/tokens/error/TokenListError.kt | 2 +- .../mapper/CurrencyStatusErrorMappers.kt | 1 + .../error/mapper/TokenListErrorMappers.kt | 1 + .../CurrenciesStatusesLceOperations.kt | 16 ++++++- .../CurrenciesStatusesOperations.kt | 42 ++++++++++++++++--- 13 files changed, 100 insertions(+), 75 deletions(-) delete mode 100644 domain/staking/src/main/java/com/tangem/domain/staking/GetStakingYieldBalanceUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt index 2c64513e3b..c6d4c83b91 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt @@ -74,18 +74,6 @@ internal object StakingDomainModule { ) } - @Provides - @Singleton - fun provideGetStakingYieldBalanceUseCase( - stakingRepository: StakingRepository, - stakingErrorResolver: StakingErrorResolver, - ): GetStakingYieldBalanceUseCase { - return GetStakingYieldBalanceUseCase( - stakingRepository = stakingRepository, - stakingErrorResolver = stakingErrorResolver, - ) - } - @Provides @Singleton fun provideInitializeStakingProcessUseCase( diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt index 008cdd1c0f..0e2ae15ec3 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt @@ -29,22 +29,31 @@ internal class DefaultStakingBalanceStore( } } - override fun get(userWalletId: UserWalletId, integrationId: String): Flow { + override fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow { return dataStore.get(userWalletId.stringValue) .mapNotNull { balances -> - balances.firstOrNull { it.integrationId == integrationId } + balances.firstOrNull { it.integrationId == integrationId && it.addresses.address == address } } } - override suspend fun getSyncOrNull(userWalletId: UserWalletId, integrationId: String): YieldBalanceWrapperDTO? { + override suspend fun getSyncOrNull( + userWalletId: UserWalletId, + address: String, + integrationId: String, + ): YieldBalanceWrapperDTO? { return dataStore.getSyncOrNull(userWalletId.stringValue) - ?.firstOrNull { it.integrationId == integrationId } + ?.firstOrNull { it.integrationId == integrationId && it.addresses.address == address } } - override suspend fun store(userWalletId: UserWalletId, integrationId: String, item: YieldBalanceWrapperDTO) { + override suspend fun store( + userWalletId: UserWalletId, + integrationId: String, + address: String, + item: YieldBalanceWrapperDTO, + ) { mutex.withLock { val balances = dataStore.getSyncOrNull(userWalletId.stringValue) - ?.addOrReplace(item) { it.integrationId == integrationId } + ?.addOrReplace(item) { it.integrationId == integrationId && it.addresses.address == address } ?: setOf(item) dataStore.store(userWalletId.stringValue, balances) diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt index 421f03dae1..601b11ccb0 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt @@ -12,9 +12,13 @@ interface StakingBalanceStore { suspend fun store(userWalletId: UserWalletId, items: Set) - fun get(userWalletId: UserWalletId, integrationId: String): Flow + fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow - suspend fun getSyncOrNull(userWalletId: UserWalletId, integrationId: String): YieldBalanceWrapperDTO? + suspend fun getSyncOrNull( + userWalletId: UserWalletId, + address: String, + integrationId: String, + ): YieldBalanceWrapperDTO? - suspend fun store(userWalletId: UserWalletId, integrationId: String, item: YieldBalanceWrapperDTO) + suspend fun store(userWalletId: UserWalletId, integrationId: String, address: String, item: YieldBalanceWrapperDTO) } \ No newline at end of file diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 6d22478790..efe1895104 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -37,7 +37,6 @@ import com.tangem.domain.staking.model.stakekit.NetworkType import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.staking.model.stakekit.YieldBalanceList -import com.tangem.domain.staking.model.stakekit.* import com.tangem.domain.staking.model.stakekit.action.StakingAction import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.domain.staking.model.stakekit.action.StakingActionType @@ -310,6 +309,7 @@ internal class DefaultStakingRepository( stakingBalanceStore.store( userWalletId, requestBody.integrationId, + address, YieldBalanceWrapperDTO( balances = result, integrationId = requestBody.integrationId, @@ -328,9 +328,10 @@ internal class DefaultStakingRepository( send(YieldBalance.Empty) } else { 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, integrationId) + stakingBalanceStore.get(userWalletId, address, integrationId) .collectLatest { send(yieldBalanceConverter.convert(it)) } @@ -354,9 +355,12 @@ internal class DefaultStakingRepository( } else { fetchSingleYieldBalance(userWalletId, cryptoCurrency) + val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty() + val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)] ?: error("Could not get integrationId") - val result = stakingBalanceStore.getSyncOrNull(userWalletId, integrationId) + + val result = stakingBalanceStore.getSyncOrNull(userWalletId, address, integrationId) ?: return@withContext YieldBalance.Error yieldBalanceConverter.convert(result) @@ -379,17 +383,19 @@ internal class DefaultStakingRepository( block = { val availableCurrencies = cryptoCurrencies .mapNotNull { currency -> - val address = walletManagersFacade.getDefaultAddress(userWalletId, currency.network) + val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network) val integrationId = integrationIdMap[getIntegrationKey(currency.id)] - if (integrationId != null && address != null) { - address to integrationId + if (integrationId != null) { + addresses to integrationId } else { null } } - .distinctBy { it.second } - .map { getBalanceRequestData(it.first, it.second) } + .flatMap { (addresses, integrationId) -> + addresses.map { address -> address to integrationId } + } + .map { getBalanceRequestData(it.first.value, it.second) } .ifEmpty { return@invokeOnExpire } val result = stakeKitApi.getMultipleYieldBalances(availableCurrencies).getOrThrow() diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalanceList.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalanceList.kt index 042aa9acbf..02f20f6e1c 100644 --- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalanceList.kt +++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalanceList.kt @@ -5,10 +5,13 @@ sealed class YieldBalanceList { data class Data( val balances: List, ) : YieldBalanceList() { - fun getBalance(rawCurrencyId: String?): YieldBalance { - return balances.firstOrNull { yield -> - (yield as? YieldBalance.Data)?.balance?.items - ?.any { rawCurrencyId == it.rawCurrencyId } == true + + fun getBalance(address: String?, rawCurrencyId: String?): YieldBalance { + return balances.firstOrNull { yieldBalance -> + val data = yieldBalance as? YieldBalance.Data + data?.balance?.items?.any { + address == data.address && rawCurrencyId == it.rawCurrencyId + } == true } ?: YieldBalance.Error } } diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingYieldBalanceUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingYieldBalanceUseCase.kt deleted file mode 100644 index 16d17d97ad..0000000000 --- a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingYieldBalanceUseCase.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tangem.domain.staking - -import arrow.core.Either -import arrow.core.left -import arrow.core.right -import com.tangem.domain.core.utils.EitherFlow -import com.tangem.domain.staking.model.stakekit.StakingError -import com.tangem.domain.staking.model.stakekit.YieldBalance -import com.tangem.domain.staking.repositories.StakingErrorResolver -import com.tangem.domain.staking.repositories.StakingRepository -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.wallets.models.UserWalletId -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.map - -class GetStakingYieldBalanceUseCase( - private val stakingRepository: StakingRepository, - private val stakingErrorResolver: StakingErrorResolver, -) { - - operator fun invoke( - userWalletId: UserWalletId, - cryptoCurrency: CryptoCurrency, - ): EitherFlow { - return stakingRepository.getSingleYieldBalanceFlow( - userWalletId = userWalletId, - cryptoCurrency = cryptoCurrency, - ).map> { it.right() } - .catch { emit(stakingErrorResolver.resolve(it).left()) } - } -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt index dceb8551cf..f74a62b2d4 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt @@ -44,7 +44,7 @@ class GetCurrencyStatusUpdatesUseCase( ): Flow> { return flow { emitAll( - getCurrency( + getCurrencyStatus( userWalletId = userWalletId, currencyId = currencyId, isSingleWalletWithTokens = isSingleWalletWithTokens, @@ -53,7 +53,7 @@ class GetCurrencyStatusUpdatesUseCase( }.flowOn(dispatchers.io) } - private suspend fun getCurrency( + private suspend fun getCurrencyStatus( userWalletId: UserWalletId, currencyId: CryptoCurrency.ID, isSingleWalletWithTokens: Boolean, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNodlTokenListUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNodlTokenListUseCase.kt index ae25bf7114..abbe7fa327 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNodlTokenListUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNodlTokenListUseCase.kt @@ -56,7 +56,7 @@ class GetNodlTokenListUseCase( stakingRepository = stakingRepository, ) - return operations.getNodlCurrencyStatusesFlow() + return operations.getCardCurrenciesStatusesFlow() .map { maybeCurrenciesStatuses -> maybeCurrenciesStatuses.mapLeft(CurrenciesStatusesOperations.Error::mapToTokenListError) } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/TokenListError.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/TokenListError.kt index 0a321a7874..5332319220 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/TokenListError.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/TokenListError.kt @@ -4,7 +4,7 @@ import com.tangem.domain.tokens.model.TokenList sealed class TokenListError { - object EmptyTokens : TokenListError() + data object EmptyTokens : TokenListError() data class UnableToSortTokenList(val unsortedTokenList: TokenList.Ungrouped) : TokenListError() diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/CurrencyStatusErrorMappers.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/CurrencyStatusErrorMappers.kt index 000588f24b..7fb8c805ca 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/CurrencyStatusErrorMappers.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/CurrencyStatusErrorMappers.kt @@ -10,6 +10,7 @@ internal fun CurrenciesStatusesOperations.Error.mapToCurrencyError(): CurrencySt is CurrenciesStatusesOperations.Error.EmptyNetworksStatuses, is CurrenciesStatusesOperations.Error.EmptyQuotes, is CurrenciesStatusesOperations.Error.EmptyCurrencies, + is CurrenciesStatusesOperations.Error.EmptyAddresses, is CurrenciesStatusesOperations.Error.UnableToCreateCurrencyStatus, -> CurrencyStatusError.UnableToCreateCurrency } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt index 4f918d6a79..5e4071d5b1 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt @@ -10,6 +10,7 @@ internal fun CurrenciesStatusesOperations.Error.mapToTokenListError(): TokenList is CurrenciesStatusesOperations.Error.EmptyNetworksStatuses, is CurrenciesStatusesOperations.Error.EmptyQuotes, is CurrenciesStatusesOperations.Error.EmptyCurrencies, + is CurrenciesStatusesOperations.Error.EmptyAddresses, is CurrenciesStatusesOperations.Error.UnableToCreateCurrencyStatus, is CurrenciesStatusesOperations.Error.EmptyYieldBalances, -> TokenListError.EmptyTokens diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesLceOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesLceOperations.kt index 8d97dc1a83..ff2271edbb 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesLceOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesLceOperations.kt @@ -73,6 +73,7 @@ internal class CurrenciesStatusesLceOperations( getQuotes(currenciesIds), getNetworksStatuses(userWalletId, networks), getYieldBalances(userWalletId, nonEmptyCurrencies), + ) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances -> val statuses = createCurrenciesStatuses( currencies = nonEmptyCurrencies, @@ -144,11 +145,15 @@ internal class CurrenciesStatusesLceOperations( currencies.map { currency -> val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId } val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network } + val address = extractAddress(networkStatus) val isStakingSupported = stakingRepository.isStakingSupported( stakingRepository.getIntegrationKey(currency.id), ) val yieldBalance = if (isStakingSupported) { - (yieldBalances as? YieldBalanceList.Data)?.getBalance(currency.id.rawCurrencyId) + (yieldBalances as? YieldBalanceList.Data)?.getBalance( + address = address, + rawCurrencyId = currency.id.rawCurrencyId, + ) } else { null } @@ -221,4 +226,13 @@ internal class CurrenciesStatusesLceOperations( return networks to currenciesIds } + + private fun extractAddress(networkStatus: NetworkStatus?): String? { + return when (val value = networkStatus?.value) { + is NetworkStatus.NoAccount -> value.address.defaultAddress.value + is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value + is NetworkStatus.Verified -> value.address.defaultAddress.value + else -> null + } + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt index a5cf2318cd..bea881092e 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt @@ -36,7 +36,12 @@ internal class CurrenciesStatusesOperations( networksRepository.getNetworkStatusesSync(userWalletId, networks, false).right() val yieldBalances = getYieldBalancesSync(nonEmptyCurrencies) - return createCurrenciesStatuses(nonEmptyCurrencies, quotes, networkStatuses, yieldBalances) + return createCurrenciesStatuses( + nonEmptyCurrencies, + quotes, + networkStatuses, + yieldBalances, + ) }, catch = { raise(Error.DataError(it)) }, ) @@ -115,8 +120,7 @@ internal class CurrenciesStatusesOperations( return createCurrencyStatus(currency, quotes, networkStatus, yieldBalances) } - /** Get flow of currency statuses for NODL card */ - fun getNodlCurrencyStatusesFlow(): Flow>> { + fun getCardCurrenciesStatusesFlow(): Flow>> { return flow { val nonEmptyCurrencies = recover( block = { getCurrenciesFromCard(userWalletId) }, @@ -147,12 +151,13 @@ internal class CurrenciesStatusesOperations( val currenciesFlow = combine( getQuotes(currenciesIds), getNetworksStatuses(networks), - ) { maybeQuotes, maybeNetworksStatuses -> + getYieldBalances(nonEmptyCurrencies), + ) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances -> createCurrenciesStatuses( currencies = nonEmptyCurrencies, maybeQuotes = maybeQuotes, maybeNetworkStatuses = maybeNetworksStatuses, - maybeYieldBalances = null, + maybeYieldBalances = maybeYieldBalances, ) } @@ -265,11 +270,16 @@ internal class CurrenciesStatusesOperations( currencies.map { currency -> val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId } val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network } + val address = extractAddress(networkStatus) + val isStakingSupported = stakingRepository.isStakingSupported( stakingRepository.getIntegrationKey(currency.id), ) val yieldBalance = if (isStakingSupported) { - (yieldBalances as? YieldBalanceList.Data)?.getBalance(currency.id.rawCurrencyId) + (yieldBalances as? YieldBalanceList.Data)?.getBalance( + address = address, + rawCurrencyId = currency.id.rawCurrencyId, + ) } else { null } @@ -393,6 +403,15 @@ internal class CurrenciesStatusesOperations( .onEmpty { emit(Error.EmptyNetworksStatuses.left()) } } + private fun getYieldBalances(cryptoCurrencies: List): Flow> { + return stakingRepository.getMultiYieldBalanceFlow( + userWalletId = userWalletId, + cryptoCurrencies = cryptoCurrencies, + ).map> { it.right() } + .catch { emit(Error.DataError(it).left()) } + .onEmpty { emit(Error.EmptyYieldBalances.left()) } + } + private suspend fun getYieldBalancesSync( cryptoCurrencies: List, ): Either { @@ -449,6 +468,15 @@ internal class CurrenciesStatusesOperations( return networks to currenciesIds } + private fun extractAddress(networkStatus: NetworkStatus?): String? { + return when (val value = networkStatus?.value) { + is NetworkStatus.NoAccount -> value.address.defaultAddress.value + is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value + is NetworkStatus.Verified -> value.address.defaultAddress.value + else -> null + } + } + sealed class Error { data object EmptyCurrencies : Error() @@ -457,6 +485,8 @@ internal class CurrenciesStatusesOperations( data object EmptyNetworksStatuses : Error() + data object EmptyAddresses : Error() + data object UnableToCreateCurrencyStatus : Error() data class DataError(val cause: Throwable) : Error()