UNPKG

@bigmi/core

Version:

TypeScript library for Bitcoin apps.

120 lines 3.32 kB
import { sha256 } from '@noble/hashes/sha256'; import { bech32, bech32m } from 'bech32'; import bs58 from 'bs58'; import { AddressType, Network, } from '../types/address.js'; const addressTypes = { 0: { type: AddressType.p2pkh, network: Network.Mainnet, }, 111: { type: AddressType.p2pkh, network: Network.Testnet, }, 5: { type: AddressType.p2sh, network: Network.Mainnet, }, 196: { type: AddressType.p2sh, network: Network.Testnet, }, }; const parseBech32 = (address) => { let decoded; try { if (address.startsWith('bc1p') || address.startsWith('tb1p') || address.startsWith('bcrt1p')) { decoded = bech32m.decode(address); } else { decoded = bech32.decode(address); } } catch (_error) { throw new Error('Invalid address'); } const mapPrefixToNetwork = { bc: Network.Mainnet, tb: Network.Testnet, bcrt: Network.Regtest, }; const network = mapPrefixToNetwork[decoded.prefix]; if (network === undefined) { throw new Error('Invalid address'); } const witnessVersion = decoded.words[0]; if (witnessVersion < 0 || witnessVersion > 16) { throw new Error('Invalid address'); } const data = bech32.fromWords(decoded.words.slice(1)); let type; if (data.length === 20) { type = AddressType.p2wpkh; } else if (witnessVersion === 1) { type = AddressType.p2tr; } else { type = AddressType.p2wsh; } const purpose = getAddressPurpose(type); return { bech32: true, network, address, type, purpose, }; }; export const getAddressInfo = (address) => { let decoded; const prefix = address.substring(0, 2).toLowerCase(); if (prefix === 'bc' || prefix === 'tb') { return parseBech32(address); } try { decoded = bs58.decode(address); } catch (_error) { throw new Error('Invalid address'); } const { length } = decoded; if (length !== 25) { throw new Error('Invalid address'); } const version = decoded[0]; const checksum = decoded.slice(length - 4, length); const body = decoded.slice(0, length - 4); const expectedChecksum = sha256(sha256(body)).slice(0, 4); if (checksum.some((value, index) => value !== expectedChecksum[index])) { throw new Error('Invalid address'); } const validVersions = Object.keys(addressTypes).map(Number); if (!validVersions.includes(version)) { throw new Error('Invalid address'); } const addressType = addressTypes[version]; return { ...addressType, address, bech32: false, purpose: getAddressPurpose(addressType.type), }; }; const getAddressPurpose = (type) => { switch (type) { case AddressType.p2tr: return 'ordinals'; case AddressType.p2wsh: return 'stacks'; case AddressType.p2wpkh: case AddressType.p2sh: case AddressType.p2pkh: return 'payment'; default: throw new Error('Invalid address type'); } }; //# sourceMappingURL=getAddressInfo.js.map