feat: sync chains config, rebrand assets icon, update onboarding image

- Sync chains.json from pezkuwi-wallet-utils (staking on Asset Hub)
- Replace Nova star with Nevruz fire icon on Assets bottom nav tab
- Update onboarding welcome background image (all DPI variants)
- Fix build URLs to point to pezkuwi-wallet-utils GitHub raw
- Update staking reward calculator and era computation
- Bump version code to 159
This commit is contained in:
2026-02-10 16:03:09 +03:00
parent 62ffa5d959
commit f475ff858b
15 changed files with 2378 additions and 2463 deletions
@@ -212,7 +212,8 @@ class StakingFeatureModule {
bagListRepository: BagListRepository,
totalIssuanceRepository: TotalIssuanceRepository,
eraTimeCalculatorFactory: EraTimeCalculatorFactory,
stakingConstantsRepository: StakingConstantsRepository
stakingConstantsRepository: StakingConstantsRepository,
chainRegistry: ChainRegistry
) = StakingSharedComputation(
stakingRepository = stakingRepository,
computationalCache = computationalCache,
@@ -221,7 +222,8 @@ class StakingFeatureModule {
bagListRepository = bagListRepository,
totalIssuanceRepository = totalIssuanceRepository,
eraTimeCalculatorFactory = eraTimeCalculatorFactory,
stakingConstantsRepository = stakingConstantsRepository
stakingConstantsRepository = stakingConstantsRepository,
chainRegistry = chainRegistry
)
@Provides
@@ -297,7 +299,8 @@ class StakingFeatureModule {
sessionRepository: SessionRepository,
chainStateRepository: ChainStateRepository,
electionsSessionRegistry: ElectionsSessionRegistry,
) = EraTimeCalculatorFactory(stakingRepository, sessionRepository, chainStateRepository, electionsSessionRegistry)
chainRegistry: ChainRegistry,
) = EraTimeCalculatorFactory(stakingRepository, sessionRepository, chainStateRepository, electionsSessionRegistry, chainRegistry)
@Provides
@FeatureScope
@@ -9,6 +9,7 @@ import io.novafoundation.nova.feature_staking_impl.data.chain
import io.novafoundation.nova.feature_staking_impl.data.repository.SessionRepository
import io.novafoundation.nova.feature_staking_impl.data.repository.consensus.ElectionsSessionRegistry
import io.novafoundation.nova.runtime.ext.timelineChainIdOrSelf
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.repository.ChainStateRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -96,6 +97,7 @@ class EraTimeCalculatorFactory(
private val sessionRepository: SessionRepository,
private val chainStateRepository: ChainStateRepository,
private val electionsSessionRegistry: ElectionsSessionRegistry,
private val chainRegistry: ChainRegistry,
) {
suspend fun create(
@@ -103,8 +105,8 @@ class EraTimeCalculatorFactory(
activeEraFlow: Flow<EraIndex>
): Flow<EraTimeCalculator> {
val stakingChain = stakingOption.chain
val stakingChainId = stakingChain.id
val timelineChainId = stakingChain.timelineChainIdOrSelf()
val timelineChain = chainRegistry.getChain(timelineChainId)
val electionsSession = electionsSessionRegistry.electionsSessionFor(stakingOption)
@@ -112,7 +114,7 @@ class EraTimeCalculatorFactory(
val sessionLength = electionsSession.sessionLength(timelineChainId)
val eraAndStartSessionIndex = activeEraFlow.map { activeEra ->
val eraStartSessionIndex = stakingRepository.eraStartSessionIndex(stakingChainId, activeEra)
val eraStartSessionIndex = stakingRepository.eraStartSessionIndex(timelineChainId, activeEra)
activeEra to eraStartSessionIndex
}
@@ -124,7 +126,7 @@ class EraTimeCalculatorFactory(
) { (activeEra, eraStartSessionIndex), currentSessionIndex, currentEpochIndex, currentSlot ->
EraTimeCalculator(
startTimeStamp = System.currentTimeMillis().toBigInteger(),
eraLength = stakingRepository.eraLength(stakingChain),
eraLength = stakingRepository.eraLength(timelineChain),
blockCreationTime = chainStateRepository.predictedBlockTime(timelineChainId),
currentSessionIndex = currentSessionIndex,
currentEpochIndex = currentEpochIndex ?: currentSessionIndex,
@@ -18,6 +18,8 @@ import io.novafoundation.nova.feature_staking_impl.domain.minimumStake
import io.novafoundation.nova.feature_staking_impl.domain.rewards.RewardCalculator
import io.novafoundation.nova.feature_staking_impl.domain.rewards.RewardCalculatorFactory
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
import io.novafoundation.nova.runtime.ext.timelineChainIdOrSelf
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.multiNetwork.ChainWithAsset
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
@@ -43,15 +45,18 @@ class StakingSharedComputation(
private val bagListRepository: BagListRepository,
private val totalIssuanceRepository: TotalIssuanceRepository,
private val eraTimeCalculatorFactory: EraTimeCalculatorFactory,
private val stakingConstantsRepository: StakingConstantsRepository
private val stakingConstantsRepository: StakingConstantsRepository,
private val chainRegistry: ChainRegistry
) {
fun eraCalculatorFlow(stakingOption: StakingOption, scope: CoroutineScope): Flow<EraTimeCalculator> {
val chainId = stakingOption.assetWithChain.chain.id
val chain = stakingOption.assetWithChain.chain
val chainId = chain.id
val timelineChainId = chain.timelineChainIdOrSelf()
val key = "ERA_TIME_CALCULATOR:$chainId"
return computationalCache.useSharedFlow(key, scope) {
val activeEraFlow = activeEraFlow(chainId, scope)
val activeEraFlow = activeEraFlow(timelineChainId, scope)
eraTimeCalculatorFactory.create(stakingOption, activeEraFlow)
}
@@ -79,14 +84,17 @@ class StakingSharedComputation(
val key = "MIN_STAKE:$chainId"
return computationalCache.useSharedFlow(key, scope) {
val minBond = stakingRepository.minimumNominatorBond(chainId)
val bagListLocator = bagListRepository.bagListLocatorOrNull(chainId)
val totalIssuance = totalIssuanceRepository.getTotalIssuance(chainId)
val bagListScoreConverter = BagListScoreConverter.U128(totalIssuance)
val maxElectingVoters = bagListRepository.maxElectingVotes(chainId)
val bagListSize = bagListRepository.bagListSize(chainId)
val chain = chainRegistry.getChain(chainId)
val timelineChainId = chain.timelineChainIdOrSelf()
electedExposuresWithActiveEraFlow(chainId, scope).map { (exposures, activeEraIndex) ->
val minBond = stakingRepository.minimumNominatorBond(timelineChainId)
val bagListLocator = bagListRepository.bagListLocatorOrNull(timelineChainId)
val totalIssuance = totalIssuanceRepository.getTotalIssuance(timelineChainId)
val bagListScoreConverter = BagListScoreConverter.U128(totalIssuance)
val maxElectingVoters = bagListRepository.maxElectingVotes(timelineChainId)
val bagListSize = bagListRepository.bagListSize(timelineChainId)
electedExposuresWithActiveEraFlow(timelineChainId, scope).map { (exposures, activeEraIndex) ->
val minStake = minimumStake(
exposures = exposures.values,
minimumNominatorBond = minBond,
@@ -28,6 +28,7 @@ import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.Asset.Staki
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.Asset.StakingType.TURING
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.Asset.StakingType.UNSUPPORTED
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
import io.novafoundation.nova.runtime.ext.timelineChainIdOrSelf
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -48,7 +49,10 @@ class RewardCalculatorFactory(
validatorsPrefs: AccountIdMap<ValidatorPrefs?>,
scope: CoroutineScope
): RewardCalculator = withContext(Dispatchers.Default) {
val totalIssuance = totalIssuanceRepository.getTotalIssuance(stakingOption.assetWithChain.chain.id)
val timelineChainId = stakingOption.assetWithChain.chain.timelineChainIdOrSelf()
val totalIssuance = totalIssuanceRepository.getTotalIssuance(timelineChainId)
Log.d("RewardCalculatorFactory", "totalIssuance for $timelineChainId: $totalIssuance")
val validators = exposures.keys.mapNotNull { accountIdHex ->
val exposure = exposures[accountIdHex] ?: accountIdNotFound(accountIdHex)
@@ -61,6 +65,12 @@ class RewardCalculatorFactory(
)
}
Log.d("RewardCalculatorFactory", "Validators count for reward calculation: ${validators.size}")
if (validators.isNotEmpty()) {
val totalStaked = validators.sumOf { it.totalStake }
Log.d("RewardCalculatorFactory", "Total staked: $totalStaked, stakedPortion: ${totalStaked.toDouble() / totalIssuance.toDouble()}")
}
stakingOption.createRewardCalculator(validators, totalIssuance, scope)
}
@@ -85,10 +95,16 @@ class RewardCalculatorFactory(
val custom = customRelayChainCalculator(validators, totalIssuance, scope)
if (custom != null) return custom
val activePublicParachains = parasRepository.activePublicParachains(assetWithChain.chain.id)
val inflationConfig = InflationConfig.create(chain.id, activePublicParachains)
val timelineChainId = chain.timelineChainIdOrSelf()
val activePublicParachains = parasRepository.activePublicParachains(timelineChainId)
Log.d("RewardCalculatorFactory", "activePublicParachains for $timelineChainId: $activePublicParachains")
RewardCurveInflationRewardCalculator(validators, totalIssuance, inflationConfig)
val inflationConfig = InflationConfig.create(timelineChainId, activePublicParachains)
Log.d("RewardCalculatorFactory", "Using Default InflationConfig for $timelineChainId")
val calculator = RewardCurveInflationRewardCalculator(validators, totalIssuance, inflationConfig)
Log.d("RewardCalculatorFactory", "expectedAPY: ${calculator.expectedAPY}, maxAPY: ${calculator.maxAPY}")
calculator
}
ALEPH_ZERO -> AlephZeroRewardCalculator(validators, chainAsset = assetWithChain.asset)