mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-04-22 14:47:58 +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,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[] })[];
|
||||
Reference in New Issue
Block a user