Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-22 12:41:07 +02:00
parent fc0295bf33
commit d9320f8c2a
25 changed files with 369 additions and 89 deletions

View file

@ -1,10 +1,8 @@
package com.tangem.domain.staking.model
import com.tangem.domain.staking.model.stakekit.Yield
sealed class StakingAvailability {
data class Available(val yield: Yield) : StakingAvailability()
data class Available(val option: StakingOption) : StakingAvailability()
data object Unavailable : StakingAvailability()

View file

@ -1,9 +1,5 @@
package com.tangem.domain.staking.model
import com.tangem.domain.staking.model.stakekit.Yield
data class StakingEntryInfo(
val rewardInfo: Yield.RewardInfo,
val rewardSchedule: Yield.Metadata.RewardSchedule,
val tokenSymbol: String,
)

View file

@ -0,0 +1,62 @@
package com.tangem.domain.staking.model
import com.tangem.domain.models.serialization.SerializedBigDecimal
import com.tangem.domain.models.staking.NetworkType
import com.tangem.domain.models.staking.YieldToken
import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault
import com.tangem.domain.staking.model.stakekit.Yield
/**
* Represents a staking option from any provider
* Unified abstraction over StakeKit and P2P staking integrations
*/
sealed interface StakingOption {
/** Unique identifier for the staking option */
val integrationId: String
/** Annual Percentage Yield */
val apy: SerializedBigDecimal
/** Token being staked */
val token: YieldToken // TODO p2p
/** Whether this staking option is available */
val isAvailable: Boolean
/**
* StakeKit staking option
* Wraps StakeKit Yield with all validator and metadata information
*/
data class StakeKit(val yield: Yield) : StakingOption {
override val integrationId: String = yield.id
override val apy: SerializedBigDecimal = yield.apy
override val token: YieldToken = yield.token
override val isAvailable: Boolean = yield.isAvailable
}
/**
* P2P pooled staking option
* Wraps P2P ETH Pool vault information
*/
data class P2P(val vault: P2PEthPoolVault) : StakingOption {
override val integrationId: String =
"p2p-ethereum-pooled:${vault.vaultAddress}"
override val apy: SerializedBigDecimal = vault.apy
override val token: YieldToken = createEthToken()
override val isAvailable: Boolean = !vault.isPrivate
private fun createEthToken(): YieldToken { // TODO
return YieldToken(
name = "Ethereum",
network = NetworkType.ETHEREUM,
symbol = "ETH",
decimals = 18,
address = null, // Native token
coinGeckoId = "ethereum",
logoURI = null,
isPoints = false,
)
}
}
}

View file

@ -1,11 +1,14 @@
package com.tangem.domain.staking.model.ethpool
import com.tangem.domain.models.serialization.SerializedBigDecimal
import kotlinx.serialization.Serializable
/**
* P2P.org pooled staking vault information
* Simplified version for vault list display
* Analogue of stakekit yield
*/
@Serializable
data class P2PEthPoolVault(
val vaultAddress: String,
val displayName: String,

View file

@ -0,0 +1,35 @@
package com.tangem.domain.staking
import arrow.core.Either
import arrow.core.raise.catch
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 kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
/**
* Use case for fetching all staking options from all providers
* Fetches both StakeKit yields and P2P vaults
*/
class FetchStakingOptionsUseCase(
private val stakingRepository: StakingRepository,
private val p2pRepository: P2PEthPoolRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(): Either<StakingError, Unit> {
return either {
catch(
block = {
coroutineScope {
launch { stakingRepository.fetchYields() }
launch { p2pRepository.fetchVaults() }
}
},
catch = { stakingErrorResolver.resolve(it) },
)
}
}
}

View file

@ -17,7 +17,7 @@ class FetchStakingTokensUseCase(
suspend operator fun invoke(): Either<StakingError, Unit> {
return either {
catch(
block = { stakingRepository.fetchEnabledYields() },
block = { stakingRepository.fetchYields() },
catch = { stakingErrorResolver.resolve(it) },
)
}

View file

@ -3,6 +3,7 @@ package com.tangem.domain.staking
import arrow.core.Either
import com.tangem.domain.models.currency.CryptoCurrency
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
@ -18,13 +19,23 @@ class GetStakingEntryInfoUseCase(
suspend operator fun invoke(
cryptoCurrencyId: CryptoCurrency.ID,
symbol: String,
stakingOption: StakingOption,
): Either<StakingError, StakingEntryInfo> {
return Either
.catch {
stakingRepository.getEntryInfo(
cryptoCurrencyId = cryptoCurrencyId,
symbol = symbol,
)
when (stakingOption) {
is StakingOption.StakeKit -> {
stakingRepository.getEntryInfo(
cryptoCurrencyId = cryptoCurrencyId,
symbol = symbol,
)
}
is StakingOption.P2P -> {
StakingEntryInfo(
tokenSymbol = "ETH",
)
}
}
}
.mapLeft { stakingErrorResolver.resolve(it) }
}

View file

@ -4,11 +4,15 @@ import arrow.core.Either
import com.tangem.domain.staking.model.ethpool.*
import com.tangem.domain.staking.model.stakekit.StakingError
/**
* P2P staking repository interface
*/
interface P2PEthPoolRepository {
/**
* Fetch and store available staking vaults
*
* @param network P2P network (MAINNET or TESTNET)
*/
suspend fun fetchVaults(network: P2PEthPoolNetwork = P2PEthPoolNetwork.MAINNET)
/**
* Get list of available staking vaults
*

View file

@ -17,10 +17,11 @@ 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 fetchEnabledYields()
suspend fun fetchYields()
fun getEnabledYields(): Flow<List<Yield>>