Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-25 18:30:59 +05:00
commit eee72adcf1
19 changed files with 516 additions and 138 deletions

View file

@ -1,10 +1,6 @@
package com.tangem.tap.di.domain
import com.tangem.domain.settings.*
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
import com.tangem.domain.staking.FetchStakingTokensUseCase
import com.tangem.domain.staking.GetYieldUseCase
import com.tangem.domain.staking.*
import com.tangem.domain.staking.repositories.StakingRepository
import dagger.Module
import dagger.Provides
@ -47,4 +43,16 @@ internal object StakingDomainModule {
stakingRepository = stakingRepository,
)
}
@Provides
@Singleton
fun provideFetchStakingYieldBalanceUseCase(stakingRepository: StakingRepository): FetchStakingYieldBalanceUseCase {
return FetchStakingYieldBalanceUseCase(stakingRepository = stakingRepository)
}
@Provides
@Singleton
fun provideGetStakingYieldBalanceUseCase(stakingRepository: StakingRepository): GetStakingYieldBalanceUseCase {
return GetStakingYieldBalanceUseCase(stakingRepository = stakingRepository)
}
}

View file

@ -1,8 +1,11 @@
package com.tangem.datasource.api.common.adapter
import com.squareup.moshi.*
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapters.EnumJsonAdapter
import com.tangem.datasource.api.stakekit.models.response.model.*
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionStatusDTO
import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionTypeDTO
import com.tangem.datasource.api.stakekit.models.response.model.transaction.StakingTransactionStatusDTO
@ -24,8 +27,7 @@ fun Moshi.Builder.addStakeKitEnumFallbackAdapters(): Moshi.Builder {
NetworkTypeDTO::class.java to NetworkTypeDTO.UNKNOWN,
StakingActionTypeDTO::class.java to StakingActionTypeDTO.UNKNOWN,
YieldDTO.RewardTypeDTO::class.java to YieldDTO.RewardTypeDTO.UNKNOWN,
YieldBalanceWrapperDTO.BalanceDTO.BalanceType::class.java to
YieldBalanceWrapperDTO.BalanceDTO.BalanceType.UNKNOWN,
BalanceDTO.BalanceType::class.java to BalanceDTO.BalanceType.UNKNOWN,
StakingTransactionTypeDTO::class.java to StakingTransactionTypeDTO.UNKNOWN,
StakingTransactionStatusDTO::class.java to StakingTransactionStatusDTO.UNKNOWN,
StakingActionStatusDTO::class.java to StakingActionStatusDTO.UNKNOWN,

View file

@ -4,6 +4,7 @@ import com.tangem.datasource.api.common.response.ApiResponse
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.EnterActionResponse
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.transaction.StakingTransactionDTO
import com.tangem.datasource.api.stakekit.models.response.model.TokenWithYieldDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
@ -29,16 +30,16 @@ interface StakeKitApi {
@Query("ledgerWalletAPICompatible") ledgerWalletAPICompatible: Boolean = false,
): ApiResponse<YieldDTO>
@GET("yields/balances")
@POST("yields/balances")
suspend fun getMultipleYieldBalances(
@Body body: List<YieldBalanceRequestBody>,
): ApiResponse<List<YieldBalanceWrapperDTO>>
@GET("yields/{integrationId}/balances")
@POST("yields/{integrationId}/balances")
suspend fun getSingleYieldBalance(
@Path("integrationId") integrationId: String,
@Body body: YieldBalanceRequestBody,
): ApiResponse<YieldBalanceWrapperDTO>
): ApiResponse<List<BalanceDTO>>
@GET("tokens")
suspend fun getTokens(): ApiResponse<List<TokenWithYieldDTO>>

View file

