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:
Kurdistan Tech Ministry committed 2026-01-07 13:05:27 +03:00
commit d21bfb1320
5867 files changed
+329019

No files matched your search

+85
View File
@@ -0,0 +1,85 @@
// Copyright 2017-2025 @pezkuwi/app-contracts authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React, { useCallback, useState } from 'react';
import { Button, Input, Modal } from '@pezkuwi/react-components';
import { isNull } from '@pezkuwi/util';
import { ABI, InputName } from '../shared/index.js';
import store from '../store.js';
import { useTranslation } from '../translate.js';
import useAbi from '../useAbi.js';
import ValidateCode from './ValidateCode.js';
interface Props {
onClose: () => void;
}
function Add ({ onClose }: Props): React.ReactElement {
const { t } = useTranslation();
const [codeHash, setCodeHash] = useState('');
const [isCodeHashValid, setIsCodeHashValid] = useState(false);
const [name, setName] = useState<string | null>(null);
const { abi, contractAbi, errorText, isAbiError, isAbiSupplied, isAbiValid, onChangeAbi, onRemoveAbi } = useAbi();
const _onSave = useCallback(
(): void => {
if (!codeHash || !name) {
return;
}
store.saveCode(codeHash, { abi, name, tags: [] });
onClose();
},
[abi, codeHash, name, onClose]
);
const isNameValid = !isNull(name) && name.length > 0;
const isValid = isCodeHashValid && isNameValid && isAbiSupplied && isAbiValid;
return (
<Modal
header={t('Add an existing code hash')}
onClose={onClose}
>
<Modal.Content>
<Input
autoFocus
isError={codeHash.length > 0 && !isCodeHashValid}
label={t('code hash')}
onChange={setCodeHash}
value={codeHash}
/>
<ValidateCode
codeHash={codeHash}
onChange={setIsCodeHashValid}
/>
<InputName
isError={!isNameValid}
onChange={setName}
value={name || undefined}
/>
<ABI
contractAbi={contractAbi}
errorText={errorText}
isError={isAbiError || !isAbiError}
isSupplied={isAbiSupplied}
isValid={isAbiValid}
onChange={onChangeAbi}
onRemove={onRemoveAbi}
/>
</Modal.Content>
<Modal.Actions>
<Button
icon='save'
isDisabled={!isValid}
label={t('Save')}
onClick={_onSave}
/>
</Modal.Actions>
</Modal>
);
}
export default React.memo(Add);
+130
View File
@@ -0,0 +1,130 @@
// Copyright 2017-2025 @pezkuwi/app-staking authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Option } from '@pezkuwi/types';
import type { Codec } from '@pezkuwi/types/types';
import type { CodeStored } from '../types.js';
import React, { useCallback } from 'react';
import { Button, Card, CopyButton, Forget, styled } from '@pezkuwi/react-components';
import { useApi, useCall, useToggle } from '@pezkuwi/react-hooks';
import { CodeRow, Messages } from '../shared/index.js';
import store from '../store.js';
import { useTranslation } from '../translate.js';
import useAbi from '../useAbi.js';
interface Props {
className?: string;
code: CodeStored;
onShowDeploy: (codeHash: string, constructorIndex: number) => void;
}
function Code ({ className, code, onShowDeploy }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const optCode = useCall<Option<Codec>>(api.query.contracts.pristineCode || api.query.contracts.codeStorage, [code.json.codeHash]);
const [isForgetOpen, toggleIsForgetOpen] = useToggle();
const { contractAbi } = useAbi([code.json.abi, code.contractAbi], code.json.codeHash, true);
const _onShowDeploy = useCallback(
() => onShowDeploy(code.json.codeHash, 0),
[code, onShowDeploy]
);
const _onDeployConstructor = useCallback(
(constructorIndex?: number): void => {
onShowDeploy && onShowDeploy(code.json.codeHash, constructorIndex || 0);
},
[code, onShowDeploy]
);
const _onForget = useCallback(
(): void => {
try {
store.forgetCode(code.json.codeHash);
} catch (error) {
console.error(error);
} finally {
toggleIsForgetOpen();
}
},
[code, toggleIsForgetOpen]
);
return (
<StyledTr className={className}>
<td className='address top'>
<Card>
<CodeRow
code={code}
withTags={false}
/>
{isForgetOpen && (
<Forget
key='modal-forget-account'
mode='code'
onClose={toggleIsForgetOpen}
onForget={_onForget}
>
<CodeRow
code={code || ''}
isInline
>
<p>{t('You are about to remove this code from your list of available code hashes. Once completed, should you need to access it again, you will have to manually add the code hash again.')}</p>
<p>{t('This operation does not remove the uploaded code WASM and ABI from the chain, nor any deployed contracts. The forget operation only limits your access to the code on this browser.')}</p>
</CodeRow>
</Forget>
)}
</Card>
</td>
<td className='all top'>
{contractAbi && (
<Messages
contractAbi={contractAbi}
onSelectConstructor={_onDeployConstructor}
withConstructors
/>
)}
</td>
<td className='together codeHash'>
<div>{`${code.json.codeHash.slice(0, 8)}…${code.json.codeHash.slice(-6)}`}</div>
<CopyButton value={code.json.codeHash} />
</td>
<td className='start together'>
{optCode && (
optCode.isSome ? t('Available') : t('Not on-chain')
)}
</td>
<td className='button'>
<Button
icon='trash'
onClick={toggleIsForgetOpen}
/>
{!contractAbi && (
<Button
icon='upload'
label={t('deploy')}
onClick={_onShowDeploy}
/>
)}
</td>
</StyledTr>
);
}
const StyledTr = styled.tr`
.codeHash {
div {
display: inline;
&:first-child {
font-family: monospace;
margin-right: 0.5rem;
}
}
}
`;
export default React.memo(Code);
@@ -0,0 +1,269 @@
// Copyright 2017-2025 @pezkuwi/app-contracts authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { SubmittableExtrinsic } from '@pezkuwi/api/types';
import type { CodeSubmittableResult } from '@pezkuwi/api-contract/promise/types';
import type { BN } from '@pezkuwi/util';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { CodePromise } from '@pezkuwi/api-contract';
import { Button, Dropdown, InputAddress, InputBalance, InputFile, MarkError, Modal, TxButton } from '@pezkuwi/react-components';
import { useAccountId, useApi, useFormField, useNonEmptyString, useStepper } from '@pezkuwi/react-hooks';
import { Available } from '@pezkuwi/react-query';
import { keyring } from '@pezkuwi/ui-keyring';
import { BN_ZERO, isNull, isWasm, stringify } from '@pezkuwi/util';
import { ABI, InputMegaGas, InputName, MessageSignature, Params } from '../shared/index.js';
import store from '../store.js';
import { useTranslation } from '../translate.js';
import useAbi from '../useAbi.js';
import useWeight from '../useWeight.js';
interface Props {
onClose: () => void;
}
function Upload ({ onClose }: Props): React.ReactElement {
const { t } = useTranslation();
const { api } = useApi();
const [accountId, setAccountId] = useAccountId();
const [step, nextStep, prevStep] = useStepper();
const [[uploadTx, error], setUploadTx] = useState<[SubmittableExtrinsic<'promise'> | null, string | null]>([null, null]);
const [constructorIndex, setConstructorIndex] = useState<number>(0);
const [value, isValueValid, setValue] = useFormField<BN>(BN_ZERO);
const [params, setParams] = useState<unknown[]>([]);
const [[wasm, isWasmValid], setWasm] = useState<[Uint8Array | null, boolean]>([null, false]);
const [name, isNameValid, setName] = useNonEmptyString();
const { abiName, contractAbi, errorText, isAbiError, isAbiSupplied, isAbiValid, onChangeAbi, onRemoveAbi } = useAbi();
const weight = useWeight();
const code = useMemo(
() => isAbiValid && isWasmValid && wasm && contractAbi
? new CodePromise(api, contractAbi, wasm)
: null,
[api, contractAbi, isAbiValid, isWasmValid, wasm]
);
const constructOptions = useMemo(
() => contractAbi
? contractAbi.constructors.map((c, index) => ({
info: c.identifier,
key: c.identifier,
text: (
<MessageSignature
asConstructor
message={c}
/>
),
value: index
}))
: [],
[contractAbi]
);
useEffect((): void => {
setConstructorIndex(0);
}, [constructOptions]);
useEffect((): void => {
setParams([]);
}, [contractAbi, constructorIndex]);
useEffect((): void => {
setWasm(
contractAbi && isWasm(contractAbi.info.source.wasm)
? [contractAbi.info.source.wasm, true]
: [null, false]
);
}, [contractAbi]);
useEffect((): void => {
abiName && setName(abiName);
}, [abiName, setName]);
useEffect((): void => {
async function dryRun () {
let contract: SubmittableExtrinsic<'promise'> | null = null;
let error: string | null = null;
try {
if (code && contractAbi?.constructors[constructorIndex]?.method && value && accountId) {
const dryRunParams: Parameters<typeof api.call.contractsApi.instantiate> =
[
accountId,
contractAbi?.constructors[constructorIndex].isPayable
? api.registry.createType('Balance', value)
: api.registry.createType('Balance', BN_ZERO),
weight.weightV2,
null,
{ Upload: api.registry.createType('Raw', wasm) },
contractAbi?.constructors[constructorIndex]?.toU8a(params),
''
];
const dryRunResult = await api.call.contractsApi.instantiate(...dryRunParams);
contract = code.tx[contractAbi.constructors[constructorIndex].method]({
gasLimit: dryRunResult.gasRequired,
storageDepositLimit: dryRunResult.storageDeposit.isCharge ? dryRunResult.storageDeposit.asCharge : null,
value: contractAbi?.constructors[constructorIndex].isPayable ? value : undefined
}, ...params);
}
} catch (e) {
error = (e as Error).message;
}
setUploadTx(() => [contract, error]);
}
dryRun().catch((e) => console.error(e));
}, [accountId, wasm, api, code, contractAbi, constructorIndex, value, params, weight]);
const _onAddWasm = useCallback(
(wasm: Uint8Array, name: string): void => {
setWasm([wasm, isWasm(wasm)]);
setName(name.replace('.wasm', '').replace('_', ' '));
},
[setName]
);
const _onSuccess = useCallback(
(result: CodeSubmittableResult): void => {
result.blueprint && store.saveCode(result.blueprint.codeHash, {
abi: stringify(result.blueprint.abi.json),
name: name || '<>',
tags: []
});
result.contract && keyring.saveContract(result.contract.address.toString(), {
contract: {
abi: stringify(result.contract.abi.json),
genesisHash: api.genesisHash.toHex()
},
name: name || '<>',
tags: []
});
},
[api, name]
);
const isSubmittable = !!accountId && (!isNull(name) && isNameValid) && isWasmValid && isAbiSupplied && isAbiValid && !!uploadTx && step === 2;
const invalidAbi = isAbiError || !isAbiSupplied;
return (
<Modal
header={t('Upload & deploy code {{info}}', { replace: { info: `${step}/2` } })}
onClose={onClose}
>
<Modal.Content>
{step === 1 && (
<>
<InputAddress
isInput={false}
label={t('deployment account')}
labelExtra={
<Available
label={t('transferable')}
params={accountId}
/>
}
onChange={setAccountId}
type='account'
value={accountId}
/>
<ABI
contractAbi={contractAbi}
errorText={errorText}
isError={invalidAbi}
isSupplied={isAbiSupplied}
isValid={isAbiValid}
label={t('json for either ABI or .contract bundle')}
onChange={onChangeAbi}
onRemove={onRemoveAbi}
withWasm
/>
{!invalidAbi && contractAbi && (
<>
{!contractAbi.info.source.wasm.length && (
<InputFile
isError={!isWasmValid}
label={t('compiled contract WASM')}
onChange={_onAddWasm}
placeholder={wasm && !isWasmValid && t('The code is not recognized as being in valid WASM format')}
/>
)}
<InputName
isError={!isNameValid}
onChange={setName}
value={name || undefined}
/>
</>
)}
</>
)}
{step === 2 && contractAbi && (
<>
<Dropdown
isDisabled={contractAbi.constructors.length <= 1}
label={t('deployment constructor')}
onChange={setConstructorIndex}
options={constructOptions}
value={constructorIndex}
/>
<Params
onChange={setParams}
params={contractAbi.constructors[constructorIndex].args}
registry={contractAbi.registry}
/>
{contractAbi.constructors[constructorIndex].isPayable && (
<InputBalance
isError={!isValueValid}
isZeroable
label={t('value')}
onChange={setValue}
value={value}
/>
)
}
<InputMegaGas
weight={weight}
/>
{error && (
<MarkError content={error} />
)}
</>
)}
</Modal.Content>
<Modal.Actions>
{step === 1
? (
<Button
icon='step-forward'
isDisabled={!code || !contractAbi}
label={t('Next')}
onClick={nextStep}
/>
)
: (
<Button
icon='step-backward'
label={t('Prev')}
onClick={prevStep}
/>
)
}
<TxButton
accountId={accountId}
extrinsic={uploadTx}
icon='upload'
isDisabled={!isSubmittable}
label={t('Deploy')}
onClick={onClose}
onSuccess={_onSuccess}
/>
</Modal.Actions>
</Modal>
);
}
export default React.memo(Upload);
@@ -0,0 +1,57 @@
// Copyright 2017-2025 @pezkuwi/app-contracts authors & contributors
// SPDX-License-Identifier: Apache-2.0
/* eslint-disable camelcase */
import type { Option } from '@pezkuwi/types';
import type { PrefabWasmModule } from '@pezkuwi/types/interfaces';
import React, { useMemo } from 'react';
import { InfoForInput } from '@pezkuwi/react-components';
import { useApi, useCall } from '@pezkuwi/react-hooks';
import { isHex } from '@pezkuwi/util';
import { useTranslation } from '../translate.js';
interface Props {
codeHash?: string | null;
onChange: React.Dispatch<boolean>;
}
function ValidateCode ({ codeHash, onChange }: Props): React.ReactElement<Props> | null {
const { api } = useApi();
const { t } = useTranslation();
const optCode = useCall<Option<PrefabWasmModule>>((api.query.contracts || api.query.contract).pristineCode || (api.query.contracts || api.query.contract).codeStorage, [codeHash]);
const [isValidHex, isValid] = useMemo(
(): [boolean, boolean] => {
const isValidHex = !!codeHash && isHex(codeHash) && codeHash.length === 66;
const isStored = !!optCode && optCode.isSome;
const isValid = isValidHex && isStored;
onChange(isValid);
return [
isValidHex,
isValid
];
},
[codeHash, optCode, onChange]
);
if (isValid || !isValidHex) {
return null;
}
return (
<InfoForInput type='error'>
{
isValidHex
? t('Unable to find on-chain WASM code for the supplied codeHash')
: t('The codeHash is not a valid hex hash')
}
</InfoForInput>
);
}
export default React.memo(ValidateCode);
@@ -0,0 +1,44 @@
// Copyright 2017-2025 @pezkuwi/app-staking authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React, { useRef } from 'react';
import { Table } from '@pezkuwi/react-components';
import contracts from '../store.js';
import { useTranslation } from '../translate.js';
import Code from './Code.js';
interface Props {
onShowDeploy: (codeHash: string, constructorIndex: number) => void;
updated: number;
}
function Codes ({ onShowDeploy }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const headerRef = useRef<[string?, string?, number?][]>([
[t('code hashes'), 'start'],
[],
[],
[t('status'), 'start'],
[]
]);
return (
<Table
empty={t('No code hashes available')}
header={headerRef.current}
>
{contracts.getAllCode().map((code): React.ReactNode => (
<Code
code={code}
key={code.json.codeHash}
onShowDeploy={onShowDeploy}
/>
))}
</Table>
);
}
export default React.memo(Codes);