UNPKG

nerve-sdk-js

Version:
1,440 lines (1,213 loc) 54.3 kB
"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]]];