Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-17 10:37:51 +04:00
parent 321b764887
commit 33f9a0d452
21 changed files with 280 additions and 157 deletions

View file

@ -0,0 +1,113 @@
package com.tangem.data.express
import arrow.core.Either
import arrow.core.raise.either
import com.tangem.data.express.converter.ExpressAssetConverter
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.express.TangemExpressApi
import com.tangem.datasource.api.express.models.request.AssetsRequestBody
import com.tangem.datasource.api.express.models.request.LeastTokenInfo
import com.tangem.datasource.exchangeservice.swap.ExpressUtils.getRefCode
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.token.ExpressAssetsStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.utils.catchOn
import com.tangem.domain.core.utils.lceContent
import com.tangem.domain.core.utils.lceError
import com.tangem.domain.core.utils.lceLoading
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.express.models.ExpressAsset
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.update
import timber.log.Timber
import javax.inject.Inject
typealias InitializationStatusFlow = MutableStateFlow<Lce<Throwable, List<ExpressAsset>>>
/**
* Default implementation of [ExpressServiceFetcher]
*
* @property tangemExpressApi express api
* @property expressAssetsStore local storage
*
[REDACTED_AUTHOR]
*/
internal class DefaultExpressServiceFetcher @Inject constructor(
private val tangemExpressApi: TangemExpressApi,
private val expressAssetsStore: ExpressAssetsStore,
private val appPreferencesStore: AppPreferencesStore,
private val userWalletsStore: UserWalletsStore,
private val dispatchers: CoroutineDispatcherProvider,
) : ExpressServiceFetcher {
private val initializationStatuses =
MutableStateFlow<Map<UserWalletId, InitializationStatusFlow>>(value = emptyMap())
override suspend fun fetch(userWalletId: UserWalletId, assetIds: Set<ExpressAsset.ID>): Either<Throwable, Unit> =
either {
val userWallet = arrow.core.raise.catch(
block = { userWalletsStore.getSyncStrict(userWalletId) },
catch = ::raise,
)
fetch(userWallet = userWallet, assetIds = assetIds).bind()
}
override suspend fun fetch(userWallet: UserWallet, assetIds: Set<ExpressAsset.ID>): Either<Throwable, Unit> {
return Either.catchOn(dispatchers.io) {
val initializationStatus = getInitializationStatusInternal(userWallet.walletId)
try {
if (assetIds.isNotEmpty()) {
val tokenList = assetIds.map {
LeastTokenInfo(contractAddress = it.contractAddress, network = it.networkId)
}
val response = tangemExpressApi.getAssets(
userWalletId = userWallet.walletId.stringValue,
refCode = getRefCode(userWallet, appPreferencesStore),
body = AssetsRequestBody(tokensList = tokenList),
).getOrThrow()
expressAssetsStore.store(userWallet.walletId, response)
val expressAssets = ExpressAssetConverter.convertList(response)
initializationStatus.update { expressAssets.lceContent() }
}
} catch (e: Throwable) {
if (expressAssetsStore.getSyncOrNull(userWallet.walletId) == null) {
initializationStatus.update { e.lceError() }
}
Timber.e(e, "Unable to fetch assets for: ${userWallet.walletId.stringValue}")
throw e
}
}
}
override fun getInitializationStatus(userWalletId: UserWalletId): Flow<Lce<Throwable, List<ExpressAsset>>> {
return flow { getInitializationStatusInternal(userWalletId).collect { emit(it) } }
}
@Suppress("SuspendFunWithFlowReturnType")
private suspend fun getInitializationStatusInternal(userWalletId: UserWalletId): InitializationStatusFlow {
val initializationStatus = initializationStatuses.value[userWalletId]
if (initializationStatus != null) return initializationStatus
val cached = expressAssetsStore.getSyncOrNull(userWalletId)?.let(ExpressAssetConverter::convertList)
val default: InitializationStatusFlow = MutableStateFlow(value = cached?.lceContent() ?: lceLoading())
initializationStatuses.update { statuses ->
statuses.toMutableMap().apply {
put(key = userWalletId, value = default)
}
}
return default
}
}

View file

