UNPKG

@muirglacier/jellyfish-transaction-builder

Version:

A collection of TypeScript + JavaScript tools and libraries for DeFi Blockchain developers to build decentralized finance for Bitcoin

160 lines 7.26 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 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) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.P2WPKHTxnBuilder = void 0; const jellyfish_transaction_1 = require("@muirglacier/jellyfish-transaction"); const jellyfish_transaction_signature_1 = require("@muirglacier/jellyfish-transaction-signature"); const bignumber_js_1 = __importDefault(require("bignumber.js")); const txn_fee_1 = require("./txn_fee"); const txn_builder_error_1 = require("./txn_builder_error"); const MAX_FEE_RATE = new bignumber_js_1.default('1'); /** * Transaction builder for P2WPKH inputs. */ class P2WPKHTxnBuilder { constructor(feeProvider, prevoutProvider, ellipticPairProvider, network) { this.feeProvider = feeProvider; this.prevoutProvider = prevoutProvider; this.ellipticPairProvider = ellipticPairProvider; this.network = network; } /** * @return {Promise<Prevouts>} */ allPrevouts() { return __awaiter(this, void 0, void 0, function* () { const prevouts = yield this.prevoutProvider.all(); if (prevouts.length === 0) { throw new txn_builder_error_1.TxnBuilderError(txn_builder_error_1.TxnBuilderErrorType.NO_PREVOUTS, 'no prevouts available to create a transaction'); } return joinPrevouts(prevouts); }); } /** * @param {BigNumber} minBalance to collect, required to form a transaction * @return {Promise<Prevouts>} */ collectPrevouts(minBalance) { return __awaiter(this, void 0, void 0, function* () { const prevouts = yield this.prevoutProvider.collect(minBalance); if (prevouts.length === 0) { throw new txn_builder_error_1.TxnBuilderError(txn_builder_error_1.TxnBuilderErrorType.NO_PREVOUTS, 'no prevouts available to create a transaction'); } const joined = joinPrevouts(prevouts); if (minBalance.gt(joined.total)) { throw new txn_builder_error_1.TxnBuilderError(txn_builder_error_1.TxnBuilderErrorType.MIN_BALANCE_NOT_ENOUGH, 'not enough balance after combing all prevouts'); } return joined; }); } /** * @param {Transaction} transaction to calculate P2WPKH fee for * @return {Promise<BigNumber>} fee for transaction */ calculateFee(transaction) { return __awaiter(this, void 0, void 0, function* () { const feeRate = yield this.feeProvider.estimate(); if (MAX_FEE_RATE.lte(feeRate)) { throw new txn_builder_error_1.TxnBuilderError(txn_builder_error_1.TxnBuilderErrorType.OVER_MAX_FEE_RATE, `attempting to use a fee rate higher than MAX_FEE_RATE of ${MAX_FEE_RATE.toFixed()} is not allowed`); } if (!feeRate.isFinite()) { throw new txn_builder_error_1.TxnBuilderError(txn_builder_error_1.TxnBuilderErrorType.INVALID_FEE_RATE, `fee rate ${feeRate.toString()} is invalid`); } return txn_fee_1.calculateFeeP2WPKH(feeRate, transaction); }); } /** * Craft a transaction with OP_DEFI_TX from the output of OP_CODES.OP_DEFI_TX_. * This is a helper method for creating custom defi transactions. * * As DeFi custom transaction will always require small amount of DFI, * collectPrevouts() is set to search for at least 0.001 DFI amount of prevout. * This will also evidently merge small prevout during the operation. * * Do not use this if you don't know what you are doing. You might misplace funds. * * @param {OP_DEFI_TX} opDeFiTx to create * @param {Script} changeScript to send unspent to after deducting the fees * @param {BigNumber} [outValue=0] for the opDeFiTx, usually always be 0. */ createDeFiTx(opDeFiTx, changeScript, outValue = new bignumber_js_1.default('0')) { return __awaiter(this, void 0, void 0, function* () { const minFee = outValue.plus(0.001); // see JSDoc above const { prevouts, vin, total } = yield this.collectPrevouts(minFee); const deFiOut = { value: outValue, script: { stack: [jellyfish_transaction_1.OP_CODES.OP_RETURN, opDeFiTx] }, tokenId: 0x00 }; const change = { value: total, script: changeScript, tokenId: 0x00 }; const txn = { version: jellyfish_transaction_1.DeFiTransactionConstants.Version, vin: vin, vout: [deFiOut, change], lockTime: 0x00000000 }; const fee = yield this.calculateFee(txn); change.value = total.minus(outValue).minus(fee); return yield this.sign(txn, prevouts); }); } /** * @param {Transaction} transaction to sign * @param {Prevout[]} prevouts input to sign */ sign(transaction, prevouts) { return __awaiter(this, void 0, void 0, function* () { const inputs = prevouts.map((prevout) => { const node = this.ellipticPairProvider.get(prevout); return { prevout: prevout, publicKey: () => __awaiter(this, void 0, void 0, function* () { return yield node.publicKey(); }), sign: (hash) => __awaiter(this, void 0, void 0, function* () { return yield node.sign(hash); }) }; }); try { return yield jellyfish_transaction_signature_1.TransactionSigner.sign(transaction, inputs); } catch (err) { throw new txn_builder_error_1.TxnBuilderError(txn_builder_error_1.TxnBuilderErrorType.SIGN_TRANSACTION_ERROR, err.message); } }); } } exports.P2WPKHTxnBuilder = P2WPKHTxnBuilder; /** * @param {Prevout[]} prevouts to join * @return {Prevouts} */ function joinPrevouts(prevouts) { const vin = prevouts.map((prevout) => { return { txid: prevout.txid, index: prevout.vout, script: { stack: [] }, sequence: 0xffffffff }; }); const total = prevouts .map(out => out.value) .reduce((a, b) => a.plus(b), new bignumber_js_1.default(0)); return { prevouts, vin, total }; } //# sourceMappingURL=txn_builder.js.map