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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 191 KiB

@@ -7,7 +7,7 @@
<clip-path <clip-path
android:pathData="M0,0h24v24h-24z"/> android:pathData="M0,0h24v24h-24z"/>
<path <path
android:pathData="M24,12V12.315C22.039,12.625 17.834,13.352 15.767,14.142C15.029,14.426 14.442,15.008 14.153,15.74C13.357,17.797 12.625,22.028 12.315,24H11.685C11.37,22.034 10.643,17.802 9.847,15.74C9.558,15.003 8.971,14.42 8.233,14.142C6.166,13.352 1.961,12.625 0,12.315V11.685C1.961,11.375 6.166,10.648 8.233,9.858C8.971,9.574 9.558,8.992 9.847,8.26C10.643,6.203 11.375,1.972 11.685,0H12.315C12.63,1.966 13.357,6.198 14.153,8.26C14.442,8.997 15.029,9.58 15.767,9.858C17.834,10.648 22.039,11.375 24,11.685V12Z" android:pathData="M12,2.3C13.4,5.4 16.4,7.3 17.6,10.5C18.8,13.8 17.6,17.1 16.4,19C15.2,20.9 13.4,22.3 12,22.7C10.6,22.3 8.8,20.9 7.6,19C6.4,17.1 5.2,13.8 6.4,10.5C7.6,7.3 10.6,5.4 12,2.3Z"
android:fillColor="#1F78FF"/> android:fillColor="#1F78FF"/>
</group> </group>
</vector> </vector>
@@ -7,7 +7,7 @@
<clip-path <clip-path
android:pathData="M0,0h24v24h-24z"/> android:pathData="M0,0h24v24h-24z"/>
<path <path
android:pathData="M14.153,15.74C14.442,15.008 15.029,14.426 15.767,14.142C17.333,13.543 20.125,12.981 22.24,12.609C22.869,12.498 23.439,12.405 23.898,12.331C23.933,12.326 23.967,12.321 24,12.315V11.685C23.967,11.679 23.933,11.674 23.898,11.669C23.439,11.595 22.869,11.502 22.24,11.391C20.125,11.019 17.333,10.457 15.767,9.858C15.029,9.58 14.442,8.997 14.153,8.26C13.549,6.695 12.985,3.882 12.611,1.757C12.5,1.128 12.405,0.56 12.332,0.102C12.326,0.067 12.321,0.033 12.315,0H11.685C11.679,0.034 11.674,0.068 11.668,0.104C11.596,0.562 11.502,1.13 11.392,1.758C11.018,3.885 10.451,6.699 9.847,8.26C9.558,8.992 8.971,9.574 8.233,9.858C6.667,10.457 3.875,11.019 1.76,11.391C1.131,11.502 0.561,11.595 0.102,11.669C0.067,11.674 0.033,11.679 0,11.685V12.315C0.033,12.321 0.067,12.326 0.102,12.331C0.561,12.405 1.131,12.498 1.76,12.609C3.875,12.981 6.667,13.543 8.233,14.142C8.971,14.42 9.558,15.003 9.847,15.74C10.451,17.305 11.015,20.118 11.389,22.243C11.5,22.872 11.595,23.44 11.668,23.898C11.674,23.933 11.679,23.967 11.685,24H12.315C12.321,23.966 12.326,23.931 12.332,23.896C12.404,23.438 12.498,22.87 12.608,22.243C12.982,20.115 13.549,17.301 14.153,15.74ZM11.999,19.08C12.304,17.664 12.659,16.275 13.034,15.307L13.037,15.3C13.449,14.254 14.286,13.426 15.337,13.022L15.338,13.022C16.304,12.652 17.678,12.302 19.079,12C17.679,11.698 16.307,11.348 15.341,10.979C14.284,10.58 13.447,9.748 13.036,8.697L13.034,8.692C12.659,7.723 12.306,6.334 12.001,4.92C11.696,6.336 11.341,7.725 10.966,8.693L10.963,8.7C10.551,9.746 9.714,10.574 8.664,10.978L8.662,10.978C7.696,11.348 6.322,11.698 4.921,12C6.321,12.302 7.693,12.652 8.659,13.021C9.716,13.42 10.553,14.252 10.964,15.303L10.966,15.308C11.341,16.277 11.694,17.666 11.999,19.08Z" android:pathData="M12,2.3C13.4,5.4 16.4,7.3 17.6,10.5C18.8,13.8 17.6,17.1 16.4,19C15.2,20.9 13.4,22.3 12,22.7C10.6,22.3 8.8,20.9 7.6,19C6.4,17.1 5.2,13.8 6.4,10.5C7.6,7.3 10.6,5.4 12,2.3ZM12,5.5C12.7,7.6 14.7,8.9 15.3,11.2C15.9,13.5 15.3,15.5 14.5,17C13.7,18.5 13,19.6 12,20.1C11,19.6 10.3,18.5 9.5,17C8.7,15.5 8.1,13.5 8.7,11.2C9.3,8.9 11.3,7.6 12,5.5Z"
android:fillColor="#ffffff" android:fillColor="#ffffff"
android:fillAlpha="0.4" android:fillAlpha="0.4"
android:fillType="evenOdd"/> android:fillType="evenOdd"/>
@@ -212,7 +212,8 @@ class StakingFeatureModule {
bagListRepository: BagListRepository, bagListRepository: BagListRepository,
totalIssuanceRepository: TotalIssuanceRepository, totalIssuanceRepository: TotalIssuanceRepository,
eraTimeCalculatorFactory: EraTimeCalculatorFactory, eraTimeCalculatorFactory: EraTimeCalculatorFactory,
stakingConstantsRepository: StakingConstantsRepository stakingConstantsRepository: StakingConstantsRepository,
chainRegistry: ChainRegistry
) = StakingSharedComputation( ) = StakingSharedComputation(
stakingRepository = stakingRepository, stakingRepository = stakingRepository,
computationalCache = computationalCache, computationalCache = computationalCache,
@@ -221,7 +222,8 @@ class StakingFeatureModule {
bagListRepository = bagListRepository, bagListRepository = bagListRepository,
totalIssuanceRepository = totalIssuanceRepository, totalIssuanceRepository = totalIssuanceRepository,
eraTimeCalculatorFactory = eraTimeCalculatorFactory, eraTimeCalculatorFactory = eraTimeCalculatorFactory,
stakingConstantsRepository = stakingConstantsRepository stakingConstantsRepository = stakingConstantsRepository,
chainRegistry = chainRegistry
) )
@Provides @Provides
@@ -297,7 +299,8 @@ class StakingFeatureModule {
sessionRepository: SessionRepository, sessionRepository: SessionRepository,
chainStateRepository: ChainStateRepository, chainStateRepository: ChainStateRepository,
electionsSessionRegistry: ElectionsSessionRegistry, electionsSessionRegistry: ElectionsSessionRegistry,
) = EraTimeCalculatorFactory(stakingRepository, sessionRepository, chainStateRepository, electionsSessionRegistry) chainRegistry: ChainRegistry,
) = EraTimeCalculatorFactory(stakingRepository, sessionRepository, chainStateRepository, electionsSessionRegistry, chainRegistry)
@Provides @Provides
@FeatureScope @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.SessionRepository
import io.novafoundation.nova.feature_staking_impl.data.repository.consensus.ElectionsSessionRegistry import io.novafoundation.nova.feature_staking_impl.data.repository.consensus.ElectionsSessionRegistry
import io.novafoundation.nova.runtime.ext.timelineChainIdOrSelf import io.novafoundation.nova.runtime.ext.timelineChainIdOrSelf
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.repository.ChainStateRepository import io.novafoundation.nova.runtime.repository.ChainStateRepository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@@ -96,6 +97,7 @@ class EraTimeCalculatorFactory(
private val sessionRepository: SessionRepository, private val sessionRepository: SessionRepository,
private val chainStateRepository: ChainStateRepository, private val chainStateRepository: ChainStateRepository,
private val electionsSessionRegistry: ElectionsSessionRegistry, private val electionsSessionRegistry: ElectionsSessionRegistry,
private val chainRegistry: ChainRegistry,
) { ) {
suspend fun create( suspend fun create(
@@ -103,8 +105,8 @@ class EraTimeCalculatorFactory(
activeEraFlow: Flow<EraIndex> activeEraFlow: Flow<EraIndex>
): Flow<EraTimeCalculator> { ): Flow<EraTimeCalculator> {
val stakingChain = stakingOption.chain val stakingChain = stakingOption.chain
val stakingChainId = stakingChain.id
val timelineChainId = stakingChain.timelineChainIdOrSelf() val timelineChainId = stakingChain.timelineChainIdOrSelf()
val timelineChain = chainRegistry.getChain(timelineChainId)
val electionsSession = electionsSessionRegistry.electionsSessionFor(stakingOption) val electionsSession = electionsSessionRegistry.electionsSessionFor(stakingOption)
@@ -112,7 +114,7 @@ class EraTimeCalculatorFactory(
val sessionLength = electionsSession.sessionLength(timelineChainId) val sessionLength = electionsSession.sessionLength(timelineChainId)
val eraAndStartSessionIndex = activeEraFlow.map { activeEra -> val eraAndStartSessionIndex = activeEraFlow.map { activeEra ->
val eraStartSessionIndex = stakingRepository.eraStartSessionIndex(stakingChainId, activeEra) val eraStartSessionIndex = stakingRepository.eraStartSessionIndex(timelineChainId, activeEra)
activeEra to eraStartSessionIndex activeEra to eraStartSessionIndex
} }
@@ -124,7 +126,7 @@ class EraTimeCalculatorFactory(
) { (activeEra, eraStartSessionIndex), currentSessionIndex, currentEpochIndex, currentSlot -> ) { (activeEra, eraStartSessionIndex), currentSessionIndex, currentEpochIndex, currentSlot ->
EraTimeCalculator( EraTimeCalculator(
startTimeStamp = System.currentTimeMillis().toBigInteger(), startTimeStamp = System.currentTimeMillis().toBigInteger(),
eraLength = stakingRepository.eraLength(stakingChain), eraLength = stakingRepository.eraLength(timelineChain),
blockCreationTime = chainStateRepository.predictedBlockTime(timelineChainId), blockCreationTime = chainStateRepository.predictedBlockTime(timelineChainId),
currentSessionIndex = currentSessionIndex, currentSessionIndex = currentSessionIndex,
currentEpochIndex = currentEpochIndex ?: 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.RewardCalculator
import io.novafoundation.nova.feature_staking_impl.domain.rewards.RewardCalculatorFactory 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.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.ChainWithAsset
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
@@ -43,15 +45,18 @@ class StakingSharedComputation(
private val bagListRepository: BagListRepository, private val bagListRepository: BagListRepository,
private val totalIssuanceRepository: TotalIssuanceRepository, private val totalIssuanceRepository: TotalIssuanceRepository,
private val eraTimeCalculatorFactory: EraTimeCalculatorFactory, private val eraTimeCalculatorFactory: EraTimeCalculatorFactory,
private val stakingConstantsRepository: StakingConstantsRepository private val stakingConstantsRepository: StakingConstantsRepository,
private val chainRegistry: ChainRegistry
) { ) {
fun eraCalculatorFlow(stakingOption: StakingOption, scope: CoroutineScope): Flow<EraTimeCalculator> { 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" val key = "ERA_TIME_CALCULATOR:$chainId"
return computationalCache.useSharedFlow(key, scope) { return computationalCache.useSharedFlow(key, scope) {
val activeEraFlow = activeEraFlow(chainId, scope) val activeEraFlow = activeEraFlow(timelineChainId, scope)
eraTimeCalculatorFactory.create(stakingOption, activeEraFlow) eraTimeCalculatorFactory.create(stakingOption, activeEraFlow)
} }
@@ -79,14 +84,17 @@ class StakingSharedComputation(
val key = "MIN_STAKE:$chainId" val key = "MIN_STAKE:$chainId"
return computationalCache.useSharedFlow(key, scope) { return computationalCache.useSharedFlow(key, scope) {
val minBond = stakingRepository.minimumNominatorBond(chainId) val chain = chainRegistry.getChain(chainId)
val bagListLocator = bagListRepository.bagListLocatorOrNull(chainId) val timelineChainId = chain.timelineChainIdOrSelf()
val totalIssuance = totalIssuanceRepository.getTotalIssuance(chainId)
val bagListScoreConverter = BagListScoreConverter.U128(totalIssuance)
val maxElectingVoters = bagListRepository.maxElectingVotes(chainId)
val bagListSize = bagListRepository.bagListSize(chainId)
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( val minStake = minimumStake(
exposures = exposures.values, exposures = exposures.values,
minimumNominatorBond = minBond, 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.TURING
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.Asset.StakingType.UNSUPPORTED 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.multiNetwork.chain.model.ChainId
import io.novafoundation.nova.runtime.ext.timelineChainIdOrSelf
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -48,7 +49,10 @@ class RewardCalculatorFactory(
validatorsPrefs: AccountIdMap<ValidatorPrefs?>, validatorsPrefs: AccountIdMap<ValidatorPrefs?>,
scope: CoroutineScope scope: CoroutineScope
): RewardCalculator = withContext(Dispatchers.Default) { ): 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 validators = exposures.keys.mapNotNull { accountIdHex ->
val exposure = exposures[accountIdHex] ?: accountIdNotFound(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) stakingOption.createRewardCalculator(validators, totalIssuance, scope)
} }
@@ -85,10 +95,16 @@ class RewardCalculatorFactory(
val custom = customRelayChainCalculator(validators, totalIssuance, scope) val custom = customRelayChainCalculator(validators, totalIssuance, scope)
if (custom != null) return custom if (custom != null) return custom
val activePublicParachains = parasRepository.activePublicParachains(assetWithChain.chain.id) val timelineChainId = chain.timelineChainIdOrSelf()
val inflationConfig = InflationConfig.create(chain.id, activePublicParachains) 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) ALEPH_ZERO -> AlephZeroRewardCalculator(validators, chainAsset = assetWithChain.asset)
+2320 -2434
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -8,9 +8,9 @@ android {
buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/android/chains.json\"" buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/android/chains.json\""
buildConfigField "String", "EVM_ASSETS_URL", "\"https://wallet.pezkuwichain.io/evm_assets.json\"" buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/assets/evm/v3/assets.json\""
buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://wallet.pezkuwichain.io/pre_configured_chains.json\"" buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/preConfigured/chains.json\""
buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://wallet.pezkuwichain.io/chain_details\"" buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/preConfigured/details\""
buildConfigField "String", "TEST_CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/tests/chains_for_testBalance.json\"" buildConfigField "String", "TEST_CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/tests/chains_for_testBalance.json\""
@@ -28,9 +28,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/android/chains.json\"" buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/android/chains.json\""
buildConfigField "String", "EVM_ASSETS_URL", "\"https://wallet.pezkuwichain.io/evm_assets.json\"" buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/assets/evm/v3/assets.json\""
buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://wallet.pezkuwichain.io/pre_configured_chains.json\"" buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/preConfigured/chains.json\""
buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://wallet.pezkuwichain.io/chain_details\"" buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/chains/v22/preConfigured/details\""
} }
} }
namespace 'io.novafoundation.nova.runtime' namespace 'io.novafoundation.nova.runtime'
+1 -1
View File
@@ -1 +1 @@
VERSION_CODE=103 VERSION_CODE=159