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/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-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/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/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 && ( (); + + 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); diff --git a/packages/react-query/src/AzeroCap.tsx b/packages/react-query/src/AzeroCap.tsx new file mode 100644 index 000000000000..45511d59205b --- /dev/null +++ b/packages/react-query/src/AzeroCap.tsx @@ -0,0 +1,33 @@ +// Copyright 2017-2024 @polkadot/react-query authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import React from 'react'; + +import { useApi, useCall } from '@polkadot/react-hooks'; + +import FormatBalance from './FormatBalance.js'; + +interface Props { + children?: React.ReactNode; + className?: string; + label?: React.ReactNode; +} + +function TotalIssuance ({ children, className = '', label }: Props): React.ReactElement | 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'; 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"