UNPKG

@bitgo/utxo-ord

Version:

Utilities for building ordinals with BitGo utxo-lib

186 lines 30.4 kB
import { fixedScriptWallet, Dimensions } from '@bitgo/wasm-utxo'; import { OrdOutput } from './OrdOutput'; import { parseSatPoint, parseOutputId } from './SatPoint'; import { SatRange } from './SatRange'; import { getOrdOutputsForLayout, toArray, findOutputLayout } from './OutputLayout'; import { powerset } from './combinations'; const { BitGoPsbt, ChainCode } = fixedScriptWallet; /** * Map utxo-lib network objects to CoinName strings. */ function networkToCoinName(network) { // Bitcoin mainnet if (network.bech32 === 'bc' && network.pubKeyHash === 0) { return 'btc'; } // Bitcoin testnet if (network.bech32 === 'tb' && network.pubKeyHash === 111) { return 'tbtc'; } throw new Error(`Unknown network: ${JSON.stringify(network)}`); } /** * Normalize network parameter - accepts either CoinName string or utxo-lib Network object. */ function normalizeCoinName(networkOrCoinName) { if (typeof networkOrCoinName === 'string') { return networkOrCoinName; } return networkToCoinName(networkOrCoinName); } /** Segwit transaction overhead in virtual bytes */ const TX_SEGWIT_OVERHEAD_VSIZE = 10; export const DefaultInscriptionConstraints = { minChangeOutput: BigInt(10000), minInscriptionOutput: BigInt(10000), maxInscriptionOutput: BigInt(20000), }; export function createPsbtFromOutputLayout(networkOrCoinName, inputBuilder, unspents, outputs, outputLayout) { if (unspents.length === 0) { throw new Error(`must provide at least one unspent`); } const coinName = normalizeCoinName(networkOrCoinName); const psbt = BitGoPsbt.createEmpty(coinName, inputBuilder.walletKeys); // Add inputs unspents.forEach((u) => { const { txid, vout } = parseOutputId(u.id); psbt.addWalletInput({ txid, vout, value: u.value }, inputBuilder.walletKeys, { scriptId: { chain: u.chain, index: u.index }, signPath: { signer: inputBuilder.signer, cosigner: inputBuilder.cosigner }, }); }); // Build ord outputs from layout const ordInput = OrdOutput.joinAll(unspents.map((u) => new OrdOutput(u.value))); const ordOutputs = getOrdOutputsForLayout(ordInput, outputLayout); toArray(ordOutputs).forEach((ordOutput) => { if (ordOutput === null) { return; } switch (ordOutput) { // skip fee output (virtual) case ordOutputs.feeOutput: return; // add padding/change outputs case ordOutputs.firstChangeOutput: case ordOutputs.secondChangeOutput: const { chain, index } = ordOutput === ordOutputs.firstChangeOutput ? outputs.changeOutputs[0] : outputs.changeOutputs[1]; psbt.addWalletOutput(inputBuilder.walletKeys, { chain, index, value: ordOutput.value }); break; // add actual inscription output case ordOutputs.inscriptionOutput: const recipient = outputs.inscriptionRecipient; if (typeof recipient === 'string') { psbt.addOutput(recipient, ordOutput.value); } else if (recipient instanceof Uint8Array) { psbt.addOutput(recipient, ordOutput.value); } else { throw new Error('inscriptionRecipient must be a string or Uint8Array'); } break; } }); return psbt; } function toSatRange(p) { const { offset } = parseSatPoint(p); return new SatRange(offset, offset); } function getFee(vsize, rateSatPerKB) { return BigInt(Math.ceil((vsize * rateSatPerKB) / 1000)); } /** * @param inputs - inscription input must come first * @param satPoint - location of the inscription * @param outputs * @param constraints * @param minimizeInputs */ export function findOutputLayoutForWalletUnspents(inputs, satPoint, outputs, constraints, { minimizeInputs = false } = {}) { if (minimizeInputs) { return findSmallestOutputLayoutForWalletUnspents(inputs, satPoint, outputs, constraints); } if (inputs.length === 0) { throw new Error(`must provide at least one input`); } if (outputs.changeOutputs[0].chain !== outputs.changeOutputs[1].chain) { // otherwise our fee calc is too complicated throw new Error(`wallet outputs must be on same chain`); } const { minChangeOutput = DefaultInscriptionConstraints.minChangeOutput, minInscriptionOutput = DefaultInscriptionConstraints.minInscriptionOutput, maxInscriptionOutput = DefaultInscriptionConstraints.maxInscriptionOutput, } = constraints; // Calculate input vsize using wasm-utxo Dimensions const inputDimensions = inputs.reduce((dims, input) => dims.plus(Dimensions.fromInput({ chain: input.chain })), Dimensions.empty()); const inputsVSize = inputDimensions.getInputVSize(); // Calculate output vsize using wasm-utxo Dimensions const outputDimensions = Dimensions.fromOutput({ scriptType: ChainCode.scriptType(outputs.changeOutputs[0].chain), }); const outputVSize = outputDimensions.getOutputVSize(); // Join all the inputs into a single inscriptionOutput. // For the purposes of finding a layout there is no difference. const inscriptionOutput = OrdOutput.joinAll(inputs.map((i) => new OrdOutput(i.value, i === inputs[0] ? [toSatRange(satPoint)] : []))); const layout = findOutputLayout(inscriptionOutput, { minChangeOutput, minInscriptionOutput, maxInscriptionOutput, feeFixed: getFee(TX_SEGWIT_OVERHEAD_VSIZE + inputsVSize, constraints.feeRateSatKB), feePerOutput: getFee(outputVSize, constraints.feeRateSatKB), }); return layout ? { inputs, layout } : undefined; } export const MAX_UNSPENTS_FOR_OUTPUT_LAYOUT = 5; /** * @param inputs - inscription input must come first * @param satPoint - location of the inscription * @param outputs * @param constraints */ function findSmallestOutputLayoutForWalletUnspents(inputs, satPoint, outputs, constraints) { if (MAX_UNSPENTS_FOR_OUTPUT_LAYOUT < inputs.length) { throw new Error(`input array is too large`); } // create powerset of all supplementary inputs and find the cheapest result const inputsArr = [inputs, ...powerset(inputs.slice(1)).map((s) => [inputs[0], ...s])]; return inputsArr .map((inputs) => findOutputLayoutForWalletUnspents(inputs, satPoint, outputs, constraints)) .reduce((best, next) => { if (best === undefined) { return next; } if (next === undefined) { return best; } return best.layout.feeOutput < next.layout.feeOutput ? best : next; }); } export class ErrorNoLayout extends Error { constructor() { super('Could not find output layout for inscription passing transaction'); } } /** * @param networkOrCoinName - Coin name (e.g., "btc", "tbtc") or utxo-lib Network object * @param inputBuilder * @param unspent * @param satPoint * @param outputs * @param constraints * @param supplementaryUnspents - additional inputs to cover fee. * @param [minimizeInputs=true] - try to find input combination with minimal fees. Limits supplementaryUnspents to 4. */ export function createPsbtForSingleInscriptionPassingTransaction(networkOrCoinName, inputBuilder, unspent, satPoint, outputs, constraints, { supplementaryUnspents = [], minimizeInputs = true, } = {}) { // support for legacy call style if (Array.isArray(unspent)) { if (unspent.length !== 1) { throw new Error(`can only pass single unspent`); } unspent = unspent[0]; } const result = findOutputLayoutForWalletUnspents([unspent, ...supplementaryUnspents], satPoint, outputs, constraints, { minimizeInputs }); if (!result) { throw new ErrorNoLayout(); } return createPsbtFromOutputLayout(networkOrCoinName, inputBuilder, result.inputs, outputs, result.layout); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHNidC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wc2J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxVQUFVLEVBQWlCLE1BQU0sa0JBQWtCLENBQUM7QUFFaEYsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN4QyxPQUFPLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBWSxNQUFNLFlBQVksQ0FBQztBQUNwRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxzQkFBc0IsRUFBZ0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakcsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBSTFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLEdBQUcsaUJBQWlCLENBQUM7QUFhbkQ7O0dBRUc7QUFDSCxTQUFTLGlCQUFpQixDQUFDLE9BQXVCO0lBQ2hELGtCQUFrQjtJQUNsQixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssSUFBSSxJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDeEQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0Qsa0JBQWtCO0lBQ2xCLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxJQUFJLElBQUksT0FBTyxDQUFDLFVBQVUsS0FBSyxHQUFHLEVBQUUsQ0FBQztRQUMxRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQkFBb0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDakUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxpQkFBNEM7SUFDckUsSUFBSSxPQUFPLGlCQUFpQixLQUFLLFFBQVEsRUFBRSxD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QUssQ0FBQyxFQUFFLENBQUM7WUFDekIsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFDRCxPQUFPLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxNQUFNLE1BQU0sR0FBRyxpQ0FBaUMsQ0FDOUMsQ0FBQyxPQUFPLEVBQUUsR0FBRyxxQkFBcUIsQ0FBQyxFQUNuQyxRQUFRLEVBQ1IsT0FBTyxFQUNQLFdBQVcsRUFDWCxFQUFFLGNBQWMsRUFBRSxDQUNuQixDQUFDO0lBRUYsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ1osTUFBTSxJQUFJLGFBQWEsRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFRCxPQUFPLDBCQUEwQixDQUFDLGlCQUFpQixFQUFFLFlBQVksRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDNUcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGZpeGVkU2NyaXB0V2FsbGV0LCBEaW1lbnNpb25zLCB0eXBlIENvaW5OYW1lIH0gZnJvbSAnQGJpdGdvL3dhc20tdXR4byc7XG5cbmltcG9ydCB7IE9yZE91dHB1dCB9IGZyb20gJy4vT3JkT3V0cHV0JztcbmltcG9ydCB7IHBhcnNlU2F0UG9pbnQsIHBhcnNlT3V0cHV0SWQsIFNhdFBvaW50IH0gZnJvbSAnLi9TYXRQb2ludCc7XG5pbXBvcnQgeyBTYXRSYW5nZSB9IGZyb20gJy4vU2F0UmFuZ2UnO1xuaW1wb3J0IHsgZ2V0T3JkT3V0cHV0c0ZvckxheW91dCwgT3V0cHV0TGF5b3V0LCB0b0FycmF5LCBmaW5kT3V0cHV0TGF5b3V0IH0gZnJvbSAnLi9PdXRwdXRMYXlvdXQnO1xuaW1wb3J0IHsgcG93ZXJzZXQgfSBmcm9tICcuL2NvbWJpbmF0aW9ucyc7XG5cbnR5cGUgV2FsbGV0S2V5c0FyZyA9IGZpeGVkU2NyaXB0V2FsbGV0LldhbGxldEtleXNBcmc7XG50eXBlIFNpZ25QYXRoID0gZml4ZWRTY3JpcHRXYWxsZXQuU2lnblBhdGg7XG5jb25zdCB7IEJpdEdvUHNidCwgQ2hhaW5Db2RlIH0gPSBmaXhlZFNjcmlwdFdhbGxldDtcblxuLyoqXG4gKiBOZXR3b3JrIHR5cGUgZnJvbSB1dHhvLWxpYiBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eS5cbiAqL1xudHlwZSBVdHhvbGliTmV0d29yayA9IHtcbiAgbWVzc2FnZVByZWZpeD86IHN0cmluZztcbiAgYmVjaDMyPzogc3RyaW5nO1xuICBwdWJLZXlIYXNoOiBudW1iZXI7XG4gIHNjcmlwdEhhc2g6IG51bWJlcjtcbiAgd2lmOiBudW1iZXI7XG59O1xuXG4vKipcbiAqIE1hcCB1dHhvLWxpYiBuZXR3b3JrIG9iamVjdHMgdG8gQ29pbk5hbWUgc3RyaW5ncy5cbiAqL1xuZnVuY3Rpb24gbmV0d29ya1RvQ29pbk5hbWUobmV0d29yazogVXR4b2xpYk5ldHdvcmspOiBDb2luTmFtZSB7XG4gIC8vIEJpdGNvaW4gbWFpbm5ldFxuICBpZiAobmV0d29yay5iZWNoMzIgPT09ICdiYycgJiYgbmV0d29yay5wdWJLZXlIYXNoID09PSAwKSB7XG4gICAgcmV0dXJuICdidGMnO1xuICB9XG4gIC8vIEJpdGNvaW4gdGVzdG5ldFxuICBpZiAobmV0d29yay5iZWNoMzIgPT09ICd0YicgJiYgbmV0d29yay5wdWJLZXlIYXNoID09PSAxMTEpIHtcbiAgICByZXR1cm4gJ3RidGMnO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBuZXR3b3JrOiAke0pTT04uc3RyaW5naWZ5KG5ldHdvcmspfWApO1xufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSBuZXR3b3JrIHBhcmFtZXRlciAtIGFjY2VwdHMgZWl0aGVyIENvaW5OYW1lIHN0cmluZyBvciB1dHhvLWxpYiBOZXR3b3JrIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplQ29pbk5hbWUobmV0d29ya09yQ29pbk5hbWU6IENvaW5OYW1lIHwgVXR4b2xpYk5ldHdvcmspOiBDb2luTmFtZSB7XG4gIGlmICh0eXBlb2YgbmV0d29ya09yQ29pbk5hbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIG5ldHdvcmtPckNvaW5OYW1lO1xuICB9XG4gIHJldHVybiBuZXR3b3JrVG9Db2luTmFtZShuZXR3b3JrT3JDb2luTmFtZSk7XG59XG5cbi8qKiBTZWd3aXQgdHJhbnNhY3Rpb24gb3ZlcmhlYWQgaW4gdmlydHVhbCBieXRlcyAqL1xuY29uc3QgVFhfU0VHV0lUX09WRVJIRUFEX1ZTSVpFID0gMTA7XG5cbmV4cG9ydCB0eXBlIFdhbGxldFVuc3BlbnQgPSB7XG4gIGlkOiBzdHJpbmc7IC8vIFwidHhpZDp2b3V0XCJcbiAgdmFsdWU6IGJpZ2ludDtcbiAgY2hhaW46IG51bWJlcjtcbiAgaW5kZXg6IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIFdhbGxldE91dHB1dFBhdGggPSB7XG4gIGNoYWluOiBmaXhlZFNjcmlwdFdhbGxldC5DaGFpbkNvZGU7XG4gIGluZGV4OiBudW1iZXI7XG59O1xuXG5leHBvcnQgdHlwZSBXYWxsZXRJbnB1dEJ1aWxkZXIgPSB7XG4gIHdhbGxldEtleXM6IFdhbGxldEtleXNBcmc7XG4gIHNpZ25lcjogU2lnblBhdGhbJ3NpZ25lciddO1xuICBjb3NpZ25lcjogU2lnblBhdGhbJ2Nvc2lnbmVyJ107XG59O1xuXG4vKipcbiAqIERlc2NyaWJlcyBhbGwgb3V0cHV0cyBvZiBhbiBpbnNjcmlwdGlvbiB0cmFuc2FjdGlvblxuICovXG5leHBvcnQgdHlwZSBJbnNjcmlwdGlvblRyYW5zYWN0aW9uT3V0cHV0cyA9IHtcbiAgaW5zY3JpcHRpb25SZWNpcGllbnQ6IHN0cmluZyB8IFVpbnQ4QXJyYXk7XG4gIGNoYW5nZU91dHB1dHM6IFtXYWxsZXRPdXRwdXRQYXRoLCBXYWxsZXRPdXRwdXRQYXRoXTtcbn07XG5cbi8qKiBAZGVwcmVjYXRlZCAqL1xuZXhwb3J0IHR5cGUgSW5zY3JpcHRpb25PdXRwdXRzID0gSW5zY3JpcHRpb25UcmFuc2FjdGlvbk91dHB1dHM7XG5cbmV4cG9ydCB0eXBlIEluc2NyaXB0aW9uVHJhbnNhY3Rpb25Db25zdHJhaW50cyA9IHtcbiAgZmVlUmF0ZVNhdEtCOiBudW1iZXI7XG4gIG1pbkNoYW5nZU91dHB1dD86IGJpZ2ludDtcbiAgbWluSW5zY3JpcHRpb25PdXRwdXQ/OiBiaWdpbnQ7XG4gIG1heEluc2NyaXB0aW9uT3V0cHV0PzogYmlnaW50O1xufTtcblxuZXhwb3J0IGNvbnN0IERlZmF1bHRJbnNjcmlwdGlvbkNvbnN0cmFpbnRzID0ge1xuICBtaW5DaGFuZ2VPdXRwdXQ6IEJpZ0ludCgxMF8wMDApLFxuICBtaW5JbnNjcmlwdGlvbk91dHB1dDogQmlnSW50KDEwXzAwMCksXG4gIG1heEluc2NyaXB0aW9uT3V0cHV0OiBCaWdJbnQoMjBfMDAwKSxcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQc2J0RnJvbU91dHB1dExheW91dChcbiAgbmV0d29ya09yQ29pbk5hbWU6IENvaW5OYW1lIHwgVXR4b2xpYk5ldHdvcmssXG4gIGlucHV0QnVpbGRlcjogV2FsbGV0SW5wdXRCdWlsZGVyLFxuICB1bnNwZW50czogV2FsbGV0VW5zcGVudFtdLFxuICBvdXRwdXRzOiBJbnNjcmlwdGlvblRyYW5zYWN0aW9uT3V0cHV0cyxcbiAgb3V0cHV0TGF5b3V0OiBPdXRwdXRMYXlvdXRcbik6IGZpeGVkU2NyaXB0V2FsbGV0LkJpdEdvUHNidCB7XG4gIGlmICh1bnNwZW50cy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYG11c3QgcHJvdmlkZSBhdCBsZWFzdCBvbmUgdW5zcGVudGApO1xuICB9XG5cbiAgY29uc3QgY29pbk5hbWUgPSBub3JtYWxpemVDb2luTmFtZShuZXR3b3JrT3JDb2luTmFtZSk7XG4gIGNvbnN0IHBzYnQgPSBCaXRHb1BzYnQuY3JlYXRlRW1wdHkoY29pbk5hbWUsIGlucHV0QnVpbGRlci53YWxsZXRLZXlzKTtcblxuICAvLyBBZGQgaW5wdXRzXG4gIHVuc3BlbnRzLmZvckVhY2goKHUpID0+IHtcbiAgICBjb25zdCB7IHR4aWQsIHZvdXQgfSA9IHBhcnNlT3V0cHV0SWQodS5pZCk7XG4gICAgcHNidC5hZGRXYWxsZXRJbnB1dCh7IHR4aWQsIHZvdXQsIHZhbHVlOiB1LnZhbHVlIH0sIGlucHV0QnVpbGRlci53YWxsZXRLZXlzLCB7XG4gICAgICBzY3JpcHRJZDogeyBjaGFpbjogdS5jaGFpbiwgaW5kZXg6IHUuaW5kZXggfSxcbiAgICAgIHNpZ25QYXRoOiB7IHNpZ25lcjogaW5wdXRCdWlsZGVyLnNpZ25lciwgY29zaWduZXI6IGlucHV0QnVpbGRlci5jb3NpZ25lciB9LFxuICAgIH0pO1xuICB9KTtcblxuICAvLyBCdWlsZCBvcmQgb3V0cHV0cyBmcm9tIGxheW91dFxuICBjb25zdCBvcmRJbnB1dCA9IE9yZE91dHB1dC5qb2luQWxsKHVuc3BlbnRzLm1hcCgodSkgPT4gbmV3IE9yZE91dHB1dCh1LnZhbHVlKSkpO1xuICBjb25zdCBvcmRPdXRwdXRzID0gZ2V0T3JkT3V0cHV0c0ZvckxheW91dChvcmRJbnB1dCwgb3V0cHV0TGF5b3V0KTtcblxuICB0b0FycmF5KG9yZE91dHB1dHMpLmZvckVhY2goKG9yZE91dHB1dCkgPT4ge1xuICAgIGlmIChvcmRPdXRwdXQgPT09IG51bGwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgc3dpdGNoIChvcmRPdXRwdXQpIHtcbiAgICAgIC8vIHNraXAgZmVlIG91dHB1dCAodmlydHVhbClcbiAgICAgIGNhc2Ugb3JkT3V0cHV0cy5mZWVPdXRwdXQ6XG4gICAgICAgIHJldHVybjtcbiAgICAgIC8vIGFkZCBwYWRkaW5nL2NoYW5nZSBvdXRwdXRzXG4gICAgICBjYXNlIG9yZE91dHB1dHMuZmlyc3RDaGFuZ2VPdXRwdXQ6XG4gICAgICBjYXNlIG9yZE91dHB1dHMuc2Vjb25kQ2hhbmdlT3V0cHV0OlxuICAgICAgICBjb25zdCB7IGNoYWluLCBpbmRleCB9ID1cbiAgICAgICAgICBvcmRPdXRwdXQgPT09IG9yZE91dHB1dHMuZmlyc3RDaGFuZ2VPdXRwdXQgPyBvdXRwdXRzLmNoYW5nZU91dHB1dHNbMF0gOiBvdXRwdXRzLmNoYW5nZU91dHB1dHNbMV07XG4gICAgICAgIHBzYnQuYWRkV2FsbGV0T3V0cHV0KGlucHV0QnVpbGRlci53YWxsZXRLZXlzLCB7IGNoYWluLCBpbmRleCwgdmFsdWU6IG9yZE91dHB1dC52YWx1ZSB9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyBhZGQgYWN0dWFsIGluc2NyaXB0aW9uIG91dHB1dFxuICAgICAgY2FzZSBvcmRPdXRwdXRzLmluc2NyaXB0aW9uT3V0cHV0OlxuICAgICAgICBjb25zdCByZWNpcGllbnQgPSBvdXRwdXRzLmluc2NyaXB0aW9uUmVjaXBpZW50O1xuICAgICAgICBpZiAodHlwZW9mIHJlY2lwaWVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBwc2J0LmFkZE91dHB1dChyZWNpcGllbnQsIG9yZE91dHB1dC52YWx1ZSk7XG4gICAgICAgIH0gZWxzZSBpZiAocmVjaXBpZW50IGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICAgIHBzYnQuYWRkT3V0cHV0KHJlY2lwaWVudCwgb3JkT3V0cHV0LnZhbHVlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2luc2NyaXB0aW9uUmVjaXBpZW50IG11c3QgYmUgYSBzdHJpbmcgb3IgVWludDhBcnJheScpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHBzYnQ7XG59XG5cbmZ1bmN0aW9uIHRvU2F0UmFuZ2UocDogU2F0UG9pbnQpIHtcbiAgY29uc3QgeyBvZmZzZXQgfSA9IHBhcnNlU2F0UG9pbnQocCk7XG4gIHJldHVybiBuZXcgU2F0UmFuZ2Uob2Zmc2V0LCBvZmZzZXQpO1xufVxuXG5mdW5jdGlvbiBnZXRGZWUodnNpemU6IG51bWJlciwgcmF0ZVNhdFBlcktCOiBudW1iZXIpOiBiaWdpbnQge1xuICByZXR1cm4gQmlnSW50KE1hdGguY2VpbCgodnNpemUgKiByYXRlU2F0UGVyS0IpIC8gMTAwMCkpO1xufVxuXG4vKipcbiAqIEBwYXJhbSBpbnB1dHMgLSBpbnNjcmlwdGlvbiBpbnB1dCBtdXN0IGNvbWUgZmlyc3RcbiAqIEBwYXJhbSBzYXRQb2ludCAtIGxvY2F0aW9uIG9mIHRoZSBpbnNjcmlwdGlvblxuICogQHBhcmFtIG91dHB1dHNcbiAqIEBwYXJhbSBjb25zdHJhaW50c1xuICogQHBhcmFtIG1pbmltaXplSW5wdXRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kT3V0cHV0TGF5b3V0Rm9yV2FsbGV0VW5zcGVudHMoXG4gIGlucHV0czogV2FsbGV0VW5zcGVudFtdLFxuICBzYXRQb2ludDogU2F0UG9pbnQsXG4gIG91dHB1dHM6IEluc2NyaXB0aW9uVHJhbnNhY3Rpb25PdXRwdXRzLFxuICBjb25zdHJhaW50czogSW5zY3JpcHRpb25UcmFuc2FjdGlvbkNvbnN0cmFpbnRzLFxuICB7IG1pbmltaXplSW5wdXRzID0gZmFsc2UgfSA9IHt9XG4pOiB7IGlucHV0czogV2FsbGV0VW5zcGVudFtdOyBsYXlvdXQ6IE91dHB1dExheW91dCB9IHwgdW5kZWZpbmVkIHtcbiAgaWYgKG1pbmltaXplSW5wdXRzKSB7XG4gICAgcmV0dXJuIGZpbmRTbWFsbGVzdE91dHB1dExheW91dEZvcldhbGxldFVuc3BlbnRzKGlucHV0cywgc2F0UG9pbnQsIG91dHB1dHMsIGNvbnN0cmFpbnRzKTtcbiAgfVxuXG4gIGlmIChpbnB1dHMubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBtdXN0IHByb3ZpZGUgYXQgbGVhc3Qgb25lIGlucHV0YCk7XG4gIH1cblxuICBpZiAob3V0cHV0cy5jaGFuZ2VPdXRwdXRzWzBdLmNoYWluICE9PSBvdXRwdXRzLmNoYW5nZU91dHB1dHNbMV0uY2hhaW4pIHtcbiAgICAvLyBvdGhlcndpc2Ugb3VyIGZlZSBjYWxjIGlzIHRvbyBjb21wbGljYXRlZFxuICAgIHRocm93IG5ldyBFcnJvcihgd2FsbGV0IG91dHB1dHMgbXVzdCBiZSBvbiBzYW1lIGNoYWluYCk7XG4gIH1cblxuICBjb25zdCB7XG4gICAgbWluQ2hhbmdlT3V0cHV0ID0gRGVmYXVsdEluc2NyaXB0aW9uQ29uc3RyYWludHMubWluQ2hhbmdlT3V0cHV0LFxuICAgIG1pbkluc2NyaXB0aW9uT3V0cHV0ID0gRGVmYXVsdEluc2NyaXB0aW9uQ29uc3RyYWludHMubWluSW5zY3JpcHRpb25PdXRwdXQsXG4gICAgbWF4SW5zY3JpcHRpb25PdXRwdXQgPSBEZWZhdWx0SW5zY3JpcHRpb25Db25zdHJhaW50cy5tYXhJbnNjcmlwdGlvbk91dHB1dCxcbiAgfSA9IGNvbnN0cmFpbnRzO1xuXG4gIC8vIENhbGN1bGF0ZSBpbnB1dCB2c2l6ZSB1c2luZyB3YXNtLXV0eG8gRGltZW5zaW9uc1xuICBjb25zdCBpbnB1dERpbWVuc2lvbnMgPSBpbnB1dHMucmVkdWNlKFxuICAgIChkaW1zLCBpbnB1dCkgPT4gZGltcy5wbHVzKERpbWVuc2lvbnMuZnJvbUlucHV0KHsgY2hhaW46IGlucHV0LmNoYWluIH0pKSxcbiAgICBEaW1lbnNpb25zLmVtcHR5KClcbiAgKTtcbiAgY29uc3QgaW5wdXRzVlNpemUgPSBpbnB1dERpbWVuc2lvbnMuZ2V0SW5wdXRWU2l6ZSgpO1xuXG4gIC8vIENhbGN1bGF0ZSBvdXRwdXQgdnNpemUgdXNpbmcgd2FzbS11dHhvIERpbWVuc2lvbnNcbiAgY29uc3Qgb3V0cHV0RGltZW5zaW9ucyA9IERpbWVuc2lvbnMuZnJvbU91dHB1dCh7XG4gICAgc2NyaXB0VHlwZTogQ2hhaW5Db2RlLnNjcmlwdFR5cGUob3V0cHV0cy5jaGFuZ2VPdXRwdXRzWzBdLmNoYWluKSxcbiAgfSk7XG4gIGNvbnN0IG91dHB1dFZTaXplID0gb3V0cHV0RGltZW5zaW9ucy5nZXRPdXRwdXRWU2l6ZSgpO1xuXG4gIC8vIEpvaW4gYWxsIHRoZSBpbnB1dHMgaW50byBhIHNpbmdsZSBpbnNjcmlwdGlvbk91dHB1dC5cbiAgLy8gRm9yIHRoZSBwdXJwb3NlcyBvZiBmaW5kaW5nIGEgbGF5b3V0IHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UuXG4gIGNvbnN0IGluc2NyaXB0aW9uT3V0cHV0ID0gT3JkT3V0cHV0LmpvaW5BbGwoXG4gICAgaW5wdXRzLm1hcCgoaSkgPT4gbmV3IE9yZE91dHB1dChpLnZhbHVlLCBpID09PSBpbnB1dHNbMF0gPyBbdG9TYXRSYW5nZShzYXRQb2ludCldIDogW10pKVxuICApO1xuICBjb25zdCBsYXlvdXQgPSBmaW5kT3V0cHV0TGF5b3V0KGluc2NyaXB0aW9uT3V0cHV0LCB7XG4gICAgbWluQ2hhbmdlT3V0cHV0LFxuICAgIG1pbkluc2NyaXB0aW9uT3V0cHV0LFxuICAgIG1heEluc2NyaXB0aW9uT3V0cHV0LFxuICAgIGZlZUZpeGVkOiBnZXRGZWUoVFhfU0VHV0lUX09WRVJIRUFEX1ZTSVpFICsgaW5wdXRzVlNpemUsIGNvbnN0cmFpbnRzLmZlZVJhdGVTYXRLQiksXG4gICAgZmVlUGVyT3V0cHV0OiBnZXRGZWUob3V0cHV0VlNpemUsIGNvbnN0cmFpbnRzLmZlZVJhdGVTYXRLQiksXG4gIH0pO1xuXG4gIHJldHVybiBsYXlvdXQgPyB7IGlucHV0cywgbGF5b3V0IH0gOiB1bmRlZmluZWQ7XG59XG5cbmV4cG9ydCBjb25zdCBNQVhfVU5TUEVOVFNfRk9SX09VVFBVVF9MQVlPVVQgPSA1O1xuXG4vKipcbiAqIEBwYXJhbSBpbnB1dHMgLSBpbnNjcmlwdGlvbiBpbnB1dCBtdXN0IGNvbWUgZmlyc3RcbiAqIEBwYXJhbSBzYXRQb2ludCAtIGxvY2F0aW9uIG9mIHRoZSBpbnNjcmlwdGlvblxuICogQHBhcmFtIG91dHB1dHNcbiAqIEBwYXJhbSBjb25zdHJhaW50c1xuICovXG5mdW5jdGlvbiBmaW5kU21hbGxlc3RPdXRwdXRMYXlvdXRGb3JXYWxsZXRVbnNwZW50cyhcbiAgaW5wdXRzOiBXYWxsZXRVbnNwZW50W10sXG4gIHNhdFBvaW50OiBTYXRQb2ludCxcbiAgb3V0cHV0czogSW5zY3JpcHRpb25UcmFuc2FjdGlvbk91dHB1dHMsXG4gIGNvbnN0cmFpbnRzOiBJbnNjcmlwdGlvblRyYW5zYWN0aW9uQ29uc3RyYWludHNcbik6IHsgaW5wdXRzOiBXYWxsZXRVbnNwZW50W107IGxheW91dDogT3V0cHV0TGF5b3V0IH0gfCB1bmRlZmluZWQge1xuICBpZiAoTUFYX1VOU1BFTlRTX0ZPUl9PVVRQVVRfTEFZT1VUIDwgaW5wdXRzLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgaW5wdXQgYXJyYXkgaXMgdG9vIGxhcmdlYCk7XG4gIH1cbiAgLy8gY3JlYXRlIHBvd2Vyc2V0IG9mIGFsbCBzdXBwbGVtZW50YXJ5IGlucHV0cyBhbmQgZmluZCB0aGUgY2hlYXBlc3QgcmVzdWx0XG4gIGNvbnN0IGlucHV0c0FyciA9IFtpbnB1dHMsIC4uLnBvd2Vyc2V0KGlucHV0cy5zbGljZSgxKSkubWFwKChzKSA9PiBbaW5wdXRzWzBdLCAuLi5zXSldO1xuICByZXR1cm4gaW5wdXRzQXJyXG4gICAgLm1hcCgoaW5wdXRzKSA9PiBmaW5kT3V0cHV0TGF5b3V0Rm9yV2FsbGV0VW5zcGVudHMoaW5wdXRzLCBzYXRQb2ludCwgb3V0cHV0cywgY29uc3RyYWludHMpKVxuICAgIC5yZWR1Y2UoKGJlc3QsIG5leHQpID0+IHtcbiAgICAgIGlmIChiZXN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQ7XG4gICAgICB9XG4gICAgICBpZiAobmV4dCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBiZXN0O1xuICAgICAgfVxuICAgICAgcmV0dXJuIGJlc3QubGF5b3V0LmZlZU91dHB1dCA8IG5leHQubGF5b3V0LmZlZU91dHB1dCA/IGJlc3QgOiBuZXh0O1xuICAgIH0pO1xufVxuXG5leHBvcnQgY2xhc3MgRXJyb3JOb0xheW91dCBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoJ0NvdWxkIG5vdCBmaW5kIG91dHB1dCBsYXlvdXQgZm9yIGluc2NyaXB0aW9uIHBhc3NpbmcgdHJhbnNhY3Rpb24nKTtcbiAgfVxufVxuXG4vKipcbiAqIEBwYXJhbSBuZXR3b3JrT3JDb2luTmFtZSAtIENvaW4gbmFtZSAoZS5nLiwgXCJidGNcIiwgXCJ0YnRjXCIpIG9yIHV0eG8tbGliIE5ldHdvcmsgb2JqZWN0XG4gKiBAcGFyYW0gaW5wdXRCdWlsZGVyXG4gKiBAcGFyYW0gdW5zcGVudFxuICogQHBhcmFtIHNhdFBvaW50XG4gKiBAcGFyYW0gb3V0cHV0c1xuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKiBAcGFyYW0gc3VwcGxlbWVudGFyeVVuc3BlbnRzIC0gYWRkaXRpb25hbCBpbnB1dHMgdG8gY292ZXIgZmVlLlxuICogQHBhcmFtIFttaW5pbWl6ZUlucHV0cz10cnVlXSAtIHRyeSB0byBmaW5kIGlucHV0IGNvbWJpbmF0aW9uIHdpdGggbWluaW1hbCBmZWVzLiBMaW1pdHMgc3VwcGxlbWVudGFyeVVuc3BlbnRzIHRvIDQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQc2J0Rm9yU2luZ2xlSW5zY3JpcHRpb25QYXNzaW5nVHJhbnNhY3Rpb24oXG4gIG5ldHdvcmtPckNvaW5OYW1lOiBDb2luTmFtZSB8IFV0eG9saWJOZXR3b3JrLFxuICBpbnB1dEJ1aWxkZXI6IFdhbGxldElucHV0QnVpbGRlcixcbiAgdW5zcGVudDogV2FsbGV0VW5zcGVudCB8IFdhbGxldFVuc3BlbnRbXSxcbiAgc2F0UG9pbnQ6IFNhdFBvaW50LFxuICBvdXRwdXRzOiBJbnNjcmlwdGlvblRyYW5zYWN0aW9uT3V0cHV0cyxcbiAgY29uc3RyYWludHM6IEluc2NyaXB0aW9uVHJhbnNhY3Rpb25Db25zdHJhaW50cyxcbiAge1xuICAgIHN1cHBsZW1lbnRhcnlVbnNwZW50cyA9IFtdLFxuICAgIG1pbmltaXplSW5wdXRzID0gdHJ1ZSxcbiAgfToge1xuICAgIHN1cHBsZW1lbnRhcnlVbnNwZW50cz86IFdhbGxldFVuc3BlbnRbXTtcbiAgICBtaW5pbWl6ZUlucHV0cz86IGJvb2xlYW47XG4gIH0gPSB7fVxuKTogZml4ZWRTY3JpcHRXYWxsZXQuQml0R29Qc2J0IHtcbiAgLy8gc3VwcG9ydCBmb3IgbGVnYWN5IGNhbGwgc3R5bGVcbiAgaWYgKEFycmF5LmlzQXJyYXkodW5zcGVudCkpIHtcbiAgICBpZiAodW5zcGVudC5sZW5ndGggIT09IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgY2FuIG9ubHkgcGFzcyBzaW5nbGUgdW5zcGVudGApO1xuICAgIH1cbiAgICB1bnNwZW50ID0gdW5zcGVudFswXTtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGZpbmRPdXRwdXRMYXlvdXRGb3JXYWxsZXRVbnNwZW50cyhcbiAgICBbdW5zcGVudCwgLi4uc3VwcGxlbWVudGFyeVVuc3BlbnRzXSxcbiAgICBzYXRQb2ludCxcbiAgICBvdXRwdXRzLFxuICAgIGNvbnN0cmFpbnRzLFxuICAgIHsgbWluaW1pemVJbnB1dHMgfVxuICApO1xuXG4gIGlmICghcmVzdWx0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yTm9MYXlvdXQoKTtcbiAgfVxuXG4gIHJldHVybiBjcmVhdGVQc2J0RnJvbU91dHB1dExheW91dChuZXR3b3JrT3JDb2luTmFtZSwgaW5wdXRCdWlsZGVyLCByZXN1bHQuaW5wdXRzLCBvdXRwdXRzLCByZXN1bHQubGF5b3V0KTtcbn1cbiJdfQ==