fix: Correct bag threshold display with CurrencyToVote conversion (#12058)

* fix: bag threshold display with CurrencyToVote conversion

* chore: update comments
This commit is contained in:
rajk93 2025-12-11 17:52:06 +05:30 committed by GitHub
parent 7724d9c2b8
commit f667e658d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 89 additions and 4 deletions

View File

@ -6,9 +6,9 @@ import type { PalletBagsListListBag } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
import type { BagInfo } from './types.js';
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { createNamedHook, useCall, useMapKeys } from '@polkadot/react-hooks';
import { createNamedHook, useApi, useCall, useCurrencyToVote, useMapKeys } from '@polkadot/react-hooks';
import { BN_ZERO } from '@polkadot/util';
import useQueryModule from './useQueryModule.js';
@ -54,13 +54,39 @@ function merge (prev: BagInfo[] | undefined, curr: BagInfo[]): BagInfo[] {
function useBagsListImpl (): BagInfo[] | undefined {
const mod = useQueryModule();
const { api } = useApi();
const { toCurrency } = useCurrencyToVote();
const [result, setResult] = useState<BagInfo[] | undefined>();
const ids = useMapKeys(mod.listBags, [], KEY_OPTS);
const query = useCall(ids && ids.length !== 0 && mod.listBags.multi, [ids], MULTI_OPTS);
const converted = useMemo(
() => {
if (!query || query.length === 0) {
return undefined;
}
// Westend Asset Hub uses SaturatingCurrencyToVote (no conversion needed)
// See: https://github.com/paritytech/polkadot-sdk/pull/8307
const chainName = api.runtimeChain.toString().toLowerCase();
const isWestendAssetHub = chainName.includes('westend') && chainName.includes('asset');
if (isWestendAssetHub) {
return query;
}
return query.map((bag) => ({
...bag,
bagLower: toCurrency(bag.bagLower),
bagUpper: toCurrency(bag.bagUpper)
}));
},
[api.runtimeChain, query, toCurrency]
);
useEffect((): void => {
query && setResult((prev) => merge(prev, query));
}, [query]);
converted && setResult((prev) => merge(prev, converted));
}, [converted]);
return result;
}

View File

@ -38,6 +38,7 @@ export { useCoreDescriptor } from './useCoreDescriptor.js';
export { useCoretimeConsts } from './useCoretimeConsts.js';
export { useCoretimeEndpoint } from './useCoretimeEndpoint.js';
export { useCoretimeInformation } from './useCoretimeInformation.js';
export { useCurrencyToVote } from './useCurrencyToVote.js';
export { useDebounce } from './useDebounce.js';
export { useDelegations } from './useDelegations.js';
export { useDeriveAccountFlags } from './useDeriveAccountFlags.js';

View File

@ -0,0 +1,58 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { useMemo } from 'react';
import { BN, BN_ONE } from '@polkadot/util';
import { createNamedHook } from './createNamedHook.js';
import { useApi } from './useApi.js';
import { useCall } from './useCall.js';
// u64::MAX = 2^64 - 1 = 18,446,744,073,709,551,615
const U64_MAX = new BN('18446744073709551615');
interface CurrencyToVote {
// The factor to convert from currency to vote
factor: BN;
// Convert a currency balance to voting power
toVote: (balance: BN) => BN;
// Convert voting power back to currency balance
toCurrency: (vote: BN) => BN;
}
/**
* Calculate the CurrencyToVote factor based on total issuance.
*
* - If total_issuance < 2^64, then factor = 1 (no conversion needed)
* - If total_issuance >= 2^64, then factor = (total_issuance / 2^64).max(1)
*
* The conversion formulas is:
* - vote = balance / factor
*/
function calculateFactor (totalIssuance: BN): BN {
if (totalIssuance.lte(U64_MAX)) {
return BN_ONE;
}
const factor = totalIssuance.div(U64_MAX);
return factor.isZero() ? BN_ONE : factor;
}
function useCurrencyToVoteImpl (): CurrencyToVote {
const { api } = useApi();
const totalIssuance = useCall<BN>(api.query.balances?.totalIssuance);
return useMemo((): CurrencyToVote => {
const factor = totalIssuance ? calculateFactor(totalIssuance) : BN_ONE;
return {
factor,
toCurrency: (vote: BN) => vote.mul(factor),
toVote: (balance: BN) => balance.div(factor)
};
}, [totalIssuance]);
}
export const useCurrencyToVote = createNamedHook('useCurrencyToVote', useCurrencyToVoteImpl);