Add Pezkuwi SDK UI - Polkadot.js Apps clone

- Clone Polkadot.js Apps repository
- Update package.json with Pezkuwi branding
- Add Pezkuwi endpoint to production chains (wss://pezkuwichain.app:9944)
- Create comprehensive README for SDK UI
- Set up project structure with all packages

Next steps:
- Apply Kurdistan colors (Kesk, Sor, Zer, Spi + Black) to UI theme
- Replace logos with Pezkuwi branding
- Test build and deployment
This commit is contained in:
Claude
2025-11-14 00:55:17 +00:00
parent c48ded7ff2
commit c71ddb6e0d
5836 changed files with 324981 additions and 17 deletions
@@ -0,0 +1,41 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { PalletBrokerScheduleItem } from '@polkadot/types/lookup';
import { BN } from '@polkadot/util';
export function hexToBin (hex: string): string {
return parseInt(hex, 16).toString(2);
}
export function processHexMask (mask: PalletBrokerScheduleItem['mask'] | undefined): string[] {
if (!mask) {
return [];
}
const trimmedHex: string = mask.toHex().slice(2);
const arr: string[] = trimmedHex.split('');
const buffArr: string[] = [];
arr.forEach((bit) => {
hexToBin(bit).split('').forEach((v) => buffArr.push(v));
});
buffArr.filter((v) => v === '1');
return buffArr;
}
export function stringToBN (value: string | undefined): BN {
if (!value) {
return new BN(0);
}
const sanitized = value.trim().replace(/,/g, '');
if (!/^\d+$/.test(sanitized)) {
throw new Error(`Invalid input for BN conversion: "${sanitized}"`);
}
return new BN(sanitized);
}
@@ -0,0 +1,25 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@polkadot/api';
import type { AnyNumber } from '@polkadot/types-codec/types';
import type { AssetInfoComplete } from '../types.js';
export const getFeeAssetLocation = (api: ApiPromise, feeAsset: AssetInfoComplete | null): AnyNumber | object | undefined => {
if (!feeAsset?.id) {
return undefined;
}
const metadata = api.registry.metadata;
const palletIndex = metadata.pallets.filter((a) => a.name.toString() === 'Assets')[0].index.toString();
// FIX ME: Might have to fix it later as it may not be applicable for all chains
const palletInstance = { PalletInstance: palletIndex };
const generalIndex = { GeneralIndex: feeAsset.id };
return {
interior: { X2: [palletInstance, generalIndex] },
parents: 0
};
};
@@ -0,0 +1,66 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { DeriveAccountRegistration } from '@polkadot/api-derive/types';
import type { DisplayedJudgement } from '@polkadot/react-components/types';
import type { SortedJudgements } from '@polkadot/react-components/util/types';
import type { RegistrationJudgement } from '@polkadot/types/interfaces';
function extractIndexes (registrars: RegistrationJudgement[]) {
return registrars.map((judgement) => judgement[0]);
}
export function getJudgements (identity: DeriveAccountRegistration | undefined): SortedJudgements {
if (!identity) {
return [];
}
const judgements = groupJudgements(identity.judgements);
const result = [];
for (const name in judgements) {
const judgementName = name as DisplayedJudgement;
if (judgements[judgementName].length !== 0) {
result.push({ judgementName, registrarsIndexes: extractIndexes(judgements[judgementName]) });
}
}
return result;
}
export function groupJudgements (judgements: RegistrationJudgement[]): Record<DisplayedJudgement, RegistrationJudgement[]> {
const consideredJudgements = filterConsideredJudgements(judgements);
const knownGoodJudgements = filterKnownGood(consideredJudgements);
const reasonableJudgements = filterReasonable(consideredJudgements);
const erroneousJudgements = filterErroneous(consideredJudgements);
const lowQualityJudgements = filterLowQuality(consideredJudgements);
return {
Erroneous: erroneousJudgements,
'Known good': knownGoodJudgements,
'Low quality': lowQualityJudgements,
Reasonable: reasonableJudgements
};
}
const filterConsideredJudgements = (judgements: RegistrationJudgement[]): RegistrationJudgement[] => {
return judgements.filter(([, judgement]) => !judgement.isFeePaid);
};
const filterKnownGood = (judgements: RegistrationJudgement[]): RegistrationJudgement[] => {
return judgements.filter(([, judgement]) => judgement.isKnownGood);
};
const filterReasonable = (judgements: RegistrationJudgement[]): RegistrationJudgement[] => {
return judgements.filter(([, judgement]) => judgement.isReasonable);
};
const filterErroneous = (judgements: RegistrationJudgement[]): RegistrationJudgement[] => {
return judgements.filter(([, judgement]) => judgement.isErroneous);
};
const filterLowQuality = (judgements: RegistrationJudgement[]): RegistrationJudgement[] => {
return judgements.filter(([, judgement]) => judgement.isLowQuality);
};
@@ -0,0 +1,16 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Struct } from '@polkadot/types-codec';
export const isEmpty = (struct: Struct) => {
if (struct.values) {
for (const v of struct.values()) {
if (!v.isEmpty) {
return false;
}
}
}
return true;
};
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { GenericExtrinsic, Vec } from '@polkadot/types';
import type { AccountId, EventRecord } from '@polkadot/types/interfaces';
import type { AnyTuple } from '@polkadot/types-codec/types';
import { stringToHex } from '@polkadot/util';
export const isEventFromMyAccounts = (newEvent: EventRecord, extrinsics: Vec<GenericExtrinsic<AnyTuple>>, author: AccountId | undefined, allAccounts: string[]) => {
const { event, phase } = newEvent;
// 1. check if any event arg matches one of the accounts
const involvesInArgs = event.data.some((args) =>
allAccounts.some((account) => args.toString().includes(account) || args.toString().includes(stringToHex(account)))
);
// 2. check if extrinsic signer matches
let involvesInSigner = false;
if (phase.isApplyExtrinsic) {
const index = phase.asApplyExtrinsic.toNumber();
const ext = extrinsics[index];
if (ext?.signer) {
involvesInSigner = allAccounts.includes(ext.signer.toString());
}
}
// 3. check if block author is in user's accounts
const involvesInAuthor = author && allAccounts.includes(author.toString());
return involvesInArgs || involvesInSigner || involvesInAuthor;
};
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Judgement } from '@polkadot/react-components/types';
import type { SortedJudgements } from '@polkadot/react-components/util/types';
import type { Registrar } from '../types.js';
export function matchRegistrarAccountsWithIndexes (
judgementsWithRegistrarIndexes: SortedJudgements,
allRegistrars: Registrar[]
): Judgement[] {
return judgementsWithRegistrarIndexes.map(({ judgementName, registrarsIndexes }) => {
const findRegistrarByIndex = (index: number) => allRegistrars.find((registrar) => registrar.index === index);
return {
judgementName,
registrars: registrarsIndexes.map((index) => findRegistrarByIndex(index.toNumber()))
};
});
}