@temple-wallet/wallet-address-validator
Version:
Wallet address validator for Bitcoin and other Altcoins.
207 lines (169 loc) • 4.92 kB
JavaScript
const bs58check = require('bs58check');
const Prefix = {
TZ1: 'tz1',
TZ2: 'tz2',
TZ3: 'tz3',
TZ4: 'tz4',
KT: 'KT',
KT1: 'KT1',
EDSK2: 'edsk2',
SPSK: 'spsk',
P2SK: 'p2sk',
EDPK: 'edpk',
SPPK: 'sppk',
P2PK: 'p2pk',
BLPK: 'BLpk',
EDESK: 'edesk',
SPESK: 'spesk',
P2ESK: 'p2esk',
EDSK: 'edsk',
EDSIG: 'edsig',
SPSIG: 'spsig',
P2SIG: 'p2sig',
SIG: 'sig',
NET: 'Net',
NCE: 'nce',
B: 'B',
O: 'o',
LO: 'Lo',
LLO: 'LLo',
P: 'P',
CO: 'Co',
ID: 'id',
EXPR: 'expr',
TZ: 'TZ',
VH: 'vh', // block_payload_hash
SASK: 'sask', // sapling_spending_key
ZET1: 'zet1', // sapling_address
//rollups
TXR1: 'txr1',
TXI: 'txi',
TXM: 'txm',
TXC: 'txc',
TXMR: 'txmr',
TXRL: 'txM',
TXW: 'txw',
SR1: 'sr1',
SRC1: 'src1'
};
const prefix = {
[]: new Uint8Array([6, 161, 159]),
[]: new Uint8Array([6, 161, 161]),
[]: new Uint8Array([6, 161, 164]),
[]: new Uint8Array([6, 161, 166]),
[]: new Uint8Array([2, 90, 121]),
[]: new Uint8Array([2, 90, 121]),
[]: new Uint8Array([43, 246, 78, 7]),
[]: new Uint8Array([13, 15, 58, 7]),
[]: new Uint8Array([17, 162, 224, 201]),
[]: new Uint8Array([16, 81, 238, 189]),
[]: new Uint8Array([13, 15, 37, 217]),
[]: new Uint8Array([3, 254, 226, 86]),
[]: new Uint8Array([3, 178, 139, 127]),
[]: new Uint8Array([6, 149, 135, 204]),
[]: new Uint8Array([7, 90, 60, 179, 41]),
[]: new Uint8Array([0x09, 0xed, 0xf1, 0xae, 0x96]),
[]: new Uint8Array([0x09, 0x30, 0x39, 0x73, 0xab]),
[]: new Uint8Array([9, 245, 205, 134, 18]),
[]: new Uint8Array([13, 115, 101, 19, 63]),
[]: new Uint8Array([54, 240, 44, 52]),
[]: new Uint8Array([4, 130, 43]),
[]: new Uint8Array([87, 82, 0]),
[]: new Uint8Array([69, 220, 169]),
[]: new Uint8Array([1, 52]),
[]: new Uint8Array([5, 116]),
[]: new Uint8Array([133, 233]),
[]: new Uint8Array([29, 159, 109]),
[]: new Uint8Array([2, 170]),
[]: new Uint8Array([79, 179]),
[]: new Uint8Array([153, 103]),
[]: new Uint8Array([13, 44, 64, 27]),
// Legacy prefix
[]: new Uint8Array([2, 90, 121]),
[]: new Uint8Array([1, 106, 242]),
[]: new Uint8Array([11, 237, 20, 92]),
[]: new Uint8Array([18, 71, 40, 223]),
[]: new Uint8Array([1, 128, 120, 31]),
[]: new Uint8Array([79, 148, 196]),
[]: new Uint8Array([79, 149, 30]),
[]: new Uint8Array([79, 148, 17]),
[]: new Uint8Array([18, 7, 206, 87]),
[]: new Uint8Array([79, 146, 82]),
[]: new Uint8Array([79, 150, 72]),
[]: new Uint8Array([6, 124, 117]),
[]: new Uint8Array([17, 165, 134, 138]),
};
const prefixLength = {
[]: 20,
[]: 20,
[]: 20,
[]: 20,
[]: 20,
[]: 20,
[]: 32,
[]: 33,
[]: 33,
//working with value in comment for base58.ml line 445 but not consistent with the three above
[]: 48,
[]: 64,
[]: 64,
[]: 64,
[]: 64,
[]: 4,
[]: 32,
[]: 32,
[]: 32,
[]: 32,
[]: 169,
[]: 43,
[]: 20,
[]: 32,
[]: 32,
[]: 32,
[]: 32,
[]: 32,
[]: 32,
[]: 20,
[]: 32,
};
function isValidPrefix(value) {
if (typeof value !== 'string') {
return false;
}
return value in prefix;
}
function validatePrefixedValue(value, prefixes) {
const match = new RegExp(`^(${prefixes.join('|')})`).exec(value);
if (!match || match.length === 0) {
return false;
}
const prefixKey = match[0];
if (!isValidPrefix(prefixKey)) {
return false;
}
// Check whether annotation exist before starting validation
if (value.includes('%')) {
value = value.split('%')[0];
}
const kt1Regex = /^(KT1\w{33})$/;
if (!kt1Regex.test(value) && prefixKey === 'KT1') {
return false;
}
let decoded = bs58check.decodeUnsafe(value);
if (!decoded) {
return false;
}
decoded = decoded.slice(prefix[prefixKey].length);
if (decoded.length !== prefixLength[prefixKey]) {
return false;
}
return true;
}
const implicitPrefix = ['tz1', 'tz2', 'tz3', 'tz4'];
const contractPrefix = ['KT1', 'txr1'];
const smartRollupPrefix = ['sr1'];
module.exports = {
isValidAddress: function (address) {
return validatePrefixedValue(address, [...implicitPrefix, ...contractPrefix, ...smartRollupPrefix]);
}
};