Updated on 2026-08-14
This commit is contained in:
parent
0fdcdda8d5
commit
f58543481d
8 changed files with 55 additions and 25 deletions
|
|
@ -21,8 +21,10 @@ dependencies {
|
|||
/** Domain modules */
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.models)
|
||||
|
||||
/** Feature Api modules */
|
||||
implementation(projects.features.staking.api)
|
||||
|
|
@ -39,8 +41,8 @@ dependencies {
|
|||
implementation(deps.moshi)
|
||||
implementation(deps.moshi.kotlin)
|
||||
|
||||
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
implementation(projects.libs.crypto)
|
||||
|
||||
implementation(deps.tangem.card.core)
|
||||
implementation(deps.tangem.blockchain) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.data.staking
|
||||
|
||||
import android.util.Base64
|
||||
import arrow.core.getOrElse
|
||||
import arrow.core.raise.catch
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
|
@ -51,9 +52,11 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -69,6 +72,7 @@ internal class DefaultStakingRepository(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val stakingFeatureToggle: StakingFeatureToggles,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
moshi: Moshi,
|
||||
) : StakingRepository {
|
||||
|
||||
|
|
@ -159,17 +163,19 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getStakingAvailabilityForActions(
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
symbol: String,
|
||||
override suspend fun getStakingAvailability(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): StakingAvailability {
|
||||
val rawCurrencyId = cryptoCurrencyId.rawCurrencyId ?: return StakingAvailability.Unavailable
|
||||
if (checkForInvalidCardBatch(userWalletId, cryptoCurrency)) return StakingAvailability.Unavailable
|
||||
|
||||
val rawCurrencyId = cryptoCurrency.id.rawCurrencyId ?: return StakingAvailability.Unavailable
|
||||
|
||||
return withContext(dispatchers.io) {
|
||||
val yields = getEnabledYields() ?: return@withContext StakingAvailability.Unavailable
|
||||
|
||||
val prefetchedYield = findPrefetchedYield(yields, rawCurrencyId, symbol)
|
||||
val isSupported = isStakingSupported(getIntegrationKey(cryptoCurrencyId))
|
||||
val prefetchedYield = findPrefetchedYield(yields, rawCurrencyId, cryptoCurrency.symbol)
|
||||
val isSupported = isStakingSupported(getIntegrationKey(cryptoCurrency.id))
|
||||
|
||||
when {
|
||||
prefetchedYield != null && isSupported -> {
|
||||
|
|
@ -183,6 +189,21 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private fun checkForInvalidCardBatch(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Boolean {
|
||||
val userWallet = getUserWalletUseCase(userWalletId).getOrElse {
|
||||
error("Failed to get user wallet")
|
||||
}
|
||||
|
||||
return when {
|
||||
isSolana(cryptoCurrency.network.id.value) -> {
|
||||
INVALID_BATCHES_FOR_SOLANA.contains(userWallet.scanResponse.card.batchId)
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createAction(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
@ -625,6 +646,8 @@ internal class DefaultStakingRepository(
|
|||
|
||||
const val ETHEREUM_POLYGON_APPROVE_SPENDER = "0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908"
|
||||
|
||||
val INVALID_BATCHES_FOR_SOLANA = listOf("AC01", "CB79")
|
||||
|
||||
// uncomment items as implementation is ready
|
||||
val integrationIdMap = mapOf(
|
||||
Blockchain.Solana.run { id + toCoinId() } to SOLANA_INTEGRATION_ID,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.tangem.datasource.local.token.StakingYieldsStore
|
|||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
|
|
@ -37,6 +38,7 @@ internal object StakingDataModule {
|
|||
stakingFeatureToggle: StakingFeatureToggles,
|
||||
cacheRegistry: CacheRegistry,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
): StakingRepository {
|
||||
return DefaultStakingRepository(
|
||||
|
|
@ -48,6 +50,7 @@ internal object StakingDataModule {
|
|||
cacheRegistry = cacheRegistry,
|
||||
stakingFeatureToggle = stakingFeatureToggle,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
getUserWalletUseCase = getUserWalletUseCase,
|
||||
moshi = moshi,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.staking.model.stakekit.StakingError
|
|||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Use case for getting info about staking capability in tangem app.
|
||||
|
|
@ -16,11 +17,16 @@ class GetStakingAvailabilityUseCase(
|
|||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
symbol: String,
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Either<StakingError, StakingAvailability> {
|
||||
return Either
|
||||
.catch { stakingRepository.getStakingAvailabilityForActions(cryptoCurrencyId, symbol) }
|
||||
.catch {
|
||||
stakingRepository.getStakingAvailability(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
)
|
||||
}
|
||||
.mapLeft { stakingErrorResolver.resolve(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -32,10 +32,7 @@ interface StakingRepository {
|
|||
|
||||
suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield
|
||||
|
||||
suspend fun getStakingAvailabilityForActions(
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
symbol: String,
|
||||
): StakingAvailability
|
||||
suspend fun getStakingAvailability(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): StakingAvailability
|
||||
|
||||
suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -129,14 +129,13 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
|
||||
// staking
|
||||
if (stakingFeatureToggles.isStakingEnabled) {
|
||||
if (isStakingAvailable(cryptoCurrency)) {
|
||||
if (isStakingAvailable(userWallet, cryptoCurrency)) {
|
||||
val yield = kotlin.runCatching {
|
||||
stakingRepository.getYield(
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
symbol = cryptoCurrency.symbol,
|
||||
)
|
||||
}.getOrNull()
|
||||
|
||||
activeList.add(
|
||||
TokenActionsState.ActionState.Stake(
|
||||
unavailabilityReason = ScenarioUnavailabilityReason.None,
|
||||
|
|
@ -301,10 +300,10 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
return networkAddress != null && networkAddress.defaultAddress.value.isNotEmpty()
|
||||
}
|
||||
|
||||
private suspend fun isStakingAvailable(cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return stakingRepository.getStakingAvailabilityForActions(
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
symbol = cryptoCurrency.symbol,
|
||||
private suspend fun isStakingAvailable(userWallet: UserWallet, cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return stakingRepository.getStakingAvailability(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
) is StakingAvailability.Available
|
||||
}
|
||||
}
|
||||
|
|
@ -113,9 +113,9 @@ class MockStakingRepository : StakingRepository {
|
|||
isAvailable = false,
|
||||
)
|
||||
|
||||
override suspend fun getStakingAvailabilityForActions(
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
symbol: String,
|
||||
override suspend fun getStakingAvailability(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): StakingAvailability = StakingAvailability.Unavailable
|
||||
|
||||
override suspend fun fetchSingleYieldBalance(
|
||||
|
|
|
|||
|
|
@ -393,8 +393,8 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
private fun updateStakingInfo() {
|
||||
viewModelScope.launch {
|
||||
val stakingAvailability = getStakingAvailabilityUseCase(
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
symbol = cryptoCurrency.symbol,
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).getOrElse { StakingAvailability.Unavailable }
|
||||
|
||||
internalUiState.value = stateFactory.getStateWithUpdatedStakingAvailability(stakingAvailability)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue