fix: Correct bag threshold display with CurrencyToVote conversion (#12058)
* fix: bag threshold display with CurrencyToVote conversion * chore: update comments
This commit is contained in:
parent
7724d9c2b8
commit
f667e658d7
@ -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;
|
||||
}
|
||||
|
||||
@ -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';
|
||||
|
||||
58
packages/react-hooks/src/useCurrencyToVote.ts
Normal file
58
packages/react-hooks/src/useCurrencyToVote.ts
Normal 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);
|
||||
Loading…
Reference in New Issue
Block a user