Skip to content

Commit

Permalink
L1-287: Update the front end to inflation changes (#124)
Browse files Browse the repository at this point in the history
Changes:
* Show max AZERO issuance
* Add yearly_inflation and current_era_payout runtime calls types
* Change inflation calculations - for Aleph fetch the inflation, for
other chain keep unchanged
  • Loading branch information
youPickItUp authored Oct 8, 2024
2 parents ea0aba5 + 054358e commit 017e5c5
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 53 deletions.
1 change: 1 addition & 0 deletions packages/apps-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
19 changes: 4 additions & 15 deletions packages/apps-config/src/api/params/inflation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -16,10 +14,6 @@ export interface InflationParams {
stakeTarget: number;
}

interface UniformEraPayoutInflationParams extends InflationParams {
yearlyInflationInTokens: BN;
}

const DEFAULT_PARAMS: InflationParams = {
auctionAdjust: 0,
auctionMax: 0,
Expand All @@ -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<string, InflationParams> = {
[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 },
Expand All @@ -60,8 +49,8 @@ const KNOWN_PARAMS: Record<string, InflationParams> = {
[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;
}
10 changes: 10 additions & 0 deletions packages/apps-config/src/api/spec/aleph-zero.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions packages/apps-config/src/api/typesBundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions packages/apps-config/src/types.ts
Original file line number Diff line number Diff line change
@@ -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<ApiType extends ApiTypes> {
/** 0xbc9d89904f5b923f/1 */
alephSessionApi?: {
/**
* The API to query account nonce (aka transaction index)
**/
yearlyInflation?: AugmentedCall<ApiType, () => Observable<Perbill>>;
/**
* Generic call
**/
[key: string]: DecoratedCallBase<ApiType> | undefined;
};
}
}

export interface TOptions {
ns?: string;
replace?: Record<string, unknown>
Expand Down
1 change: 1 addition & 0 deletions packages/apps/public/locales/en/app-explorer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion packages/apps/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "",
Expand Down Expand Up @@ -1899,4 +1900,4 @@
"{{value}}x voting balance, locked for {{duration}}x duration{{period}}": "",
"{{when}} (est.)": "",
"⚡️ Thunder Gateway": ""
}
}
10 changes: 9 additions & 1 deletion packages/page-explorer/src/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -43,6 +43,14 @@ function Summary ({ eventCount }: Props): React.ReactElement {
>
<TotalIssuance />
</CardSummary>
{api.query.aleph.azeroCap && (
<CardSummary
className='media--800'
label={t('max issuance')}
>
<AzeroCap />
</CardSummary>
)}
{!!api.query.balances.inactiveIssuance && (
<CardSummary
className='media--1300'
Expand Down
2 changes: 0 additions & 2 deletions packages/react-hooks/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ export interface ModalState {
}

export interface Inflation {
idealStake: number;
idealInterest: number;
inflation: number;
stakedFraction: number;
stakedReturn: number;
Expand Down
96 changes: 62 additions & 34 deletions packages/react-hooks/src/useInflation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 + (
Expand All @@ -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<number>();

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<BN>(api.query.balances?.totalIssuance);
const auctionCounter = useCall<BN>(api.query.auctions?.auctionCounter);
const [state, setState] = useState<Inflation>(EMPTY);
const { isSupported: isYearlyInflationApiSupported, yearlyInflation } = useYearlyInflation();

const [inflation, setInflation] = useState<Inflation>(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);
33 changes: 33 additions & 0 deletions packages/react-query/src/AzeroCap.tsx
Original file line number Diff line number Diff line change
@@ -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<Props> | null {
const { api } = useApi();
const azeroCap = useCall<string>(api.query.aleph.azeroCap);

return (
<div className={className}>
{label || ''}
<FormatBalance
className={azeroCap ? '' : '--tmp'}
value={azeroCap}
withSi
/>
{children}
</div>
);
}

export default React.memo(TotalIssuance);
1 change: 1 addition & 0 deletions packages/react-query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 017e5c5

Please sign in to comment.