Updated on 2026-08-14

This commit is contained in:
Tangem 2024-11-05 11:02:04 +02:00
parent 9597f49fed
commit 0be9414914
12 changed files with 59 additions and 162 deletions

View file

@ -7,7 +7,6 @@ import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.repository.*
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.feature.swap.domain.api.SwapRepository
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -221,7 +220,6 @@ internal object TokensDomainModule {
quotesRepository: QuotesRepository,
networksRepository: NetworksRepository,
stakingRepository: StakingRepository,
stakingFeatureToggles: StakingFeatureToggles,
dispatchers: CoroutineDispatcherProvider,
): GetCryptoCurrencyActionsUseCase {
return GetCryptoCurrencyActionsUseCase(
@ -232,7 +230,6 @@ internal object TokensDomainModule {
quotesRepository = quotesRepository,
networksRepository = networksRepository,
stakingRepository = stakingRepository,
stakingFeatureToggles = stakingFeatureToggles,
dispatchers = dispatchers,
)
}

View file

@ -18,7 +18,6 @@ import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
import com.tangem.domain.staking.FetchStakingTokensUseCase
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
import com.tangem.tap.features.main.model.MainScreenState
@ -41,7 +40,6 @@ internal class MainViewModel @Inject constructor(
private val blockchainSDKFactory: BlockchainSDKFactory,
private val userWalletsListManager: UserWalletsListManager,
private val dispatchers: CoroutineDispatcherProvider,
stakingFeatureToggles: StakingFeatureToggles,
private val fetchStakingTokensUseCase: FetchStakingTokensUseCase,
private val apiConfigsManager: ApiConfigsManager,
homeFeatureToggles: HomeFeatureToggles,
@ -79,9 +77,7 @@ internal class MainViewModel @Inject constructor(
displayBalancesHidingStatusToast()
displayHiddenBalancesModalNotification()
if (stakingFeatureToggles.isStakingEnabled) {
fetchStakingTokens()
}
fetchStakingTokens()
deleteDeprecatedLogsUseCase()
}

View file

@ -7,10 +7,6 @@
"name": "WC_SOLANA_TX_SIGN_ENABLED",
"version": "5.18.0"
},
{
"name": "STAKING_ENABLED",
"version": "5.15.0"
},
{
"name": "IS_ETHEREUM_EIP_1559_ENABLED",
"version": "5.17.0"

View file

@ -48,7 +48,6 @@ import com.tangem.domain.tokens.model.Network
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.lib.crypto.BlockchainUtils.isSolana
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.orZero
@ -65,7 +64,6 @@ internal class DefaultStakingRepository(
private val stakingBalanceStore: StakingBalanceStore,
private val cacheRegistry: CacheRegistry,
private val dispatchers: CoroutineDispatcherProvider,
private val stakingFeatureToggle: StakingFeatureToggles,
private val walletManagersFacade: WalletManagersFacade,
private val getUserWalletUseCase: GetUserWalletUseCase,
moshi: Moshi,
@ -320,8 +318,6 @@ internal class DefaultStakingRepository(
cryptoCurrency: CryptoCurrency,
refresh: Boolean,
) = withContext(dispatchers.io) {
if (!stakingFeatureToggle.isStakingEnabled) return@withContext
cacheRegistry.invokeOnExpire(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
@ -361,30 +357,26 @@ internal class DefaultStakingRepository(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): Flow<YieldBalance> = channelFlow {
if (!stakingFeatureToggle.isStakingEnabled) {
send(YieldBalance.Empty)
} else {
launch(dispatchers.io) {
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
?: error("Could not get integrationId")
stakingBalanceStore.get(userWalletId, address, integrationId)
.distinctUntilChanged()
.collectLatest {
if (it != null) {
send(yieldBalanceConverter.convert(it))
} else {
error("No yield balance available for currency ${cryptoCurrency.id.value}")
}
launch(dispatchers.io) {
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
?: error("Could not get integrationId")
stakingBalanceStore.get(userWalletId, address, integrationId)
.distinctUntilChanged()
.collectLatest {
if (it != null) {
send(yieldBalanceConverter.convert(it))
} else {
error("No yield balance available for currency ${cryptoCurrency.id.value}")
}
}
}
}
withContext(dispatchers.io) {
fetchSingleYieldBalance(
userWalletId,
cryptoCurrency,
)
}
withContext(dispatchers.io) {
fetchSingleYieldBalance(
userWalletId,
cryptoCurrency,
)
}
}.cancellable()
@ -392,21 +384,17 @@ internal class DefaultStakingRepository(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): YieldBalance = withContext(dispatchers.io) {
if (!stakingFeatureToggle.isStakingEnabled) {
YieldBalance.Empty
} else {
fetchSingleYieldBalance(userWalletId, cryptoCurrency)
fetchSingleYieldBalance(userWalletId, cryptoCurrency)
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
?: error("Could not get integrationId")
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
?: error("Could not get integrationId")
val result = stakingBalanceStore.getSyncOrNull(userWalletId, address, integrationId)
?: return@withContext YieldBalance.Error
val result = stakingBalanceStore.getSyncOrNull(userWalletId, address, integrationId)
?: return@withContext YieldBalance.Error
yieldBalanceConverter.convert(result)
}
yieldBalanceConverter.convert(result)
}
override suspend fun fetchMultiYieldBalance(
@ -414,8 +402,6 @@ internal class DefaultStakingRepository(
cryptoCurrencies: List<CryptoCurrency>,
refresh: Boolean,
) = withContext(dispatchers.io) {
if (!stakingFeatureToggle.isStakingEnabled) return@withContext
cacheRegistry.invokeOnExpire(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
@ -463,19 +449,15 @@ internal class DefaultStakingRepository(
userWalletId: UserWalletId,
cryptoCurrencies: List<CryptoCurrency>,
): Flow<YieldBalanceList> = channelFlow {
if (!stakingFeatureToggle.isStakingEnabled) {
send(YieldBalanceList.Empty)
} else {
stakingBalanceStore.get(userWalletId)
.onEach {
val balances = yieldBalanceListConverter.convert(it)
send(balances)
}
.launchIn(scope = this + dispatchers.io)
withContext(dispatchers.io) {
fetchMultiYieldBalance(userWalletId, cryptoCurrencies, refresh = false)
stakingBalanceStore.get(userWalletId)
.onEach {
val balances = yieldBalanceListConverter.convert(it)
send(balances)
}
.launchIn(scope = this + dispatchers.io)
withContext(dispatchers.io) {
fetchMultiYieldBalance(userWalletId, cryptoCurrencies, refresh = false)
}
}
@ -483,13 +465,9 @@ internal class DefaultStakingRepository(
userWalletId: UserWalletId,
cryptoCurrencies: List<CryptoCurrency>,
): YieldBalanceList = withContext(dispatchers.io) {
if (!stakingFeatureToggle.isStakingEnabled) {
YieldBalanceList.Empty
} else {
fetchMultiYieldBalance(userWalletId, cryptoCurrencies)
val result = stakingBalanceStore.getSyncOrNull(userWalletId) ?: return@withContext YieldBalanceList.Error
yieldBalanceListConverter.convert(result)
}
fetchMultiYieldBalance(userWalletId, cryptoCurrencies)
val result = stakingBalanceStore.getSyncOrNull(userWalletId) ?: return@withContext YieldBalanceList.Error
yieldBalanceListConverter.convert(result)
}
override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean {

View file

@ -18,7 +18,6 @@ import com.tangem.datasource.local.token.StakingYieldsStore
import com.tangem.domain.staking.repositories.*
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -38,7 +37,6 @@ internal object StakingDataModule {
stakingBalanceStore: StakingBalanceStore,
cacheRegistry: CacheRegistry,
dispatchers: CoroutineDispatcherProvider,
stakingFeatureToggle: StakingFeatureToggles,
walletManagersFacade: WalletManagersFacade,
getUserWalletUseCase: GetUserWalletUseCase,
@NetworkMoshi moshi: Moshi,
@ -49,7 +47,6 @@ internal object StakingDataModule {
stakingBalanceStore = stakingBalanceStore,
cacheRegistry = cacheRegistry,
dispatchers = dispatchers,
stakingFeatureToggle = stakingFeatureToggle,
walletManagersFacade = walletManagersFacade,
getUserWalletUseCase = getUserWalletUseCase,
moshi = moshi,

View file

@ -12,7 +12,6 @@ import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.isNullOrZero
import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -32,7 +31,6 @@ class GetCryptoCurrencyActionsUseCase(
private val quotesRepository: QuotesRepository,
private val networksRepository: NetworksRepository,
private val stakingRepository: StakingRepository,
private val stakingFeatureToggles: StakingFeatureToggles,
private val dispatchers: CoroutineDispatcherProvider,
) {
@ -134,28 +132,26 @@ class GetCryptoCurrencyActionsUseCase(
}
// staking
if (stakingFeatureToggles.isStakingEnabled) {
if (isStakingAvailable(userWallet, cryptoCurrency)) {
val yield = kotlin.runCatching {
stakingRepository.getYield(
cryptoCurrencyId = cryptoCurrency.id,
symbol = cryptoCurrency.symbol,
)
}.getOrNull()
activeList.add(
TokenActionsState.ActionState.Stake(
unavailabilityReason = ScenarioUnavailabilityReason.None,
yield = yield,
),
if (isStakingAvailable(userWallet, cryptoCurrency)) {
val yield = kotlin.runCatching {
stakingRepository.getYield(
cryptoCurrencyId = cryptoCurrency.id,
symbol = cryptoCurrency.symbol,
)
} else {
disabledList.add(
TokenActionsState.ActionState.Stake(
unavailabilityReason = ScenarioUnavailabilityReason.StakingUnavailable(cryptoCurrency.name),
yield = null,
),
)
}
}.getOrNull()
activeList.add(
TokenActionsState.ActionState.Stake(
unavailabilityReason = ScenarioUnavailabilityReason.None,
yield = yield,
),
)
} else {
disabledList.add(
TokenActionsState.ActionState.Stake(
unavailabilityReason = ScenarioUnavailabilityReason.StakingUnavailable(cryptoCurrency.name),
yield = null,
),
)
}
// send
@ -271,9 +267,7 @@ class GetCryptoCurrencyActionsUseCase(
}
actionsList.add(TokenActionsState.ActionState.Receive(scenario))
}
if (stakingFeatureToggles.isStakingEnabled) {
actionsList.add(TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.Unreachable, null))
}
actionsList.add(TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.Unreachable, null))
actionsList.add(TokenActionsState.ActionState.HideToken(ScenarioUnavailabilityReason.None))
return actionsList

View file

@ -1,10 +0,0 @@
package com.tangem.features.staking.api.featuretoggles
/**
* Staking feature toggles
*/
interface StakingFeatureToggles {
/** Availability of staking */
val isStakingEnabled: Boolean
}

View file

@ -1,24 +0,0 @@
package com.tangem.features.staking.impl.di
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.features.staking.impl.featuretoggles.DefaultStakingFeatureToggles
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
/**
* DI module provides implementation of [StakingFeatureToggles]
*/
@Module
@InstallIn(SingletonComponent::class)
internal object StakingFeatureTogglesModule {
@Provides
@Singleton
fun provideStakingFeatureToggles(featureTogglesManager: FeatureTogglesManager): StakingFeatureToggles {
return DefaultStakingFeatureToggles(featureTogglesManager = featureTogglesManager)
}
}

View file

@ -1,17 +0,0 @@
package com.tangem.features.staking.impl.featuretoggles
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
/**
* Default implementation of staking feature toggles
*
* @property featureTogglesManager manager for getting information about the availability of feature toggles
*/
internal class DefaultStakingFeatureToggles(
private val featureTogglesManager: FeatureTogglesManager,
) : StakingFeatureToggles {
override val isStakingEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "STAKING_ENABLED")
}

View file

@ -24,7 +24,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.features.tokendetails.impl.R
import com.tangem.lib.crypto.BlockchainUtils.isBSC
import com.tangem.lib.crypto.BlockchainUtils.isSolana
@ -46,7 +45,6 @@ internal class TokenDetailsLoadedBalanceConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
private val stakingFeatureToggles: StakingFeatureToggles,
) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, TokenDetailsState> {
private val txHistoryItemConverter by lazy {
@ -100,7 +98,7 @@ internal class TokenDetailsLoadedBalanceConverter(
): TokenDetailsBalanceBlockState {
val stakingCryptoAmount = (status.value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance()
val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) }
val isBalanceSelectorEnabled = stakingFeatureToggles.isStakingEnabled && !stakingCryptoAmount.isNullOrZero()
val isBalanceSelectorEnabled = !stakingCryptoAmount.isNullOrZero()
return when (status.value) {
is CryptoCurrencyStatus.NoQuote,
is CryptoCurrencyStatus.Loaded,

View file

@ -40,7 +40,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.t
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter.TokenDetailsLoadingTxHistoryModel
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheetConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.Provider
import kotlinx.collections.immutable.toImmutableList
@ -59,7 +58,6 @@ internal class TokenDetailsStateFactory(
private val networkHasDerivationUseCase: NetworkHasDerivationUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val userWalletId: UserWalletId,
stakingFeatureToggles: StakingFeatureToggles,
getStakingIntegrationIdUseCase: GetStakingIntegrationIdUseCase,
getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
symbol: String,
@ -91,7 +89,6 @@ internal class TokenDetailsStateFactory(
symbol = symbol,
decimals = decimals,
clickIntents = clickIntents,
stakingFeatureToggles = stakingFeatureToggles,
)
}

View file

@ -72,7 +72,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBala
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheetConfig
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.*
@ -110,7 +109,6 @@ internal class TokenDetailsViewModel @Inject constructor(
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
private val getExtendedPublicKeyForCurrencyUseCase: GetExtendedPublicKeyForCurrencyUseCase,
private val getStakingEntryInfoUseCase: GetStakingEntryInfoUseCase,
private val stakingFeatureToggles: StakingFeatureToggles,
private val getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
private val getYieldUseCase: GetYieldUseCase,
private val networkHasDerivationUseCase: NetworkHasDerivationUseCase,
@ -167,7 +165,6 @@ internal class TokenDetailsViewModel @Inject constructor(
networkHasDerivationUseCase = networkHasDerivationUseCase,
getUserWalletUseCase = getUserWalletUseCase,
userWalletId = userWalletId,
stakingFeatureToggles = stakingFeatureToggles,
getStakingIntegrationIdUseCase = getStakingIntegrationIdUseCase,
getStakingAvailabilityUseCase = getStakingAvailabilityUseCase,
symbol = cryptoCurrency.symbol,
@ -240,9 +237,7 @@ internal class TokenDetailsViewModel @Inject constructor(
subscribeOnExchangeTransactionsUpdates()
updateTxHistory(refresh = false, showItemsLoading = true)
if (stakingFeatureToggles.isStakingEnabled) {
updateStakingInfo()
}
updateStakingInfo()
}
private fun handleBalanceHiding(owner: LifecycleOwner) {