diff --git a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt
index 9995a3753b..7112c00220 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt
@@ -2,10 +2,11 @@ package com.tangem.tap.di.domain
import com.tangem.domain.staking.*
import com.tangem.domain.staking.repositories.P2PEthPoolRepository
-import com.tangem.domain.staking.repositories.StakingActionRepository
+import com.tangem.domain.staking.repositories.StakeKitActionRepository
import com.tangem.domain.staking.repositories.StakingErrorResolver
+import com.tangem.domain.staking.repositories.StakeKitRepository
import com.tangem.domain.staking.repositories.StakingRepository
-import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
+import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade
@@ -35,11 +36,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGetStakingEntryInfoUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
stakingErrorResolver: StakingErrorResolver,
): GetStakingEntryInfoUseCase {
return GetStakingEntryInfoUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -47,11 +48,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGetYieldUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
stakingErrorResolver: StakingErrorResolver,
): GetYieldUseCase {
return GetYieldUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -59,13 +60,13 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideFetchActionsUseCase(
- stakingRepository: StakingRepository,
- stakingActionRepository: StakingActionRepository,
+ stakeKitRepository: StakeKitRepository,
+ stakeKitActionRepository: StakeKitActionRepository,
stakingErrorResolver: StakingErrorResolver,
): FetchActionsUseCase {
return FetchActionsUseCase(
- stakingRepository = stakingRepository,
- stakingActionRepository = stakingActionRepository,
+ stakeKitRepository = stakeKitRepository,
+ stakeKitActionRepository = stakeKitActionRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -73,11 +74,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGetActionsUseCase(
- stakingActionRepository: StakingActionRepository,
+ stakeKitActionRepository: StakeKitActionRepository,
stakingErrorResolver: StakingErrorResolver,
): GetActionsUseCase {
return GetActionsUseCase(
- stakingActionRepository = stakingActionRepository,
+ stakeKitActionRepository = stakeKitActionRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -85,11 +86,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGetStakingTokensUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
stakingErrorResolver: StakingErrorResolver,
): FetchStakingTokensUseCase {
return FetchStakingTokensUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -97,12 +98,12 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideFetchStakingOptionsUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
p2pRepository: P2PEthPoolRepository,
stakingErrorResolver: StakingErrorResolver,
): FetchStakingOptionsUseCase {
return FetchStakingOptionsUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
p2pRepository = p2pRepository,
stakingErrorResolver = stakingErrorResolver,
)
@@ -123,11 +124,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGetStakingTransactionsUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
stakingErrorResolver: StakingErrorResolver,
): GetStakingTransactionsUseCase {
return GetStakingTransactionsUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -135,11 +136,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGasEstimateUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
stakingErrorResolver: StakingErrorResolver,
): EstimateGasUseCase {
return EstimateGasUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -147,11 +148,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideSubmitHashUseCase(
- stakingTransactionHashRepository: StakingTransactionHashRepository,
+ stakeKitTransactionHashRepository: StakeKitTransactionHashRepository,
stakingErrorResolver: StakingErrorResolver,
): SubmitHashUseCase {
return SubmitHashUseCase(
- stakingTransactionHashRepository = stakingTransactionHashRepository,
+ stakeKitTransactionHashRepository = stakeKitTransactionHashRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -159,11 +160,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideSaveUnsubmittedHashUseCase(
- stakingTransactionHashRepository: StakingTransactionHashRepository,
+ stakeKitTransactionHashRepository: StakeKitTransactionHashRepository,
stakingErrorResolver: StakingErrorResolver,
): SaveUnsubmittedHashUseCase {
return SaveUnsubmittedHashUseCase(
- stakingTransactionHashRepository = stakingTransactionHashRepository,
+ stakeKitTransactionHashRepository = stakeKitTransactionHashRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -181,11 +182,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideSendUnsubmittedHashesUseCase(
- stakingTransactionHashRepository: StakingTransactionHashRepository,
+ stakeKitTransactionHashRepository: StakeKitTransactionHashRepository,
stakingErrorResolver: StakingErrorResolver,
): SendUnsubmittedHashesUseCase {
return SendUnsubmittedHashesUseCase(
- stakingTransactionHashRepository = stakingTransactionHashRepository,
+ stakeKitTransactionHashRepository = stakeKitTransactionHashRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -193,11 +194,11 @@ internal object StakingDomainModule {
@Provides
@Singleton
fun provideGetConstructedStakingTransactionUseCase(
- stakingRepository: StakingRepository,
+ stakeKitRepository: StakeKitRepository,
stakingErrorResolver: StakingErrorResolver,
): GetConstructedStakingTransactionUseCase {
return GetConstructedStakingTransactionUseCase(
- stakingRepository = stakingRepository,
+ stakeKitRepository = stakeKitRepository,
stakingErrorResolver = stakingErrorResolver,
)
}
@@ -236,7 +237,7 @@ internal object StakingDomainModule {
@Provides
@Singleton
- fun provideStakingApyFlowUseCase(stakingRepository: StakingRepository): StakingApyFlowUseCase {
- return StakingApyFlowUseCase(stakingRepository)
+ fun provideStakingApyFlowUseCase(stakeKitRepository: StakeKitRepository): StakingApyFlowUseCase {
+ return StakingApyFlowUseCase(stakeKitRepository)
}
}
\ No newline at end of file
diff --git a/data/staking/detekt-baseline-debug.xml b/data/staking/detekt-baseline-debug.xml
deleted file mode 100644
index 39dba1e36e..0000000000
--- a/data/staking/detekt-baseline-debug.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- MultilineLambdaItParameter:DefaultMultiYieldBalanceFetcher.kt$DefaultMultiYieldBalanceFetcher${ Timber.e(it, "Unable to fetch yield balances $params") yieldsBalancesStore.storeError(userWalletId = params.userWalletId, stakingIds = stakingIds) }
- MultilineLambdaItParameter:DefaultMultiYieldBalanceFetcher.kt$DefaultMultiYieldBalanceFetcher${ Timber.e(it, "Unable to fetch yield balances $userWalletId") yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = stakingIds) throw it }
- MultilineLambdaItParameter:DefaultMultiYieldBalanceFetcher.kt$DefaultMultiYieldBalanceFetcher${ request.integrationId == it.integrationId && request.addresses.address == it.addresses.address }
- MultilineLambdaItParameter:DefaultMultiYieldBalanceFetcher.kt$DefaultMultiYieldBalanceFetcher${ stakingId.integrationId == it.integrationId && stakingId.address == it.addresses.address }
- MultilineLambdaItParameter:DefaultStakingRepository.kt$DefaultStakingRepository${ YieldConverter.convertListIgnoreErrors( input = it, onError = { Timber.e("Error converting one of the items in enabled yields: $it") }, ) }
- NamedArguments:DefaultP2PEthPoolRepository.kt$DefaultP2PEthPoolRepository$getRewards(network.value, delegatorAddress, vaultAddress, period)
- NoNameShadowing:DefaultStakingRepository.kt$DefaultStakingRepository${ Timber.e("Error converting one of the items in enabled yields: $it") }
- NullableToStringCall:DefaultStakingRepository.kt$DefaultStakingRepository$${(response as? ApiResponse.Error)?.cause}
- UseEmptyCounterpart:YieldBalanceRequestBodyFactory.kt$YieldBalanceRequestBodyFactory$listOf()
-
-
diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultP2PEthPoolRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultP2PEthPoolRepository.kt
index 4af834f017..b97325f373 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/DefaultP2PEthPoolRepository.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultP2PEthPoolRepository.kt
@@ -12,10 +12,15 @@ import com.tangem.datasource.api.ethpool.models.request.P2PEthPoolDepositRequest
import com.tangem.datasource.api.ethpool.models.request.P2PEthPoolUnstakeRequest
import com.tangem.datasource.api.ethpool.models.request.P2PEthPoolWithdrawRequest
import com.tangem.datasource.local.token.P2PEthPoolVaultsStore
+import com.tangem.domain.staking.model.StakingAvailability
+import com.tangem.domain.staking.model.StakingOption
import com.tangem.domain.staking.model.ethpool.*
import com.tangem.domain.staking.repositories.P2PEthPoolRepository
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import timber.log.Timber
@@ -192,7 +197,12 @@ internal class DefaultP2PEthPoolRepository(
period: Int?,
): Either> = either {
withContext(dispatchers.io) {
- val response = p2pApi.getRewards(network.value, delegatorAddress, vaultAddress, period)
+ val response = p2pApi.getRewards(
+ network = network.value,
+ delegatorAddress = delegatorAddress,
+ vaultAddress = vaultAddress,
+ period = period,
+ )
when (response) {
is ApiResponse.Success -> {
val data = response.data
@@ -206,4 +216,49 @@ internal class DefaultP2PEthPoolRepository(
}
}
}
+
+ override fun getStakingAvailability(): Flow {
+ return getVaultsFlow()
+ .distinctUntilChanged()
+ .map { vaults ->
+ if (vaults.isEmpty()) {
+ return@map StakingAvailability.TemporaryUnavailable
+ }
+
+ val vault = findPublicVault(vaults = vaults)
+
+ if (vault != null) {
+ StakingAvailability.Available(StakingOption.P2P(vault))
+ } else {
+ StakingAvailability.TemporaryUnavailable
+ }
+ }
+ }
+
+ override suspend fun getStakingAvailabilitySync(): StakingAvailability {
+ val vaults = getVaultsSync()
+ if (vaults.isEmpty()) {
+ return StakingAvailability.TemporaryUnavailable
+ }
+
+ val vault = findPublicVault(vaults = vaults)
+
+ return if (vault != null) {
+ StakingAvailability.Available(StakingOption.P2P(vault))
+ } else {
+ StakingAvailability.TemporaryUnavailable
+ }
+ }
+
+ private suspend fun getVaultsSync(): List {
+ return p2pEthPoolVaultsStore.getSync()
+ }
+
+ private fun getVaultsFlow(): Flow> {
+ return p2pEthPoolVaultsStore.get()
+ }
+
+ private fun findPublicVault(vaults: List): P2PEthPoolVault? {
+ return vaults.firstOrNull { vault -> !vault.isPrivate }
+ }
}
\ No newline at end of file
diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingActionRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitActionRepository.kt
similarity index 87%
rename from data/staking/src/main/java/com/tangem/data/staking/DefaultStakingActionRepository.kt
rename to data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitActionRepository.kt
index 030af40fb7..afc4dbef58 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingActionRepository.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitActionRepository.kt
@@ -4,15 +4,15 @@ import com.tangem.datasource.local.token.StakingActionsStore
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.staking.model.stakekit.action.StakingAction
-import com.tangem.domain.staking.repositories.StakingActionRepository
+import com.tangem.domain.staking.repositories.StakeKitActionRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
-internal class DefaultStakingActionRepository(
+internal class DefaultStakeKitActionRepository(
private val stakingActionsStore: StakingActionsStore,
private val dispatchers: CoroutineDispatcherProvider,
-) : StakingActionRepository {
+) : StakeKitActionRepository {
override suspend fun store(
userWalletId: UserWalletId,
diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt
new file mode 100644
index 0000000000..65c3e14fd7
--- /dev/null
+++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt
@@ -0,0 +1,421 @@
+package com.tangem.data.staking
+
+import android.util.Base64
+import com.squareup.moshi.Moshi
+import com.tangem.blockchain.common.Amount
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.blockchain.common.TransactionData
+import com.tangem.blockchain.common.TransactionStatus
+import com.tangem.blockchain.common.transaction.Fee
+import com.tangem.blockchainsdk.utils.fromNetworkId
+import com.tangem.common.extensions.hexToBytes
+import com.tangem.common.extensions.toCompressedPublicKey
+import com.tangem.data.staking.converters.YieldConverter
+import com.tangem.data.staking.converters.action.ActionStatusConverter
+import com.tangem.data.staking.converters.action.EnterActionResponseConverter
+import com.tangem.data.staking.converters.transaction.GasEstimateConverter
+import com.tangem.data.staking.converters.transaction.StakingTransactionConverter
+import com.tangem.data.staking.converters.transaction.StakingTransactionStatusConverter
+import com.tangem.data.staking.converters.transaction.StakingTransactionTypeConverter
+import com.tangem.datasource.api.common.response.ApiResponse
+import com.tangem.datasource.api.common.response.getOrThrow
+import com.tangem.datasource.api.stakekit.StakeKitApi
+import com.tangem.datasource.api.stakekit.models.request.*
+import com.tangem.datasource.api.stakekit.models.response.EnabledYieldsResponse
+import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
+import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionStatusDTO
+import com.tangem.datasource.api.stakekit.models.response.model.transaction.tron.TronStakeKitTransaction
+import com.tangem.datasource.local.token.StakingYieldsStore
+import com.tangem.datasource.local.token.converter.StakingNetworkTypeConverter
+import com.tangem.datasource.local.token.converter.YieldTokenConverter
+import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.network.Network
+import com.tangem.domain.models.staking.NetworkType
+import com.tangem.domain.models.staking.action.StakingActionType
+import com.tangem.domain.models.wallet.UserWalletId
+import com.tangem.domain.staking.model.StakingAvailability
+import com.tangem.domain.staking.model.StakingEntryInfo
+import com.tangem.domain.staking.model.StakingIntegrationID
+import com.tangem.domain.staking.model.StakingOption
+import com.tangem.domain.staking.model.stakekit.Yield
+import com.tangem.domain.staking.model.stakekit.action.StakingAction
+import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
+import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
+import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
+import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
+import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
+import com.tangem.domain.staking.repositories.StakeKitRepository
+import com.tangem.domain.staking.toggles.StakingFeatureToggles
+import com.tangem.domain.walletmanager.WalletManagersFacade
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+
+@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
+internal class DefaultStakeKitRepository(
+ private val stakeKitApi: StakeKitApi,
+ private val stakingYieldsStore: StakingYieldsStore,
+ private val dispatchers: CoroutineDispatcherProvider,
+ private val walletManagersFacade: WalletManagersFacade,
+ private val stakingFeatureToggles: StakingFeatureToggles,
+ moshi: Moshi,
+) : StakeKitRepository {
+
+ private val transactionStatusConverter = StakingTransactionStatusConverter()
+ private val transactionTypeConverter = StakingTransactionTypeConverter()
+ private val actionStatusConverter = ActionStatusConverter()
+
+ private val transactionConverter = StakingTransactionConverter(
+ transactionStatusConverter = transactionStatusConverter,
+ transactionTypeConverter = transactionTypeConverter,
+ )
+ private val enterActionResponseConverter = EnterActionResponseConverter(
+ actionStatusConverter = actionStatusConverter,
+ transactionConverter = transactionConverter,
+ )
+
+ private val tronStakeKitTransactionAdapter by lazy { moshi.adapter(TronStakeKitTransaction::class.java) }
+ private val networkTypeAdapter by lazy { moshi.adapter(NetworkTypeDTO::class.java) }
+ private val stakingActionStatusAdapter by lazy { moshi.adapter(StakingActionStatusDTO::class.java) }
+
+ override suspend fun fetchYields() {
+ withContext(dispatchers.io) {
+ val yieldsResponses = getAvailableStakeKitIntegrationsIds().map {
+ async { it.getYieldRequest() }
+ }.awaitAll()
+
+ val yields = yieldsResponses.flatMap { response ->
+ when (response) {
+ is ApiResponse.Success -> response.data.data.filter { yield -> yield.isAvailable == true }
+ is ApiResponse.Error -> {
+ Timber.e("Error fetching enabled yields: ${response.cause}")
+ emptyList()
+ }
+ }
+ }
+ stakingYieldsStore.store(yields)
+ }
+ }
+
+ override suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield {
+ return withContext(dispatchers.io) {
+ val rawCurrencyId = cryptoCurrencyId.rawCurrencyId ?: error("Staking custom tokens is not available")
+
+ val prefetchedYield = findPrefetchedYield(
+ yields = getEnabledYieldsSync(),
+ currencyId = rawCurrencyId,
+ symbol = symbol,
+ )
+
+ prefetchedYield ?: error("Staking is unavailable")
+ }
+ }
+
+ 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,
+ networkType: NetworkType,
+ stakingActionStatus: StakingActionStatus,
+ ): List {
+ return withContext(dispatchers.io) {
+ val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
+
+ val networkTypeDto = StakingNetworkTypeConverter.convertBack(networkType)
+ val networkTypeString = networkTypeDto.extractJsonName()
+
+ val actionStatusDTO = actionStatusConverter.convertBack(stakingActionStatus)
+ val actionStatusString = actionStatusDTO.extractJsonName()
+
+ enterActionResponseConverter.convertListIgnoreErrors(
+ input = stakeKitApi.getActions(
+ walletAddress = address,
+ network = networkTypeString,
+ status = actionStatusString,
+ ).getOrThrow().data,
+ onError = { Timber.e("Error converting staking actions list: $it") },
+ )
+ }
+ }
+
+ private suspend fun StakingIntegrationID.StakeKit.getYieldRequest(): ApiResponse {
+ return when (this) {
+ is StakingIntegrationID.StakeKit.Coin -> stakeKitApi.getEnabledYields(
+ preferredValidatorsOnly = false,
+ network = networkId,
+ )
+ is StakingIntegrationID.StakeKit.EthereumToken -> stakeKitApi.getEnabledYields(
+ preferredValidatorsOnly = false,
+ yieldId = value,
+ network = networkId,
+ )
+ }
+ }
+
+ private fun getAvailableStakeKitIntegrationsIds(): List {
+ return StakingIntegrationID.StakeKit.entries.filterNot {
+ it.blockchain == Blockchain.Cardano && !stakingFeatureToggles.isCardanoStakingEnabled
+ }
+ }
+
+ private fun NetworkTypeDTO.extractJsonName(): String {
+ return networkTypeAdapter.toJson(this).replace("\"", "")
+ }
+
+ private fun StakingActionStatusDTO.extractJsonName(): String {
+ return stakingActionStatusAdapter.toJson(this).replace("\"", "")
+ }
+
+ override suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo {
+ return withContext(dispatchers.io) {
+ val yield = getYield(cryptoCurrencyId, symbol)
+
+ StakingEntryInfo(
+ tokenSymbol = yield.token.symbol,
+ )
+ }
+ }
+
+ override suspend fun createAction(
+ userWalletId: UserWalletId,
+ network: Network,
+ params: ActionParams,
+ ): StakingAction {
+ return withContext(dispatchers.io) {
+ val response = when (params.actionCommonType) {
+ is StakingActionCommonType.Enter -> stakeKitApi.createEnterAction(
+ createActionRequestBody(
+ userWalletId,
+ network,
+ params,
+ ),
+ )
+ is StakingActionCommonType.Exit -> stakeKitApi.createExitAction(
+ createActionRequestBody(
+ userWalletId,
+ network,
+ params,
+ ),
+ )
+ is StakingActionCommonType.Pending -> stakeKitApi.createPendingAction(
+ createPendingActionRequestBody(params),
+ )
+ }
+
+ enterActionResponseConverter.convert(response.getOrThrow())
+ }
+ }
+
+ override suspend fun estimateGas(
+ userWalletId: UserWalletId,
+ network: Network,
+ params: ActionParams,
+ ): StakingGasEstimate {
+ return withContext(dispatchers.io) {
+ val gasEstimateDTO = when (params.actionCommonType) {
+ is StakingActionCommonType.Enter -> stakeKitApi.estimateGasOnEnter(
+ createActionRequestBody(
+ userWalletId,
+ network,
+ params,
+ ),
+ )
+ is StakingActionCommonType.Exit -> stakeKitApi.estimateGasOnExit(
+ createActionRequestBody(
+ userWalletId,
+ network,
+ params,
+ ),
+ )
+ is StakingActionCommonType.Pending -> stakeKitApi.estimateGasOnPending(
+ createPendingActionRequestBody(params),
+ )
+ }
+
+ GasEstimateConverter.convert(gasEstimateDTO.getOrThrow())
+ }
+ }
+
+ override suspend fun constructTransaction(
+ networkId: String,
+ fee: Fee,
+ amount: Amount,
+ transactionId: String,
+ ): Pair {
+ return withContext(dispatchers.io) {
+ val transactionResponse = stakeKitApi.constructTransaction(
+ transactionId = transactionId,
+ body = ConstructTransactionRequestBody(),
+ )
+
+ val transaction = transactionConverter.convert(transactionResponse.getOrThrow())
+ val unsignedTransaction =
+ transaction.unsignedTransaction ?: error("No unsigned transaction available")
+ val transactionData = TransactionData.Compiled(
+ value = getTransactionDataType(networkId, unsignedTransaction),
+ fee = fee,
+ amount = amount,
+ status = TransactionStatus.Unconfirmed,
+ )
+
+ transaction to transactionData
+ }
+ }
+
+ private suspend fun createActionRequestBody(
+ userWalletId: UserWalletId,
+ network: Network,
+ params: ActionParams,
+ ): ActionRequestBody {
+ return ActionRequestBody(
+ integrationId = params.integrationId,
+ addresses = Address(
+ address = params.address,
+ additionalAddresses = createAdditionalAddresses(userWalletId, network, params),
+ ),
+ args = ActionRequestBodyArgs(
+ amount = params.amount.toPlainString(),
+ inputToken = YieldTokenConverter.convertBack(params.token),
+ validatorAddress = params.validatorAddress,
+ validatorAddresses = listOf(params.validatorAddress), // check on other networks
+ tronResource = getTronResource(network),
+ ),
+ )
+ }
+
+ private fun createPendingActionRequestBody(params: ActionParams): PendingActionRequestBody {
+ return PendingActionRequestBody(
+ integrationId = params.integrationId,
+ type = params.type ?: StakingActionType.UNKNOWN,
+ passthrough = params.passthrough.orEmpty(),
+ args = ActionRequestBodyArgs(
+ amount = params.amount.toPlainString(),
+ validatorAddress = params.validatorAddress,
+ validatorAddresses = listOf(params.validatorAddress),
+ ),
+ )
+ }
+
+ private suspend fun createAdditionalAddresses(
+ userWalletId: UserWalletId,
+ network: Network,
+ params: ActionParams,
+ ): Address.AdditionalAddresses? {
+ val selectedWallet = walletManagersFacade.getOrCreateWalletManager(userWalletId, network)
+ return when (params.token.network) {
+ NetworkType.COSMOS -> Address.AdditionalAddresses(
+ cosmosPubKey = Base64.encodeToString(
+ /* input = */ selectedWallet?.wallet?.publicKey?.blockchainKey?.toCompressedPublicKey(),
+ /* flags = */ Base64.NO_WRAP,
+ ),
+ )
+ else -> null
+ }
+ }
+
+ private fun getTransactionDataType(networkId: String, unsignedTransaction: String): TransactionData.Compiled.Data {
+ return when (Blockchain.fromId(networkId)) {
+ Blockchain.Solana,
+ Blockchain.Cosmos,
+ -> TransactionData.Compiled.Data.Bytes(unsignedTransaction.hexToBytes())
+ Blockchain.BSC,
+ Blockchain.Ethereum,
+ Blockchain.TON,
+ Blockchain.Cardano,
+ -> TransactionData.Compiled.Data.RawString(unsignedTransaction)
+ Blockchain.Tron -> {
+ val tronStakeKitTransaction = tronStakeKitTransactionAdapter.fromJson(unsignedTransaction)
+ ?: error("Failed to parse Tron StakeKit transaction")
+ TransactionData.Compiled.Data.RawString(tronStakeKitTransaction.rawDataHex)
+ }
+ else -> error("Unsupported blockchain")
+ }
+ }
+
+ private fun findPrefetchedYield(yields: List, currencyId: CryptoCurrency.RawID, symbol: String): Yield? {
+ return yields.find { yield ->
+ yield.tokens.any { it.coinGeckoId == currencyId.value && it.symbol == symbol }
+ }
+ }
+
+ private suspend fun getEnabledYieldsSync(): List {
+ return YieldConverter.convertListIgnoreErrors(
+ input = stakingYieldsStore.getSync(),
+ onError = { Timber.e("Error converting one of the items in enabled yields: $it") },
+ )
+ }
+
+ override fun getEnabledYields(): Flow> {
+ return stakingYieldsStore.get().map { yields ->
+ YieldConverter.convertListIgnoreErrors(
+ input = yields,
+ onError = { Timber.e("Error converting one of the items in enabled yields: $it") },
+ )
+ }
+ }
+
+ override fun getStakingAvailability(
+ rawCurrencyId: CryptoCurrency.RawID,
+ symbol: String,
+ ): Flow {
+ return getEnabledYields()
+ .distinctUntilChanged()
+ .map { yields ->
+ if (yields.isEmpty()) {
+ return@map StakingAvailability.TemporaryUnavailable
+ }
+
+ val prefetchedYield = findPrefetchedYield(
+ yields = yields,
+ currencyId = rawCurrencyId,
+ symbol = symbol,
+ )
+
+ if (prefetchedYield != null) {
+ StakingAvailability.Available(StakingOption.StakeKit(prefetchedYield))
+ } else {
+ StakingAvailability.TemporaryUnavailable
+ }
+ }
+ }
+
+ override suspend fun getStakingAvailabilitySync(
+ rawCurrencyId: CryptoCurrency.RawID,
+ symbol: String,
+ ): StakingAvailability {
+ val yields = getEnabledYieldsSync()
+ if (yields.isEmpty()) {
+ return StakingAvailability.TemporaryUnavailable
+ }
+
+ val prefetchedYield = findPrefetchedYield(
+ yields = yields,
+ currencyId = rawCurrencyId,
+ symbol = symbol,
+ )
+
+ return if (prefetchedYield != null) {
+ StakingAvailability.Available(StakingOption.StakeKit(prefetchedYield))
+ } else {
+ StakingAvailability.TemporaryUnavailable
+ }
+ }
+
+ private fun getTronResource(network: Network): TronResource? {
+ val blockchain = Blockchain.fromNetworkId(network.backendId)
+
+ return if (blockchain == Blockchain.Tron || blockchain == Blockchain.TronTestnet) {
+ TronResource.ENERGY
+ } else {
+ null
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingTransactionHashRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitTransactionHashRepository.kt
similarity index 95%
rename from data/staking/src/main/java/com/tangem/data/staking/DefaultStakingTransactionHashRepository.kt
rename to data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitTransactionHashRepository.kt
index 0d12489648..0147b2da07 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingTransactionHashRepository.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitTransactionHashRepository.kt
@@ -6,16 +6,16 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectListSync
import com.tangem.domain.staking.model.UnsubmittedTransactionMetadata
-import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
+import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
import timber.log.Timber
-internal class DefaultStakingTransactionHashRepository(
+internal class DefaultStakeKitTransactionHashRepository(
private val stakeKitApi: StakeKitApi,
private val appPreferencesStore: AppPreferencesStore,
private val dispatchers: CoroutineDispatcherProvider,
-) : StakingTransactionHashRepository {
+) : StakeKitTransactionHashRepository {
override suspend fun submitHash(transactionId: String, transactionHash: String) {
withContext(dispatchers.io) {
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 689dd885f3..cfa19d6761 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
@@ -1,204 +1,38 @@
package com.tangem.data.staking
-import android.util.Base64
import arrow.core.getOrElse
-import com.squareup.moshi.Moshi
-import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
-import com.tangem.blockchain.common.TransactionData
-import com.tangem.blockchain.common.TransactionStatus
-import com.tangem.blockchain.common.transaction.Fee
-import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.blockchainsdk.utils.toBlockchain
-import com.tangem.common.extensions.hexToBytes
-import com.tangem.common.extensions.toCompressedPublicKey
-import com.tangem.data.staking.converters.YieldConverter
-import com.tangem.data.staking.converters.action.ActionStatusConverter
-import com.tangem.data.staking.converters.action.EnterActionResponseConverter
-import com.tangem.data.staking.converters.transaction.GasEstimateConverter
-import com.tangem.data.staking.converters.transaction.StakingTransactionConverter
-import com.tangem.data.staking.converters.transaction.StakingTransactionStatusConverter
-import com.tangem.data.staking.converters.transaction.StakingTransactionTypeConverter
import com.tangem.data.staking.store.YieldsBalancesStore
-import com.tangem.datasource.api.common.response.ApiResponse
-import com.tangem.datasource.api.common.response.getOrThrow
-import com.tangem.datasource.api.stakekit.StakeKitApi
-import com.tangem.datasource.api.stakekit.models.request.*
-import com.tangem.datasource.api.stakekit.models.response.EnabledYieldsResponse
-import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
-import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionStatusDTO
-import com.tangem.datasource.api.stakekit.models.response.model.transaction.tron.TronStakeKitTransaction
-import com.tangem.datasource.local.token.P2PEthPoolVaultsStore
-import com.tangem.datasource.local.token.StakingYieldsStore
-import com.tangem.datasource.local.token.converter.StakingNetworkTypeConverter
-import com.tangem.datasource.local.token.converter.YieldTokenConverter
import com.tangem.domain.card.common.TapWorkarounds.isWallet2
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
-import com.tangem.domain.models.staking.NetworkType
import com.tangem.domain.models.staking.YieldBalance
-import com.tangem.domain.models.staking.action.StakingActionType
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.staking.model.StakingAvailability
-import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.staking.model.StakingIntegrationID
-import com.tangem.domain.staking.model.StakingOption
-import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault
-import com.tangem.domain.staking.model.stakekit.Yield
-import com.tangem.domain.staking.model.stakekit.action.StakingAction
-import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
-import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
-import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
-import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
-import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
+import com.tangem.domain.staking.repositories.P2PEthPoolRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.staking.toggles.StakingFeatureToggles
-import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.lib.crypto.BlockchainUtils.isCardano
import com.tangem.lib.crypto.BlockchainUtils.isSolana
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
-import timber.log.Timber
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
internal class DefaultStakingRepository(
- private val stakeKitApi: StakeKitApi,
- private val stakingYieldsStore: StakingYieldsStore,
- private val p2pEthPoolVaultsStore: P2PEthPoolVaultsStore,
+ private val stakeKitRepository: StakeKitRepository,
+ private val p2pEthPoolRepository: P2PEthPoolRepository,
private val stakingBalanceStoreV2: YieldsBalancesStore,
private val dispatchers: CoroutineDispatcherProvider,
- private val walletManagersFacade: WalletManagersFacade,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val stakingFeatureToggles: StakingFeatureToggles,
- moshi: Moshi,
) : StakingRepository {
- private val transactionStatusConverter = StakingTransactionStatusConverter()
- private val transactionTypeConverter = StakingTransactionTypeConverter()
- private val actionStatusConverter = ActionStatusConverter()
-
- private val transactionConverter = StakingTransactionConverter(
- transactionStatusConverter = transactionStatusConverter,
- transactionTypeConverter = transactionTypeConverter,
- )
- private val enterActionResponseConverter = EnterActionResponseConverter(
- actionStatusConverter = actionStatusConverter,
- transactionConverter = transactionConverter,
- )
-
- private val tronStakeKitTransactionAdapter by lazy { moshi.adapter(TronStakeKitTransaction::class.java) }
- private val networkTypeAdapter by lazy { moshi.adapter(NetworkTypeDTO::class.java) }
- private val stakingActionStatusAdapter by lazy { moshi.adapter(StakingActionStatusDTO::class.java) }
-
- override suspend fun fetchYields() {
- withContext(dispatchers.io) {
- val yieldsResponses = getAvailableStakeKitIntegrationsIds().map {
- async { it.getYieldRequest() }
- }.awaitAll()
-
- val yields = yieldsResponses.flatMap { response ->
- when (response) {
- is ApiResponse.Success -> response.data.data.filter { yield -> yield.isAvailable == true }
- else -> {
- Timber.e("Error fetching enabled yields: ${(response as? ApiResponse.Error)?.cause}")
- emptyList()
- }
- }
- }
- stakingYieldsStore.store(yields)
- }
- }
-
- override suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield {
- return withContext(dispatchers.io) {
- val rawCurrencyId = cryptoCurrencyId.rawCurrencyId ?: error("Staking custom tokens is not available")
-
- val prefetchedYield = findPrefetchedYield(
- yields = getEnabledYieldsSync(),
- currencyId = rawCurrencyId,
- symbol = symbol,
- )
-
- prefetchedYield ?: error("Staking is unavailable")
- }
- }
-
- 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,
- networkType: NetworkType,
- stakingActionStatus: StakingActionStatus,
- ): List {
- return withContext(dispatchers.io) {
- val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
-
- val networkTypeDto = StakingNetworkTypeConverter.convertBack(networkType)
- val networkTypeString = networkTypeDto.extractJsonName()
-
- val actionStatusDTO = actionStatusConverter.convertBack(stakingActionStatus)
- val actionStatusString = actionStatusDTO.extractJsonName()
-
- enterActionResponseConverter.convertListIgnoreErrors(
- input = stakeKitApi.getActions(
- walletAddress = address,
- network = networkTypeString,
- status = actionStatusString,
- ).getOrThrow().data,
- onError = { Timber.e("Error converting staking actions list: $it") },
- )
- }
- }
-
- private suspend fun StakingIntegrationID.StakeKit.getYieldRequest(): ApiResponse {
- return when (this) {
- is StakingIntegrationID.StakeKit.Coin -> stakeKitApi.getEnabledYields(
- preferredValidatorsOnly = false,
- network = networkId,
- )
- is StakingIntegrationID.StakeKit.EthereumToken -> stakeKitApi.getEnabledYields(
- preferredValidatorsOnly = false,
- yieldId = value,
- network = networkId,
- )
- }
- }
-
- private fun getAvailableStakeKitIntegrationsIds(): List {
- return StakingIntegrationID.StakeKit.entries.filterNot {
- it.blockchain == Blockchain.Cardano && !stakingFeatureToggles.isCardanoStakingEnabled
- }
- }
-
- private fun NetworkTypeDTO.extractJsonName(): String {
- return networkTypeAdapter.toJson(this).replace("\"", "")
- }
-
- private fun StakingActionStatusDTO.extractJsonName(): String {
- return stakingActionStatusAdapter.toJson(this).replace("\"", "")
- }
-
- override suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo {
- return withContext(dispatchers.io) {
- val yield = getYield(cryptoCurrencyId, symbol)
-
- StakingEntryInfo(
- tokenSymbol = yield.token.symbol,
- )
- }
- }
-
override fun getStakingAvailability(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
@@ -222,14 +56,16 @@ internal class DefaultStakingRepository(
val stakingIntegration = StakingIntegrationID.create(currencyId = cryptoCurrency.id)
- when (stakingIntegration) {
- is StakingIntegrationID.P2P -> subscribeToP2PStakingAvailability()
- is StakingIntegrationID.StakeKit -> subscribeToStakeKitStakingAvailability(
+ val availabilityFlow = when (stakingIntegration) {
+ is StakingIntegrationID.P2P -> p2pEthPoolRepository.getStakingAvailability()
+ is StakingIntegrationID.StakeKit -> stakeKitRepository.getStakingAvailability(
rawCurrencyId,
- cryptoCurrency,
+ cryptoCurrency.symbol,
)
- null -> send(StakingAvailability.Unavailable)
+ null -> flowOf(StakingAvailability.Unavailable)
}
+
+ availabilityFlow.collect { send(it) }
}
}
@@ -254,39 +90,25 @@ internal class DefaultStakingRepository(
?: return StakingAvailability.Unavailable
return when (stakingIntegration) {
- is StakingIntegrationID.P2P -> {
- val vaults = getP2PEthPoolVaultsSync()
- if (vaults.isEmpty()) {
- return StakingAvailability.TemporaryUnavailable
- }
+ is StakingIntegrationID.P2P -> p2pEthPoolRepository.getStakingAvailabilitySync()
+ is StakingIntegrationID.StakeKit -> stakeKitRepository.getStakingAvailabilitySync(
+ rawCurrencyId,
+ cryptoCurrency.symbol,
+ )
+ }
+ }
- val vault = findP2PEthPoolVault(
- vaults = vaults,
- )
+ override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean {
+ return withContext(dispatchers.default) {
+ val balances = stakingBalanceStoreV2.getAllSyncOrNull(userWalletId) ?: return@withContext false
- if (vault != null) {
- StakingAvailability.Available(StakingOption.P2P(vault))
- } else {
- StakingAvailability.TemporaryUnavailable
+ val hasDataYieldBalance by lazy {
+ balances.any { yieldBalance ->
+ (yieldBalance as? YieldBalance.Data)?.balance?.items?.isNotEmpty() == true
}
}
- is StakingIntegrationID.StakeKit -> {
- val yields = getEnabledYieldsSync()
- if (yields.isEmpty()) {
- return StakingAvailability.TemporaryUnavailable
- }
- val prefetchedYield = findPrefetchedYield(
- yields = yields,
- currencyId = rawCurrencyId,
- symbol = cryptoCurrency.symbol,
- )
-
- when {
- prefetchedYield != null -> StakingAvailability.Available(StakingOption.StakeKit(prefetchedYield))
- else -> StakingAvailability.TemporaryUnavailable
- }
- }
+ balances.isNotEmpty() && hasDataYieldBalance
}
}
@@ -316,267 +138,6 @@ internal class DefaultStakingRepository(
}
}
- override suspend fun createAction(
- userWalletId: UserWalletId,
- network: Network,
- params: ActionParams,
- ): StakingAction {
- return withContext(dispatchers.io) {
- val response = when (params.actionCommonType) {
- is StakingActionCommonType.Enter -> stakeKitApi.createEnterAction(
- createActionRequestBody(
- userWalletId,
- network,
- params,
- ),
- )
- is StakingActionCommonType.Exit -> stakeKitApi.createExitAction(
- createActionRequestBody(
- userWalletId,
- network,
- params,
- ),
- )
- is StakingActionCommonType.Pending -> stakeKitApi.createPendingAction(
- createPendingActionRequestBody(params),
- )
- }
-
- enterActionResponseConverter.convert(response.getOrThrow())
- }
- }
-
- override suspend fun estimateGas(
- userWalletId: UserWalletId,
- network: Network,
- params: ActionParams,
- ): StakingGasEstimate {
- return withContext(dispatchers.io) {
- val gasEstimateDTO = when (params.actionCommonType) {
- is StakingActionCommonType.Enter -> stakeKitApi.estimateGasOnEnter(
- createActionRequestBody(
- userWalletId,
- network,
- params,
- ),
- )
- is StakingActionCommonType.Exit -> stakeKitApi.estimateGasOnExit(
- createActionRequestBody(
- userWalletId,
- network,
- params,
- ),
- )
- is StakingActionCommonType.Pending -> stakeKitApi.estimateGasOnPending(
- createPendingActionRequestBody(params),
- )
- }
-
- GasEstimateConverter.convert(gasEstimateDTO.getOrThrow())
- }
- }
-
- override suspend fun constructTransaction(
- networkId: String,
- fee: Fee,
- amount: Amount,
- transactionId: String,
- ): Pair {
- return withContext(dispatchers.io) {
- val transactionResponse = stakeKitApi.constructTransaction(
- transactionId = transactionId,
- body = ConstructTransactionRequestBody(),
- )
-
- val transaction = transactionConverter.convert(transactionResponse.getOrThrow())
- val unsignedTransaction =
- transaction.unsignedTransaction ?: error("No unsigned transaction available")
- val transactionData = TransactionData.Compiled(
- value = getTransactionDataType(networkId, unsignedTransaction),
- fee = fee,
- amount = amount,
- status = TransactionStatus.Unconfirmed,
- )
-
- transaction to transactionData
- }
- }
-
- override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean {
- return withContext(dispatchers.default) {
- val balances = stakingBalanceStoreV2.getAllSyncOrNull(userWalletId) ?: return@withContext false
-
- val hasDataYieldBalance by lazy {
- balances.any { yieldBalance ->
- (yieldBalance as? YieldBalance.Data)?.balance?.items?.isNotEmpty() == true
- }
- }
-
- balances.isNotEmpty() && hasDataYieldBalance
- }
- }
-
- private suspend fun createActionRequestBody(
- userWalletId: UserWalletId,
- network: Network,
- params: ActionParams,
- ): ActionRequestBody {
- return ActionRequestBody(
- integrationId = params.integrationId,
- addresses = Address(
- address = params.address,
- additionalAddresses = createAdditionalAddresses(userWalletId, network, params),
- ),
- args = ActionRequestBodyArgs(
- amount = params.amount.toPlainString(),
- inputToken = YieldTokenConverter.convertBack(params.token),
- validatorAddress = params.validatorAddress,
- validatorAddresses = listOf(params.validatorAddress), // check on other networks
- tronResource = getTronResource(network),
- ),
- )
- }
-
- private fun createPendingActionRequestBody(params: ActionParams): PendingActionRequestBody {
- return PendingActionRequestBody(
- integrationId = params.integrationId,
- type = params.type ?: StakingActionType.UNKNOWN,
- passthrough = params.passthrough.orEmpty(),
- args = ActionRequestBodyArgs(
- amount = params.amount.toPlainString(),
- validatorAddress = params.validatorAddress,
- validatorAddresses = listOf(params.validatorAddress),
- ),
- )
- }
-
- private suspend fun createAdditionalAddresses(
- userWalletId: UserWalletId,
- network: Network,
- params: ActionParams,
- ): Address.AdditionalAddresses? {
- val selectedWallet = walletManagersFacade.getOrCreateWalletManager(userWalletId, network)
- return when (params.token.network) {
- NetworkType.COSMOS -> Address.AdditionalAddresses(
- cosmosPubKey = Base64.encodeToString(
- /* input = */ selectedWallet?.wallet?.publicKey?.blockchainKey?.toCompressedPublicKey(),
- /* flags = */ Base64.NO_WRAP,
- ),
- )
- else -> null
- }
- }
-
- private fun getTransactionDataType(networkId: String, unsignedTransaction: String): TransactionData.Compiled.Data {
- return when (Blockchain.fromId(networkId)) {
- Blockchain.Solana,
- Blockchain.Cosmos,
- -> TransactionData.Compiled.Data.Bytes(unsignedTransaction.hexToBytes())
- Blockchain.BSC,
- Blockchain.Ethereum,
- Blockchain.TON,
- Blockchain.Cardano,
- -> TransactionData.Compiled.Data.RawString(unsignedTransaction)
- Blockchain.Tron -> {
- val tronStakeKitTransaction = tronStakeKitTransactionAdapter.fromJson(unsignedTransaction)
- ?: error("Failed to parse Tron StakeKit transaction")
- TransactionData.Compiled.Data.RawString(tronStakeKitTransaction.rawDataHex)
- }
- else -> error("Unsupported blockchain")
- }
- }
-
- private fun findPrefetchedYield(yields: List, currencyId: CryptoCurrency.RawID, symbol: String): Yield? {
- return yields.find { yield ->
- yield.tokens.any { it.coinGeckoId == currencyId.value && it.symbol == symbol }
- }
- }
-
- private suspend fun getEnabledYieldsSync(): List {
- return YieldConverter.convertListIgnoreErrors(
- input = stakingYieldsStore.getSync(),
- onError = { Timber.e("Error converting one of the items in enabled yields: $it") },
- )
- }
-
- override fun getEnabledYields(): Flow> {
- return stakingYieldsStore.get().map {
- YieldConverter.convertListIgnoreErrors(
- input = it,
- onError = { Timber.e("Error converting one of the items in enabled yields: $it") },
- )
- }
- }
-
- private suspend fun getP2PEthPoolVaultsSync(): List {
- return p2pEthPoolVaultsStore.getSync()
- }
-
- private fun getP2PEthPoolVaults(): Flow> {
- return p2pEthPoolVaultsStore.get()
- }
-
- private fun findP2PEthPoolVault(vaults: List): P2PEthPoolVault? {
- return vaults.firstOrNull { vault -> !vault.isPrivate }
- }
-
- private fun ProducerScope.subscribeToP2PStakingAvailability() {
- getP2PEthPoolVaults()
- .distinctUntilChanged()
- .onEach { vaults ->
- if (vaults.isEmpty()) {
- send(StakingAvailability.TemporaryUnavailable)
- return@onEach
- }
-
- val vault = findP2PEthPoolVault(vaults = vaults)
-
- if (vault != null) {
- send(StakingAvailability.Available(StakingOption.P2P(vault)))
- } else {
- send(StakingAvailability.TemporaryUnavailable)
- }
- }
- .launchIn(this)
- }
-
- private fun ProducerScope.subscribeToStakeKitStakingAvailability(
- rawCurrencyId: CryptoCurrency.RawID,
- cryptoCurrency: CryptoCurrency,
- ) {
- getEnabledYields()
- .distinctUntilChanged()
- .onEach { yields ->
- if (yields.isEmpty()) {
- send(StakingAvailability.TemporaryUnavailable)
- return@onEach
- }
-
- val prefetchedYield = findPrefetchedYield(
- yields = yields,
- currencyId = rawCurrencyId,
- symbol = cryptoCurrency.symbol,
- )
-
- if (prefetchedYield != null) {
- send(StakingAvailability.Available(StakingOption.StakeKit(prefetchedYield)))
- } else {
- send(StakingAvailability.TemporaryUnavailable)
- }
- }
- .launchIn(this)
- }
-
- private fun getTronResource(network: Network): TronResource? {
- val blockchain = Blockchain.fromNetworkId(network.backendId)
-
- return if (blockchain == Blockchain.Tron || blockchain == Blockchain.TronTestnet) {
- TronResource.ENERGY
- } else {
- null
- }
- }
-
companion object {
private val INVALID_BATCHES_FOR_SOLANA = listOf("AC01", "CB79")
}
diff --git a/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt b/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt
index 8e82d81a8f..6b51907e70 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt
@@ -4,10 +4,11 @@ import com.squareup.moshi.Moshi
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.data.staking.DefaultP2PEthPoolRepository
-import com.tangem.data.staking.DefaultStakingActionRepository
+import com.tangem.data.staking.DefaultStakeKitActionRepository
import com.tangem.data.staking.DefaultStakingErrorResolver
+import com.tangem.data.staking.DefaultStakeKitRepository
import com.tangem.data.staking.DefaultStakingRepository
-import com.tangem.data.staking.DefaultStakingTransactionHashRepository
+import com.tangem.data.staking.DefaultStakeKitTransactionHashRepository
import com.tangem.data.staking.converters.error.StakeKitErrorConverter
import com.tangem.data.staking.store.YieldsBalancesStore
import com.tangem.data.staking.toggles.DefaultStakingFeatureToggles
@@ -21,10 +22,11 @@ import com.tangem.datasource.local.token.P2PEthPoolVaultsStore
import com.tangem.datasource.local.token.StakingActionsStore
import com.tangem.datasource.local.token.StakingYieldsStore
import com.tangem.domain.staking.repositories.P2PEthPoolRepository
-import com.tangem.domain.staking.repositories.StakingActionRepository
+import com.tangem.domain.staking.repositories.StakeKitActionRepository
import com.tangem.domain.staking.repositories.StakingErrorResolver
+import com.tangem.domain.staking.repositories.StakeKitRepository
import com.tangem.domain.staking.repositories.StakingRepository
-import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
+import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
import com.tangem.domain.staking.toggles.StakingFeatureToggles
import com.tangem.domain.staking.utils.StakingCleaner
import com.tangem.domain.walletmanager.WalletManagersFacade
@@ -42,30 +44,44 @@ internal object StakingDataModule {
@Provides
@Singleton
- fun provideStakingRepository(
+ fun provideStakeKitRepository(
stakeKitApi: StakeKitApi,
stakingYieldsStore: StakingYieldsStore,
- p2pEthPoolVaultsStore: P2PEthPoolVaultsStore,
- yieldsBalancesStore: YieldsBalancesStore,
dispatchers: CoroutineDispatcherProvider,
walletManagersFacade: WalletManagersFacade,
- getUserWalletUseCase: GetUserWalletUseCase,
stakingFeatureToggles: StakingFeatureToggles,
@NetworkMoshi moshi: Moshi,
- ): StakingRepository {
- return DefaultStakingRepository(
+ ): StakeKitRepository {
+ return DefaultStakeKitRepository(
stakeKitApi = stakeKitApi,
stakingYieldsStore = stakingYieldsStore,
- p2pEthPoolVaultsStore = p2pEthPoolVaultsStore,
- stakingBalanceStoreV2 = yieldsBalancesStore,
dispatchers = dispatchers,
walletManagersFacade = walletManagersFacade,
- getUserWalletUseCase = getUserWalletUseCase,
stakingFeatureToggles = stakingFeatureToggles,
moshi = moshi,
)
}
+ @Provides
+ @Singleton
+ fun provideStakingRepository(
+ stakeKitRepository: StakeKitRepository,
+ p2pEthPoolRepository: P2PEthPoolRepository,
+ yieldsBalancesStore: YieldsBalancesStore,
+ dispatchers: CoroutineDispatcherProvider,
+ getUserWalletUseCase: GetUserWalletUseCase,
+ stakingFeatureToggles: StakingFeatureToggles,
+ ): StakingRepository {
+ return DefaultStakingRepository(
+ stakeKitRepository = stakeKitRepository,
+ p2pEthPoolRepository = p2pEthPoolRepository,
+ stakingBalanceStoreV2 = yieldsBalancesStore,
+ dispatchers = dispatchers,
+ getUserWalletUseCase = getUserWalletUseCase,
+ stakingFeatureToggles = stakingFeatureToggles,
+ )
+ }
+
@Provides
@Singleton
fun provideP2PEthPoolRepository(
@@ -86,8 +102,8 @@ internal object StakingDataModule {
stakeKitApi: StakeKitApi,
appPreferencesStore: AppPreferencesStore,
dispatchers: CoroutineDispatcherProvider,
- ): StakingTransactionHashRepository {
- return DefaultStakingTransactionHashRepository(
+ ): StakeKitTransactionHashRepository {
+ return DefaultStakeKitTransactionHashRepository(
stakeKitApi = stakeKitApi,
appPreferencesStore = appPreferencesStore,
dispatchers = dispatchers,
@@ -99,8 +115,8 @@ internal object StakingDataModule {
fun provideStakingActionRepository(
stakingActionsStore: StakingActionsStore,
dispatchers: CoroutineDispatcherProvider,
- ): StakingActionRepository {
- return DefaultStakingActionRepository(
+ ): StakeKitActionRepository {
+ return DefaultStakeKitActionRepository(
stakingActionsStore = stakingActionsStore,
dispatchers = dispatchers,
)
diff --git a/data/staking/src/main/java/com/tangem/data/staking/multi/DefaultMultiYieldBalanceFetcher.kt b/data/staking/src/main/java/com/tangem/data/staking/multi/DefaultMultiYieldBalanceFetcher.kt
index 62f2e5e33e..eca2f69f33 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/multi/DefaultMultiYieldBalanceFetcher.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/multi/DefaultMultiYieldBalanceFetcher.kt
@@ -69,8 +69,8 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
fetch(userWalletId = params.userWalletId, stakingIds = availableStakingIds)
}
- .onLeft {
- Timber.e(it, "Unable to fetch yield balances $params")
+ .onLeft { throwable ->
+ Timber.e(throwable, "Unable to fetch yield balances $params")
yieldsBalancesStore.storeError(userWalletId = params.userWalletId, stakingIds = stakingIds)
}
@@ -163,21 +163,21 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
if (!allResponsesReceived(requests, yieldBalances)) {
val values = stakingIds.filter { stakingId ->
- yieldBalances.none {
- stakingId.integrationId == it.integrationId &&
- stakingId.address == it.addresses.address
+ yieldBalances.none { balanceWrapper ->
+ stakingId.integrationId == balanceWrapper.integrationId &&
+ stakingId.address == balanceWrapper.addresses.address
}
}
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = values.toSet())
}
},
- onError = {
- Timber.e(it, "Unable to fetch yield balances $userWalletId")
+ onError = { throwable ->
+ Timber.e(throwable, "Unable to fetch yield balances $userWalletId")
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = stakingIds)
- throw it
+ throw throwable
},
)
}
@@ -187,9 +187,9 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
yieldBalances: Set,
): Boolean {
return requests.all { request ->
- yieldBalances.any {
- request.integrationId == it.integrationId &&
- request.addresses.address == it.addresses.address
+ yieldBalances.any { balance ->
+ request.integrationId == balance.integrationId &&
+ request.addresses.address == balance.addresses.address
}
}
}
diff --git a/data/staking/src/main/java/com/tangem/data/staking/utils/YieldBalanceRequestBodyFactory.kt b/data/staking/src/main/java/com/tangem/data/staking/utils/YieldBalanceRequestBodyFactory.kt
index 8da94e5450..4db8d77f02 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/utils/YieldBalanceRequestBodyFactory.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/utils/YieldBalanceRequestBodyFactory.kt
@@ -14,7 +14,7 @@ internal object YieldBalanceRequestBodyFactory {
return YieldBalanceRequestBody(
addresses = YieldBalanceRequestBodyAddressFactory.create(stakingID),
args = YieldBalanceRequestBody.YieldBalanceRequestArgs(
- validatorAddresses = listOf(), // todo add validators [REDACTED_JIRA]
+ validatorAddresses = emptyList(), // todo add validators [REDACTED_JIRA]
),
integrationId = stakingID.integrationId,
)
diff --git a/detekt_baseline_report.txt b/detekt_baseline_report.txt
index 8bd49ad41c..fac2141bcf 100644
--- a/detekt_baseline_report.txt
+++ b/detekt_baseline_report.txt
@@ -38,7 +38,7 @@ features/staking/impl 56
data/wallet-connect 55
features/swap-v2/impl 53
features/walletconnect/impl 51
-features/tokendetails/impl 50
+features/tokendetails/impl 49
features/manage-tokens/impl 45
domain/wallets 39
features/nft/impl 36
@@ -65,7 +65,6 @@ features/details/impl 10
data/markets 10
domain/staking 9
data/yield-supply 9
-data/staking 9
data/networks 9
features/welcome/impl 8
features/home/impl 8
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/EstimateGasUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/EstimateGasUseCase.kt
index 21e2e6ee0e..6c9ab7efc3 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/EstimateGasUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/EstimateGasUseCase.kt
@@ -6,14 +6,14 @@ import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
import com.tangem.domain.models.wallet.UserWalletId
/**
* Use case for staking gas estimation.
*/
class EstimateGasUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -23,7 +23,7 @@ class EstimateGasUseCase(
params: ActionParams,
): Either {
return Either.catch {
- stakingRepository.estimateGas(userWalletId, network, params)
+ stakeKitRepository.estimateGas(userWalletId, network, params)
}.mapLeft {
stakingErrorResolver.resolve(it)
}
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/FetchActionsUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/FetchActionsUseCase.kt
index f44adef4ae..bf2136e66f 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/FetchActionsUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/FetchActionsUseCase.kt
@@ -5,17 +5,17 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.staking.NetworkType
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
-import com.tangem.domain.staking.repositories.StakingActionRepository
+import com.tangem.domain.staking.repositories.StakeKitActionRepository
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
import com.tangem.domain.models.wallet.UserWalletId
/**
* Use case for getting pending actions list.
*/
class FetchActionsUseCase(
- private val stakingRepository: StakingRepository,
- private val stakingActionRepository: StakingActionRepository,
+ private val stakeKitRepository: StakeKitRepository,
+ private val stakeKitActionRepository: StakeKitActionRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -27,14 +27,14 @@ class FetchActionsUseCase(
): Either {
return Either
.catch {
- val actions = stakingRepository.getActions(
+ val actions = stakeKitRepository.getActions(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
networkType = networkType,
stakingActionStatus = stakingActionStatus,
)
- stakingActionRepository.store(userWalletId, cryptoCurrency.id, actions)
+ stakeKitActionRepository.store(userWalletId, cryptoCurrency.id, actions)
}
.mapLeft { stakingErrorResolver.resolve(it) }
}
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingOptionsUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingOptionsUseCase.kt
index 135f589770..3c5a7b4fe1 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingOptionsUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingOptionsUseCase.kt
@@ -6,7 +6,7 @@ import arrow.core.raise.either
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.repositories.P2PEthPoolRepository
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@@ -15,7 +15,7 @@ import kotlinx.coroutines.launch
* Fetches both StakeKit yields and P2P vaults
*/
class FetchStakingOptionsUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val p2pRepository: P2PEthPoolRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -24,7 +24,7 @@ class FetchStakingOptionsUseCase(
catch(
block = {
coroutineScope {
- launch { stakingRepository.fetchYields() }
+ launch { stakeKitRepository.fetchYields() }
launch { p2pRepository.fetchVaults() }
}
},
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingTokensUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingTokensUseCase.kt
index 5aef2d9cf1..86fcd054f0 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingTokensUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/FetchStakingTokensUseCase.kt
@@ -5,19 +5,19 @@ import arrow.core.raise.catch
import arrow.core.raise.either
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.staking.repositories.StakeKitRepository
/**
* Use case for getting enabled tokens
*/
class FetchStakingTokensUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(): Either {
return either {
catch(
- block = { stakingRepository.fetchYields() },
+ block = { stakeKitRepository.fetchYields() },
catch = { stakingErrorResolver.resolve(it) },
)
}
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetActionsUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetActionsUseCase.kt
index 69d66c85b3..29c649c1cf 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/GetActionsUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetActionsUseCase.kt
@@ -7,7 +7,7 @@ import com.tangem.domain.core.utils.EitherFlow
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.action.StakingAction
-import com.tangem.domain.staking.repositories.StakingActionRepository
+import com.tangem.domain.staking.repositories.StakeKitActionRepository
import com.tangem.domain.staking.repositories.StakingErrorResolver
import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.coroutines.flow.catch
@@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.map
* Use case for getting pending actions list.
*/
class GetActionsUseCase(
- private val stakingActionRepository: StakingActionRepository,
+ private val stakeKitActionRepository: StakeKitActionRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -25,7 +25,7 @@ class GetActionsUseCase(
userWalletId: UserWalletId,
cryptoCurrencyId: CryptoCurrency.ID,
): EitherFlow> {
- return stakingActionRepository.get(
+ return stakeKitActionRepository.get(
userWalletId = userWalletId,
cryptoCurrencyId = cryptoCurrencyId,
).map, Either>> { it.right() }
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetConstructedStakingTransactionUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetConstructedStakingTransactionUseCase.kt
index 38ae3bf571..3402b6bb03 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/GetConstructedStakingTransactionUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetConstructedStakingTransactionUseCase.kt
@@ -7,10 +7,10 @@ import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
class GetConstructedStakingTransactionUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -20,7 +20,7 @@ class GetConstructedStakingTransactionUseCase(
amount: Amount,
transactionId: String,
): Either> = Either.catch {
- stakingRepository.constructTransaction(networkId, fee, amount, transactionId)
+ stakeKitRepository.constructTransaction(networkId, fee, amount, transactionId)
}.mapLeft {
stakingErrorResolver.resolve(it)
}
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingAvailabilityUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingAvailabilityUseCase.kt
index ecfd9fb4fb..6f7397f5a3 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingAvailabilityUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingAvailabilityUseCase.kt
@@ -8,8 +8,8 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.staking.model.StakingAvailability
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.models.wallet.UserWalletId
+import com.tangem.domain.staking.repositories.StakingRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingEntryInfoUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingEntryInfoUseCase.kt
index b8e2633bd7..ef77b03abb 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingEntryInfoUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingEntryInfoUseCase.kt
@@ -6,13 +6,13 @@ import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.staking.model.StakingOption
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.staking.repositories.StakeKitRepository
/**
* Use case for getting entry info about staking on token screen.
*/
class GetStakingEntryInfoUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -25,7 +25,7 @@ class GetStakingEntryInfoUseCase(
.catch {
when (stakingOption) {
is StakingOption.StakeKit -> {
- stakingRepository.getEntryInfo(
+ stakeKitRepository.getEntryInfo(
cryptoCurrencyId = cryptoCurrencyId,
symbol = symbol,
)
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionsUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionsUseCase.kt
index 63f92c60e5..df26a82e64 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionsUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionsUseCase.kt
@@ -6,7 +6,7 @@ import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.coroutines.delay
@@ -14,7 +14,7 @@ import kotlinx.coroutines.delay
* Use case for creating enter action
*/
class GetStakingTransactionsUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
@@ -24,7 +24,7 @@ class GetStakingTransactionsUseCase(
params: ActionParams,
): Either> {
return Either.catch {
- val createAction = stakingRepository.createAction(userWalletId, network, params)
+ val createAction = stakeKitRepository.createAction(userWalletId, network, params)
// workaround, sometimes transaction is not created immediately after actions/enter
delay(PATCH_TRANSACTION_REQUEST_DELAY)
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 b000f7126c..4dd2f1d833 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
@@ -5,25 +5,25 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
/**
* Use case for getting staking yield for staking scenario start.
*/
class GetYieldUseCase(
- private val stakingRepository: StakingRepository,
+ private val stakeKitRepository: StakeKitRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Either {
return Either
- .catch { stakingRepository.getYield(cryptoCurrencyId, symbol) }
+ .catch { stakeKitRepository.getYield(cryptoCurrencyId, symbol) }
.mapLeft { stakingErrorResolver.resolve(it) }
}
suspend operator fun invoke(yieldId: String): Either {
return Either
- .catch { stakingRepository.getYield(yieldId) }
+ .catch { stakeKitRepository.getYield(yieldId) }
.mapLeft { stakingErrorResolver.resolve(it) }
}
}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/IsAnyTokenStakedUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/IsAnyTokenStakedUseCase.kt
index 0346ef7f06..5beff03f92 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/IsAnyTokenStakedUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/IsAnyTokenStakedUseCase.kt
@@ -3,8 +3,8 @@ package com.tangem.domain.staking
import arrow.core.Either
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.models.wallet.UserWalletId
+import com.tangem.domain.staking.repositories.StakingRepository
class IsAnyTokenStakedUseCase(
private val stakingRepository: StakingRepository,
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/SaveUnsubmittedHashUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/SaveUnsubmittedHashUseCase.kt
index abfeab0d56..629b3e8891 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/SaveUnsubmittedHashUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/SaveUnsubmittedHashUseCase.kt
@@ -4,19 +4,19 @@ import arrow.core.Either
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.UnsubmittedTransactionMetadata
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
+import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
/**
* Use case for saving hash that failed to submit during staking confirmation
*/
class SaveUnsubmittedHashUseCase(
- private val stakingTransactionHashRepository: StakingTransactionHashRepository,
+ private val stakeKitTransactionHashRepository: StakeKitTransactionHashRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(transactionId: String, transactionHash: String): Either {
return Either.catch {
- stakingTransactionHashRepository.storeUnsubmittedHash(
+ stakeKitTransactionHashRepository.storeUnsubmittedHash(
unsubmittedTransactionMetadata = UnsubmittedTransactionMetadata(
transactionId = transactionId,
transactionHash = transactionHash,
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/SendUnsubmittedHashesUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/SendUnsubmittedHashesUseCase.kt
index 3564651d9f..dc4b0a8832 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/SendUnsubmittedHashesUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/SendUnsubmittedHashesUseCase.kt
@@ -3,19 +3,19 @@ package com.tangem.domain.staking
import arrow.core.Either
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
+import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
/**
* Use case for commiting hashes that failed to submit during staking confirmation
*/
class SendUnsubmittedHashesUseCase(
- private val stakingTransactionHashRepository: StakingTransactionHashRepository,
+ private val stakeKitTransactionHashRepository: StakeKitTransactionHashRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(): Either {
return Either
- .catch { stakingTransactionHashRepository.sendUnsubmittedHashes() }
+ .catch { stakeKitTransactionHashRepository.sendUnsubmittedHashes() }
.mapLeft { stakingErrorResolver.resolve(it) }
}
}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/SubmitHashUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/SubmitHashUseCase.kt
index fba8daa29b..1f9e111df7 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/SubmitHashUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/SubmitHashUseCase.kt
@@ -4,20 +4,20 @@ import arrow.core.Either
import com.tangem.domain.staking.model.SubmitHashData
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.repositories.StakingErrorResolver
-import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
+import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
/**
* Use case for submitting transaction hash to stakekit
*/
class SubmitHashUseCase(
- private val stakingTransactionHashRepository: StakingTransactionHashRepository,
+ private val stakeKitTransactionHashRepository: StakeKitTransactionHashRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(submitHashData: SubmitHashData): Either {
return Either
.catch {
- stakingTransactionHashRepository.submitHash(
+ stakeKitTransactionHashRepository.submitHash(
transactionId = submitHashData.transactionId,
transactionHash = submitHashData.transactionHash,
)
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/P2PEthPoolRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/P2PEthPoolRepository.kt
index 4c26844a7c..fabb8176d1 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/P2PEthPoolRepository.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/P2PEthPoolRepository.kt
@@ -1,8 +1,10 @@
package com.tangem.domain.staking.repositories
import arrow.core.Either
+import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.ethpool.*
import com.tangem.domain.staking.model.stakekit.StakingError
+import kotlinx.coroutines.flow.Flow
interface P2PEthPoolRepository {
@@ -113,4 +115,20 @@ interface P2PEthPoolRepository {
vaultAddress: String,
period: Int? = null,
): Either>
+
+ /**
+ * Check P2P staking availability by finding public vault
+ *
+ * @return Flow of StakingAvailability - Available with StakingOption.P2P if public vault found,
+ * TemporaryUnavailable if not found or vaults empty
+ */
+ fun getStakingAvailability(): Flow
+
+ /**
+ * Check P2P staking availability synchronously
+ *
+ * @return StakingAvailability - Available with StakingOption.P2P if public vault found,
+ * TemporaryUnavailable if not found or vaults empty
+ */
+ suspend fun getStakingAvailabilitySync(): StakingAvailability
}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingActionRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitActionRepository.kt
similarity index 92%
rename from domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingActionRepository.kt
rename to domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitActionRepository.kt
index 3328d08add..635bbc9d1d 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingActionRepository.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitActionRepository.kt
@@ -5,7 +5,7 @@ import com.tangem.domain.staking.model.stakekit.action.StakingAction
import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.coroutines.flow.Flow
-interface StakingActionRepository {
+interface StakeKitActionRepository {
suspend fun store(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID, actions: List)
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitRepository.kt
new file mode 100644
index 0000000000..a12b108ca4
--- /dev/null
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitRepository.kt
@@ -0,0 +1,54 @@
+package com.tangem.domain.staking.repositories
+
+import com.tangem.blockchain.common.Amount
+import com.tangem.blockchain.common.TransactionData
+import com.tangem.blockchain.common.transaction.Fee
+import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.network.Network
+import com.tangem.domain.models.wallet.UserWalletId
+import com.tangem.domain.staking.model.StakingAvailability
+import com.tangem.domain.staking.model.StakingEntryInfo
+import com.tangem.domain.models.staking.NetworkType
+import com.tangem.domain.staking.model.stakekit.Yield
+import com.tangem.domain.staking.model.stakekit.action.StakingAction
+import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
+import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
+import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
+import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
+import kotlinx.coroutines.flow.Flow
+
+@Suppress("TooManyFunctions")
+interface StakeKitRepository {
+
+ suspend fun fetchYields()
+
+ fun getEnabledYields(): Flow>
+
+ fun getStakingAvailability(rawCurrencyId: CryptoCurrency.RawID, symbol: String): Flow
+
+ suspend fun getStakingAvailabilitySync(rawCurrencyId: CryptoCurrency.RawID, symbol: String): StakingAvailability
+
+ suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo
+
+ suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield
+
+ suspend fun getYield(yieldId: String): Yield
+
+ suspend fun getActions(
+ userWalletId: UserWalletId,
+ cryptoCurrency: CryptoCurrency,
+ networkType: NetworkType,
+ stakingActionStatus: StakingActionStatus,
+ ): List
+
+ suspend fun createAction(userWalletId: UserWalletId, network: Network, params: ActionParams): StakingAction
+
+ suspend fun estimateGas(userWalletId: UserWalletId, network: Network, params: ActionParams): StakingGasEstimate
+
+ suspend fun constructTransaction(
+ networkId: String,
+ fee: Fee,
+ amount: Amount,
+ transactionId: String,
+ ): Pair
+}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingTransactionHashRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitTransactionHashRepository.kt
similarity index 88%
rename from domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingTransactionHashRepository.kt
rename to domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitTransactionHashRepository.kt
index be75380a84..97d971aabd 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingTransactionHashRepository.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakeKitTransactionHashRepository.kt
@@ -2,7 +2,7 @@ package com.tangem.domain.staking.repositories
import com.tangem.domain.staking.model.UnsubmittedTransactionMetadata
-interface StakingTransactionHashRepository {
+interface StakeKitTransactionHashRepository {
suspend fun submitHash(transactionId: String, transactionHash: String)
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 ab8b969f7b..1cdbcd6ae3 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
@@ -1,36 +1,12 @@
package com.tangem.domain.staking.repositories
-import com.tangem.blockchain.common.Amount
-import com.tangem.blockchain.common.TransactionData
-import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.models.currency.CryptoCurrency
-import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.staking.model.StakingAvailability
-import com.tangem.domain.staking.model.StakingEntryInfo
-import com.tangem.domain.models.staking.NetworkType
-import com.tangem.domain.staking.model.stakekit.Yield
-import com.tangem.domain.staking.model.stakekit.action.StakingAction
-import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
-import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
-import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
-import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
import kotlinx.coroutines.flow.Flow
-// TODO p2p make 3 repos: stakekit, p2p, common staking
-@Suppress("TooManyFunctions")
interface StakingRepository {
- suspend fun fetchYields()
-
- fun getEnabledYields(): Flow>
-
- suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo
-
- suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield
-
- suspend fun getYield(yieldId: String): Yield
-
fun getStakingAvailability(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Flow
suspend fun getStakingAvailabilitySync(
@@ -38,23 +14,5 @@ interface StakingRepository {
cryptoCurrency: CryptoCurrency,
): StakingAvailability
- suspend fun getActions(
- userWalletId: UserWalletId,
- cryptoCurrency: CryptoCurrency,
- networkType: NetworkType,
- stakingActionStatus: StakingActionStatus,
- ): List
-
- suspend fun createAction(userWalletId: UserWalletId, network: Network, params: ActionParams): StakingAction
-
- suspend fun estimateGas(userWalletId: UserWalletId, network: Network, params: ActionParams): StakingGasEstimate
-
- suspend fun constructTransaction(
- networkId: String,
- fee: Fee,
- amount: Amount,
- transactionId: String,
- ): Pair
-
suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean
}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt
index 3b50f3a63c..32edb6331c 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt
@@ -1,7 +1,7 @@
package com.tangem.domain.staking.usecase
import com.tangem.domain.staking.model.stakekit.Yield
-import com.tangem.domain.staking.repositories.StakingRepository
+import com.tangem.domain.staking.repositories.StakeKitRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@@ -12,10 +12,10 @@ import kotlinx.coroutines.flow.map
* - key: currency staking key (network.backendId + "_" + symbol)
* - value: validators
*/
-class StakingApyFlowUseCase(private val stakingRepository: StakingRepository) {
+class StakingApyFlowUseCase(private val stakeKitRepository: StakeKitRepository) {
operator fun invoke(): Flow