Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-23 17:08:01 +03:00
parent cf49333c22
commit c35da7186d
9 changed files with 99 additions and 131 deletions

View file

@ -1,39 +0,0 @@
package com.tangem.features.yield.supply.impl.common
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import javax.inject.Inject
import javax.inject.Singleton
/**
* Trigger for entering/exiting protocol from other components
*/
interface YieldSupplyProtocolTrigger {
suspend fun onEnterProtocol()
suspend fun onExitProtocol()
}
/**
* Listener to observe entering/exiting protocol events
*/
interface YieldSupplyProtocolListener {
val enterProtocolTriggerFlow: Flow<Unit>
val exitProtocolTriggerFlow: Flow<Unit>
}
@Singleton
internal class DefaultYieldSupplyProtocolTrigger @Inject constructor() :
YieldSupplyProtocolTrigger,
YieldSupplyProtocolListener {
override val enterProtocolTriggerFlow = MutableSharedFlow<Unit>()
override val exitProtocolTriggerFlow = MutableSharedFlow<Unit>()
override suspend fun onEnterProtocol() {
enterProtocolTriggerFlow.emit(Unit)
}
override suspend fun onExitProtocol() {
exitProtocolTriggerFlow.emit(Unit)
}
}

View file

@ -3,10 +3,6 @@ package com.tangem.features.yield.supply.impl.di
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.features.yield.supply.impl.DefaultYieldSupplyFeatureToggles
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
import com.tangem.features.yield.supply.impl.common.DefaultYieldSupplyProtocolTrigger
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolListener
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -22,17 +18,4 @@ internal object YieldSupplyFeatureModule {
fun provideYieldFeatureToggles(featureTogglesManager: FeatureTogglesManager): YieldSupplyFeatureToggles {
return DefaultYieldSupplyFeatureToggles(featureTogglesManager)
}
}
@InstallIn(SingletonComponent::class)
@Module
internal interface YieldSupplyProtocolModuleBinds {
@Singleton
@Binds
fun bindYieldSupplyProtocolTrigger(impl: DefaultYieldSupplyProtocolTrigger): YieldSupplyProtocolTrigger
@Singleton
@Binds
fun bindYieldSupplyProtocolListener(impl: DefaultYieldSupplyProtocolTrigger): YieldSupplyProtocolListener
}

View file

