mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-06-14 02:51:09 +00:00
7a4bbeac25
- Update @pezkuwi/extension-inject to ^0.62.13 with proper /types exports - Update @pezkuwi/extension-dapp to ^0.62.13 - Update @pezkuwi/extension-compat-metamask to ^0.62.13 - Fix IconTheme type to include 'bizinikiwi' and 'pezkuwi' themes - Fix endpoint array issues (getTeleports -> direct array references) - Add type assertions for external package compatibility (acala, moonbeam, parallel) - Fix subspace.ts dynamic class typing - Fix conviction type in page-referenda - Update Pallet type names to Pezpallet prefix across codebase - Define InjectedExtension types locally for module resolution - Add styled-components DefaultTheme augmentation - Add react-copy-to-clipboard type declaration for React 18 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
177 lines
5.8 KiB
TypeScript
177 lines
5.8 KiB
TypeScript
// Copyright 2017-2026 @pezkuwi/app-teyrchains authors & contributors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import React, { useCallback, useState } from 'react';
|
|
|
|
import { Button, Input, InputAddress, InputBalance, InputFile, InputNumber, InputWasm, MarkWarning, Modal, TxButton } from '@pezkuwi/react-components';
|
|
import { useApi } from '@pezkuwi/react-hooks';
|
|
import { BN, BN_TEN, BN_THOUSAND, BN_ZERO, compactAddLength } from '@pezkuwi/util';
|
|
|
|
import { useTranslation } from '../translate.js';
|
|
|
|
interface Props {
|
|
className?: string;
|
|
onClose: () => void;
|
|
}
|
|
|
|
interface CodeState {
|
|
isWasmValid: boolean;
|
|
wasm: Uint8Array | null;
|
|
}
|
|
|
|
interface ValidatorProps {
|
|
address: string;
|
|
index: number;
|
|
setAddress: (index: number, value: string) => void;
|
|
t: (key: string, options?: { replace: Record<string, unknown> }) => string;
|
|
}
|
|
|
|
function Validator ({ address, index, setAddress, t }: ValidatorProps): React.ReactElement<ValidatorProps> {
|
|
const _setAddress = useCallback(
|
|
(value: string | null) => value && setAddress(index, value),
|
|
[index, setAddress]
|
|
);
|
|
|
|
return (
|
|
<InputAddress
|
|
defaultValue={address}
|
|
label={t('validator {{index}}', { replace: { index: index + 1 } })}
|
|
onChange={_setAddress}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function Propose ({ className, onClose }: Props): React.ReactElement<Props> {
|
|
const { t } = useTranslation();
|
|
const { api } = useApi();
|
|
const [accountId, setAccountId] = useState<string | null>(null);
|
|
const [name, setName] = useState('');
|
|
const [paraId, setParaId] = useState<BN | undefined>();
|
|
const [balance, setBalance] = useState<BN | undefined>(() => BN_THOUSAND.mul(BN_TEN.pow(new BN(api.registry.chainDecimals[0]))));
|
|
const [validators, setValidators] = useState<string[]>(['']);
|
|
const [{ isWasmValid, wasm }, setWasm] = useState<CodeState>({ isWasmValid: false, wasm: null });
|
|
const [genesisState, setGenesisState] = useState<Uint8Array | null>(null);
|
|
|
|
const _setGenesisState = useCallback(
|
|
(data: Uint8Array) => setGenesisState(compactAddLength(data)),
|
|
[]
|
|
);
|
|
|
|
const _setWasm = useCallback(
|
|
(wasm: Uint8Array, isWasmValid: boolean) => setWasm({ isWasmValid, wasm }),
|
|
[]
|
|
);
|
|
|
|
const _setAddress = useCallback(
|
|
(index: number, address: string) =>
|
|
setValidators((v) => v.map((v, i) => i === index ? address : v)),
|
|
[]
|
|
);
|
|
|
|
const _addValidator = useCallback(
|
|
() => setValidators((v) => [...v, '']),
|
|
[]
|
|
);
|
|
|
|
const _delValidator = useCallback(
|
|
() => setValidators((v) => [...v.slice(0, v.length - 1)]),
|
|
[]
|
|
);
|
|
|
|
const isNameValid = name.length >= 3;
|
|
const isValDuplicate = validators.some((a, ai) => validators.some((b, bi) => ai !== bi && a === b));
|
|
|
|
return (
|
|
<Modal
|
|
className={className}
|
|
header={t('Propose teyrchain')}
|
|
onClose={onClose}
|
|
size='large'
|
|
>
|
|
<Modal.Content>
|
|
<Modal.Columns hint={t('This account will be associated with the teyrchain and pay the deposit.')}>
|
|
<InputAddress
|
|
label={t('propose from')}
|
|
onChange={setAccountId}
|
|
type='account'
|
|
value={accountId}
|
|
/>
|
|
</Modal.Columns>
|
|
<Modal.Columns hint={t('The name for this teyrchain, the id and the allocated/requested balance.')}>
|
|
<Input
|
|
autoFocus
|
|
isError={!isNameValid}
|
|
label={t('teyrchain name')}
|
|
onChange={setName}
|
|
/>
|
|
<InputNumber
|
|
isZeroable={false}
|
|
label={t('requested id')}
|
|
onChange={setParaId}
|
|
/>
|
|
<InputBalance
|
|
defaultValue={balance}
|
|
label={t('initial balance')}
|
|
onChange={setBalance}
|
|
/>
|
|
</Modal.Columns>
|
|
<Modal.Columns hint={t('The WASM validation function as well as the genesis state for this teyrchain.')}>
|
|
<InputWasm
|
|
isError={!isWasmValid}
|
|
label={t('validation code')}
|
|
onChange={_setWasm}
|
|
placeholder={wasm && !isWasmValid && t('The code is not recognized as being in valid WASM format')}
|
|
/>
|
|
<InputFile
|
|
isError={!genesisState}
|
|
label={t('genesis state')}
|
|
onChange={_setGenesisState}
|
|
/>
|
|
</Modal.Columns>
|
|
<Modal.Columns hint={t('The validators for this teyrchain. At least one is required and where multiple is supplied, they need to be unique.')}>
|
|
{validators.map((address, index) => (
|
|
<Validator
|
|
address={address}
|
|
index={index}
|
|
key={index}
|
|
setAddress={_setAddress}
|
|
t={t}
|
|
/>
|
|
))}
|
|
{!validators.length && (
|
|
<MarkWarning content={t('You need to supply at last one running validator for your teyrchain alongside this request.')} />
|
|
)}
|
|
{isValDuplicate && (
|
|
<MarkWarning content={t('You have duplicated validator entries, ensure each is unique.')} />
|
|
)}
|
|
<Button.Group>
|
|
<Button
|
|
icon='plus'
|
|
label={t('Add validator')}
|
|
onClick={_addValidator}
|
|
/>
|
|
<Button
|
|
icon='minus'
|
|
isDisabled={validators.length === 0}
|
|
label={t('Remove validator')}
|
|
onClick={_delValidator}
|
|
/>
|
|
</Button.Group>
|
|
</Modal.Columns>
|
|
</Modal.Content>
|
|
<Modal.Actions>
|
|
<TxButton
|
|
accountId={accountId}
|
|
icon='plus'
|
|
isDisabled={!isWasmValid || !genesisState || !isNameValid || !validators.length || !paraId?.gt(BN_ZERO)}
|
|
onStart={onClose}
|
|
params={[paraId, name, wasm, genesisState, validators, balance]}
|
|
tx={api.tx.proposeTeyrchain?.proposeTeyrchain}
|
|
/>
|
|
</Modal.Actions>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
export default React.memo(Propose);
|