Adjust useCall options (#3430)

* Adjust useCall options

* Extract useCall options

* typo

* Apply suggestions from code review

* Adjust param creation in calls
This commit is contained in:
Jaco Greeff 2020-08-17 12:24:51 +02:00 committed by GitHub
parent 47bd6d319d
commit ebad8635f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
78 changed files with 307 additions and 244 deletions

View File

@ -66,7 +66,7 @@ function Status ({ optionsAll }: Props): React.ReactElement<Props> {
const { api, isApiReady } = useApi();
const { allAccounts } = useAccounts();
const { t } = useTranslation();
const events = useCall<EventRecord[]>(isApiReady && api.query.system?.events, []);
const events = useCall<EventRecord[]>(isApiReady && api.query.system?.events);
useEffect((): void => {
const filtered = filterEvents(allAccounts, t, optionsAll, events);

View File

@ -21,7 +21,7 @@ interface Props {
function ChainInfo ({ className = '', isToggled, onClick }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const runtimeVersion = useCall<RuntimeVersion>(api.rpc.state.subscribeRuntimeVersion, []);
const runtimeVersion = useCall<RuntimeVersion>(api.rpc.state.subscribeRuntimeVersion);
return (
<div

View File

@ -59,7 +59,7 @@ function checkVisible (name: string, { api, isApiConnected, isApiReady }: ApiPro
function Item ({ isCollapsed, onClick, route }: Props): React.ReactElement<Props> | null {
const { allAccounts, hasAccounts } = useAccounts();
const apiProps = useApi();
const sudoKey = useCall<AccountId>(apiProps.isApiReady && apiProps.api.query.sudo?.key, []);
const sudoKey = useCall<AccountId>(apiProps.isApiReady && apiProps.api.query.sudo?.key);
const [hasSudo, setHasSudo] = useState(false);
const [isVisible, setIsVisible] = useState(false);
const count = (route.useCounter || DUMMY_COUNTER)();

View File

@ -7,15 +7,14 @@ import { useApi, useCall } from '@polkadot/react-hooks';
function WarmUp (): React.ReactElement {
const { api, isApiReady } = useApi();
const indexes = useCall<unknown>(isApiReady && api.derive.accounts?.indexes, []);
const registrars = useCall<unknown>(isApiReady && api.query.identity?.registrars, []);
const staking = null; // useCall<unknown>(isApiReady && api.derive.staking?.overview, []);
const issuance = useCall<unknown>(isApiReady && api.query.balances?.totalIssuance, []);
const historyDepth = useCall<unknown>(api.query.staking?.historyDepth, []);
const indexes = useCall<unknown>(isApiReady && api.derive.accounts?.indexes);
const registrars = useCall<unknown>(isApiReady && api.query.identity?.registrars);
const issuance = useCall<unknown>(isApiReady && api.query.balances?.totalIssuance);
const historyDepth = useCall<unknown>(api.query.staking?.historyDepth);
const [hasValues, setHasValues] = useState(false);
useEffect((): void => {
setHasValues(!!historyDepth || !!indexes || !!issuance || !!registrars || !!staking);
setHasValues(!!historyDepth || !!indexes || !!issuance || !!registrars);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

View File

@ -73,16 +73,18 @@ function createClearDemocracyTx (api: ApiPromise, address: string, unlockableIds
);
}
const transformRecovery = {
transform: (opt: Option<RecoveryConfig>) => opt.unwrapOr(null)
};
function Account ({ account: { address, meta }, className = '', delegation, filter, isFavorite, proxy, setBalance, toggleFavorite }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { queueExtrinsic } = useContext(StatusContext);
const api = useApi();
const bestNumber = useCall<BN>(api.api.derive.chain.bestNumber, []);
const bestNumber = useCall<BN>(api.api.derive.chain.bestNumber);
const balancesAll = useCall<DeriveBalancesAll>(api.api.derive.balances.all, [address]);
const democracyLocks = useCall<DeriveDemocracyLock[]>(api.api.derive.democracy?.locks, [address]);
const recoveryInfo = useCall<RecoveryConfig | null>(api.api.query.recovery?.recoverable, [address], {
transform: (opt: Option<RecoveryConfig>) => opt.unwrapOr(null)
});
const recoveryInfo = useCall<RecoveryConfig | null>(api.api.query.recovery?.recoverable, [address], transformRecovery);
const multiInfos = useMultisigApprovals(address);
const proxyInfo = useProxies(address);
const { flags: { isDevelopment, isExternal, isHardware, isInjected, isMultisig, isProxied }, genesisHash, identity, name: accName, onSetGenesisHash, tags } = useAccountInfo(address);

View File

@ -79,14 +79,18 @@ function IdentitySub ({ address, index, name, setAddress, setName, t }: SubProps
const IdentitySubMemo = React.memo(IdentitySub);
const transformIds = {
transform: ([, ids]: ITuple<[Balance, Vec<AccountId>]>) => ids.map((a) => a.toString())
};
const transformInfo = { withParams: true };
function IdentitySubModal ({ address, className, onClose }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { allAccounts } = useAccounts();
const queryIds = useCall<string[]>(api.query.identity.subsOf, [address], {
transform: ([, ids]: ITuple<[Balance, Vec<AccountId>]>) => ids.map((a) => a.toString())
});
const queryInfos = useCall<[[string[]], Option<ITuple<[AccountId, Data]>>[]]>(queryIds && queryIds.length !== 0 && api.query.identity.superOf.multi, [queryIds], { withParams: true });
const queryIds = useCall<string[]>(api.query.identity.subsOf, [address], transformIds);
const queryInfos = useCall<[[string[]], Option<ITuple<[AccountId, Data]>>[]]>(queryIds && queryIds.length !== 0 && api.query.identity.superOf.multi, [queryIds], transformInfo);
const [infos, setInfos] = useState<[string, string][] | undefined>();
useEffect((): void => {

View File

@ -68,6 +68,10 @@ const Signature = styled.textarea`
}
`;
const transformStatement = {
transform: (option: Option<StatementKind>) => option.unwrapOr(null)
};
function ClaimsApp (): React.ReactElement {
const [didCopy, setDidCopy] = useState(false);
const [ethereumAddress, setEthereumAddress] = useState<string | undefined | null>(null);
@ -165,9 +169,7 @@ function ClaimsApp (): React.ReactElement {
// If it's 1/ not preclaimed and 2/ not the old claiming process, fetch the
// statement kind to sign.
const statementKind = useCall<StatementKind | null>(!isPreclaimed && !isOldClaimProcess && !!ethereumAddress && api.query.claims.signing, [ethereumAddress], {
transform: (option: Option<StatementKind>) => option.unwrapOr(null)
});
const statementKind = useCall<StatementKind | null>(!isPreclaimed && !isOldClaimProcess && !!ethereumAddress && api.query.claims.signing, [ethereumAddress], transformStatement);
const statementSentence = getStatement(systemChain, statementKind)?.sentence || '';

View File

@ -20,29 +20,29 @@ interface Props {
prime: AccountId | null;
}
function transformVotes (entries: DeriveCouncilVotes): Record<string, AccountId[]> {
return entries.reduce((result: Record<string, AccountId[]>, [voter, { votes }]): Record<string, AccountId[]> => {
votes.forEach((candidate): void => {
const address = candidate.toString();
const transformVotes = {
transform: (entries: DeriveCouncilVotes): Record<string, AccountId[]> => {
return entries.reduce((result: Record<string, AccountId[]>, [voter, { votes }]): Record<string, AccountId[]> => {
votes.forEach((candidate): void => {
const address = candidate.toString();
if (!result[address]) {
result[address] = [];
}
if (!result[address]) {
result[address] = [];
}
result[address].push(voter);
});
result[address].push(voter);
});
return result;
}, {});
}
return result;
}, {});
}
};
function Overview ({ className = '', prime }: Props): React.ReactElement<Props> {
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const electionsInfo = useCall<DeriveElectionsInfo>(api.derive.elections.info, []);
const allVotes = useCall<Record<string, AccountId[]>>(api.derive.council.votes, [], {
transform: transformVotes
});
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const electionsInfo = useCall<DeriveElectionsInfo>(api.derive.elections.info);
const allVotes = useCall<Record<string, AccountId[]>>(api.derive.council.votes, undefined, transformVotes);
return (
<div className={className}>

View File

@ -25,14 +25,16 @@ interface Props {
className?: string;
}
const transformPrime = {
transform: (result: Option<AccountId>): AccountId | null => result.unwrapOr(null)
};
function CouncilApp ({ basePath, className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { pathname } = useLocation();
const numMotions = useCounter();
const prime = useCall<AccountId | null>(api.query.council.prime, [], {
transform: (result: Option<AccountId>): AccountId | null => result.unwrapOr(null)
}) || null;
const prime = useCall<AccountId | null>(api.query.council.prime, undefined, transformPrime) || null;
const motions = useCall<DeriveCollectiveProposals>(api.derive.council.proposals);
const items = useMemo(() => [

View File

@ -6,16 +6,14 @@ import { DeriveCollectiveProposals } from '@polkadot/api-derive/types';
import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';
function transform (motions: DeriveCollectiveProposals): number {
return motions.filter(({ votes }): boolean => !!votes).length;
}
const transformCounter = {
transform: (motions: DeriveCollectiveProposals) => motions.filter(({ votes }): boolean => !!votes).length
};
export default function useCounter (): number {
const { hasAccounts } = useAccounts();
const { api, isApiReady } = useApi();
const counter = useCall<number>(isApiReady && hasAccounts && api.derive.council?.proposals, [], {
transform
}) || 0;
const counter = useCall<number>(isApiReady && hasAccounts && api.derive.council?.proposals, undefined, transformCounter) || 0;
return counter;
}

View File

@ -9,7 +9,7 @@ import React from 'react';
import { LinkExternal } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
import { BlockToTime } from '@polkadot/react-query';
import { BN_ZERO, formatNumber } from '@polkadot/util';
import { formatNumber } from '@polkadot/util';
import ProposalCell from './ProposalCell';
import PreImageButton from './PreImageButton';
@ -20,7 +20,7 @@ interface Props {
function DispatchEntry ({ value: { at, image, imageHash, index } }: Props): React.ReactElement<Props> {
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []) || BN_ZERO;
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
return (
<tr>

View File

@ -18,7 +18,7 @@ interface Props {
function DispatchQueue ({ className }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const queued = useCall<DeriveDispatch[]>(api.derive.democracy.dispatchQueue, []);
const queued = useCall<DeriveDispatch[]>(api.derive.democracy.dispatchQueue);
const headerRef = useRef([
[t('dispatch queue'), 'start', 2],

View File

@ -18,7 +18,7 @@ interface Props {
function Externals ({ className }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const external = useCall<DeriveProposalExternal | null>(api.derive.democracy.nextExternal, []);
const external = useCall<DeriveProposalExternal | null>(api.derive.democracy.nextExternal);
const headerRef = useRef([
[t('external'), 'start'],

View File

@ -18,7 +18,7 @@ interface Props {
function Proposals ({ className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const proposals = useCall<DeriveProposal[]>(api.derive.democracy.proposals, []);
const proposals = useCall<DeriveProposal[]>(api.derive.democracy.proposals);
const headerRef = useRef([
[t('proposals'), 'start', 2],

View File

@ -40,8 +40,8 @@ function Referendum ({ className = '', value: { allAye, allNay, image, imageHash
const { t } = useTranslation();
const { api } = useApi();
const { allAccounts } = useAccounts();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const totalIssuance = useCall<Balance>(api.query.balances.totalIssuance, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const totalIssuance = useCall<Balance>(api.query.balances.totalIssuance);
const [percentages, setPercentages] = useState<Percentages | null>(null);
const [{ hasVoted, hasVotedAye }, setHasVoted] = useState<VoteType>({ hasVoted: false, hasVotedAye: false });
const { changeAye, changeNay } = useChangeCalc(status.threshold, votedAye, votedNay, votedTotal);

View File

@ -18,7 +18,8 @@ interface Props {
function Scheduled ({ className = '', value: { blockNumber, call, maybePeriodic } }: Props): React.ReactElement<Props> {
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const period = maybePeriodic.unwrapOr(null);
return (

View File

@ -17,29 +17,29 @@ interface Props {
className?: string;
}
function transformEntries (entries: [{ args: [BlockNumber] }, Option<Scheduled>[]][]): ScheduledExt[] {
return entries
.filter(([, vecSchedOpt]) => vecSchedOpt.some((schedOpt) => schedOpt.isSome))
.reduce((items: ScheduledExt[], [key, vecSchedOpt]): ScheduledExt[] => {
const blockNumber = key.args[0];
const transformEntries = {
transform: (entries: [{ args: [BlockNumber] }, Option<Scheduled>[]][]): ScheduledExt[] => {
return entries
.filter(([, vecSchedOpt]) => vecSchedOpt.some((schedOpt) => schedOpt.isSome))
.reduce((items: ScheduledExt[], [key, vecSchedOpt]): ScheduledExt[] => {
const blockNumber = key.args[0];
return vecSchedOpt
.filter((schedOpt) => schedOpt.isSome)
.map((schedOpt) => schedOpt.unwrap())
.reduce((items: ScheduledExt[], { call, maybeId, maybePeriodic, priority }, index) => {
items.push({ blockNumber, call, key: `${blockNumber.toString()}-${index}`, maybeId, maybePeriodic, priority });
return vecSchedOpt
.filter((schedOpt) => schedOpt.isSome)
.map((schedOpt) => schedOpt.unwrap())
.reduce((items: ScheduledExt[], { call, maybeId, maybePeriodic, priority }, index) => {
items.push({ blockNumber, call, key: `${blockNumber.toString()}-${index}`, maybeId, maybePeriodic, priority });
return items;
}, items);
}, []);
}
return items;
}, items);
}, []);
}
};
function Schedule ({ className = '' }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const items = useCall<ScheduledExt[]>(api.query.scheduler.agenda.entries as any, [], {
transform: transformEntries
});
const items = useCall<ScheduledExt[]>(api.query.scheduler.agenda.entries as any, undefined, transformEntries);
const headerRef = useRef([
[t('scheduled'), 'start'],

View File

@ -17,10 +17,10 @@ interface Props {
function Summary ({ referendumCount }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const activeProposals = useCall<any[]>(api.derive.democracy.proposals, []);
const bestNumber = useCall<BN>(api.derive.chain.bestNumber, []);
const publicPropCount = useCall<BN>(api.query.democracy.publicPropCount, []);
const referendumTotal = useCall<BN>(api.query.democracy.referendumCount, []);
const activeProposals = useCall<unknown[]>(api.derive.democracy.proposals);
const bestNumber = useCall<BN>(api.derive.chain.bestNumber);
const publicPropCount = useCall<BN>(api.query.democracy.publicPropCount);
const referendumTotal = useCall<BN>(api.query.democracy.referendumCount);
return (
<SummaryBox>

View File

@ -30,12 +30,14 @@ interface ParamState {
values: Value[];
}
const transformProposal = {
transform: (optProp: Option<TreasuryProposal>) => optProp.unwrapOr(null)
};
function TreasuryCell ({ className = '', value }: Props): React.ReactElement<Props> | null {
const { api } = useApi();
const [proposalId] = useState(value.unwrap());
const proposal = useCall<TreasuryProposal | null>(api.query.treasury.proposals, [proposalId], {
transform: (optProp: Option<TreasuryProposal>) => optProp.unwrapOr(null)
});
const proposal = useCall<TreasuryProposal | null>(api.query.treasury.proposals, [proposalId], transformProposal);
const [{ params, values }, setExtracted] = useState<ParamState>({ params: [], values: [] });
useEffect((): void => {

View File

@ -28,7 +28,7 @@ function Overview ({ className }: Props): React.ReactElement<Props> {
const { api } = useApi();
const [isPreimageOpen, togglePreimage] = useToggle();
const [isProposeOpen, togglePropose] = useToggle();
const referendums = useCall<DeriveReferendumExt[]>(api.derive.democracy.referendums, []);
const referendums = useCall<DeriveReferendumExt[]>(api.derive.democracy.referendums);
return (
<div className={className}>

View File

@ -18,7 +18,7 @@ interface Result {
export default function useChangeCalc (threshold: VoteThreshold, votedAye: BN, votedNay: BN, votedTotal: BN): Result {
const { api } = useApi();
const sqrtElectorate = useCall<BN>(api.derive.democracy.sqrtElectorate, []);
const sqrtElectorate = useCall<BN>(api.derive.democracy.sqrtElectorate);
const [result, setResult] = useState<Result>({ changeAye: BN_ZERO, changeNay: BN_ZERO });
useEffect((): void => {

View File

@ -9,8 +9,8 @@ export default function useCounter (): number {
const { hasAccounts } = useAccounts();
const { api, isApiReady } = useApi();
const mountedRef = useIsMountedRef();
const proposals = useCall<any[]>(isApiReady && hasAccounts && api.derive.democracy?.proposals, []);
const referenda = useCall<any[]>(isApiReady && hasAccounts && api.derive.democracy?.referendumsActive, []);
const proposals = useCall<unknown[]>(isApiReady && hasAccounts && api.derive.democracy?.proposals);
const referenda = useCall<unknown[]>(isApiReady && hasAccounts && api.derive.democracy?.referendumsActive);
const [counter, setCounter] = useState(0);
useEffect((): void => {

View File

@ -14,7 +14,7 @@ interface Props {
function BestHash ({ className = '', label }: Props): React.ReactElement<Props> {
const { api } = useApi();
const newHead = useCall<Header>(api.rpc.chain.subscribeNewHeads, []);
const newHead = useCall<Header>(api.rpc.chain.subscribeNewHeads);
return (
<div className={className}>

View File

@ -22,18 +22,20 @@ interface Props {
value: string;
}
const transformEvents = {
isSingle: true,
transform: (events: EventRecord[]): KeyedEvent[] =>
events.map((record, index) => ({
indexes: [index],
key: `${Date.now()}-${index}-${record.hash.toHex()}`,
record
}))
};
function BlockByHash ({ className = '', value }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const events = useCall<KeyedEvent[]>(api.query.system.events.at, [value], {
isSingle: true,
transform: (events: EventRecord[]): KeyedEvent[] =>
events.map((record, index) => ({
indexes: [index],
key: `${Date.now()}-${index}-${record.hash.toHex()}`,
record
}))
});
const events = useCall<KeyedEvent[]>(api.query.system.events.at, [value], transformEvents);
const getBlock = useCall<SignedBlock>(api.rpc.chain.getBlock, [value], { isSingle: true });
const getHeader = useCall<HeaderExtended>(api.derive.chain.getHeader, [value]);

View File

@ -15,7 +15,7 @@ import BlockByNumber from './ByNumber';
function Entry (): React.ReactElement | null {
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const { value } = useParams<{ value: string }>();
const [stateValue, setStateValue] = useState<string | undefined>(value);

View File

@ -20,8 +20,8 @@ interface Props {
function SummarySession ({ withEra = true, withSession = true }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const sessionInfo = useCall<DeriveSessionProgress>(api.query.staking && api.derive.session?.progress, []);
const forcing = useCall<Forcing>(api.query.staking?.forceEra, []);
const sessionInfo = useCall<DeriveSessionProgress>(api.query.staking && api.derive.session?.progress);
const forcing = useCall<Forcing>(api.query.staking?.forceEra);
const eraLabel = t<string>('era');
const sessionLabel = sessionInfo?.isEpoch

View File

@ -21,20 +21,22 @@ interface Props {
parachain: DeriveParachain;
}
const transformHead = {
transform: (headData: Option<HeadData>): string | null => {
if (headData.isSome) {
const hex = headData.unwrap().toHex();
return `${hex.slice(0, 10)}…${hex.slice(-8)}`;
}
return null;
}
};
function Parachain ({ className = '', parachain: { didUpdate, id, info, pendingSwapId, relayDispatchQueueSize = 0 } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const headHex = useCall<string | null>(api.query.parachains.heads, [id], {
transform: (headData: Option<HeadData>): string | null => {
if (headData.isSome) {
const hex = headData.unwrap().toHex();
return `${hex.slice(0, 10)}…${hex.slice(-8)}`;
}
return null;
}
});
const headHex = useCall<string | null>(api.query.parachains.heads, [id], transformHead);
const history = useHistory();
const _onClick = useCallback(

View File

@ -30,9 +30,9 @@ const DIV = new BN(1_000_000);
function PollApp ({ className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const totals = useCall<ITuple<[Balance, Balance, Balance, Balance]>>(api.query.poll.totals, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const totalIssuance = useCall<Balance>(api.query.balances.totalIssuance, []);
const totals = useCall<ITuple<[Balance, Balance, Balance, Balance]>>(api.query.poll.totals);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const totalIssuance = useCall<Balance>(api.query.balances.totalIssuance);
const [accountId, setAccountId] = useState<string | null>(null);
const [turnout, setTurnout] = useState<Turnout | null>(null);
const [opt10m, setOpt10m] = useState(false);

View File

@ -18,7 +18,7 @@ interface Props {
function Bids ({ className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bids = useCall<Bid[]>(api.query.society.bids, []);
const bids = useCall<Bid[]>(api.query.society.bids);
const headerRef = useRef([
[t('bids'), 'start'],

View File

@ -21,7 +21,7 @@ interface Props {
function Candidates ({ allMembers, className = '', isMember, ownMembers }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const candidates = useCall<DeriveSocietyCandidate[]>(api.derive.society.candidates, []);
const candidates = useCall<DeriveSocietyCandidate[]>(api.derive.society.candidates);
const headerRef = useRef([
[t('candidates'), 'start'],

View File

@ -21,18 +21,18 @@ interface Props {
ownMembers: string[];
}
function transformVotes (members: DeriveSocietyMember[]): VoteType[] {
return members
.filter(({ vote }): boolean => !!vote)
.map(({ accountId, vote }): VoteType => [accountId.toString(), vote as SocietyVote]);
}
const transformVotes = {
transform: (members: DeriveSocietyMember[]): VoteType[] => {
return members
.filter(({ vote }): boolean => !!vote)
.map(({ accountId, vote }): VoteType => [accountId.toString(), vote as SocietyVote]);
}
};
function Defender ({ className = '', info, isMember, ownMembers }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const votes = useCall<VoteType[]>(api.derive.society.members, [], {
transform: transformVotes
});
const votes = useCall<VoteType[]>(api.derive.society.members, undefined, transformVotes);
const headerRef = useRef([
[t('defender'), 'start'],

View File

@ -19,7 +19,7 @@ interface Props {
function Members ({ className = '', info }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const members = useCall<DeriveSocietyMember[]>(api.derive.society.members, []);
const members = useCall<DeriveSocietyMember[]>(api.derive.society.members);
const headerRef = useRef([
[t('members'), 'start', 3],

View File

@ -21,8 +21,8 @@ interface Props {
function Summary ({ className = '', info }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const members = useCall<any[]>(api.derive.society.members, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const members = useCall<unknown[]>(api.derive.society.members);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const pot = useMemo((): string | null => {
return info && info.pot.gtn(0)

View File

@ -26,7 +26,7 @@ interface Props {
function Overview ({ className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const info = useCall<DeriveSociety>(api.derive.society.info, []);
const info = useCall<DeriveSociety>(api.derive.society.info);
const { allMembers, isMember, ownMembers } = useMembers();
const [isBidOpen, toggleBidOpen] = useToggle();

View File

@ -8,7 +8,7 @@ import { useApi, useCall } from '@polkadot/react-hooks';
export default function useCounter (): number {
const { api } = useApi();
const bids = useCall<Bid[]>(api.query.society?.bids, []);
const bids = useCall<Bid[]>(api.query.society?.bids);
return bids?.length || 0;
}

View File

@ -22,7 +22,7 @@ export default function useMembers (): OwnMembers {
const { api } = useApi();
const { allAccounts } = useAccounts();
const [state, setState] = useState<OwnMembers>({ allMembers: [], isMember: false, ownMembers: [] });
const members = useCall<DeriveSocietyMember[]>(api.derive.society?.members, []);
const members = useCall<DeriveSocietyMember[]>(api.derive.society?.members);
useEffect((): void => {
allAccounts && members && setState(

View File

@ -23,21 +23,25 @@ interface ErrorState {
isFatal: boolean;
}
const transformBonded = {
transform: (value: Option<AccountId>): string | null =>
value.isSome
? value.unwrap().toString()
: null
};
const transformStash = {
transform: (value: Option<StakingLedger>): string | null =>
value.isSome
? value.unwrap().stash.toString()
: null
};
function ValidateController ({ accountId, controllerId, defaultController, onError }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const bondedId = useCall<string | null>(controllerId ? api.query.staking.bonded : null, [controllerId], {
transform: (value: Option<AccountId>): string | null =>
value.isSome
? value.unwrap().toString()
: null
});
const stashId = useCall<string | null>(controllerId ? api.query.staking.ledger : null, [controllerId], {
transform: (value: Option<StakingLedger>): string | null =>
value.isSome
? value.unwrap().stash.toString()
: null
});
const bondedId = useCall<string | null>(controllerId ? api.query.staking.bonded : null, [controllerId], transformBonded);
const stashId = useCall<string | null>(controllerId ? api.query.staking.ledger : null, [controllerId], transformStash);
const allBalances = useCall<DeriveBalancesAll>(controllerId ? api.derive.balances.all : null, [controllerId]);
const [{ error, isFatal }, setError] = useState<ErrorState>({ error: null, isFatal: false });

View File

@ -11,6 +11,7 @@ import { Slash } from '../types';
import BN from 'bn.js';
import React, { useCallback, useContext, useMemo } from 'react';
import styled from 'styled-components';
import { ApiPromise } from '@polkadot/api';
import { AddressInfo, AddressMini, AddressSmall, Badge, Button, Menu, Popup, StakingBonded, StakingRedeemable, StakingUnbonding, StatusContext, TxButton } from '@polkadot/react-components';
import { useApi, useCall, useToggle } from '@polkadot/react-hooks';
import { Option } from '@polkadot/types';
@ -49,18 +50,26 @@ function extractSlashes (stashId: string, allSlashes: [BN, UnappliedSlash[]][] =
.filter(({ slashes }) => slashes.length);
}
const transformSpan = {
transform: (optSpans: Option<SlashingSpans>): number =>
optSpans.isNone
? 0
: optSpans.unwrap().prior.length + 1
};
function useStashCalls (api: ApiPromise, stashId: string) {
const params = useMemo(() => [stashId], [stashId]);
const balancesAll = useCall<DeriveBalancesAll>(api.derive.balances.all, params);
const spanCount = useCall<number>(api.query.staking.slashingSpans, params, transformSpan);
const stakingAccount = useCall<DeriveStakingAccount>(api.derive.staking.account, params);
return { balancesAll, spanCount, stakingAccount };
}
function Account ({ allSlashes, className = '', info: { controllerId, destination, destinationId, hexSessionIdNext, hexSessionIdQueue, isLoading, isOwnController, isOwnStash, isStashNominating, isStashValidating, nominating, sessionIds, stakingLedger, stashId }, isDisabled, targets }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { queueExtrinsic } = useContext(StatusContext);
const balancesAll = useCall<DeriveBalancesAll>(api.derive.balances.all, [stashId]);
const stakingAccount = useCall<DeriveStakingAccount>(api.derive.staking.account, [stashId]);
const spanCount = useCall<number>(api.query.staking.slashingSpans, [stashId], {
transform: (optSpans: Option<SlashingSpans>): number =>
optSpans.isNone
? 0
: optSpans.unwrap().prior.length + 1
});
const [isBondExtraOpen, toggleBondExtra] = useToggle();
const [isInjectOpen, toggleInject] = useToggle();
const [isNominateOpen, toggleNominate] = useToggle();
@ -70,6 +79,7 @@ function Account ({ allSlashes, className = '', info: { controllerId, destinatio
const [isSettingsOpen, toggleSettings] = useToggle();
const [isUnbondOpen, toggleUnbond] = useToggle();
const [isValidateOpen, toggleValidate] = useToggle();
const { balancesAll, spanCount, stakingAccount } = useStashCalls(api, stashId);
const slashes = useMemo(
() => extractSlashes(stashId, allSlashes),

View File

@ -65,7 +65,7 @@ export default function useInactives (stashId: string, nominees?: string[]): Ina
const { api } = useApi();
const mountedRef = useIsMountedRef();
const [state, setState] = useState<Inactives>({});
const indexes = useCall<DeriveSessionIndexes>(api.derive.session.indexes, []);
const indexes = useCall<DeriveSessionIndexes>(api.derive.session.indexes);
useEffect((): () => void => {
let unsub: (() => void) | undefined;

View File

@ -11,7 +11,7 @@ import { BN_ONE } from '@polkadot/util';
export default function useUnbondDuration (): BN | undefined {
const { api } = useApi();
const sessionInfo = useCall<DeriveSessionInfo>(api.derive.session.info, []);
const sessionInfo = useCall<DeriveSessionInfo>(api.derive.session.info);
return useMemo(
() => (sessionInfo && sessionInfo.sessionLength.gt(BN_ONE))

View File

@ -7,6 +7,7 @@ import { DeriveAccountInfo, DeriveStakingQuery } from '@polkadot/api-derive/type
import BN from 'bn.js';
import React, { useCallback, useMemo } from 'react';
import { ApiPromise } from '@polkadot/api';
import { AddressSmall, Icon, LinkExternal } from '@polkadot/react-components';
import { checkVisibility } from '@polkadot/react-components/util';
import { useApi, useCall } from '@polkadot/react-hooks';
@ -71,13 +72,22 @@ function expandInfo ({ exposure, validatorPrefs }: DeriveStakingQuery): StakingS
};
}
const transformSlashes = {
transform: (opt: Option<SlashingSpans>) => opt.unwrapOr(null)
};
function useAddressCalls (api: ApiPromise, address: string, isMain?: boolean) {
const params = useMemo(() => [address], [address]);
const accountInfo = useCall<DeriveAccountInfo>(api.derive.accounts.info, params);
const slashingSpans = useCall<SlashingSpans | null>(!isMain && api.query.staking.slashingSpans, params, transformSlashes);
const stakingInfo = useCall<DeriveStakingQuery>(api.derive.staking.query, params);
return { accountInfo, slashingSpans, stakingInfo };
}
function Address ({ address, className = '', filterName, hasQueries, isElected, isFavorite, isMain, lastBlock, nominatedBy, onlineCount, onlineMessage, points, toggleFavorite, withIdentity }: Props): React.ReactElement<Props> | null {
const { api } = useApi();
const accountInfo = useCall<DeriveAccountInfo>(api.derive.accounts.info, [address]);
const stakingInfo = useCall<DeriveStakingQuery>(api.derive.staking.query, [address]);
const slashingSpans = useCall<SlashingSpans | null>(!isMain && api.query.staking.slashingSpans, [address], {
transform: (opt: Option<SlashingSpans>) => opt.unwrapOr(null)
});
const { accountInfo, slashingSpans, stakingInfo } = useAddressCalls(api, address, isMain);
const { commission, nominators, stakeOther, stakeOwn } = useMemo(
() => stakingInfo ? expandInfo(stakingInfo) : { nominators: [] },

View File

@ -95,8 +95,8 @@ function CurrentList ({ favorites, hasQueries, isIntentions, next, stakingOvervi
const { t } = useTranslation();
const { api } = useApi();
const { byAuthor, eraPoints } = useContext(isIntentions ? EmptyAuthorsContext : BlockAuthorsContext);
const recentlyOnline = useCall<DeriveHeartbeats>(!isIntentions && api.derive.imOnline?.receivedHeartbeats, []);
const nominators = useCall<[StorageKey, Option<Nominations>][]>(isIntentions && api.query.staking.nominators.entries as any, []);
const recentlyOnline = useCall<DeriveHeartbeats>(!isIntentions && api.derive.imOnline?.receivedHeartbeats);
const nominators = useCall<[StorageKey, Option<Nominations>][]>(isIntentions && api.query.staking.nominators.entries as any);
const [nameFilter, setNameFilter] = useState<string>('');
const [withIdentity, setWithIdentity] = useState(false);

View File

@ -157,8 +157,8 @@ function Payouts ({ className = '', isInElection, ownValidators }: Props): React
const [hasOwnValidators] = useState(ownValidators.length !== 0);
const [myStashesIndex, setMyStashesIndex] = useState((api.tx.staking.payoutStakers && hasOwnValidators) ? 0 : 1);
const [eraSelectionIndex, setEraSelectionIndex] = useState(0);
const eraLength = useCall<BN>(api.derive.session.eraLength, []);
const historyDepth = useCall<BN>(api.query.staking.historyDepth, []);
const eraLength = useCall<BN>(api.derive.session.eraLength);
const historyDepth = useCall<BN>(api.query.staking.historyDepth);
const stakerPayoutsAfter = useStakerPayouts();
const isDisabled = isInElection || !isFunction(api.tx.utility?.batch);

View File

@ -12,9 +12,9 @@ import { BN_ONE } from '@polkadot/util';
export default function useEraBlocks (era?: BN): BN | undefined {
const { api } = useApi();
const depth = useCall<BN>(api.query.staking.historyDepth, []);
const progress = useCall<DeriveSessionProgress>(api.derive.session.progress, []);
const forcing = useCall<Forcing>(api.query.staking.forceEra, []);
const depth = useCall<BN>(api.query.staking.historyDepth);
const progress = useCall<DeriveSessionProgress>(api.derive.session.progress);
const forcing = useCall<Forcing>(api.query.staking.forceEra);
return useMemo(
() => (depth && era && forcing && progress && progress.sessionLength.gt(BN_ONE))

View File

@ -12,7 +12,7 @@ import { isFunction } from '@polkadot/util';
export default function useStakerPayouts (): BN {
const { api } = useApi();
const migrateEraOpt = useCall<Option<EraIndex>>(api.query.staking?.migrateEra, []);
const migrateEraOpt = useCall<Option<EraIndex>>(api.query.staking?.migrateEra);
return useMemo(
() => (migrateEraOpt && migrateEraOpt.isSome && migrateEraOpt.unwrap()) || (

View File

@ -56,7 +56,7 @@ function ChartRewards ({ validatorId }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const ownSlashes = useCall<DeriveOwnSlashes[]>(api.derive.staking.ownSlashes, [validatorId, true]);
const erasRewards = useCall<DeriveEraRewards[]>(api.derive.staking.erasRewards, []);
const erasRewards = useCall<DeriveEraRewards[]>(api.derive.staking.erasRewards);
const stakerPoints = useCall<DeriveStakerPoints[]>(api.derive.staking.stakerPoints, [validatorId, true]);
const { currency, divisor } = useMemo((): { currency: string; divisor: BN } => ({

View File

@ -13,7 +13,7 @@ import { isFunction } from '@polkadot/util';
export default function useBlockCounts (accountId: string, sessionRewards: SessionRewards[]): u32[] {
const { api } = useApi();
const mountedRef = useIsMountedRef();
const indexes = useCall<DeriveSessionIndexes>(api.derive.session?.indexes, []);
const indexes = useCall<DeriveSessionIndexes>(api.derive.session?.indexes);
const current = useCall<u32>(api.query.imOnline?.authoredBlocks, [indexes?.currentIndex, accountId]);
const [counts, setCounts] = useState<u32[]>([]);
const [historic, setHistoric] = useState<u32[]>([]);

View File

@ -21,7 +21,7 @@ interface Props {
function Header ({ slash: { era, nominators, reporters, total, validators } }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const sessionInfo = useCall<DeriveSessionProgress>(api.derive.session?.progress, []);
const sessionInfo = useCall<DeriveSessionProgress>(api.derive.session?.progress);
const [blockProgress, blockEnd] = useMemo(
() => sessionInfo

View File

@ -24,7 +24,7 @@ interface Props {
function Summary ({ avgStaked, lastReward, lowStaked, numNominators, numValidators, totalStaked }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const totalIssuance = useCall<Balance>(api.query.balances?.totalIssuance, []);
const totalIssuance = useCall<Balance>(api.query.balances?.totalIssuance);
const progressStake = useMemo(
() => totalIssuance && totalStaked && totalStaked.gtn(0)

View File

@ -30,6 +30,10 @@ import useSortedTargets from './useSortedTargets';
const HIDDEN_ACC = ['actions', 'payouts', 'query'];
const HIDDEN_QUE = ['returns', 'query'];
const transformElection = {
transform: (status: ElectionStatus) => status.isOpen
};
function StakingApp ({ basePath, className = '' }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
@ -40,10 +44,8 @@ function StakingApp ({ basePath, className = '' }: Props): React.ReactElement<Pr
const ownStashes = useOwnStashInfos();
const slashes = useAvailableSlashes();
const targets = useSortedTargets(favorites);
const stakingOverview = useCall<DeriveStakingOverview>(api.derive.staking.overview, []);
const isInElection = useCall<boolean>(api.query.staking?.eraElectionStatus, [], {
transform: (status: ElectionStatus) => status.isOpen
});
const stakingOverview = useCall<DeriveStakingOverview>(api.derive.staking.overview);
const isInElection = useCall<boolean>(api.query.staking?.eraElectionStatus, undefined, transformElection);
const hasQueries = useMemo(
() => hasAccounts && !!(api.query.imOnline?.authoredBlocks) && !!(api.query.staking.activeEra),

View File

@ -149,17 +149,21 @@ function extractInfo (allAccounts: string[], amount: BN = baseBalance(), elected
return { avgStaked: totalStaked.divn(electedDerive.info.length), lowStaked, nominators, totalStaked, validatorIds, validators };
}
const transformEra = {
transform: ({ activeEra }: DeriveSessionIndexes) => activeEra.gtn(0) ? activeEra.subn(1) : BN_ZERO
};
const transformReward = {
transform: (optBalance: Option<Balance>) => optBalance.unwrapOrDefault()
};
export default function useSortedTargets (favorites: string[]): SortedTargets {
const { api } = useApi();
const { allAccounts } = useAccounts();
const electedInfo = useCall<DeriveStakingElected>(api.derive.staking.electedInfo, []);
const waitingInfo = useCall<DeriveStakingWaiting>(api.derive.staking.waitingInfo, []);
const lastEra = useCall<BN>(api.derive.session.indexes, [], {
transform: ({ activeEra }: DeriveSessionIndexes) => activeEra.gtn(0) ? activeEra.subn(1) : BN_ZERO
});
const lastReward = useCall<BN>(lastEra && api.query.staking.erasValidatorReward, [lastEra], {
transform: (optBalance: Option<Balance>) => optBalance.unwrapOrDefault()
});
const electedInfo = useCall<DeriveStakingElected>(api.derive.staking.electedInfo);
const waitingInfo = useCall<DeriveStakingWaiting>(api.derive.staking.waitingInfo);
const lastEra = useCall<BN>(api.derive.session.indexes, undefined, transformEra);
const lastReward = useCall<BN>(lastEra && api.query.staking.erasValidatorReward, [lastEra], transformReward);
const [calcWith, setCalcWith] = useState<BN | undefined>(baseBalance());
const calcWithDebounce = useDebounce(calcWith);
const [state, setState] = useState<SortedTargets>({ setCalcWith });

View File

@ -15,7 +15,7 @@ import { useTranslation } from '../translate';
function Summary ({ className = '', members, proposals }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const proposalCount = useCall<u32>(api.query.technicalCommittee.proposalCount, []);
const proposalCount = useCall<u32>(api.query.technicalCommittee.proposalCount);
return (
<SummaryBox className={className}>

View File

@ -23,14 +23,18 @@ interface Props {
prime?: AccountId | null;
}
const transformProposal = {
transform: (optProp: Option<ProposalType>) => optProp.unwrapOr(null)
};
const transformVotes = {
transform: (optVotes: Option<Votes>) => optVotes.unwrapOr(null)
};
function Proposal ({ className = '', imageHash, isMember, members, prime }: Props): React.ReactElement<Props> | null {
const { api } = useApi();
const proposal = useCall<ProposalType | null>(api.query.technicalCommittee.proposalOf, [imageHash], {
transform: (optProp: Option<ProposalType>) => optProp.unwrapOr(null)
});
const votes = useCall<Votes | null>(api.query.technicalCommittee.voting, [imageHash], {
transform: (optVotes: Option<Votes>) => optVotes.unwrapOr(null)
});
const proposal = useCall<ProposalType | null>(api.query.technicalCommittee.proposalOf, [imageHash], transformProposal);
const votes = useCall<Votes | null>(api.query.technicalCommittee.voting, [imageHash], transformVotes);
const { hasFailed, isCloseable, isVoteable, remainingBlocks } = useVotingStatus(votes, members.length, 'technicalCommittee');
if (!proposal || !votes) {

View File

@ -21,14 +21,17 @@ interface Props {
className?: string;
}
const transformPrime = {
transform: (result: Option<AccountId>): AccountId | null => result.unwrapOr(null)
};
function TechCommApp ({ basePath, className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { isMember, members } = useMembers('technicalCommittee');
const prime = useCall<AccountId | null>(api.query.technicalCommittee.prime, [], {
transform: (result: Option<AccountId>): AccountId | null => result.unwrapOr(null)
}) || null;
const prime = useCall<AccountId | null>(api.query.technicalCommittee.prime, undefined, transformPrime) || null;
const proposals = useCall<Hash[]>(api.query.technicalCommittee.proposals);
const items = useMemo(() => [
{
isRoot: true,

View File

@ -6,15 +6,13 @@ import { Hash } from '@polkadot/types/interfaces';
import { useApi, useCall } from '@polkadot/react-hooks';
function transform (proposals: Hash[]): number {
return proposals.length;
}
const transformCounter = {
transform: (proposals: Hash[]) => proposals.length
};
export default function useCounter (): number {
const { api, isApiReady } = useApi();
const counter = useCall<number>(isApiReady && api.query.technicalCommittee?.proposals, [], {
transform
}) || 0;
const counter = useCall<number>(isApiReady && api.query.technicalCommittee?.proposals, undefined, transformCounter) || 0;
return counter;
}

View File

@ -24,8 +24,8 @@ interface Props {
function Summary ({ approvalCount, proposalCount }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useCall<Balance>(api.derive.chain.bestNumber, []);
const totalProposals = useCall<BN>(api.query.treasury.proposalCount, []);
const bestNumber = useCall<Balance>(api.derive.chain.bestNumber);
const totalProposals = useCall<BN>(api.query.treasury.proposalCount);
const treasuryBalance = useCall<DeriveBalancesAccount>(api.derive.balances.account, [TREASURY_ACCOUNT]);
const spendPeriod = api.consts.treasury.spendPeriod;

View File

@ -13,14 +13,16 @@ interface Props {
hash: Hash;
}
const transformTip = {
transform: (optBytes: Option<Bytes>) =>
optBytes.isSome
? hexToString(optBytes.unwrap().toHex())
: null
};
function TipReason ({ hash }: Props): React.ReactElement<Props> {
const { api } = useApi();
const reasonText = useCall<string | null>(api.query.treasury.reasons, [hash], {
transform: (optBytes: Option<Bytes>) =>
optBytes.isSome
? hexToString(optBytes.unwrap().toHex())
: null
});
const reasonText = useCall<string | null>(api.query.treasury.reasons, [hash], transformTip);
return (
<td className='start all'>{reasonText || hash.toHex()}</td>

View File

@ -24,7 +24,7 @@ type Tip = [string, OpenTip | OpenTipTo225];
function Tips ({ className = '', hashes, isMember, members }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const [tips, setTips] = useState<Tip[] | undefined>();
const optTips = useCall<Option<OpenTip>[]>(hashes && api.query.treasury.tips.multi, [hashes]);

View File

@ -32,7 +32,7 @@ function Voting ({ councilProposals, isDisabled, members }: Props): React.ReactE
const { t } = useTranslation();
const { hasAccounts } = useAccounts();
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const [councilOpts, setCouncilOpts] = useState<Option[]>([]);
const [councilOptId, setCouncilOptId] = useState<number>(0);
const [accountId, setAccountId] = useState<string | null>(null);

View File

@ -17,7 +17,7 @@ import Tips from './Tips';
function Overview ({ className }: Props): React.ReactElement<Props> {
const { api } = useApi();
const info = useCall<DeriveTreasuryProposals>(api.derive.treasury.proposals, []);
const info = useCall<DeriveTreasuryProposals>(api.derive.treasury.proposals);
const { isMember, members } = useMembers();
const mountedRef = useIsMountedRef();

View File

@ -10,7 +10,7 @@ import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';
export default function useCounter (): number {
const { hasAccounts } = useAccounts();
const { api, isApiReady } = useApi();
const proposals = useCall<DeriveTreasuryProposals>(isApiReady && hasAccounts && api.derive.treasury?.proposals, []);
const proposals = useCall<DeriveTreasuryProposals>(isApiReady && hasAccounts && api.derive.treasury?.proposals);
const [counter, setCounter] = useState(0);
useEffect((): void => {

View File

@ -85,7 +85,7 @@ function groupLocks (t: TFunction, bestNumber: BN, locks: DeriveDemocracyLock[]
function DemocracyLocks ({ className = '', value }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useCall<BN>(api.derive.chain.bestNumber, []);
const bestNumber = useCall<BN>(api.derive.chain.bestNumber);
const [trigger] = useState(`${Date.now()}-democracy-locks-${++id}`);
const [{ maxBalance, sorted }, setState] = useState<State>({ maxBalance: BN_ZERO, sorted: [] });

View File

@ -18,16 +18,18 @@ interface Props {
stakingInfo?: DeriveStakingAccount;
}
const transformSpan = {
transform: (optSpans: Option<SlashingSpans>): number =>
optSpans.isNone
? 0
: optSpans.unwrap().prior.length + 1
};
function StakingRedeemable ({ className = '', stakingInfo }: Props): React.ReactElement<Props> | null {
const { api } = useApi();
const { allAccounts } = useAccounts();
const { t } = useTranslation();
const spanCount = useCall<number>(api.query.staking.slashingSpans, [stakingInfo?.stashId], {
transform: (optSpans: Option<SlashingSpans>): number =>
optSpans.isNone
? 0
: optSpans.unwrap().prior.length + 1
});
const spanCount = useCall<number>(api.query.staking.slashingSpans, [stakingInfo?.stashId], transformSpan);
if (!stakingInfo?.redeemable?.gtn(0)) {
return null;

View File

@ -29,7 +29,7 @@ function remainingBlocks (remainingEras: BN, { eraLength, eraProgress }: DeriveS
function StakingUnbonding ({ className = '', stakingInfo }: Props): React.ReactElement<Props> | null {
const { api } = useApi();
const progress = useCall<DeriveSessionProgress>(api.derive.session.progress, []);
const progress = useCall<DeriveSessionProgress>(api.derive.session.progress);
const { t } = useTranslation();
if (!stakingInfo?.unlocking || !progress) {

View File

@ -14,8 +14,8 @@ type Unsub = () => void;
export default function useAvailableSlashes (): [BN, UnappliedSlash[]][] {
const { api } = useApi();
const indexes = useCall<DeriveSessionIndexes>(api.derive.session?.indexes, []);
const earliestSlash = useCall<Option<EraIndex>>(api.query.staking?.earliestUnappliedSlash, []);
const indexes = useCall<DeriveSessionIndexes>(api.derive.session?.indexes);
const earliestSlash = useCall<Option<EraIndex>>(api.query.staking?.earliestUnappliedSlash);
const mountedRef = useIsMountedRef();
const [slashes, setSlashes] = useState<[BN, UnappliedSlash[]][]>([]);

View File

@ -38,7 +38,7 @@ function transformIdentity <T> (value: unknown): T {
}
// extract the serialized and mapped params, all ready for use in our call
function extractParams (fn: unknown, params: unknown[], paramMap: (params: unknown[]) => CallParams): [string, CallParams | null] {
function extractParams <T> (fn: unknown, params: unknown[], { paramMap = transformIdentity }: CallOptions<T> = {}): [string, CallParams | null] {
return [
JSON.stringify({ f: (fn as { name: string })?.name, p: params }),
params.length === 0 || !params.some((param) => isNull(param) || isUndefined(param))
@ -58,7 +58,7 @@ function unsubscribe (tracker: TrackerRef): void {
}
// subscribe, trying to play nice with the browser threads
function subscribe <T> (mountedRef: MountedRef, tracker: TrackerRef, fn: TrackFn | undefined, params: CallParams, setValue: (value: T) => void, { isSingle, transform = transformIdentity, withParams }: CallOptions<T>): void {
function subscribe <T> (mountedRef: MountedRef, tracker: TrackerRef, fn: TrackFn | undefined, params: CallParams, setValue: (value: T) => void, { isSingle, transform = transformIdentity, withParams }: CallOptions<T> = {}): void {
const validParams = params.filter((p): boolean => !isUndefined(p));
unsubscribe(tracker);
@ -94,10 +94,10 @@ function subscribe <T> (mountedRef: MountedRef, tracker: TrackerRef, fn: TrackFn
// - returns a promise with an unsubscribe function
// - has a callback to set the value
// FIXME The typings here need some serious TLC
export default function useCall <T> (fn: TrackFn | undefined | null | false, params: CallParams = [], options: CallOptions<T> = {}): T | undefined {
export default function useCall <T> (fn: TrackFn | undefined | null | false, params?: CallParams, options?: CallOptions<T>): T | undefined {
const mountedRef = useIsMountedRef();
const tracker = useRef<Tracker>({ count: 0, isActive: false, serialized: null, subscriber: null });
const [value, setValue] = useState<T | undefined>(options.defaultValue);
const [value, setValue] = useState<T | undefined>((options || {}).defaultValue);
// initial effect, we need an un-subscription
useEffect((): () => void => {
@ -108,7 +108,7 @@ export default function useCall <T> (fn: TrackFn | undefined | null | false, par
useEffect((): void => {
// check if we have a function & that we are mounted
if (mountedRef.current && fn) {
const [serialized, mappedParams] = extractParams(fn, params, options.paramMap || transformIdentity);
const [serialized, mappedParams] = extractParams(fn, params || [], options);
if (mappedParams && serialized !== tracker.current.serialized) {
tracker.current.serialized = serialized;

View File

@ -12,13 +12,15 @@ interface Result {
members: string[];
}
const transformMembers = {
transform: (accounts: AccountId[]) =>
accounts.map((accountId) => accountId.toString())
};
export default function useMembers (collective: 'council' | 'technicalCommittee' = 'council'): Result {
const { api } = useApi();
const { allAccounts, hasAccounts } = useAccounts();
const retrieved = useCall<string[]>(hasAccounts && api.query[collective]?.members, [], {
transform: (accounts: AccountId[]) =>
accounts.map((accountId) => accountId.toString())
});
const retrieved = useCall<string[]>(hasAccounts && api.query[collective]?.members, undefined, transformMembers);
return useMemo(
() => ({

View File

@ -92,7 +92,7 @@ export default function useOwnEraRewards (maxEras?: number, ownValidators?: Stak
const { api } = useApi();
const mountedRef = useIsMountedRef();
const stashIds = useOwnStashIds();
const allEras = useCall<EraIndex[]>(api.derive.staking?.erasHistoric, []);
const allEras = useCall<EraIndex[]>(api.derive.staking?.erasHistoric);
const [{ filteredEras, validatorEras }, setFiltered] = useState<Filtered>({ filteredEras: [], validatorEras: [] });
const [state, setState] = useState<OwnRewards>({ isLoadingRewards: true, rewardCount: 0 });
const stakerRewards = useCall<[[string[]], DeriveStakerReward[][]]>(!ownValidators?.length && !!filteredEras.length && stashIds && api.derive.staking?.stakerRewardsMultiEras, [stashIds, filteredEras], { withParams: true });

View File

@ -30,7 +30,7 @@ interface State {
export default function useRegistrars (skipQuery?: boolean): State {
const { api } = useApi();
const { allAccounts, hasAccounts } = useAccounts();
const query = useCall<Option<RegistrarInfo>[]>(!skipQuery && hasAccounts && api.query.identity?.registrars, []);
const query = useCall<Option<RegistrarInfo>[]>(!skipQuery && hasAccounts && api.query.identity?.registrars);
const [state, setState] = useState<State>({ isRegistrar: false, registrars: [] });
// determine if we have a registrar or not - registrars are allowed to approve

View File

@ -7,11 +7,13 @@ import { AccountId } from '@polkadot/types/interfaces';
import useApi from './useApi';
import useCall from './useCall';
const transformStashes = {
transform: (stashes: AccountId[]) => stashes.map((accountId) => accountId.toString())
};
export default function useStashIds (): string[] | undefined {
const { api } = useApi();
const allStashes = useCall<string[]>(api.derive.staking.stashes, [], {
transform: (stashes: AccountId[]) => stashes.map((accountId) => accountId.toString())
});
const allStashes = useCall<string[]>(api.derive.staking.stashes, undefined, transformStashes);
return allStashes;
}

View File

@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Codec } from '@polkadot/types/types';
import { AccountId } from '@polkadot/types/interfaces';
import { UseSudo } from './types';
import { useEffect, useState } from 'react';
@ -11,12 +11,14 @@ import useAccounts from './useAccounts';
import useApi from './useApi';
import useCall from './useCall';
const transformSudo = {
transform: (key: AccountId) => key.toString()
};
export default function useSudo (): UseSudo {
const { api } = useApi();
const { allAccounts, hasAccounts } = useAccounts();
const sudoKey = useCall<string>(hasAccounts && api.query.sudo?.key, [], {
transform: (k: Codec) => k.toString()
});
const sudoKey = useCall<string>(hasAccounts && api.query.sudo?.key, undefined, transformSudo);
const [isMine, setIsMine] = useState(false);
useEffect((): void => {

View File

@ -49,7 +49,7 @@ function getStatus (api: ApiPromise, bestNumber: BlockNumber, votes: Votes, numM
export default function useVotingStatus (votes: Votes | null | undefined, numMembers: number, section: 'council' | 'technicalCommittee'): State {
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
const [state, setState] = useState<State>({ hasFailed: false, hasPassed: false, isCloseable: false, isVoteable: false, remainingBlocks: null });
useEffect((): void => {

View File

@ -16,7 +16,7 @@ interface Props {
function BestFinalized ({ children, className = '', label }: Props): React.ReactElement<Props> {
const { api } = useApi();
const bestNumberFinalized = useCall<BlockNumber>(api.derive.chain.bestNumberFinalized, []);
const bestNumberFinalized = useCall<BlockNumber>(api.derive.chain.bestNumberFinalized);
return (
<div className={className}>

View File

@ -17,7 +17,7 @@ interface Props {
function BestNumber ({ children, className = '', label, withPound }: Props): React.ReactElement<Props> {
const { api, isApiReady } = useApi();
const bestNumber = useCall<BlockNumber>(isApiReady && api.derive.chain.bestNumber, []);
const bestNumber = useCall<BlockNumber>(isApiReady && api.derive.chain.bestNumber);
return (
<div className={className}>

View File

@ -31,7 +31,7 @@ const ValidatorsContext: React.Context<string[]> = React.createContext<string[]>
function BlockAuthorsBase ({ children }: Props): React.ReactElement<Props> {
const { api, isApiReady } = useApi();
const queryPoints = useCall<EraRewardPoints>(isApiReady && api.derive.staking?.currentPoints, []);
const queryPoints = useCall<EraRewardPoints>(isApiReady && api.derive.staking?.currentPoints);
const [state, setState] = useState<Authors>({ byAuthor, eraPoints, lastBlockAuthors: [], lastHeaders: [] });
const [validators, setValidators] = useState<string[]>([]);

View File

@ -17,14 +17,18 @@ interface Props {
label?: React.ReactNode;
}
const transformController = {
transform: (value: Option<AccountId>) => value.unwrapOr(null)
};
const transformLedger = {
transform: (value: Option<StakingLedger>) => value.unwrapOr(null)
};
function BondedDisplay ({ children, className = '', label, params }: Props): React.ReactElement<Props> {
const { api } = useApi();
const controllerId = useCall<AccountId | null>(api.query.staking?.bonded, [params], {
transform: (value: Option<AccountId>) => value.unwrapOr(null)
});
const stakingLedger = useCall<StakingLedger | null>(controllerId && api.query.staking?.ledger, [controllerId], {
transform: (value: Option<StakingLedger>) => value.unwrapOr(null)
});
const controllerId = useCall<AccountId | null>(api.query.staking?.bonded, [params], transformController);
const stakingLedger = useCall<StakingLedger | null>(controllerId && api.query.staking?.ledger, [controllerId], transformLedger);
return (
<FormatBalance

View File

@ -18,7 +18,7 @@ interface Props {
function TimeNow ({ children, className = '', label }: Props): React.ReactElement<Props> {
const { api, isSubstrateV2 } = useApi();
const timestamp = useCall<Moment>(api.query.timestamp.now, []);
const timestamp = useCall<Moment>(api.query.timestamp.now);
const [now, setNow] = useState<BN | undefined>();
useEffect((): void => {

View File

@ -14,7 +14,7 @@ interface Props {
function TotalIssuance ({ children, className = '', label }: Props): React.ReactElement<Props> {
const { api } = useApi();
const totalIssuance = useCall<string>(api.query.balances?.totalIssuance, []);
const totalIssuance = useCall<string>(api.query.balances?.totalIssuance);
return (
<div className={className}>