UNPKG

@vbyte/btc-dev

Version:

Batteries-included toolset for plebian bitcoin development

80 lines (79 loc) 2.99 kB
import { Buff } from '@vbyte/buff'; import { Assert, B58chk, Bech32, Bech32m } from '@vbyte/micro-lib'; const ENCODING_REGEX = { base58: /^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,34}$/, bech32: /^(bc|tb|bcrt)1q[ac-hj-np-z02-9]{6,87}$/, bech32m: /^(bc|tb|bcrt)1p[ac-hj-np-z02-9]{6,87}$/ }; const VERSION = { bech32: 0, bech32m: 1 }; export function decode_address(address) { const format = get_address_format(address); if (format === null) throw new Error('unrecognized address format: ' + format); if (format === 'base58') return base58_decode(address); if (format === 'bech32') return bech32_decode(address); if (format === 'bech32m') return bech32m_decode(address); throw new Error('unable to find a matching address configuration'); } export function encode_address(config) { if (config.format === 'base58') return base58_encode(config); if (config.format === 'bech32') return bech32_encode(config); if (config.format === 'bech32m') return bech32m_encode(config); throw new Error('unrecognized encoding format: ' + config.format); } function get_address_format(address) { for (const [format, regex] of Object.entries(ENCODING_REGEX)) { if (regex.test(address)) return format; } return null; } function base58_encode(config) { Assert.ok(config.format === 'base58', 'encoding mismatch'); Assert.exists(config.version, 'must specify a version'); const bytes = Buff.join([config.version, config.data]); return B58chk.encode(bytes); } function base58_decode(encoded) { const bytes = B58chk.decode(encoded); const data = bytes.slice(1); const version = bytes[0]; return { data, format: 'base58', version }; } function bech32_encode(config) { Assert.ok(config.format === 'bech32', 'encoding mismatch'); Assert.exists(config.prefix, 'prefix is required'); const bytes = Buff.bytes(config.data); const words = Bech32.to_words(bytes); return Bech32.encode(config.prefix, [VERSION.bech32, ...words]); } function bech32_decode(encoded) { const { prefix, words } = Bech32.decode(encoded); const [version, ...rest] = words; Assert.ok(version === VERSION.bech32, 'bech32 version mismatch'); const data = Bech32.to_bytes(rest); return { data, format: 'bech32', prefix, version }; } function bech32m_encode(config) { Assert.ok(config.format === 'bech32m', 'encoding mismatch'); Assert.exists(config.prefix, 'prefix is required'); const bytes = Buff.bytes(config.data); const words = Bech32m.to_words(bytes); return Bech32m.encode(config.prefix, [VERSION.bech32m, ...words]); } function bech32m_decode(encoded) { const { prefix, words } = Bech32m.decode(encoded); const [version, ...rest] = words; Assert.ok(version === VERSION.bech32m, 'bech32m version mismatch'); const data = Bech32m.to_bytes(rest); return { data, format: 'bech32m', prefix, version }; }