From d2bef0bf1a78da679400daff91c73c000a485708 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 29 Oct 2025 23:05:18 +0300 Subject: [PATCH 1/5] Updated on 2026-08-14 --- .../tap/di/domain/YieldSupplyDomainModule.kt | 13 + .../ui/components/text/TextAnimatedCounter.kt | 54 ++++ .../format/bigdecimal/BigDecimalFiatFormat.kt | 18 ++ domain/yield-supply/build.gradle.kts | 4 + .../YieldSupplyGetRewardsBalanceUseCase.kt | 99 ++++++ ...YieldSupplyGetRewardsBalanceUseCaseTest.kt | 301 ++++++++++++++++++ features/tokendetails/impl/build.gradle.kts | 1 + .../tokendetails/TokenDetailsPreviewData.kt | 1 + .../tokendetails/model/TokenDetailsModel.kt | 25 ++ .../state/TokenDetailsBalanceBlockState.kt | 1 + .../TokenDetailsLoadedBalanceConverter.kt | 2 + .../state/factory/TokenDetailsStateFactory.kt | 14 + .../ui/components/TokenDetailsBalanceBlock.kt | 32 +- 13 files changed, 557 insertions(+), 8 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/text/TextAnimatedCounter.kt create mode 100644 domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt create mode 100644 domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.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 ea0ad78e44..e5d58f7331 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 @@ -9,6 +9,7 @@ import com.tangem.domain.yield.supply.YieldSupplyErrorResolver import com.tangem.domain.yield.supply.YieldSupplyRepository import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository import com.tangem.domain.yield.supply.usecase.* +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -176,4 +177,16 @@ internal object YieldSupplyDomainModule { currenciesRepository = currenciesRepository, ) } + + @Provides + @Singleton + fun provideYieldSupplyGetRewardsBalanceUseCase( + yieldSupplyRepository: YieldSupplyRepository, + dispatcherProvider: CoroutineDispatcherProvider, + ): YieldSupplyGetRewardsBalanceUseCase { + return YieldSupplyGetRewardsBalanceUseCase( + yieldSupplyRepository = yieldSupplyRepository, + dispatcherProvider = dispatcherProvider, + ) + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/text/TextAnimatedCounter.kt b/core/ui/src/main/java/com/tangem/core/ui/components/text/TextAnimatedCounter.kt new file mode 100644 index 0000000000..978dee9beb --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/text/TextAnimatedCounter.kt @@ -0,0 +1,54 @@ +package com.tangem.core.ui.components.text + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import com.tangem.core.ui.res.TangemTheme + +@Composable +fun TextAnimatedCounter( + text: String, + modifier: Modifier = Modifier, + style: TextStyle = TangemTheme.typography.caption1, +) { + var oldText by remember { + mutableStateOf(text) + } + SideEffect { + oldText = text + } + Row(modifier = modifier) { + for (i in text.indices) { + val oldChar = oldText.getOrNull(i) + val newChar = text[i] + val char = if (oldChar == newChar) { + oldText[i] + } else { + text[i] + } + AnimatedContent( + targetState = char, + transitionSpec = { + slideInVertically { it }.togetherWith(slideOutVertically { -it }) + }, + ) { char -> + Text( + text = char.toString(), + style = style, + softWrap = false, + ) + } + } + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt index aef02f2fe3..5c41281344 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt @@ -117,6 +117,24 @@ fun BigDecimalFiatFormat.price(): BigDecimalFormat = BigDecimalFormat { value -> .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) } +/** + * Formats fiat amount with an exact number of fractional digits. + */ +fun BigDecimalFiatFormat.anyDecimals(decimals: Int): BigDecimalFormat = BigDecimalFormat { value -> + val formatterCurrency = getJavaCurrencyByCode(fiatCurrencyCode) + + val formatter = NumberFormat.getCurrencyInstance(locale).apply { + currency = formatterCurrency + maximumFractionDigits = decimals + minimumFractionDigits = decimals + isGroupingUsed = true + roundingMode = RoundingMode.HALF_UP + } + + formatter.format(value) + .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) +} + // == Helpers == private fun BigDecimal.isLessThanThreshold() = this > BigDecimal.ZERO && this < FIAT_FORMAT_THRESHOLD diff --git a/domain/yield-supply/build.gradle.kts b/domain/yield-supply/build.gradle.kts index b2648f08f0..58724d5cd7 100644 --- a/domain/yield-supply/build.gradle.kts +++ b/domain/yield-supply/build.gradle.kts @@ -13,6 +13,9 @@ tasks.withType().configureEach { } dependencies { + /** Core */ + implementation(projects.core.ui) + /** Domain */ implementation(projects.domain.models) implementation(projects.domain.yieldSupply.models) @@ -23,6 +26,7 @@ dependencies { implementation(projects.domain.blockaid) implementation(projects.domain.quotes) implementation(projects.domain.tokens) + implementation(projects.domain.appCurrency.models) /** Tandem SDK */ implementation(tangemDeps.blockchain) diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt new file mode 100644 index 0000000000..fb055caf3f --- /dev/null +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt @@ -0,0 +1,99 @@ +package com.tangem.domain.yield.supply.usecase + +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.format.bigdecimal.anyDecimals +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.yield.supply.YieldSupplyRepository +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import java.math.BigDecimal +import java.math.RoundingMode +import kotlin.math.ceil +import kotlin.math.ln + +class YieldSupplyGetRewardsBalanceUseCase( + private val yieldSupplyRepository: YieldSupplyRepository, + private val dispatcherProvider: CoroutineDispatcherProvider, +) { + + operator fun invoke(status: CryptoCurrencyStatus, appCurrency: AppCurrency): Flow = flow { + val amount: BigDecimal? = status.value.amount?.let { amt -> + status.value.fiatRate?.let { rate -> amt.multiply(rate) } + } + if (amount == null) return@flow + + val tokenAddress = (status.currency as? CryptoCurrency.Token)?.contractAddress ?: return@flow + val apy = try { + val markets = yieldSupplyRepository.getCachedMarkets() ?: yieldSupplyRepository.updateMarkets() + markets.firstOrNull { it.tokenAddress.equals(tokenAddress, ignoreCase = true) }?.apy ?: BigDecimal.ZERO + } catch (_: Throwable) { + BigDecimal.ZERO + } + + val apyFraction = apy.divide(HUNDRED_BD, SCALE, RoundingMode.HALF_UP) + + if (apyFraction.compareTo(BigDecimal.ZERO) == 0) { + return@flow + } + + val initialPerTickDelta = amount + .multiply(apyFraction) + .multiply(TICK_SECONDS_BD) + .divide(SECONDS_PER_YEAR_BD, SCALE, RoundingMode.HALF_UP) + .abs() + + val minVisibleDecimals = calculateMinVisibleDecimals(initialPerTickDelta) + + var currentBalance: BigDecimal = amount + while (true) { + emit( + currentBalance.format { + fiat( + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ).anyDecimals(decimals = minVisibleDecimals) + }, + ) + + val perTickDelta = currentBalance + .multiply(apyFraction) + .multiply(TICK_SECONDS_BD) + .divide(SECONDS_PER_YEAR_BD, SCALE, RoundingMode.HALF_UP) + + currentBalance = currentBalance.add(perTickDelta) + + delay(TICK_MILLIS) + } + }.flowOn(dispatcherProvider.default) + + private fun calculateMinVisibleDecimals(perTickDeltaAbs: BigDecimal): Int { + if (perTickDeltaAbs <= BigDecimal.ZERO) return MIN_DECIMALS + + val perTickAsDouble = perTickDeltaAbs.toDouble() + if (perTickAsDouble.isNaN() || perTickAsDouble.isInfinite()) return MIN_DECIMALS + + val safe = if (perTickAsDouble <= 0.0) EPSILON else perTickAsDouble + val raw = ceil(-ln(safe) / LN_10) + return raw.toInt().coerceIn(MIN_DECIMALS, MAX_DECIMALS) + } + + private companion object { + const val TICK_MILLIS: Long = 300 + private val TICK_SECONDS_BD = BigDecimal("0.3") + private val SECONDS_PER_YEAR_BD = BigDecimal("31536000") // 365 * 24 * 60 * 60 + private val HUNDRED_BD = BigDecimal("100") + private const val SCALE = 18 + + private const val MIN_DECIMALS = 3 + private const val MAX_DECIMALS = 8 + + private val LN_10 = ln(10.0) + private const val EPSILON = 1e-18 + } +} \ No newline at end of file diff --git a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt new file mode 100644 index 0000000000..d592d15e50 --- /dev/null +++ b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt @@ -0,0 +1,301 @@ +package com.tangem.domain.yield.supply.usecase + +import com.google.common.truth.Truth.assertThat +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.anyDecimals +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.network.Network +import com.tangem.domain.models.network.NetworkAddress +import com.tangem.domain.yield.supply.YieldSupplyRepository +import com.tangem.domain.yield.supply.models.YieldMarketToken +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.async +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import java.math.BigDecimal +import java.math.RoundingMode +import kotlin.math.ceil +import kotlin.math.ln + +class YieldSupplyGetRewardsBalanceUseCaseTest { + + private val repository: YieldSupplyRepository = mockk(relaxed = true) + + @Test + fun `GIVEN null amount WHEN invoke THEN emit nothing`() = runTest { + val token = createToken(createNetwork()) + val status = CryptoCurrencyStatus( + currency = token, + value = CryptoCurrencyStatus.Loading, + ) + + val dispatcherProvider = testDispatcherProvider(this) + val useCase = YieldSupplyGetRewardsBalanceUseCase(repository, dispatcherProvider) + val appCurrency = AppCurrency.Default + + val emissions = useCase(status, appCurrency).toList() + assertThat(emissions).isEmpty() + } + + @Test + fun `GIVEN coin currency WHEN invoke THEN emit nothing`() = runTest { + val network = createNetwork() + val coin = createNativeCoin(network) + val status = CryptoCurrencyStatus( + currency = coin, + value = CryptoCurrencyStatus.Custom( + amount = BigDecimal.ONE, + fiatAmount = null, + fiatRate = BigDecimal.ONE, + priceChange = null, + yieldBalance = null, + yieldSupplyStatus = null, + hasCurrentNetworkTransactions = false, + pendingTransactions = emptySet(), + networkAddress = NetworkAddress.Single( + NetworkAddress.Address(value = "0xabc", type = NetworkAddress.Address.Type.Primary), + ), + sources = CryptoCurrencyStatus.Sources(), + ), + ) + + val dispatcherProvider = testDispatcherProvider(this) + val useCase = YieldSupplyGetRewardsBalanceUseCase(repository, dispatcherProvider) + val appCurrency = AppCurrency.Default + + val emissions = useCase(status, appCurrency).toList() + assertThat(emissions).isEmpty() + } + + @Test + fun `GIVEN zero apy WHEN invoke THEN emit nothing`() = runTest { + val network = createNetwork() + val token = createToken(network) + val amount = BigDecimal("123.45") + val status = CryptoCurrencyStatus( + currency = token, + value = CryptoCurrencyStatus.Custom( + amount = amount, + fiatAmount = null, + fiatRate = BigDecimal.ONE, + priceChange = null, + yieldBalance = null, + yieldSupplyStatus = null, + hasCurrentNetworkTransactions = false, + pendingTransactions = emptySet(), + networkAddress = NetworkAddress.Single( + NetworkAddress.Address(value = "0xabc", type = NetworkAddress.Address.Type.Primary), + ), + sources = CryptoCurrencyStatus.Sources(), + ), + ) + + coEvery { repository.getCachedMarkets() } returns listOf( + YieldMarketToken( + tokenAddress = token.contractAddress, + chainId = 1, + apy = BigDecimal.ZERO, + isActive = true, + maxFeeNative = "0", + maxFeeUSD = "0", + backendId = "id", + ), + ) + + val dispatcherProvider = testDispatcherProvider(this) + val useCase = YieldSupplyGetRewardsBalanceUseCase(repository, dispatcherProvider) + val appCurrency = AppCurrency.Default + + val emissions = useCase(status, appCurrency).toList() + assertThat(emissions).isEmpty() + } + + @Test + fun `GIVEN positive apy WHEN invoke THEN emit growing formatted balances`() = runTest { + val network = createNetwork() + val token = createToken(network) + val amount = BigDecimal("100.0") + val apy = BigDecimal("12.0") // 12% + + val status = CryptoCurrencyStatus( + currency = token, + value = CryptoCurrencyStatus.Custom( + amount = amount, + fiatAmount = null, + fiatRate = BigDecimal.ONE, + priceChange = null, + yieldBalance = null, + yieldSupplyStatus = null, + hasCurrentNetworkTransactions = false, + pendingTransactions = emptySet(), + networkAddress = NetworkAddress.Single( + NetworkAddress.Address(value = "0xabc", type = NetworkAddress.Address.Type.Primary), + ), + sources = CryptoCurrencyStatus.Sources(), + ), + ) + + coEvery { repository.getCachedMarkets() } returns listOf( + YieldMarketToken( + tokenAddress = token.contractAddress, + chainId = 1, + apy = apy, + isActive = true, + maxFeeNative = "0", + maxFeeUSD = "0", + backendId = "id", + ), + ) + + val dispatcherProvider = testDispatcherProvider(this) + val useCase = YieldSupplyGetRewardsBalanceUseCase(repository, dispatcherProvider) + val appCurrency = AppCurrency.Default + + val deferred = async { useCase(status, appCurrency).take(3).toList() } + + testScheduler.advanceUntilIdle() + advanceTimeBy(300) + testScheduler.advanceUntilIdle() + advanceTimeBy(300) + testScheduler.advanceUntilIdle() + + val collected = deferred.await() + assertThat(collected).hasSize(3) + + val expectedDecimals = calculateMinVisibleDecimalsForTest(initialPerTickDelta(amount, apy)) + + val firstExpected = amount.format { fiat( + appCurrency.code, + appCurrency.symbol, + ).anyDecimals(decimals = expectedDecimals) } + assertThat(collected[0]).isEqualTo(firstExpected) + + val firstNext = nextBalance(amount, apy) + val secondExpected = firstNext.format { fiat( + appCurrency.code, + appCurrency.symbol, + ).anyDecimals(decimals = expectedDecimals) } + assertThat(collected[1]).isEqualTo(secondExpected) + + val secondNext = nextBalance(firstNext, apy) + val thirdExpected = secondNext.format { fiat( + appCurrency.code, + appCurrency.symbol, + ).anyDecimals(decimals = expectedDecimals) } + assertThat(collected[2]).isEqualTo(thirdExpected) + } + + private fun testDispatcherProvider(scope: TestScope): CoroutineDispatcherProvider { + val dispatcher: CoroutineDispatcher = StandardTestDispatcher(scope.testScheduler) + return object : CoroutineDispatcherProvider { + override val main: CoroutineDispatcher = dispatcher + override val mainImmediate: CoroutineDispatcher = dispatcher + override val io: CoroutineDispatcher = dispatcher + override val default: CoroutineDispatcher = dispatcher + override val single: CoroutineDispatcher = dispatcher + } + } + + private fun createNetwork(): Network { + val derivationPath = Network.DerivationPath.None + return Network( + id = Network.ID(Network.RawID("polygon"), derivationPath), + backendId = "polygon", + name = "Polygon", + currencySymbol = "MATIC", + derivationPath = derivationPath, + isTestnet = false, + standardType = Network.StandardType.ERC20, + hasFiatFeeRate = false, + canHandleTokens = true, + transactionExtrasType = Network.TransactionExtrasType.NONE, + nameResolvingType = Network.NameResolvingType.ENS, + ) + } + + private fun createNativeCoin(network: Network): CryptoCurrency.Coin { + val nativeCoinId = CryptoCurrency.ID( + prefix = CryptoCurrency.ID.Prefix.COIN_PREFIX, + body = CryptoCurrency.ID.Body.NetworkId(network.rawId), + suffix = CryptoCurrency.ID.Suffix.RawID("polygon-ecosystem-token"), + ) + return CryptoCurrency.Coin( + id = nativeCoinId, + network = network, + name = "Polygon", + symbol = "MATIC", + decimals = 18, + iconUrl = null, + isCustom = false, + ) + } + + private fun createToken(network: Network): CryptoCurrency.Token { + val tokenId = CryptoCurrency.ID( + prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX, + body = CryptoCurrency.ID.Body.NetworkId(network.rawId), + suffix = CryptoCurrency.ID.Suffix.RawID("test-token", "0xContract"), + ) + return CryptoCurrency.Token( + id = tokenId, + network = network, + name = "Test Token", + symbol = "TT", + decimals = 18, + iconUrl = null, + isCustom = false, + contractAddress = "0xContract", + ) + } + + private fun initialPerTickDelta(amount: BigDecimal, apy: BigDecimal): BigDecimal { + val apyFraction = apy.divide(HUNDRED_BD, SCALE, RoundingMode.HALF_UP) + return amount + .multiply(apyFraction) + .multiply(TICK_SECONDS_BD) + .divide(SECONDS_PER_YEAR_BD, SCALE, RoundingMode.HALF_UP) + .abs() + } + + private fun nextBalance(current: BigDecimal, apy: BigDecimal): BigDecimal { + val apyFraction = apy.divide(HUNDRED_BD, SCALE, RoundingMode.HALF_UP) + val perTickDelta = current + .multiply(apyFraction) + .multiply(TICK_SECONDS_BD) + .divide(SECONDS_PER_YEAR_BD, SCALE, RoundingMode.HALF_UP) + return current.add(perTickDelta) + } + + private fun calculateMinVisibleDecimalsForTest(perTickDeltaAbs: BigDecimal): Int { + if (perTickDeltaAbs <= BigDecimal.ZERO) return MIN_DECIMALS + val perTickAsDouble = perTickDeltaAbs.toDouble() + if (perTickAsDouble.isNaN() || perTickAsDouble.isInfinite()) return MIN_DECIMALS + val safe = if (perTickAsDouble <= 0.0) EPSILON else perTickAsDouble + val raw = ceil(-ln(safe) / LN_10) + return raw.toInt().coerceIn(MIN_DECIMALS, MAX_DECIMALS) + } + + private companion object { + private const val SCALE = 18 + private val TICK_SECONDS_BD = BigDecimal("0.3") + private val SECONDS_PER_YEAR_BD = BigDecimal("31536000") + private val HUNDRED_BD = BigDecimal("100") + + private const val MIN_DECIMALS = 3 + private const val MAX_DECIMALS = 8 + + private val LN_10 = ln(10.0) + private const val EPSILON = 1e-18 + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts index c02aa188d0..2d9665f967 100644 --- a/features/tokendetails/impl/build.gradle.kts +++ b/features/tokendetails/impl/build.gradle.kts @@ -87,6 +87,7 @@ dependencies { implementation(projects.domain.txhistory.models) implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) + implementation(projects.domain.yieldSupply) /** Temp dependency to swap domain */ implementation(projects.features.swap.domain) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt index 66afedfdbf..6ad048f49b 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt @@ -124,6 +124,7 @@ internal object TokenDetailsPreviewData { selectedBalanceType = BalanceType.ALL, onBalanceSelect = {}, displayCryptoBalance = "966,96 XLM", + displayYeildSupplyCryptoBalance = null, displayFiatBalance = "91,50$", isBalanceSelectorEnabled = true, isBalanceFlickering = false, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index de7ae04637..97f16addf1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -40,6 +40,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TokenReceiveNotification import com.tangem.domain.models.account.Account import com.tangem.domain.models.currency.CryptoCurrency @@ -74,6 +75,7 @@ import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase import com.tangem.domain.wallets.usecase.GetExtendedPublicKeyForCurrencyUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase +import com.tangem.domain.yield.supply.usecase.YieldSupplyGetRewardsBalanceUseCase import com.tangem.feature.tokendetails.deeplink.TokenDetailsDeepLinkActionListener import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsCurrencyStatusAnalyticsSender @@ -151,6 +153,7 @@ internal class TokenDetailsModel @Inject constructor( private val accountsFeatureToggles: AccountsFeatureToggles, private val getAccountCryptoCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase, + private val yieldSupplyGetRewardsBalanceUseCase: YieldSupplyGetRewardsBalanceUseCase, ) : Model(), TokenDetailsClickIntents, YieldSupplyDepositedWarningComponent.ModelCallback { private val params = paramsContainer.require() @@ -165,6 +168,7 @@ internal class TokenDetailsModel @Inject constructor( private val expressTxJobHolder = JobHolder() private val buttonsJobHolder = JobHolder() private val stakingJobHolder = JobHolder() + private val yieldSupplyBalanceJobHolder = JobHolder() private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null @@ -352,6 +356,7 @@ internal class TokenDetailsModel @Inject constructor( updateButtons(currencyStatus = status) updateWarnings(status) subscribeOnUpdateStakingInfo(status) + subscribeOnYieldSupplyBalanceIfActive(status) } currencyStatusAnalyticsSender.send(maybeCurrencyStatus) } @@ -395,6 +400,26 @@ internal class TokenDetailsModel @Inject constructor( .saveIn(expressTxJobHolder) } + private fun subscribeOnYieldSupplyBalanceIfActive(status: CryptoCurrencyStatus) { + if (yieldSupplyFeatureToggles.isYieldSupplyFeatureEnabled && + status.value.yieldSupplyStatus?.isActive == true + ) { + if (yieldSupplyBalanceJobHolder.isActive && status.value.sources.networkSource != StatusSource.ACTUAL) { + return + } + yieldSupplyGetRewardsBalanceUseCase(status = status, appCurrency = selectedAppCurrencyFlow.value) + .onEach { formatted -> + internalUiState.value = stateFactory.getStateWithUpdatedYieldSupplyDisplayBalance(formatted) + } + .flowOn(dispatchers.main) + .launchIn(modelScope) + .saveIn(yieldSupplyBalanceJobHolder) + } else { + yieldSupplyBalanceJobHolder.cancel() + internalUiState.value = stateFactory.getStateWithUpdatedYieldSupplyDisplayBalance(null) + } + } + private fun updateNetworkToSwapBalance(toCryptoCurrency: CryptoCurrency) { modelScope.launch { updateDelayedCurrencyStatusUseCase( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsBalanceBlockState.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsBalanceBlockState.kt index b650254ea3..a74d80f6b8 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsBalanceBlockState.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsBalanceBlockState.kt @@ -28,6 +28,7 @@ internal sealed class TokenDetailsBalanceBlockState { val isBalanceSelectorEnabled: Boolean, val isBalanceFlickering: Boolean, val yieldSupplyState: TokenDetailsYieldSupplyState = TokenDetailsYieldSupplyState.Empty, + val displayYeildSupplyCryptoBalance: String? = null, ) : TokenDetailsBalanceBlockState() data class Error( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index 22b55017a2..3243636297 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -98,6 +98,8 @@ internal class TokenDetailsLoadedBalanceConverter( stakingCryptoAmount, currentState.selectedBalanceType, ), + displayYeildSupplyCryptoBalance = (currentState as? TokenDetailsBalanceBlockState.Content) + ?.displayYeildSupplyCryptoBalance, balanceSegmentedButtonConfig = currentState.balanceSegmentedButtonConfig, onBalanceSelect = clickIntents::onBalanceSelect, selectedBalanceType = currentState.selectedBalanceType, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index af30b75a43..405d41af19 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -28,6 +28,7 @@ import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig +import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig import com.tangem.features.tokendetails.impl.R @@ -313,6 +314,19 @@ internal class TokenDetailsStateFactory( return balanceSelectStateConverter.convert(buttonConfig) } + fun getStateWithUpdatedYieldSupplyDisplayBalance(displayBalance: String?): TokenDetailsState { + val state = currentStateProvider() + val balanceState = state.tokenBalanceBlockState + return state.copy( + tokenBalanceBlockState = when (balanceState) { + is TokenDetailsBalanceBlockState.Content -> + balanceState.copy(displayYeildSupplyCryptoBalance = displayBalance) + is TokenDetailsBalanceBlockState.Error -> balanceState + is TokenDetailsBalanceBlockState.Loading -> balanceState + }, + ) + } + fun getStateWithConfirmHideExpressStatus(): TokenDetailsState { return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt index d38b7d4e5c..9eaa517709 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.buttons.HorizontalActionChips import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons +import com.tangem.core.ui.components.text.TextAnimatedCounter import com.tangem.core.ui.components.text.applyBladeBrush import com.tangem.core.ui.extensions.orMaskWithStars import com.tangem.core.ui.extensions.resolveReference @@ -121,14 +122,29 @@ private fun FiatBalance( height = TangemTheme.dimens.size32, ), ) - is TokenDetailsBalanceBlockState.Content -> Text( - modifier = modifier, - text = state.displayFiatBalance.orMaskWithStars(isBalanceHidden), - style = TangemTheme.typography.h2.applyBladeBrush( - isEnabled = state.isBalanceFlickering, - textColor = TangemTheme.colors.text.primary1, - ), - ) + is TokenDetailsBalanceBlockState.Content -> if (state.displayYeildSupplyCryptoBalance != null && + !isBalanceHidden + ) { + TextAnimatedCounter( + modifier = modifier, + text = state.displayYeildSupplyCryptoBalance, + style = TangemTheme.typography.h2.applyBladeBrush( + isEnabled = state.isBalanceFlickering, + textColor = TangemTheme.colors.text.primary1, + ), + ) + } else { + Text( + modifier = modifier, + text = (state.displayYeildSupplyCryptoBalance ?: state.displayFiatBalance).orMaskWithStars( + isBalanceHidden, + ), + style = TangemTheme.typography.h2.applyBladeBrush( + isEnabled = state.isBalanceFlickering, + textColor = TangemTheme.colors.text.primary1, + ), + ) + } is TokenDetailsBalanceBlockState.Error -> Text( modifier = modifier, text = DASH_SIGN.orMaskWithStars(isBalanceHidden), From eda8c345cb79b4552ef8de4d0a296002ebd74962 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Nov 2025 08:25:45 +0300 Subject: [PATCH 2/5] Updated on 2026-08-14 --- .../usecase/YieldSupplyGetMaxFeeUseCase.kt | 8 +++----- .../impl/common/entity/YieldSupplyFeeUM.kt | 1 - .../common/ui/YieldSupplyActionContent.kt | 1 - .../YieldSupplyActiveFeeContentTransformer.kt | 11 +++++----- .../approve/model/YieldSupplyApproveModel.kt | 1 - .../ui/YieldSupplyFeePolicyContent.kt | 1 - .../model/YieldSupplyStartEarningModel.kt | 2 +- ...SupplyStartEarningFeeContentTransformer.kt | 20 +++++++------------ ...dSupplyStopEarningFeeContentTransformer.kt | 1 - 9 files changed, 17 insertions(+), 29 deletions(-) diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt index b7f7417185..ed746b30a4 100644 --- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt @@ -61,20 +61,18 @@ class YieldSupplyGetMaxFeeUseCase( .firstOrNull { it.yieldSupplyKey == token.yieldSupplyKey() } val marketToken = cachedMarketToken ?: yieldSupplyRepository.getTokenStatus(token) val maxFeeNative = marketToken.maxFeeNative - val maxFeeToken = maxFeeNative.multiply(nativeFiatRate) + val fiatMaxFee = maxFeeNative.multiply(nativeFiatRate) - val rateRatio = nativeFiatRate.divide( + val maxFeeToken = fiatMaxFee.divide( fiatRate, cryptoCurrencyStatus.currency.decimals, RoundingMode.HALF_UP, ) - val tokenValue = rateRatio.multiply(maxFeeNative) - YieldSupplyMaxFee( nativeMaxFee = maxFeeNative, tokenMaxFee = maxFeeToken, - fiatMaxFee = tokenValue.stripTrailingZeros(), + fiatMaxFee = fiatMaxFee.stripTrailingZeros(), ) } } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt index ee74e2b820..20e09cc6cb 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt @@ -15,7 +15,6 @@ internal sealed class YieldSupplyFeeUM { val feeFiatValue: TextReference, // TODO move to FeePolicyUM val estimatedFiatValue: TextReference, - val tokenFeeFiatValue: TextReference, val maxNetworkFeeFiatValue: TextReference, val minTopUpFiatValue: TextReference, val feeNoteValue: TextReference = TextReference.EMPTY, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt index d2b8c520de..71645d1247 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt @@ -149,7 +149,6 @@ private class YieldSupplyActionContentPreviewProvider : PreviewParameterProvider yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = persistentListOf(), feeFiatValue = stringReference("$0.99"), - tokenFeeFiatValue = stringReference("$1.45"), maxNetworkFeeFiatValue = stringReference("$8.50"), minTopUpFiatValue = stringReference("$50"), feeNoteValue = TextReference.EMPTY, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt index dbabb4a9f5..44e98e521f 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt @@ -37,11 +37,12 @@ internal class YieldSupplyActiveFeeContentTransformer( val tokenFiatFeeValueText = tokenFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) } val maxFeeCryptoValueText = maxNetworkFee.tokenMaxFee.format { crypto(cryptoCurrency) } - val maxFiatFeeValueText = maxNetworkFee.fiatMaxFee.format { fiat( - appCurrency.code, - appCurrency - .symbol, - ) } + val maxFiatFeeValueText = maxNetworkFee.fiatMaxFee.format { + fiat( + appCurrency.code, + appCurrency.symbol, + ) + } val feeNoteValue: TextReference = resourceReference( id = R.string.yield_module_fee_policy_sheet_fee_note, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt index e2c89da4c0..baa31bd4fd 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt @@ -254,7 +254,6 @@ internal class YieldSupplyApproveModel @Inject constructor( approvalTransitionData.copy(fee = transactionFee.normal), ), feeFiatValue = stringReference(fiatFee), - tokenFeeFiatValue = TextReference.EMPTY, maxNetworkFeeFiatValue = TextReference.EMPTY, minTopUpFiatValue = TextReference.EMPTY, feeNoteValue = TextReference.EMPTY, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt index f00297a2f9..d4593e4ca6 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt @@ -171,7 +171,6 @@ private fun YieldSupplyFeePolicyContent_Preview() { transactionDataList = persistentListOf(), feeFiatValue = stringReference("$1.45"), maxNetworkFeeFiatValue = stringReference("$8.50"), - tokenFeeFiatValue = stringReference("$1.45"), minTopUpFiatValue = stringReference("$50"), feeNoteValue = resourceReference( id = R.string.yield_module_fee_policy_sheet_fee_note, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt index 3446144179..bc56f86994 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt @@ -192,7 +192,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( updatedTransactionList = updatedTransactionList, feeValue = feeSum, maxNetworkFee = maxFee, - estimatedFeeValue = estimatedFee, + estimatedFeeValueInTokenCurrency = estimatedFee, minAmount = minAmount, ), ) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt index 782c6b2d3e..58aba7dc22 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt @@ -16,7 +16,6 @@ import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.toPersistentList import java.math.BigDecimal -import java.math.RoundingMode @Suppress("LongParameterList") internal class YieldSupplyStartEarningFeeContentTransformer( @@ -25,7 +24,7 @@ internal class YieldSupplyStartEarningFeeContentTransformer( private val appCurrency: AppCurrency, private val updatedTransactionList: List, private val feeValue: BigDecimal, - private val estimatedFeeValue: BigDecimal, + private val estimatedFeeValueInTokenCurrency: BigDecimal, private val maxNetworkFee: YieldSupplyMaxFee, private val minAmount: BigDecimal, ) : Transformer { @@ -37,14 +36,10 @@ internal class YieldSupplyStartEarningFeeContentTransformer( val feeFiat = feeFiatRate?.let(feeValue::multiply) val feeFiatValueText = feeFiat.format { fiat(appCurrency.code, appCurrency.symbol) } - val estimatedFeeFiat = estimatedFeeValue - val estimatedFeeFiatValueText = estimatedFeeFiat.format { fiat(appCurrency.code, appCurrency.symbol) } - - val tokenCryptoFee = tokenFiatRate?.let { rate -> - estimatedFeeFiat.divide(rate, cryptoCurrency.decimals, RoundingMode.HALF_UP) - } - val tokenCryptoFeeValueText = tokenCryptoFee.format { crypto(cryptoCurrency) } - val tokenFiatFeeValueText = estimatedFeeFiat.format { fiat(appCurrency.code, appCurrency.symbol) } + val estimatedFeeToken = estimatedFeeValueInTokenCurrency + val estimatedFeeTokenValueText = estimatedFeeToken.format { crypto(cryptoCurrency) } + val estimatedFiatFee = tokenFiatRate?.let(estimatedFeeToken::multiply) + val estimatedFeeFiatValueText = estimatedFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) } val maxFeeCryptoValueText = maxNetworkFee.tokenMaxFee.format { crypto(cryptoCurrency) } val maxFiatFeeValueText = maxNetworkFee.fiatMaxFee.format { fiat(appCurrency.code, appCurrency.symbol) } @@ -56,8 +51,8 @@ internal class YieldSupplyStartEarningFeeContentTransformer( val feeNoteValue = resourceReference( id = R.string.yield_module_fee_policy_sheet_fee_note, formatArgs = wrappedList( - tokenFiatFeeValueText, - tokenCryptoFeeValueText, + estimatedFeeFiatValueText, + estimatedFeeTokenValueText, maxFiatFeeValueText, maxFeeCryptoValueText, ), @@ -78,7 +73,6 @@ internal class YieldSupplyStartEarningFeeContentTransformer( yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = updatedTransactionList.toPersistentList(), feeFiatValue = stringReference(feeFiatValueText), - tokenFeeFiatValue = stringReference(tokenFiatFeeValueText), maxNetworkFeeFiatValue = stringReference(maxFiatFeeValueText), minTopUpFiatValue = stringReference(minAmountFiatText), feeNoteValue = feeNoteValue, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt index 6c1881f305..51d0fc112d 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt @@ -34,7 +34,6 @@ internal class YieldSupplyStopEarningFeeContentTransformer( yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = transactions.toPersistentList(), feeFiatValue = stringReference(fiatFeeText), - tokenFeeFiatValue = TextReference.EMPTY, maxNetworkFeeFiatValue = TextReference.EMPTY, minTopUpFiatValue = TextReference.EMPTY, feeNoteValue = TextReference.EMPTY, From 982882e67be7d9e732308bf0e1a00d75a7b0d203 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Nov 2025 17:51:19 +0300 Subject: [PATCH 3/5] Updated on 2026-08-14 --- .../usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt index d592d15e50..254c8c6d4a 100644 --- a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt +++ b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt @@ -107,8 +107,8 @@ class YieldSupplyGetRewardsBalanceUseCaseTest { chainId = 1, apy = BigDecimal.ZERO, isActive = true, - maxFeeNative = "0", - maxFeeUSD = "0", + maxFeeNative = BigDecimal.ZERO, + maxFeeUSD = BigDecimal.ZERO, backendId = "id", ), ) @@ -152,8 +152,8 @@ class YieldSupplyGetRewardsBalanceUseCaseTest { chainId = 1, apy = apy, isActive = true, - maxFeeNative = "0", - maxFeeUSD = "0", + maxFeeNative = BigDecimal.ZERO, + maxFeeUSD = BigDecimal.ZERO, backendId = "id", ), ) From 4ad958be8949a117d13bd99898c382cb616274f9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Nov 2025 19:14:56 +0300 Subject: [PATCH 4/5] Updated on 2026-08-14 --- core/res/src/main/res/values-de/strings.xml | 2 + core/res/src/main/res/values-es/strings.xml | 1 + core/res/src/main/res/values-fr/strings.xml | 2 + core/res/src/main/res/values-ja/strings.xml | 63 ++++++++++--------- core/res/src/main/res/values-ru/strings.xml | 33 +++++++++- .../src/main/res/values-uk-rUA/strings.xml | 1 + core/res/src/main/res/values/strings.xml | 13 ++-- .../utils/SdkTransactionTypeConverter.kt | 3 + .../src/main/assets/contract_methods.json | 9 ++- .../tangem/domain/models/network/TxInfo.kt | 3 + ...xHistoryItemToTransactionStateConverter.kt | 28 +++++---- .../converter/TxHistoryItemStateConverter.kt | 5 +- gradle/tangem_dependencies.toml | 2 +- 13 files changed, 111 insertions(+), 54 deletions(-) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 7ada2a897d..0c8a26dff9 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -1384,9 +1384,11 @@ Verstecken Google Wallet öffnen Richte Tangem Pay mit wenigen Klicks ein und bezahlen mit Google Pay. + Richte Tangem Pay mit wenigen Klicks ein und bezahlen mit Apple Pay. Karte zu Google Pay hinzufügen Karte zu Apple Pay hinzufügen Google Wallet öffnen + Apple Wallet öffnen Tippe auf „Karte hinzufügen“. Gebe die Kartendaten manuell ein Verifiziere die Karte mit dem Einmalpasswort (OPT), das an Dein Gerät gesendet wird. diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index d036fbae09..7a35e701c3 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -204,6 +204,7 @@ Importe En progreso Más tarde + Más información %1$s quedan Bloqueado Red principal diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index bdf1ca0a6b..547fa6c870 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -182,6 +182,7 @@ Importez En cours Plus tard + En savoir plus Il reste %1$s Verrouillé Réseau principal @@ -1452,6 +1453,7 @@ Demande de transaction Montant illimité WalletConnect + En savoir plus Ignorer Vous avez une sauvegarde interrompue. Voulez-vous la reprendre ? Oui, reprendre diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index a437982f8e..35063b6e10 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -1356,6 +1356,7 @@ 拒否 保留中 利用規約・手数料・利用制限 + 利用規約と上限条件 銀行がこの取引リクエストを拒否しました。 この手数料は、送金処理にかかるコストをカバーするためのものです。 資金は引き続き使用できます。いつでも一時停止できます。 @@ -1377,12 +1378,12 @@ 非表示 Googleウォレットを開く 数回タップするだけでTangem Payの設定完了。Google Payですぐに支払いを始めましょう。 + 数回タップするだけでTangem Payの設定完了。Apple Payですぐに支払いを始めましょう。 Google Payにカードを追加する Apple Payにカードを追加する Googleウォレットを開く - 右上の「+」ボタンをタップ - 開く - Apple Wallet + 右上の「+」ボタンをタップ + Appleウォレットを開く 「カードを追加」をタップします 「デビットカードまたはクレジットカード」をタップ カードの詳細を手動で入力してください @@ -1409,7 +1410,7 @@ 余計な費用なしで、表示金額のみを支払う あなたの住所や資産を開示することなく、個別の支払い用アカウントが作成されます。 他に類を見ないプライバシー - 無料のCryptoカード\nを数分で入手しましょう + 無料のTangem Payカードを数分でゲットしましょう 技術的な問題を修正しています。後でもう一度お試しください。 サービスは一時的に利用できません Tangem Pay @@ -1823,19 +1824,19 @@ いいえ、すべて送信します %s XTZを減らす 次回ウォレットにチャージするときに手数料の増加を避けるには、金額を%s XTZ減らしてください。 - 利息モードを有効にすると、このアドレスへの今後のすべての入金はAaveに送られます。ただし、資金の管理は引き続き自由に行えます。 + 利息モードが有効な場合、このアドレスへの今後の入金はすべてAaveに提供されます。資金は引き続き自由に管理できます。 %sはAaveに供給されています Aaveへの%1$s %2$sの供給は保留中です 承認 - トークンの承認は取り消されました。サービス機能を再開するには、再度承認を行ってください。 + トークンの承認が取り消されました。サービスの機能を再開するには、再度トークンの承認を行ってください。 承認が必要 - 手数料が差し引かれ、あなたの資産は再び貸し出されます。 - 引き続き収益を得るには承認が必要です。 + 手数料が差し引かれ、暗号資産が補充されます。 + 利息を継続的に生み出すには承認が必要です。 承認を確定する あなたの資金は現在Aaveプロトコルに預けられていますが、いつでも自由に管理できます。 - あなたの%sはAaveに預けられています + %sはAaveに供給されています チャートを読み込めません・・ - Aaveへの%1$s %2$sの供給は保留中です。 + %1$s %2$sをAaveに供給しています。 利回りモードを無効にする 年利%1$s%% 利用可能 @@ -1843,47 +1844,47 @@ 貸付のために入金する際は、残高から%1$s以下のネットワーク手数料が差し引かれます。 現在、ネットワーク手数料が高すぎるため貸付を実行できません。手数料が%1$s以下に下がり次第、資金が供給されます。 私の資金 - あなたの%1$sは現在Aaveにデプロイされ、利回りを生んでいます。あなたは%2$sトークンを保有しており、これはあなたの残高を表し、自動的に利回りが発生します。追加入金すると、手数料を差し引いた上でAaveに資産が追加され、さらに利回りを得られるようになります。 + %1$sはAaveにデプロイされ、利回りを生み出しています。保有している%2$sトークンは残高を表し、自動的に利回りを生み出します。チャージすると、手数料を差し引いた後の資金がAaveに供給され、さらに利回りを生み出します。 利息モード - 総収益 + トータルの利息 Aaveへの送金 Aaveの詳細を見る これは%sの現在の供給手数料です。実際のコストはアクティベーションタブに表示されます。 現在の手数料 - 今後の%sの入金はすべて、取引手数料が差し引かれて自動的にAaveに供給されます。 - 今後のチャージごとに、おおよそ%1$s(%2$s)のネットワーク手数料が差し引かれますが、上限の%3$s(%4$s)を超えることはありません。 - ネットワーク手数料が上限手数料を超えた場合、手数料が下がるまで取引は成立しません。この制限は後で変更できます。 + 今後の%sの追加入金はすべて、取引手数料が差し引かれた後、Aave に自動的に提供されます。 + 今後の追加入金ごとにおおよそのネットワーク手数料%1$s ( %2$s ) が差し引かれ、 %3$s ( %4$s ) の制限を超えることはありません。 + ネットワーク手数料が上限を超えた場合、手数料が下がるまで取引は成立しません。この制限は後で変更できます。 最大手数料 - 最小金額は、ネットワーク手数料がチャージ額の4%を超えないように現在の手数料に基づいて計算されます。その結果、最小金額は%1$s(%2$s)となります。 + 最小金額は現在のネットワーク手数料に基づいて計算され、入金額の4% 、つまり最小の%1$s ( %2$s ) を超えないようにします。 最低入金額 入金手数料ポリシー - Tangemはまた、得られた利回りに対して15%のサービス手数料を差し引きます。 + Tangemは、生成された利息に対して15%サービス手数料も徴収します。 ネットワーク手数料が下がるか、残高が最低必要額に達すると、資金は自動的にAaveに供給されます。 過去のリターン 利息モードでのトークンの承認が取り消されました。トークンを開いて再度許可してください。 トークンの承認が必要です ネットワーク接続を確認してください ネットワーク手数料についての情報にアクセスできません - あなたが行うすべての入金は、自動的にAaveへ供給されます。 + すべての追加入金は自動的にAaveに供給されます。 アカウントのすべての %1$s は自動的に Aave に供給されます。 - Aaveへの自動送金 + Aaveへの自動供給 いつでも、即座に資金を送信、交換、売却できます。 すぐに利用可能 使い方 - Aaveは、総額610億ドル以上の資産を管理する分散型プロトコルです。 + Aave は、ノンカストディアルな流動性市場を提供し、ユーザーが変動レートで利回りを獲得できるようにするオンチェーンプロトコルです。 分散型・自己管理型 このサービスを利用することにより、プロバイダー\n%1$sおよび%2$sに同意するものとします。 - Aave を接続 + Aaveに接続 Aave %1$s%% • 変動金利 Aave 平均%s 昨年のリターン - 現在の金利は常に変動し、リアルタイムの需要と供給に基づいて、Aaveオンチェーンスマートコントラクトによって自動的に計算されます。 + 現在の金利は常に変動しており、リアルタイムの需要と供給に基づいて、Aaveのオンチェーンスマートコントラクトによって自動的に計算されます。 提供 金利は変動します - 入金すると、資金は自動的にAaveに送金され、利息が付き始めます。%sが取引手数料として差し引かれます。 + チャージすると、資金は自動的にAaveに供給され、利息が生成され始めます。取引手数料として%sが差し引かれます。 資産を供給する - %sはAaveに供給されますが、管理可能な状態のままになります。 + %sはロックなしでAaveに提供され、いつでもアクセス可能な状態になります。 入金手数料ポリシーを見る 次回の入金は自動的にAaveに供給されます。 今後のすべての %1$s 入金は自動的に Aave に供給されます。 @@ -1891,20 +1892,20 @@ 停止中 利回りモードを解除中 これをオフにすると、Aaveから資産が引き出され、ウォレット内の%sに変換され、利回りの発生が停止します。 - ネットワーク手数料とは、ブロックチェーン上で取引を処理して承認するためにユーザーが支払う料金のことです。 - 利回りモードを無効にする + 利息モードを終了すると、ブロックチェーンによってネットワーク料金が請求されます。 + 利息モードを無効にする 供給 供給APY APY - 利息は自動的に発生します。 + 利息は自動的に発生します 利息は自動的に発生します - 利回りモード - 入金の処理中 + 利息モード + 利息モードの有効化 利息モード 自動 - 取引のネットワーク手数料をカバーするために、 %1$s %2$sを入金してください + 取引のネットワーク手数料をカバーするために、 %1$s %2$sを追加してください。 %s手数料を支払えません - 現在、利息モードのサービスは利用できません。しばらくしてから再度お試しください。 + 現在、利息モードはご利用いただけません。しばらくしてからもう一度お試しください。 利息モードは利用できません チャートを読み込めません・・ diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index eb34b26afd..b77cf5fb56 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -446,6 +446,7 @@ Создать новый кошелек Купить Сканировать + Разрешить приложению Tangem использовать биометрическую аутентификацию для подтверждения вашей личности и открытия приложения? в %s В сети %s Вы уверены, что хотите прервать процесс создания кода доступа? @@ -456,24 +457,48 @@ Завершите настройку, защитив приложение кодом доступа. Если вы это сделаете, придётся начать заново. Вы уверены, что хотите выйти из процесса активации? + Хранит вашу криптовалюту в безопасности и офлайн. Тонкая, как банковская карта — надёжнее банковского хранилища. Если вы это сделаете, придётся начать заново. Восстановить существующий кошелёк через резервную копию Google Drive Google Drive бэкап + Создайте новый защищённый кошелёк и переведите свои средства для максимальной защиты. + Создать новый кошелек Повысьте уровень безопасности с помощью продвинутого аппаратного кошелька Tangem. Аппаратный кошелёк + Перенести текущий кошелёк в Tangem Wallet. + Улучшить текущий кошелёк Перейти к бэкапу Пожалуйста, создайте резервную копию вашего кошелька перед установкой кода доступа. + Сначала завершите резервное копирование Сначала завершите создание резервной копии Не завершено + Другие способы Физические устройства, которые надёжно хранят ваш приватный ключ офлайн. Фраза восстановления + Чтобы защитить ваш кошелёк с помощью кода доступа, сначала завершите резервное копирование. + Чтобы улучшить кошелёк до аппаратного, сначала создайте резервную копию. Ваши приватные ключи надёжно зашифрованы и хранятся на вашем телефоне Ключи хранятся в приложении Создайте или восстановите свой кошелёк с помощью фразы восстановления — вашей встроенной резервной копии Резервная копия сид-фразы Создать мобильный кошелек + Импортировать существующий кошелек Эта фраза восстановления уже была импортирована Мобильный кошелек + Забыть кошелек + Этот кошелёк будет окончательно удалён с вашего устройства. + Вы уверены, что хотите выполнить эту операцию? + Забыть кошелек + Перейти к резервному копированию + Посмотреть резервное копирование + Забыть кошелек + Забыть всё равно + Резервная копия этого кошелька существует. Проверьте её перед удалением, чтобы убедиться, что сможете восстановить кошелёк позже. + Если вы удалите этот кошелёк без резервной копии, вы навсегда потеряете доступ к своим средствам. + Забыть этот кошелек? + Я понимаю, что если я не создал резервную копию кошелька перед его удалением, я могу потерять к нему доступ. + Я понимаю, что удаление моего кошелька не стирает его — оно просто удаляет его с моего устройства. + Фраза восстановления больше не нужна — ваша карта или кольцо Tangem становятся вашей надёжной резервной копией. Это устройство не может быть использовано для апгрейда, оно уже содержит другой кошелек. Выберите другое устройство. Это нельзя использовать для обновления. Во время операции произошла ошибка. @@ -1312,6 +1337,7 @@ Включите push-уведомления, и мы мгновенно сообщим вам, когда поступят средства. Не пропустите транзакцию Добавить новый кошелек + Если вы удалите этот кошелёк без резервной копии, вы навсегда потеряете доступ к своим средствам. Вы уверены, что хотите забыть этот кошелек? Произошла ошибка, пожалуйста, отсканируйте свою карту или кольцо для входа Этот кошелек уже был сохранен, вы можете добавить другой @@ -1633,8 +1659,8 @@ Отправляйте, обменивайте или продавайте свои средства мгновенно, когда захотите. Свободный доступ Как это работает? - Aave — ончейн-протокол для некостодиальных рынков ликвидности, позволяющий получать доход с переменной ставкой. - Децентрализованный и некостодиальный + Aave — ончейн-протокол для некастодиальных рынков ликвидности, позволяющий получать доход с переменной ставкой. + Децентрализованный и некастодиальный Используя сервис, вы соглашаетесь с %1$s и %2$s Подключить Aave Aave %1$s%% • Плавающая ставка @@ -1664,6 +1690,9 @@ Режим доходности Включение режима доходности Режим доходности + Доход включен + Доход выключен + Доход - пополнение Автоматически Внесите немного %1$s %2$s, чтобы покрыть комиссию сети за транзакции. Невозможно покрыть комиссию в %s diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index e86e8f9877..8fc009f93b 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -182,6 +182,7 @@ Імпортувати В процесі Пізніше + Дізнатися більше Залишилося %1$s Заблокований Основна мережа diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 21f5246f51..6c0c43f6d2 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -286,7 +286,7 @@ Import In progress Later - Learn more + Learn more %1$s left Legacy Bitcoin Locked @@ -1402,12 +1402,12 @@ Hide Open Google Wallet Set up Tangem Pay in a few taps and start paying with Google Pay. + Set up Tangem Pay in a few taps and start paying with Apple Pay. Add your card to Google Pay Add your card to Apple Pay Open Google Wallet - Tap “+” button on the top right - Open - Apple Wallet + Tap “+” button on the top right + Open Apple Wallet Tap “Add a card” Tap “Debit or Credit Card” Enter the card details manually @@ -1518,7 +1518,7 @@ Enable push notifications to receive alerts when funds arrive in your wallet. Don\'t Miss a Transaction Add new wallet - If you delete this wallet without a backup, you will permanently lose access to your funds + If you delete this wallet without a backup, you will permanently lose access to your funds. Are you sure you want to forget this wallet? An error has occurred, please scan your card or ring to log in This wallet has already been saved, you can add another one @@ -1975,6 +1975,9 @@ Yield Mode Enabling Yield Mode Yield Mode + Yield mode on + Yield mode off + Yield mode top-up Automatic Add some %1$s %2$s to cover the network fee for transactions. Unable to cover %s fee diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt index f5f82ef61d..7e674c1f59 100644 --- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt +++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt @@ -59,6 +59,9 @@ internal class SdkTransactionTypeConverter( "withdrawRewardsPOL", -> TxInfo.TransactionType.Staking.ClaimRewards "redelegate" -> TxInfo.TransactionType.Staking.Restake + "supplyEnter" -> TxInfo.TransactionType.YieldSupply.Enter + "supplyExit" -> TxInfo.TransactionType.YieldSupply.Exit + "supplyTopUp" -> TxInfo.TransactionType.YieldSupply.Topup null -> TxInfo.TransactionType.UnknownOperation else -> TxInfo.TransactionType.Operation(name = methodName.replaceFirstChar { it.titlecase() }) } diff --git a/domain/legacy/src/main/assets/contract_methods.json b/domain/legacy/src/main/assets/contract_methods.json index 944b8a716b..5ca94cd491 100644 --- a/domain/legacy/src/main/assets/contract_methods.json +++ b/domain/legacy/src/main/assets/contract_methods.json @@ -210,12 +210,12 @@ "0x79be55f7": { "info": "yieldModule", "source": "https://github.com/tangem/tangem-yield-module-contracts/", - "name": "supply" + "name": "supplyEnter" }, "0xc65e6dcf": { "info": "yieldModule", "source": "https://github.com/tangem/tangem-yield-module-contracts/", - "name": "supply" + "name": "supplyExit" }, "0xebd4b81c": { "info": "yieldModule", @@ -231,5 +231,10 @@ "info": "yieldModule", "source": "https://github.com/tangem/tangem-yield-module-contracts/", "name": "transfer" + }, + "0xb9de6a93": { + "info": "yieldModule", + "source": "https://github.com/tangem/tangem-yield-module-contracts/", + "name": "supplyTopUp" } } diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt index ed13b42827..65467f7460 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt @@ -115,6 +115,9 @@ data class TxInfo( @Serializable data object Exit : YieldSupply + + @Serializable + data object Topup : YieldSupply } @Serializable diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt index 33ef338944..c575a8070d 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt @@ -10,6 +10,7 @@ import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.utils.toTimeFormat import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.network.TxInfo +import com.tangem.domain.models.network.TxInfo.TransactionType import com.tangem.features.txhistory.impl.R import com.tangem.features.txhistory.utils.TxHistoryUiActions import com.tangem.utils.StringsSigns @@ -59,19 +60,22 @@ internal class TxHistoryItemToTransactionStateConverter( } } + @Suppress("CyclomaticComplexMethod") private fun TxInfo.extractTitle(): TextReference = when (val type = type) { - is TxInfo.TransactionType.Approve -> resourceReference(R.string.common_approval) - is TxInfo.TransactionType.Operation -> stringReference(type.name) - is TxInfo.TransactionType.Swap -> resourceReference(R.string.common_swap) - is TxInfo.TransactionType.Transfer -> resourceReference(R.string.common_transfer) - is TxInfo.TransactionType.YieldSupply -> resourceReference(R.string.yield_module_supply) - is TxInfo.TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) - is TxInfo.TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) - is TxInfo.TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) - is TxInfo.TransactionType.Staking.ClaimRewards -> resourceReference(R.string.common_claim_rewards) - is TxInfo.TransactionType.Staking.Withdraw -> resourceReference(R.string.staking_withdraw) - is TxInfo.TransactionType.Staking.Restake -> resourceReference(R.string.staking_restake) - is TxInfo.TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) + is TransactionType.Approve -> resourceReference(R.string.common_approval) + is TransactionType.Operation -> stringReference(type.name) + is TransactionType.Swap -> resourceReference(R.string.common_swap) + is TransactionType.Transfer -> resourceReference(R.string.common_transfer) + is TransactionType.YieldSupply.Enter -> resourceReference(R.string.yield_module_transaction_enter) + is TransactionType.YieldSupply.Exit -> resourceReference(R.string.yield_module_transaction_exit) + is TransactionType.YieldSupply.Topup -> resourceReference(R.string.yield_module_transaction_topup) + is TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) + is TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) + is TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) + is TransactionType.Staking.ClaimRewards -> resourceReference(R.string.common_claim_rewards) + is TransactionType.Staking.Withdraw -> resourceReference(R.string.staking_withdraw) + is TransactionType.Staking.Restake -> resourceReference(R.string.staking_restake) + is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) } private fun TxInfo.extractSubtitle(): TextReference = when (val interactionAddress = interactionAddressType) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt index d926942932..be2bd415fe 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt @@ -67,12 +67,15 @@ internal class TxHistoryItemStateConverter( } } + @Suppress("CyclomaticComplexMethod") private fun TxInfo.extractTitle(): TextReference = when (val type = type) { is TransactionType.Approve -> resourceReference(R.string.common_approval) is TransactionType.Operation -> stringReference(type.name) is TransactionType.Swap -> resourceReference(R.string.common_swap) is TransactionType.Transfer -> resourceReference(R.string.common_transfer) - is TransactionType.YieldSupply -> resourceReference(R.string.yield_module_supply) + is TransactionType.YieldSupply.Enter -> resourceReference(R.string.yield_module_transaction_enter) + is TransactionType.YieldSupply.Exit -> resourceReference(R.string.yield_module_transaction_exit) + is TransactionType.YieldSupply.Topup -> resourceReference(R.string.yield_module_transaction_topup) is TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) is TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) is TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 4e7835869e..98c8350883 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.30-1305" +tangemBlockchainSdk = "releases-5.30-1307" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.30-567" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From a30d7942d7daf33d5402400b9c26dd0d2b9579dc Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Nov 2025 05:58:23 +0000 Subject: [PATCH 5/5] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 98c8350883..e06f0759db 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.30-1307" +tangemBlockchainSdk = "develop-1306" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.30-567" +tangemCardSdk = "develop-564" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^