From 96e30660e8f99e20c826544d965893265ca34cd8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Sep 2025 15:54:44 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/YieldSupplyDomainModule.kt | 14 ++++-- ...DefaultYieldSupplyTransactionRepository.kt | 19 ++++++++ .../YieldSupplyTransactionRepository.kt | 2 + .../YieldSupplyGetProtocolBalanceUseCase.kt | 24 ++++++++++ .../entity/YieldSupplyActiveContentUM.kt | 2 +- .../active/model/YieldSupplyActiveModel.kt | 48 ++++++++++++++++--- .../active/ui/YieldSupplyActiveContent.kt | 28 +++++++---- 7 files changed, 116 insertions(+), 21 deletions(-) create mode 100644 domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetProtocolBalanceUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/YieldSupplyDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/YieldSupplyDomainModule.kt index 0921e8b1eb..f3ed8e4349 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/YieldSupplyDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/YieldSupplyDomainModule.kt @@ -4,10 +4,7 @@ import com.tangem.domain.blockaid.BlockAidGasEstimate import com.tangem.domain.transaction.FeeRepository import com.tangem.domain.transaction.error.FeeErrorResolver import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository -import com.tangem.domain.yield.supply.usecase.YieldSupplyEstimateEnterFeeUseCase -import com.tangem.domain.yield.supply.usecase.YieldSupplyGetContractAddressUseCase -import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase -import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase +import com.tangem.domain.yield.supply.usecase.* import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -59,7 +56,16 @@ internal object YieldSupplyDomainModule { ): YieldSupplyGetContractAddressUseCase { return YieldSupplyGetContractAddressUseCase( yieldSupplyTransactionRepository = yieldSupplyTransactionRepository, + ) + } + @Provides + @Singleton + fun provideYieldSupplyGetProtocolBalanceUseCase( + yieldSupplyTransactionRepository: YieldSupplyTransactionRepository, + ): YieldSupplyGetProtocolBalanceUseCase { + return YieldSupplyGetProtocolBalanceUseCase( + yieldSupplyTransactionRepository = yieldSupplyTransactionRepository, ) } } \ No newline at end of file diff --git a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt index cbc1107bd4..d2f3ce9120 100644 --- a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt +++ b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt @@ -89,6 +89,25 @@ internal class DefaultYieldSupplyTransactionRepository( ) } + override suspend fun getProtocolBalance(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): BigDecimal? = + withContext(dispatchers.io) { + require(cryptoCurrency is CryptoCurrency.Token) + runCatching { + val walletManager = walletManagersFacade.getOrCreateWalletManager( + userWalletId = userWalletId, + blockchain = cryptoCurrency.network.toBlockchain(), + derivationPath = cryptoCurrency.network.derivationPath.value, + ) ?: error("Wallet manager not found") + walletManager.getProtocolBalance( + token = Token( + symbol = cryptoCurrency.symbol, + contractAddress = cryptoCurrency.contractAddress, + decimals = cryptoCurrency.decimals, + ), + ) + }.onFailure(Timber::e).getOrNull() + } + @Suppress("LongParameterList") private fun buildEnterTransactions( walletManager: WalletManager, diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyTransactionRepository.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyTransactionRepository.kt index 7246d7a95e..68982a6e66 100644 --- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyTransactionRepository.kt +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyTransactionRepository.kt @@ -22,4 +22,6 @@ interface YieldSupplyTransactionRepository { ): TransactionData.Uncompiled suspend fun getYieldContractAddress(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): String? + + suspend fun getProtocolBalance(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): BigDecimal? } \ No newline at end of file diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetProtocolBalanceUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetProtocolBalanceUseCase.kt new file mode 100644 index 0000000000..72ff2ffef7 --- /dev/null +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetProtocolBalanceUseCase.kt @@ -0,0 +1,24 @@ +package com.tangem.domain.yield.supply.usecase + +import arrow.core.Either +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository +import java.math.BigDecimal + +class YieldSupplyGetProtocolBalanceUseCase( + private val yieldSupplyTransactionRepository: YieldSupplyTransactionRepository, +) { + + suspend operator fun invoke( + userWalletId: UserWalletId, + cryptoCurrency: CryptoCurrency, + ): Either = Either.catch { + requireNotNull(cryptoCurrency as CryptoCurrency.Token) + + yieldSupplyTransactionRepository.getProtocolBalance( + userWalletId = userWalletId, + cryptoCurrency = cryptoCurrency, + ) + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt index 222df4dcd8..7cda12cb63 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt @@ -5,7 +5,7 @@ import com.tangem.core.ui.extensions.TextReference internal data class YieldSupplyActiveContentUM( val totalEarnings: TextReference, - val availableBalance: TextReference, + val availableBalance: TextReference?, val providerTitle: TextReference, val subtitle: TextReference, val subtitleLink: TextReference, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt index de5b72b33d..b534b6f596 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt @@ -10,17 +10,20 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.domain.yield.supply.usecase.YieldSupplyGetProtocolBalanceUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.subcomponents.active.YieldSupplyActiveComponent import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch import javax.inject.Inject @ModelScoped internal class YieldSupplyActiveModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, + private val yieldSupplyGetProtocolBalanceUseCase: YieldSupplyGetProtocolBalanceUseCase, ) : Model() { private val params: YieldSupplyActiveComponent.Params = paramsContainer.require() @@ -32,11 +35,7 @@ internal class YieldSupplyActiveModel @Inject constructor( field = MutableStateFlow( YieldSupplyActiveContentUM( totalEarnings = stringReference("0"), - availableBalance = stringReference( - cryptoCurrencyStatusFlow.value.value.amount.format { - crypto(cryptoCurrency = cryptoCurrencyStatusFlow.value.currency) - }, - ), + availableBalance = null, providerTitle = resourceReference(R.string.yield_module_provider), subtitle = resourceReference( id = R.string.yield_module_earn_sheet_provider_description, @@ -49,10 +48,31 @@ internal class YieldSupplyActiveModel @Inject constructor( init { subscribeOnCurrencyUpdates() + + modelScope.launch { + val protocolBalance = yieldSupplyGetProtocolBalanceUseCase( + userWalletId = params.userWallet.walletId, + cryptoCurrency = cryptoCurrency, + ).getOrNull() + + stringReference( + protocolBalance.format { + crypto( + symbol = AAVEV3_PREFIX + cryptoCurrency.symbol, + decimals = cryptoCurrency.decimals, + ) + }, + ) + } } private fun subscribeOnCurrencyUpdates() { cryptoCurrencyStatusFlow.onEach { cryptoCurrencyStatus -> + val protocolBalance = yieldSupplyGetProtocolBalanceUseCase( + userWalletId = params.userWallet.walletId, + cryptoCurrency = cryptoCurrency, + ).getOrNull() + val approvalNotification = if (cryptoCurrencyStatus.value.yieldSupplyStatus?.isAllowedToSpend != true) { NotificationUM.Error( title = resourceReference(R.string.yield_module_approve_needed_notification_title), @@ -67,8 +87,24 @@ internal class YieldSupplyActiveModel @Inject constructor( null } - uiState.update { it.copy(notificationUM = approvalNotification) } + uiState.update { + it.copy( + notificationUM = approvalNotification, + availableBalance = stringReference( + protocolBalance.format { + crypto( + symbol = AAVEV3_PREFIX + cryptoCurrency.symbol, + decimals = cryptoCurrency.decimals, + ) + }, + ), + ) + } }.flowOn(dispatchers.default) .launchIn(modelScope) } + + private companion object { + const val AAVEV3_PREFIX = "a" + } } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt index 3f757c7f1b..b6481893e7 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt @@ -1,6 +1,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.active.ui import android.content.res.Configuration +import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -22,10 +23,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import com.tangem.common.ui.notifications.NotificationUM -import com.tangem.core.ui.components.ResizableText -import com.tangem.core.ui.components.SpacerH4 -import com.tangem.core.ui.components.SpacerH8 -import com.tangem.core.ui.components.SpacerWMax +import com.tangem.core.ui.components.* import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme @@ -152,7 +150,7 @@ private fun DescriptionText(state: YieldSupplyActiveContentUM) { } @Composable -private fun InfoRow(title: TextReference, info: TextReference) { +private fun InfoRow(title: TextReference, info: TextReference?) { Row( horizontalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier.padding(horizontal = 4.dp, vertical = 12.dp), @@ -163,11 +161,21 @@ private fun InfoRow(title: TextReference, info: TextReference) { color = TangemTheme.colors.text.primary1, ) SpacerWMax() - Text( - text = info.resolveReference(), - style = TangemTheme.typography.body1, - color = TangemTheme.colors.text.tertiary, - ) + + AnimatedContent(info) { currentInfo -> + if (currentInfo != null) { + Text( + text = currentInfo.resolveReference(), + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.tertiary, + ) + } else { + TextShimmer( + text = title.resolveReference(), + style = TangemTheme.typography.body1, + ) + } + } } }