diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/SubstrateSdkExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/SubstrateSdkExt.kt index c756602..932a29e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/SubstrateSdkExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/SubstrateSdkExt.kt @@ -257,7 +257,7 @@ fun Module.constantOrNull(name: String) = constants[name] fun RuntimeMetadata.staking() = module(Modules.STAKING) -fun RuntimeMetadata.voterListOrNull() = firstExistingModuleOrNull(Modules.VOTER_LIST, Modules.BAG_LIST) +fun RuntimeMetadata.voterListOrNull() = firstExistingModuleOrNull(Modules.VOTER_LIST, Modules.BAG_LIST, Modules.VOTER_BAGS_LIST) fun RuntimeMetadata.voterListName(): String = requireNotNull(voterListOrNull()).name fun RuntimeMetadata.system() = module(Modules.SYSTEM) @@ -632,6 +632,7 @@ object Modules { const val VOTER_LIST = "VoterList" const val BAG_LIST = "BagsList" + const val VOTER_BAGS_LIST = "VoterBagsList" const val ELECTION_PROVIDER_MULTI_PHASE = "ElectionProviderMultiPhase" diff --git a/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/signer/proxy/ProxyCallFilterFactory.kt b/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/signer/proxy/ProxyCallFilterFactory.kt index 648adbd..114d31b 100644 --- a/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/signer/proxy/ProxyCallFilterFactory.kt +++ b/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/signer/proxy/ProxyCallFilterFactory.kt @@ -42,6 +42,7 @@ class ProxyCallFilterFactory { WhiteListFilter(Modules.SLOTS), WhiteListFilter(Modules.AUCTIONS), WhiteListFilter(Modules.VOTER_LIST), + WhiteListFilter(Modules.VOTER_BAGS_LIST), WhiteListFilter(Modules.NOMINATION_POOLS), WhiteListFilter(Modules.FAST_UNSTAKE) ) @@ -62,6 +63,7 @@ class ProxyCallFilterFactory { WhiteListFilter(Modules.UTILITY), WhiteListFilter(Modules.FAST_UNSTAKE), WhiteListFilter(Modules.VOTER_LIST), + WhiteListFilter(Modules.VOTER_BAGS_LIST), WhiteListFilter(Modules.NOMINATION_POOLS) ) diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/BagListRepository.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/BagListRepository.kt index 54e0978..92d2484 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/BagListRepository.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/BagListRepository.kt @@ -42,15 +42,19 @@ class LocalBagListRepository( ) : BagListRepository { override suspend fun bagThresholds(chainId: ChainId): List? { - return chainRegistry.withRuntime(chainId) { - runtime.metadata.voterListOrNull()?.constant("BagThresholds")?.getAs(collectionOf(::score)) - } + return runCatching { + chainRegistry.withRuntime(chainId) { + runtime.metadata.voterListOrNull()?.constant("BagThresholds")?.getAs(collectionOf(::score)) + } + }.getOrNull() } override suspend fun bagListSize(chainId: ChainId): BigInteger? { - return localStorage.query(chainId) { - runtime.metadata.voterListOrNull()?.storage("CounterForListNodes")?.query(binding = ::bindNumber) - } + return runCatching { + localStorage.query(chainId) { + runtime.metadata.voterListOrNull()?.storage("CounterForListNodes")?.query(binding = ::bindNumber) + } + }.getOrNull() } override suspend fun maxElectingVotes(chainId: ChainId): BigInteger? { diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt index 90f2f30..0546e62 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt @@ -51,10 +51,6 @@ class RewardCalculatorFactory( val stakingChainId = stakingOption.assetWithChain.chain.parentId ?: stakingOption.assetWithChain.chain.id val totalIssuance = totalIssuanceRepository.getTotalIssuance(stakingChainId) - Log.d("PEZ_STAKING", "create(4-param) exposures=${exposures.size} validatorsPrefs=${validatorsPrefs.size}") - Log.d("PEZ_STAKING", "exposureKeys=${exposures.keys.take(3).map { it.take(16) }}") - Log.d("PEZ_STAKING", "prefKeys=${validatorsPrefs.keys.take(3).map { it.take(16) }}") - val validators = exposures.keys.mapNotNull { accountIdHex -> val exposure = exposures[accountIdHex] ?: accountIdNotFound(accountIdHex) val validatorPrefs = validatorsPrefs[accountIdHex] ?: return@mapNotNull null @@ -66,8 +62,6 @@ class RewardCalculatorFactory( ) } - Log.d("PEZ_STAKING", "totalIssuance=$totalIssuance validators=${validators.size} stakingChainId=${stakingChainId.take(12)}") - stakingOption.createRewardCalculator(validators, totalIssuance, stakingChainId, scope) } @@ -77,21 +71,11 @@ class RewardCalculatorFactory( // For parachains with a parent relay chain, staking exposures live on the relay chain val exposureChainId = chain.parentId ?: chainId - Log.d( - "PEZ_STAKING", - "RewardCalculatorFactory.create() chainId=${chainId.take(12)}" + - " exposureChainId=${exposureChainId.take(12)}" + - " stakingType=${stakingOption.additional.stakingType}" - ) - val activeEra = stakingRepository.getActiveEraIndex(exposureChainId) - Log.d("PEZ_STAKING", "ActiveEra: $activeEra for ${exposureChainId.take(12)}") val exposures = stakingRepository.getElectedValidatorsExposure(exposureChainId, activeEra) - Log.d("PEZ_STAKING", "Exposures: ${exposures.size}") val validatorsPrefs = stakingRepository.getValidatorPrefs(exposureChainId, exposures.keys) - Log.d("PEZ_STAKING", "ValidatorPrefs: ${validatorsPrefs.size}") create(stakingOption, exposures, validatorsPrefs, scope) } diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingProperties.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingProperties.kt index 7ad13a1..ae82c35 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingProperties.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingProperties.kt @@ -98,8 +98,10 @@ private class DirectStakingProperties( enoughAvailableToStake() } + private val stakingChainId = stakingOption.chain.parentId ?: stakingOption.chain.id + override suspend fun minStake(): Balance { - return stakingSharedComputation.minStake(stakingOption.chain.id, scope) + return stakingSharedComputation.minStake(stakingChainId, scope) } private fun StartMultiStakingValidationSystemBuilder.noConflictingStaking() { @@ -125,7 +127,7 @@ private class DirectStakingProperties( private fun StartMultiStakingValidationSystemBuilder.maximumNominatorsReached() { maximumNominatorsReached( stakingRepository = stakingRepository, - chainId = { stakingOption.chain.id }, + chainId = { stakingChainId }, errorProducer = { StartMultiStakingValidationFailure.MaxNominatorsReached(stakingType) } ) } diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingRecommendation.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingRecommendation.kt index 8125696..56f1ad1 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingRecommendation.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/setupAmount/direct/DirectStakingRecommendation.kt @@ -29,7 +29,8 @@ class DirectStakingRecommendation( override suspend fun recommendedSelection(stake: Balance): StartMultiStakingSelection { val provider = recommendationSettingsProvider.await() - val maximumValidatorsPerNominator = stakingConstantsRepository.maxValidatorsPerNominator(stakingOption.chain.id, stake) + val stakingChainId = stakingOption.chain.parentId ?: stakingOption.chain.id + val maximumValidatorsPerNominator = stakingConstantsRepository.maxValidatorsPerNominator(stakingChainId, stake) val recommendationSettings = provider.recommendedSettings(maximumValidatorsPerNominator) val recommendator = recommendator.await() diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt index 9354cb6..64f483b 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt @@ -45,20 +45,22 @@ class ValidatorProvider( ): List { val chain = stakingOption.assetWithChain.chain val chainId = chain.id + // For parachains (e.g. Asset Hub), staking validators live on the parent relay chain + val stakingChainId = chain.parentId ?: chainId val novaValidatorIds = validatorsPreferencesSource.getRecommendedValidatorIds(chainId) - val electedValidatorExposures = stakingSharedComputation.electedExposuresInActiveEra(chainId, scope) + val electedValidatorExposures = stakingSharedComputation.electedExposuresInActiveEra(stakingChainId, scope) val requestedValidatorIds = sources.allValidatorIds(chainId, electedValidatorExposures, novaValidatorIds) // we always need validator prefs for elected validators to construct reward calculator val validatorIdsToQueryPrefs = electedValidatorExposures.keys + requestedValidatorIds - val validatorPrefs = stakingRepository.getValidatorPrefs(chainId, validatorIdsToQueryPrefs) + val validatorPrefs = stakingRepository.getValidatorPrefs(stakingChainId, validatorIdsToQueryPrefs) val identities = identityRepository.getIdentitiesFromIdsHex(chainId, requestedValidatorIds) - val slashes = stakingRepository.getSlashes(chain.id, requestedValidatorIds) + val slashes = stakingRepository.getSlashes(stakingChainId, requestedValidatorIds) val rewardCalculator = rewardCalculatorFactory.create(stakingOption, electedValidatorExposures, validatorPrefs, scope) - val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId) + val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(stakingChainId) return requestedValidatorIds.map { accountIdHex -> val accountId = AccountIdKey.fromHex(accountIdHex).getOrThrow() diff --git a/pezkuwi-config/chains.json b/pezkuwi-config/chains.json index 1921da9..b87caaf 100644 --- a/pezkuwi-config/chains.json +++ b/pezkuwi-config/chains.json @@ -1,6 +1,6 @@ [ { - "chainId": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75", + "chainId": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca", "name": "Pezkuwi", "icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/tokens/colored/HEZ.svg", "addressPrefix": 42, @@ -72,13 +72,13 @@ "feeViaRuntimeCall": true, "disabledCheckMetadataHash": true, "stakingMaxElectingVoters": 22500, - "identityChain": "58269e9c184f721e0309332d90cafc410df1519a5dc27a5fd9b3bf5fd2d129f8", + "identityChain": "69a8d025ab7b63363935d7d9397e0f652826c94271c1bc55c4fdfe72cccf1cfa", "stakingWiki": "https://wiki.pezkuwichain.io/staking" } }, { - "chainId": "00d0e1d0581c3cd5c5768652d52f4520184018b44f56a2ae1e0dc9d65c00c948", - "parentId": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75", + "chainId": "e7c15092dcbe3f320260ddbbc685bfceed9125a3b3d8436db2766201dec3b949", + "parentId": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca", "name": "Pezkuwi Asset Hub", "icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/tokens/colored/PEZ.svg", "addressPrefix": 42, @@ -225,15 +225,15 @@ "disabledCheckMetadataHash": true, "relaychainAsNative": true, "stakingMaxElectingVoters": 22500, - "identityChain": "58269e9c184f721e0309332d90cafc410df1519a5dc27a5fd9b3bf5fd2d129f8", - "timelineChain": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75", + "identityChain": "69a8d025ab7b63363935d7d9397e0f652826c94271c1bc55c4fdfe72cccf1cfa", + "timelineChain": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca", "defaultBlockTime": 6000, "stakingWiki": "https://wiki.pezkuwichain.io/staking" } }, { - "chainId": "58269e9c184f721e0309332d90cafc410df1519a5dc27a5fd9b3bf5fd2d129f8", - "parentId": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75", + "chainId": "69a8d025ab7b63363935d7d9397e0f652826c94271c1bc55c4fdfe72cccf1cfa", + "parentId": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca", "name": "Pezkuwi People", "icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/chains/PezkuwiPeople.png", "addressPrefix": 42,