nerve-sdk-js
Version:
nerve nerve-js nerve-sdk nerve-js-sdk
759 lines (611 loc) • 40 kB
JavaScript
"use strict";
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = {
enumerable: true,
get: function get() {
return m[k];
}
};
}
Object.defineProperty(o, k2, desc);
} : function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
});
var __setModuleDefault = void 0 && (void 0).__setModuleDefault || (Object.create ? function (o, v) {
Object.defineProperty(o, "default", {
enumerable: true,
value: v
});
} : function (o, v) {
o["default"] = v;
});
var __importStar = void 0 && (void 0).__importStar || function () {
var _ownKeys = function ownKeys(o) {
_ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) {
if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
}
return ar;
};
return _ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = _ownKeys(mod), i = 0; i < k.length; i++) {
if (k[i] !== "default") __createBinding(result, mod, k[i]);
}
__setModuleDefault(result, mod);
return result;
};
}();
Object.defineProperty(exports, "__esModule", {
value: true
});
var tbc = __importStar(require("tbc-lib-js"));
var ftunlock_1 = require("../util/ftunlock");
/**
* Class representing a Fungible Token (FT) with methods for minting and transferring.
*/
class FT {
/**
* Constructs the FT instance either from a transaction ID or parameters.
* @param txidOrParams - Either a contract transaction ID or token parameters.
*/
constructor(txidOrParams) {
_defineProperty(this, "name", void 0);
_defineProperty(this, "symbol", void 0);
_defineProperty(this, "decimal", void 0);
_defineProperty(this, "totalSupply", void 0);
_defineProperty(this, "codeScript", void 0);
_defineProperty(this, "tapeScript", void 0);
_defineProperty(this, "contractTxid", void 0);
this.name = '';
this.symbol = '';
this.decimal = 0;
this.totalSupply = 0;
this.codeScript = '';
this.tapeScript = '';
this.contractTxid = '';
if (typeof txidOrParams === 'string') {
// Initialize from an existing contract transaction ID
this.contractTxid = txidOrParams;
} else if (txidOrParams) {
// Initialize with new token parameters
var {
name,
symbol,
amount,
decimal
} = txidOrParams;
if (amount <= 0) {
throw new Error('Amount must be a natural number');
} // Validate the decimal value
if (!Number.isInteger(decimal) || decimal <= 0) {
throw new Error('Decimal must be a positive integer');
} else if (decimal > 18) {
throw new Error('The maximum value for decimal cannot exceed 18');
} // Calculate the maximum allowable amount based on the decimal
var maxAmount = Math.floor(18 * Math.pow(10, 18 - decimal));
if (amount > maxAmount) {
throw new Error("When decimal is ".concat(decimal, ", the maximum amount cannot exceed ").concat(maxAmount));
}
this.name = name;
this.symbol = symbol;
this.decimal = decimal;
this.totalSupply = amount;
} else {
throw new Error('Invalid constructor arguments');
}
}
/**
* Initializes the FT instance by fetching the FTINFO.
*/
initialize(ftInfo) {
this.name = ftInfo.name;
this.symbol = ftInfo.symbol;
this.decimal = ftInfo.decimal;
this.totalSupply = ftInfo.totalSupply;
this.codeScript = ftInfo.codeScript;
this.tapeScript = ftInfo.tapeScript;
}
/**
* Mints a new FT and returns the raw transaction hex.
* @param privateKey_from - The private key of the sender.
* @param address_to - The recipient's address.
* @returns The raw transaction hex string.
*/
MintFT(privateKey_from, address_to, utxo) {
var privateKey = privateKey_from;
var address_from = privateKey.toAddress().toString();
var name = this.name;
var symbol = this.symbol;
var decimal = this.decimal;
var totalSupply = BigInt(Math.floor(this.totalSupply * Math.pow(10, decimal))); // Prepare the amount in BN format and write it into a buffer
var amountbn = new tbc.crypto.BN(totalSupply.toString());
var amountwriter = new tbc.encoding.BufferWriter();
amountwriter.writeUInt64LEBN(amountbn);
for (var i = 1; i < 6; i++) {
amountwriter.writeUInt64LEBN(new tbc.crypto.BN(0));
}
var tapeAmount = amountwriter.toBuffer().toString('hex'); // Convert name, symbol, and decimal to hex
var nameHex = Buffer.from(name, 'utf8').toString('hex');
var symbolHex = Buffer.from(symbol, 'utf8').toString('hex');
var decimalHex = decimal.toString(16).padStart(2, '0'); // Build the tape script
var tapeScript = tbc.Script.fromASM("OP_FALSE OP_RETURN ".concat(tapeAmount, " ").concat(decimalHex, " ").concat(nameHex, " ").concat(symbolHex, " 4654617065")); //console.log('tape:', tape.toBuffer().toString('hex'));
var tapeSize = tapeScript.toBuffer().length;
var publicKeyHash = tbc.Address.fromPrivateKey(privateKey).hashBuffer.toString('hex');
var flagHex = Buffer.from('for ft mint', 'utf8').toString('hex');
var txSource = new tbc.Transaction() //Build transcation
.from(utxo).addOutput(new tbc.Transaction.Output({
script: tbc.Script.fromASM("OP_DUP OP_HASH160 ".concat(publicKeyHash, " OP_EQUALVERIFY OP_CHECKSIG OP_RETURN ").concat(flagHex)),
satoshis: 9900
})).addOutput(new tbc.Transaction.Output({
script: tapeScript,
satoshis: 0
})).change(privateKey.toAddress());
var txSize = txSource.getEstimateSize();
if (txSize < 1000) {
txSource.fee(80);
} else {
txSource.feePerKb(100);
}
txSource.sign(privateKey).seal();
var txSourceRaw = txSource.uncheckedSerialize(); //Generate txraw
// Build the code script for minting
var codeScript = this.getFTmintCode(txSource.hash, 0, address_to, tapeSize);
this.codeScript = codeScript.toBuffer().toString('hex');
this.tapeScript = tapeScript.toBuffer().toString('hex'); // Construct the transaction
var tx = new tbc.Transaction().addInputFromPrevTx(txSource, 0) //.from(utxo)
.addOutput(new tbc.Transaction.Output({
script: codeScript,
satoshis: 500
})).addOutput(new tbc.Transaction.Output({
script: tapeScript,
satoshis: 0
})).feePerKb(100).change(privateKey.toAddress()).setInputScript({
inputIndex: 0,
privateKey
}, tx => {
var sig = tx.getSignature(0);
var publickey = privateKey.toPublicKey().toBuffer().toString('hex');
return tbc.Script.fromASM("".concat(sig, " ").concat(publickey));
}).sign(privateKey);
tx.seal();
var txMintRaw = tx.uncheckedSerialize();
this.contractTxid = tx.hash;
var txraw = [];
txraw.push(txSourceRaw);
txraw.push(txMintRaw);
return txraw;
}
/**
* Transfers FT tokens to another address and returns the raw transaction hex.
* @param privateKey_from - The private key of the sender.
* @param address_to - The recipient's address.
* @param amount - The amount to transfer.
* @returns The raw transaction hex string.
*/
transfer(privateKey_from, address_to, ft_amount, ftutxo_a, utxo, preTX, prepreTxData, tbc_amount) {
var _this = this;
var privateKey = privateKey_from;
var address_from = privateKey.toAddress().toString();
var code = this.codeScript;
var tape = this.tapeScript;
var decimal = this.decimal;
var tapeAmountSetIn = [];
if (ft_amount < 0) {
throw new Error('Invalid amount input');
}
var amountbn = BigInt(Math.floor(ft_amount * Math.pow(10, decimal))); // Fetch FT UTXO for the transfer
//const ftutxo_a = await this.fetchFtTXO(this.contractTxid, address_from, amountbn);
// Calculate the total available balance
var tapeAmountSum = BigInt(0);
for (var i = 0; i < ftutxo_a.length; i++) {
tapeAmountSetIn.push(ftutxo_a[i].ftBalance);
tapeAmountSum += BigInt(tapeAmountSetIn[i]);
} // Check if the balance is sufficient
if (amountbn > tapeAmountSum) {
throw new Error('Insufficient balance, please add more FT UTXOs');
} // Validate the decimal and amount
if (decimal > 18) {
throw new Error('The maximum value for decimal cannot exceed 18');
}
var maxAmount = Math.floor(Math.pow(10, 18 - decimal));
if (ft_amount > maxAmount) {
throw new Error("When decimal is ".concat(decimal, ", the maximum amount cannot exceed ").concat(maxAmount));
} // Build the amount and change hex strings for the tape
var {
amountHex,
changeHex
} = FT.buildTapeAmount(amountbn, tapeAmountSetIn); // Fetch UTXO for the sender's address
//const utxo = await API.fetchUTXO(privateKey, 0.1, this.network);
// Construct the transaction
var tx = new tbc.Transaction().from(ftutxo_a).from(utxo); // Build the code script for the recipient
var codeScript = FT.buildFTtransferCode(code, address_to);
tx.addOutput(new tbc.Transaction.Output({
script: codeScript,
satoshis: 500
})); // Build the tape script for the amount
var tapeScript = FT.buildFTtransferTape(tape, amountHex);
tx.addOutput(new tbc.Transaction.Output({
script: tapeScript,
satoshis: 0
}));
if (tbc_amount) {
var amount_satoshis = Math.floor(tbc_amount * Math.pow(10, 6));
tx.to(address_to, amount_satoshis);
} // If there's change, add outputs for the change
if (amountbn < tapeAmountSum) {
var changeCodeScript = FT.buildFTtransferCode(code, address_from);
tx.addOutput(new tbc.Transaction.Output({
script: changeCodeScript,
satoshis: 500
}));
var changeTapeScript = FT.buildFTtransferTape(tape, changeHex);
tx.addOutput(new tbc.Transaction.Output({
script: changeTapeScript,
satoshis: 0
}));
}
tx.feePerKb(100);
tx.change(address_from); // Set the input script asynchronously for the FT UTXO
var _loop = function _loop(_i) {
tx.setInputScript({
inputIndex: _i
}, tx => {
var unlockingScript = _this.getFTunlock(privateKey, tx, preTX[_i], prepreTxData[_i], _i, ftutxo_a[_i].outputIndex);
return unlockingScript;
});
};
for (var _i = 0; _i < ftutxo_a.length; _i++) {
_loop(_i);
}
tx.sign(privateKey);
tx.seal();
var txraw = tx.uncheckedSerialize();
return txraw;
}
transferWithAdditionalInfo(privateKey_from, address_to, amount, ftutxo_a, utxo, preTX, prepreTxData, additionalInfo) {
var _this2 = this;
var privateKey = privateKey_from;
var address_from = privateKey.toAddress().toString();
var code = this.codeScript;
var tape = this.tapeScript;
var decimal = this.decimal;
var tapeAmountSetIn = [];
if (amount < 0) {
throw new Error('Invalid amount input');
}
var amountbn = BigInt(Math.floor(amount * Math.pow(10, decimal))); // Fetch FT UTXO for the transfer
//const ftutxo_a = await this.fetchFtTXO(this.contractTxid, address_from, amountbn);
// Calculate the total available balance
var tapeAmountSum = BigInt(0);
for (var i = 0; i < ftutxo_a.length; i++) {
tapeAmountSetIn.push(ftutxo_a[i].ftBalance);
tapeAmountSum += BigInt(tapeAmountSetIn[i]);
} // Check if the balance is sufficient
if (amountbn > tapeAmountSum) {
throw new Error('Insufficient balance, please add more FT UTXOs');
} // Validate the decimal and amount
if (decimal > 18) {
throw new Error('The maximum value for decimal cannot exceed 18');
}
var maxAmount = Math.floor(Math.pow(10, 18 - decimal));
if (amount > maxAmount) {
throw new Error("When decimal is ".concat(decimal, ", the maximum amount cannot exceed ").concat(maxAmount));
} // Build the amount and change hex strings for the tape
var {
amountHex,
changeHex
} = FT.buildTapeAmount(amountbn, tapeAmountSetIn); // Fetch UTXO for the sender's address
//const utxo = await API.fetchUTXO(privateKey, 0.1, this.network);
// Construct the transaction
var tx = new tbc.Transaction().from(ftutxo_a).from(utxo); // Build the code script for the recipient
var codeScript = FT.buildFTtransferCode(code, address_to);
tx.addOutput(new tbc.Transaction.Output({
script: codeScript,
satoshis: 500
})); // Build the tape script for the amount
var tapeScript = FT.buildFTtransferTape(tape, amountHex);
tx.addOutput(new tbc.Transaction.Output({
script: tapeScript,
satoshis: 0
})); // If there's change, add outputs for the change
if (amountbn < tapeAmountSum) {
var changeCodeScript = FT.buildFTtransferCode(code, address_from);
tx.addOutput(new tbc.Transaction.Output({
script: changeCodeScript,
satoshis: 500
}));
var changeTapeScript = FT.buildFTtransferTape(tape, changeHex);
tx.addOutput(new tbc.Transaction.Output({
script: changeTapeScript,
satoshis: 0
}));
} //Additional infromation output
var additionalInfoScript = tbc.Script.fromASM('OP_FALSE OP_RETURN');
additionalInfoScript = additionalInfoScript.add(additionalInfo);
tx.addOutput(new tbc.Transaction.Output({
script: additionalInfoScript,
satoshis: 0
}));
tx.feePerKb(100);
tx.change(address_from); // Set the input script asynchronously for the FT UTXO
var _loop2 = function _loop2(_i2) {
tx.setInputScript({
inputIndex: _i2
}, tx => {
var unlockingScript = _this2.getFTunlock(privateKey, tx, preTX[_i2], prepreTxData[_i2], _i2, ftutxo_a[_i2].outputIndex);
return unlockingScript;
});
};
for (var _i2 = 0; _i2 < ftutxo_a.length; _i2++) {
_loop2(_i2);
}
tx.sign(privateKey);
tx.seal();
var txraw = tx.uncheckedSerialize();
return txraw;
}
/**
* Merges FT UTXOs.
*
* @param {tbc.PrivateKey} privateKey_from - 用于签名交易的私钥。
* @param {tbc.Transaction.IUnspentOutput[]} ftutxo - 要合并的 FT UTXO 列表。
* @param {tbc.Transaction.IUnspentOutput} utxo - 用于创建交易的未花费输出。
* @param {tbc.Transaction[]} preTX - 之前的交易列表。
* @param {string[]} prepreTxData - 之前交易的数据列表。
* @returns {string | true} 返回一个 Promise,解析为字符串形式的未检查交易数据或成功标志。
* @memberof FT
*/
mergeFT(privateKey_from, ftutxo, utxo, preTX, prepreTxData) {
var _this3 = this;
var privateKey = privateKey_from;
var address = privateKey.toAddress().toString();
var fttxo_codeScript = FT.buildFTtransferCode(this.codeScript, address).toBuffer().toString('hex');
var ftutxos = [];
if (ftutxo.length === 0) {
throw new Error('No FT UTXO available');
}
if (ftutxo.length === 1) {
console.log('Merge Success!');
return true;
} else {
for (var i = 0; i < ftutxo.length && i < 5; i++) {
ftutxos.push({
txId: ftutxo[i].txId,
outputIndex: ftutxo[i].outputIndex,
script: fttxo_codeScript,
satoshis: ftutxo[i].satoshis,
ftBalance: ftutxo[i].ftBalance
});
}
}
var tapeAmountSetIn = [];
var tapeAmountSum = BigInt(0);
for (var _i3 = 0; _i3 < ftutxos.length; _i3++) {
tapeAmountSetIn.push(ftutxos[_i3].ftBalance);
tapeAmountSum += BigInt(ftutxos[_i3].ftBalance);
}
var {
amountHex,
changeHex
} = FT.buildTapeAmount(tapeAmountSum, tapeAmountSetIn);
if (changeHex != '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000') {
throw new Error('Change amount is not zero');
}
var tx = new tbc.Transaction().from(ftutxos).from(utxo);
var codeScript = FT.buildFTtransferCode(this.codeScript, address);
tx.addOutput(new tbc.Transaction.Output({
script: codeScript,
satoshis: 500
}));
var tapeScript = FT.buildFTtransferTape(this.tapeScript, amountHex);
tx.addOutput(new tbc.Transaction.Output({
script: tapeScript,
satoshis: 0
}));
tx.feePerKb(100);
tx.change(privateKey.toAddress());
var _loop3 = function _loop3(_i4) {
tx.setInputScript({
inputIndex: _i4
}, tx => {
var unlockingScript = _this3.getFTunlock(privateKey, tx, preTX[_i4], prepreTxData[_i4], _i4, ftutxos[_i4].outputIndex);
return unlockingScript;
});
};
for (var _i4 = 0; _i4 < ftutxos.length; _i4++) {
_loop3(_i4);
}
tx.sign(privateKey);
tx.seal();
var txraw = tx.uncheckedSerialize();
return txraw;
}
/**
* Generates the unlocking script for an FT transfer.
* @param privateKey_from - The private key of the sender.
* @param currentTX - The current transaction object.
* @param currentUnlockIndex - The index of the input being unlocked.
* @param preTxId - The transaction ID of the previous transaction.
* @param preVout - The output index in the previous transaction.
* @returns The unlocking script as a tbc.Script object.
*/
getFTunlock(privateKey_from, currentTX, preTX, prepreTxData, currentUnlockIndex, preTxVout) {
var privateKey = privateKey_from;
var prepretxdata = prepreTxData; //const preTX = await API.fetchTXraw(preTxId, this.network);
var pretxdata = (0, ftunlock_1.getPreTxdata)(preTX, preTxVout);
var currenttxdata = (0, ftunlock_1.getCurrentTxdata)(currentTX, currentUnlockIndex);
var signature = currentTX.getSignature(currentUnlockIndex, privateKey);
var sig = (signature.length / 2).toString(16).padStart(2, '0') + signature;
var publicKey = (privateKey.toPublicKey().toString().length / 2).toString(16).padStart(2, '0') + privateKey.toPublicKey().toString();
var unlockingScript = new tbc.Script("".concat(currenttxdata).concat(prepretxdata).concat(sig).concat(publicKey).concat(pretxdata));
return unlockingScript;
}
/**
* Generates the unlocking script for an FT swap.
* @param privateKey_from - The private key of the sender.
* @param currentTX - The current transaction object.
* @param currentUnlockIndex - The index of the input being unlocked.
* @param preTxId - The transaction ID of the previous transaction.
* @param preVout - The output index in the previous transaction.
* @returns The unlocking script as a tbc.Script object.
*/
getFTunlockSwap(privateKey_from, currentTX, preTX, prepreTxData, contractTX, currentUnlockIndex, preTxVout) {
var privateKey = privateKey_from;
var prepretxdata = prepreTxData; //const contractTX = await API.fetchTXraw(currentTX.inputs[0].prevTxId.toString('hex'), this.network);
var contracttxdata = (0, ftunlock_1.getContractTxdata)(contractTX, currentTX.inputs[0].outputIndex); //const preTX = await API.fetchTXraw(preTxId, this.network);
var pretxdata = (0, ftunlock_1.getPreTxdata)(preTX, preTxVout);
var currentinputsdata = (0, ftunlock_1.getCurrentInputsdata)(currentTX);
var currenttxdata = (0, ftunlock_1.getCurrentTxdata)(currentTX, currentUnlockIndex);
var signature = currentTX.getSignature(currentUnlockIndex, privateKey);
var sig = (signature.length / 2).toString(16).padStart(2, '0') + signature;
var publicKey = (privateKey.toPublicKey().toString().length / 2).toString(16).padStart(2, '0') + privateKey.toPublicKey().toString();
var unlockingScript = new tbc.Script("".concat(currenttxdata).concat(prepretxdata).concat(sig).concat(publicKey).concat(currentinputsdata).concat(contracttxdata).concat(pretxdata));
return unlockingScript;
}
/**
* Builds the code script for minting FT tokens.
* @param txid - The transaction ID of the UTXO used for minting.
* @param vout - The output index of the UTXO.
* @param address - The recipient's address.
* @param tapeSize - The size of the tape script.
* @returns The code script as a tbc.Script object.
*/
getFTmintCode(txid, vout, address, tapeSize) {
var writer = new tbc.encoding.BufferWriter();
writer.writeReverse(Buffer.from(txid, 'hex'));
writer.writeUInt32LE(vout);
var utxoHex = writer.toBuffer().toString('hex');
var publicKeyHash = tbc.Address.fromString(address).hashBuffer.toString('hex');
var hash = publicKeyHash + '00';
var tapeSizeHex = (0, ftunlock_1.getSize)(tapeSize).toString('hex'); // The codeScript is constructed with specific opcodes and parameters for FT minting
var codeScript = new tbc.Script("OP_9 OP_PICK OP_TOALTSTACK OP_1 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_8 OP_SPLIT OP_8 OP_SPLIT OP_8 OP_SPLIT OP_8 OP_SPLIT OP_8 OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_DUP OP_5 0x01 0x28 OP_MUL OP_SPLIT 0x01 0x28 OP_SPLIT OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_ENDIF OP_SWAP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_DUP OP_4 0x01 0x28 OP_MUL OP_SPLIT 0x01 0x28 OP_SPLIT OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_ENDIF OP_ADD OP_SWAP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_DUP OP_3 0x01 0x28 OP_MUL OP_SPLIT 0x01 0x28 OP_SPLIT OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_ENDIF OP_ADD OP_SWAP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_DUP OP_2 0x01 0x28 OP_MUL OP_SPLIT 0x01 0x28 OP_SPLIT OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_ENDIF OP_ADD OP_SWAP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_DUP OP_1 0x01 0x28 OP_MUL OP_SPLIT 0x01 0x28 OP_SPLIT OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_ENDIF OP_ADD OP_SWAP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_DUP OP_0 0x01 0x28 OP_MUL OP_SPLIT 0x01 0x28 OP_SPLIT OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_ENDIF OP_ADD OP_FROMALTSTACK OP_DROP OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_FROMALTSTACK OP_CAT OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_3 OP_PICK OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_TOALTSTACK OP_SHA256 OP_FROMALTSTACK OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_6 OP_PUSH_META 0x01 0x20 OP_SPLIT OP_DROP OP_EQUALVERIFY OP_FROMALTSTACK OP_1 OP_SPLIT OP_NIP 0x01 0x14 OP_SPLIT OP_1 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_IF OP_DROP OP_1 OP_PICK OP_HASH160 OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ELSE OP_1 OP_EQUALVERIFY OP_2 OP_PICK OP_HASH160 OP_EQUALVERIFY OP_TOALTSTACK OP_CAT OP_TOALTSTACK OP_DUP OP_0 OP_EQUALVERIFY OP_FROMALTSTACK OP_FROMALTSTACK OP_CAT OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_OVER 0x01 0x20 OP_SPLIT OP_4 OP_SPLIT OP_DROP OP_BIN2NUM OP_0 OP_EQUALVERIFY OP_EQUALVERIFY OP_SHA256 OP_5 OP_PUSH_META OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_FROMALTSTACK OP_FROMALTSTACK 0x01 0x24 OP_SPLIT OP_DROP OP_DUP OP_TOALTSTACK 0x01 0x20 OP_SPLIT OP_DROP OP_5 OP_ROLL OP_EQUALVERIFY OP_2SWAP OP_EQUAL OP_IF OP_FROMALTSTACK OP_DROP OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_FROMALTSTACK 0x24 0x".concat(utxoHex, " OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_FROMALTSTACK OP_FROMALTSTACK 0x01 0x20 OP_SPLIT OP_DROP OP_5 OP_ROLL OP_EQUALVERIFY OP_2SWAP OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_FROMALTSTACK OP_FROMALTSTACK 0x01 0x20 OP_SPLIT OP_DROP OP_5 OP_ROLL OP_EQUALVERIFY OP_2SWAP OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_FROMALTSTACK OP_FROMALTSTACK 0x01 0x20 OP_SPLIT OP_DROP OP_5 OP_ROLL OP_EQUALVERIFY OP_2SWAP OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_FROMALTSTACK OP_FROMALTSTACK 0x01 0x20 OP_SPLIT OP_DROP OP_5 OP_ROLL OP_EQUALVERIFY OP_2SWAP OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_2 OP_PICK OP_2 OP_PICK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_PARTIAL_HASH OP_CAT OP_CAT OP_FROMALTSTACK OP_CAT OP_SHA256 OP_CAT OP_CAT OP_CAT OP_SHA256 OP_SHA256 OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_FROMALTSTACK OP_FROMALTSTACK 0x01 0x20 OP_SPLIT OP_DROP OP_5 OP_ROLL OP_EQUALVERIFY OP_2SWAP OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_0 OP_EQUALVERIFY OP_7 OP_EQUALVERIFY OP_FROMALTSTACK OP_FROMALTSTACK OP_SWAP OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP OP_DUP OP_SIZE OP_DUP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUALVERIFY OP_3 OP_SPLIT OP_SWAP OP_DROP OP_FROMALTSTACK OP_DUP OP_8 OP_MUL OP_2 OP_ROLL OP_SWAP OP_SPLIT OP_8 OP_SPLIT OP_DROP OP_BIN2NUM OP_DUP OP_0 OP_EQUAL OP_NOTIF OP_FROMALTSTACK OP_FROMALTSTACK OP_DUP OP_9 OP_PICK OP_9 OP_PICK OP_CAT OP_EQUALVERIFY OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_FROMALTSTACK OP_SWAP OP_SUB OP_TOALTSTACK OP_DROP OP_TOALTSTACK OP_SHA256 OP_CAT OP_TOALTSTACK OP_PARTIAL_HASH OP_FROMALTSTACK OP_CAT OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ELSE OP_DROP 0x01 0x").concat(tapeSizeHex, " OP_EQUAL OP_IF OP_2 OP_PICK OP_SIZE OP_5 OP_SUB OP_SPLIT 0x05 0x4654617065 OP_EQUAL OP_0 OP_EQUALVERIFY OP_DROP OP_ENDIF OP_PARTIAL_HASH OP_CAT OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_ROLL OP_FROMALTSTACK OP_CAT OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_ENDIF OP_ENDIF OP_DUP OP_2 OP_EQUAL OP_0 OP_EQUALVERIFY OP_FROMALTSTACK OP_FROMALTSTACK OP_0 OP_EQUALVERIFY OP_DROP OP_1 OP_EQUALVERIFY OP_FROMALTSTACK OP_FROMALTSTACK OP_SHA256 OP_7 OP_PUSH_META OP_EQUAL OP_NIP 0x17 0xffffffffffffffffffffffffffffffffffffffffffffff OP_DROP OP_RETURN 0x15 0x").concat(hash, " 0x05 0x32436f6465"));
return codeScript;
}
/**
* Builds the code script for transferring FT to a new address or hash.
* @param code - The original code script in hex.
* @param addressOrHash - The recipient's address or hash.
* @returns The new code script as a tbc.Script object.
*/
static buildFTtransferCode(code, addressOrHash) {
if (tbc.Address.isValid(addressOrHash)) {
// If the recipient is an address
var publicKeyHashBuffer = tbc.Address.fromString(addressOrHash).hashBuffer;
var hashBuffer = Buffer.concat([publicKeyHashBuffer, Buffer.from([0x00])]);
var codeBuffer = Buffer.from(code, 'hex');
hashBuffer.copy(codeBuffer, 1537, 0, 21); // Replace the hash in the code script
var codeScript = new tbc.Script(codeBuffer.toString('hex'));
return codeScript;
} else {
// If the recipient is a hash
if (addressOrHash.length !== 40) {
throw new Error('Invalid address or hash');
}
var hash = addressOrHash + '01';
var _hashBuffer = Buffer.from(hash, 'hex');
var _codeBuffer = Buffer.from(code, 'hex');
_hashBuffer.copy(_codeBuffer, 1537, 0, 21); // Replace the hash in the code script
var _codeScript = new tbc.Script(_codeBuffer.toString('hex'));
return _codeScript;
}
}
/**
* Builds the tape script with the specified amount for transfer.
* @param tape - The original tape script in hex.
* @param amountHex - The amount in hex format.
* @returns The new tape script as a tbc.Script object.
*/
static buildFTtransferTape(tape, amountHex) {
var amountHexBuffer = Buffer.from(amountHex, 'hex');
var tapeBuffer = Buffer.from(tape, 'hex');
amountHexBuffer.copy(tapeBuffer, 3, 0, 48); // Replace the amount in the tape script
var tapeScript = new tbc.Script(tapeBuffer.toString('hex'));
return tapeScript;
}
/**
* Builds the amount and change hex strings for the tape script.
* @param amountBN - The amount to transfer in BN format.
* @param tapeAmountSet - The set of amounts from the input tapes.
* @param ftInputIndex - (Optional) The index of the FT input.
* @returns An object containing amountHex and changeHex.
*/
static buildTapeAmount(amountBN, tapeAmountSet, ftInputIndex) {
var i = 0;
var j = 0;
var amountwriter = new tbc.encoding.BufferWriter();
var changewriter = new tbc.encoding.BufferWriter(); // Initialize with zeros if ftInputIndex is provided
if (ftInputIndex) {
for (j = 0; j < ftInputIndex; j++) {
amountwriter.writeUInt64LEBN(new tbc.crypto.BN(0));
changewriter.writeUInt64LEBN(new tbc.crypto.BN(0));
}
} // Build the amount and change for each tape slot
for (i = 0; i < 6; i++) {
if (amountBN <= BigInt(0)) {
break;
}
if (tapeAmountSet[i] < amountBN) {
amountwriter.writeUInt64LEBN(new tbc.crypto.BN(tapeAmountSet[i].toString()));
changewriter.writeUInt64LEBN(new tbc.crypto.BN(0));
amountBN -= BigInt(tapeAmountSet[i]);
} else {
amountwriter.writeUInt64LEBN(new tbc.crypto.BN(amountBN.toString()));
changewriter.writeUInt64LEBN(new tbc.crypto.BN((BigInt(tapeAmountSet[i]) - amountBN).toString()));
amountBN = BigInt(0);
}
} // Fill the remaining slots with zeros or remaining amounts
for (j += i; i < 6 && j < 6; i++, j++) {
if (tapeAmountSet[i]) {
amountwriter.writeUInt64LEBN(new tbc.crypto.BN(0));
changewriter.writeUInt64LEBN(new tbc.crypto.BN(tapeAmountSet[i].toString()));
} else {
amountwriter.writeUInt64LEBN(new tbc.crypto.BN(0));
changewriter.writeUInt64LEBN(new tbc.crypto.BN(0));
}
}
var amountHex = amountwriter.toBuffer().toString('hex');
var changeHex = changewriter.toBuffer().toString('hex');
return {
amountHex,
changeHex
};
}
/**
* Extracts and calculates the balance from a hexadecimal tape string.
*
* The function processes a hexadecimal string representing a tape,
* extracts a specific portion of the tape, and calculates the total
* balance by summing up six 64-bit unsigned integers from the extracted
* portion.
*
* @param tape - A hexadecimal string representing the tape data.
* The string is expected to contain sufficient data
* for processing (at least 51 bytes when decoded).
* @returns The total balance as a `bigint` calculated from the tape.
*
* @throws {RangeError} If the tape does not contain enough data to
* extract the required portion or read the
* 64-bit integers.
*/
static getBalanceFromTape(tape) {
var tapeBuffer = Buffer.from(tape, 'hex');
tapeBuffer = Buffer.from(tapeBuffer.subarray(3, 3 + 48));
var balance = BigInt(0);
for (var i = 0; i < 6; i++) {
var amount = tapeBuffer.readBigUInt64LE(i * 8);
balance += amount;
}
return balance;
}
}
module.exports = FT;