nerve-sdk-js
Version:
nerve nerve-js nerve-sdk nerve-js-sdk
1,440 lines (1,213 loc) • 54.3 kB
JavaScript
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
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");
var utxoSelect_1 = require("../util/utxoSelect");
class API {
/**
* Set the mainnet URL
* @param url The mainnet URL to use
*/
static setMainnetURL(url) {
if (!url.endsWith('/')) {
url += '/';
}
this.mainnetURL = url;
}
/**
* Set the testnet URL
* @param url The testnet URL to use
*/
static setTestnetURL(url) {
if (!url.endsWith('/')) {
url += '/';
}
this.testnetURL = url;
}
/**
* Get the base URL for the specified network.
*
* @param {("testnet" | "mainnet")} network - The network type.
* @returns {string} The base URL for the specified network.
*/
static getBaseURL(network) {
return network === "testnet" ? this.testnetURL : this.mainnetURL;
}
/**
* Fetches the TBC balance for a given address.
*
* @param {string} address - The address to fetch the TBC balance for.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @returns {Promise<number>} Returns a Promise that resolves to the TBC balance.
* @throws {Error} Throws an error if the request fails.
*/
static getTBCbalance(address, network) {
return _asyncToGenerator(function* () {
if (!tbc.Address.isValid(address)) {
throw new Error("Invalid address input");
}
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "address/".concat(address, "/get/balance/");
try {
var response = yield (yield fetch(url)).json();
return response.data.balance;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches a UTXO that satisfies the required amount.
*
* @param {tbc.PrivateKey} privateKey - The private key object.
* @param {number} amount - The required amount.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput>} Returns a Promise that resolves to the UTXO.
* @throws {Error} Throws an error if the request fails or if the balance is insufficient.
*/
static fetchUTXO(privateKey, amount, network) {
var _this = this;
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var address = privateKey.toAddress().toString();
var url = base_url + "address/".concat(address, "/unspent/");
var scriptPubKey = tbc.Script.buildPublicKeyHashOut(address).toBuffer().toString("hex");
var amount_bn = Math.floor(amount * Math.pow(10, 6));
try {
var response = yield (yield fetch(url)).json();
if (response.length === 0) {
throw new Error("The tbc balance in the account is zero.");
}
if (response.length === 1 && response[0].value > amount_bn) {
var _utxo = {
txId: response[0].tx_hash,
outputIndex: response[0].tx_pos,
script: scriptPubKey,
satoshis: response[0].value
};
return _utxo;
} else if (response.length === 1 && response[0].value <= amount_bn) {
throw new Error("Insufficient tbc balance");
}
var data = response[0];
for (var i = 0; i < response.length; i++) {
if (response[i].value > amount_bn) {
data = response[i];
break;
}
}
if (data.value < amount_bn) {
var totalBalance = yield _this.getTBCbalance(address, network);
if (totalBalance <= amount_bn) {
throw new Error("Insufficient tbc balance");
} else {
console.log("Merge UTXO");
yield API.mergeUTXO(privateKey, network);
yield new Promise(resolve => setTimeout(resolve, 3000));
return yield API.fetchUTXO(privateKey, amount, network);
}
}
var utxo = {
txId: data.tx_hash,
outputIndex: data.tx_pos,
script: scriptPubKey,
satoshis: data.value
};
return utxo;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Merges UTXOs for a given private key.
*
* @param {tbc.PrivateKey} privateKey - The private key object.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<boolean>} Returns a Promise that resolves to a boolean indicating whether the merge was successful.
* @throws {Error} Throws an error if the merge fails.
*/
static mergeUTXO(privateKey, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var address = tbc.Address.fromPrivateKey(privateKey).toString();
var url = base_url + "address/".concat(address, "/unspent/");
var scriptPubKey = tbc.Script.buildPublicKeyHashOut(address).toBuffer().toString("hex");
try {
var response = yield (yield fetch(url)).json();
var sumAmount = 0;
var utxo = [];
if (response.length === 0) {
throw new Error("No UTXO available");
}
if (response.length === 1) {
console.log("Merge Success!");
return true;
} else {
for (var i = 0; i < response.length; i++) {
sumAmount += response[i].value;
utxo.push({
txId: response[i].tx_hash,
outputIndex: response[i].tx_pos,
script: scriptPubKey,
satoshis: response[i].value
});
}
}
var tx = new tbc.Transaction().from(utxo);
var txSize = tx.getEstimateSize() + 100;
var fee = txSize < 1000 ? 80 : Math.ceil(txSize / 1000) * 80;
tx.to(address, sumAmount - fee).fee(fee).change(address).sign(privateKey).seal();
var txraw = tx.uncheckedSerialize();
yield API.broadcastTXraw(txraw, network);
yield new Promise(resolve => setTimeout(resolve, 5000));
yield API.mergeUTXO(privateKey, network);
return true;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Get the FT balance for a specified contract transaction ID and address or hash.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {string} addressOrHash - The address or hash.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<bigint>} Returns a Promise that resolves to the FT balance.
* @throws {Error} Throws an error if the address or hash is invalid, or if the request fails.
*/
static getFTbalance(contractTxid, addressOrHash, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var hash = "";
if (tbc.Address.isValid(addressOrHash)) {
// If the recipient is an address
var publicKeyHash = tbc.Address.fromString(addressOrHash).hashBuffer.toString("hex");
hash = publicKeyHash + "00";
} else {
// If the recipient is a hash
if (addressOrHash.length !== 40) {
throw new Error("Invalid address or hash");
}
hash = addressOrHash + "01";
}
var url = base_url + "ft/balance/combine/script/".concat(hash, "/contract/").concat(contractTxid);
try {
var response = yield (yield fetch(url)).json();
var ftBalance = response.ftBalance;
return ftBalance;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches a list of FT UTXOs for a specified contract transaction ID and address or hash.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {string} addressOrHash - The recipient's address or hash.
* @param {string} codeScript - The code script.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of FT UTXOs.
* @throws {Error} Throws an error if the request fails or if no UTXOs are found.
*/
static fetchFtUTXOList(contractTxid, addressOrHash, codeScript, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var hash = "";
if (tbc.Address.isValid(addressOrHash)) {
// If the recipient is an address
var publicKeyHash = tbc.Address.fromString(addressOrHash).hashBuffer.toString("hex");
hash = publicKeyHash + "00";
} else {
// If the recipient is a hash
if (addressOrHash.length !== 40) {
throw new Error("Invalid address or hash");
}
hash = addressOrHash + "01";
}
var url = base_url + "ft/utxo/combine/script/".concat(hash, "/contract/").concat(contractTxid);
try {
var response = yield fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
if (!response.ok) {
throw new Error("Failed to fetch from URL: ".concat(url, ", status: ").concat(response.status));
}
var responseData = yield response.json();
if (responseData.ftUtxoList.length === 0) {
throw new Error("The ft balance in the account is zero.");
}
var ftutxos = [];
for (var i = 0; i < responseData.ftUtxoList.length; i++) {
var data = responseData.ftUtxoList[i];
ftutxos.push({
txId: data.utxoId,
outputIndex: data.utxoVout,
script: codeScript,
satoshis: data.utxoBalance,
ftBalance: data.ftBalance
});
}
return ftutxos;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches an FT UTXO that satisfies the required amount.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {string} addressOrHash - The recipient's address or hash.
* @param {bigint} amount - The required amount.
* @param {string} codeScript - The code script.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput>} Returns a Promise that resolves to the FT UTXO.
* @throws {Error} Throws an error if the request fails or if the FT balance is insufficient.
*/
static fetchFtUTXO(contractTxid, addressOrHash, amount, codeScript, network) {
return _asyncToGenerator(function* () {
try {
var ftutxolist = yield API.fetchFtUTXOList(contractTxid, addressOrHash, codeScript, network);
var ftutxo = ftutxolist[0];
for (var i = 0; i < ftutxolist.length; i++) {
if (ftutxolist[i].ftBalance >= amount) {
ftutxo = ftutxolist[i];
break;
}
}
if (ftutxo.ftBalance < amount) {
var totalBalance = yield API.getFTbalance(contractTxid, addressOrHash, network);
if (totalBalance >= amount) {
throw new Error("Insufficient FTbalance, please merge FT UTXOs");
} else {
throw new Error("FTbalance not enough!");
}
}
return ftutxo;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches FT UTXOs for a specified contract transaction ID and address or hash.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {string} addressOrHash - The recipient's address or hash.
* @param {string} codeScript - The code script.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @param {bigint} [amount] - The required amount. If not specified, fetches up to 5 UTXOs.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of FT UTXOs.
* @throws {Error} Throws an error if the request fails or if the FT balance is insufficient.
*/
static fetchFtUTXOs(contractTxid, addressOrHash, codeScript, network, amount) {
return _asyncToGenerator(function* () {
try {
var ftutxolist = yield API.fetchFtUTXOList(contractTxid, addressOrHash, codeScript, network);
ftutxolist.sort((a, b) => b.ftBalance > a.ftBalance ? 1 : -1);
var sumBalance = BigInt(0);
var ftutxos = [];
if (!amount) {
for (var i = 0; i < ftutxolist.length && i < 5; i++) {
ftutxos.push(ftutxolist[i]);
}
} else {
for (var _i = 0; _i < ftutxolist.length && _i < 5; _i++) {
sumBalance += BigInt(ftutxolist[_i].ftBalance);
ftutxos.push(ftutxolist[_i]);
if (sumBalance >= amount) break;
}
if (sumBalance < amount) {
var totalBalance = yield API.getFTbalance(contractTxid, addressOrHash, network);
if (totalBalance >= amount) {
throw new Error("Insufficient FTbalance, please merge FT UTXOs");
} else {
throw new Error("FTbalance not enough!");
}
}
}
return ftutxos;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches a specified number of FT UTXOs that satisfy the required amount for a pool.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {string} addressOrHash - The recipient's address or hash.
* @param {bigint} amount - The required amount.
* @param {number} number - The number of FT UTXOs to fetch.
* @param {string} codeScript - The code script.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of FT UTXOs.
* @throws {Error} Throws an error if the request fails or if the FT balance is insufficient.
*/
static fetchFtUTXOsforPool(contractTxid, addressOrHash, amount, number, codeScript, network) {
return _asyncToGenerator(function* () {
if (number <= 0 || !Number.isInteger(number)) {
throw new Error("Number must be a positive integer greater than 0");
}
try {
var ftutxolist = yield API.fetchFtUTXOList(contractTxid, addressOrHash, codeScript, network);
ftutxolist.sort((a, b) => b.ftBalance > a.ftBalance ? 1 : -1);
var sumBalance = BigInt(0);
var ftutxos = [];
for (var i = 0; i < ftutxolist.length && i < number; i++) {
sumBalance += BigInt(ftutxolist[i].ftBalance);
ftutxos.push(ftutxolist[i]);
if (sumBalance >= amount && i >= 1) break;
}
if (sumBalance < amount) {
var totalBalance = yield API.getFTbalance(contractTxid, addressOrHash, network);
if (totalBalance >= amount) {
throw new Error("Insufficient FTbalance, please merge FT UTXOs");
} else {
throw new Error("FTbalance not enough!");
}
}
return ftutxos;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the FT information for a given contract transaction ID.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<FtInfo>} Returns a Promise that resolves to an FtInfo object containing the FT information.
* @throws {Error} Throws an error if the request to fetch FT information fails.
*/
static fetchFtInfo(contractTxid, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "ft/info/contract/id/".concat(contractTxid);
try {
var response = yield fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
if (!response.ok) {
throw new Error("Failed to fetch from URL: ".concat(url, ", status: ").concat(response.status));
}
var data = yield response.json();
var ftInfo = {
codeScript: data.ftCodeScript,
tapeScript: data.ftTapeScript,
totalSupply: data.ftSupply,
decimal: data.ftDecimal,
name: data.ftName,
symbol: data.ftSymbol
};
return ftInfo;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the pre-pre transaction data for a given transaction.
*
* @param {tbc.Transaction} preTX - The previous transaction.
* @param {number} preTxVout - The output index of the previous transaction.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<string>} Returns a Promise that resolves to the pre-pre transaction data.
* @throws {Error} Throws an error if the request fails.
*/
static fetchFtPrePreTxData(preTX, preTxVout, network) {
return _asyncToGenerator(function* () {
var preTXtape = Buffer.from(preTX.outputs[preTxVout + 1].script.toBuffer().subarray(3, 51)).toString("hex");
var prepretxdata = "";
for (var i = preTXtape.length - 16; i >= 0; i -= 16) {
var chunk = preTXtape.substring(i, i + 16);
if (chunk != "0000000000000000") {
var inputIndex = i / 16;
var prepreTX = yield API.fetchTXraw(preTX.inputs[inputIndex].prevTxId.toString("hex"), network);
prepretxdata = prepretxdata + (0, ftunlock_1.getPrePreTxdata)(prepreTX, preTX.inputs[inputIndex].outputIndex);
}
}
prepretxdata = "57" + prepretxdata;
return prepretxdata;
})();
}
static fetchFtPrePreTxDataOffline(preTX, preTxVout, prePreTxs) {
var preTXtape = Buffer.from(preTX.outputs[preTxVout + 1].script.toBuffer().subarray(3, 51)).toString("hex");
var prepretxdata = "";
for (var i = preTXtape.length - 16; i >= 0; i -= 16) {
var chunk = preTXtape.substring(i, i + 16);
if (chunk != "0000000000000000") {
var inputIndex = i / 16;
var prepreTXraw = prePreTxs[preTX.inputs[inputIndex].prevTxId.toString("hex")];
var prepreTX = new tbc.Transaction();
prepreTX.fromString(prepreTXraw);
prepretxdata = prepretxdata + (0, ftunlock_1.getPrePreTxdata)(prepreTX, preTX.inputs[inputIndex].outputIndex);
}
}
prepretxdata = "57" + prepretxdata;
return prepretxdata;
}
/**
* Fetches the Pool NFT information for a given contract transaction ID.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @returns {Promise<PoolNFTInfo>} Returns a Promise that resolves to a PoolNFTInfo object containing the Pool NFT information.
* @throws {Error} Throws an error if the request to fetch Pool NFT information fails.
*/
static fetchPoolNftInfo(contractTxid, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "ft/pool/nft/info/contract/id/".concat(contractTxid);
try {
var response = yield (yield fetch(url)).json();
var data = response;
var poolNftInfo = {
ft_lp_amount: data.ft_lp_balance,
ft_a_amount: data.ft_a_balance,
tbc_amount: data.tbc_balance,
ft_lp_partialhash: data.ft_lp_partial_hash,
ft_a_partialhash: data.ft_a_partial_hash,
ft_a_contractTxid: data.ft_a_contract_txid,
service_fee_rate: data.pool_service_fee_rate,
service_provider: data.pool_service_provider,
poolnft_code: data.pool_nft_code_script,
pool_version: data.pool_version,
currentContractTxid: data.current_pool_nft_txid,
currentContractVout: data.current_pool_nft_vout,
currentContractSatoshi: data.current_pool_nft_balance
};
return poolNftInfo;
} catch (error) {
throw new Error("Failed to fetch PoolNFTInfo.");
}
})();
}
/**
* Fetches the Pool NFT UTXO for a given contract transaction ID.
*
* @param {string} contractTxid - The contract transaction ID.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @returns {Promise<tbc.Transaction.IUnspentOutput>} Returns a Promise that resolves to a Pool NFT UTXO.
* @throws {Error} Throws an error if the request to fetch Pool NFT UTXO fails.
*/
static fetchPoolNftUTXO(contractTxid, network) {
return _asyncToGenerator(function* () {
try {
var poolNftInfo = yield API.fetchPoolNftInfo(contractTxid, network);
var poolnft = {
txId: poolNftInfo.currentContractTxid,
outputIndex: poolNftInfo.currentContractVout,
script: poolNftInfo.poolnft_code,
satoshis: poolNftInfo.currentContractSatoshi
};
return poolnft;
} catch (error) {
throw new Error("Failed to fetch PoolNFT UTXO.");
}
})();
}
/**
* Fetches the FT LP balance for a given FT LP code.
*
* @param {string} ftlpCode - The FT LP code.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @returns {Promise<bigint>} Returns a Promise that resolves to the FT LP balance.
* @throws {Error} Throws an error if the request to fetch FT LP balance fails.
*/
static fetchFtlpBalance(ftlpCode, network) {
return _asyncToGenerator(function* () {
var ftlpHash = tbc.crypto.Hash.sha256(Buffer.from(ftlpCode, "hex")).reverse().toString("hex");
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "ft/lp/unspent/by/script/hash".concat(ftlpHash);
try {
var response = yield (yield fetch(url)).json();
var ftlpBalance = BigInt(0);
for (var i = 0; i < response.ftUtxoList.length; i++) {
ftlpBalance += BigInt(response.ftUtxoList[i].ftBalance);
}
return ftlpBalance;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches an FT LP UTXO that satisfies the required amount for a given FT LP code.
*
* @param {string} ftlpCode - The FT LP code.
* @param {bigint} amount - The required amount.
* @param {("testnet" | "mainnet")} [network] - The network type. Defaults to "mainnet" if not specified.
* @returns {Promise<tbc.Transaction.IUnspentOutput>} Returns a Promise that resolves to an FT LP UTXO.
* @throws {Error} Throws an error if the request to fetch FT LP UTXO fails or if no suitable UTXO is found.
*/
static fetchFtlpUTXO(ftlpCode, amount, network) {
return _asyncToGenerator(function* () {
var ftlpHash = tbc.crypto.Hash.sha256(Buffer.from(ftlpCode, "hex")).reverse().toString("hex");
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "ft/lp/unspent/by/script/hash".concat(ftlpHash);
try {
var response = yield (yield fetch(url)).json();
var data = response.ftUtxoList[0];
for (var i = 0; i < response.ftUtxoList.length; i++) {
if (response.ftUtxoList[i].ftBalance >= amount) {
data = response.ftUtxoList[i];
break;
}
}
var ftlpBalance = BigInt(0);
if (data.ftBalance < amount) {
for (var _i2 = 0; _i2 < response.ftUtxoList.length; _i2++) {
ftlpBalance += BigInt(response.ftUtxoList[_i2].ftBalance);
}
if (ftlpBalance < amount) {
throw new Error("Insufficient FT-LP amount");
} else {
throw new Error("Please merge FT-LP UTXOs");
}
}
var ftlp = {
txId: data.utxoId,
outputIndex: data.utxoVout,
script: ftlpCode,
satoshis: data.utxoBalance,
ftBalance: data.ftBalance
};
return ftlp;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the raw transaction data for a given transaction ID.
*
* @param {string} txid - The transaction ID to fetch.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction>} Returns a Promise that resolves to the transaction object.
* @throws {Error} Throws an error if the request fails.
*/
static fetchTXraw(txid, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "tx/hex/".concat(txid);
try {
var response = yield fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch TXraw: ".concat(response.statusText));
}
var rawtx = yield response.json();
var tx = new tbc.Transaction();
tx.fromString(rawtx);
return tx;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Broadcasts the raw transaction to the network.
*
* @param {string} txraw - The raw transaction hex.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<string>} Returns a Promise that resolves to the response from the broadcast API.
* @throws {Error} Throws an error if the request fails.
*/
static broadcastTXraw(txraw, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "broadcast/tx/raw";
try {
var response = yield fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
txHex: txraw
})
});
if (!response.ok) {
throw new Error("Failed to broadcast TXraw: ".concat(response.statusText));
}
var data = yield response.json();
console.log("txid:", data.result);
if (data.error && data.error.message) {
throw new Error(data.error.message);
}
return data.result;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Broadcast multiple raw transactions in batch.
*
* @param {Array<{ txHex: string }>} txrawList - An array containing multiple transactions in the format [{ txHex: "string" }].
* @param {("testnet" | "mainnet")} [network] - The network type, either "testnet" or "mainnet".
* @returns {Promise<string[]>} Returns a Promise that resolves to a list of successfully broadcasted transaction IDs.
* @throws {Error} Throws an error if the broadcast fails.
*/
static broadcastTXsraw(txrawList, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "broadcast/txs/raw";
try {
var response = yield fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(txrawList)
});
if (!response.ok) {
throw new Error("Failed to broadcast transactions: ".concat(response.statusText));
}
var data = yield response.json();
if (!data.result.invalid) {
console.log("Broadcast success!");
} else {
throw new Error("Broadcast failed!\n ".concat(JSON.stringify(data.result.invalid)));
} // console.log("txid:", data.result);
if (data.error && data.error.message) {
throw new Error(data.error.message);
}
return data.result;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the UTXOs for a given address.
*
* @param {string} address - The address to fetch UTXOs for.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of UTXOs.
* @throws {Error} Throws an error if the request fails.
*/
static fetchUTXOs(address, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "address/".concat(address, "/unspent/");
try {
var response = yield fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch UTXO: ".concat(response.statusText));
}
var data = yield response.json();
if (data.length === 0) {
throw new Error("The balance in the account is zero.");
}
var scriptPubKey = tbc.Script.buildPublicKeyHashOut(address).toBuffer().toString("hex");
return data.map(utxo => ({
txId: utxo.tx_hash,
outputIndex: utxo.tx_pos,
script: scriptPubKey,
satoshis: utxo.value
}));
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Get UTXOs for a given address and amount.
*
* @param {string} address - The address to fetch UTXOs for.
* @param {number} amount_tbc - The required amount in TBC.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of selected UTXOs.
* @throws {Error} Throws an error if the balance is insufficient.
*/
static getUTXOs(address, amount_tbc, network) {
var _this2 = this;
return _asyncToGenerator(function* () {
try {
var utxos = [];
if (network) {
utxos = yield _this2.fetchUTXOs(address, network);
} else {
utxos = yield _this2.fetchUTXOs(address);
}
utxos.sort((a, b) => a.satoshis - b.satoshis);
var amount_satoshis = amount_tbc * Math.pow(10, 6);
var closestUTXO = utxos.find(utxo => utxo.satoshis >= amount_satoshis + 100000);
if (closestUTXO) {
return [closestUTXO];
}
var totalAmount = 0;
var selectedUTXOs = [];
for (var utxo of utxos) {
totalAmount += utxo.satoshis;
selectedUTXOs.push(utxo);
if (totalAmount >= amount_satoshis) {
break;
}
}
if (totalAmount < amount_satoshis) {
throw new Error("Insufficient tbc balance");
}
return selectedUTXOs;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches an NFT UTXO based on the provided script and optional transaction hash.
*
* @param {Object} params - The parameters for fetching the NFT UTXO.
* @param {string} params.script - The script to fetch the UTXO for.
* @param {string} [params.tx_hash] - The optional transaction hash to filter the UTXOs.
* @param {("testnet" | "mainnet")} [params.network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput>} Returns a Promise that resolves to the NFT UTXO.
* @throws {Error} Throws an error if the request fails or no matching UTXO is found.
*/
static fetchNFTTXO(params) {
return _asyncToGenerator(function* () {
var {
script,
tx_hash,
network
} = params;
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var script_hash = Buffer.from(tbc.crypto.Hash.sha256(Buffer.from(script, "hex")).toString("hex"), "hex").reverse().toString("hex");
var url = base_url + "script/hash/".concat(script_hash, "/unspent");
try {
var response = yield fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch UTXO: ".concat(response.statusText));
}
var data = yield response.json();
if (tx_hash) {
var filteredUTXOs = data.filter(item => item.tx_hash === tx_hash);
if (filteredUTXOs.length === 0) {
throw new Error("No matching UTXO found.");
}
var min_vout_utxo = filteredUTXOs.reduce((prev, current) => prev.tx_pos < current.tx_pos ? prev : current);
return {
txId: min_vout_utxo.tx_hash,
outputIndex: min_vout_utxo.tx_pos,
script: script,
satoshis: min_vout_utxo.value
};
} else {
return {
txId: data[0].tx_hash,
outputIndex: data[0].tx_pos,
script: script,
satoshis: data[0].value
};
}
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the NFT information for a given contract ID.
*
* @param {string} contract_id - The contract ID to fetch NFT information for.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<NFTInfo>} Returns a Promise that resolves to an NFTInfo object containing the NFT information.
* @throws {Error} Throws an error if the request to fetch NFT information fails.
*/
static fetchNFTInfo(contract_id, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "nft/infos/contract_ids";
try {
var response = yield fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
if_icon_needed: true,
nft_contract_list: [contract_id]
})
});
if (!response.ok) {
if (!response.ok) {
throw new Error("Failed to fetch NFTInfo: ".concat(response.statusText));
}
}
var data = yield response.json();
var nftInfo = {
collectionId: data.nftInfoList[0].collectionId,
collectionIndex: data.nftInfoList[0].collectionIndex,
collectionName: data.nftInfoList[0].collectionName,
nftCodeBalance: data.nftInfoList[0].nftCodeBalance,
nftP2pkhBalance: data.nftInfoList[0].nftP2pkhBalance,
nftName: data.nftInfoList[0].nftName,
nftSymbol: data.nftInfoList[0].nftSymbol,
nft_attributes: data.nftInfoList[0].nft_attributes,
nftDescription: data.nftInfoList[0].nftDescription,
nftTransferTimeCount: data.nftInfoList[0].nftTransferTimeCount,
nftIcon: data.nftInfoList[0].nftIcon
};
return nftInfo;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the UMTXO for a given script.
*
* @param {string} script_asm - The script to fetch the UMTXO for.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput>} Returns a Promise that resolves to the UMTXO.
* @throws {Error} Throws an error if the request fails.
*/
static fetchUMTXO(script_asm, tbc_amount, network) {
return _asyncToGenerator(function* () {
var multiScript = tbc.Script.fromASM(script_asm).toHex();
var amount_satoshis = Math.floor(tbc_amount * Math.pow(10, 6));
var script_hash = Buffer.from(tbc.crypto.Hash.sha256(Buffer.from(multiScript, "hex")).toString("hex"), "hex").reverse().toString("hex");
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "script/hash/".concat(script_hash, "/unspent/");
try {
var response = yield fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch UTXO: ".concat(response.statusText));
}
var data = yield response.json();
if (data.length === 0) {
throw new Error("The balance in the account is zero.");
}
var selectedUTXO = data[0];
for (var i = 0; i < data.length; i++) {
if (data[i].value > amount_satoshis && data[i].value < 3200000000) {
selectedUTXO = data[i];
break;
}
}
if (selectedUTXO.value < amount_satoshis) {
var balance = 0;
for (var _i3 = 0; _i3 < data.length; _i3++) {
balance += data[_i3].value;
}
if (balance < amount_satoshis) {
throw new Error("Insufficient tbc balance");
} else {
throw new Error("Please mergeUTXO");
}
}
var umtxo = {
txId: selectedUTXO.tx_hash,
outputIndex: selectedUTXO.tx_pos,
script: multiScript,
satoshis: selectedUTXO.value
};
return umtxo;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches all UMTXOs for a given script.
*
* @param {string} script_asm - The script to fetch UMTXOs for.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of UMTXOs.
* @throws {Error} Throws an error if the request fails.
*/
static fetchUMTXOs(script_asm, network) {
return _asyncToGenerator(function* () {
var multiScript = tbc.Script.fromASM(script_asm).toHex();
var script_hash = Buffer.from(tbc.crypto.Hash.sha256(Buffer.from(multiScript, "hex")).toString("hex"), "hex").reverse().toString("hex");
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var url = base_url + "script/hash/".concat(script_hash, "/unspent/");
try {
var response = yield fetch(url);
if (!response.ok) {
throw new Error("Failed to fetch UTXO: ".concat(response.statusText));
}
var data = yield response.json();
if (data.length === 0) {
throw new Error("The balance in the account is zero.");
}
var umtxos = data.map(utxo => {
return {
txId: utxo.tx_hash,
outputIndex: utxo.tx_pos,
script: multiScript,
satoshis: utxo.value
};
});
return umtxos;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Get UMTXOs for a given address and amount.
*
* @param {string} address - The address to fetch UMTXOs for.
* @param {number} amount_tbc - The required amount in TBC.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of selected UMTXOs.
* @throws {Error} Throws an error if the balance is insufficient.
*/
static getUMTXOs(script_asm, amount_tbc, network) {
var _this3 = this;
return _asyncToGenerator(function* () {
try {
var umtxos = [];
if (network) {
umtxos = yield _this3.fetchUMTXOs(script_asm, network);
} else {
umtxos = yield _this3.fetchUMTXOs(script_asm);
}
umtxos.sort((a, b) => a.satoshis - b.satoshis);
var amount_satoshis = amount_tbc * Math.pow(10, 6);
var closestUMTXO = umtxos.find(umtxo => umtxo.satoshis >= amount_satoshis + 100000);
if (closestUMTXO) {
return [closestUMTXO];
}
var totalSatoshis = 0;
var selectedUMTXOs = [];
for (var umtxo of umtxos) {
totalSatoshis += umtxo.satoshis;
selectedUMTXOs.push(umtxo);
if (totalSatoshis >= amount_satoshis) {
break;
}
}
if (totalSatoshis < amount_satoshis) {
throw new Error("Insufficient tbc balance");
}
return selectedUMTXOs;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the FT UTXOs for a given contract and multiSig address.
*
* @param {string} contractTxid - The contract TXID.
* @param {string} addressOrHash - The address or hash to fetch UMTXOs for.
* @param {string} codeScript - The code script.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of UMTXOs.
* @throws {Error} Throws an error if the request fails.
*/
static fetchFtUTXOS_multiSig(contractTxid, addressOrHash, codeScript, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var hash = "";
if (tbc.Address.isValid(addressOrHash)) {
var publicKeyHash = tbc.Address.fromString(addressOrHash).hashBuffer.toString("hex");
hash = publicKeyHash + "00";
} else {
if (addressOrHash.length !== 40) {
throw new Error("Invalid address or hash");
}
hash = addressOrHash + "01";
}
try {
var url = base_url + "ft/utxo/combine/script/".concat(hash, "/contract/").concat(contractTxid);
var response = yield fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
if (!response.ok) {
throw new Error("Failed to fetch from URL: ".concat(url, ", status: ").concat(response.status));
}
var responseData = yield response.json();
if (responseData.ftUtxoList.length === 0) {
throw new Error("The ft balance in the account is zero.");
}
var sortedData = responseData.ftUtxoList.sort((a, b) => {
if (a.ftBalance < b.ftBalance) return -1;
if (a.ftBalance > b.ftBalance) return 1;
return 0;
});
var ftutxos = [];
for (var i = 0; i < sortedData.length; i++) {
ftutxos.push({
txId: sortedData[i].utxoId,
outputIndex: sortedData[i].utxoVout,
script: codeScript,
satoshis: sortedData[i].utxoBalance,
ftBalance: sortedData[i].ftBalance
});
}
return ftutxos;
} catch (error) {
throw new Error(error.message);
}
})();
}
/**
* Fetches the FT UTXOs for a given contract and multiSig address.
*
* @param {string} contractTxid - The contract TXID.
* @param {string} addressOrHash - The address or hash to fetch UMTXOs for.
* @param {string} codeScript - The code script.
* @param {bigint} amount - The amount to fetch UMTXOs for.
* @param {("testnet" | "mainnet")} [network] - The network type.
* @returns {Promise<tbc.Transaction.IUnspentOutput[]>} Returns a Promise that resolves to an array of UMTXOs.
* @throws {Error} Throws an error if the request fails.
*/
static getFtUTXOS_multiSig(contractTxid, addressOrHash, codeScript, amount, network) {
return _asyncToGenerator(function* () {
var base_url = network ? API.getBaseURL(network) : API.getBaseURL("mainnet");
var hash = "";
if (tbc.Address.isValid(addressOrHash)) {
var publicKeyHash = tbc.Address.fromString(addressOrHash).hashBuffer.toString("hex");
hash = publicKeyHash + "00";
} else {
if (addressOrHash.length !== 40) {
throw new Error("Invalid address or hash");
}
hash = addressOrHash + "01";
}
try {
var url = base_url + "ft/utxo/combine/script/".concat(hash, "/contract/").concat(contractTxid);
var response = yield fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
if (!response.ok) {
throw new Error("Failed to fetch from URL: ".concat(url, ", status: ").concat(response.status));
}
var responseData = yield response.json();
if (responseData.ftUtxoList.length === 0) {
throw new Error("The ft balance in the account is zero.");
}
var sortedData = responseData.ftUtxoList.sort((a, b) => {
if (a.ftBalance < b.ftBalance) return -1;
if (a.ftBalance > b.ftBalance) return 1;
return 0;
});
var ftutxos = [];
for (var i = 0; i < sortedData.length; i++) {
ftutxos.push({
txId: sortedData[i].utxoId,
outputIndex: sortedData[i].utxoVout,
script: codeScript,
satoshis: sortedData[i].utxoBalance,
ftBalance: sortedData[i].ftBalance
});
}
var ftBalanceArray = ftutxos.map(item => BigInt(item.ftBalance));
switch (ftBalanceArray.length) {
case 1:
if (ftBalanceArray[0] >= amount) {
return [ftutxos[0]];
} else {
throw new Error("Insufficient FT balance");
}
case 2:
if (ftBalanceArray[0] + ftBalanceArray[1] < amount) {
throw new Error("Insufficient FT balance");
} else if (ftBalanceArray[0] >= amount) {
return [ftutxos[0]];
} else if (ftBalanceArray[1] >= amount) {
return [ftutxos[1]];
} else {
return [ftutxos[0], ftutxos[1]];
}
case 3:
if (ftBalanceArray[0] + ftBalanceArray[1] + ftBalanceArray[2] < amount) {
throw new Error("Insufficient FT balance");
} else if ((0, utxoSelect_1.findMinTwoSum)(ftBalanceArray, amount)) {
var result = (0, utxoSelect_1.findMinTwoSum)(ftBalanceArray, amount);
if (ftBalanceArray[result[0]] >= amount) {
return [ftutxos[result[0]]];
} else if (ftBalanceArray[result[1]] >= amount) {
return [ftutxos[result[1]]];
} else {
return [ftutxos[result[0]], ftutxos[result[1]]];
}
} else {
return [ftutxos[0], ftutxos[1], ftutxos[2]];
}
case 4:
if (ftBalanceArray[0] + ftBalanceArray[1] + ftBalanceArray[2] + ftBalanceArray[3] < amount) {
throw new Error("Insufficient FT balance");
} else if ((0, utxoSelect_1.findMinThreeSum)(ftBalanceArray, amount)) {
var result_three = (0, utxoSelect_1.findMinThreeSum)(ftBalanceArray, amount);
var ftBalanceArray_three = (0, utxoSelect_1.initialUtxoArray)(ftBalanceArray, result_three);
if ((0, utxoSelect_1.findMinTwoSum)(ftBalanceArray_three, amount)) {
var result_two = (0, utxoSelect_1.findMinTwoSum)(ftBalanceArray_three, amount);
if (ftBalanceArray[result_two[0]] >= amount) {
return [ftutxos[result_two[0]]];
} else if (ftBalanceArray[result_two[1]] >= amount) {
return [ftutxos[result_two[1]]];
} else {
return [ftutxos[result_two[0]], ftutxos[result_two[1]]];
}
} else {
return [ftutxos[result_three[0]], ftutxos[result_three[1]], ftutxos[result_three[2]]];