From a046ec39fc153589f30458253292ed08ffa71360 Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 25 Apr 2024 18:09:16 +0700 Subject: [PATCH 01/11] Polkadot, Kusama, Westend staking update to paged erasStakers request and all related logic --- .../co/soramitsu/core/model/StorageEntry.kt | 2 +- .../jp/co/soramitsu/core/updater/Updater.kt | 4 +- .../staking/api/data/StakingSharedState.kt | 6 +- .../staking/api/domain/model/Exposure.kt | 17 ++- .../staking/api/domain/model/Validator.kt | 17 ++- .../network/blockhain/bindings/Exposure.kt | 55 +++++--- .../network/blockhain/bindings/Identity.kt | 9 +- .../bindings/StakingMinMaxStorages.kt | 4 +- .../updaters/AccountValidatorPrefsUpdater.kt | 27 ---- .../blockhain/updaters/ActiveEraUpdater.kt | 4 +- .../updaters/CounterForNominatorsUpdater.kt | 4 +- .../blockhain/updaters/CurrentEraUpdater.kt | 4 +- .../blockhain/updaters/HistoryDepthUpdater.kt | 4 +- .../updaters/MaxNominatorsUpdater.kt | 4 +- .../blockhain/updaters/MinBondUpdater.kt | 4 +- .../blockhain/updaters/NominatorsUpdater.kt | 75 ++++++++++ .../updaters/TotalIssuanceUpdater.kt | 4 +- .../updaters/ValidatorExposureUpdater.kt | 20 ++- .../updaters/ValidatorPrefsUpdater.kt | 50 +++++++ .../data/repository/IdentityRepositoryImpl.kt | 1 - .../impl/data/repository/PayoutRepository.kt | 7 +- .../repository/StakingConstantsRepository.kt | 19 ++- .../staking/impl/di/StakingUpdatersModule.kt | 43 ++++-- .../impl/domain/StakingInteractorExt.kt | 15 +- .../impl/domain/alerts/AlertsInteractor.kt | 30 ++-- .../staking/impl/domain/model/NetworkInfo.kt | 3 +- .../RecommendationSettingsProvider.kt | 8 +- .../settings/filters/Filters.kt | 4 +- .../domain/rewards/ReefRewardCalculator.kt | 2 +- .../domain/rewards/RewardCalculationTarget.kt | 2 +- .../domain/rewards/RewardCalculatorFactory.kt | 4 +- .../domain/validators/ValidatorProvider.kt | 92 ++++++++----- .../current/CurrentValidatorsInteractor.kt | 5 +- .../impl/presentation/mappers/Validator.kt | 8 +- .../StakingRelaychainScenarioViewModel.kt | 4 +- .../details/view/ValidatorInfoView.kt | 3 +- .../StakingRelayChainScenarioInteractor.kt | 94 +++++++++---- .../StakingRelayChainScenarioRepository.kt | 130 ++++++++++++++++-- .../network/updaters/BlockNumberUpdater.kt | 4 +- 39 files changed, 573 insertions(+), 219 deletions(-) delete mode 100644 feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/AccountValidatorPrefsUpdater.kt create mode 100644 feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/NominatorsUpdater.kt create mode 100644 feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorPrefsUpdater.kt diff --git a/core-api/src/main/java/jp/co/soramitsu/core/model/StorageEntry.kt b/core-api/src/main/java/jp/co/soramitsu/core/model/StorageEntry.kt index d841c2cf1a..50dcc08798 100644 --- a/core-api/src/main/java/jp/co/soramitsu/core/model/StorageEntry.kt +++ b/core-api/src/main/java/jp/co/soramitsu/core/model/StorageEntry.kt @@ -1,6 +1,6 @@ package jp.co.soramitsu.core.model -class StorageEntry( +data class StorageEntry( val storageKey: String, val content: String? ) diff --git a/core-api/src/main/java/jp/co/soramitsu/core/updater/Updater.kt b/core-api/src/main/java/jp/co/soramitsu/core/updater/Updater.kt index 6c7470b70f..ef2df017e1 100644 --- a/core-api/src/main/java/jp/co/soramitsu/core/updater/Updater.kt +++ b/core-api/src/main/java/jp/co/soramitsu/core/updater/Updater.kt @@ -18,7 +18,7 @@ interface UpdateScope { fun invalidationFlow(): Flow } -object GlobalScope : UpdateScope { +object GlobalUpdaterScope : UpdateScope { override fun invalidationFlow() = flowOf(Unit) } @@ -26,7 +26,7 @@ object GlobalScope : UpdateScope { interface GlobalScopeUpdater : Updater { override val scope - get() = GlobalScope + get() = GlobalUpdaterScope } interface Updater : SideEffectScope { diff --git a/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/data/StakingSharedState.kt b/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/data/StakingSharedState.kt index 00a38ff441..e83774ddfa 100644 --- a/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/data/StakingSharedState.kt +++ b/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/data/StakingSharedState.kt @@ -85,7 +85,9 @@ class StakingSharedState( val assetWithChain: Flow = selectionItem.map { val (chain, asset) = chainRegistry.chainWithAsset(it.chainId, it.chainAssetId) SingleAssetSharedState.AssetWithChain(chain, asset) - }.shareIn(scope, SharingStarted.Eagerly, replay = 1) + } + .distinctUntilChanged() + .shareIn(scope, SharingStarted.Eagerly, replay = 1) suspend fun assetWithChain(selectionItem: StakingAssetSelection) { val (chain, asset) = chainRegistry.chainWithAsset( @@ -112,7 +114,7 @@ class StakingSharedState( chainAsset = chainAsset, minSupportedVersion = chain.minSupportedVersion ) - }.shareIn(scope, SharingStarted.Eagerly, replay = 1) + }.distinctUntilChanged().shareIn(scope, SharingStarted.Eagerly, replay = 1) suspend fun availableAssetsToSelect(): List { val metaAccount = accountRepository.getSelectedMetaAccount() diff --git a/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Exposure.kt b/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Exposure.kt index 0b4a6769f9..36587c2dec 100644 --- a/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Exposure.kt +++ b/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Exposure.kt @@ -2,6 +2,19 @@ package jp.co.soramitsu.staking.api.domain.model import java.math.BigInteger -class IndividualExposure(val who: ByteArray, val value: BigInteger) +interface ValidatorExposure { + val nominatorCount: Int + val total: BigInteger + val own: BigInteger +} -class Exposure(val total: BigInteger, val own: BigInteger, val others: List) +class LegacyExposure( + override val total: BigInteger, override val own: BigInteger, val others: List +): ValidatorExposure{ + override val nominatorCount: Int = others.size +} + +class Exposure(override val total: BigInteger, override val own: BigInteger, override val nominatorCount: Int, val pageCount: BigInteger): ValidatorExposure +data class ExposurePage(val pageTotal: BigInteger, val others: List) + +class IndividualExposure(val who: ByteArray, val value: BigInteger) \ No newline at end of file diff --git a/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Validator.kt b/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Validator.kt index 0a3361b8f9..e8bdd1f017 100644 --- a/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Validator.kt +++ b/feature-staking-api/src/main/java/jp/co/soramitsu/staking/api/domain/model/Validator.kt @@ -27,7 +27,20 @@ class RootIdentity( override val pgpFingerprint: String?, override val image: String?, override val twitter: String? -) : Identity +) : Identity { + companion object { + fun empty() = RootIdentity( + display = null, + legal = null, + web = null, + riot = null, + email = null, + pgpFingerprint = null, + image = null, + twitter = null + ) + } +} class ChildIdentity( childName: String?, @@ -37,7 +50,7 @@ class ChildIdentity( override val display: String = "${parentIdentity.display} / ${childName.orEmpty()}" } -class SuperOf( +data class SuperOf( val parentIdHex: String, val childName: String? ) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Exposure.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Exposure.kt index 9cfefa345f..67811a999e 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Exposure.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Exposure.kt @@ -1,25 +1,24 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.bindings +import java.math.BigInteger import jp.co.soramitsu.common.data.network.runtime.binding.HelperBinding import jp.co.soramitsu.common.data.network.runtime.binding.UseCaseBinding import jp.co.soramitsu.common.data.network.runtime.binding.incompatible import jp.co.soramitsu.common.data.network.runtime.binding.requireType +import jp.co.soramitsu.common.utils.staking +import jp.co.soramitsu.core.runtime.storage.returnType import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot import jp.co.soramitsu.shared_utils.runtime.definitions.types.Type import jp.co.soramitsu.shared_utils.runtime.definitions.types.composite.Struct import jp.co.soramitsu.shared_utils.runtime.definitions.types.fromHexOrNull +import jp.co.soramitsu.shared_utils.runtime.metadata.storage import jp.co.soramitsu.staking.api.domain.model.Exposure +import jp.co.soramitsu.staking.api.domain.model.ExposurePage import jp.co.soramitsu.staking.api.domain.model.IndividualExposure -import java.math.BigInteger +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure -/* -IndividualExposure: { - who: AccountId; // account id of the nominator - value: Compact; // nominator’s stake -} - */ @HelperBinding -fun bindIndividualExposure(dynamicInstance: Any?, runtime: RuntimeSnapshot): IndividualExposure { +fun bindIndividualExposure(dynamicInstance: Any?): IndividualExposure { requireType(dynamicInstance) val who = dynamicInstance.get("who") ?: incompatible() @@ -28,21 +27,41 @@ fun bindIndividualExposure(dynamicInstance: Any?, runtime: RuntimeSnapshot): Ind return IndividualExposure(who, value) } -/* - Exposure: { - total: Compact; // total stake of the validator - own: Compact; // own stake of the validator - others: Vec; // nominators stakes -} - */ @UseCaseBinding -fun bindExposure(scale: String, runtime: RuntimeSnapshot, type: Type<*>): Exposure? { +fun bindLegacyExposure(scale: String, runtime: RuntimeSnapshot, type: Type<*>): LegacyExposure? { val decoded = type.fromHexOrNull(runtime, scale) as? Struct.Instance ?: return null val total = decoded.get("total") ?: return null val own = decoded.get("own") ?: return null - val others = decoded.get>("others")?.map { bindIndividualExposure(it, runtime) } ?: return null + val others = decoded.get>("others")?.map { bindIndividualExposure(it) } ?: return null - return Exposure(total, own, others) + return LegacyExposure(total, own, others) } + +@UseCaseBinding +fun bindExposure(scale: String, runtime: RuntimeSnapshot): Exposure? { + val storageType = runtime.metadata.staking().storage("ErasStakersOverview").returnType() + + val decoded = storageType.fromHexOrNull(runtime, scale) as? Struct.Instance ?: return null + + val total = decoded.get("total") ?: return null + val own = decoded.get("own") ?: return null + + val nominatorCount = decoded.get("nominatorCount") ?: return null + val pageCount = decoded.get("pageCount") ?: return null + + return Exposure(total, own, nominatorCount.toInt(), pageCount) +} + +@UseCaseBinding +fun bindExposurePage(scale: String, runtime: RuntimeSnapshot): ExposurePage? { + return runCatching { + val storageType = runtime.metadata.staking().storage("ErasStakersPaged").returnType() + val decoded = storageType.fromHexOrNull(runtime, scale) as? Struct.Instance ?: return null + val pageTotal = decoded.get("pageTotal") ?: return null + val others = + decoded.get>("others")?.map { bindIndividualExposure(it) } ?: return null + ExposurePage(pageTotal, others) + }.getOrNull() +} \ No newline at end of file diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Identity.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Identity.kt index f073ead8a5..52f007f5bb 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Identity.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Identity.kt @@ -40,9 +40,14 @@ fun bindIdentity( runtime: RuntimeSnapshot, type: Type<*> ): Identity { - val decoded = type.fromHexOrNull(runtime, scale) as? Struct.Instance ?: incompatible() + val decoded = type.fromHexOrNull(runtime, scale)// as? Struct.Instance ?: incompatible() + val struct = when (decoded) { + is Struct.Instance -> decoded.cast() + is ArrayList<*> -> decoded.cast>().first() as Struct.Instance + else -> return RootIdentity.empty() + } - val identityInfo = decoded.get("info") ?: incompatible() + val identityInfo = struct.get("info") ?: incompatible() val pgpFingerprint = identityInfo.get("pgpFingerprint") diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/StakingMinMaxStorages.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/StakingMinMaxStorages.kt index 278dfa4751..ba9b4584ff 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/StakingMinMaxStorages.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/StakingMinMaxStorages.kt @@ -99,10 +99,10 @@ fun bindDelegationScheduledRequests( } } -private fun bindNumber(scale: String, runtimeSnapshot: RuntimeSnapshot, type: Type<*>): BigInteger { +fun bindNumber(scale: String, runtimeSnapshot: RuntimeSnapshot, type: Type<*>): BigInteger { return bindNumber(type.fromHexOrNull(runtimeSnapshot, scale) ?: return scale.fromHex().fromUnsignedBytes()) } -private fun bindNumberOrNull(scale: String, runtimeSnapshot: RuntimeSnapshot, type: Type<*>): BigInteger? { +fun bindNumberOrNull(scale: String, runtimeSnapshot: RuntimeSnapshot, type: Type<*>): BigInteger? { return bindNumber(type.fromHexOrNull(runtimeSnapshot, scale) ?: return null) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/AccountValidatorPrefsUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/AccountValidatorPrefsUpdater.kt deleted file mode 100644 index 298247a938..0000000000 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/AccountValidatorPrefsUpdater.kt +++ /dev/null @@ -1,27 +0,0 @@ -package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters - -import jp.co.soramitsu.common.utils.staking -import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry -import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater -import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot -import jp.co.soramitsu.shared_utils.runtime.metadata.storage -import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey -import jp.co.soramitsu.staking.api.data.StakingSharedState -import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.base.StakingUpdater -import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.scope.AccountStakingScope - -class AccountValidatorPrefsUpdater( - scope: AccountStakingScope, - storageCache: StorageCache, - stakingSharedState: StakingSharedState, - chainRegistry: ChainRegistry -) : SingleStorageKeyUpdater(scope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { - - override suspend fun storageKey(runtime: RuntimeSnapshot): String? { - val stakingAccessInfo = scope.getAccountStaking()?.stakingAccessInfo ?: return null - val stashId = stakingAccessInfo.stashId - - return runtime.metadata.staking().storage("Validators").storageKey(runtime, stashId) - } -} diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ActiveEraUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ActiveEraUpdater.kt index 638853d4a3..d945d4014f 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ActiveEraUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ActiveEraUpdater.kt @@ -2,7 +2,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.staking import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -15,7 +15,7 @@ class ActiveEraUpdater( stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, storageCache: StorageCache -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { override suspend fun storageKey(runtime: RuntimeSnapshot): String { return runtime.metadata.staking().storage("ActiveEra").storageKey() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CounterForNominatorsUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CounterForNominatorsUpdater.kt index 3c4fd9802d..6d1b879100 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CounterForNominatorsUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CounterForNominatorsUpdater.kt @@ -2,7 +2,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.Modules import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -16,7 +16,7 @@ class CounterForNominatorsUpdater( stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, storageCache: StorageCache -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { override suspend fun storageKey(runtime: RuntimeSnapshot): String? { return runtime.metadata.moduleOrNull(Modules.STAKING)?.storageOrNull("CounterForNominators")?.storageKey() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CurrentEraUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CurrentEraUpdater.kt index 1770ed0d51..3b86f27de5 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CurrentEraUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/CurrentEraUpdater.kt @@ -2,7 +2,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.staking import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -15,7 +15,7 @@ class CurrentEraUpdater( stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, storageCache: StorageCache -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { override suspend fun storageKey(runtime: RuntimeSnapshot): String { return runtime.metadata.staking().storage("CurrentEra").storageKey() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/HistoryDepthUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/HistoryDepthUpdater.kt index 8fad71431c..a42b3fbec6 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/HistoryDepthUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/HistoryDepthUpdater.kt @@ -3,7 +3,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.defaultInHex import jp.co.soramitsu.common.utils.staking import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -16,7 +16,7 @@ class HistoryDepthUpdater( stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, storageCache: StorageCache -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { override fun fallbackValue(runtime: RuntimeSnapshot): String { return storageEntry(runtime).defaultInHex() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MaxNominatorsUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MaxNominatorsUpdater.kt index cc1db92159..f08b014f53 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MaxNominatorsUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MaxNominatorsUpdater.kt @@ -3,7 +3,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.defaultInHex import jp.co.soramitsu.common.utils.staking import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -16,7 +16,7 @@ class MaxNominatorsUpdater( storageCache: StorageCache, stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { override suspend fun storageKey(runtime: RuntimeSnapshot): String? { return runtime.metadata.staking().storageOrNull("MaxNominatorsCount")?.storageKey() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MinBondUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MinBondUpdater.kt index 8af279d662..8115365bc6 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MinBondUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/MinBondUpdater.kt @@ -2,7 +2,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.staking import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -15,7 +15,7 @@ class MinBondUpdater( stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, storageCache: StorageCache -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache), StakingUpdater { override suspend fun storageKey(runtime: RuntimeSnapshot): String? { return runtime.metadata.staking().storageOrNull("MinNominatorBond")?.storageKey() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/NominatorsUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/NominatorsUpdater.kt new file mode 100644 index 0000000000..c30332b2f4 --- /dev/null +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/NominatorsUpdater.kt @@ -0,0 +1,75 @@ +package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters + +import android.util.Log +import java.math.BigInteger +import jp.co.soramitsu.common.data.network.rpc.BulkRetriever +import jp.co.soramitsu.common.utils.staking +import jp.co.soramitsu.common.utils.stakingOrNull +import jp.co.soramitsu.core.model.StorageEntry +import jp.co.soramitsu.core.storage.StorageCache +import jp.co.soramitsu.core.updater.GlobalScopeUpdater +import jp.co.soramitsu.core.updater.SubscriptionBuilder +import jp.co.soramitsu.core.updater.Updater +import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry +import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.shared_utils.runtime.metadata.storage +import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey +import jp.co.soramitsu.shared_utils.runtime.metadata.storageOrNull +import jp.co.soramitsu.shared_utils.wsrpc.SocketService +import jp.co.soramitsu.staking.api.data.StakingSharedState +import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.base.StakingUpdater +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filterNot +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +class NominatorsUpdater( + private val bulkRetriever: BulkRetriever, + private val stakingSharedState: StakingSharedState, + private val chainRegistry: ChainRegistry, + private val storageCache: StorageCache +) : GlobalScopeUpdater, StakingUpdater { + + override suspend fun listenForUpdates(storageSubscriptionBuilder: SubscriptionBuilder): Flow { + val chainId = stakingSharedState.chainId() + val runtime = chainRegistry.getRuntime(chainId) + + if (runtime.metadata.stakingOrNull() + ?.storageOrNull("ErasStakersPaged") == null + ) return flowOf() + + return storageCache.observeActiveEraIndex(runtime, chainId) + .map { activeEraIndex -> + eraStakersPagedPrefix(runtime, activeEraIndex) + } + .filterNot { storageCache.isPrefixInCache(it, chainId) } + .map { + updateNominatorsForEra(it, storageSubscriptionBuilder.socketService, chainId) + } + .flowOn(Dispatchers.IO) + .noSideAffects() + } + + private fun eraStakersPagedPrefix( + runtime: RuntimeSnapshot, + activeEraIndex: BigInteger, + ): String { + return runtime.metadata.staking().storage("ErasStakersPaged") + .storageKey(runtime, activeEraIndex) + } + + + private suspend fun updateNominatorsForEra( + eraStakersPrefix: String, + socketService: SocketService, + chainId: String + ) = runCatching { + val allKeys = bulkRetriever.retrieveAllKeys(socketService, eraStakersPrefix) + val allValues = bulkRetriever.queryKeys(socketService, allKeys) + + val toInsert = allValues.map { (key, value) -> StorageEntry(key, value) } + storageCache.insert(toInsert, chainId) + } +} diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/TotalIssuanceUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/TotalIssuanceUpdater.kt index 19ca5ecf5c..44afc71c56 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/TotalIssuanceUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/TotalIssuanceUpdater.kt @@ -3,7 +3,7 @@ package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters import jp.co.soramitsu.common.utils.Modules import jp.co.soramitsu.common.utils.balances import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.network.updaters.SingleStorageKeyUpdater import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot @@ -15,7 +15,7 @@ class TotalIssuanceUpdater( stakingSharedState: StakingSharedState, storageCache: StorageCache, chainRegistry: ChainRegistry -) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache) { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, stakingSharedState, chainRegistry, storageCache) { override val requiredModules: List = listOf(Modules.BALANCES) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorExposureUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorExposureUpdater.kt index afd5515743..fd85ca0ef2 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorExposureUpdater.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorExposureUpdater.kt @@ -7,7 +7,6 @@ import jp.co.soramitsu.core.updater.GlobalScopeUpdater import jp.co.soramitsu.core.updater.SubscriptionBuilder import jp.co.soramitsu.core.updater.Updater import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry -import jp.co.soramitsu.runtime.multiNetwork.getRuntime import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot import jp.co.soramitsu.shared_utils.runtime.metadata.storage import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey @@ -21,6 +20,9 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import java.math.BigInteger +import jp.co.soramitsu.common.utils.stakingOrNull +import jp.co.soramitsu.core.model.StorageEntry +import jp.co.soramitsu.shared_utils.runtime.metadata.storageOrNull class ValidatorExposureUpdater( private val bulkRetriever: BulkRetriever, @@ -36,20 +38,28 @@ class ValidatorExposureUpdater( return storageCache.observeActiveEraIndex(runtime, chainId) .map { eraStakersPrefix(runtime, it) } .filterNot { storageCache.isPrefixInCache(it, chainId) } - .onEach { updateNominatorsForEra(it, storageSubscriptionBuilder.socketService, chainId) } + .onEach { updateValidatorsForEra(it, storageSubscriptionBuilder.socketService, chainId) } .flowOn(Dispatchers.IO) .noSideAffects() } private fun eraStakersPrefix(runtime: RuntimeSnapshot, activeEraIndex: BigInteger): String { - return runtime.metadata.staking().storage("ErasStakers").storageKey(runtime, activeEraIndex) + return if (runtime.metadata.stakingOrNull()?.storageOrNull("ErasStakersPaged") == null) { + runtime.metadata.staking().storage("ErasStakers").storageKey(runtime, activeEraIndex) + } else { + runtime.metadata.staking().storage("ErasStakersOverview").storageKey(runtime, activeEraIndex) + } } - private suspend fun updateNominatorsForEra( + private suspend fun updateValidatorsForEra( eraStakersPrefix: String, socketService: SocketService, chainId: String ) = runCatching { - bulkRetriever.fetchPrefixValuesToCache(socketService, eraStakersPrefix, storageCache, chainId) + val allKeys = bulkRetriever.retrieveAllKeys(socketService, eraStakersPrefix) + val allValues = bulkRetriever.queryKeys(socketService, allKeys) + + val toInsert = allValues.map { (key, value) -> StorageEntry(key, value) } + storageCache.insert(toInsert, chainId) } } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorPrefsUpdater.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorPrefsUpdater.kt new file mode 100644 index 0000000000..2cd4dcdd9d --- /dev/null +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/updaters/ValidatorPrefsUpdater.kt @@ -0,0 +1,50 @@ +package jp.co.soramitsu.staking.impl.data.network.blockhain.updaters + +import jp.co.soramitsu.common.data.network.rpc.BulkRetriever +import jp.co.soramitsu.common.utils.staking +import jp.co.soramitsu.core.model.StorageEntry +import jp.co.soramitsu.core.storage.StorageCache +import jp.co.soramitsu.core.updater.GlobalScopeUpdater +import jp.co.soramitsu.core.updater.SubscriptionBuilder +import jp.co.soramitsu.core.updater.Updater +import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry +import jp.co.soramitsu.shared_utils.runtime.metadata.storage +import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey +import jp.co.soramitsu.staking.api.data.StakingSharedState +import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.base.StakingUpdater +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn + +class ValidatorPrefsUpdater( + private val bulkRetriever: BulkRetriever, + private val stakingSharedState: StakingSharedState, + private val chainRegistry: ChainRegistry, + private val storageCache: StorageCache +) : GlobalScopeUpdater, StakingUpdater { + + override suspend fun listenForUpdates(storageSubscriptionBuilder: SubscriptionBuilder): Flow { + return flow { + val chainId = stakingSharedState.chainId() + val runtime = chainRegistry.getRuntime(chainId) + val prefix = runtime.metadata.staking().storage("Validators").storageKey(runtime) + if (storageCache.isPrefixInCache(prefix, chainId)) { + return@flow + } + + val allKeys = + bulkRetriever.retrieveAllKeys(storageSubscriptionBuilder.socketService, prefix) + + val allValues = + bulkRetriever.queryKeys(storageSubscriptionBuilder.socketService, allKeys) + + val toInsert = allValues.map { (key, value) -> StorageEntry(key, value) } + + storageCache.insert(toInsert, chainId) + + emit(Unit) + }.flowOn(Dispatchers.IO) + .noSideAffects() + } +} diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/IdentityRepositoryImpl.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/IdentityRepositoryImpl.kt index 0da7709685..77d05df8f8 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/IdentityRepositoryImpl.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/IdentityRepositoryImpl.kt @@ -7,7 +7,6 @@ import jp.co.soramitsu.runtime.ext.accountFromMapKey import jp.co.soramitsu.runtime.ext.hexAccountIdOf import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain -import jp.co.soramitsu.runtime.multiNetwork.getRuntime import jp.co.soramitsu.runtime.multiNetwork.getSocket import jp.co.soramitsu.shared_utils.extensions.toHexString import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/PayoutRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/PayoutRepository.kt index f7e5611a70..411231e421 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/PayoutRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/PayoutRepository.kt @@ -21,7 +21,7 @@ import jp.co.soramitsu.shared_utils.runtime.metadata.storage import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey import jp.co.soramitsu.shared_utils.ss58.SS58Encoder.toAccountId import jp.co.soramitsu.shared_utils.wsrpc.SocketService -import jp.co.soramitsu.staking.api.domain.model.Exposure +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.staking.api.domain.model.StakingLedger import jp.co.soramitsu.staking.api.domain.model.StakingState import jp.co.soramitsu.staking.api.domain.model.ValidatorPrefs @@ -29,6 +29,7 @@ import jp.co.soramitsu.staking.impl.data.model.Payout import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.EraRewardPoints import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindEraRewardPoints import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindExposure +import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindLegacyExposure import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindStakingLedger import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindTotalValidatorEraReward import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindValidatorPrefs @@ -46,7 +47,7 @@ class ValidatorHistoricalStats( class ValidatorEraStats( val prefs: ValidatorPrefs, - val exposure: Exposure + val exposure: LegacyExposure ) } @@ -254,7 +255,7 @@ class PayoutRepository( val prefsKey = prefsKeyMapping[validatorAddress]!![era]!! val exposure = allResults[exposureKey]?.let { - bindExposure( + bindLegacyExposure( it, runtime, exposureClippedStorage.returnType() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/StakingConstantsRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/StakingConstantsRepository.kt index 0586c6a7a9..9986a24c04 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/StakingConstantsRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/StakingConstantsRepository.kt @@ -1,27 +1,36 @@ package jp.co.soramitsu.staking.impl.data.repository import java.math.BigInteger +import jp.co.soramitsu.common.utils.constantOrNull import jp.co.soramitsu.common.utils.numberConstant import jp.co.soramitsu.common.utils.parachainStaking import jp.co.soramitsu.common.utils.staking +import jp.co.soramitsu.common.utils.stakingOrNull import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.multiNetwork.chain.model.ChainId import jp.co.soramitsu.runtime.multiNetwork.chain.model.kusamaChainId import jp.co.soramitsu.runtime.multiNetwork.chain.model.polkadotChainId import jp.co.soramitsu.runtime.multiNetwork.chain.model.westendChainId -import jp.co.soramitsu.runtime.multiNetwork.getRuntime class StakingConstantsRepository( private val chainRegistry: ChainRegistry ) { - suspend fun maxRewardedNominatorPerValidator(chainId: ChainId): Int { + // returns null if there are infinity nominators per validator + suspend fun maxRewardedNominatorPerValidator(chainId: ChainId): Int? { return try { - getNumberConstant(chainId, "MaxNominatorRewardedPerValidator").toInt() + val runtime = chainRegistry.getRuntime(chainId) + + if(runtime.metadata.stakingOrNull()?.constantOrNull("MaxNominatorRewardedPerValidator") != null){ + return getNumberConstant(chainId, "MaxNominatorRewardedPerValidator").toInt() + } else { + // todo need research + //getNumberConstant(chainId, "MaxExposurePageSize").toInt() + return null + } } catch (e: NoSuchElementException) { when (chainId) { - westendChainId -> 64 - polkadotChainId, kusamaChainId -> 512 + westendChainId, polkadotChainId, kusamaChainId -> null else -> throw e } } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingUpdatersModule.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingUpdatersModule.kt index ac23974c48..18a8143e1e 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingUpdatersModule.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingUpdatersModule.kt @@ -19,7 +19,7 @@ import jp.co.soramitsu.runtime.network.updaters.SingleChainUpdateSystem import jp.co.soramitsu.staking.api.data.StakingSharedState import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.AccountNominationsUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.AccountRewardDestinationUpdater -import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.AccountValidatorPrefsUpdater +import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.ValidatorPrefsUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.ActiveEraUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.CounterForNominatorsUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.CurrentEraUpdater @@ -27,6 +27,7 @@ import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.DelegatorSta import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.HistoryDepthUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.MaxNominatorsUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.MinBondUpdater +import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.NominatorsUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.StakingLedgerUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.TotalIssuanceUpdater import jp.co.soramitsu.staking.impl.data.network.blockhain.updaters.ValidatorExposureUpdater @@ -78,7 +79,7 @@ class StakingUpdatersModule { @Provides @Singleton - fun provideElectedNominatorsUpdater( + fun provideElectedValidatorsUpdater( sharedState: StakingSharedState, chainRegistry: ChainRegistry, bulkRetriever: BulkRetriever, @@ -90,6 +91,20 @@ class StakingUpdatersModule { storageCache ) + @Provides + @Singleton + fun provideElectedNominatorsUpdater( + sharedState: StakingSharedState, + chainRegistry: ChainRegistry, + bulkRetriever: BulkRetriever, + storageCache: StorageCache + ): NominatorsUpdater = NominatorsUpdater( + bulkRetriever, + sharedState, + chainRegistry, + storageCache + ) + @Provides @Singleton fun provideTotalInsuranceUpdater( @@ -141,15 +156,15 @@ class StakingUpdatersModule { @Provides @Singleton fun provideAccountValidatorPrefsUpdater( - storageCache: StorageCache, - scope: AccountStakingScope, - sharedState: StakingSharedState, - chainRegistry: ChainRegistry - ) = AccountValidatorPrefsUpdater( - scope, - storageCache, - sharedState, - chainRegistry + bulkRetriever: BulkRetriever, + stakingSharedState: StakingSharedState, + chainRegistry: ChainRegistry, + storageCache: StorageCache + ) = ValidatorPrefsUpdater( + bulkRetriever, + stakingSharedState, + chainRegistry, + storageCache ) @Provides @@ -287,7 +302,7 @@ class StakingUpdatersModule { totalIssuanceUpdater: TotalIssuanceUpdater, currentEraUpdater: CurrentEraUpdater, stakingLedgerUpdater: StakingLedgerUpdater, - accountValidatorPrefsUpdater: AccountValidatorPrefsUpdater, + validatorPrefsUpdater: ValidatorPrefsUpdater, accountNominationsUpdater: AccountNominationsUpdater, rewardDestinationUpdater: AccountRewardDestinationUpdater, historyDepthUpdater: HistoryDepthUpdater, @@ -297,6 +312,7 @@ class StakingUpdatersModule { maxNominatorsUpdater: MaxNominatorsUpdater, counterForNominatorsUpdater: CounterForNominatorsUpdater, delegatorStateUpdater: DelegatorStateUpdater, + nominatorsUpdater: NominatorsUpdater, @Named("StakingBlockNumberUpdater") blockNumberUpdater: BlockNumberUpdater, chainRegistry: ChainRegistry, @@ -305,10 +321,11 @@ class StakingUpdatersModule { updaters = listOf( activeEraUpdater, validatorExposureUpdater, + nominatorsUpdater, totalIssuanceUpdater, currentEraUpdater, stakingLedgerUpdater, - accountValidatorPrefsUpdater, + validatorPrefsUpdater, accountNominationsUpdater, rewardDestinationUpdater, // historyDepthUpdater, diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExt.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExt.kt index 07ebba5cda..bb1d88b2c5 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExt.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExt.kt @@ -2,17 +2,17 @@ package jp.co.soramitsu.staking.impl.domain import jp.co.soramitsu.shared_utils.extensions.toHexString import jp.co.soramitsu.shared_utils.runtime.AccountId -import jp.co.soramitsu.staking.api.domain.model.Exposure import jp.co.soramitsu.staking.api.domain.model.IndividualExposure import kotlinx.coroutines.flow.first import java.math.BigInteger +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure suspend fun StakingInteractor.getSelectedChain() = selectedChainFlow().first() fun isNominationActive( stashId: AccountId, - exposures: Collection, - rewardedNominatorsPerValidator: Int + exposures: Collection, + rewardedNominatorsPerValidator: Int? ): Boolean { val comparator = { accountId: IndividualExposure -> accountId.who.contentEquals(stashId) @@ -25,10 +25,11 @@ fun isNominationActive( return validatorsWithOurStake.any { it.willAccountBeRewarded(stashId, rewardedNominatorsPerValidator) } } -fun Exposure.willAccountBeRewarded( +fun LegacyExposure.willAccountBeRewarded( accountId: AccountId, - rewardedNominatorsPerValidator: Int + rewardedNominatorsPerValidator: Int? ): Boolean { + if(rewardedNominatorsPerValidator == null) return true val indexInRewardedList = others.sortedByDescending(IndividualExposure::value).indexOfFirst { it.who.contentEquals(accountId) } @@ -43,11 +44,11 @@ fun Exposure.willAccountBeRewarded( } fun minimumStake( - exposures: Collection, + exposures: Collection, minimumNominatorBond: BigInteger ): BigInteger { val stakeByNominator = exposures - .map(Exposure::others) + .map(LegacyExposure::others) .flatten() .fold(mutableMapOf()) { acc, individualExposure -> val currentExposure = acc.getOrDefault(individualExposure.who.toHexString(), BigInteger.ZERO) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt index db7bde09f9..6e4489700e 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt @@ -4,7 +4,6 @@ import jp.co.soramitsu.account.api.domain.interfaces.AccountRepository import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.shared_utils.runtime.AccountId import jp.co.soramitsu.staking.api.data.StakingSharedState -import jp.co.soramitsu.staking.api.domain.model.Exposure import jp.co.soramitsu.staking.api.domain.model.StakingState import jp.co.soramitsu.staking.impl.data.repository.StakingConstantsRepository import jp.co.soramitsu.staking.impl.domain.common.isWaiting @@ -21,6 +20,7 @@ import kotlinx.coroutines.flow.flowOf import java.math.BigDecimal import java.math.BigInteger import jp.co.soramitsu.shared_utils.extensions.toHexString +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.core.models.Asset as CoreAsset private const val NOMINATIONS_ACTIVE_MEMO = "NOMINATIONS_ACTIVE_MEMO" @@ -34,13 +34,13 @@ class AlertsInteractor( ) { class AlertContext( - val exposures: Map, + val exposures: Map?, val stakingState: StakingState, - val maxRewardedNominatorsPerValidator: Int, + val maxRewardedNominatorsPerValidator: Int?, val minimumNominatorBond: BigInteger, val activeEra: BigInteger, val asset: Asset, - val maxNominators: Int + val maxNominators: Int? ) { val memo = mutableMapOf() @@ -54,6 +54,9 @@ class AlertsInteractor( } private fun AlertContext.isStakingActive(stashId: AccountId) = useMemo(NOMINATIONS_ACTIVE_MEMO) { + if(exposures == null) { + return true + } isNominationActive(stashId, exposures.values, maxRewardedNominatorsPerValidator) } @@ -65,7 +68,12 @@ class AlertsInteractor( private fun produceChangeValidatorsAlert(context: AlertContext): Alert? { return requireState(context.stakingState) { nominatorState: StakingState.Stash.Nominator -> - val allValidatorsAreOversubscribed = nominatorState.nominations.targets.mapNotNull { context.exposures[it.toHexString()] }.all { it.others.size > context.maxNominators } + val allValidatorsAreOversubscribed = if (context.exposures == null || context.maxNominators == null) { + false + } else { + nominatorState.nominations.targets.mapNotNull { context.exposures[it.toHexString()] } + .all { it.others.size > context.maxNominators } + } val stakingIsNotActive = context.isStakingActive(nominatorState.stashId).not() if (stakingIsNotActive.not()) return null @@ -86,9 +94,9 @@ class AlertsInteractor( } } - private fun produceMinStakeAlert(context: AlertContext) = requireState(context.stakingState) { state: StakingState.Stash -> + private suspend fun produceMinStakeAlert(context: AlertContext) = requireState(context.stakingState) { state: StakingState.Stash -> with(context) { - val minimalStakeInPlanks = minimumStake(exposures.values, minimumNominatorBond) + val minimalStakeInPlanks = (if(exposures != null) minimumStake(exposures.values, minimumNominatorBond) else stakingRepository.minimumActiveStake(stakingState.chain.id)).orZero() if ( // do not show alert for validators @@ -118,11 +126,12 @@ class AlertsInteractor( private val alertProducers = listOf( ::produceChangeValidatorsAlert, ::produceRedeemableAlert, - ::produceMinStakeAlert, ::produceWaitingNextEraAlert, ::produceSetValidatorsAlert ) + private val suspendableAlertProducers = listOf(::produceMinStakeAlert) + fun getAlertsFlow(stakingState: StakingState): Flow> = sharedState.assetWithChain.flatMapLatest { (chain, chainAsset) -> if (chainAsset.staking != CoreAsset.StakingType.RELAYCHAIN) { return@flatMapLatest flowOf(emptyList()) @@ -135,7 +144,7 @@ class AlertsInteractor( val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(chain.id) val alertsFlow = combine( - stakingRepository.electedExposuresInActiveEra(chain.id), + stakingRepository.legacyElectedExposuresInActiveEra(chain.id), walletRepository.assetFlow(meta.id, stakingState.accountId, chainAsset, chain.minSupportedVersion), stakingRepository.observeActiveEraIndex(chain.id) ) { exposures, asset, activeEra -> @@ -149,8 +158,7 @@ class AlertsInteractor( activeEra = activeEra, maxNominators = maxNominators ) - - alertProducers.mapNotNull { it.invoke(context) } + alertProducers.mapNotNull { it.invoke(context) } + suspendableAlertProducers.mapNotNull { it.invoke(context) } } alertsFlow diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/model/NetworkInfo.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/model/NetworkInfo.kt index 393f584c96..c7b6daa6e1 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/model/NetworkInfo.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/model/NetworkInfo.kt @@ -10,7 +10,8 @@ sealed class NetworkInfo( override val lockupPeriodInHours: Int, override val minimumStake: BigInteger, val totalStake: BigInteger, - val nominatorsCount: Int + val nominatorsCount: Int, + val shouldUseMinimumStakeMultiplier: Boolean ) : NetworkInfo(lockupPeriodInHours, minimumStake) data class Parachain( diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt index bed86f24bf..88cbf1ab4f 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt @@ -46,12 +46,12 @@ abstract class RecommendationSettingsProvider { abstract fun settingsChanged(schema: SettingsSchema, amount: BigInteger) class RelayChain( - private val maximumRewardedNominators: Int, + private val maximumRewardedNominators: Int?, private val maximumValidatorsPerNominator: Int ) : RecommendationSettingsProvider() { override val alwaysEnabledFilters = listOf( - BlockProducerFilters.ValidatorFilter.HasBlocked +// BlockProducerFilters.ValidatorFilter.HasBlocked ) override val customizableFilters: List> = listOf( @@ -70,7 +70,7 @@ abstract class RecommendationSettingsProvider { override fun defaultSettings(): RecommendationSettings { return RecommendationSettings( - alwaysEnabledFilters = alwaysEnabledFilters, + alwaysEnabledFilters = listOf(BlockProducerFilters.ValidatorFilter.HasBlocked), customEnabledFilters = listOf(BlockProducerFilters.ValidatorFilter.HundredPercentCommissionFilter, BlockProducerFilters.ValidatorFilter.NotOverSubscribedFilter(maximumRewardedNominators), BlockProducerFilters.ValidatorFilter.ElectedFilter), sorting = BlockProducersSorting.ValidatorSorting.APYSorting, postProcessors = allPostProcessors, @@ -79,7 +79,7 @@ abstract class RecommendationSettingsProvider { } override fun defaultSelectCustomSettings() = RecommendationSettings( - alwaysEnabledFilters = alwaysEnabledFilters, + alwaysEnabledFilters = emptyList(), customEnabledFilters = emptyList(), sorting = BlockProducersSorting.ValidatorSorting.APYSorting, postProcessors = allPostProcessors, diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/filters/Filters.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/filters/Filters.kt index 6b7bcc6c41..3ca5c6fd20 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/filters/Filters.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/filters/Filters.kt @@ -24,14 +24,14 @@ abstract class BlockProducerFilters { } class NotOverSubscribedFilter( - private val maxSubscribers: Int + private val maxSubscribers: Int? ) : ValidatorFilter() { override fun shouldInclude(model: Validator): Boolean { val electedInfo = model.electedInfo return if (electedInfo != null) { - electedInfo.nominatorStakes.size < maxSubscribers + maxSubscribers == null || electedInfo.nominatorStakes.size < maxSubscribers } else { throw IllegalStateException("Filtering validator ${model.accountIdHex} with no prefs") } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/ReefRewardCalculator.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/ReefRewardCalculator.kt index c54501e73f..87f76fbf15 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/ReefRewardCalculator.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/ReefRewardCalculator.kt @@ -69,7 +69,7 @@ class ReefRewardCalculator( val rewardForAmountInCurrentEra = userPortion * validatorReward - (validator.commission.toDouble() * userPortion * validatorReward) - hashCode() + (rewardForAmountInCurrentEra / amount.toDouble()) * DAYS_IN_YEAR }.getOrNull() ?: 0.0 } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculationTarget.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculationTarget.kt index 4e1cf43b7e..587cbc9cab 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculationTarget.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculationTarget.kt @@ -1,8 +1,8 @@ package jp.co.soramitsu.staking.impl.domain.rewards -import jp.co.soramitsu.staking.api.domain.model.IndividualExposure import java.math.BigDecimal import java.math.BigInteger +import jp.co.soramitsu.staking.api.domain.model.IndividualExposure class RewardCalculationTarget( val accountIdHex: String, diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt index 864de464f8..6c888b523e 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt @@ -10,11 +10,11 @@ import jp.co.soramitsu.shared_utils.runtime.AccountId import jp.co.soramitsu.staking.api.data.SyntheticStakingType import jp.co.soramitsu.staking.api.data.syntheticStakingType import jp.co.soramitsu.staking.api.domain.api.StakingRepository +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.staking.impl.data.network.subquery.StakingApi import jp.co.soramitsu.staking.impl.domain.error.accountIdNotFound import jp.co.soramitsu.staking.impl.scenarios.parachain.StakingParachainScenarioInteractor import jp.co.soramitsu.staking.impl.scenarios.relaychain.StakingRelayChainScenarioRepository -import jp.co.soramitsu.staking.impl.scenarios.relaychain.getActiveElectedValidatorsExposures import jp.co.soramitsu.wallet.impl.domain.model.amountFromPlanks import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -178,7 +178,7 @@ class RewardCalculatorFactory( validators: List? = null ): List { val chainId = asset.chainId - val electedExposures = relayChainRepository.getActiveElectedValidatorsExposures(chainId) + val electedExposures = relayChainRepository.getLegacyActiveElectedValidatorsExposures(chainId) val exposures = validators?.let { electedExposures.filter { validators.contains(it.key) } } ?: electedExposures diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt index d25c556ea7..ad69b91717 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt @@ -11,13 +11,14 @@ import jp.co.soramitsu.runtime.multiNetwork.chain.model.ternoaChainId import jp.co.soramitsu.shared_utils.extensions.fromHex import jp.co.soramitsu.staking.api.domain.api.AccountIdMap import jp.co.soramitsu.staking.api.domain.api.IdentityRepository -import jp.co.soramitsu.staking.api.domain.model.Exposure +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.staking.api.domain.model.Validator import jp.co.soramitsu.staking.impl.data.repository.StakingConstantsRepository import jp.co.soramitsu.staking.impl.domain.rewards.RewardCalculationTarget import jp.co.soramitsu.staking.impl.domain.rewards.RewardCalculatorFactory import jp.co.soramitsu.staking.impl.scenarios.relaychain.StakingRelayChainScenarioRepository -import jp.co.soramitsu.staking.impl.scenarios.relaychain.getActiveElectedValidatorsExposures +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope sealed class ValidatorSource { @@ -36,57 +37,72 @@ class ValidatorProvider( suspend fun getValidators( chain: Chain, source: ValidatorSource, - cachedExposures: AccountIdMap? = null - ): List { + cachedExposures: AccountIdMap? = null + ): List = coroutineScope { val chainId = chain.id - val electedValidatorExposures = cachedExposures ?: stakingRepository.getActiveElectedValidatorsExposures(chainId) - val allValidatorPrefs = stakingRepository.getAllValidatorPrefs(chainId) + val electedValidatorExposuresDeferred = async { cachedExposures ?: stakingRepository.getLegacyActiveElectedValidatorsExposures(chainId) } + val allValidatorPrefsDeferred = async { stakingRepository.getAllValidatorPrefs(chainId) } + val maxNominatorsDeferred = async { + stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId) + } + + val allValidatorPrefs = allValidatorPrefsDeferred.await() val requestedValidatorIds = when (source) { ValidatorSource.Elected -> allValidatorPrefs.keys.toList() is ValidatorSource.Custom -> source.validatorIds } - val identities = identityRepository.getIdentitiesFromIds(chain, requestedValidatorIds) - val slashes = stakingRepository.getSlashes(chainId, requestedValidatorIds) - - val calculationTargets = electedValidatorExposures.keys.mapNotNull { accountIdHex -> - val exposure = electedValidatorExposures[accountIdHex] ?: return@mapNotNull null - val prefs = allValidatorPrefs[accountIdHex] ?: return@mapNotNull null + val identitiesDeferred = async { identityRepository.getIdentitiesFromIds(chain, requestedValidatorIds) } + val slashesDeferred = async { stakingRepository.getSlashes(chainId, requestedValidatorIds) } - RewardCalculationTarget( - accountIdHex = accountIdHex, - totalStake = exposure.total, - nominatorStakes = exposure.others, - ownStake = exposure.own, - commission = prefs.commission - ) - } + val electedValidatorExposures = electedValidatorExposuresDeferred.await() - val rewardCalculator = when (chainId) { - soraMainChainId -> { - val utilityAsset = chain.utilityAsset ?: error("Utility asset not specified for chain ${chain.name} - ${chain.id}") - rewardCalculatorFactory.createSora(utilityAsset, calculationTargets) - } - reefChainId -> { - val utilityAsset = chain.utilityAsset ?: error("Utility asset not specified for chain ${chain.name} - ${chain.id}") - rewardCalculatorFactory.createReef(utilityAsset, calculationTargets) - } + val rewardCalculatorDeferred = async { + val calculationTargets = electedValidatorExposures.keys.mapNotNull { accountIdHex -> + val exposure = electedValidatorExposures[accountIdHex] ?: return@mapNotNull null + val prefs = allValidatorPrefs[accountIdHex] ?: return@mapNotNull null - ternoaChainId -> { - val utilityAsset = chain.utilityAsset ?: error("Utility asset not specified for chain ${chain.name} - ${chain.id}") - rewardCalculatorFactory.createTernoa(utilityAsset, calculationTargets) + RewardCalculationTarget( + accountIdHex = accountIdHex, + totalStake = exposure.total, + nominatorStakes = exposure.others, + ownStake = exposure.own, + commission = prefs.commission + ) } - - else -> { - rewardCalculatorFactory.createManual(chainId, calculationTargets) + when (chainId) { + soraMainChainId -> { + val utilityAsset = chain.utilityAsset + ?: error("Utility asset not specified for chain ${chain.name} - ${chain.id}") + rewardCalculatorFactory.createSora(utilityAsset, calculationTargets) + } + + reefChainId -> { + val utilityAsset = chain.utilityAsset + ?: error("Utility asset not specified for chain ${chain.name} - ${chain.id}") + rewardCalculatorFactory.createReef(utilityAsset, calculationTargets) + } + + ternoaChainId -> { + val utilityAsset = chain.utilityAsset + ?: error("Utility asset not specified for chain ${chain.name} - ${chain.id}") + rewardCalculatorFactory.createTernoa(utilityAsset, calculationTargets) + } + + else -> { + rewardCalculatorFactory.createManual(chainId, calculationTargets) + } } } - val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId) + val identities = identitiesDeferred.await() + val slashes = slashesDeferred.await() + val maxNominators = maxNominatorsDeferred.await() + val rewardCalculator = rewardCalculatorDeferred.await() - return requestedValidatorIds.map { accountIdHex -> + requestedValidatorIds.map { accountIdHex -> val prefs = allValidatorPrefs[accountIdHex] val electedInfo = electedValidatorExposures[accountIdHex]?.let { @@ -96,7 +112,7 @@ class ValidatorProvider( nominatorStakes = it.others, apy = runCatching { rewardCalculator.getApyFor(accountIdHex.fromHex()) } .getOrNull().orZero(), - isOversubscribed = it.others.size > maxNominators + isOversubscribed = maxNominators?.let { value -> it.others.size > value} ?: false ) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt index edcfb6da40..89f6e9e834 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt @@ -15,7 +15,6 @@ import jp.co.soramitsu.staking.impl.domain.common.isWaiting import jp.co.soramitsu.staking.impl.domain.validators.ValidatorProvider import jp.co.soramitsu.staking.impl.domain.validators.ValidatorSource import jp.co.soramitsu.staking.impl.scenarios.relaychain.StakingRelayChainScenarioRepository -import jp.co.soramitsu.staking.impl.scenarios.relaychain.getActiveElectedValidatorsExposures import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map @@ -45,7 +44,7 @@ class CurrentValidatorsInteractor( return stakingRepository.observeActiveEraIndex(chainId).map { activeEra -> - val exposures = stakingRepository.getActiveElectedValidatorsExposures(chainId) + val exposures = stakingRepository.getLegacyActiveElectedValidatorsExposures(chainId) val activeNominations = exposures.mapValues { (_, exposure) -> exposure.others.firstOrNull { it.who.contentEquals(stashId) } @@ -74,7 +73,7 @@ class CurrentValidatorsInteractor( val userNominationRank = userNominationIndex + 1 - val willBeRewarded = userNominationRank < maxRewardedNominators + val willBeRewarded = maxRewardedNominators == null || userNominationRank < maxRewardedNominators Status.Active(nomination = userIndividualExposure.value, willUserBeRewarded = willBeRewarded) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/mappers/Validator.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/mappers/Validator.kt index 53f4a40675..c55267a2da 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/mappers/Validator.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/mappers/Validator.kt @@ -123,12 +123,16 @@ private fun mapValidatorToValidatorDetailsParcelModel( fun mapValidatorDetailsToErrors( validator: ValidatorDetailsParcelModel ): List? { + val errors = mutableListOf() + if (validator.prefs?.isBlocked == true) { + errors.add(Error.Blocked) + } return when (val stake = validator.stake) { ValidatorStakeParcelModel.Inactive -> null is ValidatorStakeParcelModel.Active -> { val nominatorInfo = stake.nominatorInfo - return mutableListOf().apply { + return errors.apply { if (stake.isOversubscribed) { if (nominatorInfo?.willBeRewarded == true) { add(Error.OversubscribedPaid) @@ -146,7 +150,7 @@ suspend fun mapValidatorDetailsParcelToValidatorDetailsModel( chain: Chain, validator: ValidatorDetailsParcelModel, asset: Asset, - maxNominators: Int, + maxNominators: Int?, iconGenerator: AddressIconGenerator, resourceManager: ResourceManager ): ValidatorDetailsModel { diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt index bdd8375b2e..fcac1e8a60 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt @@ -10,6 +10,7 @@ import jp.co.soramitsu.common.utils.mapList import jp.co.soramitsu.common.utils.withLoading import jp.co.soramitsu.common.validation.CompositeValidation import jp.co.soramitsu.common.validation.ValidationSystem +import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.feature_staking_impl.R import jp.co.soramitsu.runtime.multiNetwork.chain.model.polkadotChainId import jp.co.soramitsu.shared_utils.extensions.toHexString @@ -160,7 +161,8 @@ class StakingRelaychainScenarioViewModel( scenarioInteractor.observeNetworkInfoState().map { it as NetworkInfo.RelayChain }, stakingInteractor.currentAssetFlow() ) { networkInfo, asset -> - val minStakeMultiplier: Double = if (asset.token.configuration.chainId == polkadotChainId) { + + val minStakeMultiplier: Double = if (networkInfo.shouldUseMinimumStakeMultiplier) { 1.15 // 15% increase } else { 1.0 diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/details/view/ValidatorInfoView.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/details/view/ValidatorInfoView.kt index bd060e618c..76445977c9 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/details/view/ValidatorInfoView.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/details/view/ValidatorInfoView.kt @@ -15,6 +15,7 @@ sealed class Error(@StringRes val errorDescription: Int, @DrawableRes val errorI object OversubscribedUnpaid : Error(R.string.staking_validator_my_oversubscribed_message, R.drawable.ic_warning_filled) object OversubscribedPaid : Error(R.string.staking_validator_other_oversubscribed_message, R.drawable.ic_warning_filled) object Slashed : Error(R.string.staking_validator_slashed_desc, R.drawable.ic_status_error_16) + object Blocked : Error(R.string.staking_custom_blocked_warning, R.drawable.ic_status_error_16) } class ValidatorInfoView @JvmOverloads constructor( @@ -35,7 +36,6 @@ class ValidatorInfoView @JvmOverloads constructor( private val totalStakeFields = listOf( binding.validatorTotalStakeView, binding.validatorNominatorsView, - binding.validatorNominatorsView, binding.validatorEstimatedReward ) @@ -90,6 +90,7 @@ class ValidatorInfoView @JvmOverloads constructor( is Error.OversubscribedUnpaid -> binding.validatorStatusView.setDescription(context.getString(err.errorDescription), err.errorIcon) is Error.OversubscribedPaid -> binding.validatorStatusView.setDescription(context.getString(err.errorDescription), err.errorIcon) is Error.Slashed -> binding.validatorNominatorsView.setDescription(context.getString(err.errorDescription), err.errorIcon) + is Error.Blocked -> binding.validatorStatusView.setDescription(context.getString(err.errorDescription), err.errorIcon) } } } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt index 7d6b713639..25085435f5 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt @@ -1,5 +1,6 @@ package jp.co.soramitsu.staking.impl.scenarios.relaychain +import android.util.Log import java.math.BigDecimal import java.math.BigInteger import java.util.Optional @@ -7,6 +8,7 @@ import jp.co.soramitsu.account.api.domain.interfaces.AccountRepository import jp.co.soramitsu.account.api.domain.model.MetaAccount import jp.co.soramitsu.account.api.domain.model.accountId import jp.co.soramitsu.common.address.AddressModel +import jp.co.soramitsu.common.utils.castOrNull import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.sumByBigInteger import jp.co.soramitsu.common.validation.CompositeValidation @@ -24,11 +26,12 @@ import jp.co.soramitsu.staking.api.data.StakingSharedState import jp.co.soramitsu.staking.api.domain.api.AccountIdMap import jp.co.soramitsu.staking.api.domain.api.IdentityRepository import jp.co.soramitsu.staking.api.domain.model.DelegationAction -import jp.co.soramitsu.staking.api.domain.model.Exposure import jp.co.soramitsu.staking.api.domain.model.IndividualExposure +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.staking.api.domain.model.RewardDestination import jp.co.soramitsu.staking.api.domain.model.StakingLedger import jp.co.soramitsu.staking.api.domain.model.StakingState +import jp.co.soramitsu.staking.api.domain.model.ValidatorExposure import jp.co.soramitsu.staking.api.domain.model.isUnbondingIn import jp.co.soramitsu.staking.impl.data.model.Payout import jp.co.soramitsu.staking.impl.data.network.blockhain.calls.bondMore @@ -94,19 +97,21 @@ import jp.co.soramitsu.wallet.impl.domain.model.amountFromPlanks import jp.co.soramitsu.wallet.impl.domain.validation.EnoughToPayFeesValidation import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.withContext import jp.co.soramitsu.core.models.Asset as CoreAsset @@ -130,9 +135,11 @@ class StakingRelayChainScenarioInteractor( override suspend fun observeNetworkInfoState(): Flow { return stakingSharedState.assetWithChain.filter { it.asset.staking == StakingType.RELAYCHAIN } + .distinctUntilChanged() .flatMapLatest { (chain, _) -> val lockupPeriod = runCatching { getLockupPeriodInHours(chain.id) }.getOrDefault(0) - stakingRelayChainScenarioRepository.electedExposuresInActiveEra(chain.id) + + stakingRelayChainScenarioRepository.legacyElectedExposuresInActiveEra(chain.id) .map { exposuresMap -> val exposures = exposuresMap.values @@ -142,25 +149,29 @@ class StakingRelayChainScenarioInteractor( NetworkInfo.RelayChain( lockupPeriodInHours = lockupPeriod, - minimumStake = minimumStake(exposures, minimumNominatorBond), + minimumStake = minimumNominatorBond, totalStake = totalStake(exposures), - nominatorsCount = activeNominators(chain.id, exposures) + nominatorsCount = activeNominators(chain.id, exposures), + shouldUseMinimumStakeMultiplier = stakingConstantsRepository.maxRewardedNominatorPerValidator(chain.id) != null ) } } } - private fun totalStake(exposures: Collection): BigInteger { - return exposures.sumOf(Exposure::total) + private fun totalStake(exposures: Collection): BigInteger { + return exposures.sumOf(ValidatorExposure::total) } - - private suspend fun activeNominators(chainId: ChainId, exposures: Collection): Int { + private suspend fun activeNominators(chainId: ChainId, exposures: Collection): Int { val activeNominatorsPerValidator = stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId) return exposures.fold(mutableSetOf()) { acc, exposure -> acc += exposure.others.sortedByDescending(IndividualExposure::value) - .take(activeNominatorsPerValidator) + .let { + if (activeNominatorsPerValidator != null) + it.take(activeNominatorsPerValidator) + else it + } .map { it.who.toHexString() } acc @@ -173,14 +184,28 @@ class StakingRelayChainScenarioInteractor( } override fun stakingStateFlow(): Flow { - return stakingSharedState.assetWithChain.distinctUntilChanged() - .flatMapLatest { (chain, asset) -> - accountRepository.selectedMetaAccountFlow().mapNotNull { - it.accountId(chain) - }.flatMapLatest { accountId -> - stakingRelayChainScenarioRepository.stakingStateFlow(chain, asset, accountId) - } - } + return combine( + stakingSharedState.assetWithChain.distinctUntilChanged(), + accountRepository.selectedMetaAccountFlow() + ) { chainWithAsset, metaAccount -> + chainWithAsset to metaAccount + }.flatMapLatest { (chainWithAsset, metaAccount) -> + val accountId = + metaAccount.accountId(chainWithAsset.chain) ?: return@flatMapLatest emptyFlow() + stakingRelayChainScenarioRepository.stakingStateFlow( + chainWithAsset.chain, + chainWithAsset.asset, + accountId + ) + } +// return stakingSharedState.assetWithChain.distinctUntilChanged() +// .flatMapLatest { (chain, asset) -> +// accountRepository.selectedMetaAccountFlow().mapNotNull { +// it.accountId(chain) +// }.flatMapLatest { accountId -> +// stakingRelayChainScenarioRepository.stakingStateFlow(chain, asset, accountId) +// } +// } } fun stakingStateFlow(chainId: ChainId): Flow { @@ -262,8 +287,7 @@ class StakingRelayChainScenarioInteractor( ) { activeEraIndex, asset, totalReward -> val totalStaked = asset.bonded - val eraStakers = - stakingRelayChainScenarioRepository.getActiveElectedValidatorsExposures(state.chain.id) + val eraStakers = stakingRelayChainScenarioRepository.getLegacyActiveElectedValidatorsExposures(state.chain.id) val rewardedNominatorsPerValidator = stakingConstantsRepository.maxRewardedNominatorPerValidator(state.chain.id) @@ -284,7 +308,10 @@ class StakingRelayChainScenarioInteractor( }.flowOn(Dispatchers.Default) } - private fun isValidatorActive(stashId: ByteArray, exposures: AccountIdMap): Boolean { + private fun isValidatorActive( + stashId: ByteArray, + exposures: AccountIdMap + ): Boolean { val stashIdHex = stashId.toHexString() return stashIdHex in exposures.keys @@ -526,12 +553,7 @@ class StakingRelayChainScenarioInteractor( } override suspend fun getMinimumStake(chainAsset: CoreAsset): BigInteger { - val exposures = - stakingRelayChainScenarioRepository.electedExposuresInActiveEra(chainAsset.chainId) - .firstOrNull()?.values ?: emptyList() - val minimumNominatorBond = - stakingRelayChainScenarioRepository.minimumNominatorBond(chainAsset) - return minimumStake(exposures, minimumNominatorBond) + return stakingRelayChainScenarioRepository.minimumNominatorBond(chainAsset) } suspend fun getLockupPeriodInHours() = withContext(Dispatchers.Default) { @@ -575,15 +597,15 @@ class StakingRelayChainScenarioInteractor( } } - suspend fun maxRewardedNominators(): Int = withContext(Dispatchers.Default) { + suspend fun maxRewardedNominators(): Int? = withContext(Dispatchers.Default) { stakingConstantsRepository.maxRewardedNominatorPerValidator(stakingSharedState.chainId()) } private class StatusResolutionContext( - val eraStakers: AccountIdMap, + val eraStakers: AccountIdMap, val activeEraIndex: BigInteger, val asset: Asset, - val rewardedNominatorsPerValidator: Int + val rewardedNominatorsPerValidator: Int? ) override suspend fun maxNumberOfStakesIsReached(chainId: ChainId): Boolean { @@ -819,3 +841,15 @@ class EraRelativeInfo( val erasLeft: BigInteger, val erasPast: BigInteger ) + +fun Collection.legacyOrNull(): Collection? { + return if (this.all { it is LegacyExposure }) { + castOrNull() + } else null +} + +fun AccountIdMap.legacyOrNull(): AccountIdMap? { + return if (values.all { it is LegacyExposure }) { + castOrNull() + } else null +} \ No newline at end of file diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt index 73018749b6..2d6138f4b6 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt @@ -8,6 +8,7 @@ import jp.co.soramitsu.common.utils.Modules import jp.co.soramitsu.common.utils.accountIdFromMapKey import jp.co.soramitsu.common.utils.babe import jp.co.soramitsu.common.utils.constant +import jp.co.soramitsu.common.utils.isNotZero import jp.co.soramitsu.common.utils.mapValuesNotNull import jp.co.soramitsu.common.utils.nominationPools import jp.co.soramitsu.common.utils.numberConstant @@ -43,6 +44,8 @@ import jp.co.soramitsu.shared_utils.ss58.SS58Encoder.toAccountId import jp.co.soramitsu.staking.api.domain.api.AccountIdMap import jp.co.soramitsu.staking.api.domain.model.EraIndex import jp.co.soramitsu.staking.api.domain.model.Exposure +import jp.co.soramitsu.staking.api.domain.model.IndividualExposure +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.staking.api.domain.model.Nominations import jp.co.soramitsu.staking.api.domain.model.SlashingSpans import jp.co.soramitsu.staking.api.domain.model.StakingLedger @@ -56,11 +59,14 @@ import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindCurrentS import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindEraRewardPoints import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindErasStartSessionIndex import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindExposure +import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindExposurePage import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindHistoryDepth +import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindLegacyExposure import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindMaxNominators import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindMinBond import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindNominations import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindNominatorsCount +import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindNumberOrNull import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindRewardDestination import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindSlashDeferDuration import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindSlashingSpans @@ -74,16 +80,22 @@ import kotlin.math.max import kotlin.time.DurationUnit import kotlin.time.toDuration import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext +typealias ValidatorExposureWithNominators = Pair> + class StakingRelayChainScenarioRepository( private val remoteStorage: StorageDataSource, private val localStorage: StorageDataSource, @@ -192,30 +204,106 @@ class StakingRelayChainScenarioRepository( ) } - fun electedExposuresInActiveEra(chainId: ChainId) = observeActiveEraIndex(chainId).mapLatest { - getElectedValidatorsExposure(chainId, it) - }.runCatching { this }.getOrDefault(emptyFlow()) + fun legacyElectedExposuresInActiveEra(chainId: ChainId): Flow> = + observeActiveEraIndex(chainId) + .filter { it.isNotZero() } + .distinctUntilChanged() + .mapLatest { + getLegacyElectedValidatorsExposure(chainId, it) + } + + private suspend fun getLegacyElectedValidatorsExposure( + chainId: ChainId, + eraIndex: EraIndex + ): Map { + return if (isLegacyErasStakersSchema(chainId)) { + localStorage.queryByPrefix( + chainId = chainId, + prefixKeyBuilder = { + it.metadata.moduleOrNull(Modules.STAKING)?.storage("ErasStakers") + ?.storageKey(it, eraIndex) + }, + keyExtractor = { it.accountIdFromMapKey() } + ) { scale, runtime, _ -> + val storageType = runtime.metadata.staking().storage("ErasStakers").returnType() + bindLegacyExposure(scale!!, runtime, storageType) + }.mapValuesNotNull { it.value } + } else { + val exposuresInNewVariant = + getElectedValidatorExposureWithNominators(chainId, eraIndex) + + exposuresInNewVariant.mapValues { (_, exposure) -> + val (validatorExposure, individualExposures) = exposure + + LegacyExposure( + validatorExposure.total, + validatorExposure.own, + individualExposures + ) + } + } + } + + private suspend fun getElectedValidatorExposureWithNominators( + chainId: ChainId, + eraIndex: EraIndex + ): Map = supervisorScope { + val runtime = chainRegistry.getRuntime(chainId) + val exposures = runCatching { getElectedValidatorsExposure(chainId, eraIndex) }.getOrNull() + ?: emptyMap() + + val resultMap = mutableMapOf() + + val rawIndividualPages = localStorage.queryByPrefix( + chainId = chainId, + prefixKeyBuilder = { + it.metadata.moduleOrNull(Modules.STAKING)?.storage("ErasStakersPaged") + ?.storageKey(it, eraIndex) + }, + keyExtractor = { it } + ) { scale, _, _ -> + scale + }.filterValues { it != null } + + exposures.entries.map { (validatorId, exposure) -> + async { + val entries = rawIndividualPages.entries.asSequence() + val validatorPages = entries.filter { it.key.contains(validatorId.removePrefix("0x")) } + val individualExposures = validatorPages.mapNotNull { entry -> + entry.value?.let { + bindExposurePage( + it, + runtime + )?.others + } + }.toList().flatten() + resultMap[validatorId] = + ValidatorExposureWithNominators(exposure, individualExposures) + } + }.awaitAll() + + resultMap + } private suspend fun getElectedValidatorsExposure( chainId: ChainId, eraIndex: EraIndex - ): Map = remoteStorage.queryByPrefix( + ): Map = localStorage.queryByPrefix( chainId = chainId, prefixKeyBuilder = { - it.metadata.moduleOrNull(Modules.STAKING)?.storage("ErasStakers") + it.metadata.moduleOrNull(Modules.STAKING)?.storage("ErasStakersOverview") ?.storageKey(it, eraIndex) }, keyExtractor = { it.accountIdFromMapKey() } ) { scale, runtime, _ -> - val storageType = runtime.metadata.staking().storage("ErasStakers").returnType() - bindExposure(scale!!, runtime, storageType) + scale?.let { bindExposure(it, runtime) } }.mapValuesNotNull { it.value } suspend fun getValidatorPrefs( chainId: ChainId, accountIdsHex: List ): AccountIdMap { - return remoteStorage.queryKeys( + return localStorage.queryKeys( keysBuilder = { runtime -> val storage = runtime.metadata.stakingOrNull()?.storage("Validators") ?: return@queryKeys emptyMap() @@ -238,7 +326,7 @@ class StakingRelayChainScenarioRepository( suspend fun getAllValidatorPrefs( chainId: ChainId ): AccountIdMap { - return remoteStorage.queryByPrefix( + return localStorage.queryByPrefix( chainId = chainId, prefixKeyBuilder = { runtime -> runtime.metadata.stakingOrNull()?.storage("Validators")?.storageKey() @@ -333,6 +421,14 @@ class StakingRelayChainScenarioRepository( chainId = chainId ) + suspend fun minimumActiveStake(chainId: ChainId): BigInteger? = queryStorageIfExists( + storageName = "MinimumActiveStake", + binder = { scale, runtimeSnapshot, type -> + bindNumberOrNull(scale, runtimeSnapshot, type) + }, + chainId = chainId + ) + suspend fun nominatorsCount(chainId: ChainId): BigInteger? = queryStorageIfExists( storageName = "CounterForNominators", binder = ::bindNominatorsCount, @@ -414,7 +510,7 @@ class StakingRelayChainScenarioRepository( chainId: ChainId, stashId: AccountId ): Flow { - return localStorage.observe( + return remoteStorage.observe( chainId = chainId, keyBuilder = { it.metadata.staking().storage("Validators").storageKey(it, stashId) }, binder = { scale, runtime -> @@ -508,6 +604,15 @@ class StakingRelayChainScenarioRepository( ) } } + + suspend fun getLegacyActiveElectedValidatorsExposures(chainId: ChainId): Map { + return legacyElectedExposuresInActiveEra(chainId).firstOrNull() ?: emptyMap() + } + + private suspend fun isLegacyErasStakersSchema(chainId: ChainId): Boolean { + val runtime = chainRegistry.getRuntime(chainId) + return runtime.metadata.stakingOrNull()?.storageOrNull("ErasStakersPaged") == null + } } suspend fun StakingRelayChainScenarioRepository.historicalEras(chainId: ChainId): List { @@ -536,6 +641,3 @@ suspend fun StakingRelayChainScenarioRepository.hoursInEra(chainId: ChainId): In val erasPerDay = erasPerDay(chainId) return floor(HOURS_IN_DAY.toDouble() / erasPerDay.toDouble()).toInt() } - -suspend fun StakingRelayChainScenarioRepository.getActiveElectedValidatorsExposures(chainId: ChainId): Map = - electedExposuresInActiveEra(chainId).firstOrNull() ?: emptyMap() diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/network/updaters/BlockNumberUpdater.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/network/updaters/BlockNumberUpdater.kt index 88c6b4680b..7359f64d01 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/network/updaters/BlockNumberUpdater.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/network/updaters/BlockNumberUpdater.kt @@ -4,7 +4,7 @@ import jp.co.soramitsu.common.data.holders.ChainIdHolder import jp.co.soramitsu.common.utils.Modules import jp.co.soramitsu.common.utils.system import jp.co.soramitsu.core.storage.StorageCache -import jp.co.soramitsu.core.updater.GlobalScope +import jp.co.soramitsu.core.updater.GlobalUpdaterScope import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot import jp.co.soramitsu.shared_utils.runtime.metadata.storage @@ -14,7 +14,7 @@ class BlockNumberUpdater( chainRegistry: ChainRegistry, chainIdHolder: ChainIdHolder, storageCache: StorageCache -) : SingleStorageKeyUpdater(GlobalScope, chainIdHolder, chainRegistry, storageCache) { +) : SingleStorageKeyUpdater(GlobalUpdaterScope, chainIdHolder, chainRegistry, storageCache) { override suspend fun storageKey(runtime: RuntimeSnapshot): String { return runtime.metadata.system().storage("Number").storageKey() From c92c69aa8fdf130791dc7302354725215b31292f Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 25 Apr 2024 18:54:31 +0700 Subject: [PATCH 02/11] fixes --- .../impl/domain/validators/ValidatorProvider.kt | 11 ++--------- .../validators/current/CurrentValidatorsInteractor.kt | 3 +-- .../scenarios/StakingRelaychainScenarioViewModel.kt | 3 ++- .../relaychain/StakingRelayChainScenarioInteractor.kt | 8 -------- .../relaychain/StakingRelayChainScenarioRepository.kt | 3 ++- 5 files changed, 7 insertions(+), 21 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt index ad69b91717..da17990b5d 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/ValidatorProvider.kt @@ -9,9 +9,7 @@ import jp.co.soramitsu.runtime.multiNetwork.chain.model.reefChainId import jp.co.soramitsu.runtime.multiNetwork.chain.model.soraMainChainId import jp.co.soramitsu.runtime.multiNetwork.chain.model.ternoaChainId import jp.co.soramitsu.shared_utils.extensions.fromHex -import jp.co.soramitsu.staking.api.domain.api.AccountIdMap import jp.co.soramitsu.staking.api.domain.api.IdentityRepository -import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import jp.co.soramitsu.staking.api.domain.model.Validator import jp.co.soramitsu.staking.impl.data.repository.StakingConstantsRepository import jp.co.soramitsu.staking.impl.domain.rewards.RewardCalculationTarget @@ -36,13 +34,10 @@ class ValidatorProvider( suspend fun getValidators( chain: Chain, - source: ValidatorSource, - cachedExposures: AccountIdMap? = null + source: ValidatorSource ): List = coroutineScope { val chainId = chain.id - val electedValidatorExposuresDeferred = async { cachedExposures ?: stakingRepository.getLegacyActiveElectedValidatorsExposures(chainId) } - val allValidatorPrefsDeferred = async { stakingRepository.getAllValidatorPrefs(chainId) } val maxNominatorsDeferred = async { stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId) @@ -53,12 +48,10 @@ class ValidatorProvider( ValidatorSource.Elected -> allValidatorPrefs.keys.toList() is ValidatorSource.Custom -> source.validatorIds } - val identitiesDeferred = async { identityRepository.getIdentitiesFromIds(chain, requestedValidatorIds) } val slashesDeferred = async { stakingRepository.getSlashes(chainId, requestedValidatorIds) } - val electedValidatorExposures = electedValidatorExposuresDeferred.await() - + val electedValidatorExposures = stakingRepository.getLegacyActiveElectedValidatorsExposures(chainId) val rewardCalculatorDeferred = async { val calculationTargets = electedValidatorExposures.keys.mapNotNull { accountIdHex -> val exposure = electedValidatorExposures[accountIdHex] ?: return@mapNotNull null diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt index 89f6e9e834..16e6c3475b 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/validators/current/CurrentValidatorsInteractor.kt @@ -58,8 +58,7 @@ class CurrentValidatorsInteractor( val groupedByStatusClass = validatorProvider.getValidators( chain = chain, - source = ValidatorSource.Custom(nominatedValidatorIds.toList()), - cachedExposures = exposures + source = ValidatorSource.Custom(nominatedValidatorIds.toList()) ) .map { validator -> val userIndividualExposure = activeNominations[validator.accountIdHex] diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt index fcac1e8a60..b744478e44 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt @@ -6,6 +6,7 @@ import jp.co.soramitsu.common.presentation.LoadingState import jp.co.soramitsu.common.resources.ResourceManager import jp.co.soramitsu.common.utils.formatCryptoDetail import jp.co.soramitsu.common.utils.formatFiat +import jp.co.soramitsu.common.utils.inBackground import jp.co.soramitsu.common.utils.mapList import jp.co.soramitsu.common.utils.withLoading import jp.co.soramitsu.common.validation.CompositeValidation @@ -198,7 +199,7 @@ class StakingRelaychainScenarioViewModel( override suspend fun alerts(): Flow>> { return stakingStateFlow.flatMapLatest { alertsInteractor.getAlertsFlow(it) - }.mapList(::mapAlertToAlertModel).withLoading() + }.mapList(::mapAlertToAlertModel).withLoading().inBackground() } private fun mapAlertToAlertModel(alert: Alert): AlertModel { diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt index 25085435f5..919029460e 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioInteractor.kt @@ -198,14 +198,6 @@ class StakingRelayChainScenarioInteractor( accountId ) } -// return stakingSharedState.assetWithChain.distinctUntilChanged() -// .flatMapLatest { (chain, asset) -> -// accountRepository.selectedMetaAccountFlow().mapNotNull { -// it.accountId(chain) -// }.flatMapLatest { accountId -> -// stakingRelayChainScenarioRepository.stakingStateFlow(chain, asset, accountId) -// } -// } } fun stakingStateFlow(chainId: ChainId): Flow { diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt index 2d6138f4b6..e02bc38421 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt @@ -606,7 +606,8 @@ class StakingRelayChainScenarioRepository( } suspend fun getLegacyActiveElectedValidatorsExposures(chainId: ChainId): Map { - return legacyElectedExposuresInActiveEra(chainId).firstOrNull() ?: emptyMap() + val era = getActiveEraIndex(chainId) + return getLegacyElectedValidatorsExposure(chainId, era) } private suspend fun isLegacyErasStakersSchema(chainId: ChainId): Boolean { From 14fe23d211a08c1b7aa47ee9cfd15b259c5480e6 Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 25 Apr 2024 18:57:35 +0700 Subject: [PATCH 03/11] increase version --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 71227e844a..74149098a8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ apply plugin: "org.sonarqube" buildscript { ext { // App version - versionName = '3.4.3' - versionCode = 168 + versionName = '3.4.4' + versionCode = 169 // SDK and tools compileSdkVersion = 34 From 79a642cd914f1b9847f0b0f672d7a31dcdc2aae6 Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 25 Apr 2024 19:20:43 +0700 Subject: [PATCH 04/11] fix tests, increase version --- build.gradle | 2 +- .../staking/impl/domain/StakingInteractorExtKtTest.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 74149098a8..286ce5bfd4 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext { // App version versionName = '3.4.4' - versionCode = 169 + versionCode = 170 // SDK and tools compileSdkVersion = 34 diff --git a/feature-staking-impl/src/test/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExtKtTest.kt b/feature-staking-impl/src/test/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExtKtTest.kt index 5e86bf74c2..2e5457493d 100644 --- a/feature-staking-impl/src/test/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExtKtTest.kt +++ b/feature-staking-impl/src/test/java/jp/co/soramitsu/staking/impl/domain/StakingInteractorExtKtTest.kt @@ -1,14 +1,14 @@ package jp.co.soramitsu.staking.impl.domain -import jp.co.soramitsu.staking.api.domain.model.Exposure import jp.co.soramitsu.staking.api.domain.model.IndividualExposure +import jp.co.soramitsu.staking.api.domain.model.LegacyExposure import org.junit.Assert.assertEquals import org.junit.Test class StakingInteractorExtKtTest { private val exposures = listOf( - Exposure( + LegacyExposure( total = 6.toBigInteger(), own = 0.toBigInteger(), others = listOf( @@ -17,7 +17,7 @@ class StakingInteractorExtKtTest { IndividualExposure(byteArrayOf(2), 2.toBigInteger()), ) ), - Exposure( + LegacyExposure( total = 3.toBigInteger(), own = 0.toBigInteger(), others = listOf( From 979a02f9b40a9070f02c59c661e2b156204725a5 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Apr 2024 12:14:09 +0700 Subject: [PATCH 05/11] fixed crash on select recommended validators for pool staking --- .../compose/SelectValidatorsViewModel.kt | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/compose/SelectValidatorsViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/compose/SelectValidatorsViewModel.kt index b4e4fd2c52..d4ed1d8742 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/compose/SelectValidatorsViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/validators/compose/SelectValidatorsViewModel.kt @@ -1,26 +1,18 @@ package jp.co.soramitsu.staking.impl.presentation.validators.compose -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.withStyle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import java.math.BigInteger import javax.inject.Inject import jp.co.soramitsu.common.AlertViewState import jp.co.soramitsu.common.base.BaseViewModel -import jp.co.soramitsu.common.compose.theme.black1 -import jp.co.soramitsu.common.compose.theme.greenText import jp.co.soramitsu.common.presentation.LoadingState import jp.co.soramitsu.common.presentation.dataOrNull import jp.co.soramitsu.common.presentation.map import jp.co.soramitsu.common.resources.ResourceManager -import jp.co.soramitsu.common.utils.formatAsPercentage -import jp.co.soramitsu.common.utils.fractionToPercentage import jp.co.soramitsu.common.utils.inBackground import jp.co.soramitsu.common.utils.invoke import jp.co.soramitsu.common.utils.lazyAsync -import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.feature_staking_impl.R import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain import jp.co.soramitsu.shared_utils.extensions.fromHex @@ -33,14 +25,12 @@ import jp.co.soramitsu.staking.impl.domain.recommendations.settings.Recommendati import jp.co.soramitsu.staking.impl.domain.recommendations.settings.SettingsStorage import jp.co.soramitsu.staking.impl.domain.recommendations.settings.filters.Filters import jp.co.soramitsu.staking.impl.domain.recommendations.settings.filters.Sorting -import jp.co.soramitsu.staking.impl.domain.recommendations.settings.sortings.BlockProducersSorting import jp.co.soramitsu.staking.impl.presentation.StakingRouter import jp.co.soramitsu.staking.impl.presentation.common.SelectValidatorFlowState import jp.co.soramitsu.staking.impl.presentation.common.StakingPoolSharedStateProvider import jp.co.soramitsu.staking.impl.presentation.mappers.mapValidatorToValidatorDetailsParcelModel import jp.co.soramitsu.staking.impl.presentation.pools.compose.SelectableListItemState import jp.co.soramitsu.staking.impl.presentation.validators.buildSegmentedValidatorsListState -import jp.co.soramitsu.wallet.api.presentation.formatters.formatCryptoFromPlanks import jp.co.soramitsu.wallet.impl.domain.model.Asset import kotlinx.coroutines.Deferred import kotlinx.coroutines.flow.MutableStateFlow @@ -51,6 +41,7 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch private val filtersSet = @@ -117,6 +108,11 @@ class SelectValidatorsViewModel @Inject constructor( private val recommendedValidators = recommendedSettings.mapNotNull { val settings = it ?: recommendationSettingsProvider().defaultSelectCustomSettings() val recommendations = validatorRecommendator().recommendations(settings) + if (selectMode == SelectValidatorFlowState.ValidatorSelectMode.RECOMMENDED) { + selectedItems.update { + recommendations.map { it.accountIdHex } + } + } LoadingState.Loaded(recommendations) }.inBackground().stateIn(viewModelScope, SharingStarted.Eagerly, LoadingState.Loading()) From 22c0f092c94b53493112284dc5963bef3feba3ad Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Apr 2024 13:47:42 +0700 Subject: [PATCH 06/11] fixed crashes on parachain staking --- .../staking/impl/data/network/blockhain/bindings/Era.kt | 3 ++- .../staking/impl/domain/rewards/RewardCalculatorFactory.kt | 1 + .../relaychain/StakingRelayChainScenarioRepository.kt | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt index f89f494f2b..d3abc4f525 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt @@ -29,9 +29,10 @@ import java.math.BigInteger */ @UseCaseBinding fun bindActiveEra( - scale: String, + scale: String?, runtime: RuntimeSnapshot ): BigInteger { + scale ?: return BigInteger.ZERO val returnType = runtime.metadata.storageReturnType("Staking", "ActiveEra") val decoded = returnType.fromHexOrNull(runtime, scale) as? Struct.Instance ?: incompatible() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt index 6c888b523e..ce082d6146 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/RewardCalculatorFactory.kt @@ -132,6 +132,7 @@ class RewardCalculatorFactory( syntheticType == SyntheticStakingType.TERNOA -> createTernoa(asset, calculationTargets) syntheticType == SyntheticStakingType.REEF -> createReef(asset, calculationTargets) stakingType == Asset.StakingType.RELAYCHAIN -> createManual(chainId, calculationTargets) + stakingType == Asset.StakingType.PARACHAIN -> createSubquery() stakingType == Asset.StakingType.UNSUPPORTED -> error("wrong staking type") else -> error("wrong staking type") diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt index e02bc38421..ce109cdefe 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt @@ -155,7 +155,7 @@ class StakingRelayChainScenarioRepository( return runtime.metadata.babe().numberConstant("ExpectedBlockTime", runtime) } - suspend fun getActiveEraIndex(chainId: ChainId): EraIndex = localStorage.queryNonNull( + suspend fun getActiveEraIndex(chainId: ChainId): EraIndex = localStorage.query( keyBuilder = { it.metadata.activeEraStorageKeyOrNull() }, binding = ::bindActiveEra, chainId = chainId From 4dc691c570d0bfb0eb97e7d636b7b4012af55a52 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Apr 2024 13:48:14 +0700 Subject: [PATCH 07/11] increase version 171 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 286ce5bfd4..a7993e1599 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext { // App version versionName = '3.4.4' - versionCode = 170 + versionCode = 171 // SDK and tools compileSdkVersion = 34 From ad9841591d2cad553c0ee85d3011d25e098330f9 Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Fri, 26 Apr 2024 13:00:31 +0500 Subject: [PATCH 08/11] avail network transfers support (appId required) --- .../jp/co/soramitsu/coredb/AppDatabase.kt | 4 +++- .../soramitsu/coredb/migrations/Migrations.kt | 6 ++++++ .../coredb/model/chain/ChainLocal.kt | 3 ++- .../CrowdloanContributeInteractor.kt | 2 +- .../domain/interfaces/WalletInteractor.kt | 1 + .../domain/interfaces/WalletRepository.kt | 1 + .../blockchain/SubstrateRemoteSource.kt | 1 + .../network/blockchain/WssSubstrateSource.kt | 2 ++ .../data/repository/WalletRepositoryImpl.kt | 3 ++- .../impl/domain/WalletInteractorImpl.kt | 2 ++ .../send/confirm/ConfirmSendViewModel.kt | 20 ++++++++++++------- gradle/libs.versions.toml | 2 +- .../runtime/multiNetwork/chain/Mappers.kt | 10 +++++++--- .../runtime/multiNetwork/chain/model/Chain.kt | 5 ++++- 14 files changed, 46 insertions(+), 16 deletions(-) diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt index 3f4c96a08e..5fe2f1b621 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt @@ -66,6 +66,7 @@ import jp.co.soramitsu.coredb.migrations.Migration_59_60 import jp.co.soramitsu.coredb.migrations.Migration_60_61 import jp.co.soramitsu.coredb.migrations.Migration_61_62 import jp.co.soramitsu.coredb.migrations.Migration_62_63 +import jp.co.soramitsu.coredb.migrations.Migration_63_64 import jp.co.soramitsu.coredb.migrations.RemoveAccountForeignKeyFromAsset_17_18 import jp.co.soramitsu.coredb.migrations.RemoveLegacyData_35_36 import jp.co.soramitsu.coredb.migrations.RemoveStakingRewardsTable_22_23 @@ -91,7 +92,7 @@ import jp.co.soramitsu.coredb.model.chain.FavoriteChainLocal import jp.co.soramitsu.coredb.model.chain.MetaAccountLocal @Database( - version = 63, + version = 64, entities = [ AccountLocal::class, AddressBookContact::class, @@ -175,6 +176,7 @@ abstract class AppDatabase : RoomDatabase() { .addMigrations(Migration_60_61) .addMigrations(Migration_61_62) .addMigrations(Migration_62_63) + .addMigrations(Migration_63_64) .build() } return instance!! diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt index 27873fa3f9..79622d6888 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt @@ -3,6 +3,12 @@ package jp.co.soramitsu.coredb.migrations import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase +val Migration_63_64 = object : Migration(63, 64) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE chains ADD COLUMN `isUsesAppId` INTEGER NOT NULL DEFAULT 0") + } +} + val Migration_62_63 = object : Migration(62, 63) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("ALTER TABLE assets ADD COLUMN `status` TEXT NULL") diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt index a97990c098..fcb7c13f08 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt @@ -22,7 +22,8 @@ class ChainLocal( val supportStakingPool: Boolean, val isEthereumChain: Boolean, val isChainlinkProvider: Boolean, - val supportNft: Boolean + val supportNft: Boolean, + val isUsesAppId: Boolean ) { class ExternalApi( diff --git a/feature-crowdloan-impl/src/main/java/jp/co/soramitsu/crowdloan/impl/domain/contribute/CrowdloanContributeInteractor.kt b/feature-crowdloan-impl/src/main/java/jp/co/soramitsu/crowdloan/impl/domain/contribute/CrowdloanContributeInteractor.kt index faaf7b1011..5412b71e16 100644 --- a/feature-crowdloan-impl/src/main/java/jp/co/soramitsu/crowdloan/impl/domain/contribute/CrowdloanContributeInteractor.kt +++ b/feature-crowdloan-impl/src/main/java/jp/co/soramitsu/crowdloan/impl/domain/contribute/CrowdloanContributeInteractor.kt @@ -139,7 +139,7 @@ class CrowdloanContributeInteractor( } return runCatching { - walletRepository.performTransfer(accountId, chain, transfer, fee, null, additional, batchAll) + walletRepository.performTransfer(accountId, chain, transfer, fee, null, null, additional, batchAll) } } diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt index 81cd730da5..501f675e7c 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt @@ -82,6 +82,7 @@ interface WalletInteractor { transfer: Transfer, fee: BigDecimal, tipInPlanks: BigInteger?, + appId: BigInteger?, additional: (suspend ExtrinsicBuilder.() -> Unit)? = null ): Result diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt index 2ac3998bbf..4beed68f62 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt @@ -71,6 +71,7 @@ interface WalletRepository { transfer: Transfer, fee: BigDecimal, tip: BigInteger?, + appId: BigInteger?, additional: (suspend ExtrinsicBuilder.() -> Unit)? = null, batchAll: Boolean = false ): String diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/SubstrateRemoteSource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/SubstrateRemoteSource.kt index d537ac99b8..a29383df62 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/SubstrateRemoteSource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/SubstrateRemoteSource.kt @@ -34,6 +34,7 @@ interface SubstrateRemoteSource { chain: Chain, transfer: Transfer, tip: BigInteger?, + appId: BigInteger?, additional: (suspend ExtrinsicBuilder.() -> Unit)?, batchAll: Boolean ): String diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/WssSubstrateSource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/WssSubstrateSource.kt index 9d0feb2fb9..df0deabc85 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/WssSubstrateSource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/WssSubstrateSource.kt @@ -202,6 +202,7 @@ class WssSubstrateSource( chain: Chain, transfer: Transfer, tip: BigInteger?, + appId: BigInteger?, additional: (suspend ExtrinsicBuilder.() -> Unit)?, batchAll: Boolean ): String { @@ -210,6 +211,7 @@ class WssSubstrateSource( accountId = accountId, useBatchAll = batchAll, tip = tip, + appId = appId, formExtrinsic = { transfer(chain, transfer, this.runtime.typeRegistry) additional?.invoke(this) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt index 4696a97ba7..523c4b3fad 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt @@ -398,6 +398,7 @@ class WalletRepositoryImpl( transfer: Transfer, fee: BigDecimal, tip: BigInteger?, + appId: BigInteger?, additional: (suspend ExtrinsicBuilder.() -> Unit)?, batchAll: Boolean ): String { @@ -411,7 +412,7 @@ class WalletRepositoryImpl( ethereumSource.performTransfer(chain, transfer, privateKey.toHexString(true)) .requireValue() // handle error } else { - substrateSource.performTransfer(accountId, chain, transfer, tip, additional, batchAll) + substrateSource.performTransfer(accountId, chain, transfer, tip, appId, additional, batchAll) } val accountAddress = chain.addressOf(accountId) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt index f8124db27f..1224cca6ff 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt @@ -316,6 +316,7 @@ class WalletInteractorImpl( transfer: Transfer, fee: BigDecimal, tipInPlanks: BigInteger?, + appId: BigInteger?, additional: (suspend ExtrinsicBuilder.() -> Unit)? ): Result { val metaAccount = accountRepository.getSelectedMetaAccount() @@ -329,6 +330,7 @@ class WalletInteractorImpl( transfer, fee, tipInPlanks, + appId, additional ) } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/send/confirm/ConfirmSendViewModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/send/confirm/ConfirmSendViewModel.kt index 0afec2cb1a..effa7d9739 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/send/confirm/ConfirmSendViewModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/send/confirm/ConfirmSendViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import java.math.BigDecimal +import java.math.BigInteger import javax.inject.Inject import jp.co.soramitsu.account.api.presentation.actions.ExternalAccountActions import jp.co.soramitsu.common.AlertViewState @@ -128,16 +129,18 @@ class ConfirmSendViewModel @Inject constructor( private val assetFlow = interactor.assetFlow(transferDraft.assetPayload.chainId, transferDraft.assetPayload.chainAssetId).share() + private val chainFlow = flowOf { + interactor.getChain(transferDraft.assetPayload.chainId) + }.share() + @OptIn(ExperimentalCoroutinesApi::class) - val utilityAssetFlow = flowOf { - val assetChain = interactor.getChain(transferDraft.assetPayload.chainId) - assetChain.utilityAsset?.id - } - .mapNotNull { it } + val utilityAssetFlow = chainFlow + .mapNotNull { it.utilityAsset?.id } .flatMapLatest { assetId -> interactor.assetFlow(transferDraft.assetPayload.chainId, assetId) } + @OptIn(ExperimentalCoroutinesApi::class) private val feeFlow = assetFlow.map { createTransfer(it.token.configuration) } .flatMapLatest { interactor.observeTransferFee(it) } .map { it.feeAmount } @@ -352,9 +355,12 @@ class ConfirmSendViewModel @Inject constructor( transferSubmittingFlow.value = true val tipInPlanks = transferDraft.tip?.let { token.planksFromAmount(it) } - val result = withContext(Dispatchers.Default) { - interactor.performTransfer(createTransfer(token, fee), fee, tipInPlanks) + val usesAppId = chainFlow.firstOrNull()?.isUsesAppId == true + val appId = if (usesAppId) BigInteger.ZERO else null + + val result = withContext(Dispatchers.Default) { + interactor.performTransfer(createTransfer(token, fee), fee, tipInPlanks, appId) } if (result.isSuccess) { val operationHash = result.getOrNull() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fdad1dad87..e5179cfd2c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,7 +48,7 @@ retrofit = "2.9.0" roomVersion = "2.6.1" rules = "1.5.0" runner = "1.5.2" -sharedFeaturesVersion = "1.1.1.28-FLW" +sharedFeaturesVersion = "1.1.1.29-FLW" shimmerVersion = "0.5.0" sonarqubeGradlePlugin = "3.3" soraUiCore = "0.2.20" diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt index b7e053ac74..7e4f44f358 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt @@ -22,6 +22,7 @@ private const val CROWDLOAN_OPTION = "crowdloans" private const val TESTNET_OPTION = "testnet" private const val NOMINATION_POOL_OPTION = "poolStaking" private const val NFT_OPTION = "nft" +private const val USES_APP_ID_OPTION = "checkAppId" private fun mapSectionTypeRemoteToSectionType(section: String) = when (section) { "subquery" -> Chain.ExternalApi.Section.Type.SUBQUERY @@ -153,7 +154,8 @@ fun ChainRemote.toChain(): Chain { isEthereumChain = ETHEREUM_OPTION in optionsOrEmpty, chainlinkProvider = CHAINLINK_PROVIDER_OPTION in optionsOrEmpty, supportNft = NFT_OPTION in optionsOrEmpty, - paraId = this.paraId + paraId = this.paraId, + isUsesAppId = USES_APP_ID_OPTION in optionsOrEmpty ) } @@ -261,7 +263,8 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo): Chain { isEthereumChain = isEthereumChain, paraId = paraId, chainlinkProvider = isChainlinkProvider, - supportNft = supportNft + supportNft = supportNft, + isUsesAppId = isUsesAppId ) } } @@ -333,7 +336,8 @@ fun mapChainToChainLocal(chain: Chain): JoinedChainInfo { isEthereumChain = isEthereumChain, paraId = paraId, isChainlinkProvider = chainlinkProvider, - supportNft = supportNft + supportNft = supportNft, + isUsesAppId = isUsesAppId ) } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt index 0e203b959b..6aee03c36a 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt @@ -51,7 +51,8 @@ data class Chain( val supportStakingPool: Boolean, val isEthereumChain: Boolean, val chainlinkProvider: Boolean, - val supportNft: Boolean + val supportNft: Boolean, + val isUsesAppId: Boolean ) : IChain { val assetsById = assets.associateBy(CoreAsset::id) @@ -104,6 +105,7 @@ data class Chain( if (isEthereumChain != other.isEthereumChain) return false if (chainlinkProvider != other.chainlinkProvider) return false if (supportNft != other.supportNft) return false + if (isUsesAppId != other.isUsesAppId) return false // custom comparison logic val defaultNodes = nodes.filter { it.isDefault } @@ -136,6 +138,7 @@ data class Chain( result = 31 * result + isEthereumChain.hashCode() result = 31 * result + chainlinkProvider.hashCode() result = 31 * result + supportNft.hashCode() + result = 31 * result + isUsesAppId.hashCode() return result } } From a368f4e54822e8257f894fcaaa3ecb47dde8678e Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Apr 2024 15:09:47 +0700 Subject: [PATCH 09/11] fixed parachain staking reward calculator --- .../impl/data/network/blockhain/bindings/BindStaked.kt | 4 ++-- .../impl/domain/rewards/SubqueryRewardCalculator.kt | 2 +- .../parachain/StakingParachainScenarioInteractor.kt | 4 ++-- .../parachain/StakingParachainScenarioRepository.kt | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/BindStaked.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/BindStaked.kt index 866dd2eeef..4f3f684e7b 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/BindStaked.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/BindStaked.kt @@ -8,11 +8,11 @@ import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot import java.math.BigInteger @UseCaseBinding -fun bindStaked( +fun bindTotal( scale: String, runtime: RuntimeSnapshot ): BigInteger { - val returnType = runtime.metadata.storageReturnType("ParachainStaking", "Staked") + val returnType = runtime.metadata.storageReturnType("ParachainStaking", "Total") return bindNumber(returnType.fromHexOrIncompatible(scale, runtime)) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SubqueryRewardCalculator.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SubqueryRewardCalculator.kt index a56e095fc6..676f3aa624 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SubqueryRewardCalculator.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SubqueryRewardCalculator.kt @@ -79,7 +79,7 @@ class SubqueryRewardCalculator( override suspend fun calculateReturns(amount: BigDecimal, days: Int, isCompound: Boolean, chainId: ChainId): PeriodReturns { val totalIssuance = stakingRepository.getTotalIssuance(chainId) - val staked = stakingParachainScenarioInteractor?.getStaked(chainId)?.getOrNull() + val staked = stakingParachainScenarioInteractor?.total(chainId)?.getOrNull() val rewardsAmountPart = BigDecimal(0.025) val currentApy = if (staked != null && staked > BigInteger.ZERO) { totalIssuance.toBigDecimal() * rewardsAmountPart / staked.toBigDecimal() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioInteractor.kt index a2bc6ac3aa..1dbddcf6aa 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioInteractor.kt @@ -180,8 +180,8 @@ class StakingParachainScenarioInteractor( return runCatching { stakingParachainScenarioRepository.getAtStakeOfCollator(chainId, collatorId, getCurrentRound(chainId).getOrThrow().current) } } - suspend fun getStaked(chainId: ChainId): Result { - return runCatching { stakingParachainScenarioRepository.getStaked(chainId, getCurrentRound(chainId).getOrThrow().current) } + suspend fun total(chainId: ChainId): Result { + return runCatching { stakingParachainScenarioRepository.total(chainId) } } fun selectedAccountStakingStateFlow( diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioRepository.kt index 3bfe553f20..c0a9638de0 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/parachain/StakingParachainScenarioRepository.kt @@ -31,7 +31,7 @@ import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindDelegati import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindDelegatorState import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindRound import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindSelectedCandidates -import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindStaked +import jp.co.soramitsu.staking.impl.data.network.blockhain.bindings.bindTotal import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map @@ -89,15 +89,15 @@ class StakingParachainScenarioRepository( ) } - suspend fun getStaked(chainId: ChainId, currentRound: BigInteger): BigInteger { + suspend fun total(chainId: ChainId): BigInteger { return remoteStorage.query( chainId = chainId, keyBuilder = { runtime -> - val storage = runtime.metadata.parachainStakingOrNull()?.storage("Staked") - storage?.storageKey(runtime, currentRound) + val storage = runtime.metadata.parachainStakingOrNull()?.storage("Total") + storage?.storageKey(runtime) }, binding = { scale, runtime -> - scale?.let { bindStaked(it, runtime) } ?: incompatible() + scale?.let { bindTotal(it, runtime) } ?: incompatible() } ) } From ad0d206814a202ab97afc96c095cd08f4c047ea0 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Apr 2024 15:26:05 +0700 Subject: [PATCH 10/11] fixed PR comment --- .../settings/RecommendationSettingsProvider.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt index 88cbf1ab4f..54d6b630c2 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/recommendations/settings/RecommendationSettingsProvider.kt @@ -50,10 +50,7 @@ abstract class RecommendationSettingsProvider { private val maximumValidatorsPerNominator: Int ) : RecommendationSettingsProvider() { - override val alwaysEnabledFilters = listOf( -// BlockProducerFilters.ValidatorFilter.HasBlocked - ) - + override val alwaysEnabledFilters: List = emptyList() override val customizableFilters: List> = listOf( BlockProducerFilters.ValidatorFilter.NotSlashedFilter, BlockProducerFilters.ValidatorFilter.HasIdentity, From ae28077989500d941ceb5410fb041135ec365a2c Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Apr 2024 15:59:32 +0700 Subject: [PATCH 11/11] increase build number --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a7993e1599..babc5df312 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext { // App version versionName = '3.4.4' - versionCode = 171 + versionCode = 172 // SDK and tools compileSdkVersion = 34