multichain-address-validator
Version:
Multichain address validator for Bitcoin and other blockchains.
90 lines (89 loc) • 2.73 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const types_js_1 = require("../types.js");
const bitcoin_validator_js_1 = __importDefault(require("./bitcoin_validator.js"));
const helpers_js_1 = require("../helpers.js");
const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
const GENERATOR = [
0x98f2bc8e61n, 0x79b76d99e2n, 0xf33e5fb3c4n, 0xae2eabe2a8n, 0x1e4f43e470n
];
function cashAddrPolymod(values) {
let chk = 1n;
for (let i = 0; i < values.length; i++) {
const top = chk >> 35n;
chk = ((chk & 0x07ffffffffn) << 5n) ^ BigInt(values[i]);
for (let j = 0n; j < 5n; j++) {
if ((top >> j) & 1n) {
chk ^= GENERATOR[Number(j)];
}
}
}
return chk ^ 1n;
}
function prefixExpand(prefix) {
const ret = [];
for (let i = 0; i < prefix.length; i++) {
ret.push(prefix.charCodeAt(i) & 31);
}
ret.push(0);
return ret;
}
function verifyCashAddrChecksum(prefix, payload) {
const expanded = prefixExpand(prefix).concat(payload);
return cashAddrPolymod(expanded) === 0n;
}
function validateCashAddr(address, opts) {
let raw_address;
const prefix = opts.networkType === types_js_1.NetworkType.MainNet
? 'bitcoincash'
: 'bchtest';
const res = address.split(':');
if (res.length === 1) {
raw_address = address;
}
else {
if (res[0] !== prefix) {
return false;
}
raw_address = res[1];
}
const regexp = new RegExp(opts.regexp);
if (!regexp.test(raw_address)) {
return false;
}
if (raw_address.toLowerCase() !== raw_address && raw_address.toUpperCase() !== raw_address) {
return false;
}
raw_address = raw_address.toLowerCase();
// Decode characters using the bech32/CashAddr charset
const data = [];
for (const c of raw_address) {
const d = CHARSET.indexOf(c);
if (d === -1) {
return false;
}
data.push(d);
}
try {
if (!verifyCashAddrChecksum(prefix, data)) {
return false;
}
}
catch {
return false;
}
return true;
}
const DefaultBCHValidatorOpts = {
regexp: /^[qQpP][0-9a-zA-Z]{41}$/,
};
exports.default = (opts) => ({
isValidAddress: function (address) {
const addr = (0, helpers_js_1.getAddress)(address);
const _opts = { ...DefaultBCHValidatorOpts, ...opts };
return validateCashAddr(addr, _opts) || (0, bitcoin_validator_js_1.default)(opts).isValidAddress(address);
}
});