@ -0,0 +1,24 @@
package com.tangem.data.express.converter
import com.tangem.datasource.api.express.models.response.Asset
import com.tangem.domain.express.models.ExpressAsset
import com.tangem.utils.converter.Converter
/**
* Converts an [Asset] from the data layer to an [ExpressAsset] in the domain layer.
*
[REDACTED_AUTHOR]
*/
internal object ExpressAssetConverter : Converter<Asset, ExpressAsset> {
override fun convert(value: Asset): ExpressAsset {
return ExpressAsset(
id = ExpressAsset.ID(
networkId = value.network,
contractAddress = value.contractAddress,
),
isExchangeAvailable = value.exchangeAvailable,
isOnrampAvailable = value.onrampAvailable,
)
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.data.express.di
import com.squareup.moshi.Moshi
import com.tangem.data.express.DefaultExpressRepository
import com.tangem.data.express.DefaultExpressServiceFetcher
import com.tangem.data.express.converter.ExpressErrorConverter
import com.tangem.data.express.error.DefaultExpressErrorResolver
import com.tangem.datasource.api.express.TangemExpressApi
@ -10,6 +11,7 @@ import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.express.ExpressErrorResolver
import com.tangem.domain.express.ExpressRepository
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -43,4 +45,10 @@ internal object ExpressDataModule {
dispatchers = dispatchers,
)
}
@Provides
@Singleton
fun provideExpressServiceFetcher(impl: DefaultExpressServiceFetcher): ExpressServiceFetcher {
return impl
}
}

View file

