diff --git a/build.gradle b/build.gradle index 3500232981..82a2016493 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { // App version - versionName = '8.7.2' - versionCode = 156 + versionName = '8.7.3' + versionCode = 157 applicationId = "io.novafoundation.nova" releaseApplicationSuffix = "market" diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/bindings/InflationDistributionAccount.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/bindings/InflationDistributionAccount.kt new file mode 100644 index 0000000000..8db0571cc8 --- /dev/null +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/bindings/InflationDistributionAccount.kt @@ -0,0 +1,45 @@ +package io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings + +import io.novafoundation.nova.common.data.network.runtime.binding.bindAccountId +import io.novafoundation.nova.common.data.network.runtime.binding.bindList +import io.novafoundation.nova.common.data.network.runtime.binding.cast +import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct +import io.novafoundation.nova.common.utils.percentageToFraction +import io.novasama.substrate_sdk_android.runtime.AccountId +import java.math.BigInteger + +typealias Percent = BigInteger + +@JvmInline +value class InflationDistributionConfig(val accounts: List) + +class InflationDistributionAccount( + // Account which receives funds intended for parachain bond + val account: AccountId, + + // Percent of inflation set aside for parachain bond account + // Will be integer number (30%) + val percent: Percent +) + +fun InflationDistributionConfig.totalPercentAsFraction(): Double { + return accounts.sumOf { it.percent }.toDouble().percentageToFraction() +} + +fun bindParachainBondConfig(decoded: Any?): InflationDistributionConfig { + val distributionAccount = bindInflationDistributionAccount(decoded) + return InflationDistributionConfig(listOf(distributionAccount)) +} + +fun bindInflationDistributionConfig(decoded: Any?): InflationDistributionConfig { + return InflationDistributionConfig(bindList(decoded, ::bindInflationDistributionAccount)) +} + +private fun bindInflationDistributionAccount(decoded: Any?): InflationDistributionAccount = decoded.castToStruct().let { + InflationDistributionAccount( + account = bindAccountId(it["account"]), + percent = bindPercent(it["percent"]) + ) +} + +private fun bindPercent(dynamicInstance: Any?): Percent = dynamicInstance.cast() diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/bindings/ParachainBondConfig.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/bindings/ParachainBondConfig.kt deleted file mode 100644 index ae6b702090..0000000000 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/bindings/ParachainBondConfig.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings - -import io.novafoundation.nova.common.data.network.runtime.binding.bindAccountId -import io.novafoundation.nova.common.data.network.runtime.binding.cast -import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct -import io.novasama.substrate_sdk_android.runtime.AccountId -import java.math.BigInteger - -typealias Percent = BigInteger - -class ParachainBondConfig( - // Account which receives funds intended for parachain bond - val account: AccountId, - - // Percent of inflation set aside for parachain bond account - // Will be integer number (30%) - val percent: Percent -) - -fun bindParachainBondConfig(dynamicInstance: Any?): ParachainBondConfig = dynamicInstance.castToStruct().let { - ParachainBondConfig( - account = bindAccountId(it["account"]), - percent = bindPercent(it["percent"]) - ) -} - -fun bindPercent(dynamicInstance: Any?): Percent = dynamicInstance.cast() diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/blockhain/updaters/ParachainBondInfoUpdater.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/blockhain/updaters/InflationDistributionConfigUpdater.kt similarity index 74% rename from feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/blockhain/updaters/ParachainBondInfoUpdater.kt rename to feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/blockhain/updaters/InflationDistributionConfigUpdater.kt index f76103fc22..4e002e5c2e 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/blockhain/updaters/ParachainBondInfoUpdater.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/network/blockhain/updaters/InflationDistributionConfigUpdater.kt @@ -9,14 +9,18 @@ import io.novafoundation.nova.runtime.network.updaters.SingleStorageKeyUpdater import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot import io.novasama.substrate_sdk_android.runtime.metadata.storage import io.novasama.substrate_sdk_android.runtime.metadata.storageKey +import io.novasama.substrate_sdk_android.runtime.metadata.storageOrNull -class ParachainBondInfoUpdater( +class InflationDistributionConfigUpdater( stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, storageCache: StorageCache ) : SingleStorageKeyUpdater(GlobalScope, stakingSharedState, chainRegistry, storageCache), ParachainStakingUpdater { override suspend fun storageKey(runtime: RuntimeSnapshot, scopeValue: Unit): String { - return runtime.metadata.parachainStaking().storage("ParachainBondInfo").storageKey() + val parachainStaking = runtime.metadata.parachainStaking() + + return parachainStaking.storageOrNull("InflationDistributionInfo")?.storageKey() + ?: parachainStaking.storage("ParachainBondInfo").storageKey() } } diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/repository/RewardsRepository.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/repository/RewardsRepository.kt index a24608c858..377dfa47dd 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/repository/RewardsRepository.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/parachainStaking/repository/RewardsRepository.kt @@ -2,9 +2,11 @@ package io.novafoundation.nova.feature_staking_impl.data.parachainStaking.reposi import io.novafoundation.nova.common.data.network.runtime.binding.Perbill import io.novafoundation.nova.common.data.network.runtime.binding.bindPerbill +import io.novafoundation.nova.common.utils.hasStorage import io.novafoundation.nova.common.utils.parachainStaking +import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.InflationDistributionConfig import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.InflationInfo -import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.ParachainBondConfig +import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.bindInflationDistributionConfig import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.bindInflationInfo import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.bindParachainBondConfig import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId @@ -15,7 +17,7 @@ interface RewardsRepository { suspend fun getInflationInfo(chainId: ChainId): InflationInfo - suspend fun getParachainBondConfig(chainId: ChainId): ParachainBondConfig + suspend fun getInflationDistributionConfig(chainId: ChainId): InflationDistributionConfig suspend fun getCollatorCommission(chainId: ChainId): Perbill } @@ -29,9 +31,16 @@ class RealRewardsRepository( } } - override suspend fun getParachainBondConfig(chainId: ChainId): ParachainBondConfig { + override suspend fun getInflationDistributionConfig(chainId: ChainId): InflationDistributionConfig { return storageDataSource.query(chainId) { - runtime.metadata.parachainStaking().storage("ParachainBondInfo").query(binding = ::bindParachainBondConfig) + val parachainStaking = runtime.metadata.parachainStaking() + val usesMultipleDistributionAccounts = parachainStaking.hasStorage("InflationDistributionInfo") + + if (usesMultipleDistributionAccounts) { + parachainStaking.storage("InflationDistributionInfo").query(binding = ::bindInflationDistributionConfig) + } else { + parachainStaking.storage("ParachainBondInfo").query(binding = ::bindParachainBondConfig) + } } } diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/staking/parachain/ParachainStakingUpdatersModule.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/staking/parachain/ParachainStakingUpdatersModule.kt index ba57a111b3..f8b28d6331 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/staking/parachain/ParachainStakingUpdatersModule.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/staking/parachain/ParachainStakingUpdatersModule.kt @@ -13,7 +13,7 @@ import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.CurrentRoundUpdater import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.DelegatorStateUpdater import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.InflationConfigUpdater -import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.ParachainBondInfoUpdater +import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.InflationDistributionConfigUpdater import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.ScheduledDelegationRequestsUpdater import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.blockhain.updaters.TotalDelegatedUpdater import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.repository.CurrentRoundRepository @@ -98,7 +98,7 @@ class ParachainStakingUpdatersModule { storageCache: StorageCache, stakingSharedState: StakingSharedState, chainRegistry: ChainRegistry, - ) = ParachainBondInfoUpdater( + ) = InflationDistributionConfigUpdater( storageCache = storageCache, stakingSharedState = stakingSharedState, chainRegistry = chainRegistry @@ -141,7 +141,7 @@ class ParachainStakingUpdatersModule { currentRoundCollatorsUpdater: CurrentRoundCollatorsUpdater, totalDelegatedUpdater: TotalDelegatedUpdater, inflationConfigUpdater: InflationConfigUpdater, - parachainBondInfoUpdater: ParachainBondInfoUpdater, + inflationDistributionConfigUpdater: InflationDistributionConfigUpdater, collatorCommissionUpdater: CollatorCommissionUpdater, scheduledDelegationRequestsUpdater: ScheduledDelegationRequestsUpdater, ) = StakingUpdaters.Group( @@ -150,7 +150,7 @@ class ParachainStakingUpdatersModule { currentRoundCollatorsUpdater, totalDelegatedUpdater, inflationConfigUpdater, - parachainBondInfoUpdater, + inflationDistributionConfigUpdater, collatorCommissionUpdater, scheduledDelegationRequestsUpdater ) diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculator.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculator.kt index 0325b63b02..affed05dc5 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculator.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculator.kt @@ -1,9 +1,9 @@ package io.novafoundation.nova.feature_staking_impl.domain.parachainStaking.rewards import io.novafoundation.nova.common.data.network.runtime.binding.Perbill -import io.novafoundation.nova.common.utils.percentageToFraction +import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.InflationDistributionConfig import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.InflationInfo -import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.ParachainBondConfig +import io.novafoundation.nova.feature_staking_impl.data.parachainStaking.network.bindings.totalPercentAsFraction import io.novafoundation.nova.feature_staking_impl.domain.rewards.PeriodReturns import io.novasama.substrate_sdk_android.extensions.toHexString import io.novasama.substrate_sdk_android.runtime.AccountId @@ -31,7 +31,7 @@ interface ParachainStakingRewardCalculator { private const val DAYS_IN_YEAR = 365 class RealParachainStakingRewardCalculator( - private val bondConfig: ParachainBondConfig, + private val inflationDistributionConfig: InflationDistributionConfig, inflationInfo: InflationInfo, totalIssuance: BigInteger, totalStaked: BigInteger, @@ -95,10 +95,8 @@ class RealParachainStakingRewardCalculator( } private fun calculatorApr(collatorStake: Double): Double { - return annualReturn * (1 - bondConfig.percentageAsFraction() - collatorCommission.toDouble()) * (averageStake / collatorStake) + return annualReturn * (1 - inflationDistributionConfig.totalPercentAsFraction() - collatorCommission.toDouble()) * (averageStake / collatorStake) } - - private fun ParachainBondConfig.percentageAsFraction() = percent.toDouble().percentageToFraction() } fun ParachainStakingRewardCalculator.maximumAnnualApr() = maximumGain(DAYS_IN_YEAR) diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculatorFactory.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculatorFactory.kt index ba5e2f4a52..3bf9c1d99a 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculatorFactory.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/parachainStaking/rewards/ParachainStakingRewardCalculatorFactory.kt @@ -48,7 +48,7 @@ class ParachainStakingRewardCalculatorFactory( val circulating = additionalIssuance + totalIssuance return RealParachainStakingRewardCalculator( - bondConfig = rewardsRepository.getParachainBondConfig(chainId), + inflationDistributionConfig = rewardsRepository.getInflationDistributionConfig(chainId), inflationInfo = rewardsRepository.getInflationInfo(chainId), totalIssuance = circulating, totalStaked = currentRoundRepository.totalStaked(chainId), @@ -61,7 +61,7 @@ class ParachainStakingRewardCalculatorFactory( chainId: ChainId, snapshots: AccountIdMap ) = RealParachainStakingRewardCalculator( - bondConfig = rewardsRepository.getParachainBondConfig(chainId), + inflationDistributionConfig = rewardsRepository.getInflationDistributionConfig(chainId), inflationInfo = rewardsRepository.getInflationInfo(chainId), totalIssuance = commonStakingRepository.getTotalIssuance(chainId), totalStaked = currentRoundRepository.totalStaked(chainId),