ecash-lib
Version:
Library for eCash transaction building
187 lines • 7.53 kB
JavaScript
;
// 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_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,
};
/** 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