Updated on 2026-08-14
This commit is contained in:
commit
f0e4aec9a4
858 changed files with 13724 additions and 5705 deletions
|
|
@ -2,13 +2,12 @@
|
|||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>CanBeNonNullable:StakingAnalyticsEvent.kt$StakingAnalyticsEvent$value: Any?</ID>
|
||||
<ID>MultilineLambdaItParameter:FetchStakingYieldBalanceUseCase.kt$FetchStakingYieldBalanceUseCase${ when (it) { is StakingIdFactory.Error.UnableToGetAddress -> raise(StakingError.DomainError("$it")) StakingIdFactory.Error.UnsupportedCurrency -> Unit.right() } return@either }</ID>
|
||||
<ID>MultilineLambdaItParameter:InvalidatePendingTransactionsUseCase.kt$InvalidatePendingTransactionsUseCase${ !it.isPending && action.amount < it.amount && it.type == BalanceType.STAKED && it.validatorAddress == action.validatorAddress }</ID>
|
||||
<ID>NamedArguments:GetConstructedStakingTransactionUseCase.kt$GetConstructedStakingTransactionUseCase$constructTransaction(networkId, fee, amount, transactionId)</ID>
|
||||
<ID>NullableToStringCall:StakingApyFlowUseCase.kt$StakingApyFlowUseCase$${yield.token.coinGeckoId}</ID>
|
||||
<ID>UnnecessaryAbstractClass:MultiYieldBalanceSupplier.kt$MultiYieldBalanceSupplier$MultiYieldBalanceSupplier</ID>
|
||||
<ID>UnnecessaryAbstractClass:SingleYieldBalanceSupplier.kt$SingleYieldBalanceSupplier$SingleYieldBalanceSupplier</ID>
|
||||
<ID>UnnecessaryAbstractClass:MultiStakingBalanceSupplier.kt$MultiStakingBalanceSupplier$MultiStakingBalanceSupplier</ID>
|
||||
<ID>UnnecessaryAbstractClass:SingleStakingBalanceSupplier.kt$SingleStakingBalanceSupplier$SingleStakingBalanceSupplier</ID>
|
||||
<ID>UseEmptyCounterpart:StakingAnalyticsEvent.kt$StakingAnalyticsEvent$mapOf()</ID>
|
||||
<ID>UseOrEmpty:InvalidatePendingTransactionsUseCase.kt$InvalidatePendingTransactionsUseCase$action.validatorAddress ?: action.validatorAddresses?.getOrNull(0) ?: ""</ID>
|
||||
</CurrentIssues>
|
||||
|
|
|
|||
19
domain/staking/models/detekt-baseline-main.xml
Normal file
19
domain/staking/models/detekt-baseline-main.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>BooleanPropertyNaming:P2PEthPoolStaking.kt$P2PEthPoolStaking.Metadata.Fee$val enabled: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:P2PEthPoolStaking.kt$P2PEthPoolStaking.Status$val enter: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:P2PEthPoolStaking.kt$P2PEthPoolStaking.Status$val exit: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:StakingActionCommonType.kt$StakingActionCommonType.Enter$val skipEnterAmount: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:StakingActionCommonType.kt$StakingActionCommonType.Exit$val partiallyUnstakeDisabled: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:StakingActionCommonType.kt$StakingActionCommonType.Pending.Stake$val skipEnterAmount: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$AddressArgument$val required: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$Yield$val allValidatorsFull: Boolean = validators.all { it.status == Validator.ValidatorStatus.FULL }</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$Yield.Metadata$val supportsMultipleValidators: Boolean?</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$Yield.Metadata.Enabled$val enabled: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$Yield.Status$val enter: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$Yield.Status$val exit: Boolean?</ID>
|
||||
<ID>BooleanPropertyNaming:Yield.kt$Yield.Validator$val preferred: Boolean</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -39,12 +39,11 @@ sealed interface StakingOption {
|
|||
* 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
|
||||
data class P2P(val vaults: List<P2PEthPoolVault>) : StakingOption {
|
||||
override val integrationId: String = "p2p-ethereum-pooled"
|
||||
override val apy: SerializedBigDecimal = vaults.maxOf { it.apy }
|
||||
override val token: YieldToken = createEthToken()
|
||||
override val isAvailable: Boolean = !vault.isPrivate
|
||||
override val isAvailable: Boolean = vaults.isNotEmpty()
|
||||
|
||||
private fun createEthToken(): YieldToken { // TODO
|
||||
return YieldToken(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ enum class P2PEthPoolNetwork(
|
|||
val value: String,
|
||||
val displayName: String,
|
||||
val chainId: Int,
|
||||
val stakingNetworkId: String,
|
||||
val isTestnet: Boolean,
|
||||
) {
|
||||
/**
|
||||
* Ethereum mainnet
|
||||
|
|
@ -20,16 +22,20 @@ enum class P2PEthPoolNetwork(
|
|||
value = "mainnet",
|
||||
displayName = "Ethereum",
|
||||
chainId = 1,
|
||||
stakingNetworkId = "ethereum",
|
||||
isTestnet = false,
|
||||
),
|
||||
|
||||
/**
|
||||
* Ethereum testnet (Holesky)
|
||||
* Ethereum testnet (Hoodi)
|
||||
* Chain ID: 17000
|
||||
*/
|
||||
TESTNET(
|
||||
value = "hoodi",
|
||||
displayName = "Holesky Testnet",
|
||||
displayName = "Hoodi Testnet",
|
||||
chainId = 17000,
|
||||
stakingNetworkId = "ethereum/test",
|
||||
isTestnet = true,
|
||||
),
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.domain.staking.model.ethpool
|
||||
|
||||
/**
|
||||
* Configuration for P2P Ethereum staking network.
|
||||
*
|
||||
* Change [USE_TESTNET] to switch between testnet and mainnet.
|
||||
*/
|
||||
object P2PStakingConfig {
|
||||
|
||||
const val USE_TESTNET: Boolean = true
|
||||
|
||||
val activeNetwork: P2PEthPoolNetwork
|
||||
get() = if (USE_TESTNET) P2PEthPoolNetwork.TESTNET else P2PEthPoolNetwork.MAINNET
|
||||
}
|
||||
|
|
@ -7,10 +7,10 @@ import arrow.core.right
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
|
||||
class FetchStakingYieldBalanceUseCase(
|
||||
private val singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
private val singleStakingBalanceFetcher: SingleStakingBalanceFetcher,
|
||||
private val stakingIdFactory: StakingIdFactory,
|
||||
) {
|
||||
|
||||
|
|
@ -32,8 +32,8 @@ class FetchStakingYieldBalanceUseCase(
|
|||
return@either
|
||||
}
|
||||
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingId = stakingId),
|
||||
singleStakingBalanceFetcher(
|
||||
params = SingleStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingId = stakingId),
|
||||
)
|
||||
.mapLeft { StakingError.DomainError("$it") }
|
||||
.bind()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.domain.staking.analytics
|
|||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.staking.analytics.StakingAnalyticsEvent.ButtonRewards.addIfValueIsNotNull
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
|
||||
|
|
@ -24,11 +23,11 @@ sealed class StakingAnalyticsEvent(
|
|||
),
|
||||
)
|
||||
|
||||
data object WhatIsStaking : StakingAnalyticsEvent(
|
||||
class WhatIsStaking : StakingAnalyticsEvent(
|
||||
event = "Link - What Is Staking",
|
||||
)
|
||||
|
||||
data object AmountScreenOpened : StakingAnalyticsEvent(
|
||||
class AmountScreenOpened : StakingAnalyticsEvent(
|
||||
event = "Amount Screen Opened",
|
||||
)
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ sealed class StakingAnalyticsEvent(
|
|||
),
|
||||
)
|
||||
|
||||
data object RewardScreenOpened : StakingAnalyticsEvent(
|
||||
class RewardScreenOpened : StakingAnalyticsEvent(
|
||||
event = "Reward Screen Opened",
|
||||
)
|
||||
|
||||
|
|
@ -67,7 +66,7 @@ sealed class StakingAnalyticsEvent(
|
|||
),
|
||||
)
|
||||
|
||||
data object ButtonMax : StakingAnalyticsEvent(
|
||||
class ButtonMax : StakingAnalyticsEvent(
|
||||
event = "Button - Max",
|
||||
)
|
||||
|
||||
|
|
@ -98,7 +97,7 @@ sealed class StakingAnalyticsEvent(
|
|||
),
|
||||
)
|
||||
|
||||
data object ButtonRewards : StakingAnalyticsEvent(
|
||||
class ButtonRewards : StakingAnalyticsEvent(
|
||||
event = "Button - Rewards",
|
||||
)
|
||||
|
||||
|
|
@ -112,9 +111,9 @@ sealed class StakingAnalyticsEvent(
|
|||
),
|
||||
)
|
||||
|
||||
data object ButtonShare : StakingAnalyticsEvent(event = "Button - Share")
|
||||
class ButtonShare : StakingAnalyticsEvent(event = "Button - Share")
|
||||
|
||||
data object ButtonExplore : StakingAnalyticsEvent(event = "Button - Explore")
|
||||
class ButtonExplore : StakingAnalyticsEvent(event = "Button - Explore")
|
||||
|
||||
data class StakeKitApiError(
|
||||
val stakingError: StakingError.StakeKitApiError,
|
||||
|
|
@ -145,12 +144,6 @@ sealed class StakingAnalyticsEvent(
|
|||
},
|
||||
)
|
||||
|
||||
fun MutableMap<String, String>.addIfValueIsNotNull(key: String, value: Any?) {
|
||||
if (value != null) {
|
||||
put(key, value.toString())
|
||||
}
|
||||
}
|
||||
|
||||
data class TransactionError(
|
||||
val errorCode: String,
|
||||
) : StakingAnalyticsEvent(
|
||||
|
|
@ -178,4 +171,11 @@ sealed class StakingAnalyticsEvent(
|
|||
|
||||
enum class StakeScreenSource {
|
||||
Info, Amount, Confirmation, Validators,
|
||||
}
|
||||
|
||||
@Suppress("CanBeNonNullable")
|
||||
fun MutableMap<String, String>.addIfValueIsNotNull(key: String, value: Any?) {
|
||||
if (value != null) {
|
||||
put(key, value.toString())
|
||||
}
|
||||
}
|
||||
|
|
@ -5,17 +5,17 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
/**
|
||||
* Params for fetchers of yield balance
|
||||
* Params for fetchers of staking balance
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed interface YieldBalanceFetcherParams {
|
||||
sealed interface StakingBalanceFetcherParams {
|
||||
|
||||
/** User wallet ID */
|
||||
val userWalletId: UserWalletId
|
||||
|
||||
/**
|
||||
* Params for fetching multiple yield balances
|
||||
* Params for fetching multiple staking balances
|
||||
*
|
||||
* @property userWalletId user wallet ID
|
||||
* @property currencyIdWithNetworkMap map of currency ID to network
|
||||
|
|
@ -23,10 +23,10 @@ sealed interface YieldBalanceFetcherParams {
|
|||
data class Multi(
|
||||
override val userWalletId: UserWalletId,
|
||||
val currencyIdWithNetworkMap: Map<CryptoCurrency.ID, Network>,
|
||||
) : YieldBalanceFetcherParams
|
||||
) : StakingBalanceFetcherParams
|
||||
|
||||
/**
|
||||
* Params for fetching single yield balance
|
||||
* Params for fetching single staking balance
|
||||
*
|
||||
* @property userWalletId user wallet ID
|
||||
* @property currencyId currency ID
|
||||
|
|
@ -36,5 +36,5 @@ sealed interface YieldBalanceFetcherParams {
|
|||
override val userWalletId: UserWalletId,
|
||||
val currencyId: CryptoCurrency.ID,
|
||||
val network: Network,
|
||||
) : YieldBalanceFetcherParams
|
||||
) : StakingBalanceFetcherParams
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import com.tangem.blockchainsdk.utils.toBlockchain
|
|||
import com.tangem.blockchainsdk.utils.toMigratedCoinId
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.staking.model.ethpool.P2PStakingConfig
|
||||
|
||||
/**
|
||||
* Represents a staking integration identifier.
|
||||
|
|
@ -101,8 +102,10 @@ sealed interface StakingIntegrationID {
|
|||
enum class P2P : StakingIntegrationID {
|
||||
EthereumPooled {
|
||||
override val value: String = "p2p-ethereum-pooled"
|
||||
override val blockchain: Blockchain = Blockchain.Ethereum
|
||||
override val networkId: String = "ethereum"
|
||||
override val blockchain: Blockchain
|
||||
get() = if (P2PStakingConfig.USE_TESTNET) Blockchain.EthereumTestnet else Blockchain.Ethereum
|
||||
override val networkId: String
|
||||
get() = P2PStakingConfig.activeNetwork.stakingNetworkId
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.models.staking.StakingID
|
||||
|
||||
/**
|
||||
* Fetcher of yields balances
|
||||
* Fetcher of staking balances
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface MultiYieldBalanceFetcher : FlowFetcher<MultiYieldBalanceFetcher.Params> {
|
||||
interface MultiStakingBalanceFetcher : FlowFetcher<MultiStakingBalanceFetcher.Params> {
|
||||
|
||||
/**
|
||||
* Params for fetching multiple yield balances
|
||||
* Params for fetching multiple staking balances
|
||||
*
|
||||
* @property userWalletId user wallet ID
|
||||
* @property stakingIds map of currency ID to network
|
||||
|
|
@ -24,7 +24,7 @@ interface MultiYieldBalanceFetcher : FlowFetcher<MultiYieldBalanceFetcher.Params
|
|||
|
||||
override fun toString(): String {
|
||||
return """
|
||||
MultiYieldBalanceFetcher.Params(
|
||||
MultiStakingBalanceFetcher.Params(
|
||||
userWalletId = $userWalletId,
|
||||
stakingIds: ${stakingIds.joinToString()}
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.domain.staking.multi
|
||||
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
/**
|
||||
* Producer of all staking balances for selected wallet [UserWalletId]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface MultiStakingBalanceProducer : FlowProducer<Set<StakingBalance>> {
|
||||
|
||||
data class Params(val userWalletId: UserWalletId)
|
||||
|
||||
interface Factory : FlowProducer.Factory<Params, MultiStakingBalanceProducer>
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.domain.staking.multi
|
||||
|
||||
import com.tangem.domain.core.flow.FlowCachingSupplier
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
|
||||
/**
|
||||
* Supplier of all staking balances for selected wallet [MultiStakingBalanceProducer.Params]
|
||||
*
|
||||
* @property factory factory for creating [MultiStakingBalanceProducer]
|
||||
* @property keyCreator key creator
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class MultiStakingBalanceSupplier(
|
||||
override val factory: FlowProducer.Factory<MultiStakingBalanceProducer.Params, MultiStakingBalanceProducer>,
|
||||
override val keyCreator: (MultiStakingBalanceProducer.Params) -> String,
|
||||
) : FlowCachingSupplier<MultiStakingBalanceProducer, MultiStakingBalanceProducer.Params, Set<StakingBalance>>()
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.tangem.domain.staking.multi
|
||||
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
/**
|
||||
* Producer of all yield balances for selected wallet [UserWalletId]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface MultiYieldBalanceProducer : FlowProducer<Set<YieldBalance>> {
|
||||
|
||||
data class Params(val userWalletId: UserWalletId)
|
||||
|
||||
interface Factory : FlowProducer.Factory<Params, MultiYieldBalanceProducer>
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.domain.staking.multi
|
||||
|
||||
import com.tangem.domain.core.flow.FlowCachingSupplier
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
|
||||
/**
|
||||
* Supplier of all yield balances for selected wallet [MultiYieldBalanceProducer.Params]
|
||||
*
|
||||
* @property factory factory for creating [MultiYieldBalanceProducer]
|
||||
* @property keyCreator key creator
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class MultiYieldBalanceSupplier(
|
||||
override val factory: FlowProducer.Factory<MultiYieldBalanceProducer.Params, MultiYieldBalanceProducer>,
|
||||
override val keyCreator: (MultiYieldBalanceProducer.Params) -> String,
|
||||
) : FlowCachingSupplier<MultiYieldBalanceProducer, MultiYieldBalanceProducer.Params, Set<YieldBalance>>()
|
||||
|
|
@ -2,7 +2,13 @@ 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.ethpool.P2PEthPoolAccount
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolBroadcastResult
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolNetwork
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolReward
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolUnsignedTx
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault
|
||||
import com.tangem.domain.staking.model.ethpool.P2PStakingConfig
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -13,7 +19,7 @@ interface P2PEthPoolRepository {
|
|||
*
|
||||
* @param network P2P network (MAINNET or TESTNET)
|
||||
*/
|
||||
suspend fun fetchVaults(network: P2PEthPoolNetwork = P2PEthPoolNetwork.MAINNET)
|
||||
suspend fun fetchVaults(network: P2PEthPoolNetwork = P2PStakingConfig.activeNetwork)
|
||||
|
||||
/**
|
||||
* Get list of available staking vaults
|
||||
|
|
@ -22,7 +28,7 @@ interface P2PEthPoolRepository {
|
|||
* @return Either error or list of vaults with APY, capacity, fees
|
||||
*/
|
||||
suspend fun getVaults(
|
||||
network: P2PEthPoolNetwork = P2PEthPoolNetwork.MAINNET,
|
||||
network: P2PEthPoolNetwork = P2PStakingConfig.activeNetwork,
|
||||
): Either<StakingError, List<P2PEthPoolVault>>
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.models.staking.StakingID
|
||||
|
||||
/**
|
||||
* Fetcher of yield balance
|
||||
* Fetcher of staking balance
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface SingleYieldBalanceFetcher : FlowFetcher<SingleYieldBalanceFetcher.Params> {
|
||||
interface SingleStakingBalanceFetcher : FlowFetcher<SingleStakingBalanceFetcher.Params> {
|
||||
|
||||
/**
|
||||
* Params for fetching single yield balance
|
||||
* Params for fetching single staking balance
|
||||
*
|
||||
* @property userWalletId user wallet ID
|
||||
* @property stakingId staking ID
|
||||
|
|
@ -2,15 +2,15 @@ package com.tangem.domain.staking.single
|
|||
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
|
||||
/**
|
||||
* Producer of yield balance for selected wallet [UserWalletId]
|
||||
* Producer of staking balance for selected wallet [UserWalletId]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface SingleYieldBalanceProducer : FlowProducer<YieldBalance> {
|
||||
interface SingleStakingBalanceProducer : FlowProducer<StakingBalance> {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
|
|
@ -19,7 +19,7 @@ interface SingleYieldBalanceProducer : FlowProducer<YieldBalance> {
|
|||
|
||||
override fun toString(): String {
|
||||
return """
|
||||
SingleYieldBalanceProducer.Params(
|
||||
SingleStakingBalanceProducer.Params(
|
||||
userWalletId = $userWalletId,
|
||||
stakingId = $stakingId,
|
||||
)
|
||||
|
|
@ -27,5 +27,5 @@ interface SingleYieldBalanceProducer : FlowProducer<YieldBalance> {
|
|||
}
|
||||
}
|
||||
|
||||
interface Factory : FlowProducer.Factory<Params, SingleYieldBalanceProducer>
|
||||
interface Factory : FlowProducer.Factory<Params, SingleStakingBalanceProducer>
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.domain.staking.single
|
||||
|
||||
import com.tangem.domain.core.flow.FlowCachingSupplier
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
|
||||
/**
|
||||
* Supplier of staking balance for selected wallet [SingleStakingBalanceProducer.Params]
|
||||
*
|
||||
* @property factory factory for creating [SingleStakingBalanceProducer]
|
||||
* @property keyCreator key creator
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class SingleStakingBalanceSupplier(
|
||||
override val factory: FlowProducer.Factory<SingleStakingBalanceProducer.Params, SingleStakingBalanceProducer>,
|
||||
override val keyCreator: (SingleStakingBalanceProducer.Params) -> String,
|
||||
) : FlowCachingSupplier<SingleStakingBalanceProducer, SingleStakingBalanceProducer.Params, StakingBalance>()
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.domain.staking.single
|
||||
|
||||
import com.tangem.domain.core.flow.FlowCachingSupplier
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
|
||||
/**
|
||||
* Supplier of yield balance for selected wallet [SingleYieldBalanceProducer.Params]
|
||||
*
|
||||
* @property factory factory for creating [SingleYieldBalanceProducer]
|
||||
* @property keyCreator key creator
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class SingleYieldBalanceSupplier(
|
||||
override val factory: FlowProducer.Factory<SingleYieldBalanceProducer.Params, SingleYieldBalanceProducer>,
|
||||
override val keyCreator: (SingleYieldBalanceProducer.Params) -> String,
|
||||
) : FlowCachingSupplier<SingleYieldBalanceProducer, SingleYieldBalanceProducer.Params, YieldBalance>()
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.tangem.domain.staking.utils
|
||||
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Provider-agnostic extension to get total balance including rewards.
|
||||
* Works for both StakeKit and P2P providers.
|
||||
*
|
||||
* Returns sum of all staking-related balances including rewards
|
||||
* (staked + unstaking + withdrawable + rewards).
|
||||
*
|
||||
* When [BlockchainUtils.isIncludeStakingTotalBalance] is false, the staked balance
|
||||
* is already included in the main wallet balance, so we only return rewards.
|
||||
*/
|
||||
fun StakingBalance.Data.getTotalWithRewardsStakingBalance(blockchainId: String): BigDecimal {
|
||||
return when (this) {
|
||||
is StakingBalance.Data.StakeKit -> getTotalWithRewardsStakingBalanceStakeKit(blockchainId)
|
||||
is StakingBalance.Data.P2P -> {
|
||||
val rewards = totalRewards
|
||||
if (BlockchainUtils.isIncludeStakingTotalBalance(blockchainId)) {
|
||||
totalStaked + unstakingAmount + withdrawableAmount + rewards
|
||||
} else {
|
||||
rewards
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider-agnostic extension to get total staking balance excluding rewards.
|
||||
* Works for both StakeKit and P2P providers.
|
||||
*
|
||||
* Returns sum of all staking-related balances (staked + unstaking + withdrawable)
|
||||
* excluding rewards.
|
||||
*/
|
||||
fun StakingBalance.Data.getTotalStakingBalance(blockchainId: String): BigDecimal {
|
||||
return when (this) {
|
||||
is StakingBalance.Data.StakeKit -> getTotalStakingBalanceStakeKit(blockchainId)
|
||||
is StakingBalance.Data.P2P -> totalStaked + unstakingAmount + withdrawableAmount
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StakeKit-specific extension to get total balance including rewards.
|
||||
*/
|
||||
private fun StakingBalance.Data.StakeKit.getTotalWithRewardsStakingBalanceStakeKit(blockchainId: String): BigDecimal {
|
||||
return if (BlockchainUtils.isIncludeStakingTotalBalance(blockchainId = blockchainId)) {
|
||||
balance.items.sumOf { it.amount }
|
||||
} else {
|
||||
getRewardStakingBalance()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StakeKit-specific extension to get total staked balance excluding rewards.
|
||||
*/
|
||||
private fun StakingBalance.Data.StakeKit.getTotalStakingBalanceStakeKit(blockchainId: String): BigDecimal {
|
||||
return if (BlockchainUtils.isIncludeStakingTotalBalance(blockchainId = blockchainId)) {
|
||||
balance.items
|
||||
.filterNot { it.type == BalanceType.REWARDS }
|
||||
.sumOf { it.amount }
|
||||
} else {
|
||||
balance.items
|
||||
.filterNot { it.type == BalanceType.REWARDS }
|
||||
.sumOf { it.amount } - getRewardStakingBalance()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StakeKit-specific extension to get reward balance.
|
||||
*/
|
||||
fun StakingBalance.Data.StakeKit.getRewardStakingBalance(): BigDecimal {
|
||||
return balance.items
|
||||
.filter { it.type == BalanceType.REWARDS }
|
||||
.sumOf { it.amount }
|
||||
}
|
||||
|
||||
/**
|
||||
* StakeKit-specific extension to get validators count.
|
||||
*/
|
||||
fun StakingBalance.Data.StakeKit.getValidatorsCount(): Int {
|
||||
return balance.items
|
||||
.filterNot { it.validatorAddress.isNullOrBlank() }
|
||||
.distinctBy { it.validatorAddress }
|
||||
.size
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.domain.staking.utils
|
||||
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import java.math.BigDecimal
|
||||
|
||||
fun YieldBalance.Data.getTotalWithRewardsStakingBalance(blockchainId: String): BigDecimal {
|
||||
return if (BlockchainUtils.isIncludeStakingTotalBalance(blockchainId = blockchainId)) {
|
||||
balance.items.sumOf { it.amount }
|
||||
} else {
|
||||
getRewardStakingBalance()
|
||||
}
|
||||
}
|
||||
|
||||
fun YieldBalance.Data.getTotalStakingBalance(blockchainId: String): BigDecimal {
|
||||
return if (BlockchainUtils.isIncludeStakingTotalBalance(blockchainId = blockchainId)) {
|
||||
balance.items
|
||||
.filterNot { it.type == BalanceType.REWARDS }
|
||||
.sumOf { it.amount }
|
||||
} else {
|
||||
balance.items
|
||||
.filterNot { it.type == BalanceType.REWARDS }
|
||||
.sumOf { it.amount } - getRewardStakingBalance()
|
||||
}
|
||||
}
|
||||
|
||||
fun YieldBalance.Data.getRewardStakingBalance(): BigDecimal {
|
||||
return balance.items
|
||||
.filter { it.type == BalanceType.REWARDS }
|
||||
.sumOf { it.amount }
|
||||
}
|
||||
|
||||
fun YieldBalance.Data.getValidatorsCount(): Int {
|
||||
return balance.items
|
||||
.filterNot { it.validatorAddress.isNullOrBlank() }
|
||||
.distinctBy { it.validatorAddress }
|
||||
.size
|
||||
}
|
||||
|
|
@ -149,7 +149,7 @@ internal class StakingIdFactoryTest {
|
|||
expected = createStakingId(integrationId = StakingIntegrationID.StakeKit.Coin.Cardano),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Ethereum),
|
||||
currencyId = createCurrencyId(blockchain = StakingIntegrationID.P2P.EthereumPooled.blockchain),
|
||||
expected = createStakingId(integrationId = StakingIntegrationID.P2P.EthereumPooled),
|
||||
),
|
||||
CreateModel(
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ class StakingIntegrationIDTest {
|
|||
expected = StakingIntegrationID.StakeKit.Coin.Cardano,
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Ethereum),
|
||||
currencyId = createCurrencyId(blockchain = StakingIntegrationID.P2P.EthereumPooled.blockchain),
|
||||
expected = StakingIntegrationID.P2P.EthereumPooled,
|
||||
),
|
||||
CreateModel(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue