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
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-accounts';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'accounts',
icon: 'users',
name: 'accounts',
text: t('nav.accounts', 'Accounts', { ns: 'apps-routing' }),
useCounter
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-addresses';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'accounts',
icon: 'address-card',
name: 'addresses',
text: t('nav.addresses', 'Address book', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-alliance';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.alliance.joinAlliance'
]
},
group: 'governance',
icon: 'people-group',
name: 'alliance',
text: t('nav.alliance', 'Alliance', { ns: 'apps-routing' }),
useCounter
};
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-ambassador';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.ambassadorCollective.vote',
'tx.ambassadorReferenda.submit',
'consts.ambassadorReferenda.tracks'
]
},
group: 'governance',
icon: 'user-friends',
name: 'ambassador',
text: t('nav.ambassador', 'Ambassador', { ns: 'apps-routing' }),
useCounter
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-assets';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.assets.setMetadata',
'tx.assets.transferKeepAlive'
]
},
group: 'network',
icon: 'shopping-basket',
name: 'assets',
text: t('nav.assets', 'Assets', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-bounties';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
['tx.bounties.proposeBounty', 'tx.treasury.proposeBounty']
]
},
group: 'governance',
icon: 'coins',
name: 'bounties',
text: t('nav.bounties', 'Bounties', { ns: 'apps-routing' }),
useCounter
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-broker';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.broker.status'
],
needsApiInstances: true
},
group: 'network',
icon: 'flask',
name: 'broker',
text: t('nav.broker', 'Coretime Broker', { ns: 'app-broker' })
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-calendar';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'network',
icon: 'calendar-alt',
name: 'calendar',
text: t('nav.calendar', 'Event calendar', { ns: 'apps-routing' })
};
}
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-claims';
import { hasBuffer, u8aToBuffer } from '@pezkuwi/util';
// See https://github.com/pezkuwi-js/apps/issues/10115 - this may not work,
// if not we will have to disable it all (no way of testing)
function needsApiCheck (): boolean {
try {
if (!Buffer.from([1, 2, 3])?.length) {
console.error('ERROR: Unable to construct Buffer object for claims module');
return false;
} else if (!hasBuffer || !Buffer.isBuffer(u8aToBuffer(new Uint8Array([1, 2, 3])))) {
console.error('ERROR: Unable to use u8aToBuffer for claims module');
return false;
}
} catch {
console.error('ERROR: Fatal error in working with Buffer module');
return false;
}
return true;
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'tx.claims.mintClaim'
],
needsApiCheck
},
group: 'accounts',
icon: 'star',
name: 'claims',
text: t('nav.claims', 'Claim Tokens', { ns: 'apps-routing' }),
useCounter
};
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-collator';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.collatorSelection.candidacyBond'
]
},
group: 'network',
icon: 'timeline',
name: 'collators',
text: t('nav.collator', 'Collators', { ns: 'apps-routing' })
};
}
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-contracts';
import { assertReturn } from '@pezkuwi/util';
function needsApiCheck (api: ApiPromise): boolean {
try {
// needs storageDepositLimit
return assertReturn(api.tx.contracts.instantiateWithCode.meta.args.length === 6, 'Invalid args');
} catch {
console.warn('Contract interface does not support storageDepositLimit, disabling route');
return false;
}
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'tx.contracts.instantiateWithCode'
],
needsApiCheck
},
group: 'developer',
icon: 'compress',
name: 'contracts',
text: t('nav.contracts', 'Contracts', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-coretime';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.coretimeAssignmentProvider.coreDescriptors'
],
needsApiInstances: true
},
group: 'network',
icon: 'flask',
name: 'coretime',
text: t('nav.coretime', 'Coretime', { ns: 'apps-routing' })
};
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-council';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.council.prime'
],
needsApiInstances: true
},
group: 'governance',
icon: 'building',
name: 'council',
text: t('nav.council', 'Council', { ns: 'apps-routing' }),
useCounter
};
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-democracy';
function needsApiCheck (api: ApiPromise): boolean {
try {
// we need to be able to create an actual vote
api.tx.democracy.vote(1, { Standard: { balance: 1, vote: { aye: true, conviction: 1 } } });
return true;
} catch {
console.warn('Unable to create referendum vote transaction, disabling democracy route');
return false;
}
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.democracy.propose'
],
needsApiCheck
},
group: 'governance',
icon: 'calendar-check',
name: 'democracy',
text: t('nav.democracy', 'Democracy', { ns: 'apps-routing' }),
useCounter
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-explorer';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'network',
icon: 'braille',
name: 'explorer',
text: t('nav.explorer', 'Explorer', { ns: 'apps-routing' })
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-extrinsics';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'developer',
icon: 'envelope-open-text',
name: 'extrinsics',
text: t('nav.extrinsics', 'Extrinsics', { ns: 'apps-routing' })
};
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-fellowship';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.fellowshipCollective.vote',
'tx.fellowshipReferenda.submit',
'consts.fellowshipReferenda.tracks'
]
},
group: 'governance',
icon: 'people-arrows',
name: 'fellowship',
text: t('nav.fellowship', 'Fellowship', { ns: 'apps-routing' }),
useCounter
};
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-files';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: []
},
group: 'developer',
icon: 'file',
name: 'files',
text: t('nav.files', 'Files (IPFS)', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-gilt';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.gilt.placeBid',
'query.proxy.proxies'
]
},
group: 'network',
icon: 'leaf',
name: 'gilt',
text: t('nav.gilt', 'Gilt', { ns: 'apps-routing' })
};
}
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Routes, TFunction } from './types.js';
import accounts from './accounts.js';
import addresses from './addresses.js';
import alliance from './alliance.js';
import ambassador from './ambassador.js';
import assets from './assets.js';
import bounties from './bounties.js';
import broker from './broker.js';
import calendar from './calendar.js';
import claims from './claims.js';
import collator from './collator.js';
import contracts from './contracts.js';
import coretime from './coretime.js';
import council from './council.js';
import democracy from './democracy.js';
import explorer from './explorer.js';
import extrinsics from './extrinsics.js';
import fellowship from './fellowship.js';
import files from './files.js';
import gilt from './gilt.js';
import js from './js.js';
import membership from './membership.js';
import nfts from './nfts.js';
import nis from './nis.js';
import teyrchains from './teyrchains.js';
import poll from './poll.js';
import preimages from './preimages.js';
import ranked from './ranked.js';
import referenda from './referenda.js';
import rpc from './rpc.js';
import runtime from './runtime.js';
import scheduler from './scheduler.js';
import settings from './settings.js';
import signing from './signing.js';
import society from './society.js';
import staking from './staking.js';
import stakingAsync from './staking-async.js';
import staking2 from './staking2.js';
import stakingLegacy from './stakingLegacy.js';
import storage from './storage.js';
import sudo from './sudo.js';
import techcomm from './techcomm.js';
import teleport from './teleport.js';
import transfer from './transfer.js';
import treasury from './treasury.js';
import utilities from './utilities.js';
import whitelist from './whitelist.js';
export default function create (t: TFunction): Routes {
return [
accounts(t),
addresses(t),
explorer(t),
claims(t),
poll(t),
transfer(t),
teleport(t),
// Staking for AssetHub Migration
stakingAsync(t),
staking(t),
staking2(t),
// Legacy staking Pre v14 pallet version.
stakingLegacy(t),
collator(t),
// Coretime
broker(t),
coretime(t),
// governance v2
referenda(t),
membership(t),
alliance(t),
ambassador(t),
fellowship(t),
ranked(t),
preimages(t),
whitelist(t),
// old v1 governance
democracy(t),
council(t),
techcomm(t),
// other governance-related
treasury(t),
bounties(t),
// others
teyrchains(t),
assets(t),
nfts(t),
society(t),
nis(t),
gilt(t),
scheduler(t),
calendar(t),
contracts(t),
storage(t),
extrinsics(t),
rpc(t),
runtime(t),
signing(t),
sudo(t),
files(t),
js(t),
utilities(t),
settings(t)
];
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-js';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'developer',
icon: 'code',
name: 'js',
text: t('nav.js', 'JavaScript', { ns: 'apps-routing' })
};
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-membership';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'query.membership.members'
]
},
group: 'governance',
icon: 'people-carry',
name: 'membership',
text: t('nav.membership', 'Membership', { ns: 'apps-routing' }),
useCounter
};
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-nfts';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.uniques.create'
]
},
group: 'network',
icon: 'shopping-cart',
name: 'nfts',
text: t('nav.nfts', 'NFTs', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-nis';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.nis.placeBid',
'query.proxy.proxies'
]
},
group: 'network',
icon: 'leaf',
name: 'nis',
text: t('nav.nis', 'Non-interactive Staking', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-poll';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'tx.poll.vote'
]
},
group: 'governance',
icon: 'podcast',
name: 'poll',
text: t('nav.poll', 'Token poll', { ns: 'apps-routing' })
};
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-preimages';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'query.preimage.statusFor',
'tx.preimage.notePreimage'
]
},
group: 'governance',
icon: 'panorama',
name: 'preimages',
text: t('nav.preimages', 'Preimages', { ns: 'apps-routing' })
};
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-ranked';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'tx.rankedCollective.vote',
'tx.rankedPolls.submit'
]
},
group: 'governance',
icon: 'people-arrows',
name: 'ranked',
text: t('nav.ranked', 'Ranked collective', { ns: 'apps-routing' }),
useCounter
};
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-referenda';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'tx.referenda.submit',
'tx.convictionVoting.vote',
'consts.referenda.tracks'
]
},
group: 'governance',
icon: 'person-booth',
name: 'referenda',
text: t('nav.referenda', 'Referenda', { ns: 'apps-routing' }),
useCounter
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-rpc';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'developer',
icon: 'network-wired',
name: 'rpc',
text: t('nav.rpc', 'RPC calls', { ns: 'apps-routing' })
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-runtime';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'developer',
icon: 'arrows-to-circle',
name: 'runtime',
text: t('nav.runtime', 'Runtime calls', { ns: 'apps-routing' })
};
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-scheduler';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.scheduler.agenda'
]
},
group: 'network',
icon: 'clock',
name: 'scheduler',
text: t('nav.scheduler', 'Scheduler', { ns: 'apps-routing' })
};
}
+18
View File
@@ -0,0 +1,18 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-settings';
export default function create (t: TFunction): Route {
return {
Component,
display: {},
group: 'settings',
icon: 'cogs',
name: 'settings',
text: t('nav.settings', 'Settings', { ns: 'apps-routing' }),
useCounter
};
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-signing';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: []
},
group: 'developer',
icon: 'signature',
name: 'signing',
text: t('nav.signing', 'Sign and verify', { ns: 'apps-routing' })
};
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-society';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'query.society.pot'
]
},
group: 'network',
icon: 'hand-spock',
name: 'society',
text: t('nav.society', 'Society', { ns: 'apps-routing' }),
useCounter
};
}
@@ -0,0 +1,29 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-staking-async';
function needsApiCheck (api: ApiPromise): boolean {
try {
return !!((api.tx.stakingAhClient) || (api.tx.staking && api.tx.stakingRcClient));
} catch {
return false;
}
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [],
needsApiCheck
},
group: 'network',
icon: 'certificate',
name: 'staking-async',
text: t('nav.staking-async', 'Staking Async', { ns: 'apps-routing' })
};
}
+85
View File
@@ -0,0 +1,85 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { u32, Vec } from '@pezkuwi/types';
import type { SpStakingPagedExposureMetadata } from '@pezkuwi/types/lookup';
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-staking';
import { ZERO_ACCOUNT } from '@pezkuwi/react-hooks/useWeight';
import { unwrapStorageType } from '@pezkuwi/types/util';
import { assert, BN_ONE } from '@pezkuwi/util';
function needsApiCheck (api: ApiPromise): boolean {
try {
// Hide for every Asset Hub chain and for Relay chains which have stakingAhClient storagr
if (api.query.stakingAhClient || api.tx.stakingRcClient) {
return false;
}
// we need a known Exposure type
const { nominatorCount, own, pageCount, total } = api.registry.createType<SpStakingPagedExposureMetadata>(
unwrapStorageType(api.registry, api.query.staking.erasStakersOverview.creator.meta.type),
{ nominatorCount: BN_ONE, own: BN_ONE, pageCount: BN_ONE, total: BN_ONE }
);
assert(total && own && nominatorCount && pageCount && total.eq(BN_ONE) && own.eq(BN_ONE), 'Needs a known Exposure type');
} catch {
console.warn('Unable to create known-shape Exposure type, disabling staking route');
return false;
}
try {
// we need to be able to bond
if (api.tx.staking.bond.meta.args.length === 3) {
// previous generation, controller account is required
// @ts-expect-error Previous generation
api.tx.staking.bond(ZERO_ACCOUNT, BN_ONE, { Account: ZERO_ACCOUNT });
} else if (api.tx.staking.bond.meta.args.length === 2) {
// current, no controller account
api.tx.staking.bond(BN_ONE, { Account: ZERO_ACCOUNT });
} else {
// unknown
return false;
}
} catch {
console.warn('Unable to create staking bond transaction, disabling staking route');
return false;
}
// For compatibility - `api.query.staking.ledger` returns `legacyClaimedRewards` instead of `claimedRewards` as of v1.4
try {
const v = api.registry.createType<Vec<u32>>(
unwrapStorageType(api.registry, api.query.staking.claimedRewards.creator.meta.type),
[0]
);
assert(v.eq([0]), 'Needs a legacyClaimedRewards array');
} catch {
console.warn('No known legacyClaimedRewards or claimedRewards inside staking ledger, disabling staking route');
return false;
}
return true;
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.staking.erasStakersOverview',
'tx.staking.bond'
],
needsApiCheck
},
group: 'network',
icon: 'certificate',
name: 'staking',
text: t('nav.staking', 'Staking', { ns: 'apps-routing' })
};
}
+67
View File
@@ -0,0 +1,67 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { SpStakingExposure } from '@pezkuwi/types/lookup';
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-staking2';
import { ZERO_ACCOUNT } from '@pezkuwi/react-hooks/useWeight';
import { unwrapStorageType } from '@pezkuwi/types/util';
import { assert, BN_ONE } from '@pezkuwi/util';
function needsApiCheck (api: ApiPromise): boolean {
try {
// we need a known Exposure type
const { others: [{ value, who }], own, total } = api.registry.createType<SpStakingExposure>(
unwrapStorageType(api.registry, api.query.staking.erasStakers.creator.meta.type),
{ others: [{ value: BN_ONE, who: ZERO_ACCOUNT }], own: BN_ONE, total: BN_ONE }
);
assert(total && own && value && who && total.eq(BN_ONE) && own.eq(BN_ONE) && value.eq(BN_ONE), 'Needs a known Exposure type');
} catch {
console.warn('Unable to create known-shape Exposure type, disabling staking route');
return false;
}
try {
// we need to be able to bond
if (api.tx.staking.bond.meta.args.length === 3) {
// previous generation, controller account is required
// @ts-expect-error Previous generation
api.tx.staking.bond(ZERO_ACCOUNT, BN_ONE, { Account: ZERO_ACCOUNT });
} else if (api.tx.staking.bond.meta.args.length === 2) {
// current, no controller account
api.tx.staking.bond(BN_ONE, { Account: ZERO_ACCOUNT });
} else {
// unknown
return false;
}
} catch {
console.warn('Unable to create staking bond transaction, disabling staking route');
return false;
}
return true;
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
isHidden: true,
needsApi: [
'query.session.validators',
'query.staking.erasStakers',
'tx.staking.bond'
],
needsApiCheck
},
group: 'network',
icon: 'certificate',
name: 'test-staking',
text: t('nav.staking', 'Staking', { ns: 'apps-routing' })
};
}
@@ -0,0 +1,93 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { u32, Vec } from '@pezkuwi/types';
import type { PalletStakingStakingLedger, SpStakingExposure } from '@pezkuwi/types/lookup';
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-staking-legacy';
import { ZERO_ACCOUNT } from '@pezkuwi/react-hooks/useWeight';
import { unwrapStorageType } from '@pezkuwi/types/util';
import { assert, BN_ONE } from '@pezkuwi/util';
function needsApiCheck (api: ApiPromise): boolean {
if (typeof api.query.staking.erasStakersOverview === 'function') {
return false;
}
try {
// we need a known Exposure type
const { others: [{ value, who }], own, total } = api.registry.createType<SpStakingExposure>(
unwrapStorageType(api.registry, api.query.staking.erasStakers.creator.meta.type),
{ others: [{ value: BN_ONE, who: ZERO_ACCOUNT }], own: BN_ONE, total: BN_ONE }
);
assert(total && own && value && who && total.eq(BN_ONE) && own.eq(BN_ONE) && value.eq(BN_ONE), 'Needs a known Exposure type');
} catch {
console.warn('Unable to create known-shape Exposure type, disabling staking route');
return false;
}
try {
// we need to be able to bond
if (api.tx.staking.bond.meta.args.length === 3) {
// previous generation, controller account is required
// @ts-expect-error Previous generation
api.tx.staking.bond(ZERO_ACCOUNT, BN_ONE, { Account: ZERO_ACCOUNT });
} else if (api.tx.staking.bond.meta.args.length === 2) {
// current, no controller account
api.tx.staking.bond(BN_ONE, { Account: ZERO_ACCOUNT });
} else {
// unknown
return false;
}
} catch {
console.warn('Unable to create staking bond transaction, disabling staking route');
return false;
}
// For compatibility - `api.query.staking.ledger` returns `legacyClaimedRewards` instead of `claimedRewards` as of v1.4
try {
const v = api.registry.createType<PalletStakingStakingLedger>(
unwrapStorageType(api.registry, api.query.staking.ledger.creator.meta.type),
{ claimedRewards: [1, 2, 3] }
);
if ((v as unknown as { claimedRewards: Vec<u32> }).claimedRewards) {
assert((v as unknown as { claimedRewards: Vec<u32> }).claimedRewards.eq([1, 2, 3]), 'Needs a claimedRewards array');
} else {
const v = api.registry.createType<PalletStakingStakingLedger>(
unwrapStorageType(api.registry, api.query.staking.ledger.creator.meta.type),
{ legacyClaimedRewards: [1, 2, 3] }
);
assert(v.legacyClaimedRewards.eq([1, 2, 3]), 'Needs a legacyClaimedRewards array');
}
} catch {
console.warn('No known legacyClaimedRewards or claimedRewards inside staking ledger, disabling staking route');
return false;
}
return true;
}
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.staking.erasStakers',
'tx.staking.bond'
],
needsApiCheck
},
group: 'network',
icon: 'certificate',
name: 'legacy-staking',
text: t('nav.staking', 'Staking', { ns: 'apps-routing' })
};
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-storage';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'developer',
icon: 'database',
name: 'chainstate',
text: t('nav.storage', 'Chain state', { ns: 'apps-routing' })
};
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-sudo';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'tx.sudo.setKey'
],
needsSudo: true
},
group: 'developer',
icon: 'unlock',
name: 'sudo',
text: t('nav.sudo', 'Sudo', { ns: 'apps-routing' })
};
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-tech-comm';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'query.technicalCommittee.members'
],
needsApiInstances: true
},
group: 'governance',
icon: 'microchip',
name: 'techcomm',
text: t('nav.tech-comm', 'Tech. comm.', { ns: 'apps-routing' }),
useCounter
};
}
+32
View File
@@ -0,0 +1,32 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Modal from '@pezkuwi/app-teyrchains/Teleport';
export default function create (t: TFunction): Route {
return {
Component: Modal,
Modal,
display: {
isHidden: false,
needsAccounts: true,
needsApi: [
[
'tx.xcm.teleportAssets',
'tx.xcmPallet.teleportAssets',
'tx.pezkuwiXcm.teleportAssets',
'tx.xcm.limitedTeleportAssets',
'tx.xcmPallet.limitedTeleportAssets',
'tx.pezkuwiXcm.limitedTeleportAssets'
]
],
needsTeleport: true
},
group: 'accounts',
icon: 'share-square',
name: 'teleport',
text: t('nav.teleport', 'Teleport', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-teyrchains';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
// children - teyrchainInfo.arachainId / teyrchainUpgrade.didSetValidationCode
['query.paras.teyrchains']
]
},
group: 'network',
icon: 'link',
name: 'teyrchains',
text: t('nav.teyrchains', 'Teyrchains', { ns: 'apps-routing' })
};
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import { TransferModal as Modal } from '@pezkuwi/react-components';
export default function create (t: TFunction): Route {
return {
Component: Modal,
Modal,
display: {
isHidden: false,
needsAccounts: true,
needsApi: [
'tx.balances.transferKeepAlive'
]
},
group: 'accounts',
icon: 'paper-plane',
name: 'transfer',
text: t('nav.transfer', 'Transfer', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component, { useCounter } from '@pezkuwi/app-treasury';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: [
'query.treasury.proposals'
]
},
group: 'governance',
icon: 'gem',
name: 'treasury',
text: t('nav.treasury', 'Treasury', { ns: 'apps-routing' }),
useCounter
};
}
+39
View File
@@ -0,0 +1,39 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { IconName } from '@fortawesome/fontawesome-svg-core';
import type React from 'react';
import type { ApiPromise } from '@pezkuwi/api';
import type { AppProps, BareProps } from '@pezkuwi/react-components/types';
export type RouteGroup = 'accounts' | 'developer' | 'governance' | 'network' | 'files' | 'settings';
export interface RouteProps extends AppProps, BareProps {
location: any;
}
export interface Route {
Component: React.ComponentType<any>;
Modal?: React.ComponentType<any>;
display: {
isDevelopment?: boolean;
isHidden?: boolean;
isModal?: boolean;
needsAccounts?: boolean;
needsApi?: (string | string[])[];
needsApiCheck?: (api: ApiPromise) => boolean;
needsApiInstances?: boolean;
needsSudo?: boolean;
needsTeleport?: boolean;
};
group: RouteGroup;
icon: IconName;
isIgnored?: boolean;
name: string;
text: string;
useCounter?: () => number | string | null;
}
export type Routes = Route[];
export type TFunction = (key: string, textOrOptions?: string | { replace: Record<string, unknown> }, options?: { ns: string }) => string;
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-utilities';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsApi: []
},
group: 'developer',
icon: 'wrench',
name: 'utilities',
text: t('nav.utilities', 'Utilities', { ns: 'apps-routing' })
};
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @pezkuwi/apps-routing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Route, TFunction } from './types.js';
import Component from '@pezkuwi/app-whitelist';
export default function create (t: TFunction): Route {
return {
Component,
display: {
needsAccounts: true,
needsApi: [
'tx.whitelist.removeWhitelistedCall'
]
},
group: 'governance',
icon: 'list-check',
name: 'whitelist',
text: t('nav.whitelist', 'Whitelist', { ns: 'apps-routing' })
};
}