UNPKG

ecash-lib

Version:

Library for eCash transaction building

168 lines 5.58 kB
"use strict"; // Copyright (c) 2025 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. Object.defineProperty(exports, "__esModule", { value: true }); exports.parseAlp = void 0; const hex_js_1 = require("../io/hex.js"); const str_js_1 = require("../io/str.js"); const bytes_js_1 = require("../io/bytes.js"); const alp_js_1 = require("./alp.js"); const common_js_1 = require("./common.js"); /** * Parse the given ALP pushdata. eMPP allows multiple pushdata per OP_RETURN. * * For data that's clearly not ALP (i.e. doesn't start with LOKAD ID "SLP2"), * it will return `undefined`. * * For an unknown token type, it'll return AlpUnknown. * * For a known token type, it'll parse the remaining data, or throw an error if * the format is invalid or if there's an unknown tx type. * * This behavior mirrors that of Chronik for consistency. **/ function parseAlp(pushdata) { // Must have at least 4 bytes for the LOKAD ID if (pushdata.length < alp_js_1.ALP_LOKAD_ID.length) { return undefined; } const bytes = new bytes_js_1.Bytes(pushdata); // If the pushdata doesn't start with "SLP2" (ALP's LOKAD ID), return undefined const lokadId = (0, str_js_1.bytesToStr)(bytes.readBytes(alp_js_1.ALP_LOKAD_ID.length)); if (lokadId != (0, str_js_1.bytesToStr)(alp_js_1.ALP_LOKAD_ID)) { return undefined; } // Return UNKNOWN for unknown token types (only "STANDARD" known so far) const tokenType = readU8(bytes, 'tokenType'); if (tokenType != alp_js_1.ALP_STANDARD) { return { txType: 'UNKNOWN', tokenType, }; } // Parse tx type (GENESIS, MINT, SEND, BURN) const txType = (0, str_js_1.bytesToStr)(readVarBytes(bytes, 'txType')); // Handle tx type specific parsing switch (txType) { case common_js_1.GENESIS_STR: return readGenesis(bytes, tokenType); case common_js_1.MINT_STR: return readMint(bytes, tokenType); case common_js_1.SEND_STR: return readSend(bytes, tokenType); case common_js_1.BURN_STR: return readBurn(bytes, tokenType); default: throw new Error('Unknown txType'); } } exports.parseAlp = parseAlp; function readGenesis(bytes, tokenType) { const tokenTicker = (0, str_js_1.bytesToStr)(readVarBytes(bytes, 'tokenTicker')); const tokenName = (0, str_js_1.bytesToStr)(readVarBytes(bytes, 'tokenName')); const url = (0, str_js_1.bytesToStr)(readVarBytes(bytes, 'url')); const data = readVarBytes(bytes, 'data'); const authPubkey = readVarBytes(bytes, 'authPubkey'); const decimals = readU8(bytes, 'decimals'); const mintData = readMintData(bytes); ensureEnd(bytes, 'GENESIS'); return { txType: common_js_1.GENESIS_STR, tokenType, genesisInfo: { tokenTicker, tokenName, url, data: (0, hex_js_1.toHex)(data), authPubkey: (0, hex_js_1.toHex)(authPubkey), decimals, }, mintData, }; } function readMint(bytes, tokenType) { const tokenId = readTokenId(bytes); const mintData = readMintData(bytes); ensureEnd(bytes, 'MINT'); return { txType: common_js_1.MINT_STR, tokenType, tokenId, mintData, }; } function readSend(bytes, tokenType) { const tokenId = readTokenId(bytes); const sendAtomsArray = readAtomsArray(bytes, 'sendAtomsArray'); ensureEnd(bytes, 'SEND'); return { txType: common_js_1.SEND_STR, tokenType, tokenId, sendAtomsArray, }; } function readBurn(bytes, tokenType) { const tokenId = readTokenId(bytes); const burnAtoms = readU48(bytes, 'burnAtoms'); ensureEnd(bytes, 'BURN'); return { txType: common_js_1.BURN_STR, tokenType, tokenId, burnAtoms, }; } function readU8(bytes, name) { if (bytes.idx >= bytes.data.length) { throw new Error(`Missing ${name}`); } return bytes.readU8(); } function readU48(bytes, name) { if (bytes.idx >= bytes.data.length) { throw new Error(`Missing ${name}`); } return bytes.readU48(); } function readTokenId(bytes) { // Note: ALP token ID endianness is little-endian (like in prevOut) return (0, hex_js_1.toHexRev)(bytes.readBytes(common_js_1.TOKEN_ID_NUM_BYTES)); } function readSize(bytes, name) { const size = readU8(bytes, name); if (size > alp_js_1.ALP_MAX_SIZE) { throw new Error(`Size must be between 0 and ${alp_js_1.ALP_MAX_SIZE}`); } return size; } function readVarBytes(bytes, name) { const numBytes = readSize(bytes, name); return bytes.readBytes(numBytes); } function readAtomsArray(bytes, name) { const numAtoms = readSize(bytes, name); const atomsArray = []; for (let i = 0; i < numAtoms; ++i) { atomsArray.push(bytes.readU48()); } return atomsArray; } function readMintData(bytes) { const atomsArray = readAtomsArray(bytes, 'atomsArray'); const numBatons = readU8(bytes, 'numBatons'); if (numBatons > alp_js_1.ALP_MAX_SIZE) { throw new Error(`numBatons must be between 0 and ${alp_js_1.ALP_MAX_SIZE}`); } return { atomsArray, numBatons, }; } function ensureEnd(bytes, txType) { if (bytes.idx < bytes.data.length) { throw new Error(`Superfluous ${txType} bytes`); } } //# sourceMappingURL=alp.parse.js.map