@atomicfinance/bitcoin-wallet-provider 2.5.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -0
- package/.turbo/turbo-test.log +1 -0
- package/CHANGELOG.md +31 -0
- package/dist/BitcoinWalletProvider.d.ts +113 -84
- package/dist/BitcoinWalletProvider.js +472 -384
- package/dist/BitcoinWalletProvider.js.map +1 -1
- package/dist/index.d.ts +0 -0
- package/dist/index.js +9 -17
- package/dist/index.js.map +0 -0
- package/lib/BitcoinWalletProvider.ts +668 -530
- package/package.json +9 -11
- package/LICENSE +0 -674
|
@@ -1,412 +1,500 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
3
13
|
});
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
for(var key in obj){
|
|
23
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
24
|
-
var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
|
|
25
|
-
if (desc.get || desc.set) {
|
|
26
|
-
Object.defineProperty(newObj, key, desc);
|
|
27
|
-
} else {
|
|
28
|
-
newObj[key] = obj[key];
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
newObj.default = obj;
|
|
34
|
-
return newObj;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
const FEE_PER_BYTE_FALLBACK = 5;
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.AddressSearchType = void 0;
|
|
26
|
+
const bitcoin_utils_1 = require("@atomicfinance/bitcoin-utils");
|
|
27
|
+
const errors_1 = require("@atomicfinance/errors");
|
|
28
|
+
const types_1 = require("@atomicfinance/types");
|
|
29
|
+
const utils_1 = require("@atomicfinance/utils");
|
|
30
|
+
const bitcoin = __importStar(require("bitcoinjs-lib"));
|
|
31
|
+
const memoizee_1 = __importDefault(require("memoizee"));
|
|
38
32
|
const ADDRESS_GAP = 20;
|
|
39
33
|
const NONCHANGE_ADDRESS = 0;
|
|
40
34
|
const CHANGE_ADDRESS = 1;
|
|
41
35
|
const NONCHANGE_OR_CHANGE_ADDRESS = 2;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
36
|
+
var AddressSearchType;
|
|
37
|
+
(function (AddressSearchType) {
|
|
38
|
+
AddressSearchType[AddressSearchType["EXTERNAL"] = 0] = "EXTERNAL";
|
|
39
|
+
AddressSearchType[AddressSearchType["CHANGE"] = 1] = "CHANGE";
|
|
40
|
+
AddressSearchType[AddressSearchType["EXTERNAL_OR_CHANGE"] = 2] = "EXTERNAL_OR_CHANGE";
|
|
41
|
+
})(AddressSearchType = exports.AddressSearchType || (exports.AddressSearchType = {}));
|
|
42
|
+
exports.default = (superclass) => {
|
|
43
|
+
class BitcoinWalletProvider extends superclass {
|
|
44
|
+
constructor(...args) {
|
|
45
|
+
const options = args[0];
|
|
46
|
+
const { network, baseDerivationPath, addressType = types_1.bitcoin.AddressType.BECH32, } = options;
|
|
47
|
+
const addressTypes = Object.values(types_1.bitcoin.AddressType);
|
|
48
|
+
if (!addressTypes.includes(addressType)) {
|
|
49
|
+
throw new Error(`addressType must be one of ${addressTypes.join(',')}`);
|
|
50
|
+
}
|
|
51
|
+
super(options);
|
|
52
|
+
this._baseDerivationPath = baseDerivationPath;
|
|
53
|
+
this._network = network;
|
|
54
|
+
this._addressType = addressType;
|
|
55
|
+
this._derivationCache = {};
|
|
56
|
+
this._unusedAddressesBlacklist = {};
|
|
57
|
+
this._maxAddressesToDerive = 5000;
|
|
61
58
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
m: m,
|
|
65
|
-
pubkeys: pubkeys.map((key)=>Buffer.from(key, 'hex')
|
|
66
|
-
),
|
|
67
|
-
network: this._network
|
|
68
|
-
});
|
|
69
|
-
// Create p2wsh for multisig
|
|
70
|
-
const p2wsh = bitcoin.payments.p2wsh({
|
|
71
|
-
redeem: p2ms,
|
|
72
|
-
network: this._network
|
|
73
|
-
});
|
|
74
|
-
return p2wsh;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Creates a native-segwit multi-signature address (P2MS in P2WSH) with n signatures of m required keys
|
|
78
|
-
* https://developer.bitcoin.org/reference/rpc/createmultisig.html
|
|
79
|
-
* @param m the number of required signatures
|
|
80
|
-
* @param pubkeys n possible pubkeys in total
|
|
81
|
-
* @returns a json object containing the `address` and `redeemScript`
|
|
82
|
-
*/ createMultisig(m, pubkeys) {
|
|
83
|
-
const p2wsh = this._createMultisigPayment(m, pubkeys);
|
|
84
|
-
return {
|
|
85
|
-
address: p2wsh.address,
|
|
86
|
-
redeemScript: p2wsh.redeem?.output?.toString('hex')
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Creates a PSBT of a native-segwit multi-signature address (P2MS in P2WSH) with n signatures of m required keys
|
|
91
|
-
* https://developer.bitcoin.org/reference/rpc/createmultisig.html
|
|
92
|
-
* https://developer.bitcoin.org/reference/rpc/createpsbt.html
|
|
93
|
-
* @param m the number of required signatures
|
|
94
|
-
* @param pubkeys n possible pubkeys in total
|
|
95
|
-
* @param inputs the Inputs to the PSBT
|
|
96
|
-
* @param ouputs the Outputs to the PSBT
|
|
97
|
-
* @returns a base64 encoded psbt string
|
|
98
|
-
*/ buildMultisigPSBT(m, pubkeys, inputs, outputs) {
|
|
99
|
-
(0, _assert).default(inputs.length > 0, 'no inputs found');
|
|
100
|
-
(0, _assert).default(outputs.length > 0, 'no outputs found');
|
|
101
|
-
const p2wsh = this._createMultisigPayment(m, pubkeys);
|
|
102
|
-
// Verify pubkeyhash for all inputs matches the p2wsh hash
|
|
103
|
-
(0, _assert).default(inputs.every((input)=>p2wsh.output.toString('hex') === input.scriptPubKey
|
|
104
|
-
), 'address pubkeyhash does not match input scriptPubKey');
|
|
105
|
-
// creator
|
|
106
|
-
const psbt = new bitcoin.Psbt({
|
|
107
|
-
network: this._network
|
|
108
|
-
});
|
|
109
|
-
// updater
|
|
110
|
-
inputs.forEach((input)=>{
|
|
111
|
-
psbt.addInput({
|
|
112
|
-
hash: input.txid,
|
|
113
|
-
index: input.vout,
|
|
114
|
-
witnessUtxo: {
|
|
115
|
-
script: p2wsh.output,
|
|
116
|
-
value: input.value
|
|
117
|
-
},
|
|
118
|
-
witnessScript: p2wsh.redeem.output
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
outputs.forEach((output)=>{
|
|
122
|
-
psbt.addOutput({
|
|
123
|
-
address: output.to,
|
|
124
|
-
value: output.value
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
return psbt.toBase64();
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Update a PSBT with input information from our wallet and then sign inputs that we can sign for
|
|
131
|
-
* https://developer.bitcoin.org/reference/rpc/walletprocesspsbt.html
|
|
132
|
-
* @param psbt a base64 encoded psbt string (P2WSH only)
|
|
133
|
-
* @returns a base64 encoded signed psbt string
|
|
134
|
-
*/ async walletProcessPSBT(psbtString) {
|
|
135
|
-
const psbt = bitcoin.Psbt.fromBase64(psbtString);
|
|
136
|
-
await Promise.all(psbt.data.inputs.map(async (input, i)=>{
|
|
137
|
-
(0, _assert).default(psbt.getInputType(i).slice(0, 5) === 'p2wsh', 'only accepts P2WSH inputs');
|
|
138
|
-
const scriptStack = bitcoin.script.decompile(input.witnessScript);
|
|
139
|
-
const pubkeys = scriptStack.filter((data)=>Buffer.isBuffer(data) && _secp256K1.default.publicKeyVerify(data)
|
|
140
|
-
);
|
|
141
|
-
await Promise.all(pubkeys.map(async (key)=>{
|
|
142
|
-
// create address using pubkey
|
|
143
|
-
const { address: addressString } = bitcoin.payments.p2wpkh({
|
|
144
|
-
pubkey: key,
|
|
145
|
-
network: this._network
|
|
146
|
-
});
|
|
147
|
-
// Retrieve address object from wallet using address
|
|
148
|
-
const address = await this.quickFindAddress([
|
|
149
|
-
addressString,
|
|
150
|
-
]);
|
|
151
|
-
// exit if address doesn't exist in wallet
|
|
152
|
-
if (!address) return;
|
|
153
|
-
// derive keypair
|
|
154
|
-
const keyPair = await this.getMethod('keyPair')(address.derivationPath);
|
|
155
|
-
// sign PSBT using keypair
|
|
156
|
-
psbt.signInput(i, keyPair);
|
|
157
|
-
}));
|
|
158
|
-
}));
|
|
159
|
-
psbt.validateSignaturesOfAllInputs(); // ensure all signatures are valid!
|
|
160
|
-
return psbt.toBase64();
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Finalize the inputs of a PSBT. If the transaction is fully signed, it will
|
|
164
|
-
* produce a network serialized transaction which can be broadcast with sendrawtransaction
|
|
165
|
-
* https://developer.bitcoin.org/reference/rpc/finalizepsbt.html
|
|
166
|
-
* @param psbt a base64 encoded psbt string
|
|
167
|
-
* @returns a json object containing `psbt` in base64, `hex` for transaction and `complete` for if
|
|
168
|
-
* the transaction has a complete set of signatures
|
|
169
|
-
*/ finalizePSBT(psbtString) {
|
|
170
|
-
const psbt = bitcoin.Psbt.fromBase64(psbtString);
|
|
171
|
-
try {
|
|
172
|
-
psbt.validateSignaturesOfAllInputs(); // ensure all signatures are valid!
|
|
173
|
-
psbt.finalizeAllInputs();
|
|
174
|
-
} catch (error) {
|
|
175
|
-
return {
|
|
176
|
-
psbt: psbt.toBase64(),
|
|
177
|
-
complete: false
|
|
178
|
-
};
|
|
59
|
+
getDerivationCache() {
|
|
60
|
+
return this._derivationCache;
|
|
179
61
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async getUnusedAddress(change = false, numAddressPerCall = 100) {
|
|
187
|
-
const addressType = change ? CHANGE_ADDRESS : NONCHANGE_ADDRESS;
|
|
188
|
-
const key = change ? 'change' : 'nonChange';
|
|
189
|
-
const address = await this._getUsedUnusedAddresses(numAddressPerCall, addressType).then(({ unusedAddress })=>unusedAddress[key]
|
|
190
|
-
);
|
|
191
|
-
this._unusedAddressesBlacklist[address.address] = true;
|
|
192
|
-
return address;
|
|
193
|
-
}
|
|
194
|
-
async _getUsedUnusedAddresses(numAddressPerCall = 100, addressType) {
|
|
195
|
-
const usedAddresses = [];
|
|
196
|
-
const addressCountMap = {
|
|
197
|
-
change: 0,
|
|
198
|
-
nonChange: 0
|
|
199
|
-
};
|
|
200
|
-
const unusedAddressMap = {
|
|
201
|
-
change: null,
|
|
202
|
-
nonChange: null
|
|
203
|
-
};
|
|
204
|
-
let addrList;
|
|
205
|
-
let addressIndex = 0;
|
|
206
|
-
let changeAddresses = [];
|
|
207
|
-
let nonChangeAddresses = [];
|
|
208
|
-
/* eslint-disable no-unmodified-loop-condition */ while(addressType === NONCHANGE_OR_CHANGE_ADDRESS && (addressCountMap.change < ADDRESS_GAP || addressCountMap.nonChange < ADDRESS_GAP) || addressType === NONCHANGE_ADDRESS && addressCountMap.nonChange < ADDRESS_GAP || addressType === CHANGE_ADDRESS && addressCountMap.change < ADDRESS_GAP){
|
|
209
|
-
/* eslint-enable no-unmodified-loop-condition */ addrList = [];
|
|
210
|
-
if ((addressType === NONCHANGE_OR_CHANGE_ADDRESS || addressType === CHANGE_ADDRESS) && addressCountMap.change < ADDRESS_GAP) {
|
|
211
|
-
// Scanning for change addr
|
|
212
|
-
changeAddresses = await this.client.wallet.getAddresses(addressIndex, numAddressPerCall, true);
|
|
213
|
-
addrList = addrList.concat(changeAddresses);
|
|
214
|
-
} else {
|
|
215
|
-
changeAddresses = [];
|
|
62
|
+
async setDerivationCache(derivationCache) {
|
|
63
|
+
const address = await this.getDerivationPathAddress(Object.keys(derivationCache)[0]);
|
|
64
|
+
if (derivationCache[address.derivationPath].address !== address.address) {
|
|
65
|
+
throw new Error(`derivationCache at ${address.derivationPath} does not match`);
|
|
216
66
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
67
|
+
this._derivationCache = derivationCache;
|
|
68
|
+
}
|
|
69
|
+
sendOptionsToOutputs(transactions) {
|
|
70
|
+
const targets = [];
|
|
71
|
+
transactions.forEach((tx) => {
|
|
72
|
+
if (tx.to && tx.value && tx.value.gt(0)) {
|
|
73
|
+
targets.push({
|
|
74
|
+
address: utils_1.addressToString(tx.to),
|
|
75
|
+
value: tx.value.toNumber(),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (tx.data) {
|
|
79
|
+
const scriptBuffer = bitcoin.script.compile([
|
|
80
|
+
bitcoin.script.OPS.OP_RETURN,
|
|
81
|
+
Buffer.from(tx.data, 'hex'),
|
|
82
|
+
]);
|
|
83
|
+
targets.push({
|
|
84
|
+
value: 0,
|
|
85
|
+
script: scriptBuffer,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return targets;
|
|
90
|
+
}
|
|
91
|
+
async buildTransaction(output, feePerByte) {
|
|
92
|
+
return this._buildTransaction([output], feePerByte);
|
|
93
|
+
}
|
|
94
|
+
async buildBatchTransaction(outputs) {
|
|
95
|
+
return this._buildTransaction(outputs);
|
|
96
|
+
}
|
|
97
|
+
async _sendTransaction(transactions, feePerByte) {
|
|
98
|
+
const { hex, fee } = await this._buildTransaction(transactions, feePerByte);
|
|
99
|
+
await this.getMethod('sendRawTransaction')(hex);
|
|
100
|
+
return bitcoin_utils_1.normalizeTransactionObject(bitcoin_utils_1.decodeRawTransaction(hex, this._network), fee);
|
|
101
|
+
}
|
|
102
|
+
async sendTransaction(options) {
|
|
103
|
+
return this._sendTransaction(this.sendOptionsToOutputs([options]), options.fee);
|
|
104
|
+
}
|
|
105
|
+
async sendBatchTransaction(transactions) {
|
|
106
|
+
return this._sendTransaction(this.sendOptionsToOutputs(transactions));
|
|
107
|
+
}
|
|
108
|
+
async buildSweepTransaction(externalChangeAddress, feePerByte) {
|
|
109
|
+
return this._buildSweepTransaction(externalChangeAddress, feePerByte);
|
|
110
|
+
}
|
|
111
|
+
async sendSweepTransaction(externalChangeAddress, feePerByte) {
|
|
112
|
+
const { hex, fee } = await this._buildSweepTransaction(utils_1.addressToString(externalChangeAddress), feePerByte);
|
|
113
|
+
await this.getMethod('sendRawTransaction')(hex);
|
|
114
|
+
return bitcoin_utils_1.normalizeTransactionObject(bitcoin_utils_1.decodeRawTransaction(hex, this._network), fee);
|
|
115
|
+
}
|
|
116
|
+
getUnusedAddressesBlacklist() {
|
|
117
|
+
return this._unusedAddressesBlacklist;
|
|
118
|
+
}
|
|
119
|
+
setUnusedAddressesBlacklist(unusedAddressesBlacklist) {
|
|
120
|
+
this._unusedAddressesBlacklist = unusedAddressesBlacklist;
|
|
121
|
+
}
|
|
122
|
+
setMaxAddressesToDerive(maxAddressesToDerive) {
|
|
123
|
+
this._maxAddressesToDerive = maxAddressesToDerive;
|
|
124
|
+
}
|
|
125
|
+
getMaxAddressesToDerive() {
|
|
126
|
+
return this._maxAddressesToDerive;
|
|
127
|
+
}
|
|
128
|
+
async updateTransactionFee(tx, newFeePerByte) {
|
|
129
|
+
const txHash = typeof tx === 'string' ? tx : tx.hash;
|
|
130
|
+
const transaction = (await this.getMethod('getTransactionByHash')(txHash))._raw;
|
|
131
|
+
const fixedInputs = [transaction.vin[0]]; // TODO: should this pick more than 1 input? RBF doesn't mandate it
|
|
132
|
+
const lookupAddresses = transaction.vout.map((vout) => vout.scriptPubKey.addresses[0]);
|
|
133
|
+
const changeAddress = await this.findAddress(lookupAddresses, true);
|
|
134
|
+
const changeOutput = transaction.vout.find((vout) => vout.scriptPubKey.addresses[0] === changeAddress.address);
|
|
135
|
+
let outputs = transaction.vout;
|
|
136
|
+
if (changeOutput) {
|
|
137
|
+
outputs = outputs.filter((vout) => vout.scriptPubKey.addresses[0] !==
|
|
138
|
+
changeOutput.scriptPubKey.addresses[0]);
|
|
221
139
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
140
|
+
// TODO more checks?
|
|
141
|
+
const transactions = outputs.map((output) => ({
|
|
142
|
+
address: output.scriptPubKey.addresses[0],
|
|
143
|
+
value: new types_1.BigNumber(output.value).times(1e8).toNumber(),
|
|
144
|
+
}));
|
|
145
|
+
const { hex, fee } = await this._buildTransaction(transactions, newFeePerByte, fixedInputs);
|
|
146
|
+
await this.getMethod('sendRawTransaction')(hex);
|
|
147
|
+
return bitcoin_utils_1.normalizeTransactionObject(bitcoin_utils_1.decodeRawTransaction(hex, this._network), fee);
|
|
148
|
+
}
|
|
149
|
+
async getUnusedAddress(change = false, numAddressPerCall = 100) {
|
|
150
|
+
const addressType = change ? CHANGE_ADDRESS : NONCHANGE_ADDRESS;
|
|
151
|
+
const key = change ? 'change' : 'nonChange';
|
|
152
|
+
const address = await this._getUsedUnusedAddresses(numAddressPerCall, addressType).then(({ unusedAddress }) => unusedAddress[key]);
|
|
153
|
+
this._unusedAddressesBlacklist[address.address] = true;
|
|
154
|
+
return address;
|
|
155
|
+
}
|
|
156
|
+
async _getUsedUnusedAddresses(numAddressPerCall = 100, addressType) {
|
|
157
|
+
const usedAddresses = [];
|
|
158
|
+
const addressCountMap = { change: 0, nonChange: 0 };
|
|
159
|
+
const unusedAddressMap = { change: null, nonChange: null };
|
|
160
|
+
let addrList;
|
|
161
|
+
let addressIndex = 0;
|
|
162
|
+
let changeAddresses = [];
|
|
163
|
+
let nonChangeAddresses = [];
|
|
164
|
+
/* eslint-disable no-unmodified-loop-condition */
|
|
165
|
+
while ((addressType === NONCHANGE_OR_CHANGE_ADDRESS &&
|
|
166
|
+
(addressCountMap.change < ADDRESS_GAP ||
|
|
167
|
+
addressCountMap.nonChange < ADDRESS_GAP)) ||
|
|
168
|
+
(addressType === NONCHANGE_ADDRESS &&
|
|
169
|
+
addressCountMap.nonChange < ADDRESS_GAP) ||
|
|
170
|
+
(addressType === CHANGE_ADDRESS && addressCountMap.change < ADDRESS_GAP)) {
|
|
171
|
+
/* eslint-enable no-unmodified-loop-condition */
|
|
172
|
+
addrList = [];
|
|
173
|
+
if ((addressType === NONCHANGE_OR_CHANGE_ADDRESS ||
|
|
174
|
+
addressType === CHANGE_ADDRESS) &&
|
|
175
|
+
addressCountMap.change < ADDRESS_GAP) {
|
|
176
|
+
// Scanning for change addr
|
|
177
|
+
changeAddresses = await this.client.wallet.getAddresses(addressIndex, numAddressPerCall, true);
|
|
178
|
+
addrList = addrList.concat(changeAddresses);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
changeAddresses = [];
|
|
182
|
+
}
|
|
183
|
+
if ((addressType === NONCHANGE_OR_CHANGE_ADDRESS ||
|
|
184
|
+
addressType === NONCHANGE_ADDRESS) &&
|
|
185
|
+
addressCountMap.nonChange < ADDRESS_GAP) {
|
|
186
|
+
// Scanning for non change addr
|
|
187
|
+
nonChangeAddresses = await this.getAddresses(addressIndex, numAddressPerCall, false);
|
|
188
|
+
addrList = addrList.concat(nonChangeAddresses);
|
|
189
|
+
}
|
|
190
|
+
const transactionCounts = await this.getMethod('getAddressTransactionCounts')(addrList);
|
|
191
|
+
for (const address of addrList) {
|
|
192
|
+
const isUsed = transactionCounts[address.address] > 0 ||
|
|
193
|
+
this._unusedAddressesBlacklist[address.address];
|
|
194
|
+
const isChangeAddress = changeAddresses.find((a) => address.address === a.address);
|
|
195
|
+
const key = isChangeAddress ? 'change' : 'nonChange';
|
|
196
|
+
if (isUsed) {
|
|
197
|
+
usedAddresses.push(address);
|
|
198
|
+
addressCountMap[key] = 0;
|
|
199
|
+
unusedAddressMap[key] = null;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
addressCountMap[key]++;
|
|
203
|
+
if (!unusedAddressMap[key]) {
|
|
204
|
+
unusedAddressMap[key] = address;
|
|
205
|
+
}
|
|
236
206
|
}
|
|
237
207
|
}
|
|
208
|
+
addressIndex += numAddressPerCall;
|
|
238
209
|
}
|
|
239
|
-
|
|
210
|
+
let firstUnusedAddress;
|
|
211
|
+
const indexNonChange = unusedAddressMap.nonChange
|
|
212
|
+
? unusedAddressMap.nonChange.index
|
|
213
|
+
: Infinity;
|
|
214
|
+
const indexChange = unusedAddressMap.change
|
|
215
|
+
? unusedAddressMap.change.index
|
|
216
|
+
: Infinity;
|
|
217
|
+
if (indexNonChange <= indexChange)
|
|
218
|
+
firstUnusedAddress = unusedAddressMap.nonChange;
|
|
219
|
+
else
|
|
220
|
+
firstUnusedAddress = unusedAddressMap.change;
|
|
221
|
+
return {
|
|
222
|
+
usedAddresses,
|
|
223
|
+
unusedAddress: unusedAddressMap,
|
|
224
|
+
firstUnusedAddress,
|
|
225
|
+
};
|
|
240
226
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
227
|
+
async getWalletAddress(address) {
|
|
228
|
+
const foundAddress = await this.findAddress([address]);
|
|
229
|
+
if (foundAddress)
|
|
230
|
+
return foundAddress;
|
|
231
|
+
throw new Error('Wallet does not contain address');
|
|
232
|
+
}
|
|
233
|
+
getAddressFromPublicKey(publicKey) {
|
|
234
|
+
return this.getPaymentVariantFromPublicKey(publicKey).address;
|
|
235
|
+
}
|
|
236
|
+
getPaymentVariantFromPublicKey(publicKey) {
|
|
237
|
+
if (this._addressType === types_1.bitcoin.AddressType.LEGACY) {
|
|
238
|
+
return bitcoin.payments.p2pkh({
|
|
239
|
+
pubkey: publicKey,
|
|
240
|
+
network: this._network,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
else if (this._addressType === types_1.bitcoin.AddressType.P2SH_SEGWIT) {
|
|
244
|
+
return bitcoin.payments.p2sh({
|
|
245
|
+
redeem: bitcoin.payments.p2wpkh({
|
|
246
|
+
pubkey: publicKey,
|
|
247
|
+
network: this._network,
|
|
248
|
+
}),
|
|
249
|
+
network: this._network,
|
|
250
|
+
});
|
|
265
251
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
252
|
+
else if (this._addressType === types_1.bitcoin.AddressType.BECH32) {
|
|
253
|
+
return bitcoin.payments.p2wpkh({
|
|
254
|
+
pubkey: publicKey,
|
|
255
|
+
network: this._network,
|
|
256
|
+
});
|
|
271
257
|
}
|
|
272
|
-
const inputsForAmount = await this._getInputForAmountWithoutUtxoCheck(_outputs, _feePerByte, fixedInputs);
|
|
273
|
-
inputs.push(...inputsForAmount.inputs.map((utxo)=>_types.Input.fromUTXO(utxo)
|
|
274
|
-
) || []);
|
|
275
|
-
outputs.push(...inputsForAmount.outputs || []);
|
|
276
258
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const utxoBalance = fixedInputs.reduce((a, b)=>a + (b['value'] || 0)
|
|
290
|
-
, 0);
|
|
291
|
-
const outputBalance = _outputs.reduce((a, b)=>a + (b['value'] || 0)
|
|
292
|
-
, 0);
|
|
293
|
-
const amountToSend = utxoBalance - _feePerByte * ((_outputs.length + 1) * 39 + fixedInputs.length * 153); // todo better calculation
|
|
294
|
-
const targets = _outputs.map((target, i)=>({
|
|
295
|
-
id: 'main',
|
|
296
|
-
value: target.value
|
|
297
|
-
})
|
|
298
|
-
);
|
|
299
|
-
if (amountToSend - outputBalance > 0) {
|
|
300
|
-
targets.push({
|
|
301
|
-
id: 'main',
|
|
302
|
-
value: amountToSend - outputBalance
|
|
259
|
+
async getDerivationPathAddress(path) {
|
|
260
|
+
if (path in this._derivationCache) {
|
|
261
|
+
return this._derivationCache[path];
|
|
262
|
+
}
|
|
263
|
+
const baseDerivationNode = await this.baseDerivationNode();
|
|
264
|
+
const subPath = path.replace(this._baseDerivationPath + '/', '');
|
|
265
|
+
const publicKey = baseDerivationNode.derivePath(subPath).publicKey;
|
|
266
|
+
const address = this.getAddressFromPublicKey(publicKey);
|
|
267
|
+
const addressObject = new types_1.Address({
|
|
268
|
+
address,
|
|
269
|
+
publicKey: publicKey.toString('hex'),
|
|
270
|
+
derivationPath: path,
|
|
303
271
|
});
|
|
272
|
+
this._derivationCache[path] = addressObject;
|
|
273
|
+
return addressObject;
|
|
304
274
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
275
|
+
/**
|
|
276
|
+
* getAddresses is an optimized version of upstream CAL's getAddresses.
|
|
277
|
+
* It removes the call to `asyncSetImmediate()`, speeding up the function by a factor of 6x.
|
|
278
|
+
*
|
|
279
|
+
* @param startingIndex
|
|
280
|
+
* @param numAddresses
|
|
281
|
+
* @param change
|
|
282
|
+
* @returns {Promise<Address[]>}
|
|
283
|
+
*/
|
|
284
|
+
async getAddresses(startingIndex = 0, numAddresses = 1, change = false) {
|
|
285
|
+
if (numAddresses < 1) {
|
|
286
|
+
throw new Error('You must return at least one address');
|
|
287
|
+
}
|
|
288
|
+
const addresses = [];
|
|
289
|
+
const lastIndex = startingIndex + numAddresses;
|
|
290
|
+
const changeVal = change ? '1' : '0';
|
|
291
|
+
for (let currentIndex = startingIndex; currentIndex < lastIndex; currentIndex++) {
|
|
292
|
+
const subPath = changeVal + '/' + currentIndex;
|
|
293
|
+
const path = this._baseDerivationPath + '/' + subPath;
|
|
294
|
+
const addressObject = await this.getDerivationPathAddress(path);
|
|
295
|
+
addresses.push(addressObject);
|
|
296
|
+
}
|
|
297
|
+
return addresses;
|
|
315
298
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
299
|
+
/**
|
|
300
|
+
* findAddress is an optimized version of upstream CAL's findAddress.
|
|
301
|
+
*
|
|
302
|
+
* It searches through both change and non-change addresses (if change arg is not provided) each iteration.
|
|
303
|
+
*
|
|
304
|
+
* This is in contrast to the original findAddress function which searches
|
|
305
|
+
* through all non-change addresses before moving on to change addresses.
|
|
306
|
+
*
|
|
307
|
+
* @param addresses
|
|
308
|
+
* @returns {Promise<Address>}
|
|
309
|
+
*/
|
|
310
|
+
async findAddress(addresses, change = null) {
|
|
311
|
+
const addressesPerCall = 20;
|
|
312
|
+
let index = 0;
|
|
313
|
+
while (index < this._maxAddressesToDerive) {
|
|
314
|
+
const walletAddresses = [];
|
|
315
|
+
if (change === null || change === false) {
|
|
316
|
+
walletAddresses.push(...(await this.getAddresses(index, addressesPerCall, false)));
|
|
317
|
+
}
|
|
318
|
+
if (change === null || change === true) {
|
|
319
|
+
walletAddresses.push(...(await this.getAddresses(index, addressesPerCall, true)));
|
|
320
|
+
}
|
|
321
|
+
const walletAddress = walletAddresses.find((walletAddr) => addresses.find((addr) => walletAddr.address === addr));
|
|
322
|
+
if (walletAddress) {
|
|
323
|
+
// Increment max addresses to derive by 100 if found within 100 addresses of maxAddressesToDerive
|
|
324
|
+
this._maxAddressesToDerive = Math.max(this._maxAddressesToDerive, index + 100);
|
|
325
|
+
return walletAddress;
|
|
326
|
+
}
|
|
327
|
+
index += addressesPerCall;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async getUsedAddresses(numAddressPerCall = 100) {
|
|
331
|
+
return this._getUsedUnusedAddresses(numAddressPerCall, AddressSearchType.EXTERNAL_OR_CHANGE).then(({ usedAddresses }) => usedAddresses);
|
|
322
332
|
}
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
+
async withCachedUtxos(func) {
|
|
334
|
+
const originalGetMethod = this.getMethod;
|
|
335
|
+
const memoizedGetFeePerByte = memoizee_1.default(this.getMethod('getFeePerByte'), {
|
|
336
|
+
primitive: true,
|
|
337
|
+
});
|
|
338
|
+
const memoizedGetUnspentTransactions = memoizee_1.default(this.getMethod('getUnspentTransactions'), { primitive: true });
|
|
339
|
+
const memoizedGetAddressTransactionCounts = memoizee_1.default(this.getMethod('getAddressTransactionCounts'), {
|
|
340
|
+
primitive: true,
|
|
341
|
+
});
|
|
342
|
+
this.getMethod = (method, requestor = this) => {
|
|
343
|
+
if (method === 'getFeePerByte')
|
|
344
|
+
return memoizedGetFeePerByte;
|
|
345
|
+
if (method === 'getUnspentTransactions')
|
|
346
|
+
return memoizedGetUnspentTransactions;
|
|
347
|
+
else if (method === 'getAddressTransactionCounts')
|
|
348
|
+
return memoizedGetAddressTransactionCounts;
|
|
349
|
+
else
|
|
350
|
+
return originalGetMethod.bind(this)(method, requestor);
|
|
333
351
|
};
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
txb.sign(signParams);
|
|
352
|
+
const result = await func.bind(this)();
|
|
353
|
+
this.getMethod = originalGetMethod;
|
|
354
|
+
return result;
|
|
338
355
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
* @param numAddresses
|
|
350
|
-
* @param change
|
|
351
|
-
* @returns {Promise<Address[]>}
|
|
352
|
-
*/ async quickGetAddresses(startingIndex = 0, numAddresses = 1, change = false) {
|
|
353
|
-
if (numAddresses < 1) {
|
|
354
|
-
throw new Error('You must return at least one address');
|
|
356
|
+
async getTotalFee(opts, max) {
|
|
357
|
+
const targets = this.sendOptionsToOutputs([opts]);
|
|
358
|
+
if (!max) {
|
|
359
|
+
const { fee } = await this.getInputsForAmount(targets, opts.fee);
|
|
360
|
+
return fee;
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
const { fee } = await this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, [], 100, true);
|
|
364
|
+
return fee;
|
|
365
|
+
}
|
|
355
366
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const path = baseDerivationPath + '/' + subPath;
|
|
367
|
-
const addressObject = await getDerivationPathAddressFn(path);
|
|
368
|
-
addresses.push(addressObject);
|
|
367
|
+
async getTotalFees(transactions, max) {
|
|
368
|
+
const fees = await this.withCachedUtxos(async () => {
|
|
369
|
+
const fees = {};
|
|
370
|
+
for (const tx of transactions) {
|
|
371
|
+
const fee = await this.getTotalFee(tx, max);
|
|
372
|
+
fees[tx.fee] = new types_1.BigNumber(fee);
|
|
373
|
+
}
|
|
374
|
+
return fees;
|
|
375
|
+
});
|
|
376
|
+
return fees;
|
|
369
377
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
378
|
+
async getInputsForAmount(_targets, feePerByte, fixedInputs = [], numAddressPerCall = 100, sweep = false) {
|
|
379
|
+
let addressIndex = 0;
|
|
380
|
+
let changeAddresses = [];
|
|
381
|
+
let externalAddresses = [];
|
|
382
|
+
const addressCountMap = {
|
|
383
|
+
change: 0,
|
|
384
|
+
nonChange: 0,
|
|
385
|
+
};
|
|
386
|
+
const feePerBytePromise = this.getMethod('getFeePerByte')();
|
|
387
|
+
let utxos = [];
|
|
388
|
+
while (addressCountMap.change < ADDRESS_GAP ||
|
|
389
|
+
addressCountMap.nonChange < ADDRESS_GAP) {
|
|
390
|
+
let addrList = [];
|
|
391
|
+
if (addressCountMap.change < ADDRESS_GAP) {
|
|
392
|
+
// Scanning for change addr
|
|
393
|
+
changeAddresses = await this.getAddresses(addressIndex, numAddressPerCall, true);
|
|
394
|
+
addrList = addrList.concat(changeAddresses);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
changeAddresses = [];
|
|
398
|
+
}
|
|
399
|
+
if (addressCountMap.nonChange < ADDRESS_GAP) {
|
|
400
|
+
// Scanning for non change addr
|
|
401
|
+
externalAddresses = await this.getAddresses(addressIndex, numAddressPerCall, false);
|
|
402
|
+
addrList = addrList.concat(externalAddresses);
|
|
403
|
+
}
|
|
404
|
+
const fixedUtxos = [];
|
|
405
|
+
if (fixedInputs.length > 0) {
|
|
406
|
+
for (const input of fixedInputs) {
|
|
407
|
+
const txHex = await this.getMethod('getRawTransactionByHash')(input.txid);
|
|
408
|
+
const tx = bitcoin_utils_1.decodeRawTransaction(txHex, this._network);
|
|
409
|
+
const value = new types_1.BigNumber(tx.vout[input.vout].value)
|
|
410
|
+
.times(1e8)
|
|
411
|
+
.toNumber();
|
|
412
|
+
const address = tx.vout[input.vout].scriptPubKey.addresses[0];
|
|
413
|
+
const walletAddress = await this.getWalletAddress(address);
|
|
414
|
+
const utxo = {
|
|
415
|
+
...input,
|
|
416
|
+
value,
|
|
417
|
+
address,
|
|
418
|
+
derivationPath: walletAddress.derivationPath,
|
|
419
|
+
};
|
|
420
|
+
fixedUtxos.push(utxo);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (!sweep || fixedUtxos.length === 0) {
|
|
424
|
+
const _utxos = await this.getMethod('getUnspentTransactions')(addrList);
|
|
425
|
+
utxos.push(..._utxos.map((utxo) => {
|
|
426
|
+
const addr = addrList.find((a) => a.address === utxo.address);
|
|
427
|
+
return {
|
|
428
|
+
...utxo,
|
|
429
|
+
derivationPath: addr.derivationPath,
|
|
430
|
+
};
|
|
431
|
+
}));
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
utxos = fixedUtxos;
|
|
435
|
+
}
|
|
436
|
+
const utxoBalance = utxos.reduce((a, b) => a + (b.value || 0), 0);
|
|
437
|
+
const transactionCounts = await this.getMethod('getAddressTransactionCounts')(addrList);
|
|
438
|
+
if (!feePerByte)
|
|
439
|
+
feePerByte = await feePerBytePromise;
|
|
440
|
+
const minRelayFee = await this.getMethod('getMinRelayFee')();
|
|
441
|
+
if (feePerByte < minRelayFee) {
|
|
442
|
+
throw new Error(`Fee supplied (${feePerByte} sat/b) too low. Minimum relay fee is ${minRelayFee} sat/b`);
|
|
443
|
+
}
|
|
444
|
+
let targets;
|
|
445
|
+
if (sweep) {
|
|
446
|
+
const outputBalance = _targets.reduce((a, b) => a + (b['value'] || 0), 0);
|
|
447
|
+
const sweepOutputSize = 39;
|
|
448
|
+
const paymentOutputSize = _targets.filter((t) => t.value && t.address).length * 39;
|
|
449
|
+
const scriptOutputSize = _targets
|
|
450
|
+
.filter((t) => !t.value && t.script)
|
|
451
|
+
.reduce((size, t) => size + 39 + t.script.byteLength, 0);
|
|
452
|
+
const outputSize = sweepOutputSize + paymentOutputSize + scriptOutputSize;
|
|
453
|
+
const inputSize = utxos.length * 153;
|
|
454
|
+
const sweepFee = feePerByte * (inputSize + outputSize);
|
|
455
|
+
const amountToSend = new types_1.BigNumber(utxoBalance).minus(sweepFee);
|
|
456
|
+
targets = _targets.map((target) => ({
|
|
457
|
+
id: 'main',
|
|
458
|
+
value: target.value,
|
|
459
|
+
script: target.script,
|
|
460
|
+
}));
|
|
461
|
+
targets.push({
|
|
462
|
+
id: 'main',
|
|
463
|
+
value: amountToSend.minus(outputBalance).toNumber(),
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
targets = _targets.map((target) => ({
|
|
468
|
+
id: 'main',
|
|
469
|
+
value: target.value,
|
|
470
|
+
script: target.script,
|
|
471
|
+
}));
|
|
472
|
+
}
|
|
473
|
+
const { inputs, outputs, change, fee } = bitcoin_utils_1.selectCoins(utxos, targets, Math.ceil(feePerByte), fixedUtxos);
|
|
474
|
+
if (inputs && outputs) {
|
|
475
|
+
return {
|
|
476
|
+
inputs,
|
|
477
|
+
change,
|
|
478
|
+
outputs,
|
|
479
|
+
fee,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
for (const address of addrList) {
|
|
483
|
+
const isUsed = transactionCounts[address.address];
|
|
484
|
+
const isChangeAddress = changeAddresses.find((a) => address.address === a.address);
|
|
485
|
+
const key = isChangeAddress ? 'change' : 'nonChange';
|
|
486
|
+
if (isUsed) {
|
|
487
|
+
addressCountMap[key] = 0;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
addressCountMap[key]++;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
addressIndex += numAddressPerCall;
|
|
399
494
|
}
|
|
400
|
-
|
|
495
|
+
throw new errors_1.InsufficientBalanceError('Not enough balance');
|
|
401
496
|
}
|
|
402
497
|
}
|
|
403
|
-
|
|
404
|
-
super();
|
|
405
|
-
this._network = network;
|
|
406
|
-
this._unusedAddressesBlacklist = {};
|
|
407
|
-
this._maxAddressesToDerive = 5000;
|
|
408
|
-
}
|
|
498
|
+
return BitcoinWalletProvider;
|
|
409
499
|
};
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL2xpYi9CaXRjb2luV2FsbGV0UHJvdmlkZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFByb3ZpZGVyIGZyb20gJ0BhdG9taWNmaW5hbmNlL3Byb3ZpZGVyJztcbmltcG9ydCB7XG4gIENyZWF0ZU11bHRpc2lnUmVzcG9uc2UsXG4gIGZpbmFsaXplUFNCVFJlc3BvbnNlLFxuICBGaW5hbmNlV2FsbGV0UHJvdmlkZXIsXG4gIElucHV0LFxuICBPdXRwdXQsXG59IGZyb20gJ0BhdG9taWNmaW5hbmNlL3R5cGVzJztcbmltcG9ydCB7IEJpdGNvaW5OZXR3b3JrIH0gZnJvbSAnQGxpcXVhbGl0eS9iaXRjb2luLW5ldHdvcmtzJztcbmltcG9ydCB7XG4gIGRlY29kZVJhd1RyYW5zYWN0aW9uLFxuICBub3JtYWxpemVUcmFuc2FjdGlvbk9iamVjdCxcbiAgc2VsZWN0Q29pbnMsXG59IGZyb20gJ0BsaXF1YWxpdHkvYml0Y29pbi11dGlscyc7XG5pbXBvcnQgeyBBZGRyZXNzLCBiaXRjb2luIGFzIGJULCBUcmFuc2FjdGlvbiB9IGZyb20gJ0BsaXF1YWxpdHkvdHlwZXMnO1xuaW1wb3J0IGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0ICogYXMgYml0Y29pbiBmcm9tICdiaXRjb2luanMtbGliJztcbmltcG9ydCBzZWNwMjU2azEgZnJvbSAnc2VjcDI1NmsxJztcblxuY29uc3QgRkVFX1BFUl9CWVRFX0ZBTExCQUNLID0gNTtcbmNvbnN0IEFERFJFU1NfR0FQID0gMjA7XG5jb25zdCBOT05DSEFOR0VfQUREUkVTUyA9IDA7XG5jb25zdCBDSEFOR0VfQUREUkVTUyA9IDE7XG5jb25zdCBOT05DSEFOR0VfT1JfQ0hBTkdFX0FERFJFU1MgPSAyO1xuXG50eXBlIFVudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdCA9IHtcbiAgW2FkZHJlc3M6IHN0cmluZ106IHRydWU7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCaXRjb2luV2FsbGV0UHJvdmlkZXJcbiAgZXh0ZW5kcyBQcm92aWRlclxuICBpbXBsZW1lbnRzIFBhcnRpYWw8RmluYW5jZVdhbGxldFByb3ZpZGVyPiB7XG4gIF9uZXR3b3JrOiBCaXRjb2luTmV0d29yaztcbiAgX3VudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdDogVW51c2VkQWRkcmVzc2VzQmxhY2tsaXN0O1xuICBfbWF4QWRkcmVzc2VzVG9EZXJpdmU6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihuZXR3b3JrOiBCaXRjb2luTmV0d29yaykge1xuICAgIHN1cGVyKCk7XG5cbiAgICB0aGlzLl9uZXR3b3JrID0gbmV0d29yaztcbiAgICB0aGlzLl91bnVzZWRBZGRyZXNzZXNCbGFja2xpc3QgPSB7fTtcbiAgICB0aGlzLl9tYXhBZGRyZXNzZXNUb0Rlcml2ZSA9IDUwMDA7XG4gIH1cblxuICBhc3luYyBidWlsZFN3ZWVwVHJhbnNhY3Rpb25XaXRoU2V0T3V0cHV0cyhcbiAgICBleHRlcm5hbENoYW5nZUFkZHJlc3M6IHN0cmluZyxcbiAgICBmZWVQZXJCeXRlOiBudW1iZXIsXG4gICAgX291dHB1dHM6IE91dHB1dFtdLFxuICAgIGZpeGVkSW5wdXRzOiBJbnB1dFtdLFxuICApIHtcbiAgICByZXR1cm4gdGhpcy5fYnVpbGRTd2VlcFRyYW5zYWN0aW9uKFxuICAgICAgZXh0ZXJuYWxDaGFuZ2VBZGRyZXNzLFxuICAgICAgZmVlUGVyQnl0ZSxcbiAgICAgIF9vdXRwdXRzLFxuICAgICAgZml4ZWRJbnB1dHMsXG4gICAgKTtcbiAgfVxuXG4gIGdldFVudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdCgpOiBVbnVzZWRBZGRyZXNzZXNCbGFja2xpc3Qge1xuICAgIHJldHVybiB0aGlzLl91bnVzZWRBZGRyZXNzZXNCbGFja2xpc3Q7XG4gIH1cblxuICBzZXRVbnVzZWRBZGRyZXNzZXNCbGFja2xpc3QoXG4gICAgdW51c2VkQWRkcmVzc2VzQmxhY2tsaXN0OiBVbnVzZWRBZGRyZXNzZXNCbGFja2xpc3QsXG4gICkge1xuICAgIHRoaXMuX3VudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdCA9IHVudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdDtcbiAgfVxuXG4gIHNldE1heEFkZHJlc3Nlc1RvRGVyaXZlKG1heEFkZHJlc3Nlc1RvRGVyaXZlOiBudW1iZXIpIHtcbiAgICB0aGlzLl9tYXhBZGRyZXNzZXNUb0Rlcml2ZSA9IG1heEFkZHJlc3Nlc1RvRGVyaXZlO1xuICB9XG5cbiAgZ2V0TWF4QWRkcmVzc2VzVG9EZXJpdmUoKSB7XG4gICAgcmV0dXJuIHRoaXMuX21heEFkZHJlc3Nlc1RvRGVyaXZlO1xuICB9XG5cbiAgX2NyZWF0ZU11bHRpc2lnUGF5bWVudChtOiBudW1iZXIsIHB1YmtleXM6IHN0cmluZ1tdKTogYml0Y29pbi5QYXltZW50IHtcbiAgICBpZiAobSA+IHB1YmtleXMubGVuZ3RoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBub3QgZW5vdWdoIGtleXMgc3VwcGxpZWQgKGdvdCAke3B1YmtleXMubGVuZ3RofSBrZXlzLCBidXQgbmVlZCBhdCBsZWFzdCAke219IHRvIHJlZGVlbSlgLFxuICAgICAgKTtcbiAgICB9XG4gICAgLy8gQ3JlYXRlIG0tb2YtbiBtdWx0aXNpZ1xuICAgIGNvbnN0IHAybXMgPSBiaXRjb2luLnBheW1lbnRzLnAybXMoe1xuICAgICAgbTogbSxcbiAgICAgIHB1YmtleXM6IHB1YmtleXMubWFwKChrZXk6IHN0cmluZykgPT4gQnVmZmVyLmZyb20oa2V5LCAnaGV4JykpLFxuICAgICAgbmV0d29yazogdGhpcy5fbmV0d29yayxcbiAgICB9KTtcblxuICAgIC8vIENyZWF0ZSBwMndzaCBmb3IgbXVsdGlzaWdcbiAgICBjb25zdCBwMndzaCA9IGJpdGNvaW4ucGF5bWVudHMucDJ3c2goe1xuICAgICAgcmVkZWVtOiBwMm1zLFxuICAgICAgbmV0d29yazogdGhpcy5fbmV0d29yayxcbiAgICB9KTtcblxuICAgIHJldHVybiBwMndzaDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmF0aXZlLXNlZ3dpdCBtdWx0aS1zaWduYXR1cmUgYWRkcmVzcyAoUDJNUyBpbiBQMldTSCkgd2l0aCBuIHNpZ25hdHVyZXMgb2YgbSByZXF1aXJlZCBrZXlzXG4gICAqIGh0dHBzOi8vZGV2ZWxvcGVyLmJpdGNvaW4ub3JnL3JlZmVyZW5jZS9ycGMvY3JlYXRlbXVsdGlzaWcuaHRtbFxuICAgKiBAcGFyYW0gbSB0aGUgbnVtYmVyIG9mIHJlcXVpcmVkIHNpZ25hdHVyZXNcbiAgICogQHBhcmFtIHB1YmtleXMgbiBwb3NzaWJsZSBwdWJrZXlzIGluIHRvdGFsXG4gICAqIEByZXR1cm5zIGEganNvbiBvYmplY3QgY29udGFpbmluZyB0aGUgYGFkZHJlc3NgIGFuZCBgcmVkZWVtU2NyaXB0YFxuICAgKi9cbiAgY3JlYXRlTXVsdGlzaWcobTogbnVtYmVyLCBwdWJrZXlzOiBzdHJpbmdbXSk6IENyZWF0ZU11bHRpc2lnUmVzcG9uc2Uge1xuICAgIGNvbnN0IHAyd3NoID0gdGhpcy5fY3JlYXRlTXVsdGlzaWdQYXltZW50KG0sIHB1YmtleXMpO1xuICAgIHJldHVybiB7XG4gICAgICBhZGRyZXNzOiBwMndzaC5hZGRyZXNzLFxuICAgICAgcmVkZWVtU2NyaXB0OiBwMndzaC5yZWRlZW0/Lm91dHB1dD8udG9TdHJpbmcoJ2hleCcpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIFBTQlQgb2YgYSBuYXRpdmUtc2Vnd2l0IG11bHRpLXNpZ25hdHVyZSBhZGRyZXNzIChQMk1TIGluIFAyV1NIKSB3aXRoIG4gc2lnbmF0dXJlcyBvZiBtIHJlcXVpcmVkIGtleXNcbiAgICogaHR0cHM6Ly9kZXZlbG9wZXIuYml0Y29pbi5vcmcvcmVmZXJlbmNlL3JwYy9jcmVhdGVtdWx0aXNpZy5odG1sXG4gICAqIGh0dHBzOi8vZGV2ZWxvcGVyLmJpdGNvaW4ub3JnL3JlZmVyZW5jZS9ycGMvY3JlYXRlcHNidC5odG1sXG4gICAqIEBwYXJhbSBtIHRoZSBudW1iZXIgb2YgcmVxdWlyZWQgc2lnbmF0dXJlc1xuICAgKiBAcGFyYW0gcHVia2V5cyBuIHBvc3NpYmxlIHB1YmtleXMgaW4gdG90YWxcbiAgICogQHBhcmFtIGlucHV0cyB0aGUgSW5wdXRzIHRvIHRoZSBQU0JUXG4gICAqIEBwYXJhbSBvdXB1dHMgdGhlIE91dHB1dHMgdG8gdGhlIFBTQlRcbiAgICogQHJldHVybnMgYSBiYXNlNjQgZW5jb2RlZCBwc2J0IHN0cmluZ1xuICAgKi9cbiAgYnVpbGRNdWx0aXNpZ1BTQlQoXG4gICAgbTogbnVtYmVyLFxuICAgIHB1YmtleXM6IHN0cmluZ1tdLFxuICAgIGlucHV0czogSW5wdXRbXSxcbiAgICBvdXRwdXRzOiBPdXRwdXRbXSxcbiAgKTogc3RyaW5nIHtcbiAgICBhc3NlcnQoaW5wdXRzLmxlbmd0aCA+IDAsICdubyBpbnB1dHMgZm91bmQnKTtcbiAgICBhc3NlcnQob3V0cHV0cy5sZW5ndGggPiAwLCAnbm8gb3V0cHV0cyBmb3VuZCcpO1xuXG4gICAgY29uc3QgcDJ3c2ggPSB0aGlzLl9jcmVhdGVNdWx0aXNpZ1BheW1lbnQobSwgcHVia2V5cyk7XG5cbiAgICAvLyBWZXJpZnkgcHVia2V5aGFzaCBmb3IgYWxsIGlucHV0cyBtYXRjaGVzIHRoZSBwMndzaCBoYXNoXG4gICAgYXNzZXJ0KFxuICAgICAgaW5wdXRzLmV2ZXJ5KFxuICAgICAgICAoaW5wdXQ6IElucHV0KSA9PiBwMndzaC5vdXRwdXQudG9TdHJpbmcoJ2hleCcpID09PSBpbnB1dC5zY3JpcHRQdWJLZXksXG4gICAgICApLFxuICAgICAgJ2FkZHJlc3MgcHVia2V5aGFzaCBkb2VzIG5vdCBtYXRjaCBpbnB1dCBzY3JpcHRQdWJLZXknLFxuICAgICk7XG5cbiAgICAvLyBjcmVhdG9yXG4gICAgY29uc3QgcHNidCA9IG5ldyBiaXRjb2luLlBzYnQoeyBuZXR3b3JrOiB0aGlzLl9uZXR3b3JrIH0pO1xuXG4gICAgLy8gdXBkYXRlclxuICAgIGlucHV0cy5mb3JFYWNoKChpbnB1dDogSW5wdXQpID0+IHtcbiAgICAgIHBzYnQuYWRkSW5wdXQoe1xuICAgICAgICBoYXNoOiBpbnB1dC50eGlkLFxuICAgICAgICBpbmRleDogaW5wdXQudm91dCxcbiAgICAgICAgd2l0bmVzc1V0eG86IHsgc2NyaXB0OiBwMndzaC5vdXRwdXQsIHZhbHVlOiBpbnB1dC52YWx1ZSB9LFxuICAgICAgICB3aXRuZXNzU2NyaXB0OiBwMndzaC5yZWRlZW0ub3V0cHV0LFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBvdXRwdXRzLmZvckVhY2goKG91dHB1dDogT3V0cHV0KSA9PiB7XG4gICAgICBwc2J0LmFkZE91dHB1dCh7XG4gICAgICAgIGFkZHJlc3M6IG91dHB1dC50byxcbiAgICAgICAgdmFsdWU6IG91dHB1dC52YWx1ZSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHBzYnQudG9CYXNlNjQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgYSBQU0JUIHdpdGggaW5wdXQgaW5mb3JtYXRpb24gZnJvbSBvdXIgd2FsbGV0IGFuZCB0aGVuIHNpZ24gaW5wdXRzIHRoYXQgd2UgY2FuIHNpZ24gZm9yXG4gICAqIGh0dHBzOi8vZGV2ZWxvcGVyLmJpdGNvaW4ub3JnL3JlZmVyZW5jZS9ycGMvd2FsbGV0cHJvY2Vzc3BzYnQuaHRtbFxuICAgKiBAcGFyYW0gcHNidCBhIGJhc2U2NCBlbmNvZGVkIHBzYnQgc3RyaW5nIChQMldTSCBvbmx5KVxuICAgKiBAcmV0dXJucyBhIGJhc2U2NCBlbmNvZGVkIHNpZ25lZCBwc2J0IHN0cmluZ1xuICAgKi9cbiAgYXN5bmMgd2FsbGV0UHJvY2Vzc1BTQlQocHNidFN0cmluZzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBwc2J0ID0gYml0Y29pbi5Qc2J0LmZyb21CYXNlNjQocHNidFN0cmluZyk7XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHBzYnQuZGF0YS5pbnB1dHMubWFwKGFzeW5jIChpbnB1dCwgaTogbnVtYmVyKSA9PiB7XG4gICAgICAgIGFzc2VydChcbiAgICAgICAgICBwc2J0LmdldElucHV0VHlwZShpKS5zbGljZSgwLCA1KSA9PT0gJ3Ayd3NoJyxcbiAgICAgICAgICAnb25seSBhY2NlcHRzIFAyV1NIIGlucHV0cycsXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3Qgc2NyaXB0U3RhY2sgPSBiaXRjb2luLnNjcmlwdC5kZWNvbXBpbGUoaW5wdXQud2l0bmVzc1NjcmlwdCk7XG4gICAgICAgIGNvbnN0IHB1YmtleXMgPSBzY3JpcHRTdGFjay5maWx0ZXIoXG4gICAgICAgICAgKGRhdGEpID0+IEJ1ZmZlci5pc0J1ZmZlcihkYXRhKSAmJiBzZWNwMjU2azEucHVibGljS2V5VmVyaWZ5KGRhdGEpLFxuICAgICAgICApO1xuXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgIHB1YmtleXMubWFwKGFzeW5jIChrZXkpID0+IHtcbiAgICAgICAgICAgIC8vIGNyZWF0ZSBhZGRyZXNzIHVzaW5nIHB1YmtleVxuICAgICAgICAgICAgY29uc3QgeyBhZGRyZXNzOiBhZGRyZXNzU3RyaW5nIH0gPSBiaXRjb2luLnBheW1lbnRzLnAyd3BraCh7XG4gICAgICAgICAgICAgIHB1YmtleToga2V5IGFzIEJ1ZmZlcixcbiAgICAgICAgICAgICAgbmV0d29yazogdGhpcy5fbmV0d29yayxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBSZXRyaWV2ZSBhZGRyZXNzIG9iamVjdCBmcm9tIHdhbGxldCB1c2luZyBhZGRyZXNzXG4gICAgICAgICAgICBjb25zdCBhZGRyZXNzOiBBZGRyZXNzID0gYXdhaXQgdGhpcy5xdWlja0ZpbmRBZGRyZXNzKFtcbiAgICAgICAgICAgICAgYWRkcmVzc1N0cmluZyxcbiAgICAgICAgICAgIF0pO1xuXG4gICAgICAgICAgICAvLyBleGl0IGlmIGFkZHJlc3MgZG9lc24ndCBleGlzdCBpbiB3YWxsZXRcbiAgICAgICAgICAgIGlmICghYWRkcmVzcykgcmV0dXJuO1xuXG4gICAgICAgICAgICAvLyBkZXJpdmUga2V5cGFpclxuICAgICAgICAgICAgY29uc3Qga2V5UGFpciA9IGF3YWl0IHRoaXMuZ2V0TWV0aG9kKCdrZXlQYWlyJykoXG4gICAgICAgICAgICAgIGFkZHJlc3MuZGVyaXZhdGlvblBhdGgsXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAvLyBzaWduIFBTQlQgdXNpbmcga2V5cGFpclxuICAgICAgICAgICAgcHNidC5zaWduSW5wdXQoaSwga2V5UGFpcik7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgcHNidC52YWxpZGF0ZVNpZ25hdHVyZXNPZkFsbElucHV0cygpOyAvLyBlbnN1cmUgYWxsIHNpZ25hdHVyZXMgYXJlIHZhbGlkIVxuICAgIHJldHVybiBwc2J0LnRvQmFzZTY0KCk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgdGhlIGlucHV0cyBvZiBhIFBTQlQuIElmIHRoZSB0cmFuc2FjdGlvbiBpcyBmdWxseSBzaWduZWQsIGl0IHdpbGxcbiAgICogcHJvZHVjZSBhIG5ldHdvcmsgc2VyaWFsaXplZCB0cmFuc2FjdGlvbiB3aGljaCBjYW4gYmUgYnJvYWRjYXN0IHdpdGggc2VuZHJhd3RyYW5zYWN0aW9uXG4gICAqIGh0dHBzOi8vZGV2ZWxvcGVyLmJpdGNvaW4ub3JnL3JlZmVyZW5jZS9ycGMvZmluYWxpemVwc2J0Lmh0bWxcbiAgICogQHBhcmFtIHBzYnQgYSBiYXNlNjQgZW5jb2RlZCBwc2J0IHN0cmluZ1xuICAgKiBAcmV0dXJucyBhIGpzb24gb2JqZWN0IGNvbnRhaW5pbmcgYHBzYnRgIGluIGJhc2U2NCwgYGhleGAgZm9yIHRyYW5zYWN0aW9uIGFuZCBgY29tcGxldGVgIGZvciBpZlxuICAgKiB0aGUgdHJhbnNhY3Rpb24gaGFzIGEgY29tcGxldGUgc2V0IG9mIHNpZ25hdHVyZXNcbiAgICovXG4gIGZpbmFsaXplUFNCVChwc2J0U3RyaW5nOiBzdHJpbmcpOiBmaW5hbGl6ZVBTQlRSZXNwb25zZSB7XG4gICAgY29uc3QgcHNidCA9IGJpdGNvaW4uUHNidC5mcm9tQmFzZTY0KHBzYnRTdHJpbmcpO1xuXG4gICAgdHJ5IHtcbiAgICAgIHBzYnQudmFsaWRhdGVTaWduYXR1cmVzT2ZBbGxJbnB1dHMoKTsgLy8gZW5zdXJlIGFsbCBzaWduYXR1cmVzIGFyZSB2YWxpZCFcbiAgICAgIHBzYnQuZmluYWxpemVBbGxJbnB1dHMoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcHNidDogcHNidC50b0Jhc2U2NCgpLFxuICAgICAgICBjb21wbGV0ZTogZmFsc2UsXG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgcHNidDogcHNidC50b0Jhc2U2NCgpLFxuICAgICAgaGV4OiBwc2J0LmV4dHJhY3RUcmFuc2FjdGlvbigpLnRvSGV4KCksXG4gICAgICBjb21wbGV0ZTogdHJ1ZSxcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgZ2V0VW51c2VkQWRkcmVzcyhjaGFuZ2UgPSBmYWxzZSwgbnVtQWRkcmVzc1BlckNhbGwgPSAxMDApIHtcbiAgICBjb25zdCBhZGRyZXNzVHlwZSA9IGNoYW5nZSA/IENIQU5HRV9BRERSRVNTIDogTk9OQ0hBTkdFX0FERFJFU1M7XG4gICAgY29uc3Qga2V5ID0gY2hhbmdlID8gJ2NoYW5nZScgOiAnbm9uQ2hhbmdlJztcblxuICAgIGNvbnN0IGFkZHJlc3MgPSBhd2FpdCB0aGlzLl9nZXRVc2VkVW51c2VkQWRkcmVzc2VzKFxuICAgICAgbnVtQWRkcmVzc1BlckNhbGwsXG4gICAgICBhZGRyZXNzVHlwZSxcbiAgICApLnRoZW4oKHsgdW51c2VkQWRkcmVzcyB9KSA9PiB1bnVzZWRBZGRyZXNzW2tleV0pO1xuICAgIHRoaXMuX3VudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdFthZGRyZXNzLmFkZHJlc3NdID0gdHJ1ZTtcblxuICAgIHJldHVybiBhZGRyZXNzO1xuICB9XG5cbiAgYXN5bmMgX2dldFVzZWRVbnVzZWRBZGRyZXNzZXMobnVtQWRkcmVzc1BlckNhbGwgPSAxMDAsIGFkZHJlc3NUeXBlKSB7XG4gICAgY29uc3QgdXNlZEFkZHJlc3NlcyA9IFtdO1xuICAgIGNvbnN0IGFkZHJlc3NDb3VudE1hcCA9IHsgY2hhbmdlOiAwLCBub25DaGFuZ2U6IDAgfTtcbiAgICBjb25zdCB1bnVzZWRBZGRyZXNzTWFwID0geyBjaGFuZ2U6IG51bGwsIG5vbkNoYW5nZTogbnVsbCB9O1xuXG4gICAgbGV0IGFkZHJMaXN0O1xuICAgIGxldCBhZGRyZXNzSW5kZXggPSAwO1xuICAgIGxldCBjaGFuZ2VBZGRyZXNzZXM6IEFkZHJlc3NbXSA9IFtdO1xuICAgIGxldCBub25DaGFuZ2VBZGRyZXNzZXM6IEFkZHJlc3NbXSA9IFtdO1xuXG4gICAgLyogZXNsaW50LWRpc2FibGUgbm8tdW5tb2RpZmllZC1sb29wLWNvbmRpdGlvbiAqL1xuICAgIHdoaWxlIChcbiAgICAgIChhZGRyZXNzVHlwZSA9PT0gTk9OQ0hBTkdFX09SX0NIQU5HRV9BRERSRVNTICYmXG4gICAgICAgIChhZGRyZXNzQ291bnRNYXAuY2hhbmdlIDwgQUREUkVTU19HQVAgfHxcbiAgICAgICAgICBhZGRyZXNzQ291bnRNYXAubm9uQ2hhbmdlIDwgQUREUkVTU19HQVApKSB8fFxuICAgICAgKGFkZHJlc3NUeXBlID09PSBOT05DSEFOR0VfQUREUkVTUyAmJlxuICAgICAgICBhZGRyZXNzQ291bnRNYXAubm9uQ2hhbmdlIDwgQUREUkVTU19HQVApIHx8XG4gICAgICAoYWRkcmVzc1R5cGUgPT09IENIQU5HRV9BRERSRVNTICYmIGFkZHJlc3NDb3VudE1hcC5jaGFuZ2UgPCBBRERSRVNTX0dBUClcbiAgICApIHtcbiAgICAgIC8qIGVzbGludC1lbmFibGUgbm8tdW5tb2RpZmllZC1sb29wLWNvbmRpdGlvbiAqL1xuICAgICAgYWRkckxpc3QgPSBbXTtcblxuICAgICAgaWYgKFxuICAgICAgICAoYWRkcmVzc1R5cGUgPT09IE5PTkNIQU5HRV9PUl9DSEFOR0VfQUREUkVTUyB8fFxuICAgICAgICAgIGFkZHJlc3NUeXBlID09PSBDSEFOR0VfQUREUkVTUykgJiZcbiAgICAgICAgYWRkcmVzc0NvdW50TWFwLmNoYW5nZSA8IEFERFJFU1NfR0FQXG4gICAgICApIHtcbiAgICAgICAgLy8gU2Nhbm5pbmcgZm9yIGNoYW5nZSBhZGRyXG4gICAgICAgIGNoYW5nZUFkZHJlc3NlcyA9IGF3YWl0IHRoaXMuY2xpZW50LndhbGxldC5nZXRBZGRyZXNzZXMoXG4gICAgICAgICAgYWRkcmVzc0luZGV4LFxuICAgICAgICAgIG51bUFkZHJlc3NQZXJDYWxsLFxuICAgICAgICAgIHRydWUsXG4gICAgICAgICk7XG4gICAgICAgIGFkZHJMaXN0ID0gYWRkckxpc3QuY29uY2F0KGNoYW5nZUFkZHJlc3Nlcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjaGFuZ2VBZGRyZXNzZXMgPSBbXTtcbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICAoYWRkcmVzc1R5cGUgPT09IE5PTkNIQU5HRV9PUl9DSEFOR0VfQUREUkVTUyB8fFxuICAgICAgICAgIGFkZHJlc3NUeXBlID09PSBOT05DSEFOR0VfQUREUkVTUykgJiZcbiAgICAgICAgYWRkcmVzc0NvdW50TWFwLm5vbkNoYW5nZSA8IEFERFJFU1NfR0FQXG4gICAgICApIHtcbiAgICAgICAgLy8gU2Nhbm5pbmcgZm9yIG5vbiBjaGFuZ2UgYWRkclxuICAgICAgICBub25DaGFuZ2VBZGRyZXNzZXMgPSBhd2FpdCB0aGlzLnF1aWNrR2V0QWRkcmVzc2VzKFxuICAgICAgICAgIGFkZHJlc3NJbmRleCxcbiAgICAgICAgICBudW1BZGRyZXNzUGVyQ2FsbCxcbiAgICAgICAgICBmYWxzZSxcbiAgICAgICAgKTtcbiAgICAgICAgYWRkckxpc3QgPSBhZGRyTGlzdC5jb25jYXQobm9uQ2hhbmdlQWRkcmVzc2VzKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdHJhbnNhY3Rpb25Db3VudHMgPSBhd2FpdCB0aGlzLmdldE1ldGhvZChcbiAgICAgICAgJ2dldEFkZHJlc3NUcmFuc2FjdGlvbkNvdW50cycsXG4gICAgICApKGFkZHJMaXN0KTtcblxuICAgICAgZm9yIChjb25zdCBhZGRyZXNzIG9mIGFkZHJMaXN0KSB7XG4gICAgICAgIGNvbnN0IGlzVXNlZCA9XG4gICAgICAgICAgdHJhbnNhY3Rpb25Db3VudHNbYWRkcmVzcy5hZGRyZXNzXSA+IDAgfHxcbiAgICAgICAgICB0aGlzLl91bnVzZWRBZGRyZXNzZXNCbGFja2xpc3RbYWRkcmVzcy5hZGRyZXNzXTtcbiAgICAgICAgY29uc3QgaXNDaGFuZ2VBZGRyZXNzID0gY2hhbmdlQWRkcmVzc2VzLmZpbmQoXG4gICAgICAgICAgKGEpID0+IGFkZHJlc3MuYWRkcmVzcyA9PT0gYS5hZGRyZXNzLFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBrZXkgPSBpc0NoYW5nZUFkZHJlc3MgPyAnY2hhbmdlJyA6ICdub25DaGFuZ2UnO1xuXG4gICAgICAgIGlmIChpc1VzZWQpIHtcbiAgICAgICAgICB1c2VkQWRkcmVzc2VzLnB1c2goYWRkcmVzcyk7XG4gICAgICAgICAgYWRkcmVzc0NvdW50TWFwW2tleV0gPSAwO1xuICAgICAgICAgIHVudXNlZEFkZHJlc3NNYXBba2V5XSA9IG51bGw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYWRkcmVzc0NvdW50TWFwW2tleV0rKztcblxuICAgICAgICAgIGlmICghdW51c2VkQWRkcmVzc01hcFtrZXldKSB7XG4gICAgICAgICAgICB1bnVzZWRBZGRyZXNzTWFwW2tleV0gPSBhZGRyZXNzO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBhZGRyZXNzSW5kZXggKz0gbnVtQWRkcmVzc1BlckNhbGw7XG4gICAgfVxuXG4gICAgbGV0IGZpcnN0VW51c2VkQWRkcmVzcztcbiAgICBjb25zdCBpbmRleE5vbkNoYW5nZSA9IHVudXNlZEFkZHJlc3NNYXAubm9uQ2hhbmdlXG4gICAgICA/IHVudXNlZEFkZHJlc3NNYXAubm9uQ2hhbmdlLmluZGV4XG4gICAgICA6IEluZmluaXR5O1xuICAgIGNvbnN0IGluZGV4Q2hhbmdlID0gdW51c2VkQWRkcmVzc01hcC5jaGFuZ2VcbiAgICAgID8gdW51c2VkQWRkcmVzc01hcC5jaGFuZ2UuaW5kZXhcbiAgICAgIDogSW5maW5pdHk7XG5cbiAgICBpZiAoaW5kZXhOb25DaGFuZ2UgPD0gaW5kZXhDaGFuZ2UpXG4gICAgICBmaXJzdFVudXNlZEFkZHJlc3MgPSB1bnVzZWRBZGRyZXNzTWFwLm5vbkNoYW5nZTtcbiAgICBlbHNlIGZpcnN0VW51c2VkQWRkcmVzcyA9IHVudXNlZEFkZHJlc3NNYXAuY2hhbmdlO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHVzZWRBZGRyZXNzZXMsXG4gICAgICB1bnVzZWRBZGRyZXNzOiB1bnVzZWRBZGRyZXNzTWFwLFxuICAgICAgZmlyc3RVbnVzZWRBZGRyZXNzLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBzZW5kU3dlZXBUcmFuc2FjdGlvbldpdGhTZXRPdXRwdXRzKFxuICAgIGV4dGVybmFsQ2hhbmdlQWRkcmVzczogc3RyaW5nLFxuICAgIGZlZVBlckJ5dGU6IG51bWJlcixcbiAgICBfb3V0cHV0czogT3V0cHV0W10sXG4gICAgZml4ZWRJbnB1dHM6IElucHV0W10sXG4gICk6IFByb21pc2U8VHJhbnNhY3Rpb248YlQuVHJhbnNhY3Rpb24+PiB7XG4gICAgY29uc3QgeyBoZXgsIGZlZSB9ID0gYXdhaXQgdGhpcy5fYnVpbGRTd2VlcFRyYW5zYWN0aW9uKFxuICAgICAgZXh0ZXJuYWxDaGFuZ2VBZGRyZXNzLFxuICAgICAgZmVlUGVyQnl0ZSxcbiAgICAgIF9vdXRwdXRzLFxuICAgICAgZml4ZWRJbnB1dHMsXG4gICAgKTtcbiAgICBhd2FpdCB0aGlzLmdldE1ldGhvZCgnc2VuZFJhd1RyYW5zYWN0aW9uJykoaGV4KTtcbiAgICByZXR1cm4gbm9ybWFsaXplVHJhbnNhY3Rpb25PYmplY3QoXG4gICAgICBkZWNvZGVSYXdUcmFuc2FjdGlvbihoZXgsIHRoaXMuX25ldHdvcmspLFxuICAgICAgZmVlLFxuICAgICk7XG4gIH1cblxuICBhc3luYyBfYnVpbGRTd2VlcFRyYW5zYWN0aW9uKFxuICAgIGV4dGVybmFsQ2hhbmdlQWRkcmVzczogc3RyaW5nLFxuICAgIGZlZVBlckJ5dGU6IG51bWJlcixcbiAgICBfb3V0cHV0czogT3V0cHV0W10gPSBbXSxcbiAgICBmaXhlZElucHV0czogSW5wdXRbXSxcbiAgKSB7XG4gICAgY29uc3QgX2ZlZVBlckJ5dGUgPVxuICAgICAgZmVlUGVyQnl0ZSB8fFxuICAgICAgKGF3YWl0IHRoaXMuZ2V0TWV0aG9kKCdnZXRGZWVQZXJCeXRlJykoKSkgfHxcbiAgICAgIEZFRV9QRVJfQllURV9GQUxMQkFDSztcbiAgICBjb25zdCBpbnB1dHM6IElucHV0W10gPSBbXTtcbiAgICBjb25zdCBvdXRwdXRzOiBPdXRwdXRbXSA9IFtdO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBpbnB1dHNGb3JBbW91bnQgPSBhd2FpdCB0aGlzLmdldE1ldGhvZCgnZ2V0SW5wdXRzRm9yQW1vdW50JykoXG4gICAgICAgIF9vdXRwdXRzLFxuICAgICAgICBfZmVlUGVyQnl0ZSxcbiAgICAgICAgZml4ZWRJbnB1dHMsXG4gICAgICAgIDEwMCxcbiAgICAgICAgdHJ1ZSxcbiAgICAgICk7XG4gICAgICBpZiAoaW5wdXRzRm9yQW1vdW50LmNoYW5nZSkge1xuICAgICAgICB0aHJvdyBFcnJvcignVGhlcmUgc2hvdWxkIG5vdCBiZSBhbnkgY2hhbmdlIGZvciBzd2VlcGluZyB0cmFuc2FjdGlvbicpO1xuICAgICAgfVxuICAgICAgaW5wdXRzLnB1c2goLi4uKGlucHV0c0ZvckFtb3VudC5pbnB1dHMgfHwgW10pKTtcbiAgICAgIG91dHB1dHMucHVzaCguLi4oaW5wdXRzRm9yQW1vdW50Lm91dHB1dHMgfHwgW10pKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoZml4ZWRJbnB1dHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IEVycm9yKFxuICAgICAgICAgIGBJbnB1dHMgZm9yIGFtb3VudCBkb2Vzbid0IGV4aXN0IGFuZCBubyBmaXhlZElucHV0cyBwcm92aWRlZGAsXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlucHV0c0ZvckFtb3VudCA9IGF3YWl0IHRoaXMuX2dldElucHV0Rm9yQW1vdW50V2l0aG91dFV0eG9DaGVjayhcbiAgICAgICAgX291dHB1dHMsXG4gICAgICAgIF9mZWVQZXJCeXRlLFxuICAgICAgICBmaXhlZElucHV0cyxcbiAgICAgICk7XG4gICAgICBpbnB1dHMucHVzaChcbiAgICAgICAgLi4uKGlucHV0c0ZvckFtb3VudC5pbnB1dHMubWFwKCh1dHhvKSA9PiBJbnB1dC5mcm9tVVRYTyh1dHhvKSkgfHwgW10pLFxuICAgICAgKTtcbiAgICAgIG91dHB1dHMucHVzaCguLi4oaW5wdXRzRm9yQW1vdW50Lm91dHB1dHMgfHwgW10pKTtcbiAgICB9XG4gICAgX291dHB1dHMuZm9yRWFjaCgob3V0cHV0KSA9PiB7XG4gICAgICBjb25zdCBzcGxpY2VJbmRleCA9IG91dHB1dHMuZmluZEluZGV4KFxuICAgICAgICAoc3dlZXBPdXRwdXQ6IE91dHB1dCkgPT4gb3V0cHV0LnZhbHVlID09PSBzd2VlcE91dHB1dC52YWx1ZSxcbiAgICAgICk7XG4gICAgICBvdXRwdXRzLnNwbGljZShzcGxpY2VJbmRleCwgMSk7XG4gICAgfSk7XG4gICAgX291dHB1dHMucHVzaCh7XG4gICAgICB0bzogZXh0ZXJuYWxDaGFuZ2VBZGRyZXNzLFxuICAgICAgdmFsdWU6IG91dHB1dHNbMF0udmFsdWUsXG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXMuX2J1aWxkVHJhbnNhY3Rpb25XaXRob3V0VXR4b0NoZWNrKFxuICAgICAgX291dHB1dHMsXG4gICAgICBfZmVlUGVyQnl0ZSxcbiAgICAgIGlucHV0cyxcbiAgICApO1xuICB9XG5cbiAgX2dldElucHV0Rm9yQW1vdW50V2l0aG91dFV0eG9DaGVjayhcbiAgICBfb3V0cHV0czogT3V0cHV0W10sXG4gICAgX2ZlZVBlckJ5dGU6IG51bWJlcixcbiAgICBmaXhlZElucHV0czogSW5wdXRbXSxcbiAgKToge1xuICAgIGlucHV0czogYlQuVVRYT1tdO1xuICAgIG91dHB1dHM6IHsgdmFsdWU6IG51bWJlcjsgaWQ/OiBzdHJpbmcgfVtdO1xuICAgIGZlZTogbnVtYmVyO1xuICAgIGNoYW5nZTogeyB2YWx1ZTogbnVtYmVyOyBpZD86IHN0cmluZyB9O1xuICB9IHtcbiAgICBjb25zdCB1dHhvQmFsYW5jZSA9IGZpeGVkSW5wdXRzLnJlZHVjZSgoYSwgYikgPT4gYSArIChiWyd2YWx1ZSddIHx8IDApLCAwKTtcbiAgICBjb25zdCBvdXRwdXRCYWxhbmNlID0gX291dHB1dHMucmVkdWNlKChhLCBiKSA9PiBhICsgKGJbJ3ZhbHVlJ10gfHwgMCksIDApO1xuICAgIGNvbnN0IGFtb3VudFRvU2VuZCA9XG4gICAgICB1dHhvQmFsYW5jZSAtXG4gICAgICBfZmVlUGVyQnl0ZSAqICgoX291dHB1dHMubGVuZ3RoICsgMSkgKiAzOSArIGZpeGVkSW5wdXRzLmxlbmd0aCAqIDE1Myk7IC8vIHRvZG8gYmV0dGVyIGNhbGN1bGF0aW9uXG5cbiAgICBjb25zdCB0YXJnZXRzID0gX291dHB1dHMubWFwKCh0YXJnZXQsIGkpID0+ICh7XG4gICAgICBpZDogJ21haW4nLFxuICAgICAgdmFsdWU6IHRhcmdldC52YWx1ZSxcbiAgICB9KSk7XG4gICAgaWYgKGFtb3VudFRvU2VuZCAtIG91dHB1dEJhbGFuY2UgPiAwKSB7XG4gICAgICB0YXJnZXRzLnB1c2goeyBpZDogJ21haW4nLCB2YWx1ZTogYW1vdW50VG9TZW5kIC0gb3V0cHV0QmFsYW5jZSB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VsZWN0Q29pbnMoXG4gICAgICBmaXhlZElucHV0cyxcbiAgICAgIHRhcmdldHMsXG4gICAgICBNYXRoLmNlaWwoX2ZlZVBlckJ5dGUpLFxuICAgICAgZml4ZWRJbnB1dHMsXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIF9idWlsZFRyYW5zYWN0aW9uV2l0aG91dFV0eG9DaGVjayhcbiAgICBvdXRwdXRzOiBPdXRwdXRbXSxcbiAgICBmZWVQZXJCeXRlOiBudW1iZXIsXG4gICAgZml4ZWRJbnB1dHM6IElucHV0W10sXG4gICkge1xuICAgIGNvbnN0IG5ldHdvcmsgPSB0aGlzLl9uZXR3b3JrO1xuXG4gICAgY29uc3QgeyBmZWUgfSA9IHRoaXMuX2dldElucHV0Rm9yQW1vdW50V2l0aG91dFV0eG9DaGVjayhcbiAgICAgIG91dHB1dHMsXG4gICAgICBmZWVQZXJCeXRlLFxuICAgICAgZml4ZWRJbnB1dHMsXG4gICAgKTtcbiAgICBjb25zdCBpbnB1dHMgPSBmaXhlZElucHV0cztcblxuICAgIGNvbnN0IHR4YiA9IG5ldyBiaXRjb2luLlRyYW5zYWN0aW9uQnVpbGRlcihuZXR3b3JrKTtcblxuICAgIGZvciAoY29uc3Qgb3V0cHV0IG9mIG91dHB1dHMpIHtcbiAgICAgIGNvbnN0IHRvID0gb3V0cHV0LnRvOyAvLyBBbGxvdyBmb3IgT1BfUkVUVVJOXG4gICAgICB0eGIuYWRkT3V0cHV0KHRvLCBvdXRwdXQudmFsdWUpO1xuICAgIH1cblxuICAgIGNvbnN0IHByZXZPdXRTY3JpcHRUeXBlID0gJ3Ayd3BraCc7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0cy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3Qgd2FsbGV0ID0gYXdhaXQgdGhpcy5nZXRNZXRob2QoJ2dldFdhbGxldEFkZHJlc3MnKShcbiAgICAgICAgaW5wdXRzW2ldLmFkZHJlc3MsXG4gICAgICApO1xuICAgICAgY29uc3Qga2V5UGFpciA9IGF3YWl0IHRoaXMuZ2V0TWV0aG9kKCdrZXlQYWlyJykod2FsbGV0LmRlcml2YXRpb25QYXRoKTtcbiAgICAgIGNvbnN0IHBheW1lbnRWYXJpYW50ID0gdGhpcy5nZXRNZXRob2QoJ2dldFBheW1lbnRWYXJpYW50RnJvbVB1YmxpY0tleScpKFxuICAgICAgICBrZXlQYWlyLnB1YmxpY0tleSxcbiAgICAgICk7XG5cbiAgICAgIHR4Yi5hZGRJbnB1dChpbnB1dHNbaV0udHhpZCwgaW5wdXRzW2ldLnZvdXQsIDAsIHBheW1lbnRWYXJpYW50Lm91dHB1dCk7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbnB1dHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IHdhbGxldCA9IGF3YWl0IHRoaXMuZ2V0TWV0aG9kKCdnZXRXYWxsZXRBZGRyZXNzJykoXG4gICAgICAgIGlucHV0c1tpXS5hZGRyZXNzLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBhd2FpdCB0aGlzLmdldE1ldGhvZCgna2V5UGFpcicpKHdhbGxldC5kZXJpdmF0aW9uUGF0aCk7XG4gICAgICBjb25zdCBwYXltZW50VmFyaWFudCA9IHRoaXMuZ2V0TWV0aG9kKCdnZXRQYXltZW50VmFyaWFudEZyb21QdWJsaWNLZXknKShcbiAgICAgICAga2V5UGFpci5wdWJsaWNLZXksXG4gICAgICApO1xuICAgICAgY29uc3QgbmVlZHNXaXRuZXNzID0gdHJ1ZTtcblxuICAgICAgY29uc3Qgc2lnblBhcmFtcyA9IHtcbiAgICAgICAgcHJldk91dFNjcmlwdFR5cGUsXG4gICAgICAgIHZpbjogaSxcbiAgICAgICAga2V5UGFpcixcbiAgICAgICAgd2l0bmVzc1ZhbHVlOiAwLFxuICAgICAgfTtcblxuICAgICAgaWYgKG5lZWRzV2l0bmVzcykge1xuICAgICAgICBzaWduUGFyYW1zLndpdG5lc3NWYWx1ZSA9IGlucHV0c1tpXS52YWx1ZTtcbiAgICAgIH1cblxuICAgICAgdHhiLnNpZ24oc2lnblBhcmFtcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgaGV4OiB0eGIuYnVpbGQoKS50b0hleCgpLCBmZWUgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBxdWlja0dldEFkZHJlc3NlcyBpcyBhbiBvcHRpbWl6ZWQgdmVyc2lvbiBvZiBnZXRBZGRyZXNzZXMuXG4gICAqIEl0IHJlbW92ZXMgdGhlIGNhbGwgdG8gYGFzeW5jU2V0SW1tZWRpYXRlKClgLCBzcGVlZGluZyB1cCB0aGUgZnVuY3Rpb24gYnkgYSBmYWN0b3Igb2YgNnguXG4gICAqXG4gICAqIEBwYXJhbSBzdGFydGluZ0luZGV4XG4gICAqIEBwYXJhbSBudW1BZGRyZXNzZXNcbiAgICogQHBhcmFtIGNoYW5nZVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBZGRyZXNzW10+fVxuICAgKi9cbiAgYXN5bmMgcXVpY2tHZXRBZGRyZXNzZXMoXG4gICAgc3RhcnRpbmdJbmRleCA9IDAsXG4gICAgbnVtQWRkcmVzc2VzID0gMSxcbiAgICBjaGFuZ2UgPSBmYWxzZSxcbiAgKTogUHJvbWlzZTxBZGRyZXNzW10+IHtcbiAgICBpZiAobnVtQWRkcmVzc2VzIDwgMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbXVzdCByZXR1cm4gYXQgbGVhc3Qgb25lIGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBjb25zdCBhZGRyZXNzZXMgPSBbXTtcbiAgICBjb25zdCBsYXN0SW5kZXggPSBzdGFydGluZ0luZGV4ICsgbnVtQWRkcmVzc2VzO1xuICAgIGNvbnN0IGNoYW5nZVZhbCA9IGNoYW5nZSA/ICcxJyA6ICcwJztcblxuICAgIC8vIE9yaWdpbmFsIHdhbGxldCBwcm92aWRlciBpcyBmZXRjaGVkIHRvIGdldCB0aGUgYmFzZSBkZXJpdmF0aW9uIHBhdGhcbiAgICBjb25zdCBvcmlnaW5hbFByb3ZpZGVyID0gdGhpcy5jbGllbnQuZ2V0UHJvdmlkZXJGb3JNZXRob2QoJ2dldEFkZHJlc3NlcycpO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gICAgY29uc3QgYmFzZURlcml2YXRpb25QYXRoID0gKG9yaWdpbmFsUHJvdmlkZXIgYXMgYW55KVxuICAgICAgLl9iYXNlRGVyaXZhdGlvblBhdGggYXMgc3RyaW5nO1xuXG4gICAgY29uc3QgZ2V0RGVyaXZhdGlvblBhdGhBZGRyZXNzRm46IChcbiAgICAgIHBhdGg6IHN0cmluZyxcbiAgICApID0+IFByb21pc2U8QWRkcmVzcz4gPSB0aGlzLmNsaWVudC5nZXRNZXRob2QoJ2dldERlcml2YXRpb25QYXRoQWRkcmVzcycpO1xuXG4gICAgZm9yIChcbiAgICAgIGxldCBjdXJyZW50SW5kZXggPSBzdGFydGluZ0luZGV4O1xuICAgICAgY3VycmVudEluZGV4IDwgbGFzdEluZGV4O1xuICAgICAgY3VycmVudEluZGV4KytcbiAgICApIHtcbiAgICAgIGNvbnN0IHN1YlBhdGggPSBjaGFuZ2VWYWwgKyAnLycgKyBjdXJyZW50SW5kZXg7XG4gICAgICBjb25zdCBwYXRoID0gYmFzZURlcml2YXRpb25QYXRoICsgJy8nICsgc3ViUGF0aDtcbiAgICAgIGNvbnN0IGFkZHJlc3NPYmplY3QgPSBhd2FpdCBnZXREZXJpdmF0aW9uUGF0aEFkZHJlc3NGbihwYXRoKTtcbiAgICAgIGFkZHJlc3Nlcy5wdXNoKGFkZHJlc3NPYmplY3QpO1xuICAgIH1cblxuICAgIHJldHVybiBhZGRyZXNzZXM7XG4gIH1cblxuICAvKipcbiAgICogcXVpY2tGaW5kQWRkcmVzcyBpcyBhbiBvcHRpbWl6ZWQgdmVyc2lvbiBvZiBmaW5kQWRkcmVzcy5cbiAgICpcbiAgICogSXQgc2VhcmNoZXMgdGhyb3VnaCBib3RoIGNoYW5nZSBhbmQgbm9uLWNoYW5nZSBhZGRyZXNzZXMgZWFjaCBpdGVyYXRpb24uXG4gICAqXG4gICAqIFRoaXMgaXMgaW4gY29udHJhc3QgdG8gdGhlIG9yaWdpbmFsIGZpbmRBZGRyZXNzIGZ1bmN0aW9uIHdoaWNoIHNlYXJjaGVzXG4gICAqIHRocm91Z2ggYWxsIG5vbi1jaGFuZ2UgYWRkcmVzc2VzIGJlZm9yZSBtb3Zpbmcgb24gdG8gY2hhbmdlIGFkZHJlc3Nlcy5cbiAgICpcbiAgICogQHBhcmFtIGFkZHJlc3Nlc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBZGRyZXNzW10+fVxuICAgKi9cbiAgYXN5bmMgcXVpY2tGaW5kQWRkcmVzcyhhZGRyZXNzZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxBZGRyZXNzPiB7XG4gICAgY29uc3QgYWRkcmVzc2VzUGVyQ2FsbCA9IDIwO1xuICAgIGxldCBpbmRleCA9IDA7XG5cbiAgICB3aGlsZSAoaW5kZXggPCB0aGlzLl9tYXhBZGRyZXNzZXNUb0Rlcml2ZSkge1xuICAgICAgY29uc3Qgd2FsbGV0Tm9uQ2hhbmdlQWRkcmVzc2VzID0gYXdhaXQgdGhpcy5xdWlja0dldEFkZHJlc3NlcyhcbiAgICAgICAgaW5kZXgsXG4gICAgICAgIGFkZHJlc3Nlc1BlckNhbGwsXG4gICAgICAgIHRydWUsXG4gICAgICApO1xuICAgICAgY29uc3Qgd2FsbGV0Q2hhbmdlQWRkcmVzc2VzID0gYXdhaXQgdGhpcy5xdWlja0dldEFkZHJlc3NlcyhcbiAgICAgICAgaW5kZXgsXG4gICAgICAgIGFkZHJlc3Nlc1BlckNhbGwsXG4gICAgICAgIGZhbHNlLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHdhbGxldEFkZHJlc3NlcyA9IFtcbiAgICAgICAgLi4ud2FsbGV0Tm9uQ2hhbmdlQWRkcmVzc2VzLFxuICAgICAgICAuLi53YWxsZXRDaGFuZ2VBZGRyZXNzZXMsXG4gICAgICBdO1xuICAgICAgY29uc3Qgd2FsbGV0QWRkcmVzcyA9IHdhbGxldEFkZHJlc3Nlcy5maW5kKCh3YWxsZXRBZGRyKSA9PlxuICAgICAgICBhZGRyZXNzZXMuZmluZCgoYWRkcikgPT4gd2FsbGV0QWRkci5hZGRyZXNzID09PSBhZGRyKSxcbiAgICAgICk7XG5cbiAgICAgIGlmICh3YWxsZXRBZGRyZXNzKSB7XG4gICAgICAgIC8vIEluY3JlbWVudCBtYXggYWRkcmVzc2VzIHRvIGRlcml2ZSBieSAxMDAgaWYgZm91bmQgd2l0aGluIDEwMCBhZGRyZXNzZXMgb2YgbWF4QWRkcmVzc2VzVG9EZXJpdmVcbiAgICAgICAgdGhpcy5fbWF4QWRkcmVzc2VzVG9EZXJpdmUgPSBNYXRoLm1heChcbiAgICAgICAgICB0aGlzLl9tYXhBZGRyZXNzZXNUb0Rlcml2ZSxcbiAgICAgICAgICBpbmRleCArIDEwMCxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHdhbGxldEFkZHJlc3M7XG4gICAgICB9XG4gICAgICBpbmRleCArPSBhZGRyZXNzZXNQZXJDYWxsO1xuICAgIH1cbiAgfVxufVxuIl0sIm5hbWVzIjpbImJpdGNvaW4iLCJGRUVfUEVSX0JZVEVfRkFMTEJBQ0siLCJBRERSRVNTX0dBUCIsIk5PTkNIQU5HRV9BRERSRVNTIiwiQ0hBTkdFX0FERFJFU1MiLCJOT05DSEFOR0VfT1JfQ0hBTkdFX0FERFJFU1MiLCJCaXRjb2luV2FsbGV0UHJvdmlkZXIiLCJQcm92aWRlciIsImJ1aWxkU3dlZXBUcmFuc2FjdGlvbldpdGhTZXRPdXRwdXRzIiwiZXh0ZXJuYWxDaGFuZ2VBZGRyZXNzIiwiZmVlUGVyQnl0ZSIsIl9vdXRwdXRzIiwiZml4ZWRJbnB1dHMiLCJfYnVpbGRTd2VlcFRyYW5zYWN0aW9uIiwiZ2V0VW51c2VkQWRkcmVzc2VzQmxhY2tsaXN0IiwiX3VudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdCIsInNldFVudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdCIsInVudXNlZEFkZHJlc3Nlc0JsYWNrbGlzdCIsInNldE1heEFkZHJlc3Nlc1RvRGVyaXZlIiwibWF4QWRkcmVzc2VzVG9EZXJpdmUiLCJfbWF4QWRkcmVzc2VzVG9EZXJpdmUiLCJnZXRNYXhBZGRyZXNzZXNUb0Rlcml2ZSIsIl9jcmVhdGVNdWx0aXNpZ1BheW1lbnQiLCJtIiwicHVia2V5cyIsImxlbmd0aCIsIkVycm9yIiwicDJtcyIsInBheW1lbnRzIiwibWFwIiwia2V5IiwiQnVmZmVyIiwiZnJvbSIsIm5ldHdvcmsiLCJfbmV0d29yayIsInAyd3NoIiwicmVkZWVtIiwiY3JlYXRlTXVsdGlzaWciLCJhZGRyZXNzIiwicmVkZWVtU2NyaXB0Iiwib3V0cHV0IiwidG9TdHJpbmciLCJidWlsZE11bHRpc2lnUFNCVCIsImlucHV0cyIsIm91dHB1dHMiLCJhc3NlcnQiLCJldmVyeSIsImlucHV0Iiwic2NyaXB0UHViS2V5IiwicHNidCIsIlBzYnQiLCJmb3JFYWNoIiwiYWRkSW5wdXQiLCJoYXNoIiwidHhpZCIsImluZGV4Iiwidm91dCIsIndpdG5lc3NVdHhvIiwic2NyaXB0IiwidmFsdWUiLCJ3aXRuZXNzU2NyaXB0IiwiYWRkT3V0cHV0IiwidG8iLCJ0b0Jhc2U2NCIsIndhbGxldFByb2Nlc3NQU0JUIiwicHNidFN0cmluZyIsImZyb21CYXNlNjQiLCJQcm9taXNlIiwiYWxsIiwiZGF0YSIsImkiLCJnZXRJbnB1dFR5cGUiLCJzbGljZSIsInNjcmlwdFN0YWNrIiwiZGVjb21waWxlIiwiZmlsdGVyIiwiaXNCdWZmZXIiLCJzZWNwMjU2azEiLCJwdWJsaWNLZXlWZXJpZnkiLCJhZGRyZXNzU3RyaW5nIiwicDJ3cGtoIiwicHVia2V5IiwicXVpY2tGaW5kQWRkcmVzcyIsImtleVBhaXIiLCJnZXRNZXRob2QiLCJkZXJpdmF0aW9uUGF0aCIsInNpZ25JbnB1dCIsInZhbGlkYXRlU2lnbmF0dXJlc09mQWxsSW5wdXRzIiwiZmluYWxpemVQU0JUIiwiZmluYWxpemVBbGxJbnB1dHMiLCJlcnJvciIsImNvbXBsZXRlIiwiaGV4IiwiZXh0cmFjdFRyYW5zYWN0aW9uIiwidG9IZXgiLCJnZXRVbnVzZWRBZGRyZXNzIiwiY2hhbmdlIiwibnVtQWRkcmVzc1BlckNhbGwiLCJhZGRyZXNzVHlwZSIsIl9nZXRVc2VkVW51c2VkQWRkcmVzc2VzIiwidGhlbiIsInVudXNlZEFkZHJlc3MiLCJ1c2VkQWRkcmVzc2VzIiwiYWRkcmVzc0NvdW50TWFwIiwibm9uQ2hhbmdlIiwidW51c2VkQWRkcmVzc01hcCIsImFkZHJMaXN0IiwiYWRkcmVzc0luZGV4IiwiY2hhbmdlQWRkcmVzc2VzIiwibm9uQ2hhbmdlQWRkcmVzc2VzIiwiY2xpZW50Iiwid2FsbGV0IiwiZ2V0QWRkcmVzc2VzIiwiY29uY2F0IiwicXVpY2tHZXRBZGRyZXNzZXMiLCJ0cmFuc2FjdGlvbkNvdW50cyIsImlzVXNlZCIsImlzQ2hhbmdlQWRkcmVzcyIsImZpbmQiLCJhIiwicHVzaCIsImZpcnN0VW51c2VkQWRkcmVzcyIsImluZGV4Tm9uQ2hhbmdlIiwiSW5maW5pdHkiLCJpbmRleENoYW5nZSIsInNlbmRTd2VlcFRyYW5zYWN0aW9uV2l0aFNldE91dHB1dHMiLCJmZWUiLCJub3JtYWxpemVUcmFuc2FjdGlvbk9iamVjdCIsImRlY29kZVJhd1RyYW5zYWN0aW9uIiwiX2ZlZVBlckJ5dGUiLCJpbnB1dHNGb3JBbW91bnQiLCJlIiwiX2dldElucHV0Rm9yQW1vdW50V2l0aG91dFV0eG9DaGVjayIsInV0eG8iLCJJbnB1dCIsImZyb21VVFhPIiwic3BsaWNlSW5kZXgiLCJmaW5kSW5kZXgiLCJzd2VlcE91dHB1dCIsInNwbGljZSIsIl9idWlsZFRyYW5zYWN0aW9uV2l0aG91dFV0eG9DaGVjayIsInV0eG9CYWxhbmNlIiwicmVkdWNlIiwiYiIsIm91dHB1dEJhbGFuY2UiLCJhbW91bnRUb1NlbmQiLCJ0YXJnZXRzIiwidGFyZ2V0IiwiaWQiLCJzZWxlY3RDb2lucyIsIk1hdGgiLCJjZWlsIiwidHhiIiwiVHJhbnNhY3Rpb25CdWlsZGVyIiwicHJldk91dFNjcmlwdFR5cGUiLCJwYXltZW50VmFyaWFudCIsInB1YmxpY0tleSIsIm5lZWRzV2l0bmVzcyIsInNpZ25QYXJhbXMiLCJ2aW4iLCJ3aXRuZXNzVmFsdWUiLCJzaWduIiwiYnVpbGQiLCJzdGFydGluZ0luZGV4IiwibnVtQWRkcmVzc2VzIiwiYWRkcmVzc2VzIiwibGFzdEluZGV4IiwiY2hhbmdlVmFsIiwib3JpZ2luYWxQcm92aWRlciIsImdldFByb3ZpZGVyRm9yTWV0aG9kIiwiYmFzZURlcml2YXRpb25QYXRoIiwiX2Jhc2VEZXJpdmF0aW9uUGF0aCIsImdldERlcml2YXRpb25QYXRoQWRkcmVzc0ZuIiwiY3VycmVudEluZGV4Iiwic3ViUGF0aCIsInBhdGgiLCJhZGRyZXNzT2JqZWN0IiwiYWRkcmVzc2VzUGVyQ2FsbCIsIndhbGxldE5vbkNoYW5nZUFkZHJlc3NlcyIsIndhbGxldENoYW5nZUFkZHJlc3NlcyIsIndhbGxldEFkZHJlc3NlcyIsIndhbGxldEFkZHJlc3MiLCJ3YWxs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
|
|
500
|
+
//# sourceMappingURL=BitcoinWalletProvider.js.map
|