@ecash/lib
Version:
Library for eCash transaction building
172 lines • 6.73 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.slpAmount = exports.slpBurn = exports.slpSend = exports.slpMintVault = exports.slpMint = exports.slpGenesis = exports.SLP_NFT1_GROUP = exports.SLP_NFT1_CHILD = exports.SLP_MINT_VAULT = exports.SLP_FUNGIBLE = exports.SLP_LOKAD_ID = 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 = (0, str_js_1.strToBytes)('SLP\0');
/** 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;
/** 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(slpAmount(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, additionalQuantity, 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(slpAmount(additionalQuantity)),
]);
}
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, additionalQuantities) {
verifyTokenId(tokenId);
verifySendAmounts(additionalQuantities);
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(additionalQuantities.map(qty => pushdataOpSlp(slpAmount(qty)))));
}
exports.slpMintVault = slpMintVault;
/**
* Build an SLP SEND pushdata section, moving SLP tokens to different outputs
**/
function slpSend(tokenId, tokenType, sendAmounts) {
verifyTokenType(tokenType);
verifyTokenId(tokenId);
verifySendAmounts(sendAmounts);
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(sendAmounts.map(qty => pushdataOpSlp(slpAmount(qty)))));
}
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, burnAmount) {
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(slpAmount(burnAmount)),
]);
}
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 verifySendAmounts(sendAmounts) {
if (sendAmounts.length == 0) {
throw new Error('Send amount cannot be empty');
}
if (sendAmounts.length > 19) {
throw new Error(`Cannot use more than 19 amounts, but got ${sendAmounts.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 slpAmount(amount) {
if (amount < 0 || BigInt(amount) > 0xffffffffffffffffn) {
throw new Error(`Amount out of range: ${amount}`);
}
const amountBytes = new Uint8Array(8);
const view = new DataView(amountBytes.buffer, amountBytes.byteOffset, amountBytes.byteLength);
view.setBigUint64(0, BigInt(amount), /*little endian=*/ false);
return amountBytes;
}
exports.slpAmount = slpAmount;
//# sourceMappingURL=slp.js.map