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:
2026-01-07 13:05:27 +03:00
commit d21bfb1320
5867 changed files with 329019 additions and 0 deletions
@@ -0,0 +1,70 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BlockNumber } from '@pezkuwi/types/interfaces';
import type { BN } from '@pezkuwi/util';
import { BN_ZERO, bnMin } from '@pezkuwi/util';
interface VestingSchedule {
startingBlock: BN;
endBlock: BN;
perBlock: BN;
locked: BN;
vested: BN;
}
interface RecalculatedVesting {
vestedBalance: BN;
vestedClaimable: BN;
vestingLocked: BN;
}
/**
* Manually recalculate vesting amounts using the correct block number.
* This is needed because after Asset Hub migration, vesting schedules use
* relay chain block numbers, but derive.balances.all calculates using
* the current chain's block number.
*/
export function recalculateVesting (
schedules: VestingSchedule[],
currentBlock: BlockNumber
): RecalculatedVesting {
let totalVested = BN_ZERO;
let totalLocked = BN_ZERO;
for (const schedule of schedules) {
const { endBlock, locked, perBlock, startingBlock } = schedule;
// If we haven't reached the start block yet, nothing vested
if (currentBlock.lt(startingBlock)) {
totalLocked = totalLocked.add(locked);
continue;
}
// If we've passed the end block, everything is vested
if (currentBlock.gte(endBlock)) {
totalVested = totalVested.add(locked);
continue;
}
// We're in the middle of vesting
// Calculate how many blocks have passed since start
const blocksPassed = currentBlock.sub(startingBlock);
// Calculate vested amount: min(blocksPassed * perBlock, locked)
const vestedAmount = bnMin(blocksPassed.mul(perBlock), locked);
// Calculate still locked amount
const stillLocked = locked.sub(vestedAmount);
totalVested = totalVested.add(vestedAmount);
totalLocked = totalLocked.add(stillLocked);
}
return {
vestedBalance: totalVested,
vestedClaimable: totalVested, // Will be adjusted in caller with original offset
vestingLocked: totalLocked
};
}
@@ -0,0 +1,44 @@
// Copyright 2017-2025 @pezkuwi/app-staking authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { DeriveAccountInfo } from '@pezkuwi/api-derive/types';
import { keyring } from '@pezkuwi/ui-keyring';
import { isFunction } from '@pezkuwi/util';
export function checkVisibility (api: ApiPromise, address: string, accountInfo: DeriveAccountInfo, filterName = '', onlyNamed = false): boolean {
let isVisible = false;
const filterLower = filterName.toLowerCase();
if (filterLower || onlyNamed) {
if (accountInfo) {
const { accountId, accountIndex, identity, nickname } = accountInfo;
const hasAddressMatch = (!!accountId && accountId.toString().includes(filterName)) || (!!accountIndex && accountIndex.toString().includes(filterName));
if (!onlyNamed && hasAddressMatch) {
isVisible = true;
} else if (isFunction(api.query.identity?.identityOf)) {
isVisible = !!identity && (!!identity.display || !!identity.displayParent) && (
hasAddressMatch ||
(!!identity.display && identity.display.toLowerCase().includes(filterLower)) ||
(!!identity.displayParent && identity.displayParent.toLowerCase().includes(filterLower))
);
} else if (nickname) {
isVisible = nickname.toLowerCase().includes(filterLower);
}
}
if (!isVisible) {
const account = keyring.getAddress(address);
isVisible = account?.meta?.name
? account.meta.name.toLowerCase().includes(filterLower)
: false;
}
} else {
isVisible = true;
}
return isVisible;
}
@@ -0,0 +1,8 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { DropdownItemProps } from 'semantic-ui-react';
export const filterDropdownItems = (items: DropdownItemProps[], query: string) => {
return items.filter((item) => item.value?.toString().toLowerCase().includes(query.toLowerCase()));
};
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { AccountIdIsh } from '../types.js';
import { keyring } from '@pezkuwi/ui-keyring';
export function getAccountCryptoType (accountId: AccountIdIsh): string {
try {
const current = accountId
? keyring.getPair(accountId.toString())
: null;
if (current) {
return current.meta.isInjected
? 'injected'
: current.meta.isHardware
? current.meta.hardwareType as string || 'hardware'
: current.meta.isExternal
? current.meta.isMultisig
? 'multisig'
: current.meta.isProxied
? 'proxied'
: current.meta.isLocal
? 'chopsticks'
: 'qr'
: current.type;
}
} catch {
// cannot determine, keep unknown
}
return 'unknown';
}
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { KeyringItemType, KeyringJson$Meta } from '@pezkuwi/ui-keyring/types';
import { keyring } from '@pezkuwi/ui-keyring';
export function getAddressMeta (address: string, type: KeyringItemType | null = null): KeyringJson$Meta {
let meta: KeyringJson$Meta | undefined;
try {
const pair = keyring.getAddress(address, type);
meta = pair?.meta;
} catch {
// we could pass invalid addresses, so it may throw
}
return meta || {};
}
@@ -0,0 +1,18 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { KeyringItemType } from '@pezkuwi/ui-keyring/types';
import { getAddressMeta } from './getAddressMeta.js';
// import { toShortAddress } from './toShortAddress.js';
// isName, isDefault, name
export function getAddressName (address: string, type: KeyringItemType | null = null, defaultName?: string): [boolean, boolean, string] {
const meta = getAddressMeta(address, type);
return meta.name
? [false, false, meta.name.toUpperCase()]
: defaultName
? [false, true, defaultName.toUpperCase()]
: [true, false, address]; // toShortAddress(address)];
}
@@ -0,0 +1,10 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { KeyringItemType } from '@pezkuwi/ui-keyring/types';
import { getAddressMeta } from './getAddressMeta.js';
export function getAddressTags (address: string, type: KeyringItemType | null = null): string[] {
return getAddressMeta(address, type).tags || [];
}
@@ -0,0 +1,26 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { Abi } from '@pezkuwi/api-contract';
import { statics } from '@pezkuwi/react-api/statics';
import { getAddressMeta } from './getAddressMeta.js';
export function getContractAbi (address: string | null): Abi | null {
if (!address) {
return null;
}
let abi: Abi | undefined;
const meta = getAddressMeta(address, 'contract');
try {
const data = (meta.contract && JSON.parse(meta.contract.abi)) as string;
abi = new Abi(data, statics.api.registry.getChainProperties());
} catch (error) {
console.error(error);
}
return abi || null;
}
@@ -0,0 +1,13 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
export { checkVisibility } from './checkVisibility.js';
export { filterDropdownItems } from './dropdownItemsFilter.js';
export { getAccountCryptoType } from './getAccountCryptoType.js';
export { getAddressMeta } from './getAddressMeta.js';
export { getAddressName } from './getAddressName.js';
export { getAddressTags } from './getAddressTags.js';
export { getContractAbi } from './getContractAbi.js';
export { isTreasuryProposalVote } from './isTreasuryProposalVote.js';
export { toAddress } from './toAddress.js';
export { toShortAddress } from './toShortAddress.js';
@@ -0,0 +1,16 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Proposal } from '@pezkuwi/types/interfaces';
export function isTreasuryProposalVote (proposal?: Proposal | null): boolean {
if (!proposal) {
return false;
}
const { method, section } = proposal.registry.findMetaCall(proposal.callIndex);
return section === 'treasury' &&
['approveProposal', 'rejectProposal'].includes(method) &&
!!proposal.args[0];
}
@@ -0,0 +1,32 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { keyring } from '@pezkuwi/ui-keyring';
import { hexToU8a, isHex } from '@pezkuwi/util';
import { ethereumEncode } from '@pezkuwi/util-crypto';
export function toAddress (value?: string | Uint8Array | null, allowIndices = false, bytesLength?: 20 | 32): string | undefined {
if (value) {
try {
const u8a = isHex(value)
? hexToU8a(value)
: keyring.decodeAddress(value);
if (!allowIndices && u8a.length !== 32 && u8a.length !== 20) {
throw new Error('AccountIndex values not allowed');
} else if (bytesLength && u8a.length !== bytesLength) {
throw new Error('Invalid key length');
}
if (u8a.length === 20) {
return ethereumEncode(u8a);
} else {
return keyring.encodeAddress(u8a);
}
} catch {
// undefined return below indicates invalid/transient
}
}
return undefined;
}
@@ -0,0 +1,12 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { AccountId, AccountIndex, Address } from '@pezkuwi/types/interfaces';
export function toShortAddress (_address?: AccountId | AccountIndex | Address | string | null | Uint8Array): string {
const address = (_address || '').toString();
return (address.length > 11)
? `${address.slice(0, 5)}${address.slice(-5)}`
: address;
}
@@ -0,0 +1,16 @@
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type React from 'react';
import type { RegistrarIndex } from '@pezkuwi/types/interfaces/identity/types';
import type { DisplayedJudgement } from '../types.js';
export interface DropdownOption {
className?: string;
key?: string;
text: React.ReactNode;
value: string;
}
export type DropdownOptions = DropdownOption[];
export type SortedJudgements = ({ judgementName: DisplayedJudgement, registrarsIndexes: RegistrarIndex[] })[];