UNPKG

aladinnetwork-blockstack

Version:

The Aladin Javascript library for authentication, identity, and storage.

194 lines 6.91 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const bitcoinjs_lib_1 = require("bitcoinjs-lib"); const ripemd160_1 = __importDefault(require("ripemd160")); const bn_js_1 = __importDefault(require("bn.js")); const errors_1 = require("../errors"); /** * * @ignore */ exports.DUST_MINIMUM = 5500; /** * * @ignore */ function hash160(buff) { const sha256 = bitcoinjs_lib_1.crypto.sha256(buff); return (new ripemd160_1.default()).update(sha256).digest(); } exports.hash160 = hash160; /** * * @ignore */ function hash128(buff) { return Buffer.from(bitcoinjs_lib_1.crypto.sha256(buff).slice(0, 16)); } exports.hash128 = hash128; // COPIED FROM coinselect, because 1 byte matters sometimes. // baseline estimates, used to improve performance const TX_EMPTY_SIZE = 4 + 1 + 1 + 4; const TX_INPUT_BASE = 32 + 4 + 1 + 4; const TX_INPUT_PUBKEYHASH = 107; const TX_OUTPUT_BASE = 8 + 1; const TX_OUTPUT_PUBKEYHASH = 25; function inputBytes(input) { if (input && input.script && input.script.length > 0) { return TX_INPUT_BASE + input.script.length; } else { return TX_INPUT_BASE + TX_INPUT_PUBKEYHASH; } } function outputBytes(output) { if (output && output.script && output.script.length > 0) { return TX_OUTPUT_BASE + output.script.length; } else { return TX_OUTPUT_BASE + TX_OUTPUT_PUBKEYHASH; } } function transactionBytes(inputs, outputs) { return TX_EMPTY_SIZE + inputs.reduce((a, x) => (a + inputBytes(x)), 0) + outputs.reduce((a, x) => (a + outputBytes(x)), 0); } /** * * @ignore */ function getTransactionInsideBuilder(txBuilder) { return txBuilder.__TX; } exports.getTransactionInsideBuilder = getTransactionInsideBuilder; function getTransaction(txIn) { if (txIn instanceof bitcoinjs_lib_1.Transaction) { return txIn; } return getTransactionInsideBuilder(txIn); } // /** * * @ignore */ function estimateTXBytes(txIn, additionalInputs, additionalOutputs) { const innerTx = getTransaction(txIn); const dummyInputs = new Array(additionalInputs); dummyInputs.fill(null); const dummyOutputs = new Array(additionalOutputs); dummyOutputs.fill(null); const inputs = [].concat(innerTx.ins, dummyInputs); const outputs = [].concat(innerTx.outs, dummyOutputs); return transactionBytes(inputs, outputs); } exports.estimateTXBytes = estimateTXBytes; /** * * @ignore */ function sumOutputValues(txIn) { const innerTx = getTransaction(txIn); return innerTx.outs.reduce((agg, x) => agg + x.value, 0); } exports.sumOutputValues = sumOutputValues; /** * * @ignore */ function decodeB40(input) { // treat input as a base40 integer, and output a hex encoding // of that integer. // // for each digit of the string, find its location in `characters` // to get the value of the digit, then multiply by 40^(-index in input) // e.g., // the 'right-most' character has value: (digit-value) * 40^0 // the next character has value: (digit-value) * 40^1 // // hence, we reverse the characters first, and use the index // to compute the value of each digit, then sum const characters = '0123456789abcdefghijklmnopqrstuvwxyz-_.+'; const base = new bn_js_1.default(40); const inputDigits = input.split('').reverse(); const digitValues = inputDigits.map(((character, exponent) => new bn_js_1.default(characters.indexOf(character)) .mul(base.pow(new bn_js_1.default(exponent))))); const sum = digitValues.reduce((agg, cur) => agg.add(cur), new bn_js_1.default(0)); return sum.toString(16, 2); } exports.decodeB40 = decodeB40; /** * Adds UTXOs to fund a transaction * @param {TransactionBuilder} txBuilderIn - a transaction builder object to add the inputs to. this * object is _always_ mutated. If not enough UTXOs exist to fund, the tx builder object * will still contain as many inputs as could be found. * @param {Array<{value: number, tx_hash: string, tx_output_n}>} utxos - the utxo set for the * payer's address. * @param {number} amountToFund - the amount of satoshis to fund in the transaction. the payer's * utxos will be included to fund up to this amount of *output* and the corresponding *fees* * for those additional inputs * @param {number} feeRate - the satoshis/byte fee rate to use for fee calculation * @param {boolean} fundNewFees - if true, this function will fund `amountToFund` and any new fees * associated with including the new inputs. * if false, this function will fund _at most_ `amountToFund` * @returns {number} - the amount of leftover change (in satoshis) * @private * @ignore */ function addUTXOsToFund(txBuilderIn, utxos, amountToFund, feeRate, fundNewFees = true) { if (utxos.length === 0) { throw new errors_1.NotEnoughFundsError(amountToFund); } // how much are we increasing fees by adding an input ? const newFees = feeRate * (estimateTXBytes(txBuilderIn, 1, 0) - estimateTXBytes(txBuilderIn, 0, 0)); let utxoThreshhold = amountToFund; if (fundNewFees) { utxoThreshhold += newFees; } const goodUtxos = utxos.filter(utxo => utxo.value >= utxoThreshhold); if (goodUtxos.length > 0) { goodUtxos.sort((a, b) => a.value - b.value); const selected = goodUtxos[0]; let change = selected.value - amountToFund; if (fundNewFees) { change -= newFees; } txBuilderIn.addInput(selected.tx_hash, selected.tx_output_n); return change; } else { utxos.sort((a, b) => b.value - a.value); const largest = utxos[0]; if (newFees >= largest.value) { throw new errors_1.NotEnoughFundsError(amountToFund); } txBuilderIn.addInput(largest.tx_hash, largest.tx_output_n); let remainToFund = amountToFund - largest.value; if (fundNewFees) { remainToFund += newFees; } return addUTXOsToFund(txBuilderIn, utxos.slice(1), remainToFund, feeRate, fundNewFees); } } exports.addUTXOsToFund = addUTXOsToFund; function signInputs(txB, defaultSigner, otherSigners) { const txInner = getTransactionInsideBuilder(txB); const signerArray = txInner.ins.map(() => defaultSigner); if (otherSigners) { otherSigners.forEach((signerPair) => { signerArray[signerPair.index] = signerPair.signer; }); } let signingPromise = Promise.resolve(); for (let i = 0; i < txInner.ins.length; i++) { signingPromise = signingPromise.then(() => signerArray[i].signTransaction(txB, i)); } return signingPromise.then(() => txB); } exports.signInputs = signInputs; //# sourceMappingURL=utils.js.map