diff --git a/src/canvas/ManageNominations/index.tsx b/src/canvas/ManageNominations/index.tsx index 9a04d337e3..8e8ca9aec0 100644 --- a/src/canvas/ManageNominations/index.tsx +++ b/src/canvas/ManageNominations/index.tsx @@ -25,6 +25,7 @@ import type { NominationSelection, NominationSelectionWithResetCounter, } from 'library/GenerateNominations/types'; +import { useBondedPools } from 'contexts/Pools/BondedPools'; import { RevertPrompt } from './Prompts/RevertPrompt'; import { CanvasSubmitTxFooter, ManageNominationsWrapper } from './Wrappers'; @@ -42,6 +43,7 @@ export const ManageNominations = () => { const { addNotification } = useNotifications(); const { selectedActivePool } = useActivePools(); const { openPromptWith, closePrompt } = usePrompt(); + const { updatePoolNominations } = useBondedPools(); const controller = getBondedAccount(activeAccount); const { maxNominations } = consts; const bondFor = options?.bondFor || 'nominator'; @@ -128,7 +130,16 @@ export const ManageNominations = () => { callbackSubmit: () => { setCanvasStatus('closing'); }, - callbackInBlock: () => {}, + callbackInBlock: () => { + if (isPool) { + // Upate bonded pool targets if updating pool nominations. + if (selectedActivePool?.id) + updatePoolNominations( + selectedActivePool.id, + newNominations.nominations.map((n) => n.address) + ); + } + }, }); // Valid if there are between 1 and `maxNominations` nominations. diff --git a/src/contexts/NetworkMetrics/index.tsx b/src/contexts/NetworkMetrics/index.tsx index 725c3f24a0..e7e067d7b8 100644 --- a/src/contexts/NetworkMetrics/index.tsx +++ b/src/contexts/NetworkMetrics/index.tsx @@ -101,7 +101,7 @@ export const NetworkMetricsProvider = ({ // initiate subscription, add to unsubs. await Promise.all([subscribeToMetrics(), subscribeToActiveEra()]).then( - (u: any) => { + (u) => { unsubsRef.current = unsubsRef.current.concat(u); } ); diff --git a/src/contexts/Pools/ActivePools/index.tsx b/src/contexts/Pools/ActivePools/index.tsx index a0fa72a39d..e5878959d2 100644 --- a/src/contexts/Pools/ActivePools/index.tsx +++ b/src/contexts/Pools/ActivePools/index.tsx @@ -91,6 +91,7 @@ export const ActivePoolsProvider = ({ const p = membership?.poolId ? String(membership.poolId) : '0'; return String(a.id) === p; }) || null; + const getSelectedActivePool = () => activePoolsRef.current.find((a) => a.id === Number(selectedPoolId)) || null; diff --git a/src/contexts/Pools/BondedPools/defaults.ts b/src/contexts/Pools/BondedPools/defaults.ts index 0074e1771c..6da43eb4d0 100644 --- a/src/contexts/Pools/BondedPools/defaults.ts +++ b/src/contexts/Pools/BondedPools/defaults.ts @@ -5,7 +5,6 @@ import type { BondedPoolsContextState } from '../types'; export const defaultBondedPoolsContext: BondedPoolsContextState = { - fetchPoolsMetaBatch: (k, v: [], r) => {}, queryBondedPool: (p) => {}, getBondedPool: (p) => null, updateBondedPools: (p) => {}, @@ -16,7 +15,9 @@ export const defaultBondedPoolsContext: BondedPoolsContextState = { getAccountRoles: (w) => null, getAccountPools: (w) => null, replacePoolRoles: (p, e) => {}, - poolSearchFilter: (l, k, v) => {}, + poolSearchFilter: (l, v) => {}, bondedPools: [], - meta: {}, + poolsMetaData: {}, + poolsNominations: {}, + updatePoolNominations: (id, nominations) => {}, }; diff --git a/src/contexts/Pools/BondedPools/index.tsx b/src/contexts/Pools/BondedPools/index.tsx index df6330040e..9975a3ff7a 100644 --- a/src/contexts/Pools/BondedPools/index.tsx +++ b/src/contexts/Pools/BondedPools/index.tsx @@ -2,18 +2,21 @@ // SPDX-License-Identifier: GPL-3.0-only import { u8aToString, u8aUnwrapBytes } from '@polkadot/util'; -import { setStateWithRef, shuffle } from '@polkadot-cloud/utils'; +import { rmCommas, shuffle } from '@polkadot-cloud/utils'; import React, { useRef, useState } from 'react'; import type { BondedPool, BondedPoolsContextState, MaybePool, NominationStatuses, + PoolNominations, } from 'contexts/Pools/types'; import { useStaking } from 'contexts/Staking'; -import type { AnyApi, AnyMetaBatch, Fn, MaybeAddress } from 'types'; +import type { AnyApi, MaybeAddress, Sync } from 'types'; import { useEffectIgnoreInitial } from '@polkadot-cloud/react/hooks'; import { useNetwork } from 'contexts/Network'; +import { useNetworkMetrics } from 'contexts/NetworkMetrics'; +import type { AnyJson } from '@polkadot-cloud/react/types'; import { useApi } from '../../Api'; import { usePoolsConfig } from '../PoolsConfig'; import { defaultBondedPoolsContext } from './defaults'; @@ -25,43 +28,88 @@ export const BondedPoolsProvider = ({ }) => { const { network } = useNetwork(); const { api, isReady } = useApi(); + const { activeEra } = useNetworkMetrics(); const { createAccounts, stats } = usePoolsConfig(); const { getNominationsStatusFromTargets } = useStaking(); const { lastPoolId } = stats; - // Stores the meta data batches for pool lists. - const [poolMetaBatches, setPoolMetaBatch]: AnyMetaBatch = useState({}); - const poolMetaBatchesRef = useRef(poolMetaBatches); - - // Stores the meta batch subscriptions for pool lists. - const poolSubs = useRef>({}); - // Store bonded pools. const [bondedPools, setBondedPools] = useState([]); - const unsubscribe = () => { - Object.values(poolSubs.current).map((batch: Fn[]) => - Object.entries(batch).map(([, v]) => v()) - ); - setBondedPools([]); - }; + // Track the sync status of `bondedPools`. + const bondedPoolsSynced = useRef('unsynced'); - // fetch all bonded pool entries - const fetchBondedPools = async () => { - if (!api) return; + // Store bonded pools metadata. + const [poolsMetaData, setPoolsMetadata] = useState>( + {} + ); + + // Store bonded pools nominations. + const [poolsNominations, setPoolsNominations] = useState< + Record + >({}); - const result = await api.query.nominationPools.bondedPools.entries(); - let exposures = result.map(([_keys, _val]: AnyApi) => { - const id = _keys.toHuman()[0]; - const pool = _val.toHuman(); - return getPoolWithAddresses(id, pool); + // Fetch all bonded pool entries and their metadata. + const fetchBondedPools = async () => { + if (!api || bondedPoolsSynced.current !== 'unsynced') return; + bondedPoolsSynced.current = 'syncing'; + + const ids: number[] = []; + + // Fetch bonded pools entries. + const bondedPoolsMulti = + await api.query.nominationPools.bondedPools.entries(); + let exposures = bondedPoolsMulti.map(([keys, val]: AnyApi) => { + const id = keys.toHuman()[0]; + ids.push(id); + return getPoolWithAddresses(id, val.toHuman()); }); exposures = shuffle(exposures); setBondedPools(exposures); + + // Fetch pools metadata. + const metadataMulti = await api.query.nominationPools.metadata.multi(ids); + setPoolsMetadata( + Object.fromEntries( + metadataMulti.map((m, i) => [ids[i], String(m.toHuman())]) + ) + ); + + bondedPoolsSynced.current = 'synced'; + }; + + // Fetches pool nominations and updates state. + const fetchPoolsNominations = async () => { + if (!api) return; + + const ids: number[] = []; + const nominationsMulti = await api.query.staking.nominators.multi( + bondedPools.map(({ addresses, id }) => { + ids.push(id); + return addresses.stash; + }) + ); + setPoolsNominations(formatPoolsNominations(nominationsMulti, ids)); }; - // queries a bonded pool and injects ID and addresses to a result. + // Format raw pool nominations data. + const formatPoolsNominations = (raw: AnyJson, ids: number[]) => + Object.fromEntries( + raw.map((n: AnyJson, i: number) => { + const human = n.toHuman() as PoolNominations; + if (!human) return [ids[i], null]; + return [ + ids[i], + { + ...human, + submittedIn: rmCommas(human.submittedIn), + }, + ]; + }) + ); + + // Queries a bonded pool and injects ID and addresses to a result. const queryBondedPool = async (id: number) => { if (!api) return null; @@ -79,137 +127,23 @@ export const BondedPoolsProvider = ({ }; }; - /* - Fetches a new batch of pool metadata. - Fetches the metadata of a pool that we assume to be a string. - structure: - { - key: { - [ - { - metadata: [], - } - ] - }, - }; - */ - const fetchPoolsMetaBatch = async ( - key: string, - p: AnyMetaBatch, - refetch = false - ) => { - if (!isReady || !api || !p.length) return; - - if (!refetch) { - // if already exists, do not re-fetch - if (poolMetaBatchesRef.current[key] !== undefined) { - return; - } - } else { - // tidy up if existing batch exists - const updatedPoolMetaBatches: AnyMetaBatch = { - ...poolMetaBatchesRef.current, - }; - delete updatedPoolMetaBatches[key]; - setStateWithRef( - updatedPoolMetaBatches, - setPoolMetaBatch, - poolMetaBatchesRef - ); - - if (poolSubs.current[key] !== undefined) { - for (const unsub of poolSubs.current[key]) { - unsub(); - } - } - } - - // aggregate pool ids and addresses - const ids = []; - const addresses = []; - for (const pool of p) { - ids.push(Number(pool.id)); - - if (pool?.addresses?.stash) { - addresses.push(pool.addresses.stash); - } - } - - // store batch ids - const batchesUpdated = Object.assign(poolMetaBatchesRef.current); - batchesUpdated[key] = {}; - batchesUpdated[key].ids = ids; - setStateWithRef( - { ...batchesUpdated }, - setPoolMetaBatch, - poolMetaBatchesRef - ); - - const subscribeToMetadata = async (_ids: AnyApi) => { - const unsub = await api.query.nominationPools.metadata.multi( - _ids, - (_metadata: AnyApi) => { - const metadata = []; - for (let i = 0; i < _metadata.length; i++) { - metadata.push(_metadata[i].toHuman()); - } - const updated = Object.assign(poolMetaBatchesRef.current); - updated[key].metadata = metadata; - - setStateWithRef({ ...updated }, setPoolMetaBatch, poolMetaBatchesRef); - } - ); - return unsub; - }; - - const subscribeToNominations = async (_addresses: AnyApi) => { - const unsub = await api.query.staking.nominators.multi( - _addresses, - (_nominations: AnyApi) => { - const nominations = []; - for (let i = 0; i < _nominations.length; i++) { - nominations.push(_nominations[i].toHuman()); - } - const updated = Object.assign(poolMetaBatchesRef.current); - updated[key].nominations = nominations; - setStateWithRef({ ...updated }, setPoolMetaBatch, poolMetaBatchesRef); - } - ); - return unsub; - }; - - // initiate subscriptions - await Promise.all([ - subscribeToMetadata(ids), - subscribeToNominations(addresses), - ]).then((unsubs: Fn[]) => { - addMetaBatchUnsubs(key, unsubs); - }); - }; - - /* - * Get bonded pool nomination statuses - */ + // Get bonded pool nomination statuses const getPoolNominationStatus = ( nominator: MaybeAddress, nomination: MaybeAddress ) => { const pool = bondedPools.find((p: any) => p.addresses.stash === nominator); - if (!pool) { - return 'waiting'; - } - // get pool targets from nominations metadata - const batchIndex = bondedPools.indexOf(pool); - const nominations = poolMetaBatches.bonded_pools?.nominations ?? []; - const targets = nominations[batchIndex]?.targets ?? []; + if (!pool) return 'waiting'; - const target = targets.find((t: string) => t === nomination); + // get pool targets from nominations metadata + const nominations = poolsNominations[pool.id]; + const targets = nominations ? nominations.targets : []; + const target = targets.find((t) => t === nomination); const nominationStatus = getNominationsStatusFromTargets(nominator, [ target, ]); - return getPoolNominationStatusCode(nominationStatus); }; @@ -233,18 +167,6 @@ export const BondedPoolsProvider = ({ return status; }; - /* - * Helper: to add mataBatch unsubs by key. - */ - const addMetaBatchUnsubs = (key: string, unsubs: Fn[]) => { - const newUnsubs = poolSubs.current; - const newUnsubItem = newUnsubs[key] ?? []; - - newUnsubItem.push(...unsubs); - newUnsubs[key] = newUnsubItem; - poolSubs.current = newUnsubs; - }; - /* * Helper: to add addresses to pool record. */ @@ -255,69 +177,40 @@ export const BondedPoolsProvider = ({ }); const getBondedPool = (poolId: MaybePool) => - bondedPools.find((p) => p.id === String(poolId)) ?? null; + bondedPools.find((p) => p.id === poolId) ?? null; /* - * poolSearchFilter - * Iterates through the supplied list and refers to the meta - * batch of the list to filter those list items that match - * the search term. - * Returns the updated filtered list. + * poolSearchFilter Iterates through the supplied list and refers to the meta batch of the list to + * filter those list items that match the search term. Returns the updated filtered list. */ - const poolSearchFilter = ( - list: any, - batchKey: string, - searchTerm: string - ) => { - const meta = poolMetaBatchesRef.current; - - if (meta[batchKey] === undefined) { - return list; - } + const poolSearchFilter = (list: any, searchTerm: string) => { const filteredList: any = []; for (const pool of list) { - const batchIndex = meta[batchKey].ids?.indexOf(Number(pool.id)) ?? -1; - - // if we cannot derive data, fallback to include pool in filtered list - if (batchIndex === -1) { + // If pool metadata has not yet been synced, include the pool in results. + if (!Object.values(poolsMetaData).length) { filteredList.push(pool); continue; } - const ids = meta[batchKey].ids ?? false; - const metadatas = meta[batchKey]?.metadata ?? false; - - if (!metadatas || !ids) { - filteredList.push(pool); - continue; - } - - const id = ids[batchIndex] ?? 0; const address = pool?.addresses?.stash ?? ''; - const metadata = metadatas[batchIndex] ?? ''; - + const metadata = poolsMetaData[pool.id] || ''; const metadataAsBytes = u8aToString(u8aUnwrapBytes(metadata)); const metadataSearch = ( metadataAsBytes === '' ? metadata : metadataAsBytes ).toLowerCase(); - if (String(id).includes(searchTerm.toLowerCase())) { + if (pool.id.includes(searchTerm.toLowerCase())) filteredList.push(pool); + if (address.toLowerCase().includes(searchTerm.toLowerCase())) filteredList.push(pool); - } - if (address.toLowerCase().includes(searchTerm.toLowerCase())) { - filteredList.push(pool); - } - if (metadataSearch.includes(searchTerm.toLowerCase())) { + if (metadataSearch.includes(searchTerm.toLowerCase())) filteredList.push(pool); - } } return filteredList; }; const updateBondedPools = (updatedPools: BondedPool[]) => { if (!updatedPools) return; - setBondedPools( bondedPools.map( (original) => @@ -326,6 +219,22 @@ export const BondedPoolsProvider = ({ ); }; + const updatePoolNominations = (id: number, newTargets: string[]) => { + const newPoolsNominations = { ...poolsNominations }; + + let record = newPoolsNominations?.[id]; + if (record !== null) { + record.targets = newTargets; + } else { + record = { + submittedIn: activeEra.index.toString(), + targets: newTargets, + suppressed: false, + }; + } + setPoolsNominations(newPoolsNominations); + }; + const removeFromBondedPools = (id: number) => { setBondedPools(bondedPools.filter((b: BondedPool) => b.id !== id)); }; @@ -409,7 +318,7 @@ export const BondedPoolsProvider = ({ // replaces the pool roles from roleEdits const replacePoolRoles = (poolId: number, roleEdits: any) => { - let pool = bondedPools.find((b) => String(b.id) === String(poolId)) || null; + let pool = bondedPools.find((b) => b.id === poolId) || null; if (!pool) return; @@ -422,9 +331,7 @@ export const BondedPoolsProvider = ({ }; const newBondedPools = [ - ...bondedPools.map((b) => - String(b.id) === String(poolId) && pool !== null ? pool : b - ), + ...bondedPools.map((b) => (b.id === poolId && pool !== null ? pool : b)), ]; setBondedPools(newBondedPools); @@ -432,28 +339,27 @@ export const BondedPoolsProvider = ({ // Clear existing state for network refresh. useEffectIgnoreInitial(() => { + bondedPoolsSynced.current = 'unsynced'; setBondedPools([]); - setStateWithRef({}, setPoolMetaBatch, poolMetaBatchesRef); + setPoolsMetadata({}); + setPoolsNominations({}); }, [network]); // Initial setup for fetching bonded pools. useEffectIgnoreInitial(() => { - if (isReady) fetchBondedPools(); - return () => { - unsubscribe(); - }; - }, [network, isReady, lastPoolId]); + if (isReady && lastPoolId) fetchBondedPools(); + }, [bondedPools, isReady, lastPoolId]); - // After bonded pools have synced, fetch metabatch. + // Re-fetch bonded pools nominations when active era changes or when `bondedPools` update. useEffectIgnoreInitial(() => { - if (bondedPools.length) - fetchPoolsMetaBatch('bonded_pools', bondedPools, true); - }, [bondedPools]); + if (!activeEra.index.isZero() && bondedPools.length) { + fetchPoolsNominations(); + } + }, [activeEra.index, bondedPools.length]); return ( {children} diff --git a/src/contexts/Pools/PoolMembers/index.tsx b/src/contexts/Pools/PoolMembers/index.tsx index bc3e9af98c..4772c53691 100644 --- a/src/contexts/Pools/PoolMembers/index.tsx +++ b/src/contexts/Pools/PoolMembers/index.tsx @@ -97,7 +97,7 @@ export const PoolMembersProvider = ({ }; const getMembersOfPoolFromNode = (poolId: number) => - poolMembersNode.filter((p: any) => p.poolId === String(poolId)) ?? null; + poolMembersNode.filter((p) => p.poolId === poolId) ?? null; // queries a pool member and formats to `PoolMember`. const queryPoolMember = async (who: MaybeAddress) => { diff --git a/src/contexts/Pools/types.ts b/src/contexts/Pools/types.ts index f8c068cff4..a89bb1cfae 100644 --- a/src/contexts/Pools/types.ts +++ b/src/contexts/Pools/types.ts @@ -60,7 +60,6 @@ export interface PoolMembership { // BondedPool types export interface BondedPoolsContextState { - fetchPoolsMetaBatch: (k: string, v: [], r?: boolean) => void; queryBondedPool: (p: number) => any; getBondedPool: (p: number) => BondedPool | null; updateBondedPools: (p: BondedPool[]) => void; @@ -71,9 +70,11 @@ export interface BondedPoolsContextState { getAccountRoles: (w: MaybeAddress) => any; getAccountPools: (w: MaybeAddress) => any; replacePoolRoles: (poolId: number, roleEdits: AnyJson) => void; - poolSearchFilter: (l: any, k: string, v: string) => void; + poolSearchFilter: (l: any, v: string) => void; bondedPools: BondedPool[]; - meta: AnyMetaBatch; + poolsMetaData: Record; + poolsNominations: Record; + updatePoolNominations: (id: number, nominations: string[]) => void; } export interface ActivePool { @@ -87,7 +88,7 @@ export interface ActivePool { export interface BondedPool { addresses: PoolAddresses; - id: number | string; + id: number; memberCounter: string; points: string; roles: { @@ -108,6 +109,12 @@ export interface BondedPool { }; } +export type PoolNominations = { + submittedIn: string; + suppressed: boolean; + targets: string[]; +} | null; + export type NominationStatuses = Record; export interface ActivePoolsContextState { diff --git a/src/library/Account/Pool.tsx b/src/library/Account/Pool.tsx index 0c416f7832..9cdfd4f1df 100644 --- a/src/library/Account/Pool.tsx +++ b/src/library/Account/Pool.tsx @@ -3,12 +3,9 @@ import { u8aToString, u8aUnwrapBytes } from '@polkadot/util'; import { ellipsisFn, remToUnit } from '@polkadot-cloud/utils'; -import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useApi } from 'contexts/Api'; import { useBondedPools } from 'contexts/Pools/BondedPools'; import { Polkicon } from '@polkadot-cloud/react'; -import { useActiveAccounts } from 'contexts/ActiveAccounts'; import { Wrapper } from './Wrapper'; import type { AccountProps } from './types'; @@ -20,44 +17,15 @@ export const Account = ({ fontSize = '1.05rem', }: AccountProps) => { const { t } = useTranslation('library'); - const { isReady } = useApi(); - const { activeAccount } = useActiveAccounts(); - const { fetchPoolsMetaBatch, meta } = useBondedPools(); + const { poolsMetaData } = useBondedPools(); - // is this the initial fetch - const [fetched, setFetched] = useState(false); - - const batchKey = 'pool_header'; - - // refetch when pool or active account changes - useEffect(() => { - setFetched(false); - }, [activeAccount, pool]); - - // configure pool list when network is ready to fetch - useEffect(() => { - if (isReady) { - setFetched(true); - - if (!fetched) { - getPoolMeta(); - } - } - }, [isReady, fetched]); - - // handle pool list bootstrapping - const getPoolMeta = () => { - const pools: any = [{ id: pool.id }]; - fetchPoolsMetaBatch(batchKey, pools, true); - }; - - const metaBatch = meta[batchKey]; - const metaData = metaBatch?.metadata?.[0]; - const syncing = metaData === undefined; + const syncing = !Object.values(poolsMetaData).length; // display value const defaultDisplay = ellipsisFn(pool.addresses.stash); - let display = syncing ? t('syncing') : metaData ?? defaultDisplay; + let display = syncing + ? t('syncing') + : poolsMetaData[pool.id] ?? defaultDisplay; // check if super identity has been byte encoded const displayAsBytes = u8aToString(u8aUnwrapBytes(display)); diff --git a/src/library/Hooks/usePoolFilters/index.tsx b/src/library/Hooks/usePoolFilters/index.tsx index 07e87b87bd..e8dff2f588 100644 --- a/src/library/Hooks/usePoolFilters/index.tsx +++ b/src/library/Hooks/usePoolFilters/index.tsx @@ -8,27 +8,20 @@ import type { AnyFunction, AnyJson } from 'types'; export const usePoolFilters = () => { const { t } = useTranslation('library'); - const { meta } = useBondedPools(); + const { poolsNominations } = useBondedPools(); const { getNominationsStatusFromTargets } = useStaking(); const { getPoolNominationStatusCode } = useBondedPools(); /* - * include active pools. - * Iterates through the supplied list and refers to the meta - * batch of the list to filter those list items that are - * actively nominating. + * Include active pools. * Returns the updated filtered list. */ - const includeActive = (list: any, batchKey: string) => { - // get pool targets from nominations meta batch - const nominations = meta[batchKey]?.nominations ?? []; - if (!nominations) { - return list; - } - let i = -1; + const includeActive = (list: any) => { + if (!Object.keys(poolsNominations).length) return list; + const filteredList = list.filter((p: BondedPool) => { - i++; - const targets = nominations[i]?.targets ?? []; + const nominations = poolsNominations[p.id]; + const targets = nominations?.targets || []; const status = getPoolNominationStatusCode( getNominationsStatusFromTargets(p.addresses.stash, targets) ); @@ -38,22 +31,15 @@ export const usePoolFilters = () => { }; /* - * dont include active pools. - * Iterates through the supplied list and refers to the meta - * batch of the list to filter those list items that are - * actively nominating. + * Dont include active pools. * Returns the updated filtered list. */ - const excludeActive = (list: any, batchKey: string) => { - // get pool targets from nominations meta batch - const nominations = meta[batchKey]?.nominations ?? []; - if (!nominations) { - return list; - } - let i = -1; + const excludeActive = (list: any) => { + if (!Object.keys(poolsNominations).length) return list; + const filteredList = list.filter((p: BondedPool) => { - i++; - const targets = nominations[i]?.targets ?? []; + const nominations = poolsNominations[p.id]; + const targets = nominations?.targets || []; const status = getPoolNominationStatusCode( getNominationsStatusFromTargets(p.addresses.stash, targets) ); @@ -135,20 +121,19 @@ export const usePoolFilters = () => { const applyFilter = ( includes: string[] | null, excludes: string[] | null, - list: AnyJson, - batchKey: string + list: AnyJson ) => { if (!excludes && !includes) { return list; } if (includes) { for (const fn of getFiltersFromKey(includes, 'include')) { - list = fn(list, batchKey); + list = fn(list); } } if (excludes) { for (const fn of getFiltersFromKey(excludes, 'exclude')) { - list = fn(list, batchKey); + list = fn(list); } } return list; diff --git a/src/library/ListItem/Labels/PoolBonded.tsx b/src/library/ListItem/Labels/PoolBonded.tsx index e2a12a473c..c73285fd7f 100644 --- a/src/library/ListItem/Labels/PoolBonded.tsx +++ b/src/library/ListItem/Labels/PoolBonded.tsx @@ -15,26 +15,18 @@ import { ValidatorStatusWrapper } from 'library/ListItem/Wrappers'; import type { Pool } from 'library/Pool/types'; import { useNetwork } from 'contexts/Network'; -export const PoolBonded = ({ - pool, - batchKey, - batchIndex, -}: { - pool: Pool; - batchKey: string; - batchIndex: number; -}) => { +export const PoolBonded = ({ pool }: { pool: Pool }) => { const { t } = useTranslation('library'); const { networkData: { units, unit }, } = useNetwork(); - const { meta, getPoolNominationStatusCode } = useBondedPools(); + const { getPoolNominationStatusCode, poolsNominations } = useBondedPools(); const { eraStakers, getNominationsStatusFromTargets } = useStaking(); const { addresses, points } = pool; // get pool targets from nominations meta batch - const nominations = meta[batchKey]?.nominations ?? []; - const targets = nominations[batchIndex]?.targets ?? []; + const nominations = poolsNominations[pool.id]; + const targets = nominations?.targets || []; // store nomination status in state const [nominationsStatus, setNominationsStatus] = @@ -65,7 +57,7 @@ export const PoolBonded = ({ // recalculate nominations status useEffect(() => { handleNominationsStatus(); - }, [meta, pool, eraStakers.stakers.length]); + }, [pool, eraStakers.stakers.length, Object.keys(poolsNominations).length]); // calculate total bonded pool amount const poolBonded = planckToUnit(new BigNumber(rmCommas(points)), units); diff --git a/src/library/ListItem/Labels/PoolIdentity.tsx b/src/library/ListItem/Labels/PoolIdentity.tsx index b9111f1d6d..642b7d94fd 100644 --- a/src/library/ListItem/Labels/PoolIdentity.tsx +++ b/src/library/ListItem/Labels/PoolIdentity.tsx @@ -8,21 +8,15 @@ import { IdentityWrapper } from 'library/ListItem/Wrappers'; import type { PoolIdentityProps } from '../types'; export const PoolIdentity = ({ - pool, - batchKey, - batchIndex, + pool: { addresses, id }, }: PoolIdentityProps) => { - const { meta } = useBondedPools(); - const { addresses } = pool; + const { poolsMetaData } = useBondedPools(); + const metadataSynced = Object.values(poolsMetaData).length > 0 ?? false; - // get metadata from pools metabatch - const metadata = meta[batchKey]?.metadata ?? []; - - // aggregate synced status - const metadataSynced = metadata.length > 0 ?? false; - - // pool display name - const display = determinePoolDisplay(addresses.stash, metadata[batchIndex]); + const display = determinePoolDisplay( + addresses.stash, + poolsMetaData[Number(id)] + ); return ( diff --git a/src/library/ListItem/types.ts b/src/library/ListItem/types.ts index 0a1967deab..c6808b504b 100644 --- a/src/library/ListItem/types.ts +++ b/src/library/ListItem/types.ts @@ -25,8 +25,6 @@ export interface IdentityProps { } export interface PoolIdentityProps { - batchIndex: number; - batchKey: string; pool: BondedPool; } diff --git a/src/library/Pool/index.tsx b/src/library/Pool/index.tsx index 98ed0be7f7..1b8cd159fa 100644 --- a/src/library/Pool/index.tsx +++ b/src/library/Pool/index.tsx @@ -34,15 +34,15 @@ import { PoolId } from '../ListItem/Labels/PoolId'; import type { PoolProps } from './types'; import { Rewards } from './Rewards'; -export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => { +export const Pool = ({ pool }: PoolProps) => { const { t } = useTranslation('library'); const { memberCounter, addresses, id, state } = pool; const { isPoolSyncing } = useUi(); - const { meta } = useBondedPools(); const { validators } = useValidators(); const { setActiveTab } = usePoolsTabs(); const { openModal } = useOverlay().modal; const { membership } = usePoolMemberships(); + const { poolsNominations } = useBondedPools(); const { activeAccount } = useActiveAccounts(); const { addNotification } = useNotifications(); const { isReadOnlyAccount } = useImportedAccounts(); @@ -52,10 +52,10 @@ export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => { const currentCommission = getCurrentCommission(id); // get metadata from pools metabatch - const nominations = meta[batchKey]?.nominations ?? []; + const nominations = poolsNominations[pool.id]; // get pool targets from nominations metadata - const targets = nominations[batchIndex]?.targets ?? []; + const targets = nominations?.targets || []; // extract validator entries from pool targets const targetValidators = validators.filter(({ address }) => @@ -126,11 +126,7 @@ export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => {
- +
@@ -155,11 +151,7 @@ export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => { - + {displayJoin && ( diff --git a/src/library/Pool/types.ts b/src/library/Pool/types.ts index acaf7ae0b0..d720ac34e0 100644 --- a/src/library/Pool/types.ts +++ b/src/library/Pool/types.ts @@ -6,8 +6,6 @@ import type { DisplayFor } from 'types'; export interface PoolProps { pool: Pool; - batchKey: string; - batchIndex: number; } export interface Pool { diff --git a/src/library/PoolList/Default.tsx b/src/library/PoolList/Default.tsx index 9c470d015b..139ae4925a 100644 --- a/src/library/PoolList/Default.tsx +++ b/src/library/PoolList/Default.tsx @@ -33,7 +33,6 @@ import type { PoolListProps } from './types'; export const PoolList = ({ allowMoreCols, pagination, - batchKey = '', disableThrottle, allowSearch, pools, @@ -52,7 +51,7 @@ export const PoolList = ({ const { listFormat, setListFormat } = usePoolList(); const { getFilters, setMultiFilters, getSearchTerm, setSearchTerm } = useFilters(); - const { fetchPoolsMetaBatch, poolSearchFilter, meta } = useBondedPools(); + const { poolSearchFilter, poolsNominations } = useBondedPools(); const includes = getFilters('include', 'pools'); const excludes = getFilters('exclude', 'pools'); @@ -101,16 +100,15 @@ export const PoolList = ({ setPoolsDefault(pools); setListPools(pools); setFetched(true); - fetchPoolsMetaBatch(batchKey, pools, true); }; // handle filter / order update const handlePoolsFilterUpdate = ( filteredPools: any = Object.assign(poolsDefault) ) => { - filteredPools = applyFilter(includes, excludes, filteredPools, batchKey); + filteredPools = applyFilter(includes, excludes, filteredPools); if (searchTerm) { - filteredPools = poolSearchFilter(filteredPools, batchKey, searchTerm); + filteredPools = poolSearchFilter(filteredPools, searchTerm); } setListPools(filteredPools); setPage(1); @@ -120,8 +118,8 @@ export const PoolList = ({ const handleSearchChange = (e: React.FormEvent) => { const newValue = e.currentTarget.value; let filteredPools = Object.assign(poolsDefault); - filteredPools = applyFilter(includes, excludes, filteredPools, batchKey); - filteredPools = poolSearchFilter(filteredPools, batchKey, newValue); + filteredPools = applyFilter(includes, excludes, filteredPools); + filteredPools = poolSearchFilter(filteredPools, newValue); // ensure no duplicates filteredPools = filteredPools.filter( @@ -160,10 +158,10 @@ export const PoolList = ({ // List ui changes / validator changes trigger re-render of list. useEffect(() => { // only filter when pool nominations have been synced. - if (!isSyncing && meta[batchKey]?.nominations) { + if (!isSyncing && Object.keys(poolsNominations).length) { handlePoolsFilterUpdate(); } - }, [isSyncing, includes, excludes, meta]); + }, [isSyncing, includes, excludes, Object.keys(poolsNominations).length]); // Scroll to top of the window on every filter. useEffect(() => { @@ -262,11 +260,7 @@ export const PoolList = ({ }, }} > - + ))} diff --git a/src/library/PoolList/types.ts b/src/library/PoolList/types.ts index e99b0de132..e80be52056 100644 --- a/src/library/PoolList/types.ts +++ b/src/library/PoolList/types.ts @@ -11,7 +11,6 @@ export interface PoolListProps { allowMoreCols?: boolean; allowSearch?: boolean; pagination?: boolean; - batchKey?: string; disableThrottle?: boolean; refetchOnListUpdate?: string; allowListFormat?: boolean; diff --git a/src/modals/ManagePool/Forms/SetMetadata.tsx b/src/modals/ManagePool/Forms/SetMetadata.tsx index 3347326cd0..166eae4be6 100644 --- a/src/modals/ManagePool/Forms/SetMetadata.tsx +++ b/src/modals/ManagePool/Forms/SetMetadata.tsx @@ -26,7 +26,7 @@ export const SetMetadata = ({ setSection, section }: any) => { const { setModalStatus } = useOverlay().modal; const { activeAccount } = useActiveAccounts(); const { isOwner, selectedActivePool } = useActivePools(); - const { bondedPools, meta } = useBondedPools(); + const { bondedPools, poolsMetaData } = useBondedPools(); const { getSignerWarnings } = useSignerWarnings(); const poolId = selectedActivePool?.id; @@ -43,9 +43,7 @@ export const SetMetadata = ({ setSection, section }: any) => { ({ addresses }) => addresses.stash === selectedActivePool?.addresses.stash ); if (pool) { - const metadataBatch = meta.bonded_pools?.metadata ?? []; - const batchIndex = bondedPools.indexOf(pool); - setMetadata(u8aToString(u8aUnwrapBytes(metadataBatch[batchIndex]))); + setMetadata(u8aToString(u8aUnwrapBytes(poolsMetaData[Number(pool.id)]))); } }, [section]); diff --git a/src/pages/Payouts/PayoutList/index.tsx b/src/pages/Payouts/PayoutList/index.tsx index 9d9143f051..0a1ad28c81 100644 --- a/src/pages/Payouts/PayoutList/index.tsx +++ b/src/pages/Payouts/PayoutList/index.tsx @@ -159,9 +159,7 @@ export const PayoutListInner = ({ ); // get pool if it exists - const pool = bondedPools.find( - ({ id }) => String(id) === String(p.pool_id) - ); + const pool = bondedPools.find(({ id }) => id === p.pool_id); const batchIndex = validator ? validators.indexOf(validator) @@ -220,11 +218,7 @@ export const PayoutListInner = ({ {label === t('payouts.poolClaim') && ( <> {pool ? ( - + ) : (

{t('payouts.fromPool')} {p.pool_id} diff --git a/src/pages/Pools/Home/Favorites/index.tsx b/src/pages/Pools/Home/Favorites/index.tsx index 62a91638d8..f704e0c6a4 100644 --- a/src/pages/Pools/Home/Favorites/index.tsx +++ b/src/pages/Pools/Home/Favorites/index.tsx @@ -49,12 +49,7 @@ export const PoolFavorites = () => { isReady && (favoritesList.length > 0 ? ( - + ) : ( {t('pools.noFavorites')} diff --git a/src/pages/Pools/Home/Status/MembershipStatus.tsx b/src/pages/Pools/Home/Status/MembershipStatus.tsx index 54055f4643..442a0b05ea 100644 --- a/src/pages/Pools/Home/Status/MembershipStatus.tsx +++ b/src/pages/Pools/Home/Status/MembershipStatus.tsx @@ -28,9 +28,9 @@ export const MembershipStatus = ({ const { openModal } = useOverlay().modal; const { activeAccount } = useActiveAccounts(); const { label, buttons } = useStatusButtons(); - const { bondedPools, meta } = useBondedPools(); const { isReadOnlyAccount } = useImportedAccounts(); const { getTransferOptions } = useTransferOptions(); + const { bondedPools, poolsMetaData } = useBondedPools(); const { selectedActivePool, isOwner, isBouncer, isMember } = useActivePools(); const { active } = getTransferOptions(activeAccount).pool; @@ -41,15 +41,13 @@ export const MembershipStatus = ({ if (selectedActivePool) { const pool = bondedPools.find( - (p: any) => p.addresses.stash === selectedActivePool.addresses.stash + (p) => p.addresses.stash === selectedActivePool.addresses.stash ); if (pool) { // Determine pool membership display. - const metadata = meta.bonded_pools?.metadata ?? []; - const batchIndex = bondedPools.indexOf(pool); membershipDisplay = determinePoolDisplay( selectedActivePool.addresses.stash, - metadata[batchIndex] + poolsMetaData[Number(pool.id)] ); } diff --git a/src/pages/Pools/Home/index.tsx b/src/pages/Pools/Home/index.tsx index f9de8fda5a..4334b1232b 100644 --- a/src/pages/Pools/Home/index.tsx +++ b/src/pages/Pools/Home/index.tsx @@ -146,7 +146,6 @@ export const HomeInner = () => {