Skip to content

Commit

Permalink
Merge pull request #1724 from novasamatech/hotfix/9.0.2
Browse files Browse the repository at this point in the history
Hotfix/9.0.2
  • Loading branch information
valentunn authored Nov 20, 2024
2 parents 2d4cbaf + ab171b5 commit 5dafb75
Show file tree
Hide file tree
Showing 17 changed files with 187 additions and 35 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
buildscript {
ext {
// App version
versionName = '9.0.1'
versionCode = 159
versionName = '9.0.2'
versionCode = 161

applicationId = "io.novafoundation.nova"
releaseApplicationSuffix = "market"
Expand Down Expand Up @@ -51,7 +51,7 @@ buildscript {

web3jVersion = '4.9.5'

substrateSdkVersion = '2.2.0'
substrateSdkVersion = '2.3.0'

gifVersion = '1.2.19'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ internal class HydrationConversionFeePayment(
) : FeePayment {

override suspend fun modifyExtrinsic(extrinsicBuilder: ExtrinsicBuilder) {
val baseCall = extrinsicBuilder.getCall()
val baseCalls = extrinsicBuilder.getCalls()
extrinsicBuilder.resetCalls()

extrinsicBuilder.setFeeCurrency(hydraDxAssetIdConverter.toOnChainIdOrThrow(paymentAsset))
extrinsicBuilder.call(baseCall)
extrinsicBuilder.calls(baseCalls)
extrinsicBuilder.setFeeCurrency(hydraDxAssetIdConverter.systemAssetId)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_staking_api.domain.api
import io.novafoundation.nova.feature_account_api.data.model.AccountIdMap
import io.novafoundation.nova.feature_staking_api.domain.model.EraIndex
import io.novafoundation.nova.feature_staking_api.domain.model.Exposure
import io.novafoundation.nova.feature_staking_api.domain.model.InflationPredictionInfo
import io.novafoundation.nova.feature_staking_api.domain.model.RewardDestination
import io.novafoundation.nova.feature_staking_api.domain.model.SlashingSpans
import io.novafoundation.nova.feature_staking_api.domain.model.StakingLedger
Expand Down Expand Up @@ -58,6 +59,8 @@ interface StakingRepository {
suspend fun maxNominators(chainId: ChainId): BigInteger?

suspend fun nominatorsCount(chainId: ChainId): BigInteger?

suspend fun getInflationPredictionInfo(chainId: ChainId): InflationPredictionInfo
}

suspend fun StakingRepository.historicalEras(chainId: ChainId): List<BigInteger> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.novafoundation.nova.feature_staking_api.domain.model

import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
import io.novafoundation.nova.common.data.network.runtime.binding.castToList
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
import io.novafoundation.nova.common.utils.divideToDecimal
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
import kotlin.math.roundToInt
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days

class InflationPredictionInfo(
val nextMint: NextMint
) {

class NextMint(
val toStakers: Balance,
val toTreasury: Balance
)

companion object {

fun fromDecoded(decoded: Any?): InflationPredictionInfo {
val asStruct = decoded.castToStruct()

return InflationPredictionInfo(
nextMint = bindNextMint(asStruct["nextMint"])
)
}

private fun bindNextMint(decoded: Any?): NextMint {
val (toStakersRaw, toTreasuryRaw) = decoded.castToList()

return NextMint(
toStakers = bindNumber(toStakersRaw),
toTreasury = bindNumber(toTreasuryRaw)
)
}
}
}

fun InflationPredictionInfo.calculateStakersInflation(totalIssuance: Balance, eraDuration: Duration): Double {
val periodsInYear = (365.days / eraDuration).roundToInt()
val inflationPerMint = nextMint.toStakers.divideToDecimal(totalIssuance)

return inflationPerMint.toDouble() * periodsInYear
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import io.novafoundation.nova.feature_staking_api.domain.model.Exposure
import io.novafoundation.nova.feature_staking_api.domain.model.ExposureOverview
import io.novafoundation.nova.feature_staking_api.domain.model.ExposurePage
import io.novafoundation.nova.feature_staking_api.domain.model.IndividualExposure
import io.novafoundation.nova.feature_staking_api.domain.model.InflationPredictionInfo
import io.novafoundation.nova.feature_staking_api.domain.model.Nominations
import io.novafoundation.nova.feature_staking_api.domain.model.SlashingSpans
import io.novafoundation.nova.feature_staking_api.domain.model.StakingLedger
Expand Down Expand Up @@ -43,6 +44,7 @@ import io.novafoundation.nova.feature_staking_impl.data.network.blockhain.update
import io.novafoundation.nova.feature_staking_impl.data.network.blockhain.updaters.activeEraStorageKey
import io.novafoundation.nova.feature_staking_impl.data.repository.datasource.StakingStoriesDataSource
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletConstants
import io.novafoundation.nova.runtime.call.MultiChainRuntimeCallsApi
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
Expand Down Expand Up @@ -75,6 +77,7 @@ class StakingRepositoryImpl(
private val chainRegistry: ChainRegistry,
private val stakingStoriesDataSource: StakingStoriesDataSource,
private val storageCache: StorageCache,
private val multiChainRuntimeCallsApi: MultiChainRuntimeCallsApi,
) : StakingRepository {

override suspend fun eraStartSessionIndex(chainId: ChainId, currentEra: BigInteger): EraIndex {
Expand Down Expand Up @@ -266,6 +269,17 @@ class StakingRepositoryImpl(
chainId = chainId
)

override suspend fun getInflationPredictionInfo(chainId: ChainId): InflationPredictionInfo {
val callApi = multiChainRuntimeCallsApi.forChain(chainId)

return callApi.call(
section = "Inflation",
method = "experimental_inflation_prediction_info",
arguments = emptyMap(),
returnBinding = InflationPredictionInfo::fromDecoded
)
}

private suspend fun <T> queryStorageIfExists(
chainId: ChainId,
storageName: String,
Expand Down Expand Up @@ -318,6 +332,7 @@ class StakingRepositoryImpl(
stashId,
prefs
)

nominations != null -> StakingState.Stash.Nominator(
chain,
chainAsset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ import io.novafoundation.nova.feature_staking_impl.data.repository.datasource.re
import io.novafoundation.nova.feature_staking_impl.data.repository.datasource.reward.PoolStakingRewardsDataSource
import io.novafoundation.nova.feature_staking_impl.data.repository.datasource.reward.RealStakingRewardsDataSourceRegistry
import io.novafoundation.nova.feature_staking_impl.data.repository.datasource.reward.StakingRewardsDataSourceRegistry
import io.novafoundation.nova.feature_staking_impl.data.validators.ValidatorsPreferencesSource
import io.novafoundation.nova.feature_staking_impl.data.validators.NovaValidatorsApi
import io.novafoundation.nova.feature_staking_impl.data.validators.RemoteValidatorsPreferencesSource
import io.novafoundation.nova.feature_staking_impl.data.validators.ValidatorsPreferencesSource
import io.novafoundation.nova.feature_staking_impl.di.staking.DefaultBulkRetriever
import io.novafoundation.nova.feature_staking_impl.di.staking.PayoutsBulkRetriever
import io.novafoundation.nova.feature_staking_impl.domain.StakingInteractor
Expand Down Expand Up @@ -177,15 +177,17 @@ class StakingFeatureModule {
stakingStoriesDataSource: StakingStoriesDataSource,
walletConstants: WalletConstants,
chainRegistry: ChainRegistry,
storageCache: StorageCache
storageCache: StorageCache,
multiChainRuntimeCallsApi: MultiChainRuntimeCallsApi
): StakingRepository = StakingRepositoryImpl(
accountStakingDao = accountStakingDao,
remoteStorage = remoteStorageSource,
localStorage = localStorageSource,
stakingStoriesDataSource = stakingStoriesDataSource,
walletConstants = walletConstants,
chainRegistry = chainRegistry,
storageCache = storageCache
storageCache = storageCache,
multiChainRuntimeCallsApi = multiChainRuntimeCallsApi
)

@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.novafoundation.nova.feature_staking_impl.domain.rewards

import io.novafoundation.nova.feature_staking_api.domain.model.InflationPredictionInfo
import io.novafoundation.nova.feature_staking_api.domain.model.calculateStakersInflation
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
import kotlin.time.Duration

class InflationPredictionInfoCalculator(
private val inflationPredictionInfo: InflationPredictionInfo,
private val eraDuration: Duration,
private val totalIssuance: Balance,
validators: List<RewardCalculationTarget>
) : InflationBasedRewardCalculator(validators, totalIssuance) {

override fun calculateYearlyInflation(stakedPortion: Double): Double {
return inflationPredictionInfo.calculateStakersInflation(totalIssuance, eraDuration)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import io.novafoundation.nova.feature_staking_impl.data.stakingType
import io.novafoundation.nova.feature_staking_impl.data.unwrapNominationPools
import io.novafoundation.nova.feature_staking_impl.domain.common.StakingSharedComputation
import io.novafoundation.nova.feature_staking_impl.domain.common.electedExposuresInActiveEra
import io.novafoundation.nova.feature_staking_impl.domain.common.eraTimeCalculator
import io.novafoundation.nova.feature_staking_impl.domain.error.accountIdNotFound
import io.novafoundation.nova.runtime.ext.Geneses
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
Expand Down Expand Up @@ -42,7 +43,8 @@ class RewardCalculatorFactory(
suspend fun create(
stakingOption: StakingOption,
exposures: AccountIdMap<Exposure>,
validatorsPrefs: AccountIdMap<ValidatorPrefs?>
validatorsPrefs: AccountIdMap<ValidatorPrefs?>,
scope: CoroutineScope
): RewardCalculator = withContext(Dispatchers.Default) {
val totalIssuance = totalIssuanceRepository.getTotalIssuance(stakingOption.assetWithChain.chain.id)

Expand All @@ -57,7 +59,7 @@ class RewardCalculatorFactory(
)
}

stakingOption.createRewardCalculator(validators, totalIssuance)
stakingOption.createRewardCalculator(validators, totalIssuance, scope)
}

suspend fun create(stakingOption: StakingOption, scope: CoroutineScope): RewardCalculator = withContext(Dispatchers.Default) {
Expand All @@ -66,13 +68,17 @@ class RewardCalculatorFactory(
val exposures = shareStakingSharedComputation.get().electedExposuresInActiveEra(chainId, scope)
val validatorsPrefs = stakingRepository.getValidatorPrefs(chainId, exposures.keys)

create(stakingOption, exposures, validatorsPrefs)
create(stakingOption, exposures, validatorsPrefs, scope)
}

private suspend fun StakingOption.createRewardCalculator(validators: List<RewardCalculationTarget>, totalIssuance: BigInteger): RewardCalculator {
private suspend fun StakingOption.createRewardCalculator(
validators: List<RewardCalculationTarget>,
totalIssuance: BigInteger,
scope: CoroutineScope
): RewardCalculator {
return when (unwrapNominationPools().stakingType) {
RELAYCHAIN, RELAYCHAIN_AURA -> {
val custom = customRelayChainCalculator(validators, totalIssuance)
val custom = customRelayChainCalculator(validators, totalIssuance, scope)
if (custom != null) return custom

val activePublicParachains = parasRepository.activePublicParachains(assetWithChain.chain.id)
Expand All @@ -88,10 +94,12 @@ class RewardCalculatorFactory(

private suspend fun StakingOption.customRelayChainCalculator(
validators: List<RewardCalculationTarget>,
totalIssuance: BigInteger
totalIssuance: BigInteger,
scope: CoroutineScope
): RewardCalculator? {
return when (chain.id) {
Chain.Geneses.VARA -> Vara(chain.id, validators, totalIssuance)
Chain.Geneses.POLKADOT -> PolkadotInflationPrediction(validators, totalIssuance, scope)
else -> null
}
}
Expand Down Expand Up @@ -119,4 +127,28 @@ class RewardCalculatorFactory(
}
.getOrNull()
}

private suspend fun StakingOption.PolkadotInflationPrediction(
validators: List<RewardCalculationTarget>,
totalIssuance: BigInteger,
scope: CoroutineScope
): RewardCalculator? {
return runCatching {
val eraRewardCalculator = shareStakingSharedComputation.get().eraTimeCalculator(this, scope)
val eraDuration = eraRewardCalculator.eraDuration()

val inflationPredictionInfo = stakingRepository.getInflationPredictionInfo(chain.id)

InflationPredictionInfoCalculator(
inflationPredictionInfo = inflationPredictionInfo,
eraDuration = eraDuration,
totalIssuance = totalIssuance,
validators = validators
)
}
.onFailure {
Log.e("RewardCalculatorFactory", "Failed to create Polkadot Inflation Prediction reward calculator, fallbacking to default", it)
}
.getOrNull()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import io.novafoundation.nova.feature_staking_impl.data.components
import io.novafoundation.nova.feature_staking_impl.data.stakingType
import io.novafoundation.nova.feature_staking_impl.domain.common.StakingSharedComputation
import io.novafoundation.nova.feature_staking_impl.domain.model.PayoutType
import io.novafoundation.nova.feature_staking_impl.domain.rewards.DAYS_IN_YEAR
import io.novafoundation.nova.feature_staking_impl.domain.rewards.calculateMaxPeriodReturns
import io.novafoundation.nova.feature_staking_impl.domain.staking.start.common.types.StakingTypeDetails
import io.novafoundation.nova.feature_staking_impl.domain.staking.start.common.types.StakingTypeDetailsInteractor
import io.novafoundation.nova.feature_wallet_api.domain.model.Asset
Expand Down Expand Up @@ -63,7 +61,7 @@ class RelaychainStakingTypeDetailsInteractor(
val (chain, chainAsset, stakingType) = stakingOption.components

return stakingSharedComputation.rewardCalculator(chain, chainAsset, stakingType, coroutineScope)
.calculateMaxPeriodReturns(DAYS_IN_YEAR)
.maxAPY
.asPerbill()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ValidatorProvider(
val identities = identityRepository.getIdentitiesFromIdsHex(chainId, requestedValidatorIds)
val slashes = stakingRepository.getSlashes(chainId, requestedValidatorIds)

val rewardCalculator = rewardCalculatorFactory.create(stakingOption, electedValidatorExposures, validatorPrefs)
val rewardCalculator = rewardCalculatorFactory.create(stakingOption, electedValidatorExposures, validatorPrefs, scope)
val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(chainId)

return requestedValidatorIds.map { accountIdHex ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ sealed class AssetLocationPath {
}

enum class XcmTransferType {
X_TOKENS, XCM_PALLET_RESERVE, XCM_PALLET_TELEPORT, UNKNOWN
X_TOKENS,
XCM_PALLET_RESERVE,
XCM_PALLET_TELEPORT,
XCM_PALLET_TRANSFER_ASSETS,
UNKNOWN
}

enum class XCMInstructionType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private fun mapXcmTransferTypeFromRemote(remote: String): XcmTransferType {
"xtokens" -> XcmTransferType.X_TOKENS
"xcmpallet" -> XcmTransferType.XCM_PALLET_RESERVE
"xcmpallet-teleport" -> XcmTransferType.XCM_PALLET_TELEPORT
"xcmpallet-transferAssets" -> XcmTransferType.XCM_PALLET_TRANSFER_ASSETS
else -> XcmTransferType.UNKNOWN
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class RealCrossChainTransactor(
XcmTransferType.X_TOKENS -> xTokensTransfer(configuration, transfer, crossChainFee)
XcmTransferType.XCM_PALLET_RESERVE -> xcmPalletReserveTransfer(configuration, transfer, crossChainFee)
XcmTransferType.XCM_PALLET_TELEPORT -> xcmPalletTeleport(configuration, transfer, crossChainFee)
XcmTransferType.XCM_PALLET_TRANSFER_ASSETS -> xcmPalletTransferAssets(configuration, transfer, crossChainFee)
XcmTransferType.UNKNOWN -> throw IllegalArgumentException("Unknown transfer type")
}
}
Expand Down Expand Up @@ -126,6 +127,20 @@ class RealCrossChainTransactor(
}

private fun destWeightEncodable(weight: Weight): Any = weight

private suspend fun ExtrinsicBuilder.xcmPalletTransferAssets(
configuration: CrossChainTransferConfiguration,
assetTransfer: AssetTransfer,
crossChainFee: Balance
) {
xcmPalletTransfer(
configuration = configuration,
assetTransfer = assetTransfer,
crossChainFee = crossChainFee,
callName = "transfer_assets"
)
}

private suspend fun ExtrinsicBuilder.xcmPalletReserveTransfer(
configuration: CrossChainTransferConfiguration,
assetTransfer: AssetTransfer,
Expand Down
Loading

0 comments on commit 5dafb75

Please sign in to comment.