Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-16 13:33:15 +03:00
parent b1c2f8d6e3
commit 4ed210cd90
16 changed files with 65 additions and 39 deletions

View file

@ -31,6 +31,7 @@ import com.tangem.domain.card.ScanCardProcessor
import com.tangem.domain.common.LogConfig
import com.tangem.domain.settings.repositories.AppRatingRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.WalletManagersRepository
@ -181,6 +182,9 @@ internal class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var walletManagersFacade: WalletManagersFacade
@Inject
lateinit var networksRepository: NetworksRepository
@Inject
lateinit var currenciesRepository: CurrenciesRepository
@ -290,6 +294,7 @@ internal class TapApplication : Application(), ImageLoaderFactory {
appCurrencyRepository = appCurrencyRepository,
walletManagersFacade = walletManagersFacade,
appStateHolder = appStateHolder,
networksRepository = networksRepository,
currenciesRepository = currenciesRepository,
appThemeModeRepository = appThemeModeRepository,
balanceHidingRepository = balanceHidingRepository,

View file

@ -35,7 +35,6 @@ internal object CustomTokenInteractorModule {
reduxStateHolder = reduxStateHolder,
),
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
reduxStateHolder = reduxStateHolder,
)
}
}

View file

@ -29,7 +29,6 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -39,14 +38,12 @@ import timber.log.Timber
* Default implementation of custom token interactor
*
* @property featureRepository feature repository
* @property reduxStateHolder redux state holder
*
[REDACTED_AUTHOR]
*/
class DefaultCustomTokenInteractor(
private val featureRepository: CustomTokenRepository,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val reduxStateHolder: AppStateHolder,
) : CustomTokenInteractor {
override suspend fun findToken(address: String, blockchain: Blockchain): FoundToken {
@ -57,28 +54,30 @@ class DefaultCustomTokenInteractor(
}
override suspend fun saveToken(customCurrency: CustomCurrency) {
val scanResponse = reduxStateHolder.scanResponse ?: return
val userWallet = getSelectedWalletSyncUseCase().fold(ifLeft = { return }, ifRight = { it })
val currency = Currency.fromCustomCurrency(customCurrency)
val isNeedToDerive = isNeedToDerive(scanResponse, currency)
val isNeedToDerive = isNeedToDerive(userWallet, currency)
if (isNeedToDerive) {
deriveMissingBlockchains(scanResponse = scanResponse, currencyList = listOf(currency)) {
submitAdd(scanResponse = it, currency = currency)
deriveMissingBlockchains(userWallet = userWallet, currencyList = listOf(currency)) {
submitAdd(userWallet = userWallet, currency = currency)
}
} else {
submitAdd(scanResponse, currency)
submitAdd(userWallet, currency)
}
}
private fun isNeedToDerive(scanResponse: ScanResponse, currency: Currency): Boolean {
private fun isNeedToDerive(userWallet: UserWallet, currency: Currency): Boolean {
val scanResponse = userWallet.scanResponse
return currency.derivationPath?.let { !scanResponse.hasDerivation(currency.blockchain, it) } ?: false
}
private suspend fun deriveMissingBlockchains(
scanResponse: ScanResponse,
userWallet: UserWallet,
currencyList: List<Currency>,
onSuccess: suspend (ScanResponse) -> Unit,
) {
val scanResponse = userWallet.scanResponse
val config = CardConfig.createConfig(scanResponse.card)
val derivationDataList = currencyList.mapNotNull { currency ->
val curve = config.primaryCurve(currency.blockchain)
@ -161,14 +160,15 @@ class DefaultCustomTokenInteractor(
return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
}
private suspend fun submitAdd(scanResponse: ScanResponse, currency: Currency) {
private suspend fun submitAdd(userWallet: UserWallet, currency: Currency) {
val scanResponse = userWallet.scanResponse
val walletFeatureToggles = store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles)
if (walletFeatureToggles.isRedesignedScreenEnabled) {
val cryptoCurrencyFactory = CryptoCurrencyFactory()
submitNewAdd(
userWalletId = getSelectedWalletSyncUseCase().fold(ifLeft = { return }, ifRight = UserWallet::walletId),
userWalletId = userWallet.walletId,
updatedScanResponse = scanResponse,
currencyList = listOfNotNull(
when (currency) {
@ -219,7 +219,7 @@ class DefaultCustomTokenInteractor(
currencyList: List<CryptoCurrency>,
) {
val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
val networksRepository = store.state.daggerGraphState.get(DaggerGraphState::networksRepository)
scope.launch {
userWalletsListManager.update(
userWalletId = userWalletId,
@ -227,6 +227,12 @@ class DefaultCustomTokenInteractor(
)
currenciesRepository.addCurrencies(userWalletId = userWalletId, currencies = currencyList)
val networks = currencyList.map { it.network }.toSet()
networksRepository.getNetworkStatusesSync(
userWalletId = userWalletId,
networks = networks,
refresh = true,
)
}
}
}

View file

@ -33,6 +33,7 @@ import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
@Suppress("LargeClass")
object TokensMiddleware {
val tokensMiddleware: Middleware<AppState> = { _, _ ->
@ -360,6 +361,7 @@ object TokensMiddleware {
currencyList: List<CryptoCurrency>,
) {
val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
val networksRepository = store.state.daggerGraphState.get(DaggerGraphState::networksRepository)
scope.launch {
userWalletsListManager.update(
@ -368,6 +370,12 @@ object TokensMiddleware {
)
currenciesRepository.addCurrencies(userWalletId = userWalletId, currencies = currencyList)
val networks = currencyList.map { it.network }.toSet()
networksRepository.getNetworkStatusesSync(
userWalletId = userWalletId,
networks = networks,
refresh = true,
)
}
}

View file

@ -20,6 +20,7 @@ import com.tangem.domain.common.util.hasDerivation
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.lib.crypto.DerivationManager
import com.tangem.lib.crypto.models.Currency
@ -42,6 +43,7 @@ import com.tangem.tap.features.wallet.models.Currency as WalletModelCurrency
class DerivationManagerImpl(
private val appStateHolder: AppStateHolder,
private val currenciesRepository: CurrenciesRepository,
private val networksRepository: NetworksRepository,
) : DerivationManager {
override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation ->
@ -155,16 +157,20 @@ class DerivationManagerImpl(
derivationPath: String,
derivationStyleProvider: DerivationStyleProvider,
) {
val cryptoCurrency = convertCurrency(
blockchain = blockchain,
currency = currency,
derivationPath = derivationPath,
derivationStyleProvider = derivationStyleProvider,
)
currenciesRepository.addCurrencies(
userWalletId,
listOf(
convertCurrency(
blockchain = blockchain,
currency = currency,
derivationPath = derivationPath,
derivationStyleProvider = derivationStyleProvider,
),
),
listOf(cryptoCurrency),
)
networksRepository.getNetworkStatusesSync(
userWalletId = userWalletId,
networks = setOf(cryptoCurrency.network),
refresh = true,
)
}

View file

@ -7,6 +7,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
@ -70,10 +71,12 @@ class ProxyModule {
fun provideDerivationManager(
appStateHolder: AppStateHolder,
currenciesRepository: CurrenciesRepository,
networksRepository: NetworksRepository,
): DerivationManager {
return DerivationManagerImpl(
appStateHolder = appStateHolder,
currenciesRepository = currenciesRepository,
networksRepository = networksRepository,
)
}

View file

@ -9,6 +9,7 @@ import com.tangem.domain.card.ScanCardProcessor
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.features.tester.api.TesterRouter
@ -44,6 +45,7 @@ data class DaggerGraphState(
val balanceHidingRepository: BalanceHidingRepository? = null,
val detailsFeatureToggles: DetailsFeatureToggles? = null,
val walletsRepository: WalletsRepository? = null,
val networksRepository: NetworksRepository? = null,
// FIXME: It is used only for TokensList screen. Remove after refactoring of TokensList
val currenciesRepository: CurrenciesRepository? = null,

View file

@ -56,12 +56,6 @@ data class CryptoCurrencyStatus(
override val fiatRate: BigDecimal?,
) : Status(isError = true)
/** Represents a state where the cryptocurrency's network amount not found. */
data class NoAmount(
override val priceChange: BigDecimal?,
override val fiatRate: BigDecimal?,
) : Status(isError = true)
/** Represents a state where the cryptocurrency's derivation is missed. */
data class MissedDerivation(
override val priceChange: BigDecimal?,

View file

@ -142,8 +142,7 @@ internal class CurrenciesStatusesOperations(
suspend fun getNetworkCoinForSingleWalletWithTokenFlow(
networkId: Network.ID,
): Flow<Either<Error,
CryptoCurrencyStatus,>,> {
): Flow<Either<Error, CryptoCurrencyStatus>> {
val currency = recover(
block = { getNetworkCoinForSingleWalletWithToken(networkId) },
recover = { return flowOf(it.left()) },

View file

@ -40,7 +40,7 @@ internal class CurrencyStatusOperations(
private fun createStatus(status: NetworkStatus.Verified): CryptoCurrencyStatus.Status {
val amount = status.amounts[currency.id]
?: return CryptoCurrencyStatus.NoAmount(priceChange = quote?.priceChange, fiatRate = quote?.fiatRate)
?: return CryptoCurrencyStatus.Loading
val hasCurrentNetworkTransactions = status.pendingTransactions.isNotEmpty()
val currentTransactions = status.pendingTransactions.getOrElse(currency.id, ::emptySet)

View file

@ -22,7 +22,6 @@ internal class TokenListFiatBalanceOperations(
}
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.NoAmount,
-> {
fiatBalance = TokenList.FiatBalance.Failed
break

View file

@ -2,6 +2,7 @@ package com.tangem.feature.swap.domain
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.feature.swap.domain.cache.SwapDataCache
@ -30,6 +31,7 @@ internal class SwapInteractorImpl @Inject constructor(
private val cache: SwapDataCache,
private val allowPermissionsHandler: AllowPermissionsHandler,
private val currenciesRepository: CurrenciesRepository,
private val networksRepository: NetworksRepository,
private val walletFeatureToggles: WalletFeatureToggles,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
) : SwapInteractor {
@ -279,10 +281,15 @@ internal class SwapInteractorImpl @Inject constructor(
}
private suspend fun getAndAddCryptoCurrency(userWallet: UserWallet, currency: Currency, network: Network) {
repository.getCryptoCurrency(userWallet, currency, network)?.let {
repository.getCryptoCurrency(userWallet, currency, network)?.let { cryptoCurrency ->
currenciesRepository.addCurrencies(
userWallet.walletId,
listOf(it),
listOf(cryptoCurrency),
)
networksRepository.getNetworkStatusesSync(
userWalletId = userWallet.walletId,
networks = setOf(cryptoCurrency.network),
refresh = true,
)
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.feature.swap.domain.di
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.wallets.legacy.WalletsStateHolder
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.feature.swap.domain.*
@ -26,6 +27,7 @@ class SwapDomainModule {
userWalletManager: UserWalletManager,
transactionManager: TransactionManager,
currenciesRepository: CurrenciesRepository,
networksRepository: NetworksRepository,
walletFeatureToggles: WalletFeatureToggles,
@SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
): SwapInteractor {
@ -36,6 +38,7 @@ class SwapDomainModule {
cache = SwapDataCacheImpl(),
allowPermissionsHandler = AllowPermissionsHandlerImpl(),
currenciesRepository = currenciesRepository,
networksRepository = networksRepository,
walletFeatureToggles = walletFeatureToggles,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
)

View file

@ -74,7 +74,6 @@ internal class TokenDetailsLoadedBalanceConverter(
is CryptoCurrencyStatus.Loading -> TokenDetailsBalanceBlockState.Loading(currentState.actionButtons)
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.NoAmount,
is CryptoCurrencyStatus.Unreachable,
-> TokenDetailsBalanceBlockState.Error(currentState.actionButtons)
}
@ -91,7 +90,6 @@ internal class TokenDetailsLoadedBalanceConverter(
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.NoAccount,
is CryptoCurrencyStatus.NoAmount,
is CryptoCurrencyStatus.Unreachable,
-> MarketPriceBlockState.Content(
currencySymbol = currencySymbol,

View file

@ -71,7 +71,6 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.NoAccount,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.NoAmount,
-> MarketPriceBlockState.Error(currencyName)
}
}
@ -113,7 +112,6 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
is CryptoCurrencyStatus.NoAccount,
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.NoAmount,
-> {
WalletCardState.Error(
id = selectedWallet.id,

View file

@ -28,7 +28,6 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
-> value.mapToTokenItemState()
is CryptoCurrencyStatus.MissedDerivation -> value.mapToNoAddressTokenItemState()
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.NoAmount,
-> value.mapToUnreachableTokenItemState()
}
}