ghost-portal/packages/page-collator/src/useCollators.ts
Jaco 3bf0562a51
Collators support (#7495)
* Collators support

* Ordering

* Adjust

* Adjust icons

* Bump API

* Adjust

* Rebuild
2022-04-30 15:07:00 +03:00

99 lines
2.7 KiB
TypeScript

// Copyright 2017-2022 @polkadot/app-collator authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BTreeSet } from '@polkadot/types';
import type { AccountId32, Balance } from '@polkadot/types/interfaces';
import type { BN } from '@polkadot/util';
import type { Collator } from './types';
import { useEffect, useMemo, useState } from 'react';
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
type Authored = Record<string, BN>;
interface PalletCollatorSelectionCandidateInfo {
deposit: Balance;
who: AccountId32;
}
const OPT_INV = {
transform: (invulnerables: AccountId32[]) =>
invulnerables.map((accountId32): Collator => ({
accountId: accountId32.toString(),
isInvulnerable: true
}))
};
const OPT_CAN = {
transform: (candidates: PalletCollatorSelectionCandidateInfo[] | BTreeSet) =>
Array.isArray(candidates)
? candidates.map(({ deposit, who }): Collator => ({
accountId: who.toString(),
deposit,
isInvulnerable: false
}))
: candidates.strings.map((accountId): Collator => ({
accountId,
isInvulnerable: false
}))
};
const OPT_AUT = {
transform: ([[accountIds], lastAuthoredBlocks]: [[string[]], BN[]]) =>
accountIds.reduce<Authored>((map, accountId, index): Authored => ({
...map,
[accountId]: lastAuthoredBlocks[index]
}), {}),
withParamsTransform: true
};
function includeAuthors (prev: Collator[], authored: Authored): Collator[] {
let hasDiff = false;
const adjusted = prev.map((c): Collator => {
if (authored[c.accountId] && (!c.lastBlock || !authored[c.accountId].eq(c.lastBlock))) {
hasDiff = true;
return { ...c, lastBlock: authored[c.accountId] };
}
return c;
});
return hasDiff
? adjusted
: prev;
}
function useCollatorImpl (): Collator[] | undefined {
const { api } = useApi();
const [state, setState] = useState<Collator[] | undefined>();
const accountIds = useMemo(
() => state && state.map(({ accountId }) => accountId),
[state]
);
const invulnerables = useCall<Collator[]>(api.query.collatorSelection.invulnerables, [], OPT_INV);
const candidates = useCall<Collator[]>(api.query.collatorSelection.candidates, [], OPT_CAN);
const lastBlocks = useCall<Authored>(accountIds && api.query.collatorSelection.lastAuthoredBlock?.multi, [accountIds], OPT_AUT);
useEffect(
() => invulnerables && candidates && setState(() =>
[...invulnerables, ...candidates]
),
[candidates, invulnerables]
);
useEffect(
() => lastBlocks && setState((prev) =>
prev && includeAuthors(prev, lastBlocks)
),
[lastBlocks]
);
return state;
}
export default createNamedHook('useCollatorImpl', useCollatorImpl);