mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-07-22 19:35:45 +00:00
feat: initial Pezkuwi Apps rebrand from polkadot-apps
Rebranded terminology: - Polkadot → Pezkuwi - Kusama → Dicle - Westend → Zagros - Rococo → PezkuwiChain - Substrate → Bizinikiwi - parachain → teyrchain Custom logos with Kurdistan brand colors (#e6007a → #86e62a): - bizinikiwi-hexagon.svg - sora-bizinikiwi.svg - hezscanner.svg - heztreasury.svg - pezkuwiscan.svg - pezkuwistats.svg - pezkuwiassembly.svg - pezkuwiholic.svg
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ParaId } from '@pezkuwi/types/interfaces';
|
||||
import type { BN } from '@pezkuwi/util';
|
||||
import type { OwnedId } from '../types.js';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from '@pezkuwi/react-components';
|
||||
import { useApi, useCall, useToggle } from '@pezkuwi/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate.js';
|
||||
import { LOWEST_PUBLIC_ID } from './constants.js';
|
||||
import DeregisterId from './DeregisterId.js';
|
||||
import RegisterId from './RegisterId.js';
|
||||
import RegisterThread from './RegisterThread.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
ownedIds: OwnedId[];
|
||||
}
|
||||
|
||||
const OPT_NEXT = {
|
||||
transform: (nextId: ParaId) =>
|
||||
nextId.isZero()
|
||||
? LOWEST_PUBLIC_ID
|
||||
: nextId
|
||||
};
|
||||
|
||||
function Actions ({ className, ownedIds }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [isRegisterOpen, toggleRegisterOpen] = useToggle();
|
||||
const [isReserveOpen, toggleReserveOpen] = useToggle();
|
||||
const [isDeregisterOpen, toggleDeregisterOpen] = useToggle();
|
||||
const nextParaId = useCall<ParaId | BN>(api.query.registrar.nextFreeParaId, [], OPT_NEXT);
|
||||
|
||||
return (
|
||||
<Button.Group className={className}>
|
||||
<Button
|
||||
icon='minus'
|
||||
isDisabled={api.tx.registrar.deregister ? !ownedIds.length : false}
|
||||
label={t('Deregister')}
|
||||
onClick={toggleDeregisterOpen}
|
||||
/>
|
||||
{isDeregisterOpen && (
|
||||
<DeregisterId
|
||||
nextParaId={nextParaId}
|
||||
onClose={toggleDeregisterOpen}
|
||||
ownedIds={ownedIds}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={!api.tx.registrar.reserve}
|
||||
label={t('ParaId')}
|
||||
onClick={toggleReserveOpen}
|
||||
/>
|
||||
{isReserveOpen && (
|
||||
<RegisterId
|
||||
nextParaId={nextParaId}
|
||||
onClose={toggleReserveOpen}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={api.tx.registrar.reserve ? !ownedIds.length : false}
|
||||
label={t('ParaThread')}
|
||||
onClick={toggleRegisterOpen}
|
||||
/>
|
||||
{isRegisterOpen && (
|
||||
<RegisterThread
|
||||
nextParaId={nextParaId}
|
||||
onClose={toggleRegisterOpen}
|
||||
ownedIds={ownedIds}
|
||||
/>
|
||||
)}
|
||||
</Button.Group>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Actions);
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { OwnedId, OwnerInfo } from '../types.js';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { InputAddress, InputNumber, MarkWarning, Modal, styled, TxButton } from '@pezkuwi/react-components';
|
||||
import { useApi } from '@pezkuwi/react-hooks';
|
||||
import { CallExpander } from '@pezkuwi/react-params';
|
||||
|
||||
import InputOwner from '../InputOwner.js';
|
||||
import { useTranslation } from '../translate.js';
|
||||
import { LOWEST_INVALID_ID } from './constants.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
onClose: () => void;
|
||||
nextParaId?: BN;
|
||||
ownedIds: OwnedId[];
|
||||
}
|
||||
|
||||
function DeregisterId ({ className, nextParaId, onClose, ownedIds }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [paraId, setParaId] = useState<BN | undefined>();
|
||||
|
||||
const _setOwner = useCallback(
|
||||
({ accountId, paraId }: OwnerInfo) => {
|
||||
setAccountId(accountId);
|
||||
setParaId(new BN(paraId));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const isIdError = !paraId || !paraId.gt(LOWEST_INVALID_ID);
|
||||
|
||||
const extrinsic = useMemo(() => api.tx.registrar.deregister(paraId), [api.tx.registrar, paraId]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={className}
|
||||
header={t('Deregister ParaId')}
|
||||
onClose={onClose}
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
{api.tx.registrar.reserve
|
||||
? (
|
||||
<InputOwner
|
||||
noCodeCheck
|
||||
onChange={_setOwner}
|
||||
ownedIds={ownedIds}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<Modal.Columns hint={t('This account will be associated with the teyrchain and pay the deposit.')}>
|
||||
<InputAddress
|
||||
label={t('register from')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
value={accountId}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns hint={t('The id of this teyrchain as known on the network')}>
|
||||
<InputNumber
|
||||
autoFocus
|
||||
defaultValue={nextParaId}
|
||||
isError={isIdError}
|
||||
isZeroable={false}
|
||||
label={t('teyrchain id')}
|
||||
onChange={setParaId}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<Modal.Columns>
|
||||
<CallExpander
|
||||
isExpanded
|
||||
isHeader
|
||||
value={extrinsic}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<MarkWarning withIcon={false}>
|
||||
<strong>{t('Deregistering a paraID will:')}</strong>
|
||||
<WarningList>
|
||||
<WarningItem>{t('Remove it from the active teyrchain/parathread set.')}</WarningItem>
|
||||
<WarningItem>{t('Exclude it from future auctions and onboarding.')}</WarningItem>
|
||||
<WarningItem>{t('Potentially release any reserved deposits linked to it.')}</WarningItem>
|
||||
<WarningItem>{t('Require re-registration if you wish to use it again.')}</WarningItem>
|
||||
</WarningList>
|
||||
<p><strong>{t('This action is permanent.')}</strong> {t('Please ensure this is your intended action before continuing.')}</p>
|
||||
</MarkWarning>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
extrinsic={extrinsic}
|
||||
icon='minus'
|
||||
isDisabled={isIdError}
|
||||
label={t('Deregister')}
|
||||
onStart={onClose}
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const WarningList = styled.ul`
|
||||
padding-left: 20px;
|
||||
margin: 8px 0;
|
||||
`;
|
||||
|
||||
const WarningItem = styled.li`
|
||||
margin-bottom: 2px;
|
||||
`;
|
||||
|
||||
export default React.memo(DeregisterId);
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ParaId } from '@pezkuwi/types/interfaces';
|
||||
import type { LeaseInfo, LeasePeriod, QueuedAction } from '../types.js';
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { AddressSmall, ParaLink, Table, TxButton } from '@pezkuwi/react-components';
|
||||
import { useAccounts, useApi } from '@pezkuwi/react-hooks';
|
||||
|
||||
import Lifecycle from '../Overview/Lifecycle.js';
|
||||
// import TeyrchainInfo from '../Overview/TeyrchainInfo.js';
|
||||
import Periods from '../Overview/Periods.js';
|
||||
import { useTranslation } from '../translate.js';
|
||||
import useThreadInfo from './useThreadInfo.js';
|
||||
|
||||
interface Props {
|
||||
id: ParaId;
|
||||
leasePeriod: LeasePeriod;
|
||||
leases: LeaseInfo[];
|
||||
nextAction?: QueuedAction;
|
||||
}
|
||||
|
||||
function Parathread ({ id, leasePeriod, leases, nextAction }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { isAccount } = useAccounts();
|
||||
const { headHex, lifecycle, manager } = useThreadInfo(id);
|
||||
|
||||
const periods = useMemo(
|
||||
() => leasePeriod?.currentPeriod && leases?.map(({ period }) => period),
|
||||
[leasePeriod?.currentPeriod, leases]
|
||||
);
|
||||
|
||||
const isManager = isAccount(manager?.toString());
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<Table.Column.Id value={id} />
|
||||
<td className='badge'><ParaLink id={id} /></td>
|
||||
<td className='address media--2000'>{manager && <AddressSmall value={manager} />}</td>
|
||||
<td className='start together hash media--1500'>
|
||||
<div className='shortHash'>{headHex}</div>
|
||||
</td>
|
||||
<td className='start'>
|
||||
<Lifecycle
|
||||
lifecycle={lifecycle}
|
||||
nextAction={nextAction}
|
||||
/>
|
||||
</td>
|
||||
<td className='all' />
|
||||
<td className='number no-pad-left'>
|
||||
{/* <!-- TeyrchainInfo id={id} /--> */}
|
||||
</td>
|
||||
<td className='number together'>
|
||||
{leasePeriod && leases && periods && (
|
||||
leases.length
|
||||
? (
|
||||
<Periods
|
||||
fromFirst
|
||||
leasePeriod={leasePeriod}
|
||||
periods={periods}
|
||||
/>
|
||||
)
|
||||
: t('None')
|
||||
)}
|
||||
</td>
|
||||
<td className='button media--900'>
|
||||
<TxButton
|
||||
accountId={manager}
|
||||
icon='times'
|
||||
isDisabled={!isManager}
|
||||
label={t('Deregister')}
|
||||
params={[id]}
|
||||
tx={api.tx.registrar.deregister}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Parathread);
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { u128 } from '@pezkuwi/types';
|
||||
import type { BN } from '@pezkuwi/util';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { InputAddress, InputBalance, InputNumber, Modal, TxButton } from '@pezkuwi/react-components';
|
||||
import { useApi } from '@pezkuwi/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
nextParaId?: BN;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
function RegisterId ({ className, nextParaId, onClose }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={className}
|
||||
header={t('Reserve ParaId')}
|
||||
onClose={onClose}
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<Modal.Columns hint={t('This account will be used to the Id reservation and for the future parathread.')}>
|
||||
<InputAddress
|
||||
label={t('reserve from')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
value={accountId}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns hint={t('The Id of this teyrchain as known on the network (selected from nextFreeId)')}>
|
||||
<InputNumber
|
||||
defaultValue={nextParaId}
|
||||
isDisabled
|
||||
label={t('teyrchain id')}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns hint={t('The reservation fee for this Id')}>
|
||||
<InputBalance
|
||||
defaultValue={api.consts.registrar.paraDeposit as u128}
|
||||
isDisabled
|
||||
label={t('reserved deposit')}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
icon='plus'
|
||||
isDisabled={!nextParaId}
|
||||
onStart={onClose}
|
||||
params={[]}
|
||||
tx={api.tx.registrar.reserve}
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(RegisterId);
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BalanceOf } from '@pezkuwi/types/interfaces';
|
||||
import type { PezkuwiRuntimeTeyrchainsConfigurationHostConfiguration } from '@pezkuwi/types/lookup';
|
||||
import type { OwnedId, OwnerInfo } from '../types.js';
|
||||
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { InputAddress, InputBalance, InputFile, InputNumber, Modal, TxButton } from '@pezkuwi/react-components';
|
||||
import { useApi, useCall } from '@pezkuwi/react-hooks';
|
||||
import { BN, compactAddLength } from '@pezkuwi/util';
|
||||
|
||||
import InputOwner from '../InputOwner.js';
|
||||
import { useTranslation } from '../translate.js';
|
||||
import { LOWEST_INVALID_ID } from './constants.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
nextParaId?: BN;
|
||||
onClose: () => void;
|
||||
ownedIds: OwnedId[];
|
||||
}
|
||||
|
||||
function RegisterThread ({ className, nextParaId, onClose, ownedIds }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [paraId, setParaId] = useState<BN | undefined>();
|
||||
const [wasm, setWasm] = useState<Uint8Array | null>(null);
|
||||
const [genesisState, setGenesisState] = useState<Uint8Array | null>(null);
|
||||
const paraConfig = useCall<PezkuwiRuntimeTeyrchainsConfigurationHostConfiguration>(api.query.configuration?.activeConfig);
|
||||
|
||||
const _setGenesisState = useCallback(
|
||||
(data: Uint8Array) => setGenesisState(compactAddLength(data)),
|
||||
[]
|
||||
);
|
||||
|
||||
const _setWasm = useCallback(
|
||||
(data: Uint8Array) => setWasm(compactAddLength(data)),
|
||||
[]
|
||||
);
|
||||
|
||||
const _setOwner = useCallback(
|
||||
({ accountId, paraId }: OwnerInfo) => {
|
||||
setAccountId(accountId);
|
||||
setParaId(new BN(paraId));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const reservedDeposit = useMemo(
|
||||
() => (api.consts.registrar.paraDeposit as BalanceOf)
|
||||
.add((api.consts.registrar.dataDepositPerByte as BalanceOf).muln(
|
||||
paraConfig?.maxCodeSize
|
||||
? paraConfig.maxCodeSize.toNumber()
|
||||
: wasm
|
||||
? wasm.length
|
||||
: 0
|
||||
))
|
||||
.iadd((api.consts.registrar.dataDepositPerByte as BalanceOf).muln(genesisState ? genesisState.length : 0)),
|
||||
[api, wasm, genesisState, paraConfig]
|
||||
);
|
||||
|
||||
const isIdError = !paraId || !paraId.gt(LOWEST_INVALID_ID);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={className}
|
||||
header={t('Register parathread')}
|
||||
onClose={onClose}
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
{api.tx.registrar.reserve
|
||||
? (
|
||||
<InputOwner
|
||||
noCodeCheck
|
||||
onChange={_setOwner}
|
||||
ownedIds={ownedIds}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<Modal.Columns hint={t('This account will be associated with the teyrchain and pay the deposit.')}>
|
||||
<InputAddress
|
||||
label={t('register from')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
value={accountId}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns hint={t('The id of this teyrchain as known on the network')}>
|
||||
<InputNumber
|
||||
autoFocus
|
||||
defaultValue={nextParaId}
|
||||
isError={isIdError}
|
||||
isZeroable={false}
|
||||
label={t('teyrchain id')}
|
||||
onChange={setParaId}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<Modal.Columns hint={t('The WASM validation function for this teyrchain.')}>
|
||||
<InputFile
|
||||
isError={!wasm}
|
||||
label={t('code')}
|
||||
onChange={_setWasm}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns hint={t('The genesis state for this teyrchain.')}>
|
||||
<InputFile
|
||||
isError={!genesisState}
|
||||
label={t('initial state')}
|
||||
onChange={_setGenesisState}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns hint={t('The reservation fee for this teyrchain, including base fee and per-byte fees')}>
|
||||
<InputBalance
|
||||
defaultValue={reservedDeposit}
|
||||
isDisabled
|
||||
label={t('reserved deposit')}
|
||||
/>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
icon='plus'
|
||||
isDisabled={!wasm || !genesisState || isIdError}
|
||||
onStart={onClose}
|
||||
params={[paraId, genesisState, wasm]}
|
||||
tx={api.tx.registrar.register}
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(RegisterThread);
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { BN, BN_ONE, BN_THOUSAND } from '@pezkuwi/util';
|
||||
|
||||
export const LOWEST_PUBLIC_ID = new BN(2_000);
|
||||
|
||||
export const LOWEST_INVALID_ID = LOWEST_PUBLIC_ID.sub(BN_ONE);
|
||||
|
||||
export const LOWEST_USER_ID = BN_THOUSAND;
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ParaId } from '@pezkuwi/types/interfaces';
|
||||
import type { LeasePeriod, OwnedId, QueuedAction } from '../types.js';
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { Table } from '@pezkuwi/react-components';
|
||||
|
||||
import { useTranslation } from '../translate.js';
|
||||
import Actions from './Actions.js';
|
||||
import Parathread from './Parathread.js';
|
||||
import useParaMap from './useParaMap.js';
|
||||
|
||||
interface Props {
|
||||
actionsQueue: QueuedAction[];
|
||||
className?: string;
|
||||
ids?: ParaId[];
|
||||
leasePeriod?: LeasePeriod;
|
||||
ownedIds: OwnedId[];
|
||||
}
|
||||
|
||||
function Parathreads ({ actionsQueue, className, ids, leasePeriod, ownedIds }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const leaseMap = useParaMap(ids);
|
||||
|
||||
const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([
|
||||
[t('parathreads'), 'start', 2],
|
||||
['', 'media--2000'],
|
||||
[t('head'), 'start media--1500'],
|
||||
[t('lifecycle'), 'start'],
|
||||
[],
|
||||
[], // [t('chain'), 'no-pad-left'],
|
||||
[t('leases')],
|
||||
['', 'media--900']
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Actions ownedIds={ownedIds} />
|
||||
<Table
|
||||
empty={leasePeriod && ids && (ids.length === 0 || leaseMap) && t('There are no available parathreads')}
|
||||
header={headerRef.current}
|
||||
>
|
||||
{leasePeriod && leaseMap?.map(([id, leases]): React.ReactNode => (
|
||||
<Parathread
|
||||
id={id}
|
||||
key={id.toString()}
|
||||
leasePeriod={leasePeriod}
|
||||
leases={leases}
|
||||
nextAction={actionsQueue.find(({ paraIds }) =>
|
||||
paraIds.some((p) => p.eq(id))
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Parathreads);
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Option } from '@pezkuwi/types';
|
||||
import type { AccountId, BalanceOf, ParaId } from '@pezkuwi/types/interfaces';
|
||||
import type { ITuple } from '@pezkuwi/types/types';
|
||||
import type { LeaseInfo } from '../types.js';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { createNamedHook, useApi, useCall, useIsParasLinked } from '@pezkuwi/react-hooks';
|
||||
|
||||
type Result = [ParaId, LeaseInfo[]][];
|
||||
|
||||
function extractParaMap (hasLinksMap: Record<string, boolean>, paraIds: ParaId[], leases: Option<ITuple<[AccountId, BalanceOf]>>[][]): Result {
|
||||
return paraIds
|
||||
.reduce((all: Result, id, index): Result => {
|
||||
all.push([
|
||||
id,
|
||||
leases[index]
|
||||
.map((optLease, period): LeaseInfo | null => {
|
||||
if (optLease.isNone) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [accountId, balance] = optLease.unwrap();
|
||||
|
||||
return {
|
||||
accountId,
|
||||
balance,
|
||||
period
|
||||
};
|
||||
})
|
||||
.filter((item): item is LeaseInfo => !!item)
|
||||
]);
|
||||
|
||||
return all;
|
||||
}, [])
|
||||
.sort(([aId, aLeases], [bId, bLeases]): number => {
|
||||
const aKnown = hasLinksMap[aId.toString()] || false;
|
||||
const bKnown = hasLinksMap[bId.toString()] || false;
|
||||
|
||||
return aLeases.length && bLeases.length
|
||||
? (aLeases[0].period - bLeases[0].period) || aId.cmp(bId)
|
||||
: aLeases.length
|
||||
? -1
|
||||
: bLeases.length
|
||||
? 1
|
||||
: aKnown === bKnown
|
||||
? aId.cmp(bId)
|
||||
: aKnown
|
||||
? -1
|
||||
: 1;
|
||||
});
|
||||
}
|
||||
|
||||
function useParaMapImpl (ids?: ParaId[]): Result | undefined {
|
||||
const { api } = useApi();
|
||||
const hasLinksMap = useIsParasLinked(ids);
|
||||
const transform = useCallback(
|
||||
([[paraIds], leases]: [[ParaId[]], Option<ITuple<[AccountId, BalanceOf]>>[][]]): Result =>
|
||||
extractParaMap(hasLinksMap, paraIds, leases),
|
||||
[hasLinksMap]
|
||||
);
|
||||
|
||||
return useCall<Result>(ids && api.query.slots.leases.multi, [ids], {
|
||||
transform,
|
||||
withParamsTransform: true
|
||||
});
|
||||
}
|
||||
|
||||
export default createNamedHook('useParaMap', useParaMapImpl);
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-teyrchains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Option } from '@pezkuwi/types';
|
||||
import type { AccountId, HeadData, ParaId } from '@pezkuwi/types/interfaces';
|
||||
import type { PezkuwiRuntimeCommonParasRegistrarParaInfo, PezkuwiRuntimeTeyrchainsParasParaGenesisArgs, PezkuwiRuntimeTeyrchainsParasParaLifecycle } from '@pezkuwi/types/lookup';
|
||||
|
||||
import { createNamedHook, useApi, useCallMulti } from '@pezkuwi/react-hooks';
|
||||
|
||||
interface Result {
|
||||
headHex: string | null;
|
||||
lifecycle: PezkuwiRuntimeTeyrchainsParasParaLifecycle | null;
|
||||
manager: AccountId | null;
|
||||
}
|
||||
|
||||
const OPT_MULTI = {
|
||||
defaultValue: {
|
||||
headHex: null,
|
||||
lifecycle: null,
|
||||
manager: null
|
||||
},
|
||||
transform: ([optHead, optGenesis, optLifecycle, optInfo]: [Option<HeadData>, Option<PezkuwiRuntimeTeyrchainsParasParaGenesisArgs>, Option<PezkuwiRuntimeTeyrchainsParasParaLifecycle>, Option<PezkuwiRuntimeCommonParasRegistrarParaInfo>]): Result => ({
|
||||
headHex: optHead.isSome
|
||||
? optHead.unwrap().toHex()
|
||||
: optGenesis.isSome
|
||||
? optGenesis.unwrap().genesisHead.toHex()
|
||||
: null,
|
||||
lifecycle: optLifecycle.unwrapOr(null),
|
||||
manager: optInfo.isSome
|
||||
? optInfo.unwrap().manager
|
||||
: null
|
||||
})
|
||||
};
|
||||
|
||||
function useThreadInfoImpl (id: ParaId): Result {
|
||||
const { api } = useApi();
|
||||
|
||||
return useCallMulti<Result>([
|
||||
[api.query.paras.heads, id],
|
||||
[api.query.paras.upcomingParasGenesis, id],
|
||||
[api.query.paras.paraLifecycles, id],
|
||||
[api.query.registrar.paras, id]
|
||||
], OPT_MULTI);
|
||||
}
|
||||
|
||||
export default createNamedHook('useThreadInfo', useThreadInfoImpl);
|
||||
Reference in New Issue
Block a user