UNPKG

ecash-lib

Version:

Library for eCash transaction building

202 lines 8.05 kB
"use strict"; // Copyright (c) 2024 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.slpAtoms = exports.slpBurn = exports.slpSend = exports.slpMintVault = exports.slpMint = exports.slpGenesis = exports.SLP_TOKEN_TYPE_NFT1_CHILD = exports.SLP_TOKEN_TYPE_NFT1_GROUP = exports.SLP_TOKEN_TYPE_MINT_VAULT = exports.SLP_TOKEN_TYPE_FUNGIBLE = exports.SLP_ATOMS_NUM_BYTES = exports.SLP_MAX_SEND_OUTPUTS = exports.SLP_MINT_VAULT_SCRIPTHASH_NUM_BYTES = exports.SLP_GENESIS_HASH_NUM_BYTES = exports.SLP_NFT1_GROUP = exports.SLP_NFT1_CHILD = exports.SLP_MINT_VAULT = exports.SLP_FUNGIBLE = exports.SLP_LOKAD_ID = exports.SLP_LOKAD_ID_STR = void 0; const hex_js_1 = require("../io/hex.js"); const str_js_1 = require("../io/str.js"); const op_js_1 = require("../op.js"); const opcode_js_1 = require("../opcode.js"); const script_js_1 = require("../script.js"); const common_js_1 = require("./common.js"); /** LOKAD ID for SLP */ exports.SLP_LOKAD_ID_STR = 'SLP\0'; /** LOKAD ID for SLP */ exports.SLP_LOKAD_ID = (0, str_js_1.strToBytes)(exports.SLP_LOKAD_ID_STR); /** SLP fungible token type number */ exports.SLP_FUNGIBLE = 1; /** SLP MINT Vault token type number */ exports.SLP_MINT_VAULT = 2; /** SLP NFT1 Child token type number */ exports.SLP_NFT1_CHILD = 0x41; /** SLP NFT1 Group token type number */ exports.SLP_NFT1_GROUP = 0x81; /** How many bytes the GENESIS `hash` field must have (or 0) */ exports.SLP_GENESIS_HASH_NUM_BYTES = 32; /** How many bytes the GENESIS `mintVaultScripthash` field must have */ exports.SLP_MINT_VAULT_SCRIPTHASH_NUM_BYTES = 20; /** How many outputs a SEND can specify at most */ exports.SLP_MAX_SEND_OUTPUTS = 19; /** How many bytes every atoms amount has */ exports.SLP_ATOMS_NUM_BYTES = 8; exports.SLP_TOKEN_TYPE_FUNGIBLE = { protocol: 'SLP', type: 'SLP_TOKEN_TYPE_FUNGIBLE', number: exports.SLP_FUNGIBLE, }; exports.SLP_TOKEN_TYPE_MINT_VAULT = { protocol: 'SLP', type: 'SLP_TOKEN_TYPE_MINT_VAULT', number: exports.SLP_MINT_VAULT, }; exports.SLP_TOKEN_TYPE_NFT1_GROUP = { protocol: 'SLP', type: 'SLP_TOKEN_TYPE_NFT1_GROUP', number: exports.SLP_NFT1_GROUP, }; exports.SLP_TOKEN_TYPE_NFT1_CHILD = { protocol: 'SLP', type: 'SLP_TOKEN_TYPE_NFT1_CHILD', number: exports.SLP_NFT1_CHILD, }; /** Build an SLP GENESIS OP_RETURN, creating a new SLP token */ function slpGenesis(tokenType, genesisInfo, initialQuantity, mintBatonOutIdx) { verifyTokenType(tokenType); const data = []; data.push(exports.SLP_LOKAD_ID); data.push(new Uint8Array([tokenType])); data.push(common_js_1.GENESIS); data.push((0, str_js_1.strToBytes)(genesisInfo.tokenTicker ?? '')); data.push((0, str_js_1.strToBytes)(genesisInfo.tokenName ?? '')); data.push((0, str_js_1.strToBytes)(genesisInfo.url ?? '')); data.push(genesisInfo.hash ? (0, hex_js_1.fromHex)(genesisInfo.hash) : new Uint8Array()); data.push(new Uint8Array([genesisInfo.decimals ?? 0])); if (tokenType == exports.SLP_MINT_VAULT) { if (genesisInfo.mintVaultScripthash === undefined) { throw new Error('Must set mintVaultScripthash for MINT VAULT'); } data.push((0, hex_js_1.fromHex)(genesisInfo.mintVaultScripthash)); } else { if (mintBatonOutIdx !== undefined) { if (mintBatonOutIdx < 2) { throw new Error('mintBatonOutIdx must be >= 2'); } data.push(new Uint8Array([mintBatonOutIdx])); } else { data.push(new Uint8Array()); } } data.push(slpAtoms(initialQuantity)); return script_js_1.Script.fromOps([opcode_js_1.OP_RETURN].concat(data.map(pushdataOpSlp))); } exports.slpGenesis = slpGenesis; /** * Build an SLP MINT pushdata section, creating new SLP tokens and mint batons * of the given token ID. **/ function slpMint(tokenId, tokenType, additionalAtoms, mintBatonOutIdx) { verifyTokenType(tokenType); verifyTokenId(tokenId); return script_js_1.Script.fromOps([ opcode_js_1.OP_RETURN, pushdataOpSlp(exports.SLP_LOKAD_ID), pushdataOpSlp(new Uint8Array([tokenType])), pushdataOpSlp(common_js_1.MINT), pushdataOpSlp((0, hex_js_1.fromHex)(tokenId)), pushdataOpSlp(new Uint8Array(mintBatonOutIdx !== undefined ? [mintBatonOutIdx] : [])), pushdataOpSlp(slpAtoms(additionalAtoms)), ]); } exports.slpMint = slpMint; /** * Build an SLP MINT VAULT pushdata section, creating new SLP tokens and mint batons * of the given token ID. **/ function slpMintVault(tokenId, additionalAtomsArray) { verifyTokenId(tokenId); verifySendAtomsArray(additionalAtomsArray); return script_js_1.Script.fromOps([ opcode_js_1.OP_RETURN, pushdataOpSlp(exports.SLP_LOKAD_ID), pushdataOpSlp(new Uint8Array([exports.SLP_MINT_VAULT])), pushdataOpSlp(common_js_1.MINT), pushdataOpSlp((0, hex_js_1.fromHex)(tokenId)), ].concat(additionalAtomsArray.map(atoms => pushdataOpSlp(slpAtoms(atoms))))); } exports.slpMintVault = slpMintVault; /** * Build an SLP SEND pushdata section, moving SLP tokens to different outputs **/ function slpSend(tokenId, tokenType, sendAtomsArray) { verifyTokenType(tokenType); verifyTokenId(tokenId); verifySendAtomsArray(sendAtomsArray); return script_js_1.Script.fromOps([ opcode_js_1.OP_RETURN, pushdataOpSlp(exports.SLP_LOKAD_ID), pushdataOpSlp(new Uint8Array([tokenType])), pushdataOpSlp(common_js_1.SEND), pushdataOpSlp((0, hex_js_1.fromHex)(tokenId)), ].concat(sendAtomsArray.map(atoms => pushdataOpSlp(slpAtoms(atoms))))); } exports.slpSend = slpSend; /** * Build an SLP BURN pushdata section, intentionally burning SLP tokens. * See https://github.com/badger-cash/slp-self-mint-protocol/blob/master/token-type1-burn.md **/ function slpBurn(tokenId, tokenType, burnAtoms) { verifyTokenType(tokenType); verifyTokenId(tokenId); return script_js_1.Script.fromOps([ opcode_js_1.OP_RETURN, pushdataOpSlp(exports.SLP_LOKAD_ID), pushdataOpSlp(new Uint8Array([tokenType])), pushdataOpSlp(common_js_1.BURN), pushdataOpSlp((0, hex_js_1.fromHex)(tokenId)), pushdataOpSlp(slpAtoms(burnAtoms)), ]); } exports.slpBurn = slpBurn; function verifyTokenType(tokenType) { switch (tokenType) { case exports.SLP_FUNGIBLE: case exports.SLP_MINT_VAULT: case exports.SLP_NFT1_GROUP: case exports.SLP_NFT1_CHILD: return; default: throw new Error(`Unknown token type ${tokenType}`); } } function verifyTokenId(tokenId) { if (tokenId.length != 64) { throw new Error(`Token ID must be 64 hex characters in length, but got ${tokenId.length}`); } } function verifySendAtomsArray(sendAtomsArray) { if (sendAtomsArray.length == 0) { throw new Error('sendAtomsArray cannot be empty'); } if (sendAtomsArray.length > 19) { throw new Error(`Cannot use more than 19 amounts, but got ${sendAtomsArray.length}`); } } function pushdataOpSlp(pushdata) { if (pushdata.length == 0) { return { opcode: opcode_js_1.OP_PUSHDATA1, data: pushdata, }; } if (pushdata.length < opcode_js_1.OP_PUSHDATA1) { return { opcode: pushdata.length, data: pushdata, }; } return (0, op_js_1.pushBytesOp)(pushdata); } function slpAtoms(atoms) { if (atoms < 0n || atoms > 0xffffffffffffffffn) { throw new Error(`Atoms out of range: ${atoms}`); } const atomsBytes = new Uint8Array(8); const view = new DataView(atomsBytes.buffer, atomsBytes.byteOffset, atomsBytes.byteLength); view.setBigUint64(0, atoms, /*little endian=*/ false); return atomsBytes; } exports.slpAtoms = slpAtoms; //# sourceMappingURL=slp.js.map