@ -29,6 +29,7 @@ dependencies {
implementation(projects.domain.walletManager)
implementation(projects.domain.appTheme.models)
implementation(projects.domain.models)
implementation(projects.domain.express.models)
// region DI

View file

@ -12,7 +12,6 @@ import com.tangem.data.onramp.converters.error.OnrampErrorConverter
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.express.TangemExpressApi
import com.tangem.datasource.api.express.models.TangemExpressValues
import com.tangem.datasource.api.express.models.response.ExchangeProvider
import com.tangem.datasource.api.express.models.response.ExchangeProviderType
import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
@ -38,6 +37,7 @@ import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObject
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
import com.tangem.datasource.local.preferences.utils.storeObject
import com.tangem.domain.express.models.ExpressAsset
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
@ -560,7 +560,7 @@ internal class DefaultOnrampRepository(
}
private fun CryptoCurrency.getContractAddress(): String = when (this) {
is CryptoCurrency.Coin -> TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
is CryptoCurrency.Coin -> ExpressAsset.EMPTY_CONTRACT_ADDRESS_VALUE
is CryptoCurrency.Token -> this.contractAddress
}

View file

@ -28,6 +28,7 @@ dependencies {
implementation(projects.domain.card)
implementation(projects.domain.core)
implementation(projects.domain.demo)
implementation(projects.domain.express)
implementation(projects.domain.legacy)
implementation(projects.domain.models)
implementation(projects.domain.staking)

View file

@ -7,15 +7,14 @@ import com.tangem.data.common.currency.UserTokensResponseFactory
import com.tangem.data.common.currency.UserTokensSaver
import com.tangem.data.tokens.utils.CustomTokensMerger
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
import com.tangem.datasource.api.express.models.request.LeastTokenInfo
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.core.utils.catchOn
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.express.models.ExpressAsset
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher
@ -32,7 +31,7 @@ import timber.log.Timber
* @property userTokensResponseStore store of [UserTokensResponse]
* @property userTokensSaver user tokens saver
* @property cardCryptoCurrencyFactory factory for creating crypto currencies for specified card
* @property expressServiceLoader express service loader
* @property expressServiceFetcher express service loader
* @property dispatchers dispatchers
*
[REDACTED_AUTHOR]
@ -46,7 +45,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
private val userTokensResponseStore: UserTokensResponseStore,
private val userTokensSaver: UserTokensSaver,
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory,
private val expressServiceLoader: ExpressServiceLoader,
private val expressServiceFetcher: ExpressServiceFetcher,
private val dispatchers: CoroutineDispatcherProvider,
) : MultiWalletCryptoCurrenciesFetcher {
@ -109,14 +108,14 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
}
private suspend fun fetchExpressAssetsByNetworkIds(userWallet: UserWallet, userTokens: UserTokensResponse) {
val tokens = userTokens.tokens.map { token ->
LeastTokenInfo(
contractAddress = token.contractAddress ?: EMPTY_CONTRACT_ADDRESS_VALUE,
network = token.networkId,
val tokens = userTokens.tokens.mapTo(hashSetOf()) { token ->
ExpressAsset.ID(
networkId = token.networkId,
contractAddress = token.contractAddress,
)
}
expressServiceLoader.update(userWallet = userWallet, userTokens = tokens)
expressServiceFetcher.fetch(userWallet = userWallet, assetIds = tokens)
}
private fun createDefaultUserTokensResponse(userWallet: UserWallet): UserTokensResponse {

View file

@ -7,11 +7,11 @@ import com.tangem.data.tokens.AccountListCryptoCurrenciesFetcher
import com.tangem.data.tokens.DefaultMultiWalletCryptoCurrenciesFetcher
import com.tangem.data.tokens.utils.CustomTokensMerger
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
@ -33,7 +33,7 @@ internal class MultiWalletCryptoCurrenciesFetcherModule {
userTokensResponseStore: UserTokensResponseStore,
userTokensSaver: UserTokensSaver,
cardCryptoCurrencyFactory: CardCryptoCurrencyFactory,
expressServiceLoader: ExpressServiceLoader,
expressServiceFetcher: ExpressServiceFetcher,
walletAccountsFetcher: WalletAccountsFetcher,
dispatchers: CoroutineDispatcherProvider,
): MultiWalletCryptoCurrenciesFetcher {
@ -56,7 +56,7 @@ internal class MultiWalletCryptoCurrenciesFetcherModule {
userTokensResponseStore = userTokensResponseStore,
userTokensSaver = userTokensSaver,
cardCryptoCurrencyFactory = cardCryptoCurrencyFactory,
expressServiceLoader = expressServiceLoader,
expressServiceFetcher = expressServiceFetcher,
dispatchers = dispatchers,
)
}

View file

@ -5,22 +5,14 @@ import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.common.currency.CardCryptoCurrencyFactory
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.common.currency.UserTokensSaver
import com.tangem.data.tokens.repository.DefaultCurrenciesRepository
import com.tangem.data.tokens.repository.DefaultCurrencyChecksRepository
import com.tangem.data.tokens.repository.DefaultPolkadotAccountHealthCheckRepository
import com.tangem.data.tokens.repository.DefaultTokenReceiveWarningsViewedRepository
import com.tangem.data.tokens.repository.DefaultYieldSupplyWarningsViewedRepository
import com.tangem.data.tokens.repository.*
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.token.TokenReceiveWarningActionStore
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.tokens.repository.*
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
@ -42,7 +34,7 @@ internal object TokensDataModule {
walletManagersFacade: WalletManagersFacade,
cacheRegistry: CacheRegistry,
dispatchers: CoroutineDispatcherProvider,
expressServiceLoader: ExpressServiceLoader,
expressServiceFetcher: ExpressServiceFetcher,
excludedBlockchains: ExcludedBlockchains,
cardCryptoCurrencyFactory: CardCryptoCurrencyFactory,
tokensSaver: UserTokensSaver,
@ -54,7 +46,7 @@ internal object TokensDataModule {
walletManagersFacade = walletManagersFacade,
cacheRegistry = cacheRegistry,
userTokensResponseStore = userTokensResponseStore,
expressServiceLoader = expressServiceLoader,
expressServiceFetcher = expressServiceFetcher,
dispatchers = dispatchers,
excludedBlockchains = excludedBlockchains,
cardCryptoCurrencyFactory = cardCryptoCurrencyFactory,

View file

@ -10,17 +10,16 @@ import com.tangem.data.common.currency.*
import com.tangem.data.tokens.utils.CustomTokensMerger
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
import com.tangem.datasource.api.express.models.request.LeastTokenInfo
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.card.CardTypesResolver
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.core.error.DataError
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.express.models.ExpressAsset
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
@ -40,7 +39,7 @@ internal class DefaultCurrenciesRepository(
private val userWalletsStore: UserWalletsStore,
private val walletManagersFacade: WalletManagersFacade,
private val cacheRegistry: CacheRegistry,
private val expressServiceLoader: ExpressServiceLoader,
private val expressServiceFetcher: ExpressServiceFetcher,
private val dispatchers: CoroutineDispatcherProvider,
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory,
private val userTokensSaver: UserTokensSaver,
@ -649,15 +648,15 @@ internal class DefaultCurrenciesRepository(
// TODO [REDACTED_JIRA]
private suspend fun fetchExpressAssetsByNetworkIds(userWallet: UserWallet, userTokens: UserTokensResponse) {
val tokens = userTokens.tokens.map { token ->
LeastTokenInfo(
contractAddress = token.contractAddress ?: EMPTY_CONTRACT_ADDRESS_VALUE,
network = token.networkId,
val tokens = userTokens.tokens.mapTo(hashSetOf()) { token ->
ExpressAsset.ID(
networkId = token.networkId,
contractAddress = token.contractAddress,
)
}
coroutineScope {
launch { expressServiceLoader.update(userWallet, tokens) }
launch { expressServiceFetcher.fetch(userWallet, tokens) }
}
}
@ -666,11 +665,11 @@ internal class DefaultCurrenciesRepository(
cryptoCurrencies: List<CryptoCurrency>,
refresh: Boolean = false,
) {
val tokens = cryptoCurrencies.map { currency ->
val tokens = cryptoCurrencies.mapTo(hashSetOf()) { currency ->
val tokenCurrency = currency as? CryptoCurrency.Token
LeastTokenInfo(
contractAddress = tokenCurrency?.contractAddress ?: EMPTY_CONTRACT_ADDRESS_VALUE,
network = currency.network.backendId,
ExpressAsset.ID(
networkId = currency.network.backendId,
contractAddress = tokenCurrency?.contractAddress,
)
}
cacheRegistry.invokeOnExpire(
@ -678,7 +677,7 @@ internal class DefaultCurrenciesRepository(
skipCache = refresh,
block = {
coroutineScope {
launch { expressServiceLoader.update(userWallet, tokens) }
launch { expressServiceFetcher.fetch(userWallet, tokens) }
}
},
)

View file

@ -11,14 +11,13 @@ import com.tangem.data.common.currency.UserTokensSaver
import com.tangem.data.tokens.utils.CustomTokensMerger
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
import com.tangem.datasource.api.express.models.request.LeastTokenInfo
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.express.models.ExpressAsset
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.isMultiCurrency
@ -45,7 +44,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
private val userTokensResponseStore: UserTokensResponseStore = mockk(relaxUnitFun = true)
private val userTokensSaver: UserTokensSaver = mockk(relaxUnitFun = true)
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory = mockk()
private val expressServiceLoader: ExpressServiceLoader = mockk(relaxUnitFun = true)
private val expressServiceFetcher: ExpressServiceFetcher = mockk(relaxUnitFun = true)
private val fetcher = DefaultMultiWalletCryptoCurrenciesFetcher(
demoConfig = DemoConfig(),
@ -55,7 +54,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userTokensResponseStore = userTokensResponseStore,
userTokensSaver = userTokensSaver,
cardCryptoCurrencyFactory = cardCryptoCurrencyFactory,
expressServiceLoader = expressServiceLoader,
expressServiceFetcher = expressServiceFetcher,
dispatchers = TestingCoroutineDispatcherProvider(),
)
@ -67,7 +66,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userTokensResponseStore,
userTokensSaver,
cardCryptoCurrencyFactory,
expressServiceLoader,
expressServiceFetcher,
)
}
@ -131,6 +130,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
} returns userTokensResponse
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = userTokensResponse.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -144,7 +150,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = userTokensResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = userTokensResponse.toAssetId())
}
}
@ -170,6 +176,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = apiResponse.data)
} returns apiResponse.data
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = defaultResponse.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -183,7 +196,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = apiResponse.data)
userTokensSaver.store(userWalletId = params.userWalletId, response = apiResponse.data)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = defaultResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = defaultResponse.toAssetId())
}
coVerify(inverse = true) {
@ -212,6 +225,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = apiResponse.data)
} returns apiResponse.data
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = apiResponse.data.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -224,7 +244,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = apiResponse.data)
userTokensSaver.store(userWalletId = params.userWalletId, response = apiResponse.data)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = defaultResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = defaultResponse.toAssetId())
}
coVerify(inverse = true) {
@ -273,6 +293,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
} returns userTokensResponse
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = userTokensResponse.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -286,7 +313,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = userTokensResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = userTokensResponse.toAssetId())
}
coVerify(inverse = true) {
@ -317,6 +344,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = defaultResponse)
} returns defaultResponse
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = defaultResponse.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -330,7 +364,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = defaultResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = defaultResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = defaultResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = defaultResponse.toAssetId())
}
coVerify(inverse = true) {
@ -383,6 +417,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
} returns userTokensResponse
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = userTokensResponse.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -398,7 +439,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userTokensSaver.push(userWalletId = params.userWalletId, response = userTokensResponse)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = userTokensResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = userTokensResponse.toAssetId())
}
}
@ -429,6 +470,13 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = defaultResponse)
} returns defaultResponse
coEvery {
expressServiceFetcher.fetch(
userWallet = mockUserWallet,
assetIds = defaultResponse.toAssetId(),
)
} returns Unit.right()
// Act
val actual = fetcher(params)
@ -443,7 +491,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userTokensSaver.push(userWalletId = params.userWalletId, response = defaultResponse)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = defaultResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = defaultResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = defaultResponse.toLeastTokens())
expressServiceFetcher.fetch(userWallet = mockUserWallet, assetIds = defaultResponse.toAssetId())
}
coVerify(inverse = true) {
@ -471,11 +519,11 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
),
)
fun UserTokensResponse.toLeastTokens(): List<LeastTokenInfo> {
return tokens.map { token ->
LeastTokenInfo(
contractAddress = token.contractAddress ?: EMPTY_CONTRACT_ADDRESS_VALUE,
network = token.networkId,
fun UserTokensResponse.toAssetId(): Set<ExpressAsset.ID> {
return tokens.mapTo(hashSetOf()) { token ->
ExpressAsset.ID(
networkId = token.networkId,
contractAddress = token.contractAddress,
)
}
}