From ca286232ba061e97bb091b689acea8174edd2d8b Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 3 Mar 2025 15:30:31 +0200 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/tap/routing/utils/ChildFactory.kt | 4 +- .../com/tangem/common/routing/AppRoute.kt | 5 +- .../data/staking/DefaultStakingRepository.kt | 6 + .../tangem/domain/staking/GetYieldUseCase.kt | 6 + .../staking/repositories/StakingRepository.kt | 2 + .../repository/MockStakingRepository.kt | 150 +++++++++--------- .../impl/model/TokenActionsHandler.kt | 2 +- .../features/staking/api/StakingComponent.kt | 3 +- .../impl/presentation/model/StakingModel.kt | 13 +- .../router/DefaultTokenDetailsRouter.kt | 5 +- .../router/InnerTokenDetailsRouter.kt | 3 +- .../viewmodels/TokenDetailsViewModel.kt | 2 +- .../WalletCurrencyActionsClickIntents.kt | 2 +- 13 files changed, 111 insertions(+), 92 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 1efd190304..f1217ef2d0 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -219,7 +219,7 @@ internal class ChildFactory @Inject constructor( params = StakingComponent.Params( userWalletId = route.userWalletId, cryptoCurrencyId = route.cryptoCurrencyId, - yield = route.yield, + yieldId = route.yieldId, ), componentFactory = stakingComponentFactory, ) @@ -376,7 +376,7 @@ internal class ChildFactory @Inject constructor( params = StakingComponent.Params( userWalletId = route.userWalletId, cryptoCurrencyId = route.cryptoCurrencyId, - yield = route.yield, + yieldId = route.yieldId, ), componentFactory = stakingComponentFactory, ) diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index 6028d6a876..d7a1d74eeb 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -10,7 +10,6 @@ import com.tangem.domain.markets.TokenMarketParams import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.onramp.model.OnrampSource import com.tangem.domain.qrscanning.models.SourceType -import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import kotlinx.serialization.Serializable @@ -257,8 +256,8 @@ sealed class AppRoute(val path: String) : Route { data class Staking( val userWalletId: UserWalletId, val cryptoCurrencyId: CryptoCurrency.ID, - val yield: Yield, - ) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrencyId.value}/${yield.id}") + val yieldId: String, + ) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrencyId.value}/$yieldId") @Serializable data object PushNotification : AppRoute(path = "/push_notification") diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 620bad0ce9..8956f6f26a 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -133,6 +133,12 @@ internal class DefaultStakingRepository( } } + override suspend fun getYield(yieldId: String): Yield { + return withContext(dispatchers.io) { + getEnabledYieldsSync().find { it.id == yieldId } ?: error("Staking is unavailable") + } + } + override suspend fun getActions( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetYieldUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetYieldUseCase.kt index 3bf59574a6..383ca53ad5 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/GetYieldUseCase.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetYieldUseCase.kt @@ -20,4 +20,10 @@ class GetYieldUseCase( .catch { stakingRepository.getYield(cryptoCurrencyId, symbol) } .mapLeft { stakingErrorResolver.resolve(it) } } + + suspend operator fun invoke(yieldId: String): Either { + return Either + .catch { stakingRepository.getYield(yieldId) } + .mapLeft { stakingErrorResolver.resolve(it) } + } } \ No newline at end of file diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt index 35d7f0c0d9..ffd12cda37 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt @@ -33,6 +33,8 @@ interface StakingRepository { suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield + suspend fun getYield(yieldId: String): Yield + suspend fun getStakingAvailability(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): StakingAvailability suspend fun getActions( diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockStakingRepository.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockStakingRepository.kt index dbb5002018..37fe931195 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockStakingRepository.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockStakingRepository.kt @@ -39,78 +39,9 @@ class MockStakingRepository : StakingRepository { rewardSchedule = Yield.Metadata.RewardSchedule.DAY, ) - override suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield = Yield( - id = "1", - token = Token( - name = "Solana", - network = NetworkType.SOLANA, - symbol = "SOL", - decimals = 18, - address = null, - coinGeckoId = "solana", - logoURI = null, - isPoints = null, - ), - tokens = listOf(), - args = Yield.Args( - enter = Yield.Args.Enter( - addresses = Yield.Args.Enter.Addresses( - address = AddressArgument( - required = false, - network = null, - minimum = null, - maximum = null, - ), - additionalAddresses = mapOf(), - ), - args = mapOf(), - ), - exit = null, - ), - status = Yield.Status(enter = false, exit = null), - apy = 1.toBigDecimal(), - rewardRate = 2.3, - rewardType = Yield.RewardType.APR, - metadata = Yield.Metadata( - name = "Yield", - logoUri = "", - description = "", - documentation = null, - gasFeeToken = Token( - name = "Solana", - network = NetworkType.SOLANA, - symbol = "SOL", - decimals = 18, - address = null, - coinGeckoId = null, - logoURI = null, - isPoints = null, - ), - token = Token( - name = "Solana", - network = NetworkType.SOLANA, - symbol = "SOL", - decimals = 18, - address = null, - coinGeckoId = null, - logoURI = null, - isPoints = null, - ), - tokens = listOf(), - type = "auto", - rewardSchedule = Yield.Metadata.RewardSchedule.DAY, - cooldownPeriod = Yield.Metadata.Period(days = 1), - warmupPeriod = Yield.Metadata.Period(days = 1), - rewardClaiming = Yield.Metadata.RewardClaiming.AUTO, - defaultValidator = null, - minimumStake = null, - supportsMultipleValidators = false, - revshare = Yield.Metadata.Enabled(enabled = false), - fee = Yield.Metadata.Enabled(enabled = false), - ), - validators = listOf(), - isAvailable = false, - ) + override suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield = yield + + override suspend fun getYield(yieldId: String) = yield override suspend fun getStakingAvailability( userWalletId: UserWalletId, @@ -245,4 +176,79 @@ class MockStakingRepository : StakingRepository { override fun getStakingApproval(cryptoCurrency: CryptoCurrency): StakingApproval = StakingApproval.Empty override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean = false + + private companion object { + val yield = Yield( + id = "1", + token = Token( + name = "Solana", + network = NetworkType.SOLANA, + symbol = "SOL", + decimals = 18, + address = null, + coinGeckoId = "solana", + logoURI = null, + isPoints = null, + ), + tokens = listOf(), + args = Yield.Args( + enter = Yield.Args.Enter( + addresses = Yield.Args.Enter.Addresses( + address = AddressArgument( + required = false, + network = null, + minimum = null, + maximum = null, + ), + additionalAddresses = mapOf(), + ), + args = mapOf(), + ), + exit = null, + ), + status = Yield.Status(enter = false, exit = null), + apy = 1.toBigDecimal(), + rewardRate = 2.3, + rewardType = Yield.RewardType.APR, + metadata = Yield.Metadata( + name = "Yield", + logoUri = "", + description = "", + documentation = null, + gasFeeToken = Token( + name = "Solana", + network = NetworkType.SOLANA, + symbol = "SOL", + decimals = 18, + address = null, + coinGeckoId = null, + logoURI = null, + isPoints = null, + ), + token = Token( + name = "Solana", + network = NetworkType.SOLANA, + symbol = "SOL", + decimals = 18, + address = null, + coinGeckoId = null, + logoURI = null, + isPoints = null, + ), + tokens = listOf(), + type = "auto", + rewardSchedule = Yield.Metadata.RewardSchedule.DAY, + cooldownPeriod = Yield.Metadata.Period(days = 1), + warmupPeriod = Yield.Metadata.Period(days = 1), + rewardClaiming = Yield.Metadata.RewardClaiming.AUTO, + defaultValidator = null, + minimumStake = null, + supportsMultipleValidators = false, + revshare = Yield.Metadata.Enabled(enabled = false), + fee = Yield.Metadata.Enabled(enabled = false), + ), + validators = listOf(), + isAvailable = false, + ) + } } \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt index 471770d6a4..7b854e3c07 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt @@ -179,7 +179,7 @@ internal class TokenActionsHandler @AssistedInject constructor( AppRoute.Staking( userWalletId = cryptoCurrencyData.userWallet.walletId, cryptoCurrencyId = cryptoCurrencyData.status.currency.id, - yield = yield, + yieldId = yield.id, ), ) } diff --git a/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt b/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt index 207a7bdc94..ad3a44fc15 100644 --- a/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt +++ b/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt @@ -2,7 +2,6 @@ package com.tangem.features.staking.api import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId @@ -11,7 +10,7 @@ interface StakingComponent : ComposableContentComponent { data class Params( val userWalletId: UserWalletId, val cryptoCurrencyId: CryptoCurrency.ID, - val yield: Yield, + val yieldId: String, ) interface Factory : ComponentFactory diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index bb2c07e2c4..01d1f570c7 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -26,10 +26,7 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.BlockchainErrorInfo import com.tangem.domain.feedback.models.FeedbackEmailType -import com.tangem.domain.staking.GetActionsUseCase -import com.tangem.domain.staking.InvalidatePendingTransactionsUseCase -import com.tangem.domain.staking.IsAnyTokenStakedUseCase -import com.tangem.domain.staking.IsApproveNeededUseCase +import com.tangem.domain.staking.* import com.tangem.domain.staking.analytics.StakeScreenSource import com.tangem.domain.staking.analytics.StakingAnalyticsEvent import com.tangem.domain.staking.model.StakingApproval @@ -81,6 +78,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import timber.log.Timber import java.math.BigDecimal import java.util.concurrent.CopyOnWriteArrayList @@ -119,6 +117,7 @@ internal class StakingModel @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val getActionsUseCase: GetActionsUseCase, + private val getYieldUseCase: GetYieldUseCase, private val paramsInterceptorHolder: ParamsInterceptorHolder, private val shareManager: ShareManager, @DelayedWork private val coroutineScope: CoroutineScope, @@ -139,7 +138,11 @@ internal class StakingModel @Inject constructor( private val cryptoCurrencyId: CryptoCurrency.ID = params.cryptoCurrencyId private val userWalletId: UserWalletId = params.userWalletId - private val yield: Yield = params.yield + private val yield: Yield = runBlocking { + getYieldUseCase(params.yieldId).getOrElse { + error("yield must be not null") + } + } private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() private var processingActions: List = emptyList() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt index d8a3eb4733..f0e4b2fee5 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt @@ -5,7 +5,6 @@ import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.navigation.share.ShareManager import com.tangem.core.navigation.url.UrlOpener -import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.tokendetails.presentation.TokenDetailsFragment @@ -39,12 +38,12 @@ internal class DefaultTokenDetailsRouter( ) } - override fun openStaking(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, yield: Yield) { + override fun openStaking(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, yieldId: String) { router.push( AppRoute.Staking( userWalletId = userWalletId, cryptoCurrencyId = cryptoCurrency.id, - yield = yield, + yieldId = yieldId, ), ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt index e4a143ccd1..4f40d92a2b 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt @@ -1,6 +1,5 @@ package com.tangem.feature.tokendetails.presentation.router -import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.tokendetails.navigation.TokenDetailsRouter @@ -18,7 +17,7 @@ internal interface InnerTokenDetailsRouter : TokenDetailsRouter { fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency) - fun openStaking(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, yield: Yield) + fun openStaking(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, yieldId: String) fun openOnrampSuccess(externalTxId: String) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index 68fe1de07a..d779c92d75 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -994,7 +994,7 @@ internal class TokenDetailsViewModel @Inject constructor( error("Staking is unavailable for ${cryptoCurrency.name}") } - router.openStaking(userWalletId, cryptoCurrency, yield) + router.openStaking(userWalletId, cryptoCurrency, yield.id) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt index 47b8fc42ec..b9647e9365 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt @@ -409,7 +409,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( AppRoute.Staking( userWalletId = userWalletId, cryptoCurrencyId = cryptoCurrency.id, - yield = yield ?: return@launch, + yieldId = yield?.id ?: return@launch, ), ) }