Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-01 12:27:58 +05:00
parent 1166f7e8bf
commit 84cf236d5f
20 changed files with 258 additions and 10 deletions

View file

@ -16,6 +16,9 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.*
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyUpdateUseCase
import com.tangem.feature.wallet.presentation.wallet.domain.IsWalletNFTEnabledSyncUseCase
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
import com.tangem.features.hotwallet.HotWalletFeatureToggles
@ -448,4 +451,24 @@ internal object WalletsDomainModule {
userWalletUseCase = getUserWalletUseCase,
)
}
@Provides
@Singleton
fun provideYieldSupplyApyFlowUseCase(
yieldSupplyMarketRepository: YieldSupplyMarketRepository,
): YieldSupplyApyFlowUseCase {
return YieldSupplyApyFlowUseCase(
yieldSupplyMarketRepository = yieldSupplyMarketRepository,
)
}
@Provides
@Singleton
fun provideYieldSupplyApyUpdateUseCase(
yieldSupplyMarketRepository: YieldSupplyMarketRepository,
): YieldSupplyApyUpdateUseCase {
return YieldSupplyApyUpdateUseCase(
yieldSupplyMarketRepository = yieldSupplyMarketRepository,
)
}
}

View file

@ -218,6 +218,13 @@ class TokenItemStateConverter(
text = status.getFormattedFiatAmount(appCurrency = appCurrency),
isFlickering = status.value.isFlickering(),
icons = buildList {
if (status.value.yieldSupplyStatus?.isActive == true &&
status.value.yieldSupplyStatus?.isAllowedToSpend == false) {
TokenItemState.FiatAmountState.Content.IconUM(
iconRes = R.drawable.ic_alert_triangle_20,
tint = IconTint.Warning,
).let(::add)
}
if (!status.getStakedBalance().isZero()) {
add(
TokenItemState.FiatAmountState.Content.IconUM(

View file

@ -8,9 +8,9 @@ import retrofit2.http.Path
interface YieldSupplyApi {
@GET("v1/yield/markets")
@GET("api/v1/yield/markets")
suspend fun getYieldMarkets(): ApiResponse<YieldMarketsResponse>
@GET("v1/yield/token/{tokenAddress}")
@GET("api/v1/yield/token/{tokenAddress}")
suspend fun getYieldTokenStatus(@Path("tokenAddress") tokenAddress: String): ApiResponse<YieldTokenStatusResponse>
}

View file

@ -53,6 +53,20 @@ internal object ApiConfigsModule {
appInfoProvider = appInfoProvider,
)
@Provides
@IntoSet
fun provideYieldSupplyConfig(
environmentConfigStorage: EnvironmentConfigStorage,
appVersionProvider: AppVersionProvider,
authProvider: AuthProvider,
appInfoProvider: AppInfoProvider,
): ApiConfig = YieldSupply(
environmentConfigStorage = environmentConfigStorage,
appVersionProvider = appVersionProvider,
authProvider = authProvider,
appInfoProvider = appInfoProvider,
)
@Provides
@IntoSet
fun provideTangemVisaConfig(appVersionProvider: AppVersionProvider): ApiConfig = TangemPay(appVersionProvider)

View file

@ -37,6 +37,14 @@ class ApiConfigTest {
appInfoProvider = mockk(),
)
}
ApiConfig.ID.YieldSupply -> {
YieldSupply(
environmentConfigStorage = mockk(),
appVersionProvider = mockk(),
authProvider = mockk(),
appInfoProvider = mockk(),
)
}
ApiConfig.ID.TangemTech -> {
TangemTech(
environmentConfigStorage = mockk(),

View file

@ -16,6 +16,9 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
express = ExpressModel(apiKey = EXPRESS_API_KEY, signVerifierPublicKey = "vocibus"),
devExpress = ExpressModel(apiKey = EXPRESS_DEV_API_KEY, signVerifierPublicKey = "pellentesque"),
blockAidApiKey = BLOCK_AID_API_KEY,
tangemApiKey = TANGEM_API_KEY,
tangemApiKeyDev = TANGEM_API_KEY_DEV,
tangemApiKeyStage = TANGEM_API_KEY_STAGE,
)
override suspend fun initialize() = environmentConfig
@ -26,5 +29,8 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
const val EXPRESS_API_KEY = "express_api_key"
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
const val BLOCK_AID_API_KEY = "block_aid_api_key"
const val TANGEM_API_KEY = "tangem_api_key"
const val TANGEM_API_KEY_DEV = "tangem_api_key_dev"
const val TANGEM_API_KEY_STAGE = "tangem_api_key_stage"
}
}

View file

@ -84,6 +84,14 @@ internal class ProdApiConfigsManagerTest {
appInfoProvider = appInfoProvider,
)
}
ApiConfig.ID.YieldSupply -> {
YieldSupply(
environmentConfigStorage = environmentConfigStorage,
appVersionProvider = appVersionProvider,
authProvider = appAuthProvider,
appInfoProvider = appInfoProvider,
)
}
ApiConfig.ID.TangemTech -> {
TangemTech(
environmentConfigStorage = environmentConfigStorage,
@ -102,6 +110,7 @@ internal class ProdApiConfigsManagerTest {
private fun provideTestModels() = ApiConfig.ID.entries.map {
when (it) {
ApiConfig.ID.Express -> createExpressModel()
ApiConfig.ID.YieldSupply -> createYieldSupplyModel()
ApiConfig.ID.TangemTech -> createTangemTechModel()
ApiConfig.ID.StakeKit -> createStakeKitModel()
ApiConfig.ID.TangemPay -> createTangemPayModel()
@ -166,6 +175,30 @@ internal class ProdApiConfigsManagerTest {
environment = ApiEnvironment.PROD,
baseUrl = "https://api.tangem.org/",
headers = mapOf(
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.TANGEM_API_KEY },
"card_id" to ProviderSuspend { APP_CARD_ID },
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
"version" to ProviderSuspend { VERSION_NAME },
"platform" to ProviderSuspend { "android" },
"system_version" to ProviderSuspend { "Android 16" },
"language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() },
"timezone" to ProviderSuspend {
TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty()
},
"device" to ProviderSuspend { "${Build.MANUFACTURER} ${Build.MODEL}".checkHeaderValueOrEmpty() },
),
),
)
}
private fun createYieldSupplyModel(): TestModel {
return TestModel(
id = ApiConfig.ID.YieldSupply,
expected = ApiEnvironmentConfig(
environment = ApiEnvironment.PROD,
baseUrl = "https://yield.tangem.org/",
headers = mapOf(
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.TANGEM_API_KEY },
"card_id" to ProviderSuspend { APP_CARD_ID },
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
"version" to ProviderSuspend { VERSION_NAME },

View file

@ -0,0 +1,26 @@
package com.tangem.domain.yield.supply.usecase
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Emits a map of APY values per token.
*
* Return map:
* - key: token contract address
* - value: APY as string
*/
class YieldSupplyApyFlowUseCase(
private val yieldSupplyMarketRepository: YieldSupplyMarketRepository,
) {
operator fun invoke(): Flow<Map<String, String>> {
return yieldSupplyMarketRepository.getMarketsFlow()
.map { yieldMarketTokenList ->
yieldMarketTokenList.filter { it.isActive }.associate {
it.tokenAddress to it.apy.toString()
}
}
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.domain.yield.supply.usecase
import arrow.core.Either
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
import kotlin.collections.filter
/**
* Updates and returns a map of APY values per token.
*
* Return map:
* - key: token contract address
* - value: APY as string
*/
class YieldSupplyApyUpdateUseCase(
private val yieldSupplyMarketRepository: YieldSupplyMarketRepository,
) {
suspend operator fun invoke(): Either<Throwable, Map<String, String>> = Either.catch {
yieldSupplyMarketRepository.updateMarkets()
.filter { it.isActive }
.associate {
it.tokenAddress to it.apy.toString()
}
}
}

View file

@ -98,6 +98,8 @@ dependencies {
implementation(projects.domain.wallets.models)
implementation(projects.domain.notifications)
implementation(projects.domain.transaction)
implementation(projects.domain.yieldSupply)
implementation(projects.domain.yieldSupply.models)
/** Feature Apis */
implementation(projects.features.details.api)

View file

@ -23,6 +23,7 @@ import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase
import com.tangem.domain.settings.*
import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase
import com.tangem.domain.wallets.usecase.*
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyUpdateUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
@ -43,6 +44,7 @@ import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.features.tangempay.TangemPayFeatureToggles
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.*
import kotlinx.coroutines.*
@ -92,6 +94,8 @@ internal class WalletModel @Inject constructor(
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
private val tangemPayIssueOrderUseCase: TangemPayIssueOrderUseCase,
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
private val yieldSupplyApyUpdateUseCase: YieldSupplyApyUpdateUseCase,
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
val screenLifecycleProvider: ScreenLifecycleProvider,
val innerWalletRouter: InnerWalletRouter,
) : Model() {
@ -116,6 +120,7 @@ internal class WalletModel @Inject constructor(
maybeMigrateNames()
maybeSetWalletFirstTimeUsage()
updateYieldSupplyApy()
subscribeToUserWalletsUpdates()
subscribeOnBalanceHiding()
subscribeOnSelectedWalletFlow()
@ -127,6 +132,14 @@ internal class WalletModel @Inject constructor(
clickIntents.initialize(innerWalletRouter, modelScope)
}
private fun updateYieldSupplyApy() {
if (yieldSupplyFeatureToggles.isYieldSupplyFeatureEnabled) {
modelScope.launch(dispatchers.default) {
yieldSupplyApyUpdateUseCase()
}
}
}
private fun maybeMigrateNames() {
modelScope.launch {
walletNameMigrationUseCase()

View file

@ -10,6 +10,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
@ -42,6 +43,7 @@ internal class MultiWalletContentLoader(
private val walletsRepository: WalletsRepository,
private val currenciesRepository: CurrenciesRepository,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
@ -57,6 +59,7 @@ internal class MultiWalletContentLoader(
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
).let(::add)
WalletNFTListSubscriber(

View file

@ -10,6 +10,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
@ -40,6 +41,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
private val currenciesRepository: CurrenciesRepository,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): WalletContentLoader {
@ -62,6 +64,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
getNFTCollectionsUseCase = getNFTCollectionsUseCase,
currenciesRepository = currenciesRepository,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
)
}
}

View file

@ -5,6 +5,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
@ -32,6 +33,7 @@ internal class SingleWalletWithTokenContentLoader(
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
@ -46,6 +48,7 @@ internal class SingleWalletWithTokenContentLoader(
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
).let(::add)
MultiWalletWarningsSubscriber(
userWallet = userWallet,

View file

@ -6,6 +6,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
@ -33,6 +34,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
) {
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
@ -51,6 +53,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
getStoryContentUseCase = getStoryContentUseCase,
shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
)
}
}

View file

@ -16,6 +16,7 @@ internal class SetTokenListTransformer(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val clickIntents: WalletClickIntents,
private val yieldSupplyApyMap: Map<String, String> = emptyMap(),
) : WalletStateTransformer(userWallet.walletId) {
override fun transform(prevState: WalletState): WalletState {
@ -58,6 +59,7 @@ internal class SetTokenListTransformer(
selectedWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
apyMap = yieldSupplyApyMap,
).convert(value = this)
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert
import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
import com.tangem.common.ui.tokens.TokenItemStateConverter
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resourceReference
@ -13,6 +14,7 @@ import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.tokenlist.TokenList.GroupedByNetwork.NetworkGroup
@ -34,6 +36,7 @@ internal class TokenListStateConverter(
private val params: TokenConverterParams,
private val selectedWallet: UserWallet,
private val clickIntents: WalletClickIntents,
private val apyMap: Map<String, String> = emptyMap(),
) : Converter<WalletTokensListState, WalletTokensListState> {
private val onTokenClick: (accountId: AccountId?, currencyStatus: CryptoCurrencyStatus) -> Unit =
@ -165,12 +168,54 @@ internal class TokenListStateConverter(
tokenConverter: TokenItemStateConverter,
token: CryptoCurrencyStatus,
): List<TokensListItemUM> {
val tokenItemState = tokenConverter.convert(token)
val tokenItemState = tokenConverter.convert(token).withEarnApyBadge(token)
add(TokensListItemUM.Token(tokenItemState))
return this
}
private fun TokenItemState.withEarnApyBadge(cryptoCurrencyStatus: CryptoCurrencyStatus): TokenItemState {
val apy: String? = resolveEarnApy(cryptoCurrencyStatus)
val shouldApply = apy != null && this.titleState is TokenItemState.TitleState.Content
return if (!shouldApply) {
this
} else {
val contentTitle = this.titleState as TokenItemState.TitleState.Content
val newTitle = contentTitle.copy(
earnApy = resourceReference(
R.string.yield_module_earn_badge,
wrappedList(apy),
),
)
when (this) {
is TokenItemState.Content -> this.copy(titleState = newTitle)
is TokenItemState.Unreachable -> this.copy(titleState = newTitle)
is TokenItemState.NoAddress -> this.copy(titleState = newTitle)
is TokenItemState.Loading -> this.copy(titleState = newTitle)
is TokenItemState.Draggable -> this.copy(titleState = newTitle)
is TokenItemState.Locked -> this
}
}
}
private fun resolveEarnApy(cryptoCurrencyStatus: CryptoCurrencyStatus): String? {
if (apyMap.isEmpty()) return null
val isYieldSupplyActive = (cryptoCurrencyStatus.value as? CryptoCurrencyStatus.Loaded)
?.yieldSupplyStatus?.isActive == true
if (isYieldSupplyActive) return null
val contract = (cryptoCurrencyStatus.currency as? CryptoCurrency.Token)
?.contractAddress
?.lowercase() ?: return null
return apyMap[contract]
}
private fun getOrganizeTokensButtonState(tokenList: TokenList): WalletOrganizeTokensButtonConfig? {
val currenciesSize = when (tokenList) {
TokenList.Empty -> return null

View file

@ -13,6 +13,7 @@ import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
@ -39,6 +40,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
protected abstract val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase
protected abstract val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase
protected abstract val accountDependencies: AccountDependencies
protected abstract val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase
private val sendAnalyticsJobHolder = JobHolder()
private val onTokenListReceivedJobHolder = JobHolder()
@ -73,8 +75,14 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
coroutineScope.launch { startCheck(maybeTokenList) }
},
flow2 = appCurrencyFlow(),
transform = { maybeTokenList, appCurrency ->
singleAccountTransform(maybeTokenList, appCurrency, PortfolioId(userWallet.walletId))
flow3 = yieldSupplyApyFlow(),
transform = { maybeTokenList, appCurrency, yieldSupplyApyMap ->
singleAccountTransform(
maybeTokenList = maybeTokenList,
appCurrency = appCurrency,
portfolioId = PortfolioId(userWallet.walletId),
yieldSupplyApyMap = yieldSupplyApyMap,
)
},
)
}
@ -83,6 +91,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
maybeTokenList: Lce<TokenListError, TokenList>,
appCurrency: AppCurrency,
portfolioId: PortfolioId,
yieldSupplyApyMap: Map<String, String>,
) {
val tokenList = maybeTokenList.getOrElse(
ifLoading = { maybeContent ->
@ -106,7 +115,12 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
return
},
)
updateContent(TokenConverterParams.Wallet(portfolioId, tokenList), appCurrency)
updateContent(
params = TokenConverterParams.Wallet(portfolioId, tokenList),
appCurrency = appCurrency,
yieldSupplyApyMap = yieldSupplyApyMap,
)
walletWithFundsChecker.check(tokenList)
}
@ -143,7 +157,8 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
flow2 = appCurrencyFlow(),
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),
transform = { accountList, appCurrency, expandedAccounts, isAccountMode ->
flow5 = yieldSupplyApyFlow(),
transform = { accountList, appCurrency, expandedAccounts, isAccountMode, yieldSupplyApyMap ->
val accountFlattenTokensList = accountList.flattenTokens()
val accountFlattenCurrencies = accountFlattenTokensList
.map { it.flattenCurrencies() }
@ -153,7 +168,12 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
}
suspend fun singleAccountTransform(maybeTokenList: Lce<TokenListError, TokenList>) =
this.singleAccountTransform(maybeTokenList, appCurrency, PortfolioId(mainAccount.account.accountId))
this.singleAccountTransform(
maybeTokenList,
appCurrency,
PortfolioId(mainAccount.account.accountId),
yieldSupplyApyMap,
)
when {
!isAccountMode -> when (mainAccount.tokenList.flattenCurrencies().isEmpty()) {
@ -171,7 +191,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
)
false -> {
val convertParams = TokenConverterParams.Account(accountList, expandedAccounts)
updateContent(convertParams, appCurrency)
updateContent(convertParams, appCurrency, yieldSupplyApyMap)
accountFlattenTokensList
.map { tokenList -> coroutineScope.launch { walletWithFundsChecker.check(tokenList) } }
.joinAll()
@ -197,13 +217,18 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
)
}
private fun updateContent(params: TokenConverterParams, appCurrency: AppCurrency) {
private fun updateContent(
params: TokenConverterParams,
appCurrency: AppCurrency,
yieldSupplyApyMap: Map<String, String>,
) {
stateHolder.update(
SetTokenListTransformer(
params = params,
userWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
yieldSupplyApyMap = yieldSupplyApyMap,
),
)
}
@ -216,4 +241,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
}
}
.distinctUntilChanged()
private fun yieldSupplyApyFlow(): Flow<Map<String, String>> = yieldSupplyApyFlowUseCase()
.distinctUntilChanged()
}

View file

@ -13,6 +13,7 @@ import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
@ -34,6 +35,7 @@ internal class MultiWalletTokenListSubscriber(
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
override val accountDependencies: AccountDependencies,
override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
) : BasicTokenListSubscriber() {
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {

View file

@ -9,6 +9,7 @@ import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
@ -29,6 +30,7 @@ internal class SingleWalletWithTokenListSubscriber(
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
override val accountDependencies: AccountDependencies,
override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
) : BasicTokenListSubscriber() {
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {