mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-22 05:38:02 +00:00
fix: resolve parentId for Asset Hub staking to relay chain
ValidatorProvider, DirectStakingProperties, and DirectStakingRecommendation were querying Asset Hub chainId for staking data (validators, exposures, minStake, maxNominations) but these live on the relay chain. Added chain.parentId resolution so parachain staking correctly routes to relay. Also: - Add VoterBagsList pallet support (Pezkuwi naming) - Wrap BagListRepository queries in runCatching for binding compat - Remove debug logging
This commit is contained in:
@@ -257,7 +257,7 @@ fun Module.constantOrNull(name: String) = constants[name]
|
|||||||
|
|
||||||
fun RuntimeMetadata.staking() = module(Modules.STAKING)
|
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.voterListName(): String = requireNotNull(voterListOrNull()).name
|
||||||
|
|
||||||
fun RuntimeMetadata.system() = module(Modules.SYSTEM)
|
fun RuntimeMetadata.system() = module(Modules.SYSTEM)
|
||||||
@@ -632,6 +632,7 @@ object Modules {
|
|||||||
|
|
||||||
const val VOTER_LIST = "VoterList"
|
const val VOTER_LIST = "VoterList"
|
||||||
const val BAG_LIST = "BagsList"
|
const val BAG_LIST = "BagsList"
|
||||||
|
const val VOTER_BAGS_LIST = "VoterBagsList"
|
||||||
|
|
||||||
const val ELECTION_PROVIDER_MULTI_PHASE = "ElectionProviderMultiPhase"
|
const val ELECTION_PROVIDER_MULTI_PHASE = "ElectionProviderMultiPhase"
|
||||||
|
|
||||||
|
|||||||
+2
@@ -42,6 +42,7 @@ class ProxyCallFilterFactory {
|
|||||||
WhiteListFilter(Modules.SLOTS),
|
WhiteListFilter(Modules.SLOTS),
|
||||||
WhiteListFilter(Modules.AUCTIONS),
|
WhiteListFilter(Modules.AUCTIONS),
|
||||||
WhiteListFilter(Modules.VOTER_LIST),
|
WhiteListFilter(Modules.VOTER_LIST),
|
||||||
|
WhiteListFilter(Modules.VOTER_BAGS_LIST),
|
||||||
WhiteListFilter(Modules.NOMINATION_POOLS),
|
WhiteListFilter(Modules.NOMINATION_POOLS),
|
||||||
WhiteListFilter(Modules.FAST_UNSTAKE)
|
WhiteListFilter(Modules.FAST_UNSTAKE)
|
||||||
)
|
)
|
||||||
@@ -62,6 +63,7 @@ class ProxyCallFilterFactory {
|
|||||||
WhiteListFilter(Modules.UTILITY),
|
WhiteListFilter(Modules.UTILITY),
|
||||||
WhiteListFilter(Modules.FAST_UNSTAKE),
|
WhiteListFilter(Modules.FAST_UNSTAKE),
|
||||||
WhiteListFilter(Modules.VOTER_LIST),
|
WhiteListFilter(Modules.VOTER_LIST),
|
||||||
|
WhiteListFilter(Modules.VOTER_BAGS_LIST),
|
||||||
WhiteListFilter(Modules.NOMINATION_POOLS)
|
WhiteListFilter(Modules.NOMINATION_POOLS)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -42,15 +42,19 @@ class LocalBagListRepository(
|
|||||||
) : BagListRepository {
|
) : BagListRepository {
|
||||||
|
|
||||||
override suspend fun bagThresholds(chainId: ChainId): List<BagListNode.Score>? {
|
override suspend fun bagThresholds(chainId: ChainId): List<BagListNode.Score>? {
|
||||||
return chainRegistry.withRuntime(chainId) {
|
return runCatching {
|
||||||
|
chainRegistry.withRuntime(chainId) {
|
||||||
runtime.metadata.voterListOrNull()?.constant("BagThresholds")?.getAs(collectionOf(::score))
|
runtime.metadata.voterListOrNull()?.constant("BagThresholds")?.getAs(collectionOf(::score))
|
||||||
}
|
}
|
||||||
|
}.getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun bagListSize(chainId: ChainId): BigInteger? {
|
override suspend fun bagListSize(chainId: ChainId): BigInteger? {
|
||||||
return localStorage.query(chainId) {
|
return runCatching {
|
||||||
|
localStorage.query(chainId) {
|
||||||
runtime.metadata.voterListOrNull()?.storage("CounterForListNodes")?.query(binding = ::bindNumber)
|
runtime.metadata.voterListOrNull()?.storage("CounterForListNodes")?.query(binding = ::bindNumber)
|
||||||
}
|
}
|
||||||
|
}.getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun maxElectingVotes(chainId: ChainId): BigInteger? {
|
override suspend fun maxElectingVotes(chainId: ChainId): BigInteger? {
|
||||||
|
|||||||
-16
@@ -51,10 +51,6 @@ class RewardCalculatorFactory(
|
|||||||
val stakingChainId = stakingOption.assetWithChain.chain.parentId ?: stakingOption.assetWithChain.chain.id
|
val stakingChainId = stakingOption.assetWithChain.chain.parentId ?: stakingOption.assetWithChain.chain.id
|
||||||
val totalIssuance = totalIssuanceRepository.getTotalIssuance(stakingChainId)
|
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 validators = exposures.keys.mapNotNull { accountIdHex ->
|
||||||
val exposure = exposures[accountIdHex] ?: accountIdNotFound(accountIdHex)
|
val exposure = exposures[accountIdHex] ?: accountIdNotFound(accountIdHex)
|
||||||
val validatorPrefs = validatorsPrefs[accountIdHex] ?: return@mapNotNull null
|
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)
|
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
|
// For parachains with a parent relay chain, staking exposures live on the relay chain
|
||||||
val exposureChainId = chain.parentId ?: chainId
|
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)
|
val activeEra = stakingRepository.getActiveEraIndex(exposureChainId)
|
||||||
Log.d("PEZ_STAKING", "ActiveEra: $activeEra for ${exposureChainId.take(12)}")
|
|
||||||
|
|
||||||
val exposures = stakingRepository.getElectedValidatorsExposure(exposureChainId, activeEra)
|
val exposures = stakingRepository.getElectedValidatorsExposure(exposureChainId, activeEra)
|
||||||
Log.d("PEZ_STAKING", "Exposures: ${exposures.size}")
|
|
||||||
|
|
||||||
val validatorsPrefs = stakingRepository.getValidatorPrefs(exposureChainId, exposures.keys)
|
val validatorsPrefs = stakingRepository.getValidatorPrefs(exposureChainId, exposures.keys)
|
||||||
Log.d("PEZ_STAKING", "ValidatorPrefs: ${validatorsPrefs.size}")
|
|
||||||
|
|
||||||
create(stakingOption, exposures, validatorsPrefs, scope)
|
create(stakingOption, exposures, validatorsPrefs, scope)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -98,8 +98,10 @@ private class DirectStakingProperties(
|
|||||||
enoughAvailableToStake()
|
enoughAvailableToStake()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val stakingChainId = stakingOption.chain.parentId ?: stakingOption.chain.id
|
||||||
|
|
||||||
override suspend fun minStake(): Balance {
|
override suspend fun minStake(): Balance {
|
||||||
return stakingSharedComputation.minStake(stakingOption.chain.id, scope)
|
return stakingSharedComputation.minStake(stakingChainId, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun StartMultiStakingValidationSystemBuilder.noConflictingStaking() {
|
private fun StartMultiStakingValidationSystemBuilder.noConflictingStaking() {
|
||||||
@@ -125,7 +127,7 @@ private class DirectStakingProperties(
|
|||||||
private fun StartMultiStakingValidationSystemBuilder.maximumNominatorsReached() {
|
private fun StartMultiStakingValidationSystemBuilder.maximumNominatorsReached() {
|
||||||
maximumNominatorsReached(
|
maximumNominatorsReached(
|
||||||
stakingRepository = stakingRepository,
|
stakingRepository = stakingRepository,
|
||||||
chainId = { stakingOption.chain.id },
|
chainId = { stakingChainId },
|
||||||
errorProducer = { StartMultiStakingValidationFailure.MaxNominatorsReached(stakingType) }
|
errorProducer = { StartMultiStakingValidationFailure.MaxNominatorsReached(stakingType) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -29,7 +29,8 @@ class DirectStakingRecommendation(
|
|||||||
|
|
||||||
override suspend fun recommendedSelection(stake: Balance): StartMultiStakingSelection {
|
override suspend fun recommendedSelection(stake: Balance): StartMultiStakingSelection {
|
||||||
val provider = recommendationSettingsProvider.await()
|
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 recommendationSettings = provider.recommendedSettings(maximumValidatorsPerNominator)
|
||||||
val recommendator = recommendator.await()
|
val recommendator = recommendator.await()
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -45,20 +45,22 @@ class ValidatorProvider(
|
|||||||
): List<Validator> {
|
): List<Validator> {
|
||||||
val chain = stakingOption.assetWithChain.chain
|
val chain = stakingOption.assetWithChain.chain
|
||||||
val chainId = chain.id
|
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 novaValidatorIds = validatorsPreferencesSource.getRecommendedValidatorIds(chainId)
|
||||||
val electedValidatorExposures = stakingSharedComputation.electedExposuresInActiveEra(chainId, scope)
|
val electedValidatorExposures = stakingSharedComputation.electedExposuresInActiveEra(stakingChainId, scope)
|
||||||
|
|
||||||
val requestedValidatorIds = sources.allValidatorIds(chainId, electedValidatorExposures, novaValidatorIds)
|
val requestedValidatorIds = sources.allValidatorIds(chainId, electedValidatorExposures, novaValidatorIds)
|
||||||
// we always need validator prefs for elected validators to construct reward calculator
|
// we always need validator prefs for elected validators to construct reward calculator
|
||||||
val validatorIdsToQueryPrefs = electedValidatorExposures.keys + requestedValidatorIds
|
val validatorIdsToQueryPrefs = electedValidatorExposures.keys + requestedValidatorIds
|
||||||
|
|
||||||
val validatorPrefs = stakingRepository.getValidatorPrefs(chainId, validatorIdsToQueryPrefs)
|
val validatorPrefs = stakingRepository.getValidatorPrefs(stakingChainId, validatorIdsToQueryPrefs)
|
||||||
val identities = identityRepository.getIdentitiesFromIdsHex(chainId, requestedValidatorIds)
|
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 rewardCalculator = rewardCalculatorFactory.create(stakingOption, electedValidatorExposures, validatorPrefs, scope)
|
||||||
val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId)
|
val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(stakingChainId)
|
||||||
|
|
||||||
return requestedValidatorIds.map { accountIdHex ->
|
return requestedValidatorIds.map { accountIdHex ->
|
||||||
val accountId = AccountIdKey.fromHex(accountIdHex).getOrThrow()
|
val accountId = AccountIdKey.fromHex(accountIdHex).getOrThrow()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"chainId": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75",
|
"chainId": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca",
|
||||||
"name": "Pezkuwi",
|
"name": "Pezkuwi",
|
||||||
"icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/tokens/colored/HEZ.svg",
|
"icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/tokens/colored/HEZ.svg",
|
||||||
"addressPrefix": 42,
|
"addressPrefix": 42,
|
||||||
@@ -72,13 +72,13 @@
|
|||||||
"feeViaRuntimeCall": true,
|
"feeViaRuntimeCall": true,
|
||||||
"disabledCheckMetadataHash": true,
|
"disabledCheckMetadataHash": true,
|
||||||
"stakingMaxElectingVoters": 22500,
|
"stakingMaxElectingVoters": 22500,
|
||||||
"identityChain": "58269e9c184f721e0309332d90cafc410df1519a5dc27a5fd9b3bf5fd2d129f8",
|
"identityChain": "69a8d025ab7b63363935d7d9397e0f652826c94271c1bc55c4fdfe72cccf1cfa",
|
||||||
"stakingWiki": "https://wiki.pezkuwichain.io/staking"
|
"stakingWiki": "https://wiki.pezkuwichain.io/staking"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"chainId": "00d0e1d0581c3cd5c5768652d52f4520184018b44f56a2ae1e0dc9d65c00c948",
|
"chainId": "e7c15092dcbe3f320260ddbbc685bfceed9125a3b3d8436db2766201dec3b949",
|
||||||
"parentId": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75",
|
"parentId": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca",
|
||||||
"name": "Pezkuwi Asset Hub",
|
"name": "Pezkuwi Asset Hub",
|
||||||
"icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/tokens/colored/PEZ.svg",
|
"icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/tokens/colored/PEZ.svg",
|
||||||
"addressPrefix": 42,
|
"addressPrefix": 42,
|
||||||
@@ -225,15 +225,15 @@
|
|||||||
"disabledCheckMetadataHash": true,
|
"disabledCheckMetadataHash": true,
|
||||||
"relaychainAsNative": true,
|
"relaychainAsNative": true,
|
||||||
"stakingMaxElectingVoters": 22500,
|
"stakingMaxElectingVoters": 22500,
|
||||||
"identityChain": "58269e9c184f721e0309332d90cafc410df1519a5dc27a5fd9b3bf5fd2d129f8",
|
"identityChain": "69a8d025ab7b63363935d7d9397e0f652826c94271c1bc55c4fdfe72cccf1cfa",
|
||||||
"timelineChain": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75",
|
"timelineChain": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca",
|
||||||
"defaultBlockTime": 6000,
|
"defaultBlockTime": 6000,
|
||||||
"stakingWiki": "https://wiki.pezkuwichain.io/staking"
|
"stakingWiki": "https://wiki.pezkuwichain.io/staking"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"chainId": "58269e9c184f721e0309332d90cafc410df1519a5dc27a5fd9b3bf5fd2d129f8",
|
"chainId": "69a8d025ab7b63363935d7d9397e0f652826c94271c1bc55c4fdfe72cccf1cfa",
|
||||||
"parentId": "bb4a61ab0c4b8c12f5eab71d0c86c482e03a275ecdafee678dea712474d33d75",
|
"parentId": "1aa94987791a5544e9667ec249d2cef1b8fdd6083c85b93fc37892d54a1156ca",
|
||||||
"name": "Pezkuwi People",
|
"name": "Pezkuwi People",
|
||||||
"icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/chains/PezkuwiPeople.png",
|
"icon": "https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/main/icons/chains/PezkuwiPeople.png",
|
||||||
"addressPrefix": 42,
|
"addressPrefix": 42,
|
||||||
|
|||||||
Reference in New Issue
Block a user