bch-slpjs
Version:
Simple Ledger Protocol (SLP) JavaScript Library
271 lines • 12.4 kB
JavaScript
"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