@ -16,12 +16,13 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.currency.yieldSupplyNotAllAmountSupplied
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.domain.yield.supply.YieldSupplyRepository
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
import com.tangem.domain.yield.supply.usecase.YieldSupplyActivateUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase
@ -29,7 +30,6 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyIsAvailableUseCase
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.api.YieldSupplyComponent
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolListener
import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM
import com.tangem.features.yield.supply.impl.main.model.transformers.YieldSupplyTokenStatusSuccessTransformer
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -59,7 +59,7 @@ internal class YieldSupplyModel @Inject constructor(
private val yieldSupplyIsAvailableUseCase: YieldSupplyIsAvailableUseCase,
private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase,
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
private val yieldSupplyProtocolListener: YieldSupplyProtocolListener,
private val yieldSupplyRepository: YieldSupplyRepository,
) : Model(), YieldSupplyClickIntents {
private val params = paramsContainer.require<YieldSupplyComponent.Params>()
@ -87,38 +87,6 @@ internal class YieldSupplyModel @Inject constructor(
init {
checkIfYieldSupplyIsAvailable()
observeProtocolEvents()
}
private fun observeProtocolEvents() {
yieldSupplyProtocolListener.exitProtocolTriggerFlow.onEach {
uiState.update {
YieldSupplyUM.Processing.Exit
}
coroutineScope.launch(dispatchers.io) {
delay(PROCESSING_UPDATE_DELAY)
singleNetworkStatusFetcher(
params = SingleNetworkStatusFetcher.Params(
userWalletId = userWallet.walletId,
network = cryptoCurrency.network,
),
)
}
}.launchIn(modelScope)
yieldSupplyProtocolListener.enterProtocolTriggerFlow.onEach {
uiState.update {
YieldSupplyUM.Processing.Enter
}
coroutineScope.launch(dispatchers.io) {
delay(PROCESSING_UPDATE_DELAY)
singleNetworkStatusFetcher(
params = SingleNetworkStatusFetcher.Params(
userWalletId = userWallet.walletId,
network = cryptoCurrency.network,
),
)
}
}.launchIn(modelScope)
}
private fun checkIfYieldSupplyIsAvailable() {
@ -142,7 +110,6 @@ internal class YieldSupplyModel @Inject constructor(
currencyId = cryptoCurrency.id,
isSingleWalletWithTokens = false,
).onEach { maybeCryptoCurrency ->
Timber.tag("getSingleCryptoCurrencyStatusUseCase").d("update $maybeCryptoCurrency")
maybeCryptoCurrency.fold(
ifRight = { cryptoCurrencyStatus ->
cryptoCurrencyStatusFlow.update { cryptoCurrencyStatus }
@ -175,7 +142,7 @@ internal class YieldSupplyModel @Inject constructor(
)
}.onLeft {
Timber.e(it)
uiState.update { YieldSupplyUM.Unavailable }
uiState.update { YieldSupplyUM.Initial }
}
}
}
@ -214,39 +181,46 @@ internal class YieldSupplyModel @Inject constructor(
@Suppress("MaximumLineLength")
private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) {
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
val hasActiveTransaction = cryptoCurrencyStatus.value.hasCurrentNetworkTransactions
val yieldTransaction = cryptoCurrencyStatus.value.pendingTransactions.firstOrNull {
it.type is TxInfo.TransactionType.YieldSupply
}?.type as? TxInfo.TransactionType.YieldSupply
if ((yieldSupplyStatus == null || yieldSupplyStatus.isActive == false) &&
yieldSupplyRepository.getTokenProtocolStatus(cryptoCurrency) == YieldSupplyEnterStatus.Enter) {
uiState.update {
YieldSupplyUM.Processing.Enter
}
fetchCurrencyWithDelay()
return
}
if (yieldSupplyStatus?.isActive == true &&
yieldSupplyRepository.getTokenProtocolStatus(cryptoCurrency) == YieldSupplyEnterStatus.Exit) {
uiState.update {
YieldSupplyUM.Processing.Exit
}
fetchCurrencyWithDelay()
return
}
sendInfoAboutProtocolStatus(cryptoCurrencyStatus)
when {
hasActiveTransaction && yieldTransaction != null -> {
coroutineScope.launch(dispatchers.io) {
delay(PROCESSING_UPDATE_DELAY)
singleNetworkStatusFetcher(
params = SingleNetworkStatusFetcher.Params(
userWalletId = userWallet.walletId,
network = cryptoCurrency.network,
),
)
}
uiState.update {
when (yieldTransaction) {
TxInfo.TransactionType.YieldSupply.Enter -> YieldSupplyUM.Processing.Enter
TxInfo.TransactionType.YieldSupply.Exit -> YieldSupplyUM.Processing.Exit
}
}
}
yieldSupplyStatus?.isActive == true -> {
loadActiveState(
cryptoCurrencyStatus = cryptoCurrencyStatus,
yieldSupplyStatus = yieldSupplyStatus,
)
}
else -> {
loadTokenStatus()
}
if (yieldSupplyStatus?.isActive == true) {
loadActiveState(
cryptoCurrencyStatus = cryptoCurrencyStatus,
yieldSupplyStatus = yieldSupplyStatus,
)
} else {
loadTokenStatus()
}
}
private fun fetchCurrencyWithDelay() {
coroutineScope.launch(dispatchers.io) {
delay(PROCESSING_UPDATE_DELAY)
singleNetworkStatusFetcher(
params = SingleNetworkStatusFetcher.Params(
userWalletId = userWallet.walletId,
network = cryptoCurrency.network,
),
)
}
}

View file

@ -20,6 +20,8 @@ import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.domain.yield.supply.YieldSupplyRepository
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
import com.tangem.domain.yield.supply.usecase.YieldSupplyActivateUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyEstimateEnterFeeUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase
@ -28,7 +30,6 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
@ -66,7 +67,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase,
private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase,
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase,
private val yieldSupplyProtocolTrigger: YieldSupplyProtocolTrigger,
private val yieldSupplyRepository: YieldSupplyRepository,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require()
@ -252,7 +253,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
)
},
ifRight = {
yieldSupplyProtocolTrigger.onEnterProtocol()
yieldSupplyRepository.saveTokenProtocolStatus(cryptoCurrency, YieldSupplyEnterStatus.Enter)
analytics.send(YieldSupplyAnalytics.FundsEarned)
yieldSupplyActivateUseCase(cryptoCurrency)
modelScope.launch {

View file

@ -16,12 +16,13 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.yield.supply.YieldSupplyRepository
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
@ -55,7 +56,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger,
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
private val yieldSupplyProtocolTrigger: YieldSupplyProtocolTrigger,
private val yieldSupplyRepository: YieldSupplyRepository,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyStopEarningComponent.Params = paramsContainer.require()
@ -158,7 +159,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
)
},
ifRight = {
yieldSupplyProtocolTrigger.onExitProtocol()
yieldSupplyRepository.saveTokenProtocolStatus(cryptoCurrency, YieldSupplyEnterStatus.Exit)
analytics.send(
YieldSupplyAnalytics.FundsWithdrawn(
token = cryptoCurrency.symbol,