UNPKG

@atomiqlabs/sdk-lib

Version:

Basic SDK functionality library for atomiq

280 lines (279 loc) 7.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.maxSendable = exports.coinSelect = exports.DUST_THRESHOLDS = void 0; const accumulative_1 = require("./accumulative"); const blackjack_1 = require("./blackjack"); const utils_1 = require("./utils"); Object.defineProperty(exports, "DUST_THRESHOLDS", { enumerable: true, get: function () { return utils_1.DUST_THRESHOLDS; } }); // order by descending value, minus the inputs approximate fee function utxoScore(x, feeRate) { let valueAfterFee = x.value - (feeRate * utils_1.utils.inputBytes(x)); if (x.cpfp != null && x.cpfp.txEffectiveFeeRate < feeRate) valueAfterFee -= x.cpfp.txVsize * (feeRate - x.cpfp.txEffectiveFeeRate); return valueAfterFee; } function coinSelect(utxos, outputs, feeRate, type, requiredInputs) { // order by descending value, minus the inputs approximate fee utxos = utxos.sort((a, b) => { // if(a.cpfp!=null && b.cpfp==null) return 1; // if(a.cpfp==null && b.cpfp!=null) return -1; return utxoScore(b, feeRate) - utxoScore(a, feeRate); }); // attempt to use the blackjack strategy first (no change output) const base = (0, blackjack_1.blackjack)(utxos, outputs, feeRate, type, requiredInputs); if (base.inputs) return base; // else, try the accumulative strategy return (0, accumulative_1.accumulative)(utxos, outputs, feeRate, type, requiredInputs); } exports.coinSelect = coinSelect; function maxSendable(utxos, output, feeRate, requiredInputs, additionalOutputs) { if (!isFinite(utils_1.utils.uintOrNaN(feeRate))) return null; const outputs = additionalOutputs ?? []; const inputs = requiredInputs ?? []; let bytesAccum = utils_1.utils.transactionBytes(inputs, outputs.concat([output]), null); let cpfpAddFee = 0; let inAccum = utils_1.utils.sumOrNaN(inputs); let outAccum = utils_1.utils.sumOrNaN(outputs); for (let i = 0; i < utxos.length; ++i) { const utxo = utxos[i]; const utxoBytes = utils_1.utils.inputBytes(utxo); const utxoFee = feeRate * utxoBytes; let cpfpFee = 0; if (utxo.cpfp != null && utxo.cpfp.txEffectiveFeeRate < feeRate) cpfpFee = utxo.cpfp.txVsize * (feeRate - utxo.cpfp.txEffectiveFeeRate); const utxoValue = utils_1.utils.uintOrNaN(utxo.value); // skip detrimental input if (utxoFee + cpfpFee > utxo.value) { continue; } bytesAccum += utxoBytes; inAccum += utxoValue; cpfpAddFee += cpfpFee; inputs.push(utxo); } const fee = (feeRate * bytesAccum) + cpfpAddFee; const outputValue = inAccum - fee - outAccum; const dustThreshold = utils_1.DUST_THRESHOLDS[output.type]; if (outputValue < dustThreshold) return { fee, value: 0 }; return { fee, value: outputValue }; } exports.maxSendable = maxSendable; // // //Test coinselect // const utxoPool = [ // { // "vout": 3, // "txId": "bacac5f947b808eff4002d2418d18a1a18923543fbb145e751b005899991480a", // "value": 46522, // "type": "p2wpkh", // "outputScript": Buffer.from([ // 0, // 20, // 0, // 33, // 139, // 63, // 90, // 139, // 32, // 245, // 21, // 132, // 7, // 21, // 103, // 231, // 142, // 109, // 179, // 175, // 170, // 26 // ]), // "address": "bc1qqqsck0663vs029vyqu2k0euwdke6l2s6kzvxgn", // "cpfp": { // "txVsize": 292, // "txEffectiveFeeRate": 5.018675721561969 // }, // "confirmed": false // }, // { // "vout": 1, // "txId": "4540b7e587a965594071643012488c6cd5fedfc965bcb0a60687c4c87dc94c1b", // "value": 450, // "type": "p2wpkh", // "outputScript": Buffer.from([ // 0, // 20, // 0, // 33, // 139, // 63, // 90, // 139, // 32, // 245, // 21, // 132, // 7, // 21, // 103, // 231, // 142, // 109, // 179, // 175, // 170, // 26 // ]), // "address": "bc1qqqsck0663vs029vyqu2k0euwdke6l2s6kzvxgn", // "cpfp": null, // "confirmed": true // } // ]; // // const targets = [ // { // "value": 600, // "script": Buffer.from([ // 81, // 32, // 144, // 178, // 224, // 127, // 167, // 6, // 20, // 79, // 80, // 202, // 73, // 78, // 21, // 169, // 135, // 214, // 72, // 214, // 240, // 155, // 185, // 33, // 228, // 90, // 41, // 220, // 8, // 185, // 218, // 110, // 218, // 180 // ]) // }, // { // "value": 0, // "script": Buffer.from([ // 106, // 48, // 4, // 59, // 210, // 45, // 228, // 162, // 208, // 71, // 39, // 68, // 7, // 91, // 150, // 33, // 181, // 190, // 0, // 13, // 213, // 184, // 201, // 204, // 127, // 177, // 159, // 65, // 67, // 12, // 159, // 143, // 234, // 17, // 231, // 117, // 73, // 0, // 0, // 0, // 0, // 0, // 0, // 202, // 154, // 59, // 0, // 0, // 0, // 0 // ]) // }, // { // "value": 10000, // "script": Buffer.from([ // 0, // 20, // 52, // 171, // 216, // 195, // 0, // 15, // 129, // 181, // 100, // 208, // 56, // 16, // 204, // 254, // 43, // 145, // 229, // 169, // 223, // 133 // ]) // } // ]; // // const additionalInputs = [ // { // "txId": "ecddf546c6b637c049b01344f3949e621ec0fb98a06f7e145ea56cc6b2daa3fd", // "vout": 0, // "value": 600, // "type": "p2tr" // } // ]; // // const result = coinSelect(utxoPool as any, targets, 7, "p2wpkh", additionalInputs as any); // // console.log(result);