UNPKG

bch-slpjs

Version:

Simple Ledger Protocol (SLP) JavaScript Library

271 lines 12.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const bignumber_js_1 = require("bignumber.js"); const _ = require("lodash"); const bchaddr = require("bchaddrjs-slp"); const bitcore = require("bitcore-lib-cash"); const slp_1 = require("./slp"); const axios_1 = require("axios"); const utils_1 = require("./utils"); const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); class BitboxNetwork { constructor(BITBOX, validator) { this.BITBOX = BITBOX; this.slp = new slp_1.Slp(BITBOX); if (validator) this.validator = validator; else { this.validatorUrl = BITBOX.restURL.replace('v1', 'v2'); this.validatorUrl = this.validatorUrl.concat('/slp/validate'); this.validatorUrl = this.validatorUrl.replace('//slp', '/slp'); } } getTokenInformation(txid) { return __awaiter(this, void 0, void 0, function* () { let txhex = (yield this.BITBOX.RawTransactions.getRawTransaction([txid]))[0]; let txn = new bitcore.Transaction(txhex); return this.slp.parseSlpOutputScript(txn.outputs[0]._scriptBuffer); }); } getUtxos(address) { return __awaiter(this, void 0, void 0, function* () { // must be a cash or legacy addr let res; if (!bchaddr.isCashAddress(address) && !bchaddr.isLegacyAddress(address)) throw new Error("Not an a valid address format, must be cashAddr or Legacy address format."); res = (yield this.BITBOX.Address.utxo([address]))[0]; return res; }); } getAllSlpBalancesAndUtxos(address) { return __awaiter(this, void 0, void 0, function* () { address = bchaddr.toCashAddress(address); let result = yield this.getUtxoWithTxDetails(address); return yield this.processUtxosForSlp(result); }); } // Sent SLP tokens to a single output address with change handled (Warning: Sweeps all BCH/SLP UTXOs for the funding address) simpleTokenSend(tokenId, sendAmount, inputUtxos, tokenReceiverAddress, changeReceiverAddress) { return __awaiter(this, void 0, void 0, function* () { // 1) Set the token send amounts, we'll send 100 tokens to a new receiver and send token change back to the sender let totalTokenInputAmount = inputUtxos .filter(txo => { return slp_1.Slp.preSendSlpJudgementCheck(txo, tokenId); }) .reduce((tot, txo) => { return tot.plus(txo.slpUtxoJudgementAmount); }, new bignumber_js_1.default(0)); // 2) Compute the token Change amount. let tokenChangeAmount = totalTokenInputAmount.minus(sendAmount); let txHex; if (tokenChangeAmount.isGreaterThan(new bignumber_js_1.default(0))) { // 3) Create the Send OP_RETURN message let sendOpReturn = this.slp.buildSendOpReturn({ tokenIdHex: tokenId, outputQtyArray: [sendAmount, tokenChangeAmount], }); // 4) Create the raw Send transaction hex txHex = this.slp.buildRawSendTx({ slpSendOpReturn: sendOpReturn, input_token_utxos: utils_1.Utils.mapToUtxoArray(inputUtxos), tokenReceiverAddressArray: [tokenReceiverAddress, changeReceiverAddress], bchChangeReceiverAddress: changeReceiverAddress }); } else if (tokenChangeAmount.isEqualTo(new bignumber_js_1.default(0))) { // 3) Create the Send OP_RETURN message let sendOpReturn = this.slp.buildSendOpReturn({ tokenIdHex: tokenId, outputQtyArray: [sendAmount], }); // 4) Create the raw Send transaction hex txHex = this.slp.buildRawSendTx({ slpSendOpReturn: sendOpReturn, input_token_utxos: utils_1.Utils.mapToUtxoArray(inputUtxos), tokenReceiverAddressArray: [tokenReceiverAddress], bchChangeReceiverAddress: changeReceiverAddress }); } else { throw Error('Token inputs less than the token outputs'); } // 5) Broadcast the transaction over the network using this.BITBOX return yield this.sendTx(txHex); }); } simpleTokenGenesis(tokenName, tokenTicker, tokenAmount, documentUri, documentHash, decimals, tokenReceiverAddress, batonReceiverAddress, bchChangeReceiverAddress, inputUtxos) { return __awaiter(this, void 0, void 0, function* () { let genesisOpReturn = this.slp.buildGenesisOpReturn({ ticker: tokenTicker, name: tokenName, documentUri: documentUri, hash: documentHash, decimals: decimals, batonVout: 2, initialQuantity: tokenAmount, }); // 4) Create/sign the raw transaction hex for Genesis let genesisTxHex = this.slp.buildRawGenesisTx({ slpGenesisOpReturn: genesisOpReturn, mintReceiverAddress: tokenReceiverAddress, batonReceiverAddress: batonReceiverAddress, bchChangeReceiverAddress: bchChangeReceiverAddress, input_utxos: utils_1.Utils.mapToUtxoArray(inputUtxos) }); return yield this.sendTx(genesisTxHex); }); } // Sent SLP tokens to a single output address with change handled (Warning: Sweeps all BCH/SLP UTXOs for the funding address) simpleTokenMint(tokenId, mintAmount, inputUtxos, tokenReceiverAddress, batonReceiverAddress, changeReceiverAddress) { return __awaiter(this, void 0, void 0, function* () { // // convert address to cashAddr from SLP format. // let fundingAddress_cashfmt = bchaddr.toCashAddress(fundingAddress); // 1) Create the Send OP_RETURN message let mintOpReturn = this.slp.buildMintOpReturn({ tokenIdHex: tokenId, mintQuantity: mintAmount, batonVout: 2 }); // 2) Create the raw Mint transaction hex let txHex = this.slp.buildRawMintTx({ input_baton_utxos: utils_1.Utils.mapToUtxoArray(inputUtxos), slpMintOpReturn: mintOpReturn, mintReceiverAddress: tokenReceiverAddress, batonReceiverAddress: batonReceiverAddress, bchChangeReceiverAddress: changeReceiverAddress }); //console.log(txHex); // 5) Broadcast the transaction over the network using this.BITBOX return yield this.sendTx(txHex); }); } getUtxoWithRetry(address, retries = 40) { return __awaiter(this, void 0, void 0, function* () { let result; let count = 0; while (result === undefined) { result = yield this.getUtxos(address); count++; if (count > retries) throw new Error("this.BITBOX.Address.utxo endpoint experienced a problem"); yield sleep(250); } return result; }); } getUtxoWithTxDetails(address) { return __awaiter(this, void 0, void 0, function* () { let utxos = utils_1.Utils.mapToSlpAddressUtxoResultArray(yield this.getUtxoWithRetry(address)); let txIds = utxos.map(i => i.txid); if (txIds.length === 0) return []; // Split txIds into chunks of 20 (BitBox limit), run the detail queries in parallel let txDetails = (yield Promise.all(_.chunk(txIds, 20).map((txids) => { return this.getTransactionDetailsWithRetry([...new Set(txids)]); }))); // concat the chunked arrays txDetails = [].concat(...txDetails); utxos = utxos.map(i => { i.tx = txDetails.find((d) => d.txid === i.txid); return i; }); return utxos; }); } getTransactionDetailsWithRetry(txids, retries = 40) { return __awaiter(this, void 0, void 0, function* () { let result; let count = 0; while (result === undefined) { result = yield this.BITBOX.Transaction.details(txids); count++; if (count > retries) throw new Error("this.BITBOX.Address.details endpoint experienced a problem"); yield sleep(500); } return result; }); } getAddressDetailsWithRetry(address, retries = 40) { return __awaiter(this, void 0, void 0, function* () { // must be a cash or legacy addr if (!bchaddr.isCashAddress(address) && !bchaddr.isLegacyAddress(address)) throw new Error("Not an a valid address format, must be cashAddr or Legacy address format."); let result; let count = 0; while (result === undefined) { result = yield this.BITBOX.Address.details([address]); count++; if (count > retries) throw new Error("this.BITBOX.Address.details endpoint experienced a problem"); yield sleep(250); } return result; }); } sendTx(hex) { return __awaiter(this, void 0, void 0, function* () { let res = yield this.BITBOX.RawTransactions.sendRawTransaction(hex); //console.log(res); return res; }); } monitorForPayment(paymentAddress, fee, onPaymentCB) { return __awaiter(this, void 0, void 0, function* () { let utxo; // must be a cash or legacy addr if (!bchaddr.isCashAddress(paymentAddress) && !bchaddr.isLegacyAddress(paymentAddress)) throw new Error("Not an a valid address format, must be cashAddr or Legacy address format."); while (true) { try { utxo = yield this.getUtxos(paymentAddress); if (utxo) if (utxo.utxos[0].satoshis >= fee) break; } catch (ex) { console.log(ex); } yield sleep(2000); } onPaymentCB(); }); } isValidSlpTxid(txid) { throw new Error("Method not implemented."); } validateSlpTransactions(txids) { return __awaiter(this, void 0, void 0, function* () { const result = yield axios_1.default({ method: "post", url: this.validatorUrl, data: { txids: txids } }); if (result && result.data) { return result.data; } else { return []; } }); } getRawTransactions(txid) { throw Error("Method not implemented."); } processUtxosForSlp(utxos) { return __awaiter(this, void 0, void 0, function* () { if (this.validator) return yield this.slp.processUtxosForSlpAbstract(utxos, this.validator); return yield this.slp.processUtxosForSlpAbstract(utxos, this); }); } } exports.BitboxNetwork = BitboxNetwork; //# sourceMappingURL=bitboxnetwork.js.map