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

@ -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,
)
}
}