@bitgo/utxo-ord
Version:
Utilities for building ordinals with BitGo utxo-lib
193 lines • 30.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorNoLayout = exports.MAX_UNSPENTS_FOR_OUTPUT_LAYOUT = exports.DefaultInscriptionConstraints = void 0;
exports.createPsbtFromOutputLayout = createPsbtFromOutputLayout;
exports.findOutputLayoutForWalletUnspents = findOutputLayoutForWalletUnspents;
exports.createPsbtForSingleInscriptionPassingTransaction = createPsbtForSingleInscriptionPassingTransaction;
const wasm_utxo_1 = require("@bitgo/wasm-utxo");
const OrdOutput_1 = require("./OrdOutput");
const SatPoint_1 = require("./SatPoint");
const SatRange_1 = require("./SatRange");
const OutputLayout_1 = require("./OutputLayout");
const combinations_1 = require("./combinations");
const { BitGoPsbt, ChainCode } = wasm_utxo_1.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;
exports.DefaultInscriptionConstraints = {
minChangeOutput: BigInt(10000),
minInscriptionOutput: BigInt(10000),
maxInscriptionOutput: BigInt(20000),
};
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 } = (0, SatPoint_1.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_1.OrdOutput.joinAll(unspents.map((u) => new OrdOutput_1.OrdOutput(u.value)));
const ordOutputs = (0, OutputLayout_1.getOrdOutputsForLayout)(ordInput, outputLayout);
(0, OutputLayout_1.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 } = (0, SatPoint_1.parseSatPoint)(p);
return new SatRange_1.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
*/
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 = exports.DefaultInscriptionConstraints.minChangeOutput, minInscriptionOutput = exports.DefaultInscriptionConstraints.minInscriptionOutput, maxInscriptionOutput = exports.DefaultInscriptionConstraints.maxInscriptionOutput, } = constraints;
// Calculate input vsize using wasm-utxo Dimensions
const inputDimensions = inputs.reduce((dims, input) => dims.plus(wasm_utxo_1.Dimensions.fromInput({ chain: input.chain })), wasm_utxo_1.Dimensions.empty());
const inputsVSize = inputDimensions.getInputVSize();
// Calculate output vsize using wasm-utxo Dimensions
const outputDimensions = wasm_utxo_1.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_1.OrdOutput.joinAll(inputs.map((i) => new OrdOutput_1.OrdOutput(i.value, i === inputs[0] ? [toSatRange(satPoint)] : [])));
const layout = (0, OutputLayout_1.findOutputLayout)(inscriptionOutput, {
minChangeOutput,
minInscriptionOutput,
maxInscriptionOutput,
feeFixed: getFee(TX_SEGWIT_OVERHEAD_VSIZE + inputsVSize, constraints.feeRateSatKB),
feePerOutput: getFee(outputVSize, constraints.feeRateSatKB),
});
return layout ? { inputs, layout } : undefined;
}
exports.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 (exports.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, ...(0, combinations_1.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;
});
}
class ErrorNoLayout extends Error {
constructor() {
super('Could not find output layout for inscription passing transaction');
}
}
exports.ErrorNoLayout = ErrorNoLayout;
/**
* @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.
*/
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHNidC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wc2J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQTZGQSxnRUF5REM7QUFrQkQsOEVBcURDO0FBa0RELDRHQW9DQztBQW5URCxnREFBZ0Y7QUFFaEYsMkNBQXdDO0FBQ3hDLHlDQUFvRTtBQUNwRSx5Q0FBc0M7QUFDdEMsaURBQWlHO0FBQ2pHLGlEQUEwQztBQUkxQyxNQUFNLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxHQUFHLDZCQUFpQixDQUFDO0FBYW5EOztHQUVHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxPQUF1QjtJQUNoRCxrQkFBa0I7SUFDbEIsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLElBQUksSUFBSSxPQUFPLENBQUMsVUFBVSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3hELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUNELGtCQUFrQjtJQUNsQixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssSUFBSSxJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssR0FBRyxFQUFFLENBQUM7UUFDMUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ2pFLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsaUJBQTRDO0lBQ3JFLElBQUksT0FBTyxpQkFBaUIsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUMxQyxPQUFPLGlCQUFpQixDQUFDO0lBQzNCLENBQUM7SUFDRCxPQUFPLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVELG1EQUFtRDtBQUNuRCxNQUFNLHdCQUF3QixHQUFHLEVBQUUsQ0FBQztBQXNDdkIsUUFBQSw2QkFBNkIsR0FBRztJQUMzQyxlQUFlLEVBQUUsTUFB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LE9BQU8sRUFBRSxHQUFHLHFCQUFxQixDQUFDLEVBQ25DLFFBQVEsRUFDUixPQUFPLEVBQ1AsV0FBVyxFQUNYLEVBQUUsY0FBYyxFQUFFLENBQ25CLENBQUM7SUFFRixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixNQUFNLElBQUksYUFBYSxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVELE9BQU8sMEJBQTBCLENBQUMsaUJBQWlCLEVBQUUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM1RyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZml4ZWRTY3JpcHRXYWxsZXQsIERpbWVuc2lvbnMsIHR5cGUgQ29pbk5hbWUgfSBmcm9tICdAYml0Z28vd2FzbS11dHhvJztcblxuaW1wb3J0IHsgT3JkT3V0cHV0IH0gZnJvbSAnLi9PcmRPdXRwdXQnO1xuaW1wb3J0IHsgcGFyc2VTYXRQb2ludCwgcGFyc2VPdXRwdXRJZCwgU2F0UG9pbnQgfSBmcm9tICcuL1NhdFBvaW50JztcbmltcG9ydCB7IFNhdFJhbmdlIH0gZnJvbSAnLi9TYXRSYW5nZSc7XG5pbXBvcnQgeyBnZXRPcmRPdXRwdXRzRm9yTGF5b3V0LCBPdXRwdXRMYXlvdXQsIHRvQXJyYXksIGZpbmRPdXRwdXRMYXlvdXQgfSBmcm9tICcuL091dHB1dExheW91dCc7XG5pbXBvcnQgeyBwb3dlcnNldCB9IGZyb20gJy4vY29tYmluYXRpb25zJztcblxudHlwZSBXYWxsZXRLZXlzQXJnID0gZml4ZWRTY3JpcHRXYWxsZXQuV2FsbGV0S2V5c0FyZztcbnR5cGUgU2lnblBhdGggPSBmaXhlZFNjcmlwdFdhbGxldC5TaWduUGF0aDtcbmNvbnN0IHsgQml0R29Qc2J0LCBDaGFpbkNvZGUgfSA9IGZpeGVkU2NyaXB0V2FsbGV0O1xuXG4vKipcbiAqIE5ldHdvcmsgdHlwZSBmcm9tIHV0eG8tbGliIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5LlxuICovXG50eXBlIFV0eG9saWJOZXR3b3JrID0ge1xuICBtZXNzYWdlUHJlZml4Pzogc3RyaW5nO1xuICBiZWNoMzI/OiBzdHJpbmc7XG4gIHB1YktleUhhc2g6IG51bWJlcjtcbiAgc2NyaXB0SGFzaDogbnVtYmVyO1xuICB3aWY6IG51bWJlcjtcbn07XG5cbi8qKlxuICogTWFwIHV0eG8tbGliIG5ldHdvcmsgb2JqZWN0cyB0byBDb2luTmFtZSBzdHJpbmdzLlxuICovXG5mdW5jdGlvbiBuZXR3b3JrVG9Db2luTmFtZShuZXR3b3JrOiBVdHhvbGliTmV0d29yayk6IENvaW5OYW1lIHtcbiAgLy8gQml0Y29pbiBtYWlubmV0XG4gIGlmIChuZXR3b3JrLmJlY2gzMiA9PT0gJ2JjJyAmJiBuZXR3b3JrLnB1YktleUhhc2ggPT09IDApIHtcbiAgICByZXR1cm4gJ2J0Yyc7XG4gIH1cbiAgLy8gQml0Y29pbiB0ZXN0bmV0XG4gIGlmIChuZXR3b3JrLmJlY2gzMiA9PT0gJ3RiJyAmJiBuZXR3b3JrLnB1YktleUhhc2ggPT09IDExMSkge1xuICAgIHJldHVybiAndGJ0Yyc7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG5ldHdvcms6ICR7SlNPTi5zdHJpbmdpZnkobmV0d29yayl9YCk7XG59XG5cbi8qKlxuICogTm9ybWFsaXplIG5ldHdvcmsgcGFyYW1ldGVyIC0gYWNjZXB0cyBlaXRoZXIgQ29pbk5hbWUgc3RyaW5nIG9yIHV0eG8tbGliIE5ldHdvcmsgb2JqZWN0LlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVDb2luTmFtZShuZXR3b3JrT3JDb2luTmFtZTogQ29pbk5hbWUgfCBVdHhvbGliTmV0d29yayk6IENvaW5OYW1lIHtcbiAgaWYgKHR5cGVvZiBuZXR3b3JrT3JDb2luTmFtZSA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gbmV0d29ya09yQ29pbk5hbWU7XG4gIH1cbiAgcmV0dXJuIG5ldHdvcmtUb0NvaW5OYW1lKG5ldHdvcmtPckNvaW5OYW1lKTtcbn1cblxuLyoqIFNlZ3dpdCB0cmFuc2FjdGlvbiBvdmVyaGVhZCBpbiB2aXJ0dWFsIGJ5dGVzICovXG5jb25zdCBUWF9TRUdXSVRfT1ZFUkhFQURfVlNJWkUgPSAxMDtcblxuZXhwb3J0IHR5cGUgV2FsbGV0VW5zcGVudCA9IHtcbiAgaWQ6IHN0cmluZzsgLy8gXCJ0eGlkOnZvdXRcIlxuICB2YWx1ZTogYmlnaW50O1xuICBjaGFpbjogbnVtYmVyO1xuICBpbmRleDogbnVtYmVyO1xufTtcblxuZXhwb3J0IHR5cGUgV2FsbGV0T3V0cHV0UGF0aCA9IHtcbiAgY2hhaW46IGZpeGVkU2NyaXB0V2FsbGV0LkNoYWluQ29kZTtcbiAgaW5kZXg6IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIFdhbGxldElucHV0QnVpbGRlciA9IHtcbiAgd2FsbGV0S2V5czogV2FsbGV0S2V5c0FyZztcbiAgc2lnbmVyOiBTaWduUGF0aFsnc2lnbmVyJ107XG4gIGNvc2lnbmVyOiBTaWduUGF0aFsnY29zaWduZXInXTtcbn07XG5cbi8qKlxuICogRGVzY3JpYmVzIGFsbCBvdXRwdXRzIG9mIGFuIGluc2NyaXB0aW9uIHRyYW5zYWN0aW9uXG4gKi9cbmV4cG9ydCB0eXBlIEluc2NyaXB0aW9uVHJhbnNhY3Rpb25PdXRwdXRzID0ge1xuICBpbnNjcmlwdGlvblJlY2lwaWVudDogc3RyaW5nIHwgVWludDhBcnJheTtcbiAgY2hhbmdlT3V0cHV0czogW1dhbGxldE91dHB1dFBhdGgsIFdhbGxldE91dHB1dFBhdGhdO1xufTtcblxuLyoqIEBkZXByZWNhdGVkICovXG5leHBvcnQgdHlwZSBJbnNjcmlwdGlvbk91dHB1dHMgPSBJbnNjcmlwdGlvblRyYW5zYWN0aW9uT3V0cHV0cztcblxuZXhwb3J0IHR5cGUgSW5zY3JpcHRpb25UcmFuc2FjdGlvbkNvbnN0cmFpbnRzID0ge1xuICBmZWVSYXRlU2F0S0I6IG51bWJlcjtcbiAgbWluQ2hhbmdlT3V0cHV0PzogYmlnaW50O1xuICBtaW5JbnNjcmlwdGlvbk91dHB1dD86IGJpZ2ludDtcbiAgbWF4SW5zY3JpcHRpb25PdXRwdXQ/OiBiaWdpbnQ7XG59O1xuXG5leHBvcnQgY29uc3QgRGVmYXVsdEluc2NyaXB0aW9uQ29uc3RyYWludHMgPSB7XG4gIG1pbkNoYW5nZU91dHB1dDogQmlnSW50KDEwXzAwMCksXG4gIG1pbkluc2NyaXB0aW9uT3V0cHV0OiBCaWdJbnQoMTBfMDAwKSxcbiAgbWF4SW5zY3JpcHRpb25PdXRwdXQ6IEJpZ0ludCgyMF8wMDApLFxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVBzYnRGcm9tT3V0cHV0TGF5b3V0KFxuICBuZXR3b3JrT3JDb2luTmFtZTogQ29pbk5hbWUgfCBVdHhvbGliTmV0d29yayxcbiAgaW5wdXRCdWlsZGVyOiBXYWxsZXRJbnB1dEJ1aWxkZXIsXG4gIHVuc3BlbnRzOiBXYWxsZXRVbnNwZW50W10sXG4gIG91dHB1dHM6IEluc2NyaXB0aW9uVHJhbnNhY3Rpb25PdXRwdXRzLFxuICBvdXRwdXRMYXlvdXQ6IE91dHB1dExheW91dFxuKTogZml4ZWRTY3JpcHRXYWxsZXQuQml0R29Qc2J0IHtcbiAgaWYgKHVuc3BlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgbXVzdCBwcm92aWRlIGF0IGxlYXN0IG9uZSB1bnNwZW50YCk7XG4gIH1cblxuICBjb25zdCBjb2luTmFtZSA9IG5vcm1hbGl6ZUNvaW5OYW1lKG5ldHdvcmtPckNvaW5OYW1lKTtcbiAgY29uc3QgcHNidCA9IEJpdEdvUHNidC5jcmVhdGVFbXB0eShjb2luTmFtZSwgaW5wdXRCdWlsZGVyLndhbGxldEtleXMpO1xuXG4gIC8vIEFkZCBpbnB1dHNcbiAgdW5zcGVudHMuZm9yRWFjaCgodSkgPT4ge1xuICAgIGNvbnN0IHsgdHhpZCwgdm91dCB9ID0gcGFyc2VPdXRwdXRJZCh1LmlkKTtcbiAgICBwc2J0LmFkZFdhbGxldElucHV0KHsgdHhpZCwgdm91dCwgdmFsdWU6IHUudmFsdWUgfSwgaW5wdXRCdWlsZGVyLndhbGxldEtleXMsIHtcbiAgICAgIHNjcmlwdElkOiB7IGNoYWluOiB1LmNoYWluLCBpbmRleDogdS5pbmRleCB9LFxuICAgICAgc2lnblBhdGg6IHsgc2lnbmVyOiBpbnB1dEJ1aWxkZXIuc2lnbmVyLCBjb3NpZ25lcjogaW5wdXRCdWlsZGVyLmNvc2lnbmVyIH0sXG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vIEJ1aWxkIG9yZCBvdXRwdXRzIGZyb20gbGF5b3V0XG4gIGNvbnN0IG9yZElucHV0ID0gT3JkT3V0cHV0LmpvaW5BbGwodW5zcGVudHMubWFwKCh1KSA9PiBuZXcgT3JkT3V0cHV0KHUudmFsdWUpKSk7XG4gIGNvbnN0IG9yZE91dHB1dHMgPSBnZXRPcmRPdXRwdXRzRm9yTGF5b3V0KG9yZElucHV0LCBvdXRwdXRMYXlvdXQpO1xuXG4gIHRvQXJyYXkob3JkT3V0cHV0cykuZm9yRWFjaCgob3JkT3V0cHV0KSA9PiB7XG4gICAgaWYgKG9yZE91dHB1dCA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBzd2l0Y2ggKG9yZE91dHB1dCkge1xuICAgICAgLy8gc2tpcCBmZWUgb3V0cHV0ICh2aXJ0dWFsKVxuICAgICAgY2FzZSBvcmRPdXRwdXRzLmZlZU91dHB1dDpcbiAgICAgICAgcmV0dXJuO1xuICAgICAgLy8gYWRkIHBhZGRpbmcvY2hhbmdlIG91dHB1dHNcbiAgICAgIGNhc2Ugb3JkT3V0cHV0cy5maXJzdENoYW5nZU91dHB1dDpcbiAgICAgIGNhc2Ugb3JkT3V0cHV0cy5zZWNvbmRDaGFuZ2VPdXRwdXQ6XG4gICAgICAgIGNvbnN0IHsgY2hhaW4sIGluZGV4IH0gPVxuICAgICAgICAgIG9yZE91dHB1dCA9PT0gb3JkT3V0cHV0cy5maXJzdENoYW5nZU91dHB1dCA/IG91dHB1dHMuY2hhbmdlT3V0cHV0c1swXSA6IG91dHB1dHMuY2hhbmdlT3V0cHV0c1sxXTtcbiAgICAgICAgcHNidC5hZGRXYWxsZXRPdXRwdXQoaW5wdXRCdWlsZGVyLndhbGxldEtleXMsIHsgY2hhaW4sIGluZGV4LCB2YWx1ZTogb3JkT3V0cHV0LnZhbHVlIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIC8vIGFkZCBhY3R1YWwgaW5zY3JpcHRpb24gb3V0cHV0XG4gICAgICBjYXNlIG9yZE91dHB1dHMuaW5zY3JpcHRpb25PdXRwdXQ6XG4gICAgICAgIGNvbnN0IHJlY2lwaWVudCA9IG91dHB1dHMuaW5zY3JpcHRpb25SZWNpcGllbnQ7XG4gICAgICAgIGlmICh0eXBlb2YgcmVjaXBpZW50ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIHBzYnQuYWRkT3V0cHV0KHJlY2lwaWVudCwgb3JkT3V0cHV0LnZhbHVlKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZWNpcGllbnQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICAgICAgcHNidC5hZGRPdXRwdXQocmVjaXBpZW50LCBvcmRPdXRwdXQudmFsdWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignaW5zY3JpcHRpb25SZWNpcGllbnQgbXVzdCBiZSBhIHN0cmluZyBvciBVaW50OEFycmF5Jyk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4gcHNidDtcbn1cblxuZnVuY3Rpb24gdG9TYXRSYW5nZShwOiBTYXRQb2ludCkge1xuICBjb25zdCB7IG9mZnNldCB9ID0gcGFyc2VTYXRQb2ludChwKTtcbiAgcmV0dXJuIG5ldyBTYXRSYW5nZShvZmZzZXQsIG9mZnNldCk7XG59XG5cbmZ1bmN0aW9uIGdldEZlZSh2c2l6ZTogbnVtYmVyLCByYXRlU2F0UGVyS0I6IG51bWJlcik6IGJpZ2ludCB7XG4gIHJldHVybiBCaWdJbnQoTWF0aC5jZWlsKCh2c2l6ZSAqIHJhdGVTYXRQZXJLQikgLyAxMDAwKSk7XG59XG5cbi8qKlxuICogQHBhcmFtIGlucHV0cyAtIGluc2NyaXB0aW9uIGlucHV0IG11c3QgY29tZSBmaXJzdFxuICogQHBhcmFtIHNhdFBvaW50IC0gbG9jYXRpb24gb2YgdGhlIGluc2NyaXB0aW9uXG4gKiBAcGFyYW0gb3V0cHV0c1xuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKiBAcGFyYW0gbWluaW1pemVJbnB1dHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRPdXRwdXRMYXlvdXRGb3JXYWxsZXRVbnNwZW50cyhcbiAgaW5wdXRzOiBXYWxsZXRVbnNwZW50W10sXG4gIHNhdFBvaW50OiBTYXRQb2ludCxcbiAgb3V0cHV0czogSW5zY3JpcHRpb25UcmFuc2FjdGlvbk91dHB1dHMsXG4gIGNvbnN0cmFpbnRzOiBJbnNjcmlwdGlvblRyYW5zYWN0aW9uQ29uc3RyYWludHMsXG4gIHsgbWluaW1pemVJbnB1dHMgPSBmYWxzZSB9ID0ge31cbik6IHsgaW5wdXRzOiBXYWxsZXRVbnNwZW50W107IGxheW91dDogT3V0cHV0TGF5b3V0IH0gfCB1bmRlZmluZWQge1xuICBpZiAobWluaW1pemVJbnB1dHMpIHtcbiAgICByZXR1cm4gZmluZFNtYWxsZXN0T3V0cHV0TGF5b3V0Rm9yV2FsbGV0VW5zcGVudHMoaW5wdXRzLCBzYXRQb2ludCwgb3V0cHV0cywgY29uc3RyYWludHMpO1xuICB9XG5cbiAgaWYgKGlucHV0cy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYG11c3QgcHJvdmlkZSBhdCBsZWFzdCBvbmUgaW5wdXRgKTtcbiAgfVxuXG4gIGlmIChvdXRwdXRzLmNoYW5nZU91dHB1dHNbMF0uY2hhaW4gIT09IG91dHB1dHMuY2hhbmdlT3V0cHV0c1sxXS5jaGFpbikge1xuICAgIC8vIG90aGVyd2lzZSBvdXIgZmVlIGNhbGMgaXMgdG9vIGNvbXBsaWNhdGVkXG4gICAgdGhyb3cgbmV3IEVycm9yKGB3YWxsZXQgb3V0cHV0cyBtdXN0IGJlIG9uIHNhbWUgY2hhaW5gKTtcbiAgfVxuXG4gIGNvbnN0IHtcbiAgICBtaW5DaGFuZ2VPdXRwdXQgPSBEZWZhdWx0SW5zY3JpcHRpb25Db25zdHJhaW50cy5taW5DaGFuZ2VPdXRwdXQsXG4gICAgbWluSW5zY3JpcHRpb25PdXRwdXQgPSBEZWZhdWx0SW5zY3JpcHRpb25Db25zdHJhaW50cy5taW5JbnNjcmlwdGlvbk91dHB1dCxcbiAgICBtYXhJbnNjcmlwdGlvbk91dHB1dCA9IERlZmF1bHRJbnNjcmlwdGlvbkNvbnN0cmFpbnRzLm1heEluc2NyaXB0aW9uT3V0cHV0LFxuICB9ID0gY29uc3RyYWludHM7XG5cbiAgLy8gQ2FsY3VsYXRlIGlucHV0IHZzaXplIHVzaW5nIHdhc20tdXR4byBEaW1lbnNpb25zXG4gIGNvbnN0IGlucHV0RGltZW5zaW9ucyA9IGlucHV0cy5yZWR1Y2UoXG4gICAgKGRpbXMsIGlucHV0KSA9PiBkaW1zLnBsdXMoRGltZW5zaW9ucy5mcm9tSW5wdXQoeyBjaGFpbjogaW5wdXQuY2hhaW4gfSkpLFxuICAgIERpbWVuc2lvbnMuZW1wdHkoKVxuICApO1xuICBjb25zdCBpbnB1dHNWU2l6ZSA9IGlucHV0RGltZW5zaW9ucy5nZXRJbnB1dFZTaXplKCk7XG5cbiAgLy8gQ2FsY3VsYXRlIG91dHB1dCB2c2l6ZSB1c2luZyB3YXNtLXV0eG8gRGltZW5zaW9uc1xuICBjb25zdCBvdXRwdXREaW1lbnNpb25zID0gRGltZW5zaW9ucy5mcm9tT3V0cHV0KHtcbiAgICBzY3JpcHRUeXBlOiBDaGFpbkNvZGUuc2NyaXB0VHlwZShvdXRwdXRzLmNoYW5nZU91dHB1dHNbMF0uY2hhaW4pLFxuICB9KTtcbiAgY29uc3Qgb3V0cHV0VlNpemUgPSBvdXRwdXREaW1lbnNpb25zLmdldE91dHB1dFZTaXplKCk7XG5cbiAgLy8gSm9pbiBhbGwgdGhlIGlucHV0cyBpbnRvIGEgc2luZ2xlIGluc2NyaXB0aW9uT3V0cHV0LlxuICAvLyBGb3IgdGhlIHB1cnBvc2VzIG9mIGZpbmRpbmcgYSBsYXlvdXQgdGhlcmUgaXMgbm8gZGlmZmVyZW5jZS5cbiAgY29uc3QgaW5zY3JpcHRpb25PdXRwdXQgPSBPcmRPdXRwdXQuam9pbkFsbChcbiAgICBpbnB1dHMubWFwKChpKSA9PiBuZXcgT3JkT3V0cHV0KGkudmFsdWUsIGkgPT09IGlucHV0c1swXSA/IFt0b1NhdFJhbmdlKHNhdFBvaW50KV0gOiBbXSkpXG4gICk7XG4gIGNvbnN0IGxheW91dCA9IGZpbmRPdXRwdXRMYXlvdXQoaW5zY3JpcHRpb25PdXRwdXQsIHtcbiAgICBtaW5DaGFuZ2VPdXRwdXQsXG4gICAgbWluSW5zY3JpcHRpb25PdXRwdXQsXG4gICAgbWF4SW5zY3JpcHRpb25PdXRwdXQsXG4gICAgZmVlRml4ZWQ6IGdldEZlZShUWF9TRUdXSVRfT1ZFUkhFQURfVlNJWkUgKyBpbnB1dHNWU2l6ZSwgY29uc3RyYWludHMuZmVlUmF0ZVNhdEtCKSxcbiAgICBmZWVQZXJPdXRwdXQ6IGdldEZlZShvdXRwdXRWU2l6ZSwgY29uc3RyYWludHMuZmVlUmF0ZVNhdEtCKSxcbiAgfSk7XG5cbiAgcmV0dXJuIGxheW91dCA/IHsgaW5wdXRzLCBsYXlvdXQgfSA6IHVuZGVmaW5lZDtcbn1cblxuZXhwb3J0IGNvbnN0IE1BWF9VTlNQRU5UU19GT1JfT1VUUFVUX0xBWU9VVCA9IDU7XG5cbi8qKlxuICogQHBhcmFtIGlucHV0cyAtIGluc2NyaXB0aW9uIGlucHV0IG11c3QgY29tZSBmaXJzdFxuICogQHBhcmFtIHNhdFBvaW50IC0gbG9jYXRpb24gb2YgdGhlIGluc2NyaXB0aW9uXG4gKiBAcGFyYW0gb3V0cHV0c1xuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKi9cbmZ1bmN0aW9uIGZpbmRTbWFsbGVzdE91dHB1dExheW91dEZvcldhbGxldFVuc3BlbnRzKFxuICBpbnB1dHM6IFdhbGxldFVuc3BlbnRbXSxcbiAgc2F0UG9pbnQ6IFNhdFBvaW50LFxuICBvdXRwdXRzOiBJbnNjcmlwdGlvblRyYW5zYWN0aW9uT3V0cHV0cyxcbiAgY29uc3RyYWludHM6IEluc2NyaXB0aW9uVHJhbnNhY3Rpb25Db25zdHJhaW50c1xuKTogeyBpbnB1dHM6IFdhbGxldFVuc3BlbnRbXTsgbGF5b3V0OiBPdXRwdXRMYXlvdXQgfSB8IHVuZGVmaW5lZCB7XG4gIGlmIChNQVhfVU5TUEVOVFNfRk9SX09VVFBVVF9MQVlPVVQgPCBpbnB1dHMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBpbnB1dCBhcnJheSBpcyB0b28gbGFyZ2VgKTtcbiAgfVxuICAvLyBjcmVhdGUgcG93ZXJzZXQgb2YgYWxsIHN1cHBsZW1lbnRhcnkgaW5wdXRzIGFuZCBmaW5kIHRoZSBjaGVhcGVzdCByZXN1bHRcbiAgY29uc3QgaW5wdXRzQXJyID0gW2lucHV0cywgLi4ucG93ZXJzZXQoaW5wdXRzLnNsaWNlKDEpKS5tYXAoKHMpID0+IFtpbnB1dHNbMF0sIC4uLnNdKV07XG4gIHJldHVybiBpbnB1dHNBcnJcbiAgICAubWFwKChpbnB1dHMpID0+IGZpbmRPdXRwdXRMYXlvdXRGb3JXYWxsZXRVbnNwZW50cyhpbnB1dHMsIHNhdFBvaW50LCBvdXRwdXRzLCBjb25zdHJhaW50cykpXG4gICAgLnJlZHVjZSgoYmVzdCwgbmV4dCkgPT4ge1xuICAgICAgaWYgKGJlc3QgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gbmV4dDtcbiAgICAgIH1cbiAgICAgIGlmIChuZXh0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIGJlc3Q7XG4gICAgICB9XG4gICAgICByZXR1cm4gYmVzdC5sYXlvdXQuZmVlT3V0cHV0IDwgbmV4dC5sYXlvdXQuZmVlT3V0cHV0ID8gYmVzdCA6IG5leHQ7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBjbGFzcyBFcnJvck5vTGF5b3V0IGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcignQ291bGQgbm90IGZpbmQgb3V0cHV0IGxheW91dCBmb3IgaW5zY3JpcHRpb24gcGFzc2luZyB0cmFuc2FjdGlvbicpO1xuICB9XG59XG5cbi8qKlxuICogQHBhcmFtIG5ldHdvcmtPckNvaW5OYW1lIC0gQ29pbiBuYW1lIChlLmcuLCBcImJ0Y1wiLCBcInRidGNcIikgb3IgdXR4by1saWIgTmV0d29yayBvYmplY3RcbiAqIEBwYXJhbSBpbnB1dEJ1aWxkZXJcbiAqIEBwYXJhbSB1bnNwZW50XG4gKiBAcGFyYW0gc2F0UG9pbnRcbiAqIEBwYXJhbSBvdXRwdXRzXG4gKiBAcGFyYW0gY29uc3RyYWludHNcbiAqIEBwYXJhbSBzdXBwbGVtZW50YXJ5VW5zcGVudHMgLSBhZGRpdGlvbmFsIGlucHV0cyB0byBjb3ZlciBmZWUuXG4gKiBAcGFyYW0gW21pbmltaXplSW5wdXRzPXRydWVdIC0gdHJ5IHRvIGZpbmQgaW5wdXQgY29tYmluYXRpb24gd2l0aCBtaW5pbWFsIGZlZXMuIExpbWl0cyBzdXBwbGVtZW50YXJ5VW5zcGVudHMgdG8gNC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVBzYnRGb3JTaW5nbGVJbnNjcmlwdGlvblBhc3NpbmdUcmFuc2FjdGlvbihcbiAgbmV0d29ya09yQ29pbk5hbWU6IENvaW5OYW1lIHwgVXR4b2xpYk5ldHdvcmssXG4gIGlucHV0QnVpbGRlcjogV2FsbGV0SW5wdXRCdWlsZGVyLFxuICB1bnNwZW50OiBXYWxsZXRVbnNwZW50IHwgV2FsbGV0VW5zcGVudFtdLFxuICBzYXRQb2ludDogU2F0UG9pbnQsXG4gIG91dHB1dHM6IEluc2NyaXB0aW9uVHJhbnNhY3Rpb25PdXRwdXRzLFxuICBjb25zdHJhaW50czogSW5zY3JpcHRpb25UcmFuc2FjdGlvbkNvbnN0cmFpbnRzLFxuICB7XG4gICAgc3VwcGxlbWVudGFyeVVuc3BlbnRzID0gW10sXG4gICAgbWluaW1pemVJbnB1dHMgPSB0cnVlLFxuICB9OiB7XG4gICAgc3VwcGxlbWVudGFyeVVuc3BlbnRzPzogV2FsbGV0VW5zcGVudFtdO1xuICAgIG1pbmltaXplSW5wdXRzPzogYm9vbGVhbjtcbiAgfSA9IHt9XG4pOiBmaXhlZFNjcmlwdFdhbGxldC5CaXRHb1BzYnQge1xuICAvLyBzdXBwb3J0IGZvciBsZWdhY3kgY2FsbCBzdHlsZVxuICBpZiAoQXJyYXkuaXNBcnJheSh1bnNwZW50KSkge1xuICAgIGlmICh1bnNwZW50Lmxlbmd0aCAhPT0gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBjYW4gb25seSBwYXNzIHNpbmdsZSB1bnNwZW50YCk7XG4gICAgfVxuICAgIHVuc3BlbnQgPSB1bnNwZW50WzBdO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0ID0gZmluZE91dHB1dExheW91dEZvcldhbGxldFVuc3BlbnRzKFxuICAgIFt1bnNwZW50LCAuLi5zdXBwbGVtZW50YXJ5VW5zcGVudHNdLFxuICAgIHNhdFBvaW50LFxuICAgIG91dHB1dHMsXG4gICAgY29uc3RyYWludHMsXG4gICAgeyBtaW5pbWl6ZUlucHV0cyB9XG4gICk7XG5cbiAgaWYgKCFyZXN1bHQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3JOb0xheW91dCgpO1xuICB9XG5cbiAgcmV0dXJuIGNyZWF0ZVBzYnRGcm9tT3V0cHV0TGF5b3V0KG5ldHdvcmtPckNvaW5OYW1lLCBpbnB1dEJ1aWxkZXIsIHJlc3VsdC5pbnB1dHMsIG91dHB1dHMsIHJlc3VsdC5sYXlvdXQpO1xufVxuIl19