Initial rebrand: @polkadot -> @pezkuwi (14 packages)

- Package namespace: @polkadot/* -> @pezkuwi/*
- Repository: polkadot-js/common -> pezkuwichain/pezkuwi-common
- Author: Pezkuwi Team <team@pezkuwichain.io>

Core packages:
- @pezkuwi/util (utilities)
- @pezkuwi/util-crypto (crypto primitives)
- @pezkuwi/keyring (account management)
- @pezkuwi/networks (chain metadata)
- @pezkuwi/hw-ledger (Ledger hardware wallet)
- @pezkuwi/x-* (10 polyfill packages)

Total: 14 packages
Upstream: polkadot-js/common v14.0.1
This commit is contained in:
2026-01-05 14:00:34 +03:00
commit ec06da0ebc
687 changed files with 48096 additions and 0 deletions
@@ -0,0 +1,16 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { hexToU8a } from '@pezkuwi/util';
import { addressToEvm } from './addressToEvm.js';
describe('addressToEvm', (): void => {
it('creates a valid known EVM address', (): void => {
expect(
addressToEvm('KWCv1L3QX9LDPwY4VzvLmarEmXjVJidUzZcinvVnmxAJJCBou')
).toEqual(hexToU8a('0x03b9dc646dd71118e5f7fda681ad9eca36eb3ee9'));
});
});
@@ -0,0 +1,12 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { decodeAddress } from './decode.js';
/**
* @name addressToEvm
* @summary Converts an SS58 address to its corresponding EVM address.
*/
export function addressToEvm (address: string | Uint8Array, ignoreChecksum?: boolean): Uint8Array {
return decodeAddress(address, ignoreChecksum).subarray(0, 20);
}
@@ -0,0 +1,44 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { checkAddress } from './index.js';
describe('checkAddress', (): void => {
it('returns [true, null] for Kusama', (): void => {
expect(
checkAddress('FJaco77EJ99VtBmVFibuBJR3x5Qq9KQrgQJvWjqScCcCCae', 2)
).toEqual([true, null]);
});
it('returns [true, null] for Substrate', (): void => {
expect(
checkAddress('5EnxxUmEbw8DkENKiYuZ1DwQuMoB2UWEQJZZXrTsxoz7SpgG', 42)
).toEqual([true, null]);
});
it('fails when an invalid base58 character is supplied', (): void => {
expect(
checkAddress('5EnxIUmEbw8DkENKiYuZ1DwQuMoB2UWEQJZZXrTsxoz7SpgG', 2)
).toEqual([false, 'Invalid base58 character "I" (0x49) at index 4']);
});
it('fails with invalid prefix when checking Substrate against Kusama prefix', (): void => {
expect(
checkAddress('5EnxxUmEbw8DkENKiYuZ1DwQuMoB2UWEQJZZXrTsxoz7SpgG', 2)
).toEqual([false, 'Prefix mismatch, expected 2, found 42']);
});
it('fails with invalid length when some bytes are missing', (): void => {
expect(
checkAddress('y9EMHt34JJo4rWLSaxoLGdYXvjgSXEd4zHUnQgfNzwES8b', 42)
).toEqual([false, 'Invalid decoded address length']);
});
it('fails with invalid length on checksum mismatch', (): void => {
expect(
checkAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDwU', 42)
).toEqual([false, 'Invalid decoded address checksum']);
});
});
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
import { base58Decode } from '../base58/index.js';
import { checkAddressChecksum } from './checksum.js';
import { defaults } from './defaults.js';
/**
* @name checkAddress
* @summary Validates an ss58 address.
* @description
* From the provided input, validate that the address is a valid input.
*/
export function checkAddress (address: string, prefix: Prefix): [boolean, string | null] {
let decoded;
try {
decoded = base58Decode(address);
} catch (error) {
return [false, (error as Error).message];
}
const [isValid,,, ss58Decoded] = checkAddressChecksum(decoded);
if (ss58Decoded !== prefix) {
return [false, `Prefix mismatch, expected ${prefix}, found ${ss58Decoded}`];
} else if (!defaults.allowedEncodedLengths.includes(decoded.length)) {
return [false, 'Invalid decoded address length'];
}
return [isValid, isValid ? null : 'Invalid decoded address checksum'];
}
@@ -0,0 +1,45 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { base58Decode } from '../base58/index.js';
import { checkAddressChecksum } from './checksum.js';
describe('checkAddressChecksum', (): void => {
it('correctly extracts the info from a 1-byte-prefix address', (): void => {
expect(
checkAddressChecksum(base58Decode('F3opxRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29'))
).toEqual([true, 33, 1, 2]);
});
it('correctly extracts the info from a 2-byte-prefix address (66)', (): void => {
expect(
checkAddressChecksum(base58Decode('cTGShekJ1L1UKFZR9xmv9UTJod7vqjFAPo4sDhXih2c3y1yLS'))
).toEqual([true, 34, 2, 66]);
});
it('correctly extracts the info from a 2-byte-prefix address (69)', (): void => {
expect(
checkAddressChecksum(base58Decode('cnVvyMzRdqjwejTFuByQQ4w2yu78V2hpFixjHQz5zr6NSYsxA'))
).toEqual([true, 34, 2, 69]);
});
it('correctly extracts the info from a 2-byte-prefix address (252)', (): void => {
expect(
checkAddressChecksum(base58Decode('xw8Ffc2SZtDqUJKd9Ky4vc7PRz2D2asuVkEEzf3WGAbw9cnfq'))
).toEqual([true, 34, 2, 252]);
});
it('correctly extracts the info from a 2-byte-prefix address (255)', (): void => {
expect(
checkAddressChecksum(base58Decode('yGHU8YKprxHbHdEv7oUK4rzMZXtsdhcXVG2CAMyC9WhzhjH2k'))
).toEqual([true, 34, 2, 255]);
});
it('correctly extracts the info from a 2-byte-prefix address (ecdsa, from Substrate)', (): void => {
expect(
checkAddressChecksum(base58Decode('4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV'))
).toEqual([true, 35, 2, 200]);
});
});
@@ -0,0 +1,25 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { sshash } from './sshash.js';
export function checkAddressChecksum (decoded: Uint8Array): [boolean, number, number, number] {
const ss58Length = (decoded[0] & 0b0100_0000) ? 2 : 1;
const ss58Decoded = ss58Length === 1
? decoded[0]
: ((decoded[0] & 0b0011_1111) << 2) | (decoded[1] >> 6) | ((decoded[1] & 0b0011_1111) << 8);
// 32/33 bytes public + 2 bytes checksum + prefix
const isPublicKey = [34 + ss58Length, 35 + ss58Length].includes(decoded.length);
const length = decoded.length - (isPublicKey ? 2 : 1);
// calculate the hash and do the checksum byte checks
const hash = sshash(decoded.subarray(0, length));
const isValid = (decoded[0] & 0b1000_0000) === 0 && ![46, 47].includes(decoded[0]) && (
isPublicKey
? decoded[decoded.length - 2] === hash[0] && decoded[decoded.length - 1] === hash[1]
: decoded[decoded.length - 1] === hash[0]
);
return [isValid, length, ss58Length, ss58Decoded];
}
@@ -0,0 +1,138 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { hexToU8a, stringToU8a, u8aToHex } from '@pezkuwi/util';
import { ALICE_PUBLIC_SR } from './encode.spec.js';
import { decodeAddress } from './index.js';
describe('decodeAddress', (): void => {
it('decodes an address', (): void => {
expect(
decodeAddress('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
).toEqual(
ALICE_PUBLIC_SR
);
});
it('decodes the council address', (): void => {
expect(
u8aToHex(decodeAddress('F3opxRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29'))
).toEqual(u8aToHex(stringToU8a('modlpy/trsry'.padEnd(32, '\0'))));
});
it('converts a publicKey (u8a) as-is', (): void => {
expect(
decodeAddress(new Uint8Array([1, 2, 3]))
).toEqual(
new Uint8Array([1, 2, 3])
);
});
it('converts a publicKey (hex) as-is', (): void => {
expect(
decodeAddress('0x01020304')
).toEqual(
new Uint8Array([1, 2, 3, 4])
);
});
it('decodes a short address', (): void => {
expect(
decodeAddress('F7NZ')
).toEqual(new Uint8Array([1]));
});
it('decodes a 1-byte accountId (with prefix)', (): void => {
expect(
decodeAddress('g4b', false, 2)
).toEqual(new Uint8Array([1]));
});
it('decodes a 2-byte accountId', (): void => {
expect(
decodeAddress('3xygo', false, 2)
).toEqual(new Uint8Array([0, 1]));
});
it('encodes a 4-byte address', (): void => {
expect(
decodeAddress('zswfoZa', false, 2)
).toEqual(new Uint8Array([1, 2, 3, 4]));
});
it('decodes a 8-byte address', (): void => {
expect(
decodeAddress('848Gh2GcGaZia', false, 2)
).toEqual(new Uint8Array([42, 44, 10, 0, 0, 0, 0, 0]));
});
it('decodes a 33-byte address', (): void => {
expect(
decodeAddress('KWCv1L3QX9LDPwY4VzvLmarEmXjVJidUzZcinvVnmxAJJCBou')
).toEqual(
hexToU8a('0x03b9dc646dd71118e5f7fda681ad9eca36eb3ee96f344f582fbe7b5bcdebb13077')
);
});
it('decodes a 2-byte prefix (65)', (): void => {
expect(
decodeAddress('cLtA6nCDyvwKcEHH4QkZDSHMhS9s78BvUJUsKUbUAn1Jc2SCF')
).toEqual(
hexToU8a('0x08e8969768fc14399930d4b8d693f68a2ff6c6a597325d6946095e5e9d9d1b0e')
);
});
it('decodes a 2-byte prefix (69)', (): void => {
expect(
decodeAddress('cnUaoo5wodnTVA4bnr4woSweto8hWZADUvLFXkR9Q6U7BRsbF')
).toEqual(
hexToU8a('0x88eafe0305d460d1695cf34c2f786050df8e40d215e488790cc70929c9e8316d')
);
});
it('decodes a 2-byte prefix (252)', (): void => {
expect(
decodeAddress('xw9Hca4RJTmBRgzJT4ieJBh7XCK9gE3NXBDSEmgGHd4TCrbnG')
).toEqual(
hexToU8a('0xfc422da6c3bc6dfa2a436a506428072941662f816987baaa8914e02ff5947f4b')
);
});
it('decodes a 2-byte prefix (255)', (): void => {
expect(
decodeAddress('yGHU8YKprxHbHdEv7oUK4rzMZXtsdhcXVG2CAMyC9WhzhjH2k')
).toEqual(
decodeAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQua')
);
});
it('decodes a 2-byte prefix (ecdsa, from Substrate)', (): void => {
expect(
u8aToHex(decodeAddress('4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV'))
).toEqual('0x035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9');
});
it('fails when length is invalid', (): void => {
expect(
(): Uint8Array => decodeAddress('y9EMHt34JJo4rWLSaxoLGdYXvjgSXEd4zHUnQgfNzwES8b')
).toThrow(/address length/);
});
it('fails when the checksum does not match', (): void => {
expect(
(): Uint8Array => decodeAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMa9cj')
).toThrow(/address checksum/);
expect(
(): Uint8Array => decodeAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDwU')
).toThrow(/address checksum/);
});
it('fails when invalid base58 encoded address is found', (): void => {
expect(
() => u8aToHex(decodeAddress('F3opIRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29'))
).toThrow(/Decoding F3opIRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29: Invalid base58 character "I" \(0x49\) at index 4/);
});
});
@@ -0,0 +1,41 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
// Original implementation: https://github.com/paritytech/polka-ui/blob/4858c094684769080f5811f32b081dd7780b0880/src/polkadot.js#L6
import { isHex, isU8a, u8aToU8a } from '@pezkuwi/util';
import { base58Decode } from '../base58/index.js';
import { checkAddressChecksum } from './checksum.js';
import { defaults } from './defaults.js';
export function decodeAddress (encoded?: string | Uint8Array | null, ignoreChecksum?: boolean, ss58Format: Prefix = -1): Uint8Array {
if (!encoded) {
throw new Error('Invalid empty address passed');
}
if (isU8a(encoded) || isHex(encoded)) {
return u8aToU8a(encoded);
}
try {
const decoded = base58Decode(encoded);
if (!defaults.allowedEncodedLengths.includes(decoded.length)) {
throw new Error('Invalid decoded address length');
}
const [isValid, endPos, ss58Length, ss58Decoded] = checkAddressChecksum(decoded);
if (!isValid && !ignoreChecksum) {
throw new Error('Invalid decoded address checksum');
} else if (ss58Format !== -1 && ss58Format !== ss58Decoded) {
throw new Error(`Expected ss58Format ${ss58Format}, received ${ss58Decoded}`);
}
return decoded.slice(ss58Length, endPos);
} catch (error) {
throw new Error(`Decoding ${encoded}: ${(error as Error).message}`);
}
}
@@ -0,0 +1,12 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { availableNetworks } from '../networks.js';
export const defaults = {
allowedDecodedLengths: [1, 2, 4, 8, 32, 33],
// publicKey has prefix + 2 checksum bytes, short only prefix + 1 checksum byte
allowedEncodedLengths: [3, 4, 6, 10, 35, 36, 37, 38],
allowedPrefix: availableNetworks.map(({ prefix }) => prefix),
prefix: 42
};
@@ -0,0 +1,26 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { waitReady } from '@pezkuwi/wasm-crypto';
import { deriveAddress } from './index.js';
describe('deriveAddress', (): void => {
beforeEach(async (): Promise<void> => {
await waitReady();
});
it('derives a known path', (): void => {
expect(
deriveAddress('5CZtJLXtVzrBJq1fMWfywDa6XuRwXekGdShPR4b8i9GWSbzB', '/joe/polkadot/0')
).toEqual('5GZ4srnepXvdsuNVoxCGyVZd8ScDm4gkGLTKuaGARy9akjTa');
});
it('fails on hard paths', (): void => {
expect(
() => deriveAddress('5CZtJLXtVzrBJq1fMWfywDa6XuRwXekGdShPR4b8i9GWSbzB', '//bob')
).toThrow(/Expected suri to contain a combination of non-hard paths/);
});
});
@@ -0,0 +1,36 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { DeriveJunction } from '../key/DeriveJunction.js';
import type { Prefix } from './types.js';
import { keyExtractPath } from '../key/index.js';
import { sr25519DerivePublic } from '../sr25519/index.js';
import { decodeAddress } from './decode.js';
import { encodeAddress } from './encode.js';
function filterHard ({ isHard }: DeriveJunction): boolean {
return isHard;
}
/**
* @name deriveAddress
* @summary Creates a sr25519 derived address from the supplied and path.
* @description
* Creates a sr25519 derived address based on the input address/publicKey and the uri supplied.
*/
export function deriveAddress (who: string | Uint8Array, suri: string, ss58Format?: Prefix): string {
const { path } = keyExtractPath(suri);
if (!path.length || path.every(filterHard)) {
throw new Error('Expected suri to contain a combination of non-hard paths');
}
let publicKey = decodeAddress(who);
for (const { chainCode } of path) {
publicKey = sr25519DerivePublic(publicKey, chainCode);
}
return encodeAddress(publicKey, ss58Format);
}
@@ -0,0 +1,177 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { encodeAddress } from './index.js';
// eslint-disable-next-line jest/no-export
export const ALICE_PUBLIC_SR = new Uint8Array([212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]);
// eslint-disable-next-line jest/no-export
export const ALICE_PUBLIC_ED = new Uint8Array([209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79]);
const SUBKEY = [
{
// substrate default
address: '5DA4D4GL5iakrn22h5uKoevgvo18Pqj5BcdEUv8etEDPdijA',
publicKey: '0x3050f8456519829fe03302da802d22d3233a5f4037b9a3e2bcc403ccfcb2d735',
ss58Format: 42
},
{
// aventus
address: 'cLtA6nCDyvwKcEHH4QkZDSHMhS9s78BvUJUsKUbUAn1Jc2SCF',
publicKey: '0x08e8969768fc14399930d4b8d693f68a2ff6c6a597325d6946095e5e9d9d1b0e',
ss58Format: 65
},
{
// crust
address: 'cTGShekJ1L1UKFZR9xmv9UTJod7vqjFAPo4sDhXih2c3y1yLS',
publicKey: '0x04a047d52fe542484c69bc528990cfeaf3a663dded0638ee1b51cf78bacd1072',
ss58Format: 66
},
{
// sora
address: 'cnVRwXfAnz3RSVQyBUC8f8McrK3YBX2QYd4WoctpeSC6VTJYm',
publicKey: '0xae640d53cfa815f4a6a50ae70235cd7d9d134d0f1c3a4ccd118e321dfb6ab51f',
ss58Format: 69
},
{
// ecdsa
address: '4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV',
publicKey: '0x035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9',
ss58Format: 200
},
{
// social-network
address: 'xw5g1Eec8LT99pZLZMaTWwrwvNtfM6vrSuZeVbtEszCDUwByg',
publicKey: '0x5c64f1151f0ce4358c27238fb20c88e7c899825436f565410724c8c2c5add869',
ss58Format: 252
},
{
address: 'yGF4JP7q5AK46d1FPCEm9sYQ4KooSjHMpyVAjLnsCSWVafPnf',
publicKey: '0x66cd6cf085627d6c85af1aaf2bd10cf843033e929b4e3b1c2ba8e4aa46fe111b',
ss58Format: 255
},
{
address: 'yGDYxQatQwuxqT39Zs4LtcTnpzE12vXb7ZJ6xpdiHv6gTu1hF',
publicKey: '0x242fd5a078ac6b7c3c2531e9bcf1314343782aeb58e7bc6880794589e701db55',
ss58Format: 255
},
{
address: 'mHm8k9Emsvyfp3piCauSH684iA6NakctF8dySQcX94GDdrJrE',
publicKey: '0x44d5a3ac156335ea99d33a83c57c7146c40c8e2260a8a4adf4e7a86256454651',
ss58Format: 4242
},
{
address: 'r6Gr4gaMP8TsjhFbqvZhv3YvnasugLiRJpzpRHifsqqG18UXa',
publicKey: '0x88f01441682a17b52d6ae12d1a5670cf675fd254897efabaa5069eb3a701ab73',
ss58Format: 14269
}
];
describe('encode', (): void => {
it('encodes an address to a valid value', (): void => {
expect(
encodeAddress(ALICE_PUBLIC_ED)
).toEqual('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQua');
});
it('can re-encode an address', (): void => {
expect(
encodeAddress('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', 2)
).toEqual('HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F');
});
it('can re-encode an address to Polkadot live', (): void => {
expect(
encodeAddress('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', 0)
).toEqual('15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5');
});
it('fails when non-valid publicKey provided', (): void => {
expect(
(): string => encodeAddress(
ALICE_PUBLIC_ED.slice(0, 30)
)
).toThrow(/Expected a valid key/);
});
it('encodes a 1-byte address', (): void => {
expect(
encodeAddress(
new Uint8Array([1])
)
).toEqual('F7NZ');
});
it('encodes a 1-byte address (with prefix)', (): void => {
expect(
encodeAddress(
new Uint8Array([1]), 2
)
).toEqual('g4b');
});
it('encodes a 2-byte address', (): void => {
expect(
encodeAddress(
new Uint8Array([0, 1]), 2
)
).toEqual('3xygo');
});
it('encodes a 4-byte address', (): void => {
expect(
encodeAddress(
new Uint8Array([1, 2, 3, 4]), 2
)
).toEqual('zswfoZa');
});
it('encodes a 8-byte address', (): void => {
expect(
encodeAddress(
new Uint8Array([42, 44, 10, 0, 0, 0, 0, 0]), 2
)
).toEqual('848Gh2GcGaZia');
});
it('encodes an 33-byte address', (): void => {
expect(
encodeAddress('0x03b9dc646dd71118e5f7fda681ad9eca36eb3ee96f344f582fbe7b5bcdebb13077')
).toEqual('KWCv1L3QX9LDPwY4VzvLmarEmXjVJidUzZcinvVnmxAJJCBou');
});
it('encodes with 2 byte prefix', (): void => {
expect(
encodeAddress(ALICE_PUBLIC_ED, 255)
).toEqual('yGHU8YKprxHbHdEv7oUK4rzMZXtsdhcXVG2CAMyC9WhzhjH2k');
});
SUBKEY.forEach(({ address, publicKey, ss58Format }, index): void => {
it(`encodes with Subkey equality (${index} - ${ss58Format})`, (): void => {
expect(
encodeAddress(publicKey, ss58Format)
).toEqual(address);
});
});
it('does not encode for > 16,383, < 0', (): void => {
expect(
() => encodeAddress(ALICE_PUBLIC_ED, -1)
).toThrow(/range ss58Format specified/);
expect(
() => encodeAddress(ALICE_PUBLIC_ED, 16384)
).toThrow(/range ss58Format specified/);
});
it('does not encode reserved', (): void => {
expect(
() => encodeAddress(ALICE_PUBLIC_ED, 46)
).toThrow(/range ss58Format specified/);
expect(
() => encodeAddress(ALICE_PUBLIC_ED, 47)
).toThrow(/range ss58Format specified/);
});
});
@@ -0,0 +1,43 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
// Original implementation: https://github.com/paritytech/polka-ui/blob/4858c094684769080f5811f32b081dd7780b0880/src/polkadot.js#L34
import { u8aConcat } from '@pezkuwi/util';
import { base58Encode } from '../base58/index.js';
import { decodeAddress } from './decode.js';
import { defaults } from './defaults.js';
import { sshash } from './sshash.js';
export function encodeAddress (key: string | Uint8Array, ss58Format: Prefix = defaults.prefix): string {
// decode it, this means we can re-encode an address
const u8a = decodeAddress(key);
if ((ss58Format < 0) || (ss58Format > 16383 && !ss58Exceptions.includes(ss58Format)) || [46, 47].includes(ss58Format)) {
throw new Error('Out of range ss58Format specified');
} else if (!defaults.allowedDecodedLengths.includes(u8a.length)) {
throw new Error(`Expected a valid key to convert, with length ${defaults.allowedDecodedLengths.join(', ')}`);
}
const input = u8aConcat(
ss58Format < 64
? [ss58Format]
: [
((ss58Format & 0b0000_0000_1111_1100) >> 2) | 0b0100_0000,
(ss58Format >> 8) | ((ss58Format & 0b0000_0000_0000_0011) << 6)
],
u8a
);
return base58Encode(
u8aConcat(
input,
sshash(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1)
)
);
}
// Exceptions like 29972 (Mythos chain) which uses Ethereum style account (not ss58 Encoded)
const ss58Exceptions = [29972];
@@ -0,0 +1,14 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { encodeDerivedAddress } from './index.js';
describe('encodeDerivedAddress', (): void => {
it('creates a valid known derived address', (): void => {
expect(
encodeDerivedAddress('5GvUh7fGKsdBEh5XpypkfkGuf7j3vXLxH9BdxjxnJNVXRYi1', 0)
).toEqual('5E5XxqPxm7QbEs6twYfp3tyjXidn4kqRrNPH4o6JK9JSLUeD');
});
});
@@ -0,0 +1,19 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BN } from '@pezkuwi/util';
import type { Prefix } from './types.js';
import { decodeAddress } from './decode.js';
import { encodeAddress } from './encode.js';
import { createKeyDerived } from './keyDerived.js';
/**
* @name encodeDerivedAddress
* @summary Creates a derived address as used in Substrate utility.
* @description
* Creates a Substrate derived address based on the input address/publicKey and the index supplied.
*/
export function encodeDerivedAddress (who: string | Uint8Array, index: bigint | BN | number, ss58Format?: Prefix): string {
return encodeAddress(createKeyDerived(decodeAddress(who), index), ss58Format);
}
@@ -0,0 +1,18 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { encodeMultiAddress } from './index.js';
describe('encodeMultiAddress', (): void => {
it('creates a valid known multi address', (): void => {
expect(
encodeMultiAddress([
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
'5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
'5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y'
], 2)
).toEqual('5DjYJStmdZ2rcqXbXGX7TW85JsrW6uG4y9MUcLq2BoPMpRA7');
});
});
@@ -0,0 +1,18 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BN } from '@pezkuwi/util';
import type { Prefix } from './types.js';
import { encodeAddress } from './encode.js';
import { createKeyMulti } from './keyMulti.js';
/**
* @name encodeMultiAddress
* @summary Creates a multisig address.
* @description
* Creates a Substrate multisig address based on the input address and the required threshold.
*/
export function encodeMultiAddress (who: (string | Uint8Array)[], threshold: bigint | BN | number, ss58Format?: Prefix): string {
return encodeAddress(createKeyMulti(who, threshold), ss58Format);
}
@@ -0,0 +1,45 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { ALICE_PUBLIC_SR } from './encode.spec.js';
import { addressEq } from './index.js';
describe('addressEq', (): void => {
it('returns false with non-equal', (): void => {
expect(
addressEq(
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
'5EnxxUmEbw8DkENKiYuZ1DwQuMoB2UWEQJZZXrTsxoz7SpgG'
)
).toEqual(false);
});
it('returns true for equal, matching prefix', (): void => {
expect(
addressEq(
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
)
).toEqual(true);
});
it('returns true for equal, non-matching prefix', (): void => {
expect(
addressEq(
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
'15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5'
)
).toEqual(true);
});
it('returns true for equal, address vs publicKey', (): void => {
expect(
addressEq(
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
ALICE_PUBLIC_SR
)
).toEqual(true);
});
});
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { u8aEq } from '@pezkuwi/util';
import { decodeAddress } from './decode.js';
/**
* @name addressEq
* @summary Compares two addresses, either in ss58, Uint8Array or hex format.
* @description
* For the input values, return true is the underlying public keys do match.
* @example
* <BR>
*
* ```javascript
* import { u8aEq } from '@pezkuwi/util';
*
* u8aEq(new Uint8Array([0x68, 0x65]), new Uint8Array([0x68, 0x65])); // true
* ```
*/
export function addressEq (a: string | Uint8Array, b: string | Uint8Array): boolean {
return u8aEq(decodeAddress(a), decodeAddress(b));
}
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { evmToAddress } from './index.js';
describe('evmToAddress', (): void => {
it('creates a valid known SS58 address', (): void => {
expect(
evmToAddress('0xd43593c715fdd31c61141abd04a99fd6822c8558', 42, 'blake2')
).toEqual('5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngRLNectCn64UjtZ');
});
it('fails when length is invalid', (): void => {
expect(
() => evmToAddress('0x1234567890ABCDEF1234567890ABCDEF')
).toThrow(/address length/);
});
});
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { HashType } from '../secp256k1/types.js';
import type { Prefix } from './types.js';
import { u8aConcat } from '@pezkuwi/util';
import { hasher } from '../secp256k1/hasher.js';
import { encodeAddress } from './encode.js';
/**
* @name evmToAddress
* @summary Converts an EVM address to its corresponding SS58 address.
*/
export function evmToAddress (evmAddress: string | Uint8Array, ss58Format?: Prefix, hashType: HashType = 'blake2'): string {
const message = u8aConcat('evm:', evmAddress);
if (message.length !== 24) {
throw new Error(`Converting ${evmAddress as string}: Invalid evm address length`);
}
return encodeAddress(hasher(hashType, message), ss58Format);
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
export { addressToEvm } from './addressToEvm.js';
export { checkAddress } from './check.js';
export { checkAddressChecksum } from './checksum.js';
export { decodeAddress } from './decode.js';
export { deriveAddress } from './derive.js';
export { encodeAddress } from './encode.js';
export { encodeDerivedAddress } from './encodeDerived.js';
export { encodeMultiAddress } from './encodeMulti.js';
export { addressEq } from './eq.js';
export { evmToAddress } from './evmToAddress.js';
export { isAddress } from './is.js';
export { createKeyDerived } from './keyDerived.js';
export { createKeyMulti } from './keyMulti.js';
export { sortAddresses } from './sort.js';
export { validateAddress } from './validate.js';
// eslint-disable-next-line deprecation/deprecation
export { setSS58Format } from './setSS58Format.js';
+113
View File
@@ -0,0 +1,113 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { isAddress } from './index.js';
describe('isAddress', (): void => {
it('decodes an address', (): void => {
expect(
isAddress('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
).toEqual(true);
});
it('decodes the council address', (): void => {
expect(
isAddress('F3opxRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29')
).toEqual(true);
});
it('converts a publicKey (hex) as-is', (): void => {
expect(
isAddress('0x01020304')
).toEqual(true);
});
it('decodes a short address', (): void => {
expect(
isAddress('F7NZ')
).toEqual(true);
});
it('decodes a 1-byte accountId (with prefix)', (): void => {
expect(
isAddress('g4b', false, 2)
).toEqual(true);
});
it('decodes a 2-byte accountId', (): void => {
expect(
isAddress('3xygo', false, 2)
).toEqual(true);
});
it('encodes a 4-byte address', (): void => {
expect(
isAddress('zswfoZa', false, 2)
).toEqual(true);
});
it('decodes a 8-byte address', (): void => {
expect(
isAddress('848Gh2GcGaZia', false, 2)
).toEqual(true);
});
it('decodes a 33-byte address', (): void => {
expect(
isAddress('KWCv1L3QX9LDPwY4VzvLmarEmXjVJidUzZcinvVnmxAJJCBou')
).toEqual(true);
});
it('decodes a 2-byte prefix (65)', (): void => {
expect(
isAddress('cLtA6nCDyvwKcEHH4QkZDSHMhS9s78BvUJUsKUbUAn1Jc2SCF')
).toEqual(true);
});
it('decodes a 2-byte prefix (69)', (): void => {
expect(
isAddress('cnUaoo5wodnTVA4bnr4woSweto8hWZADUvLFXkR9Q6U7BRsbF')
).toEqual(true);
});
it('decodes a 2-byte prefix (252)', (): void => {
expect(
isAddress('xw9Hca4RJTmBRgzJT4ieJBh7XCK9gE3NXBDSEmgGHd4TCrbnG')
).toEqual(true);
});
it('decodes a 2-byte prefix (255)', (): void => {
expect(
isAddress('yGHU8YKprxHbHdEv7oUK4rzMZXtsdhcXVG2CAMyC9WhzhjH2k')
).toEqual(true);
});
it('decodes a 2-byte prefix (ecdsa, from Substrate)', (): void => {
expect(
isAddress('4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV')
).toEqual(true);
});
it('fails when length is invalid', (): void => {
expect(
isAddress('y9EMHt34JJo4rWLSaxoLGdYXvjgSXEd4zHUnQgfNzwES8b')
).toEqual(false);
});
it('fails when the checksum does not match', (): void => {
expect(
isAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMa9cj')
).toEqual(false);
expect(
isAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDwU')
).toEqual(false);
});
it('fails when invalid base58 encoded address is found', (): void => {
expect(
isAddress('F3opIRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29')
).toEqual(false);
});
});
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
import { validateAddress } from './validate.js';
export function isAddress (address?: string | null, ignoreChecksum?: boolean, ss58Format?: Prefix): address is string {
try {
return validateAddress(address, ignoreChecksum, ss58Format);
} catch {
return false;
}
}
@@ -0,0 +1,24 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { createKeyDerived } from './index.js';
describe('createKeyDerived', (): void => {
it('matches sub accounts with Rust', (): void => {
expect(
createKeyDerived(new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0]), 0)
).toEqual(
new Uint8Array([234, 236, 28, 96, 177, 168, 152, 193, 71, 179, 226, 102, 179, 155, 188, 240, 90, 182, 21, 175, 47, 47, 250, 179, 178, 0, 81, 222, 70, 56, 52, 234])
);
});
it('creates a valid subkey', (): void => {
expect(
createKeyDerived('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', 1)
).toEqual(
new Uint8Array([248, 19, 86, 209, 254, 89, 84, 48, 54, 128, 166, 239, 153, 212, 143, 34, 191, 60, 210, 50, 39, 77, 122, 71, 29, 60, 247, 198, 95, 101, 246, 83])
);
});
});
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BN } from '@pezkuwi/util';
import { bnToU8a, stringToU8a, u8aConcat } from '@pezkuwi/util';
import { blake2AsU8a } from '../blake2/asU8a.js';
import { BN_LE_16_OPTS } from '../bn.js';
import { decodeAddress } from './decode.js';
const PREFIX = stringToU8a('modlpy/utilisuba');
export function createKeyDerived (who: string | Uint8Array, index: bigint | BN | number): Uint8Array {
return blake2AsU8a(
u8aConcat(
PREFIX,
decodeAddress(who),
bnToU8a(index, BN_LE_16_OPTS)
)
);
}
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { createKeyMulti } from './index.js';
describe('createKeyMulti', (): void => {
it('creates a valid multikey (aligning with Rust, needs sorting)', (): void => {
expect(
createKeyMulti([
new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0]),
new Uint8Array([3, 0, 0, 0, 0, 0, 0, 0]),
new Uint8Array([2, 0, 0, 0, 0, 0, 0, 0])
], 2)
).toEqual(
new Uint8Array([67, 151, 196, 155, 179, 207, 47, 123, 90, 2, 35, 54, 162, 111, 241, 226, 88, 148, 54, 193, 252, 195, 93, 101, 16, 5, 93, 101, 186, 186, 254, 79])
);
});
});
@@ -0,0 +1,23 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BN } from '@pezkuwi/util';
import { bnToU8a, compactToU8a, stringToU8a, u8aConcat, u8aSorted } from '@pezkuwi/util';
import { blake2AsU8a } from '../blake2/asU8a.js';
import { BN_LE_16_OPTS } from '../bn.js';
import { addressToU8a } from './util.js';
const PREFIX = stringToU8a('modlpy/utilisuba');
export function createKeyMulti (who: (string | Uint8Array)[], threshold: bigint | BN | number): Uint8Array {
return blake2AsU8a(
u8aConcat(
PREFIX,
compactToU8a(who.length),
...u8aSorted(who.map(addressToU8a)),
bnToU8a(threshold, BN_LE_16_OPTS)
)
);
}
@@ -0,0 +1,21 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { encodeAddress, setSS58Format } from './index.js';
describe('setSS58Format', (): void => {
beforeEach((): void => {
// eslint-disable-next-line deprecation/deprecation
setSS58Format(2);
});
it('sets and allows encoding using', (): void => {
expect(
encodeAddress(
new Uint8Array([1])
)
).toEqual('g4b');
});
});
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
import { logger } from '@pezkuwi/util';
import { defaults } from './defaults.js';
const l = logger('setSS58Format');
/**
* @description Sets the global SS58 format to use for address encoding
* @deprecated Use keyring.setSS58Format
*/
export function setSS58Format (prefix: Prefix): void {
l.warn('Global setting of the ss58Format is deprecated and not recommended. Set format on the keyring (if used) or as part of the address encode function');
defaults.prefix = prefix;
}
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { sortAddresses } from './index.js';
describe('sortAddresses', (): void => {
it('sorts addresses by the publicKeys', (): void => {
expect(
sortAddresses([
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
'5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
'5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y'
])
).toEqual([
'5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
'5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y',
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
]);
});
});
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
import { u8aSorted } from '@pezkuwi/util';
import { encodeAddress } from './encode.js';
import { addressToU8a } from './util.js';
export function sortAddresses (addresses: (string | Uint8Array)[], ss58Format?: Prefix): string[] {
const u8aToAddress = (u8a: Uint8Array) => encodeAddress(u8a, ss58Format);
return u8aSorted(
addresses.map(addressToU8a)
).map(u8aToAddress);
}
@@ -0,0 +1,12 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { stringToU8a, u8aConcat } from '@pezkuwi/util';
import { blake2AsU8a } from '../blake2/asU8a.js';
const SS58_PREFIX = stringToU8a('SS58PRE');
export function sshash (key: Uint8Array): Uint8Array {
return blake2AsU8a(u8aConcat(SS58_PREFIX, key), 512);
}
@@ -0,0 +1,6 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// FIXME we really want this to map with what is in the allowedSS58 array... i.e. the
// values there. As of now, we just map to number.
export type Prefix = number;
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { decodeAddress } from './decode.js';
export function addressToU8a (who: string | Uint8Array): Uint8Array {
return decodeAddress(who);
}
@@ -0,0 +1,113 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { validateAddress } from './index.js';
describe('validateAddress', (): void => {
it('decodes an address', (): void => {
expect(
validateAddress('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')
).toEqual(true);
});
it('decodes the council address', (): void => {
expect(
validateAddress('F3opxRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29')
).toEqual(true);
});
it('converts a publicKey (hex) as-is', (): void => {
expect(
validateAddress('0x01020304')
).toEqual(true);
});
it('decodes a short address', (): void => {
expect(
validateAddress('F7NZ')
).toEqual(true);
});
it('decodes a 1-byte accountId (with prefix)', (): void => {
expect(
validateAddress('g4b', false, 2)
).toEqual(true);
});
it('decodes a 2-byte accountId', (): void => {
expect(
validateAddress('3xygo', false, 2)
).toEqual(true);
});
it('encodes a 4-byte address', (): void => {
expect(
validateAddress('zswfoZa', false, 2)
).toEqual(true);
});
it('decodes a 8-byte address', (): void => {
expect(
validateAddress('848Gh2GcGaZia', false, 2)
).toEqual(true);
});
it('decodes a 33-byte address', (): void => {
expect(
validateAddress('KWCv1L3QX9LDPwY4VzvLmarEmXjVJidUzZcinvVnmxAJJCBou')
).toEqual(true);
});
it('decodes a 2-byte prefix (65)', (): void => {
expect(
validateAddress('cLtA6nCDyvwKcEHH4QkZDSHMhS9s78BvUJUsKUbUAn1Jc2SCF')
).toEqual(true);
});
it('decodes a 2-byte prefix (69)', (): void => {
expect(
validateAddress('cnUaoo5wodnTVA4bnr4woSweto8hWZADUvLFXkR9Q6U7BRsbF')
).toEqual(true);
});
it('decodes a 2-byte prefix (252)', (): void => {
expect(
validateAddress('xw9Hca4RJTmBRgzJT4ieJBh7XCK9gE3NXBDSEmgGHd4TCrbnG')
).toEqual(true);
});
it('decodes a 2-byte prefix (255)', (): void => {
expect(
validateAddress('yGHU8YKprxHbHdEv7oUK4rzMZXtsdhcXVG2CAMyC9WhzhjH2k')
).toEqual(true);
});
it('decodes a 2-byte prefix (ecdsa, from Substrate)', (): void => {
expect(
validateAddress('4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV')
).toEqual(true);
});
it('fails when length is invalid', (): void => {
expect(
() => validateAddress('y9EMHt34JJo4rWLSaxoLGdYXvjgSXEd4zHUnQgfNzwES8b')
).toThrow(/address length/);
});
it('fails when the checksum does not match', (): void => {
expect(
() => validateAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMa9cj')
).toThrow(/address checksum/);
expect(
() => validateAddress('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDwU')
).toThrow(/address checksum/);
});
it('fails when invalid base58 encoded address is found', (): void => {
expect(
() => validateAddress('F3opIRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29')
).toThrow(/Decoding F3opIRbN5ZbjJNU511Kj2TLuzFcDq9BGduA9TgiECafpg29: Invalid base58 character "I" \(0x49\) at index 4/);
});
});
@@ -0,0 +1,10 @@
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from './types.js';
import { decodeAddress } from './decode.js';
export function validateAddress (encoded?: string | null, ignoreChecksum?: boolean, ss58Format?: Prefix): encoded is string {
return !!decodeAddress(encoded, ignoreChecksum, ss58Format);
}