From 32ced9df85d29e6832168fd8584d8cd61c03e1b6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 9 Oct 2023 13:28:33 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../repository/DefaultCurrenciesRepository.kt | 18 +++++----- .../utils/ResponseCryptoCurrenciesFactory.kt | 7 ++-- .../tokens/FetchCurrencyStatusUseCase.kt | 7 ++-- .../domain/tokens/GetCryptoCurrencyUseCase.kt | 8 +++-- .../tokens/GetCurrencyStatusUpdatesUseCase.kt | 8 +++-- .../tokens/GetCurrencyWarningsUseCase.kt | 7 ++-- .../tokens/GetNetworkCoinStatusUseCase.kt | 5 ++- .../CurrenciesStatusesOperations.kt | 34 ++++++++++++++----- .../tokens/repository/CurrenciesRepository.kt | 14 ++++++-- .../repository/MockCurrenciesRepository.kt | 7 +++- .../viewmodels/TokenDetailsViewModel.kt | 4 +++ .../wallet/viewmodels/WalletViewModel.kt | 1 + 12 files changed, 87 insertions(+), 33 deletions(-) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt index fa5f16dbf1..661dd32011 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt @@ -186,6 +186,7 @@ internal class DefaultCurrenciesRepository( override suspend fun getMultiCurrencyWalletCurrency( userWalletId: UserWalletId, id: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): CryptoCurrency = withContext(dispatchers.io) { val userWallet = getUserWallet(userWalletId) ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true) @@ -194,10 +195,14 @@ internal class DefaultCurrenciesRepository( "Unable to find tokens response for user wallet with provided ID: $userWalletId" } - responseCurrenciesFactory.createCurrency(id, response, userWallet.scanResponse) + responseCurrenciesFactory.createCurrency(id, response, userWallet.scanResponse, derivationPath.value) } - override suspend fun getNetworkCoin(userWalletId: UserWalletId, networkId: Network.ID): CryptoCurrency.Coin { + override suspend fun getNetworkCoin( + userWalletId: UserWalletId, + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): CryptoCurrency.Coin { val userWallet = getUserWallet(userWalletId) ensureIsCorrectUserWallet(userWallet = userWallet, isMultiCurrencyWalletExpected = true) @@ -207,15 +212,12 @@ internal class DefaultCurrenciesRepository( "Unable to find tokens response for user wallet with provided ID: $userWalletId" } val blockchain = Blockchain.fromId(networkId.value) - val derivationPath = blockchain - .derivationPath(userWallet.scanResponse.derivationStyleProvider.getDerivationStyle()) - ?.rawPath + val blockchainNetworkId = blockchain.toNetworkId() + val coinId = blockchain.toCoinId() val storedCoin = storedTokens.tokens .find { - it.networkId == blockchain.toNetworkId() && - it.id == blockchain.toCoinId() && - it.derivationPath == derivationPath + it.networkId == blockchainNetworkId && it.id == coinId && it.derivationPath == derivationPath.value } ?: error("Coin in this network $networkId not found") val coin = responseCurrenciesFactory.createCurrency(storedCoin, userWallet.scanResponse) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt index 27afcb1c84..3274fb2221 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt @@ -20,13 +20,10 @@ internal class ResponseCryptoCurrenciesFactory(private val demoConfig: DemoConfi currencyId: CryptoCurrency.ID, response: UserTokensResponse, scanResponse: ScanResponse, + derivationPath: String?, ): CryptoCurrency { val responseTokenId = currencyId.rawCurrencyId - val blockchain = Blockchain.fromId(currencyId.rawNetworkId) - val networkId = blockchain.toNetworkId() - val derivationPath = blockchain - .derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle()) - ?.rawPath + val networkId = Blockchain.fromId(currencyId.rawNetworkId).toNetworkId() val token = requireNotNull( value = response.tokens diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCurrencyStatusUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCurrencyStatusUseCase.kt index eeeea7c9ec..7b5c4de6fb 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCurrencyStatusUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCurrencyStatusUseCase.kt @@ -36,16 +36,18 @@ class FetchCurrencyStatusUseCase( * * @param userWalletId The ID of the user's wallet. * @param id The ID of the cryptocurrency. + * @param derivationPath currency derivation path. * @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, + derivationPath: Network.DerivationPath, refresh: Boolean = false, ): Either { return either { - val currency = getCurrency(userWalletId, id) + val currency = getCurrency(userWalletId, id, derivationPath) fetchCurrencyStatus(userWalletId, currency, refresh) } @@ -87,8 +89,9 @@ class FetchCurrencyStatusUseCase( private suspend fun Raise.getCurrency( userWalletId: UserWalletId, id: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): CryptoCurrency { - return catch({ currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id) }) { + return catch({ currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id, derivationPath) }) { raise(CurrencyStatusError.DataError(it)) } } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt index 194ffc0416..ae9b7f6326 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt @@ -6,6 +6,7 @@ import arrow.core.raise.catch import arrow.core.raise.either import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.wallets.models.UserWalletId @@ -18,13 +19,15 @@ class GetCryptoCurrencyUseCase( * * @param userWalletId The ID of the user's wallet. * @param id The ID of the cryptocurrency. + * @param derivationPath currency derivation path. * @return An [Either] representing success (Right) or an error (Left) in fetching the status. */ suspend operator fun invoke( userWalletId: UserWalletId, id: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): Either { - return either { getCurrency(userWalletId, id) } + return either { getCurrency(userWalletId, id, derivationPath) } } /** @@ -40,9 +43,10 @@ class GetCryptoCurrencyUseCase( private suspend fun Raise.getCurrency( userWalletId: UserWalletId, id: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): CryptoCurrency { return catch( - block = { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id) }, + block = { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id, derivationPath) }, catch = { raise(CurrencyStatusError.DataError(it)) }, ) } 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 d018b74e85..f575854cc6 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 @@ -5,6 +5,7 @@ import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.error.mapper.mapToCurrencyError import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository @@ -32,20 +33,23 @@ class GetCurrencyStatusUpdatesUseCase( * * @param userWalletId The unique identifier of the user's wallet. * @param currencyId The unique identifier of the cryptocurrency. + * @param derivationPath currency derivation path. * @return A [Flow] emitting either a [CurrencyStatusError] or a [CryptoCurrencyStatus], indicating the result of the fetch operation. */ operator fun invoke( userWalletId: UserWalletId, currencyId: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): Flow> { return flow { - emitAll(getCurrency(userWalletId, currencyId)) + emitAll(getCurrency(userWalletId, currencyId, derivationPath)) }.flowOn(dispatchers.io) } private suspend fun getCurrency( userWalletId: UserWalletId, currencyId: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): Flow> { val operations = CurrenciesStatusesOperations( currenciesRepository = currenciesRepository, @@ -54,7 +58,7 @@ class GetCurrencyStatusUpdatesUseCase( userWalletId = userWalletId, ) - return operations.getCurrencyStatusFlow(currencyId).map { maybeCurrency -> + return operations.getCurrencyStatusFlow(currencyId, derivationPath).map { maybeCurrency -> maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError) } } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index d11e7b8f93..994eda5490 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -24,12 +24,14 @@ class GetCurrencyWarningsUseCase( suspend operator fun invoke( userWalletId: UserWalletId, currency: CryptoCurrency, + derivationPath: Network.DerivationPath, ): Flow> { return combine( getFeeWarningFlow( userWalletId = userWalletId, networkId = currency.network.id, currencyId = currency.id, + derivationPath = derivationPath, ), flowOf(walletManagersFacade.getRentInfo(userWalletId, currency.network)), flowOf(walletManagersFacade.getExistentialDeposit(userWalletId, currency.network)), @@ -51,6 +53,7 @@ class GetCurrencyWarningsUseCase( userWalletId: UserWalletId, networkId: Network.ID, currencyId: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): Flow { val operations = CurrenciesStatusesOperations( currenciesRepository = currenciesRepository, @@ -60,8 +63,8 @@ class GetCurrencyWarningsUseCase( ) return combine( - operations.getCurrencyStatusFlow(currencyId).map { it.getOrNull() }, - operations.getNetworkCoinFlow(networkId).map { it.getOrNull() }, + operations.getCurrencyStatusFlow(currencyId, derivationPath).map { it.getOrNull() }, + operations.getNetworkCoinFlow(networkId, derivationPath).map { it.getOrNull() }, ) { tokenStatus, coinStatus -> when { tokenStatus != null && coinStatus != null -> { diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt index 999d6e15af..44ca1e09cc 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt @@ -23,12 +23,14 @@ class GetNetworkCoinStatusUseCase( operator fun invoke( userWalletId: UserWalletId, networkId: Network.ID, + derivationPath: Network.DerivationPath, ): Flow> { return flow { emitAll( flow = getCurrency( userWalletId = userWalletId, networkId = networkId, + derivationPath = derivationPath, ), ) } @@ -38,6 +40,7 @@ class GetNetworkCoinStatusUseCase( private suspend fun getCurrency( userWalletId: UserWalletId, networkId: Network.ID, + derivationPath: Network.DerivationPath, ): Flow> { val operations = CurrenciesStatusesOperations( currenciesRepository = currenciesRepository, @@ -46,7 +49,7 @@ class GetNetworkCoinStatusUseCase( userWalletId = userWalletId, ) - return operations.getNetworkCoinFlow(networkId).map { maybeCurrency -> + return operations.getNetworkCoinFlow(networkId, derivationPath).map { maybeCurrency -> maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError) } } 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 fc4ec95f89..4271ce732e 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 @@ -67,18 +67,24 @@ internal class CurrenciesStatusesOperations( } } - suspend fun getCurrencyStatusFlow(currencyId: CryptoCurrency.ID): Flow> { + suspend fun getCurrencyStatusFlow( + currencyId: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, + ): Flow> { val currency = recover( - block = { getMultiCurrencyWalletCurrency(currencyId) }, + block = { getMultiCurrencyWalletCurrency(currencyId, derivationPath) }, recover = { return flowOf(it.left()) }, ) return getCurrencyStatusFlow(currency) } - suspend fun getNetworkCoinFlow(networkId: Network.ID): Flow> { + suspend fun getNetworkCoinFlow( + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): Flow> { val currency = recover( - block = { getNetworkCoin(networkId) }, + block = { getNetworkCoin(networkId, derivationPath) }, recover = { return flowOf(it.left()) }, ) @@ -178,14 +184,26 @@ internal class CurrenciesStatusesOperations( .onEmpty { emit(Error.EmptyCurrencies.left()) } } - private suspend fun Raise.getMultiCurrencyWalletCurrency(currencyId: CryptoCurrency.ID): CryptoCurrency { - return Either.catch { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, currencyId) } + private suspend fun Raise.getMultiCurrencyWalletCurrency( + currencyId: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, + ): CryptoCurrency { + return Either.catch { + currenciesRepository.getMultiCurrencyWalletCurrency( + userWalletId, + currencyId, + derivationPath, + ) + } .mapLeft { Error.DataError(it) } .bind() } - private suspend fun Raise.getNetworkCoin(networkId: Network.ID): CryptoCurrency { - return Either.catch { currenciesRepository.getNetworkCoin(userWalletId, networkId) } + private suspend fun Raise.getNetworkCoin( + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): CryptoCurrency { + return Either.catch { currenciesRepository.getNetworkCoin(userWalletId, networkId, derivationPath) } .mapLeft { Error.DataError(it) } .bind() } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt index 5554ee3990..2973c698f6 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt @@ -98,19 +98,29 @@ interface CurrenciesRepository { * * @param userWalletId The unique identifier of the user wallet. * @param id The unique identifier of the cryptocurrency to be retrieved. + * @param derivationPath currency derivation path. * @return The cryptocurrency associated with the user wallet and ID. * @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet * ID provided. */ - suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: CryptoCurrency.ID): CryptoCurrency + suspend fun getMultiCurrencyWalletCurrency( + userWalletId: UserWalletId, + id: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, + ): CryptoCurrency /** * Get the coin for a specific network. * * @param userWalletId The unique identifier of the user wallet. * @param networkId The unique identifier of the network. + * @param derivationPath currency derivation path. */ - suspend fun getNetworkCoin(userWalletId: UserWalletId, networkId: Network.ID): CryptoCurrency.Coin + suspend fun getNetworkCoin( + userWalletId: UserWalletId, + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): CryptoCurrency.Coin /** * Determines whether the tokens within a specific multi-currency user wallet are grouped. diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt index 8cdec88feb..c50ee469db 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt @@ -67,6 +67,7 @@ internal class MockCurrenciesRepository( override suspend fun getMultiCurrencyWalletCurrency( userWalletId: UserWalletId, id: CryptoCurrency.ID, + derivationPath: Network.DerivationPath, ): CryptoCurrency { val token = token.getOrElse { e -> throw e } @@ -75,7 +76,11 @@ internal class MockCurrenciesRepository( return token } - override suspend fun getNetworkCoin(userWalletId: UserWalletId, networkId: Network.ID): CryptoCurrency.Coin { + override suspend fun getNetworkCoin( + userWalletId: UserWalletId, + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): CryptoCurrency.Coin { TODO("Not yet implemented") } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index fcb13d0d4c..bbf6300015 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -140,6 +140,7 @@ internal class TokenDetailsViewModel @Inject constructor( getCurrencyWarningsUseCase.invoke( userWalletId = selectedWallet.walletId, currency = cryptoCurrency, + derivationPath = cryptoCurrency.network.derivationPath, ) .distinctUntilChanged() .onEach { uiState = stateFactory.getStateWithNotifications(it) } @@ -151,6 +152,7 @@ internal class TokenDetailsViewModel @Inject constructor( getCurrencyStatusUpdatesUseCase( userWalletId = selectedWallet.walletId, currencyId = cryptoCurrency.id, + derivationPath = cryptoCurrency.network.derivationPath, ) .distinctUntilChanged() .onEach { either -> @@ -247,6 +249,7 @@ internal class TokenDetailsViewModel @Inject constructor( getNetworkCoinStatusUseCase( userWalletId = wallet.walletId, networkId = status.currency.network.id, + derivationPath = status.currency.network.derivationPath, ) .take(count = 1) .collectLatest { @@ -373,6 +376,7 @@ internal class TokenDetailsViewModel @Inject constructor( fetchCurrencyStatusUseCase.invoke( userWalletId = wallet.walletId, id = cryptoCurrency.id, + derivationPath = cryptoCurrency.network.derivationPath, refresh = true, ) }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 850c1aeef3..0705092df8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -579,6 +579,7 @@ internal class WalletViewModel @Inject constructor( getNetworkCoinStatusUseCase( userWalletId = userWallet.walletId, networkId = cryptoCurrencyStatus.currency.network.id, + derivationPath = cryptoCurrencyStatus.currency.network.derivationPath, ) .take(count = 1) .collectLatest {