@ -1,8 +1,8 @@
package com.tangem.datasource.api.stakekit.models.request
import com.squareup.moshi.Json
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.TokenDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
data class EnterActionRequestBody(
@Json(name = "integrationId")
@ -27,7 +27,7 @@ data class EnterActionRequestBody(
@Json(name = "duration")
val duration: String? = null,
@Json(name = "nfts")
val nfts: List<YieldBalanceWrapperDTO.BalanceDTO.PendingAction.PendingActionArgs.Nft>? = null,
val nfts: List<BalanceDTO.PendingAction.PendingActionArgs.Nft>? = null,
@Json(name = "ledgerWalletAPICompatible")
val ledgerWalletAPICompatible: Boolean? = null,
@Json(name = "tronResource")

View file

@ -12,130 +12,129 @@ data class YieldBalanceWrapperDTO(
val balances: List<BalanceDTO>,
@Json(name = "integrationId")
val integrationId: String?,
)
@JsonClass(generateAdapter = true)
data class BalanceDTO(
@Json(name = "groupId")
val groupId: String,
@Json(name = "type")
val type: BalanceType,
@Json(name = "amount")
val amount: BigDecimal,
@Json(name = "date")
val date: DateTime?,
@Json(name = "pricePerShare")
val pricePerShare: BigDecimal,
@Json(name = "pendingActions")
val pendingActions: List<PendingAction>,
@Json(name = "token")
val tokenDTO: TokenDTO,
@Json(name = "validatorAddress")
val validatorAddress: String?,
@Json(name = "validatorAddresses")
val validatorAddresses: List<String>?,
@Json(name = "providerId")
val providerId: String?,
) {
enum class BalanceType {
@Json(name = "available")
AVAILABLE,
@Json(name = "staked")
STAKED,
@Json(name = "unstaking")
UNSTAKING,
@Json(name = "unstaked")
UNSTAKED,
@Json(name = "preparing")
PREPARING,
@Json(name = "rewards")
REWARDS,
@Json(name = "locked")
LOCKED,
@Json(name = "unlocking")
UNLOCKING,
UNKNOWN,
}
@JsonClass(generateAdapter = true)
data class BalanceDTO(
@Json(name = "groupId")
val groupId: String,
data class PendingAction(
@Json(name = "type")
val type: BalanceType,
@Json(name = "amount")
val amount: BigDecimal,
@Json(name = "date")
val date: DateTime?,
@Json(name = "pricePerShare")
val pricePerShare: BigDecimal,
@Json(name = "pendingActions")
val pendingActions: List<PendingAction>,
@Json(name = "token")
val tokenDTO: TokenDTO,
@Json(name = "validatorAddress")
val validatorAddress: String?,
@Json(name = "validatorAddresses")
val validatorAddresses: List<String>?,
@Json(name = "providerId")
val providerId: String?,
val type: StakingActionTypeDTO,
@Json(name = "passthrough")
val passthrough: String,
@Json(name = "args")
val args: PendingActionArgs?,
) {
enum class BalanceType {
@Json(name = "available")
AVAILABLE,
@Json(name = "staked")
STAKED,
@Json(name = "unstaking")
UNSTAKING,
@Json(name = "unstaked")
UNSTAKED,
@Json(name = "preparing")
PREPARING,
@Json(name = "rewards")
REWARDS,
@Json(name = "locked")
LOCKED,
@Json(name = "unlocking")
UNLOCKING,
UNKNOWN,
}
@JsonClass(generateAdapter = true)
data class PendingAction(
@Json(name = "type")
val type: StakingActionTypeDTO,
@Json(name = "passthrough")
val passthrough: String,
@Json(name = "args")
val args: PendingActionArgs?,
data class PendingActionArgs(
@Json(name = "amount")
val amount: Amount?,
@Json(name = "duration")
val duration: Duration?,
@Json(name = "validatorAddress")
val validatorAddress: Required?,
@Json(name = "validatorAddresses")
val validatorAddresses: Required?,
@Json(name = "nfts")
val nfts: List<Nft>?,
@Json(name = "tronResource")
val tronResource: TronResource?,
@Json(name = "signatureVerification")
val signatureVerification: Required?,
) {
@JsonClass(generateAdapter = true)
data class PendingActionArgs(
@Json(name = "amount")
val amount: Amount?,
@Json(name = "duration")
val duration: Duration?,
@Json(name = "validatorAddress")
val validatorAddress: Required?,
@Json(name = "validatorAddresses")
val validatorAddresses: Required?,
@Json(name = "nfts")
val nfts: List<Nft>?,
@Json(name = "tronResource")
val tronResource: TronResource?,
@Json(name = "signatureVerification")
val signatureVerification: Required?,
) {
@JsonClass(generateAdapter = true)
data class Amount(
@Json(name = "required")
val required: Boolean,
@Json(name = "minimum")
val minimum: BigDecimal?,
@Json(name = "maximum")
val maximum: BigDecimal?,
)
data class Amount(
@Json(name = "required")
val required: Boolean,
@Json(name = "minimum")
val minimum: BigDecimal?,
@Json(name = "maximum")
val maximum: BigDecimal?,
)
@JsonClass(generateAdapter = true)
data class Duration(
@Json(name = "required")
val required: Boolean,
@Json(name = "minimum")
val minimum: Int?,
@Json(name = "maximum")
val maximum: Int?,
)
@JsonClass(generateAdapter = true)
data class Duration(
@Json(name = "required")
val required: Boolean,
@Json(name = "minimum")
val minimum: Int?,
@Json(name = "maximum")
val maximum: Int?,
)
@JsonClass(generateAdapter = true)
data class Nft(
@Json(name = "baycId")
val baycId: Required?,
@Json(name = "maycId")
val maycId: Required?,
@Json(name = "bakcId")
val bakcId: Required?,
)
@JsonClass(generateAdapter = true)
data class Nft(
@Json(name = "baycId")
val baycId: Required?,
@Json(name = "maycId")
val maycId: Required?,
@Json(name = "bakcId")
val bakcId: Required?,
)
@JsonClass(generateAdapter = true)
data class TronResource(
@Json(name = "required")
val required: Boolean,
@Json(name = "options")
val options: List<String>,
)
}
@JsonClass(generateAdapter = true)
data class TronResource(
@Json(name = "required")
val required: Boolean,
@Json(name = "options")
val options: List<String>,
)
}
@JsonClass(generateAdapter = true)
data class Required(
@Json(name = "required")
val required: Boolean,
)
}
@JsonClass(generateAdapter = true)
data class Required(
@Json(name = "required")
val required: Boolean,
)
}

View file

@ -0,0 +1,21 @@
package com.tangem.datasource.di
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.token.DefaultStakingBalanceStore
import com.tangem.datasource.local.token.StakingBalanceStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object StakingBalanceStoreModule {
@Provides
@Singleton
fun provideStakingBalanceStore(): StakingBalanceStore {
return DefaultStakingBalanceStore(dataStore = RuntimeDataStore())
}
}

View file

@ -0,0 +1,51 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
internal class DefaultStakingBalanceStore(
private val dataStore: StringKeyDataStore<List<YieldBalanceWrapperDTO>>,
) : StakingBalanceStore {
override fun get(): Flow<List<YieldBalanceWrapperDTO>> {
return dataStore.get(STAKING_BALANCE_KEY)
}
override suspend fun getSyncOrNull(): List<YieldBalanceWrapperDTO>? {
return dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
}
override suspend fun store(items: List<YieldBalanceWrapperDTO>) {
return dataStore.store(STAKING_BALANCE_KEY, items)
}
override fun get(integrationId: String): Flow<List<BalanceDTO>> {
return dataStore.get(STAKING_BALANCE_KEY)
.map { balances ->
balances.filter { it.integrationId == integrationId }
.flatMap { it.balances }
}
}
override suspend fun getSyncOrNull(integrationId: String): List<BalanceDTO>? {
return dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
?.firstOrNull { it.integrationId == integrationId }?.balances
}
override suspend fun store(integrationId: String, item: YieldBalanceWrapperDTO) {
val balances = dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
?.toMutableList()
?.addOrReplace(item) { item.integrationId == integrationId }
?: listOf(item)
return dataStore.store(STAKING_BALANCE_KEY, balances)
}
companion object {
private const val STAKING_BALANCE_KEY = "STAKING_BALANCE_KEY"
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import kotlinx.coroutines.flow.Flow
interface StakingBalanceStore {
fun get(): Flow<List<YieldBalanceWrapperDTO>>
suspend fun getSyncOrNull(): List<YieldBalanceWrapperDTO>?
suspend fun store(items: List<YieldBalanceWrapperDTO>)
fun get(integrationId: String): Flow<List<BalanceDTO>>
suspend fun getSyncOrNull(integrationId: String): List<BalanceDTO>?
suspend fun store(integrationId: String, item: YieldBalanceWrapperDTO)
}

View file

@ -12,10 +12,17 @@ android {
dependencies {
/** Core modules */
implementation(projects.core.datasource)
implementation(projects.core.utils)
/** Common modules */
implementation(projects.data.common)
/** Domain modules */
implementation(projects.domain.tokens.models)
implementation(projects.domain.staking)
implementation(projects.domain.wallets.models)
// region DI

View file

@ -2,23 +2,33 @@ package com.tangem.data.staking
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.toCoinId
import com.tangem.data.staking.converters.StakingNetworkTypeConverter
import com.tangem.data.staking.converters.TokenConverter
import com.tangem.data.staking.converters.YieldConverter
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.staking.converters.*
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.stakekit.StakeKitApi
import com.tangem.datasource.api.stakekit.models.request.Address
import com.tangem.datasource.api.stakekit.models.request.YieldBalanceRequestBody
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.datasource.local.token.StakingBalanceStore
import com.tangem.datasource.local.token.StakingYieldsStore
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.staking.model.Yield
import com.tangem.domain.staking.model.*
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
internal class DefaultStakingRepository(
private val stakeKitApi: StakeKitApi,
private val stakingYieldsStore: StakingYieldsStore,
private val stakingBalanceStore: StakingBalanceStore,
private val cacheRegistry: CacheRegistry,
private val dispatchers: CoroutineDispatcherProvider,
) : StakingRepository {
@ -31,6 +41,10 @@ internal class DefaultStakingRepository(
tokenConverter = tokenConverter,
)
private val yieldBalanceConverter = YieldBalanceConverter()
private val yieldBalanceListConverter = YieldBalanceListConverter()
override fun isStakingSupported(currencyId: String): Boolean {
return integrationIds.contains(currencyId)
}
@ -94,9 +108,93 @@ internal class DefaultStakingRepository(
}
}
override suspend fun fetchSingleYieldBalance(
userWalletId: UserWalletId,
networkStatus: NetworkStatus,
integrationId: String,
refresh: Boolean,
) = withContext(dispatchers.io) {
cacheRegistry.invokeOnExpire(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
block = {
val result = stakeKitApi.getSingleYieldBalance(
integrationId = integrationId,
body = getBalanceRequestData(networkStatus),
).getOrThrow()
stakingBalanceStore.store(
integrationId,
YieldBalanceWrapperDTO(
balances = result,
integrationId = integrationId,
),
)
},
)
}
override fun getSingleYieldBalanceFlow(
userWalletId: UserWalletId,
networkStatus: NetworkStatus,
integrationId: String,
): Flow<List<YieldBalance>> = channelFlow {
launch(dispatchers.io) {
stakingBalanceStore.get(integrationId)
.collectLatest {
send(yieldBalanceConverter.convertList(it))
}
}
withContext(dispatchers.io) {
fetchSingleYieldBalance(
userWalletId,
networkStatus,
integrationId,
)
}
}.cancellable()
override suspend fun fetchMultiYieldBalance(
userWalletId: UserWalletId,
networks: Set<NetworkStatus>,
integrationId: String,
refresh: Boolean,
) = withContext(dispatchers.io) {
cacheRegistry.invokeOnExpire(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
block = {
val result = stakeKitApi.getMultipleYieldBalances(
networks.map(::getBalanceRequestData),
).getOrThrow()
stakingBalanceStore.store(result)
},
)
}
override fun getMultiYieldBalanceFlow(
userWalletId: UserWalletId,
networks: Set<NetworkStatus>,
integrationId: String,
): Flow<List<YieldBalanceList>> = channelFlow {
launch(dispatchers.io) {
stakingBalanceStore.get()
.collectLatest { send(yieldBalanceListConverter.convertList(it)) }
}
withContext(dispatchers.io) {
fetchMultiYieldBalance(
userWalletId,
networks,
integrationId,
)
}
}.cancellable()
private fun findPrefetchedYield(yields: List<Yield>, currencyId: String, symbol: String): Yield? {
return yields
.find { it.token.coinGeckoId == currencyId && it.token.symbol == symbol }
return yields.find { it.token.coinGeckoId == currencyId && it.token.symbol == symbol }
}
private suspend fun getEnabledYields(): List<Yield>? {
@ -104,6 +202,28 @@ internal class DefaultStakingRepository(
return yields.map { yieldConverter.convert(it) }
}
private fun getBalanceRequestData(networkStatus: NetworkStatus): YieldBalanceRequestBody {
val networkAddress = when (val network = networkStatus.value) {
NetworkStatus.MissedDerivation -> null
is NetworkStatus.NoAccount -> network.address
is NetworkStatus.Unreachable -> network.address
is NetworkStatus.Verified -> network.address
}
val address = networkAddress?.defaultAddress?.value.orEmpty()
return YieldBalanceRequestBody(
addresses = Address(
address = address,
additionalAddresses = null, // todo fill additional addresses metadata if needed
explorerUrl = "", // todo fill exporer url
),
args = YieldBalanceRequestBody.YieldBalanceRequestArgs(
validatorAddresses = listOf(), // todo add validator addresses
),
)
}
private fun getYieldBalancesKey(userWalletId: UserWalletId) = "yield_balance_${userWalletId.stringValue}"
companion object {
private val integrationIds = setOf(
Blockchain.Solana.toCoinId(),

View file

@ -0,0 +1,16 @@
package com.tangem.data.staking.converters
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.domain.staking.model.BalanceType
import com.tangem.domain.staking.model.YieldBalance
import com.tangem.utils.converter.Converter
internal class YieldBalanceConverter : Converter<BalanceDTO, YieldBalance> {
override fun convert(value: BalanceDTO): YieldBalance {
return YieldBalance(
type = BalanceType.valueOf(value.type.name),
amount = value.amount,
pricePerShare = value.pricePerShare,
)
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.data.staking.converters
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.domain.staking.model.YieldBalanceList
import com.tangem.utils.converter.Converter
internal class YieldBalanceListConverter : Converter<YieldBalanceWrapperDTO, YieldBalanceList> {
internal val converter by lazy(LazyThreadSafetyMode.NONE) {
YieldBalanceConverter()
}
override fun convert(value: YieldBalanceWrapperDTO): YieldBalanceList {
return YieldBalanceList(
balances = converter.convertList(value.balances),
)
}
}

View file

@ -1,7 +1,9 @@
package com.tangem.data.staking.di
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.staking.DefaultStakingRepository
import com.tangem.datasource.api.stakekit.StakeKitApi
import com.tangem.datasource.local.token.StakingBalanceStore
import com.tangem.datasource.local.token.StakingYieldsStore
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -20,12 +22,16 @@ internal object StakingDataModule {
fun provideStakingRepository(
stakeKitApi: StakeKitApi,
stakingTokenStore: StakingYieldsStore,
stakingBalanceStore: StakingBalanceStore,
dispatchers: CoroutineDispatcherProvider,
cacheRegistry: CacheRegistry,
): StakingRepository {
return DefaultStakingRepository(
stakeKitApi = stakeKitApi,
stakingYieldsStore = stakingTokenStore,
stakingBalanceStore = stakingBalanceStore,
dispatchers = dispatchers,
cacheRegistry = cacheRegistry,
)
}
}

View file

@ -17,4 +17,5 @@ dependencies {
implementation(deps.kotlin.serialization)
implementation(projects.domain.tokens.models)
implementation(projects.domain.wallets.models)
}

View file

@ -0,0 +1,21 @@
package com.tangem.domain.staking.model
import java.math.BigDecimal
data class YieldBalance(
val type: BalanceType,
val amount: BigDecimal,
val pricePerShare: BigDecimal,
)
enum class BalanceType {
AVAILABLE,
STAKED,
UNSTAKING,
UNSTAKED,
PREPARING,
REWARDS,
LOCKED,
UNLOCKING,
UNKNOWN,
}

View file

@ -0,0 +1,5 @@
package com.tangem.domain.staking.model
data class YieldBalanceList(
val balances: List<YieldBalance>,
)

View file

@ -0,0 +1,25 @@
package com.tangem.domain.staking
import arrow.core.Either
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.wallets.models.UserWalletId
class FetchStakingYieldBalanceUseCase(
private val stakingRepository: StakingRepository,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
networkStatus: NetworkStatus,
integrationId: String,
refresh: Boolean = false,
): Either<Throwable, Unit> = Either.catch {
stakingRepository.fetchSingleYieldBalance(
userWalletId = userWalletId,
networkStatus = networkStatus,
integrationId = integrationId,
refresh = refresh,
)
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.domain.staking
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.tangem.domain.core.utils.EitherFlow
import com.tangem.domain.staking.model.YieldBalance
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
class GetStakingYieldBalanceUseCase(
private val stakingRepository: StakingRepository,
) {
operator fun invoke(
userWalletId: UserWalletId,
networkStatus: NetworkStatus,
integrationId: String,
): EitherFlow<Throwable, List<YieldBalance>> {
return stakingRepository.getSingleYieldBalanceFlow(
userWalletId = userWalletId,
networkStatus = networkStatus,
integrationId = integrationId,
).map<List<YieldBalance>, Either<Throwable, List<YieldBalance>>> { it.right() }
.catch { emit(it.left()) }
}
}

View file

@ -1,9 +1,10 @@
package com.tangem.domain.staking.repositories
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.staking.model.Yield
import com.tangem.domain.staking.model.*
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
interface StakingRepository {
@ -19,4 +20,30 @@ interface StakingRepository {
cryptoCurrencyId: CryptoCurrency.ID,
symbol: String,
): StakingAvailability
suspend fun fetchSingleYieldBalance(
userWalletId: UserWalletId,
networkStatus: NetworkStatus,
integrationId: String,
refresh: Boolean = false,
)
fun getSingleYieldBalanceFlow(
userWalletId: UserWalletId,
networkStatus: NetworkStatus,
integrationId: String,
): Flow<List<YieldBalance>>
suspend fun fetchMultiYieldBalance(
userWalletId: UserWalletId,
networks: Set<NetworkStatus>,
integrationId: String,
refresh: Boolean = false,
)
fun getMultiYieldBalanceFlow(
userWalletId: UserWalletId,
networks: Set<NetworkStatus>,
integrationId: String,
): Flow<List<YieldBalanceList>>
}