From 25467cd780bec5e55da8f72abf6e273cc1cdd783 Mon Sep 17 00:00:00 2001 From: Wojciech Basiura Date: Mon, 7 Oct 2024 16:58:03 +0200 Subject: [PATCH 1/3] L1-287: Show AZERO max issuance --- packages/page-explorer/src/Summary.tsx | 10 +++++++- packages/react-query/src/AzeroCap.tsx | 33 ++++++++++++++++++++++++++ packages/react-query/src/index.ts | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/react-query/src/AzeroCap.tsx diff --git a/packages/page-explorer/src/Summary.tsx b/packages/page-explorer/src/Summary.tsx index 386d85300728..443914789d9b 100644 --- a/packages/page-explorer/src/Summary.tsx +++ b/packages/page-explorer/src/Summary.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { CardSummary, SummaryBox } from '@polkadot/react-components'; import { useApi } from '@polkadot/react-hooks'; -import { BestFinalized, BestNumber, BlockToTime, TimeNow, TotalInactive, TotalIssuance } from '@polkadot/react-query'; +import { AzeroCap, BestFinalized, BestNumber, BlockToTime, TimeNow, TotalInactive, TotalIssuance } from '@polkadot/react-query'; import { BN_ONE, formatNumber } from '@polkadot/util'; import SummarySession from './SummarySession.js'; @@ -43,6 +43,14 @@ function Summary ({ eventCount }: Props): React.ReactElement { > + {api.query.aleph.azeroCap && ( + + + + )} {!!api.query.balances.inactiveIssuance && ( | null { + const { api } = useApi(); + const azeroCap = useCall(api.query.aleph.azeroCap); + + return ( +
+ {label || ''} + + {children} +
+ ); +} + +export default React.memo(TotalIssuance); diff --git a/packages/react-query/src/index.ts b/packages/react-query/src/index.ts index ecfdf75d4c45..9fd95e284a42 100644 --- a/packages/react-query/src/index.ts +++ b/packages/react-query/src/index.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 export { default as Available } from './Available.js'; +export { default as AzeroCap } from './AzeroCap.js'; export { default as BalanceFree } from './BalanceFree.js'; export { default as BalanceVoting } from './BalanceVoting.js'; export { default as BestFinalized } from './BestFinalized.js'; From e23aa5a9a98ad12a949d82d88cac135f40756c78 Mon Sep 17 00:00:00 2001 From: Wojciech Basiura Date: Tue, 8 Oct 2024 11:09:16 +0200 Subject: [PATCH 2/3] L1-287: Add `yearly_inflation` and `current_era_payout` runtime calls types --- packages/apps-config/package.json | 1 + .../apps-config/src/api/spec/aleph-zero.ts | 10 ++++++++++ packages/apps-config/src/api/typesBundle.ts | 10 ++++++++++ packages/apps-config/src/types.ts | 20 +++++++++++++++++++ yarn.lock | 1 + 5 files changed, 42 insertions(+) diff --git a/packages/apps-config/package.json b/packages/apps-config/package.json index 9578394f4d72..2b4a1e2e4a9d 100644 --- a/packages/apps-config/package.json +++ b/packages/apps-config/package.json @@ -39,6 +39,7 @@ "@pendulum-chain/type-definitions": "0.3.8", "@phala/typedefs": "0.2.33", "@polkadot/api": "^10.11.2", + "@polkadot/api-base": "^10.11.2", "@polkadot/api-derive": "^10.11.2", "@polkadot/networks": "^12.6.2", "@polkadot/react-identicon": "^3.6.4", diff --git a/packages/apps-config/src/api/spec/aleph-zero.ts b/packages/apps-config/src/api/spec/aleph-zero.ts index 92b0e99c665e..06d2773b8430 100644 --- a/packages/apps-config/src/api/spec/aleph-zero.ts +++ b/packages/apps-config/src/api/spec/aleph-zero.ts @@ -90,6 +90,16 @@ export default { description: '', params: [], type: 'u32' + }, + yearly_inflation: { + description: 'Returns inflation from now to now + one year.', + params: [], + type: 'Perbill' + }, + current_era_payout: { + description: 'Returns payout. First tuple item is a validators payout, second is the rest.', + params: [], + type: '(Balance, Balance)' } }, version: 1 diff --git a/packages/apps-config/src/api/typesBundle.ts b/packages/apps-config/src/api/typesBundle.ts index 680682da78c3..15adf0c14584 100644 --- a/packages/apps-config/src/api/typesBundle.ts +++ b/packages/apps-config/src/api/typesBundle.ts @@ -98,6 +98,16 @@ export const typesBundle = { "description": "", "params": [], "type": "u32" + }, + "yearly_inflation": { + "description": "Returns inflation from now to now + one year.", + "params": [], + "type": "Perbill" + }, + "current_era_payout": { + "description": "Returns payout. First tuple item is a validators payout, second is the rest.", + "params": [], + "type": "(Balance, Balance)" } }, "version": 1 diff --git a/packages/apps-config/src/types.ts b/packages/apps-config/src/types.ts index 8d57eda9ffae..287e16af098c 100644 --- a/packages/apps-config/src/types.ts +++ b/packages/apps-config/src/types.ts @@ -1,6 +1,26 @@ // Copyright 2017-2024 @polkadot/apps-config authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { ApiTypes, AugmentedCall, DecoratedCallBase } from '@polkadot/api-base/types'; +import type { Perbill } from '@polkadot/types/interfaces/runtime'; +import type { Observable } from '@polkadot/types/types'; + +declare module '@polkadot/api-base/types/calls' { + interface AugmentedCalls { + /** 0xbc9d89904f5b923f/1 */ + alephSessionApi?: { + /** + * The API to query account nonce (aka transaction index) + **/ + yearlyInflation?: AugmentedCall Observable>; + /** + * Generic call + **/ + [key: string]: DecoratedCallBase | undefined; + }; + } +} + export interface TOptions { ns?: string; replace?: Record diff --git a/yarn.lock b/yarn.lock index d7d2690bda00..fcbd38aecb5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1987,6 +1987,7 @@ __metadata: "@pendulum-chain/type-definitions": "npm:0.3.8" "@phala/typedefs": "npm:0.2.33" "@polkadot/api": "npm:^10.11.2" + "@polkadot/api-base": "npm:^10.11.2" "@polkadot/api-derive": "npm:^10.11.2" "@polkadot/networks": "npm:^12.6.2" "@polkadot/react-identicon": "npm:^3.6.4" From 054358ec9b38ceb5faeed387ac06e7b2073cdf4b Mon Sep 17 00:00:00 2001 From: Wojciech Basiura Date: Tue, 8 Oct 2024 13:15:02 +0200 Subject: [PATCH 3/3] L1-287: Change inflation calculations --- .../apps-config/src/api/params/inflation.ts | 19 +--- .../apps/public/locales/en/app-explorer.json | 1 + .../apps/public/locales/en/translation.json | 3 +- packages/react-hooks/src/types.ts | 2 - packages/react-hooks/src/useInflation.ts | 96 ++++++++++++------- 5 files changed, 69 insertions(+), 52 deletions(-) diff --git a/packages/apps-config/src/api/params/inflation.ts b/packages/apps-config/src/api/params/inflation.ts index 3567832d6e47..952b0e1f34df 100644 --- a/packages/apps-config/src/api/params/inflation.ts +++ b/packages/apps-config/src/api/params/inflation.ts @@ -3,8 +3,6 @@ import type { ApiPromise } from '@polkadot/api'; -import { BN, BN_MILLION } from '@polkadot/util'; - import { ALEPHZERO_MAINNET_GENESIS, ALEPHZERO_TESTNET_GENESIS, CERE_NETWORK_GENESIS, CERE_NETWORK_TESTNET_GENESIS, DOCK_POS_TESTNET_GENESIS, KUSAMA_GENESIS, NEATCOIN_GENESIS, NFTMART_GENESIS, POLKADOT_GENESIS, VARA_NETWORK_GENESIS, VARA_NETWORK_TESTNET_GENESIS } from '../constants.js'; export interface InflationParams { @@ -16,10 +14,6 @@ export interface InflationParams { stakeTarget: number; } -interface UniformEraPayoutInflationParams extends InflationParams { - yearlyInflationInTokens: BN; -} - const DEFAULT_PARAMS: InflationParams = { auctionAdjust: 0, auctionMax: 0, @@ -33,18 +27,13 @@ const DEFAULT_PARAMS: InflationParams = { stakeTarget: 0.5 }; -const DEFAULT_UNIFORM_ERA_PAYOUT_PARAMS: UniformEraPayoutInflationParams = { - ...DEFAULT_PARAMS, - yearlyInflationInTokens: BN_MILLION.mul(new BN(30)) -}; - const CERE_NETWORK_INFLATION_PARAMS = { ...DEFAULT_PARAMS, maxInflation: 0.05, minInflation: 0.0001, stakeTarget: 0.2 }; const VARA_NETWORK_INFLATION_PARAMS = { ...DEFAULT_PARAMS, maxInflation: 0, minInflation: 0.0001, stakeTarget: 0.85 }; const KNOWN_PARAMS: Record = { - [ALEPHZERO_MAINNET_GENESIS]: DEFAULT_UNIFORM_ERA_PAYOUT_PARAMS, - [ALEPHZERO_TESTNET_GENESIS]: DEFAULT_UNIFORM_ERA_PAYOUT_PARAMS, + [ALEPHZERO_MAINNET_GENESIS]: DEFAULT_PARAMS, + [ALEPHZERO_TESTNET_GENESIS]: DEFAULT_PARAMS, [CERE_NETWORK_GENESIS]: CERE_NETWORK_INFLATION_PARAMS, [CERE_NETWORK_TESTNET_GENESIS]: CERE_NETWORK_INFLATION_PARAMS, [DOCK_POS_TESTNET_GENESIS]: { ...DEFAULT_PARAMS, stakeTarget: 0.75 }, @@ -60,8 +49,8 @@ const KNOWN_PARAMS: Record = { [VARA_NETWORK_TESTNET_GENESIS]: VARA_NETWORK_INFLATION_PARAMS }; -export function getInflationParams (api: ApiPromise): InflationParams | UniformEraPayoutInflationParams { +export function getInflationParams (api: ApiPromise): InflationParams { // below behaviour is different between our fork and upstream, that by default we are operating // in uniform era payout model, rather than Polkadot-js's RewardCurve model - return KNOWN_PARAMS[api.genesisHash.toHex()] || DEFAULT_UNIFORM_ERA_PAYOUT_PARAMS; + return KNOWN_PARAMS[api.genesisHash.toHex()] || DEFAULT_PARAMS; } diff --git a/packages/apps/public/locales/en/app-explorer.json b/packages/apps/public/locales/en/app-explorer.json index be74201bb1e7..2a2f545ee3ed 100644 --- a/packages/apps/public/locales/en/app-explorer.json +++ b/packages/apps/public/locales/en/app-explorer.json @@ -49,6 +49,7 @@ "last events": "last events", "logs": "logs", "max": "max", + "max issuance": "max issuance", "min": "min", "mortal, valid from #{{startAt}} to #{{endsAt}}": "mortal, valid from #{{startAt}} to #{{endsAt}}", "no": "no", diff --git a/packages/apps/public/locales/en/translation.json b/packages/apps/public/locales/en/translation.json index d3e7a7c4203c..48994610d5ee 100644 --- a/packages/apps/public/locales/en/translation.json +++ b/packages/apps/public/locales/en/translation.json @@ -1500,6 +1500,7 @@ "max RefTime allowed (M, {{estimatedRefTime}} estimated)": "", "max gas allowed (M)": "", "max gas allowed (M, {{estimatedMg}} estimated)": "", + "max issuance": "", "max read gas": "", "max. members": "", "max. members / pool": "", @@ -1899,4 +1900,4 @@ "{{value}}x voting balance, locked for {{duration}}x duration{{period}}": "", "{{when}} (est.)": "", "⚡️ Thunder Gateway": "" -} +} \ No newline at end of file diff --git a/packages/react-hooks/src/types.ts b/packages/react-hooks/src/types.ts index a04bf14786f0..de2c6dd2a370 100644 --- a/packages/react-hooks/src/types.ts +++ b/packages/react-hooks/src/types.ts @@ -44,8 +44,6 @@ export interface ModalState { } export interface Inflation { - idealStake: number; - idealInterest: number; inflation: number; stakedFraction: number; stakedReturn: number; diff --git a/packages/react-hooks/src/useInflation.ts b/packages/react-hooks/src/useInflation.ts index a67a5ab05c7c..9475cd76cf10 100644 --- a/packages/react-hooks/src/useInflation.ts +++ b/packages/react-hooks/src/useInflation.ts @@ -8,20 +8,13 @@ import type { Inflation } from './types.js'; import { useEffect, useState } from 'react'; import { getInflationParams } from '@polkadot/apps-config'; -import { BN_BILLION, BN_MILLION, BN_ZERO } from '@polkadot/util'; -import { BN_THOUSAND } from '@polkadot/util/bn/consts'; +import { BN_MILLION, BN_ZERO, isFunction } from '@polkadot/util'; import { createNamedHook } from './createNamedHook.js'; import { useApi } from './useApi.js'; import { useCall } from './useCall.js'; -const EMPTY: Inflation = { idealInterest: 0, idealStake: 0, inflation: 0, stakedFraction: 0, stakedReturn: 0 }; - -function calcInflationUniformEraPayout (totalIssuance: BN, yearlyInflationInTokens: BN): number { - const totalIssuanceInTokens = totalIssuance.div(BN_BILLION).div(BN_THOUSAND); - - return (totalIssuanceInTokens.isZero() ? 0.0 : yearlyInflationInTokens.toNumber() / totalIssuanceInTokens.toNumber()); -} +const EMPTY: Inflation = { inflation: 0, stakedFraction: 0, stakedReturn: 0 }; function calcInflationRewardCurve (minInflation: number, stakedFraction: number, idealStake: number, idealInterest: number, falloff: number) { return (minInflation + ( @@ -31,57 +24,92 @@ function calcInflationRewardCurve (minInflation: number, stakedFraction: number, )); } -function calcInflation (api: ApiPromise, totalStaked: BN, totalIssuance: BN, numAuctions: BN): Inflation { - const inflationParams = getInflationParams(api); - const { auctionAdjust, auctionMax, falloff, maxInflation, minInflation, stakeTarget } = inflationParams; - const stakedFraction = totalStaked.isZero() || totalIssuance.isZero() - ? 0 - : totalStaked.mul(BN_MILLION).div(totalIssuance).toNumber() / BN_MILLION.toNumber(); +function calcInflationOnNonAleph (api: ApiPromise, stakedFraction: number, numAuctions: BN): Inflation { + const { auctionAdjust, auctionMax, falloff, maxInflation, minInflation, stakeTarget } = getInflationParams(api); + const idealStake = stakeTarget - (Math.min(auctionMax, numAuctions.toNumber()) * auctionAdjust); const idealInterest = maxInflation / idealStake; - let inflationInPercentage = 0; - if ('yearlyInflationInTokens' in inflationParams) { - inflationInPercentage = 100 * calcInflationUniformEraPayout(totalIssuance, inflationParams.yearlyInflationInTokens); - } else { - inflationInPercentage = 100 * calcInflationRewardCurve(minInflation, stakedFraction, idealStake, idealInterest, falloff); - } + const inflationInPercentage = 100 * calcInflationRewardCurve(minInflation, stakedFraction, idealStake, idealInterest, falloff); - let stakedReturn = stakedFraction + const stakedReturn = stakedFraction ? (inflationInPercentage / stakedFraction) : 0; + return { + inflation: inflationInPercentage, + stakedFraction, + stakedReturn + }; +} + +function calcInflationOnAleph (yearlyInflationInPercentage: number, stakedFraction: number) { + const baseStakedReturn = stakedFraction !== 0 + ? (yearlyInflationInPercentage / stakedFraction) + : 0; + // Here we multiply stakedReturn by 0.9, as in case of Aleph Zero chain 10% of return goes to treasury - if ('yearlyInflationInTokens' in inflationParams) { - stakedReturn *= 0.9; - } + const stakedReturn = baseStakedReturn * 0.9; return { - idealInterest, - idealStake, - inflation: inflationInPercentage, + inflation: yearlyInflationInPercentage, stakedFraction, stakedReturn }; } +function useYearlyInflation () { + const { api } = useApi(); + + const [yearlyInflation, setYearlyInflation] = useState(); + + const getYearlyInflation = api.call?.alephSessionApi?.yearlyInflation; + + useEffect(() => { + getYearlyInflation?.().then((val) => { + setYearlyInflation(val.toNumber() / 1_000_000_000); + }).catch(console.error); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return { isSupported: isFunction(getYearlyInflation), yearlyInflation }; +} + function useInflationImpl (totalStaked?: BN): Inflation { const { api } = useApi(); + const totalIssuance = useCall(api.query.balances?.totalIssuance); const auctionCounter = useCall(api.query.auctions?.auctionCounter); - const [state, setState] = useState(EMPTY); + const { isSupported: isYearlyInflationApiSupported, yearlyInflation } = useYearlyInflation(); + + const [inflation, setInflation] = useState(EMPTY); useEffect((): void => { const numAuctions = api.query.auctions ? auctionCounter : BN_ZERO; - numAuctions && totalIssuance && totalStaked && setState( - calcInflation(api, totalStaked, totalIssuance, numAuctions) - ); - }, [api, auctionCounter, totalIssuance, totalStaked]); + if ( + numAuctions === undefined || + totalStaked === undefined || + totalIssuance === undefined || + (isYearlyInflationApiSupported && yearlyInflation === undefined) + ) { + return; + } + + const stakedFraction = totalStaked.isZero() || totalIssuance.isZero() + ? 0 + : totalStaked.mul(BN_MILLION).div(totalIssuance).toNumber() / BN_MILLION.toNumber(); + + const inflation = isYearlyInflationApiSupported && yearlyInflation !== undefined + ? calcInflationOnAleph(yearlyInflation * 100, stakedFraction) + : calcInflationOnNonAleph(api, stakedFraction, numAuctions); + + setInflation(inflation); + }, [api, auctionCounter, isYearlyInflationApiSupported, totalIssuance, totalStaked, yearlyInflation]); - return state; + return inflation; } export const useInflation = createNamedHook('useInflation', useInflationImpl);