From 9f30cc3f5ccb2a66d08d6a1c0c5b16868029763a Mon Sep 17 00:00:00 2001 From: valentun Date: Tue, 19 Nov 2024 12:08:39 +0200 Subject: [PATCH 1/5] Support xcmPallet.transferAssets --- .../model/CrossChainTransfersConfiguration.kt | 6 +++++- .../data/mappers/CrossChain.kt | 1 + .../crosschain/RealCrossChainTransactor.kt | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/domain/model/CrossChainTransfersConfiguration.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/domain/model/CrossChainTransfersConfiguration.kt index 706c6c58ea..23bd7973c6 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/domain/model/CrossChainTransfersConfiguration.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/domain/model/CrossChainTransfersConfiguration.kt @@ -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 { diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/mappers/CrossChain.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/mappers/CrossChain.kt index c1e82e458f..e7b844d398 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/mappers/CrossChain.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/mappers/CrossChain.kt @@ -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 } } diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/crosschain/RealCrossChainTransactor.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/crosschain/RealCrossChainTransactor.kt index 1c8532640d..adc1f4cd52 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/crosschain/RealCrossChainTransactor.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/crosschain/RealCrossChainTransactor.kt @@ -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") } } @@ -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, From 5b03c562679de9a643d05e32d9b6d3357869f9ba Mon Sep 17 00:00:00 2001 From: valentun Date: Tue, 19 Nov 2024 16:16:55 +0200 Subject: [PATCH 2/5] Update inflation calculation for Polkadot --- build.gradle | 2 +- .../types/HydrationConversionFeePayment.kt | 4 +- .../domain/api/StakingRepository.kt | 3 ++ .../domain/model/InflationPredictionInfo.kt | 46 +++++++++++++++++++ .../data/repository/StakingRepositoryImpl.kt | 15 ++++++ .../di/StakingFeatureModule.kt | 8 ++-- .../InflationPredictionInfoCalculator.kt | 18 ++++++++ .../domain/rewards/RewardCalculatorFactory.kt | 44 +++++++++++++++--- .../domain/validators/ValidatorProvider.kt | 2 +- .../nova/runtime/call/RuntimeCallsApi.kt | 35 ++++++++++++-- .../runtime/RuntimeMetadataFetcher.kt | 2 +- .../nova/runtime/network/rpc/RpcCalls.kt | 1 + .../runtime/network/rpc/StateCallRequest.kt | 11 ----- 13 files changed, 162 insertions(+), 29 deletions(-) create mode 100644 feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt create mode 100644 feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/InflationPredictionInfoCalculator.kt delete mode 100644 runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/StateCallRequest.kt diff --git a/build.gradle b/build.gradle index e6d337163a..879ed159ee 100644 --- a/build.gradle +++ b/build.gradle @@ -51,7 +51,7 @@ buildscript { web3jVersion = '4.9.5' - substrateSdkVersion = '2.2.0' + substrateSdkVersion = '2.3.0' gifVersion = '1.2.19' diff --git a/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/fee/types/HydrationConversionFeePayment.kt b/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/fee/types/HydrationConversionFeePayment.kt index c5a608a0a0..4edd2629ef 100644 --- a/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/fee/types/HydrationConversionFeePayment.kt +++ b/feature-account-impl/src/main/java/io/novafoundation/nova/feature_account_impl/data/fee/types/HydrationConversionFeePayment.kt @@ -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) } diff --git a/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/api/StakingRepository.kt b/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/api/StakingRepository.kt index ca036b6da3..04a1ad3c5f 100644 --- a/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/api/StakingRepository.kt +++ b/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/api/StakingRepository.kt @@ -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 @@ -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 { diff --git a/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt b/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt new file mode 100644 index 0000000000..dd664c7442 --- /dev/null +++ b/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt @@ -0,0 +1,46 @@ +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.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 + val inflationPerMint = nextMint.toStakers.divideToDecimal(totalIssuance) + + return inflationPerMint.toDouble() * periodsInYear +} diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/StakingRepositoryImpl.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/StakingRepositoryImpl.kt index b7d96a6ef9..a19d3af0e8 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/StakingRepositoryImpl.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/data/repository/StakingRepositoryImpl.kt @@ -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 @@ -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 @@ -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 { @@ -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 queryStorageIfExists( chainId: ChainId, storageName: String, @@ -318,6 +332,7 @@ class StakingRepositoryImpl( stashId, prefs ) + nominations != null -> StakingState.Stash.Nominator( chain, chainAsset, diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/StakingFeatureModule.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/StakingFeatureModule.kt index 492950cbc0..c34e31b46a 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/StakingFeatureModule.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/di/StakingFeatureModule.kt @@ -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 @@ -177,7 +177,8 @@ class StakingFeatureModule { stakingStoriesDataSource: StakingStoriesDataSource, walletConstants: WalletConstants, chainRegistry: ChainRegistry, - storageCache: StorageCache + storageCache: StorageCache, + multiChainRuntimeCallsApi: MultiChainRuntimeCallsApi ): StakingRepository = StakingRepositoryImpl( accountStakingDao = accountStakingDao, remoteStorage = remoteStorageSource, @@ -185,7 +186,8 @@ class StakingFeatureModule { stakingStoriesDataSource = stakingStoriesDataSource, walletConstants = walletConstants, chainRegistry = chainRegistry, - storageCache = storageCache + storageCache = storageCache, + multiChainRuntimeCallsApi = multiChainRuntimeCallsApi ) @Provides diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/InflationPredictionInfoCalculator.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/InflationPredictionInfoCalculator.kt new file mode 100644 index 0000000000..d8ed7fb6f5 --- /dev/null +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/InflationPredictionInfoCalculator.kt @@ -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 +) : InflationBasedRewardCalculator(validators, totalIssuance) { + + override fun calculateYearlyInflation(stakedPortion: Double): Double { + return inflationPredictionInfo.calculateStakersInflation(totalIssuance, eraDuration) + } +} diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt index e4cbeb12bf..c28f959bb0 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/rewards/RewardCalculatorFactory.kt @@ -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 @@ -42,7 +43,8 @@ class RewardCalculatorFactory( suspend fun create( stakingOption: StakingOption, exposures: AccountIdMap, - validatorsPrefs: AccountIdMap + validatorsPrefs: AccountIdMap, + scope: CoroutineScope ): RewardCalculator = withContext(Dispatchers.Default) { val totalIssuance = totalIssuanceRepository.getTotalIssuance(stakingOption.assetWithChain.chain.id) @@ -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) { @@ -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, totalIssuance: BigInteger): RewardCalculator { + private suspend fun StakingOption.createRewardCalculator( + validators: List, + 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) @@ -88,10 +94,12 @@ class RewardCalculatorFactory( private suspend fun StakingOption.customRelayChainCalculator( validators: List, - 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 } } @@ -119,4 +127,28 @@ class RewardCalculatorFactory( } .getOrNull() } + + private suspend fun StakingOption.PolkadotInflationPrediction( + validators: List, + 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() + } } diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt index 2c01a3d0ba..b6f6f95c7e 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/validators/ValidatorProvider.kt @@ -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 -> diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/call/RuntimeCallsApi.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/call/RuntimeCallsApi.kt index b6113a54db..b69f25dc29 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/call/RuntimeCallsApi.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/call/RuntimeCallsApi.kt @@ -1,7 +1,6 @@ package io.novafoundation.nova.runtime.call import io.novafoundation.nova.common.data.network.runtime.binding.fromHexOrIncompatible -import io.novafoundation.nova.runtime.network.rpc.StateCallRequest import io.novafoundation.nova.runtime.network.rpc.stateCall import io.novasama.substrate_sdk_android.extensions.requireHexPrefix import io.novasama.substrate_sdk_android.extensions.toHexString @@ -9,7 +8,12 @@ import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot import io.novasama.substrate_sdk_android.runtime.definitions.registry.TypeRegistry import io.novasama.substrate_sdk_android.runtime.definitions.registry.getOrThrow import io.novasama.substrate_sdk_android.runtime.definitions.types.bytes +import io.novasama.substrate_sdk_android.runtime.metadata.createRequest +import io.novasama.substrate_sdk_android.runtime.metadata.decodeOutput +import io.novasama.substrate_sdk_android.runtime.metadata.method +import io.novasama.substrate_sdk_android.runtime.metadata.runtimeApi import io.novasama.substrate_sdk_android.wsrpc.SocketService +import io.novasama.substrate_sdk_android.wsrpc.request.runtime.state.StateCallRequest typealias RuntimeTypeName = String typealias RuntimeTypeValue = Any? @@ -18,13 +22,13 @@ interface RuntimeCallsApi { val runtime: RuntimeSnapshot - // TODO we can do better than that - it is possible to auto-detect method signature's types - // However it requires a separate research - // We should revisit this when Metadata v15 will take place /** * @param arguments - list of pairs [runtimeTypeValue, runtimeTypeName], * where runtimeTypeValue is value to be encoded and runtimeTypeName is type name that can be found in [TypeRegistry] * It can also be null, in that case argument is considered as already encoded in hex form + * + * This should only be used if automatic decoding via metadata is not possible + * For the other cases use another [call] overload */ suspend fun call( section: String, @@ -33,6 +37,13 @@ interface RuntimeCallsApi { returnType: RuntimeTypeName, returnBinding: (Any?) -> R ): R + + suspend fun call( + section: String, + method: String, + arguments: Map, + returnBinding: (Any?) -> R + ): R } internal class RealRuntimeCallsApi( @@ -58,6 +69,22 @@ internal class RealRuntimeCallsApi( return returnBinding(decoded) } + override suspend fun call( + section: String, + method: String, + arguments: Map, + returnBinding: (Any?) -> R + ): R { + val apiMethod = runtime.metadata.runtimeApi(section).method(method) + val request = apiMethod.createRequest(runtime, arguments) + + val response = socketService.stateCall(request) + + val decoded = response?.let { apiMethod.decodeOutput(runtime, it) } + + return returnBinding(decoded) + } + private fun decodeResponse(responseHex: String?, returnTypeName: String): Any? { val returnType = runtime.typeRegistry.getOrThrow(returnTypeName) diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeMetadataFetcher.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeMetadataFetcher.kt index 9ceade987c..04236ee624 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeMetadataFetcher.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeMetadataFetcher.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.runtime.multiNetwork.runtime import android.util.Log import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId -import io.novafoundation.nova.runtime.network.rpc.StateCallRequest import io.novafoundation.nova.runtime.network.rpc.stateCall import io.novasama.substrate_sdk_android.extensions.fromHex import io.novasama.substrate_sdk_android.runtime.metadata.GetMetadataRequest @@ -13,6 +12,7 @@ import io.novasama.substrate_sdk_android.wsrpc.SocketService import io.novasama.substrate_sdk_android.wsrpc.executeAsync import io.novasama.substrate_sdk_android.wsrpc.mappers.nonNull import io.novasama.substrate_sdk_android.wsrpc.mappers.pojo +import io.novasama.substrate_sdk_android.wsrpc.request.runtime.state.StateCallRequest private const val LATEST_SUPPORTED_METADATA_VERSION = 15 diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/RpcCalls.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/RpcCalls.kt index 905aab2f1a..15c6577bf3 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/RpcCalls.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/RpcCalls.kt @@ -40,6 +40,7 @@ import io.novasama.substrate_sdk_android.wsrpc.request.runtime.author.SubmitAndW import io.novasama.substrate_sdk_android.wsrpc.request.runtime.author.SubmitExtrinsicRequest import io.novasama.substrate_sdk_android.wsrpc.request.runtime.chain.RuntimeVersionFull import io.novasama.substrate_sdk_android.wsrpc.request.runtime.chain.RuntimeVersionRequest +import io.novasama.substrate_sdk_android.wsrpc.request.runtime.state.StateCallRequest import io.novasama.substrate_sdk_android.wsrpc.subscriptionFlow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emitAll diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/StateCallRequest.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/StateCallRequest.kt deleted file mode 100644 index e154fd1c47..0000000000 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/network/rpc/StateCallRequest.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.novafoundation.nova.runtime.network.rpc - -import io.novasama.substrate_sdk_android.wsrpc.request.runtime.RuntimeRequest - -class StateCallRequest( - runtimeRpcName: String, - vararg params: Any -) : RuntimeRequest( - "state_call", - listOf(runtimeRpcName) + params -) From 813cbb9e2c9eb5a244676490c17240d5d42dce75 Mon Sep 17 00:00:00 2001 From: valentun Date: Tue, 19 Nov 2024 16:41:46 +0200 Subject: [PATCH 3/5] Bump version --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 879ed159ee..750d1a4928 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { // App version - versionName = '9.0.1' - versionCode = 159 + versionName = '9.0.2' + versionCode = 160 applicationId = "io.novafoundation.nova" releaseApplicationSuffix = "market" From 81fc3968f8b95a350a2307d762b2975609a43890 Mon Sep 17 00:00:00 2001 From: valentun Date: Tue, 19 Nov 2024 18:50:55 +0200 Subject: [PATCH 4/5] Fixes --- .../domain/model/InflationPredictionInfo.kt | 3 ++- .../types/direct/RelaychainStakingTypeDetailsInteractor.kt | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt b/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt index dd664c7442..3e9908152e 100644 --- a/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt +++ b/feature-staking-api/src/main/java/io/novafoundation/nova/feature_staking_api/domain/model/InflationPredictionInfo.kt @@ -5,6 +5,7 @@ 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 @@ -39,7 +40,7 @@ class InflationPredictionInfo( } fun InflationPredictionInfo.calculateStakersInflation(totalIssuance: Balance, eraDuration: Duration): Double { - val periodsInYear = 365.days / eraDuration + val periodsInYear = (365.days / eraDuration).roundToInt() val inflationPerMint = nextMint.toStakers.divideToDecimal(totalIssuance) return inflationPerMint.toDouble() * periodsInYear diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/common/types/direct/RelaychainStakingTypeDetailsInteractor.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/common/types/direct/RelaychainStakingTypeDetailsInteractor.kt index b06c1f2116..16b0e42201 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/common/types/direct/RelaychainStakingTypeDetailsInteractor.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/domain/staking/start/common/types/direct/RelaychainStakingTypeDetailsInteractor.kt @@ -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 @@ -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() } } From ab171b5098a80145f3ce1c4d2e10669fb24d300a Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 20 Nov 2024 01:19:26 +0100 Subject: [PATCH 5/5] Bump version code --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 750d1a4928..acffd89dc6 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { // App version versionName = '9.0.2' - versionCode = 160 + versionCode = 161 applicationId = "io.novafoundation.nova" releaseApplicationSuffix = "market"