mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-08-09 02:45:43 +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,111 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-accounts authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { Button, IdentityIcon, styled } from '@pezkuwi/react-components';
|
||||
import { u8aToHex } from '@pezkuwi/util';
|
||||
|
||||
import { useTranslation } from '../translate.js';
|
||||
|
||||
interface Props {
|
||||
address: string;
|
||||
className?: string;
|
||||
count: number;
|
||||
offset: number;
|
||||
onCreateToggle: (seed: string) => void;
|
||||
onRemove: (address: string) => void;
|
||||
seed?: Uint8Array;
|
||||
}
|
||||
|
||||
function Match ({ address, className = '', count, offset, onCreateToggle, onRemove, seed }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const hexSeed = useMemo(
|
||||
() => u8aToHex(seed),
|
||||
[seed]
|
||||
);
|
||||
const _onCreate = useCallback(
|
||||
() => onCreateToggle(hexSeed),
|
||||
[hexSeed, onCreateToggle]
|
||||
);
|
||||
const _onRemove = useCallback(
|
||||
() => onRemove(address),
|
||||
[address, onRemove]
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledTr className={className}>
|
||||
<td
|
||||
className='number'
|
||||
colSpan={2}
|
||||
>
|
||||
<IdentityIcon
|
||||
className='vanity--Match-icon'
|
||||
value={address}
|
||||
/>
|
||||
</td>
|
||||
<td className='address all'>
|
||||
<div className='vanity--Match-addr'>
|
||||
<span className='no'>{address.slice(0, offset)}</span><span className='yes'>{address.slice(offset, count + offset)}</span><span className='no'>{address.slice(count + offset)}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className='hash'>
|
||||
{hexSeed}
|
||||
</td>
|
||||
<td className='button'>
|
||||
<Button
|
||||
icon='plus'
|
||||
label={t('Save')}
|
||||
onClick={_onCreate}
|
||||
/>
|
||||
<Button
|
||||
icon='times'
|
||||
onClick={_onRemove}
|
||||
/>
|
||||
</td>
|
||||
</StyledTr>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledTr = styled.tr`
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background: #f9f8f7;
|
||||
}
|
||||
|
||||
.vanity--Match-addr {
|
||||
font-size: 1.1rem;
|
||||
|
||||
.no {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.yes {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.vanity--Match-buttons,
|
||||
.vanity--Match-data,
|
||||
.vanity--Match-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.vanity--Match-item {
|
||||
display: inline-block;
|
||||
font: var(--font-mono);
|
||||
margin: 0 auto;
|
||||
padding: 0.5em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vanity--Match-seed {
|
||||
opacity: 0.45;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
`;
|
||||
|
||||
export default React.memo(Match);
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-accounts authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { cryptoWaitReady, ed25519PairFromSeed, mnemonicGenerate, mnemonicToMiniSecret, sr25519PairFromSeed } from '@pezkuwi/util-crypto';
|
||||
|
||||
const ctx: Worker = self as unknown as Worker;
|
||||
|
||||
cryptoWaitReady().catch((): void => {
|
||||
// ignore
|
||||
});
|
||||
|
||||
ctx.onmessage = async ({ data: { pairType } }): Promise<void> => {
|
||||
await cryptoWaitReady();
|
||||
|
||||
const seed = mnemonicGenerate();
|
||||
const miniSecret = mnemonicToMiniSecret(seed);
|
||||
const { publicKey } = pairType === 'sr25519'
|
||||
? sr25519PairFromSeed(miniSecret)
|
||||
: ed25519PairFromSeed(miniSecret);
|
||||
|
||||
ctx.postMessage({
|
||||
publicKey,
|
||||
seed
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-accounts authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ActionStatus } from '@pezkuwi/react-components/Status/types';
|
||||
import type { KeypairType } from '@pezkuwi/util-crypto/types';
|
||||
import type { GeneratorMatch, GeneratorMatches, GeneratorResult } from '@polkadot/vanitygen/types';
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Button, Dropdown, Input, styled, Table } from '@pezkuwi/react-components';
|
||||
import { useApi, useIsMountedRef } from '@pezkuwi/react-hooks';
|
||||
import { settings } from '@pezkuwi/ui-settings';
|
||||
import { nextTick } from '@pezkuwi/util';
|
||||
import generator from '@polkadot/vanitygen/generator';
|
||||
import matchRegex from '@polkadot/vanitygen/regex';
|
||||
import generatorSort from '@polkadot/vanitygen/sort';
|
||||
|
||||
import CreateModal from '../modals/Create.js';
|
||||
import { useTranslation } from '../translate.js';
|
||||
import Match from './Match.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
onStatusChange: (status: ActionStatus) => void;
|
||||
}
|
||||
|
||||
interface MatchState {
|
||||
isMatchValid: boolean;
|
||||
match: string;
|
||||
}
|
||||
|
||||
interface Results {
|
||||
elapsed: number;
|
||||
isRunning: boolean;
|
||||
keyCount: number;
|
||||
keyTime: number;
|
||||
matches: GeneratorMatches;
|
||||
startAt: number;
|
||||
}
|
||||
|
||||
const DEFAULT_MATCH = 'Some';
|
||||
const BOOL_OPTIONS = [
|
||||
{ text: 'No', value: false },
|
||||
{ text: 'Yes', value: true }
|
||||
];
|
||||
|
||||
function VanityApp ({ className = '', onStatusChange }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api, isEthereum } = useApi();
|
||||
const results = useRef<GeneratorResult[]>([]);
|
||||
const runningRef = useRef(false);
|
||||
const mountedRef = useIsMountedRef();
|
||||
const [createSeed, setCreateSeed] = useState<string | null>(null);
|
||||
const [{ elapsed, isRunning, keyCount, matches }, setResults] = useState<Results>({
|
||||
elapsed: 0,
|
||||
isRunning: false,
|
||||
keyCount: -1,
|
||||
keyTime: 0,
|
||||
matches: [],
|
||||
startAt: 0
|
||||
});
|
||||
const [{ isMatchValid, match }, setMatch] = useState<MatchState>({ isMatchValid: true, match: DEFAULT_MATCH });
|
||||
const [type, setType] = useState<KeypairType>('ed25519');
|
||||
const [withCase, setWithCase] = useState(true);
|
||||
|
||||
const _clearSeed = useCallback(
|
||||
() => setCreateSeed(null),
|
||||
[]
|
||||
);
|
||||
|
||||
const _checkMatches = useCallback(
|
||||
(): void => {
|
||||
const checks = results.current;
|
||||
|
||||
results.current = [];
|
||||
|
||||
if (checks.length === 0 || !mountedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setResults(
|
||||
({ isRunning, keyCount, keyTime, matches, startAt }: Results): Results => {
|
||||
let newKeyCount = keyCount;
|
||||
let newKeyTime = keyTime;
|
||||
const newMatches = checks.reduce((result, { elapsed, found }): GeneratorMatch[] => {
|
||||
newKeyCount += found.length;
|
||||
newKeyTime += elapsed;
|
||||
|
||||
return result.concat(found);
|
||||
}, matches);
|
||||
|
||||
return {
|
||||
elapsed: Date.now() - startAt,
|
||||
isRunning,
|
||||
keyCount: newKeyCount,
|
||||
keyTime: newKeyTime,
|
||||
matches: newMatches.sort(generatorSort).slice(0, 25),
|
||||
startAt
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
[mountedRef]
|
||||
);
|
||||
|
||||
const _executeGeneration = useCallback(
|
||||
(): void => {
|
||||
if (!runningRef.current) {
|
||||
return _checkMatches();
|
||||
}
|
||||
|
||||
nextTick((): void => {
|
||||
if (mountedRef.current) {
|
||||
if (results.current.length === 25) {
|
||||
_checkMatches();
|
||||
}
|
||||
|
||||
results.current.push(
|
||||
generator({ match, runs: 10, ss58Format: api.registry.chainSS58 || 0, type, withCase, withHex: true })
|
||||
);
|
||||
|
||||
_executeGeneration();
|
||||
}
|
||||
});
|
||||
},
|
||||
[_checkMatches, api, match, mountedRef, runningRef, type, withCase]
|
||||
);
|
||||
|
||||
const _onChangeMatch = useCallback(
|
||||
(match: string): void => setMatch({
|
||||
isMatchValid:
|
||||
matchRegex.test(match) &&
|
||||
(match.length !== 0) &&
|
||||
(match.length < 31),
|
||||
match
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const _onRemove = useCallback(
|
||||
(address: string): void => setResults(
|
||||
(results: Results): Results => ({
|
||||
...results,
|
||||
matches: results.matches.filter((item) => item.address !== address)
|
||||
})
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const _toggleStart = useCallback(
|
||||
(): void => setResults(
|
||||
({ elapsed, isRunning, keyCount, keyTime, matches, startAt }: Results): Results => ({
|
||||
elapsed,
|
||||
isRunning: !isRunning,
|
||||
keyCount: isRunning ? keyCount : 0,
|
||||
keyTime: isRunning ? keyTime : 0,
|
||||
matches,
|
||||
startAt: isRunning ? startAt : Date.now()
|
||||
})
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect((): void => {
|
||||
runningRef.current = isRunning;
|
||||
|
||||
if (isRunning) {
|
||||
_executeGeneration();
|
||||
}
|
||||
}, [_executeGeneration, isRunning]);
|
||||
|
||||
const header = useMemo<[React.ReactNode?, string?, number?][]>(
|
||||
() => [
|
||||
[t('matches'), 'start', 2],
|
||||
[t('Evaluated {{count}} keys in {{elapsed}}s ({{avg}} keys/s)', {
|
||||
replace: {
|
||||
avg: (keyCount / (elapsed / 1000)).toFixed(3),
|
||||
count: keyCount,
|
||||
elapsed: (elapsed / 1000).toFixed(2)
|
||||
}
|
||||
}), 'start --digits'],
|
||||
[t('secret'), 'start'],
|
||||
[]
|
||||
],
|
||||
[elapsed, keyCount, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledDiv className={className}>
|
||||
<div className='ui--row'>
|
||||
<Input
|
||||
autoFocus
|
||||
className='medium'
|
||||
isDisabled={isRunning}
|
||||
isError={!isMatchValid}
|
||||
label={t('Search for')}
|
||||
onChange={_onChangeMatch}
|
||||
onEnter={_toggleStart}
|
||||
value={match}
|
||||
/>
|
||||
<Dropdown
|
||||
className='medium'
|
||||
isDisabled={isRunning}
|
||||
label={t('case sensitive')}
|
||||
onChange={setWithCase}
|
||||
options={BOOL_OPTIONS}
|
||||
value={withCase}
|
||||
/>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<Dropdown
|
||||
className='medium'
|
||||
defaultValue={type}
|
||||
label={t('keypair crypto type')}
|
||||
onChange={setType}
|
||||
options={isEthereum ? settings.availableCryptosEth : settings.availableCryptos}
|
||||
/>
|
||||
</div>
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon={
|
||||
isRunning
|
||||
? 'stop'
|
||||
: 'sign-in-alt'
|
||||
}
|
||||
isDisabled={!isMatchValid}
|
||||
label={
|
||||
isRunning
|
||||
? t('Stop generation')
|
||||
: t('Start generation')
|
||||
}
|
||||
onClick={_toggleStart}
|
||||
/>
|
||||
</Button.Group>
|
||||
{matches.length !== 0 && (
|
||||
<>
|
||||
<article className='warning centered'>{t('Ensure that you utilized the "Save" functionality before using a generated address to receive funds. Without saving the address and the associated seed any funds sent to it will be lost.')}</article>
|
||||
<Table
|
||||
className='vanity--App-matches'
|
||||
empty={t('No matches found')}
|
||||
header={header}
|
||||
>
|
||||
{matches.map((match): React.ReactNode => (
|
||||
<Match
|
||||
{...match}
|
||||
key={match.address}
|
||||
onCreateToggle={setCreateSeed}
|
||||
onRemove={_onRemove}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</>
|
||||
)}
|
||||
{createSeed && (
|
||||
<CreateModal
|
||||
onClose={_clearSeed}
|
||||
onStatusChange={onStatusChange}
|
||||
seed={createSeed}
|
||||
type={type}
|
||||
/>
|
||||
)}
|
||||
</StyledDiv>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledDiv = styled.div`
|
||||
.vanity--App-matches {
|
||||
overflow-x: auto;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
.vanity--App-stats {
|
||||
padding: 1em 0 0 0;
|
||||
opacity: 0.45;
|
||||
text-align: center;
|
||||
}
|
||||
`;
|
||||
|
||||
export default React.memo(VanityApp);
|
||||
Reference in New Issue
Block a user