@bitgo-beta/sdk-coin-eth 4.4.1-beta.21 → 4.4.1-beta.2100
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/dist/src/erc20Token.d.ts +13 -5
- package/dist/src/erc20Token.d.ts.map +1 -1
- package/dist/src/erc20Token.js +73 -32
- package/dist/src/erc721Token.d.ts +60 -0
- package/dist/src/erc721Token.d.ts.map +1 -0
- package/dist/src/erc721Token.js +337 -0
- package/dist/src/erc7984Token.d.ts +187 -0
- package/dist/src/erc7984Token.d.ts.map +1 -0
- package/dist/src/erc7984Token.js +944 -0
- package/dist/src/eth.d.ts +25 -537
- package/dist/src/eth.d.ts.map +1 -1
- package/dist/src/eth.js +252 -1657
- package/dist/src/gteth.d.ts +0 -4
- package/dist/src/gteth.d.ts.map +1 -1
- package/dist/src/gteth.js +1 -11
- package/dist/src/hteth.d.ts +8 -0
- package/dist/src/hteth.d.ts.map +1 -0
- package/dist/src/hteth.js +14 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -2
- package/dist/src/lib/index.d.ts +5 -13
- package/dist/src/lib/index.d.ts.map +1 -1
- package/dist/src/lib/index.js +18 -30
- package/dist/src/lib/messages/index.d.ts +3 -0
- package/dist/src/lib/messages/index.d.ts.map +1 -0
- package/dist/src/lib/messages/index.js +6 -0
- package/dist/src/lib/transactionBuilder.d.ts +10 -214
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -1
- package/dist/src/lib/transactionBuilder.js +23 -678
- package/dist/src/lib/transferBuilder.d.ts +2 -50
- package/dist/src/lib/transferBuilder.d.ts.map +1 -1
- package/dist/src/lib/transferBuilder.js +3 -199
- package/dist/src/lib/transferBuilders/index.d.ts +2 -3
- package/dist/src/lib/transferBuilders/index.d.ts.map +1 -1
- package/dist/src/lib/transferBuilders/index.js +7 -14
- package/dist/src/lib/walletUtil.d.ts +0 -25
- package/dist/src/lib/walletUtil.d.ts.map +1 -1
- package/dist/src/lib/walletUtil.js +2 -27
- package/dist/src/register.d.ts +2 -0
- package/dist/src/register.d.ts.map +1 -1
- package/dist/src/register.js +41 -2
- package/dist/src/sepeth.d.ts +8 -0
- package/dist/src/sepeth.d.ts.map +1 -0
- package/dist/src/sepeth.js +14 -0
- package/dist/src/teth.d.ts +0 -3
- package/dist/src/teth.d.ts.map +1 -1
- package/dist/src/teth.js +1 -8
- package/dist/test/fixtures/eth.d.ts +57 -0
- package/dist/test/fixtures/eth.d.ts.map +1 -0
- package/dist/test/fixtures/eth.js +277 -0
- package/dist/test/resources/erc1155Abi.d.ts +40 -0
- package/dist/test/resources/erc1155Abi.d.ts.map +1 -0
- package/dist/test/resources/erc1155Abi.js +329 -0
- package/dist/test/resources/erc721Abi.d.ts +12 -0
- package/dist/test/resources/erc721Abi.d.ts.map +1 -0
- package/dist/test/resources/erc721Abi.js +34 -0
- package/dist/test/resources/eth.d.ts +51 -0
- package/dist/test/resources/eth.d.ts.map +1 -0
- package/dist/test/resources/eth.js +72 -0
- package/dist/test/resources/nftEncodings.d.ts +4 -0
- package/dist/test/resources/nftEncodings.d.ts.map +1 -0
- package/dist/test/resources/nftEncodings.js +7 -0
- package/dist/test/resources/walletSimpleAbi.d.ts +12 -0
- package/dist/test/resources/walletSimpleAbi.d.ts.map +1 -0
- package/dist/test/resources/walletSimpleAbi.js +44 -0
- package/dist/test/unit/erc7984Token.d.ts +2 -0
- package/dist/test/unit/erc7984Token.d.ts.map +1 -0
- package/dist/test/unit/erc7984Token.js +1645 -0
- package/dist/test/unit/eth.d.ts +2 -0
- package/dist/test/unit/eth.d.ts.map +1 -0
- package/dist/test/unit/eth.js +3164 -0
- package/dist/test/unit/ethWallet.d.ts +2 -0
- package/dist/test/unit/ethWallet.d.ts.map +1 -0
- package/dist/test/unit/ethWallet.js +552 -0
- package/dist/test/unit/fixtures/ethMultiSigBackupKey.d.ts +4 -0
- package/dist/test/unit/fixtures/ethMultiSigBackupKey.d.ts.map +1 -0
- package/dist/test/unit/fixtures/ethMultiSigBackupKey.js +10 -0
- package/dist/test/unit/fixtures/ethTssBackupKey.d.ts +5 -0
- package/dist/test/unit/fixtures/ethTssBackupKey.d.ts.map +1 -0
- package/dist/test/unit/fixtures/ethTssBackupKey.js +25 -0
- package/dist/test/unit/getBuilder.d.ts +3 -0
- package/dist/test/unit/getBuilder.d.ts.map +1 -0
- package/dist/test/unit/getBuilder.js +10 -0
- package/dist/test/unit/keyPair.d.ts +2 -0
- package/dist/test/unit/keyPair.d.ts.map +1 -0
- package/dist/test/unit/keyPair.js +175 -0
- package/dist/test/unit/register.d.ts +2 -0
- package/dist/test/unit/register.d.ts.map +1 -0
- package/dist/test/unit/register.js +75 -0
- package/dist/test/unit/transaction.d.ts +2 -0
- package/dist/test/unit/transaction.d.ts.map +1 -0
- package/dist/test/unit/transaction.js +117 -0
- package/dist/test/unit/transactionBuilder/addressInitialization.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/addressInitialization.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/addressInitialization.js +101 -0
- package/dist/test/unit/transactionBuilder/contractCall.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/contractCall.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/contractCall.js +101 -0
- package/dist/test/unit/transactionBuilder/decryptionDelegation.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/decryptionDelegation.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/decryptionDelegation.js +59 -0
- package/dist/test/unit/transactionBuilder/decryptionDelegationTxBuilder.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/decryptionDelegationTxBuilder.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/decryptionDelegationTxBuilder.js +136 -0
- package/dist/test/unit/transactionBuilder/flushCoins.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/flushCoins.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/flushCoins.js +133 -0
- package/dist/test/unit/transactionBuilder/flushTokens.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/flushTokens.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/flushTokens.js +298 -0
- package/dist/test/unit/transactionBuilder/send.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/send.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/send.js +331 -0
- package/dist/test/unit/transactionBuilder/sendERC7984Token.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/sendERC7984Token.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/sendERC7984Token.js +361 -0
- package/dist/test/unit/transactionBuilder/sendNFT.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/sendNFT.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/sendNFT.js +295 -0
- package/dist/test/unit/transactionBuilder/singleSigSend.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/singleSigSend.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/singleSigSend.js +196 -0
- package/dist/test/unit/transactionBuilder/walletInitialization.d.ts +2 -0
- package/dist/test/unit/transactionBuilder/walletInitialization.d.ts.map +1 -0
- package/dist/test/unit/transactionBuilder/walletInitialization.js +436 -0
- package/dist/test/unit/transferBuilder.d.ts +2 -0
- package/dist/test/unit/transferBuilder.d.ts.map +1 -0
- package/dist/test/unit/transferBuilder.js +124 -0
- package/dist/test/unit/utils.d.ts +2 -0
- package/dist/test/unit/utils.d.ts.map +1 -0
- package/dist/test/unit/utils.js +74 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +18 -19
- package/.eslintignore +0 -5
- package/.mocharc.yml +0 -8
- package/CHANGELOG.md +0 -229
- package/dist/src/lib/contractCall.d.ts +0 -8
- package/dist/src/lib/contractCall.d.ts.map +0 -1
- package/dist/src/lib/contractCall.js +0 -17
- package/dist/src/lib/iface.d.ts +0 -130
- package/dist/src/lib/iface.d.ts.map +0 -1
- package/dist/src/lib/iface.js +0 -8
- package/dist/src/lib/keyPair.d.ts +0 -26
- package/dist/src/lib/keyPair.d.ts.map +0 -1
- package/dist/src/lib/keyPair.js +0 -66
- package/dist/src/lib/transaction.d.ts +0 -64
- package/dist/src/lib/transaction.d.ts.map +0 -1
- package/dist/src/lib/transaction.js +0 -137
- package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.d.ts +0 -47
- package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.d.ts.map +0 -1
- package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.js +0 -113
- package/dist/src/lib/transferBuilders/transferBuilderERC1155.d.ts +0 -14
- package/dist/src/lib/transferBuilders/transferBuilderERC1155.d.ts.map +0 -1
- package/dist/src/lib/transferBuilders/transferBuilderERC1155.js +0 -83
- package/dist/src/lib/transferBuilders/transferBuilderERC721.d.ts +0 -13
- package/dist/src/lib/transferBuilders/transferBuilderERC721.d.ts.map +0 -1
- package/dist/src/lib/transferBuilders/transferBuilderERC721.js +0 -68
- package/dist/src/lib/types.d.ts +0 -39
- package/dist/src/lib/types.d.ts.map +0 -1
- package/dist/src/lib/types.js +0 -137
- package/dist/src/lib/utils.d.ts +0 -227
- package/dist/src/lib/utils.d.ts.map +0 -1
- package/dist/src/lib/utils.js +0 -577
|
@@ -0,0 +1,944 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Erc7984Token = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* @prettier
|
|
39
|
+
*/
|
|
40
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
41
|
+
const statics_1 = require("@bitgo-beta/statics");
|
|
42
|
+
const abstract_eth_1 = require("@bitgo-beta/abstract-eth");
|
|
43
|
+
const secp256k1_1 = require("@bitgo-beta/secp256k1");
|
|
44
|
+
const _ = __importStar(require("lodash"));
|
|
45
|
+
const eth_1 = require("./eth");
|
|
46
|
+
const lib_1 = require("./lib");
|
|
47
|
+
class Erc7984Token extends eth_1.Eth {
|
|
48
|
+
constructor(bitgo, tokenConfig) {
|
|
49
|
+
const staticsCoin = statics_1.coins.get(tokenConfig.coin);
|
|
50
|
+
super(bitgo, staticsCoin);
|
|
51
|
+
this.tokenConfig = tokenConfig;
|
|
52
|
+
// ERC7984 confidential transfers use sendMultiSig (not sendMultiSigToken) because
|
|
53
|
+
// the calldata parameter is required to carry confidentialTransfer(recipient, encryptedHandle, inputProof).
|
|
54
|
+
// sendMultiSigToken has no data parameter and cannot carry inner calldata.
|
|
55
|
+
this.sendMethodName = 'sendMultiSig';
|
|
56
|
+
}
|
|
57
|
+
static createTokenConstructor(config) {
|
|
58
|
+
return (bitgo) => new Erc7984Token(bitgo, config);
|
|
59
|
+
}
|
|
60
|
+
static createTokenConstructors(tokenConfigs = [
|
|
61
|
+
...statics_1.tokens.bitcoin.eth.confidentialTokens,
|
|
62
|
+
...statics_1.tokens.testnet.eth.confidentialTokens,
|
|
63
|
+
]) {
|
|
64
|
+
const tokensCtors = [];
|
|
65
|
+
for (const token of tokenConfigs) {
|
|
66
|
+
const tokenConstructor = Erc7984Token.createTokenConstructor(token);
|
|
67
|
+
tokensCtors.push({ name: token.type, coinConstructor: tokenConstructor });
|
|
68
|
+
tokensCtors.push({ name: token.tokenContractAddress, coinConstructor: tokenConstructor });
|
|
69
|
+
}
|
|
70
|
+
return tokensCtors;
|
|
71
|
+
}
|
|
72
|
+
get type() {
|
|
73
|
+
return this.tokenConfig.type;
|
|
74
|
+
}
|
|
75
|
+
get name() {
|
|
76
|
+
return this.tokenConfig.name;
|
|
77
|
+
}
|
|
78
|
+
get coin() {
|
|
79
|
+
return this.tokenConfig.coin;
|
|
80
|
+
}
|
|
81
|
+
get network() {
|
|
82
|
+
return this.tokenConfig.network;
|
|
83
|
+
}
|
|
84
|
+
get tokenContractAddress() {
|
|
85
|
+
return this.tokenConfig.tokenContractAddress;
|
|
86
|
+
}
|
|
87
|
+
get decimalPlaces() {
|
|
88
|
+
return this.tokenConfig.decimalPlaces;
|
|
89
|
+
}
|
|
90
|
+
getChain() {
|
|
91
|
+
return this.tokenConfig.type;
|
|
92
|
+
}
|
|
93
|
+
getFullName() {
|
|
94
|
+
return 'ERC7984 Confidential Token';
|
|
95
|
+
}
|
|
96
|
+
getBaseFactor() {
|
|
97
|
+
return Math.pow(10, this.tokenConfig.decimalPlaces);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Flag for sending value of 0.
|
|
101
|
+
* ERC-7984 confidential transfers always carry an encrypted amount; zero-value sends are not meaningful.
|
|
102
|
+
*/
|
|
103
|
+
valuelessTransferAllowed() {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Flag for sending data along with transactions via the standard token-send API.
|
|
108
|
+
* Returns false because ERC-7984 sends use confidentialTransfer() calldata built
|
|
109
|
+
* by WP, not an arbitrary data field on the send params.
|
|
110
|
+
* Note: this does not prevent calldata-based flows like getDelegationBuilder(),
|
|
111
|
+
* which bypass the token-send path entirely.
|
|
112
|
+
*/
|
|
113
|
+
transactionDataAllowed() {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
/** @inheritDoc */
|
|
117
|
+
supportsTss() {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
/** @inheritDoc */
|
|
121
|
+
getMPCAlgorithm() {
|
|
122
|
+
return 'ecdsa';
|
|
123
|
+
}
|
|
124
|
+
getTransactionBuilder() {
|
|
125
|
+
return new lib_1.TransactionBuilder(statics_1.coins.get(this.getBaseChain()));
|
|
126
|
+
}
|
|
127
|
+
/** @inheritDoc */
|
|
128
|
+
async verifyTransaction(params) {
|
|
129
|
+
if (params.txParams?.type === 'enabletoken') {
|
|
130
|
+
return this.verifyEnableTokenTransaction(params);
|
|
131
|
+
}
|
|
132
|
+
if (params.txParams?.type === 'wrap') {
|
|
133
|
+
return this.verifyWrapTransaction(params);
|
|
134
|
+
}
|
|
135
|
+
if (params.txParams?.type === 'unwrap') {
|
|
136
|
+
return this.verifyUnwrapTransaction(params);
|
|
137
|
+
}
|
|
138
|
+
if (params.txParams?.type === 'finalizeUnwrap') {
|
|
139
|
+
return this.verifyFinalizeUnwrapTransaction(params);
|
|
140
|
+
}
|
|
141
|
+
if (this.isConsolidationTransaction(params)) {
|
|
142
|
+
return this.verifyConfidentialConsolidation(params);
|
|
143
|
+
}
|
|
144
|
+
return this.verifyConfidentialTransfer(params);
|
|
145
|
+
}
|
|
146
|
+
isConsolidationTransaction(params) {
|
|
147
|
+
const { txParams, txPrebuild, verification } = params;
|
|
148
|
+
return !!(verification?.consolidationToBaseAddress ||
|
|
149
|
+
txPrebuild?.consolidateId ||
|
|
150
|
+
txParams?.type === 'consolidate' ||
|
|
151
|
+
// TSS signing path: resolveEffectiveTxParams sets type from intent.intentType which is
|
|
152
|
+
// 'consolidateToken' for ERC-7984 token consolidations. txPrebuild has only txHex
|
|
153
|
+
// (no consolidateId) in this path.
|
|
154
|
+
txParams?.type === 'consolidateToken' ||
|
|
155
|
+
txParams?.prebuildTx?.consolidateId);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Verifies WrapERC7984 (shield) transactions.
|
|
159
|
+
*
|
|
160
|
+
* TSS / direct shape:
|
|
161
|
+
* tx.to = wrapper contract
|
|
162
|
+
* tx.data = wrap(baseAddress, amount)
|
|
163
|
+
*
|
|
164
|
+
* Multisig shape:
|
|
165
|
+
* tx.to = wallet contract
|
|
166
|
+
* tx.data = sendMultiSig(wrapper, 0, wrap(baseAddress, amount), ...)
|
|
167
|
+
*
|
|
168
|
+
* Checks: wrapper address, self-directed `to` == base, amount > 0, amount matches
|
|
169
|
+
* recipients, and floor(amount / rate) fits uint64 when statics rate is present.
|
|
170
|
+
*/
|
|
171
|
+
async verifyWrapTransaction(params) {
|
|
172
|
+
const { txParams, txPrebuild, wallet } = params;
|
|
173
|
+
if (!txPrebuild?.txHex) {
|
|
174
|
+
throw new Error('verifyWrapTransaction: missing txHex in txPrebuild');
|
|
175
|
+
}
|
|
176
|
+
const txBuilder = this.getTransactionBuilder();
|
|
177
|
+
txBuilder.from(txPrebuild.txHex);
|
|
178
|
+
const tx = await txBuilder.build();
|
|
179
|
+
const txJson = tx.toJson();
|
|
180
|
+
let wrapperAddress;
|
|
181
|
+
let wrapCalldata;
|
|
182
|
+
try {
|
|
183
|
+
if (txJson.data.toLowerCase().startsWith(abstract_eth_1.sendMultisigMethodId.toLowerCase())) {
|
|
184
|
+
const decoded = (0, abstract_eth_1.decodeTransferData)(txJson.data);
|
|
185
|
+
wrapperAddress = decoded.to;
|
|
186
|
+
wrapCalldata = decoded.data;
|
|
187
|
+
if (decoded.amount !== '0') {
|
|
188
|
+
throw new Error(`expected sendMultiSig value 0 but got ${decoded.amount}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else if (txJson.data.toLowerCase().startsWith(abstract_eth_1.wrapMethodId.toLowerCase())) {
|
|
192
|
+
wrapperAddress = txJson.to;
|
|
193
|
+
wrapCalldata = txJson.data;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
200
|
+
throw new Error(`verifyWrapTransaction: failed to decode wrap calldata — ${e.message}`);
|
|
201
|
+
}
|
|
202
|
+
if (wrapperAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
|
|
203
|
+
throw new Error(`verifyWrapTransaction: wrapper address mismatch — ` +
|
|
204
|
+
`expected ${this.tokenContractAddress}, got ${wrapperAddress}`);
|
|
205
|
+
}
|
|
206
|
+
let to;
|
|
207
|
+
let amount;
|
|
208
|
+
try {
|
|
209
|
+
({ to, amount } = (0, abstract_eth_1.decodeWrapCalldata)(wrapCalldata));
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
throw new Error(`verifyWrapTransaction: invalid wrap inner calldata — ${e.message}`);
|
|
213
|
+
}
|
|
214
|
+
if (!Erc7984Token.isPositiveIntegerString(amount)) {
|
|
215
|
+
throw new Error(`verifyWrapTransaction: amount must be a positive integer string, got '${amount}'`);
|
|
216
|
+
}
|
|
217
|
+
const baseAddress = this.getWalletBaseAddress(wallet);
|
|
218
|
+
if (!baseAddress) {
|
|
219
|
+
throw new Error('verifyWrapTransaction: unable to determine wallet base address');
|
|
220
|
+
}
|
|
221
|
+
if (to.toLowerCase() !== baseAddress.toLowerCase()) {
|
|
222
|
+
throw new Error(`verifyWrapTransaction: wrap recipient must equal wallet base address — expected ${baseAddress}, got ${to}`);
|
|
223
|
+
}
|
|
224
|
+
const expectedAmount = txParams?.recipients?.[0]?.amount ?? txPrebuild.buildParams?.recipients?.[0]?.amount;
|
|
225
|
+
if (expectedAmount !== undefined && String(expectedAmount) !== amount) {
|
|
226
|
+
throw new Error(`verifyWrapTransaction: amount mismatch — calldata has '${amount}' but params have '${expectedAmount}'`);
|
|
227
|
+
}
|
|
228
|
+
const rate = this.tokenConfig.rate;
|
|
229
|
+
if (rate !== undefined) {
|
|
230
|
+
try {
|
|
231
|
+
(0, abstract_eth_1.assertWrapAmountFitsUint64)(amount, rate);
|
|
232
|
+
}
|
|
233
|
+
catch (e) {
|
|
234
|
+
throw new Error(`verifyWrapTransaction: ${e.message}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (txJson.value !== undefined && txJson.value !== '0' && txJson.value !== 0) {
|
|
238
|
+
throw new Error(`verifyWrapTransaction: expected transaction value 0 but got ${txJson.value}`);
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Verifies UnwrapERC7984 (unshield phase-1) transactions.
|
|
244
|
+
*
|
|
245
|
+
* TSS / direct shape:
|
|
246
|
+
* tx.to = wrapper contract
|
|
247
|
+
* tx.data = unwrap(base, base, encryptedAmount, inputProof)
|
|
248
|
+
*
|
|
249
|
+
* Multisig shape:
|
|
250
|
+
* tx.to = wallet contract
|
|
251
|
+
* tx.data = sendMultiSig(wrapper, 0, unwrap(base, base, ...), ...)
|
|
252
|
+
*
|
|
253
|
+
* v1 is self-directed only: from == to == wallet base address.
|
|
254
|
+
*/
|
|
255
|
+
async verifyUnwrapTransaction(params) {
|
|
256
|
+
const { txPrebuild, wallet } = params;
|
|
257
|
+
if (!txPrebuild?.txHex) {
|
|
258
|
+
throw new Error('verifyUnwrapTransaction: missing txHex in txPrebuild');
|
|
259
|
+
}
|
|
260
|
+
const txBuilder = this.getTransactionBuilder();
|
|
261
|
+
txBuilder.from(txPrebuild.txHex);
|
|
262
|
+
const tx = await txBuilder.build();
|
|
263
|
+
const txJson = tx.toJson();
|
|
264
|
+
let wrapperAddress;
|
|
265
|
+
let unwrapCalldata;
|
|
266
|
+
try {
|
|
267
|
+
if (txJson.data.toLowerCase().startsWith(abstract_eth_1.sendMultisigMethodId.toLowerCase())) {
|
|
268
|
+
const decoded = (0, abstract_eth_1.decodeTransferData)(txJson.data);
|
|
269
|
+
wrapperAddress = decoded.to;
|
|
270
|
+
unwrapCalldata = decoded.data;
|
|
271
|
+
if (decoded.amount !== '0') {
|
|
272
|
+
throw new Error(`expected sendMultiSig value 0 but got ${decoded.amount}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else if (txJson.data.toLowerCase().startsWith(abstract_eth_1.unwrapMethodId.toLowerCase())) {
|
|
276
|
+
wrapperAddress = txJson.to;
|
|
277
|
+
unwrapCalldata = txJson.data;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
throw new Error(`verifyUnwrapTransaction: failed to decode unwrap calldata — ${e.message}`);
|
|
285
|
+
}
|
|
286
|
+
if (wrapperAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
|
|
287
|
+
throw new Error(`verifyUnwrapTransaction: wrapper address mismatch — expected ${this.tokenContractAddress}, got ${wrapperAddress}`);
|
|
288
|
+
}
|
|
289
|
+
let from;
|
|
290
|
+
let to;
|
|
291
|
+
let encryptedAmount;
|
|
292
|
+
let inputProof;
|
|
293
|
+
try {
|
|
294
|
+
({ from, to, encryptedAmount, inputProof } = (0, abstract_eth_1.decodeUnwrapCalldata)(unwrapCalldata));
|
|
295
|
+
}
|
|
296
|
+
catch (e) {
|
|
297
|
+
throw new Error(`verifyUnwrapTransaction: invalid unwrap inner calldata — ${e.message}`);
|
|
298
|
+
}
|
|
299
|
+
const baseAddress = this.getWalletBaseAddress(wallet);
|
|
300
|
+
if (!baseAddress) {
|
|
301
|
+
throw new Error('verifyUnwrapTransaction: unable to determine wallet base address');
|
|
302
|
+
}
|
|
303
|
+
if (from.toLowerCase() !== baseAddress.toLowerCase()) {
|
|
304
|
+
throw new Error(`verifyUnwrapTransaction: unwrap from must equal wallet base address — expected ${baseAddress}, got ${from}`);
|
|
305
|
+
}
|
|
306
|
+
if (to.toLowerCase() !== baseAddress.toLowerCase()) {
|
|
307
|
+
throw new Error(`verifyUnwrapTransaction: unwrap to must equal wallet base address — expected ${baseAddress}, got ${to}`);
|
|
308
|
+
}
|
|
309
|
+
if (!encryptedAmount || encryptedAmount === '0x' || /^0x0+$/.test(encryptedAmount)) {
|
|
310
|
+
throw new Error('verifyUnwrapTransaction: encryptedAmount is missing or empty');
|
|
311
|
+
}
|
|
312
|
+
if (!inputProof || inputProof === '0x') {
|
|
313
|
+
throw new Error('verifyUnwrapTransaction: inputProof is missing or empty');
|
|
314
|
+
}
|
|
315
|
+
if (txJson.value !== undefined && txJson.value !== '0' && txJson.value !== 0) {
|
|
316
|
+
throw new Error(`verifyUnwrapTransaction: expected transaction value 0 but got ${txJson.value}`);
|
|
317
|
+
}
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Verifies FinalizeUnwrapERC7984 (unshield phase-2) transactions.
|
|
322
|
+
*
|
|
323
|
+
* TSS / direct shape:
|
|
324
|
+
* tx.to = wrapper contract
|
|
325
|
+
* tx.data = finalizeUnwrap(requestId, cleartextAmount, decryptionProof)
|
|
326
|
+
*
|
|
327
|
+
* Multisig shape:
|
|
328
|
+
* tx.to = wallet contract
|
|
329
|
+
* tx.data = sendMultiSig(wrapper, 0, finalizeUnwrap(...), ...)
|
|
330
|
+
*/
|
|
331
|
+
async verifyFinalizeUnwrapTransaction(params) {
|
|
332
|
+
const { txParams, txPrebuild } = params;
|
|
333
|
+
if (!txPrebuild?.txHex) {
|
|
334
|
+
throw new Error('verifyFinalizeUnwrapTransaction: missing txHex in txPrebuild');
|
|
335
|
+
}
|
|
336
|
+
const txBuilder = this.getTransactionBuilder();
|
|
337
|
+
txBuilder.from(txPrebuild.txHex);
|
|
338
|
+
const tx = await txBuilder.build();
|
|
339
|
+
const txJson = tx.toJson();
|
|
340
|
+
let wrapperAddress;
|
|
341
|
+
let finalizeCalldata;
|
|
342
|
+
try {
|
|
343
|
+
if (txJson.data.toLowerCase().startsWith(abstract_eth_1.sendMultisigMethodId.toLowerCase())) {
|
|
344
|
+
const decoded = (0, abstract_eth_1.decodeTransferData)(txJson.data);
|
|
345
|
+
wrapperAddress = decoded.to;
|
|
346
|
+
finalizeCalldata = decoded.data;
|
|
347
|
+
if (decoded.amount !== '0') {
|
|
348
|
+
throw new Error(`expected sendMultiSig value 0 but got ${decoded.amount}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else if (txJson.data.toLowerCase().startsWith(abstract_eth_1.finalizeUnwrapMethodId.toLowerCase())) {
|
|
352
|
+
wrapperAddress = txJson.to;
|
|
353
|
+
finalizeCalldata = txJson.data;
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
catch (e) {
|
|
360
|
+
throw new Error(`verifyFinalizeUnwrapTransaction: failed to decode finalizeUnwrap calldata — ${e.message}`);
|
|
361
|
+
}
|
|
362
|
+
if (wrapperAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
|
|
363
|
+
throw new Error(`verifyFinalizeUnwrapTransaction: wrapper address mismatch — expected ${this.tokenContractAddress}, got ${wrapperAddress}`);
|
|
364
|
+
}
|
|
365
|
+
let requestId;
|
|
366
|
+
let cleartextAmount;
|
|
367
|
+
let decryptionProof;
|
|
368
|
+
try {
|
|
369
|
+
({ requestId, cleartextAmount, decryptionProof } = (0, abstract_eth_1.decodeFinalizeUnwrapCalldata)(finalizeCalldata));
|
|
370
|
+
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
throw new Error(`verifyFinalizeUnwrapTransaction: invalid finalizeUnwrap inner calldata — ${e.message}`);
|
|
373
|
+
}
|
|
374
|
+
if (!requestId || requestId === '0x' || /^0x0+$/.test(requestId)) {
|
|
375
|
+
throw new Error('verifyFinalizeUnwrapTransaction: requestId is missing or empty');
|
|
376
|
+
}
|
|
377
|
+
if (!Erc7984Token.isPositiveIntegerString(cleartextAmount)) {
|
|
378
|
+
throw new Error(`verifyFinalizeUnwrapTransaction: cleartextAmount must be a positive integer string, got '${cleartextAmount}'`);
|
|
379
|
+
}
|
|
380
|
+
if (BigInt(cleartextAmount) > abstract_eth_1.UINT64_MAX) {
|
|
381
|
+
throw new Error('verifyFinalizeUnwrapTransaction: cleartextAmount exceeds uint64');
|
|
382
|
+
}
|
|
383
|
+
if (!decryptionProof || decryptionProof === '0x') {
|
|
384
|
+
throw new Error('verifyFinalizeUnwrapTransaction: decryptionProof is missing or empty');
|
|
385
|
+
}
|
|
386
|
+
const expectedAmount = txParams?.recipients?.[0]?.amount ?? txPrebuild.buildParams?.recipients?.[0]?.amount;
|
|
387
|
+
if (expectedAmount !== undefined && String(expectedAmount) !== cleartextAmount) {
|
|
388
|
+
throw new Error(`verifyFinalizeUnwrapTransaction: amount mismatch — calldata has '${cleartextAmount}' but params have '${expectedAmount}'`);
|
|
389
|
+
}
|
|
390
|
+
if (txJson.value !== undefined && txJson.value !== '0' && txJson.value !== 0) {
|
|
391
|
+
throw new Error(`verifyFinalizeUnwrapTransaction: expected transaction value 0 but got ${txJson.value}`);
|
|
392
|
+
}
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
getWalletBaseAddress(wallet) {
|
|
396
|
+
if (!wallet) {
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
const coinSpecific = typeof wallet.coinSpecific === 'function' ? wallet.coinSpecific() : wallet.coinSpecific;
|
|
400
|
+
const ethCoinSpecific = coinSpecific;
|
|
401
|
+
return ethCoinSpecific?.baseAddress ?? ethCoinSpecific?.rootAddress;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Verifies ERC-7984 forwarder consolidation (flush) transactions.
|
|
405
|
+
*
|
|
406
|
+
* Multisig shape:
|
|
407
|
+
* tx.to = wallet contract
|
|
408
|
+
* tx.data = sendMultiSig(forwarder, 0, callFromParent(token, 0, confidentialTransferNoProof(base, handle)), ...)
|
|
409
|
+
*
|
|
410
|
+
* TSS / direct shape:
|
|
411
|
+
* tx.to = forwarder contract
|
|
412
|
+
* tx.data = callFromParent(token, 0, confidentialTransferNoProof(base, handle))
|
|
413
|
+
*/
|
|
414
|
+
async verifyConfidentialConsolidation(params) {
|
|
415
|
+
const { txParams, txPrebuild, wallet } = params;
|
|
416
|
+
if (!txPrebuild?.txHex) {
|
|
417
|
+
if (!txPrebuild?.consolidateId && !txParams?.prebuildTx?.consolidateId) {
|
|
418
|
+
throw new Error('verifyConfidentialConsolidation: missing consolidateId');
|
|
419
|
+
}
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
const txBuilder = this.getTransactionBuilder();
|
|
423
|
+
txBuilder.from(txPrebuild.txHex);
|
|
424
|
+
const tx = await txBuilder.build();
|
|
425
|
+
const txJson = tx.toJson();
|
|
426
|
+
let tokenContractAddress;
|
|
427
|
+
let parentAddress;
|
|
428
|
+
let encryptedHandle;
|
|
429
|
+
let forwarderAddress;
|
|
430
|
+
try {
|
|
431
|
+
if (txJson.data.startsWith(abstract_eth_1.sendMultisigMethodId)) {
|
|
432
|
+
const decoded = (0, abstract_eth_1.decodeSendMultiSigFlushERC7984Data)(txJson.data);
|
|
433
|
+
forwarderAddress = decoded.forwarderAddress;
|
|
434
|
+
tokenContractAddress = decoded.tokenContractAddress;
|
|
435
|
+
parentAddress = decoded.parentAddress;
|
|
436
|
+
encryptedHandle = decoded.encryptedHandle;
|
|
437
|
+
}
|
|
438
|
+
else if (txJson.data.startsWith(abstract_eth_1.callFromParentMethodId)) {
|
|
439
|
+
const decoded = (0, abstract_eth_1.decodeFlushERC7984ForwarderTokenCalldata)(txJson.data);
|
|
440
|
+
tokenContractAddress = decoded.tokenContractAddress;
|
|
441
|
+
parentAddress = decoded.parentAddress;
|
|
442
|
+
encryptedHandle = decoded.encryptedHandle;
|
|
443
|
+
forwarderAddress = txJson.to;
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
catch (e) {
|
|
450
|
+
throw new Error(`verifyConfidentialConsolidation: failed to decode consolidation calldata — ${e.message}`);
|
|
451
|
+
}
|
|
452
|
+
if (tokenContractAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
|
|
453
|
+
throw new Error(`verifyConfidentialConsolidation: token contract address mismatch — ` +
|
|
454
|
+
`expected ${this.tokenContractAddress}, got ${tokenContractAddress}`);
|
|
455
|
+
}
|
|
456
|
+
const baseAddress = this.getWalletBaseAddress(wallet);
|
|
457
|
+
if (!baseAddress) {
|
|
458
|
+
throw new Error('verifyConfidentialConsolidation: unable to determine wallet base address');
|
|
459
|
+
}
|
|
460
|
+
if (parentAddress.toLowerCase() !== baseAddress.toLowerCase()) {
|
|
461
|
+
throw new Error(`verifyConfidentialConsolidation: parent address mismatch — expected ${baseAddress}, got ${parentAddress}`);
|
|
462
|
+
}
|
|
463
|
+
if (!encryptedHandle || encryptedHandle === '0x') {
|
|
464
|
+
throw new Error('verifyConfidentialConsolidation: encryptedHandle is missing or empty in transaction calldata');
|
|
465
|
+
}
|
|
466
|
+
const expectedForwarder = txPrebuild.recipients?.[0]?.address ??
|
|
467
|
+
txPrebuild.txInfo?.recipients?.[0]?.address ??
|
|
468
|
+
txParams?.recipients?.[0]?.address;
|
|
469
|
+
if (forwarderAddress && expectedForwarder) {
|
|
470
|
+
if (forwarderAddress.toLowerCase() !== expectedForwarder.toLowerCase()) {
|
|
471
|
+
throw new Error(`verifyConfidentialConsolidation: forwarder address mismatch — ` +
|
|
472
|
+
`expected ${expectedForwarder}, got ${forwarderAddress}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Verifies a confidential token transfer (SendERC7984) transaction.
|
|
479
|
+
*
|
|
480
|
+
* With txHex — two on-chain shapes are supported:
|
|
481
|
+
*
|
|
482
|
+
* sendMultiSig-wrapped (multisig / smart-contract wallet):
|
|
483
|
+
* tx.to = wallet contract
|
|
484
|
+
* tx.data = sendMultiSig(tokenAddr, 0, confidentialTransfer(recipient, handle, proof), ...)
|
|
485
|
+
* Token contract address is decoded from the sendMultiSig inner calldata.
|
|
486
|
+
*
|
|
487
|
+
* Direct call (hot / TSS EOA wallet):
|
|
488
|
+
* tx.to = token contract
|
|
489
|
+
* tx.data = confidentialTransfer(recipient, handle, proof)
|
|
490
|
+
* Token contract address is taken from tx.to.
|
|
491
|
+
*
|
|
492
|
+
* For both shapes the verifier checks:
|
|
493
|
+
* 1. Token contract address matches this coin's tokenContractAddress.
|
|
494
|
+
* 2. Decoded recipient matches txParams.recipients[0].address or buildParams.recipients[0].address.
|
|
495
|
+
* 3. encryptedHandle and inputProof are structurally present (non-empty).
|
|
496
|
+
* 4. txParams.recipients[0].amount is a positive integer and matches buildParams when both present.
|
|
497
|
+
*
|
|
498
|
+
* Without txHex (first-signer / pre-signing path):
|
|
499
|
+
* 1. Requires exactly one recipient in txParams.
|
|
500
|
+
* 2. Validates txParams.recipients[0].address is a valid Ethereum address.
|
|
501
|
+
* 3. Validates txParams.recipients[0].amount is a positive integer.
|
|
502
|
+
* 4. Cross-checks address and amount against buildParams when the server has stored the intent.
|
|
503
|
+
*/
|
|
504
|
+
async verifyConfidentialTransfer(params) {
|
|
505
|
+
const { txParams, txPrebuild } = params;
|
|
506
|
+
if (!txPrebuild?.txHex) {
|
|
507
|
+
// No raw tx available (multisig first-signer path).
|
|
508
|
+
// Validate ERC7984-specific invariants from txParams and buildParams.
|
|
509
|
+
const recipients = txParams?.recipients;
|
|
510
|
+
if (!recipients || recipients.length === 0) {
|
|
511
|
+
throw new Error('verifyConfidentialTransfer: recipients must contain at least one entry');
|
|
512
|
+
}
|
|
513
|
+
if (recipients.length !== 1) {
|
|
514
|
+
throw new Error(`verifyConfidentialTransfer: confidential transfers support exactly 1 recipient, got ${recipients.length}`);
|
|
515
|
+
}
|
|
516
|
+
const recipient = recipients[0];
|
|
517
|
+
if (!recipient.address || !this.isValidAddress(recipient.address)) {
|
|
518
|
+
throw new Error(`verifyConfidentialTransfer: recipient address is missing or invalid: ${recipient.address}`);
|
|
519
|
+
}
|
|
520
|
+
const amountStr = String(recipient.amount);
|
|
521
|
+
if (!Erc7984Token.isPositiveIntegerString(amountStr)) {
|
|
522
|
+
throw new Error(`verifyConfidentialTransfer: amount must be a positive integer string in base units, got '${amountStr}'`);
|
|
523
|
+
}
|
|
524
|
+
// Cross-check against buildParams when the server has already stored the intent
|
|
525
|
+
const buildParamsRecipient = txPrebuild?.buildParams?.recipients?.[0];
|
|
526
|
+
if (buildParamsRecipient?.address !== undefined) {
|
|
527
|
+
if (recipient.address.toLowerCase() !== buildParamsRecipient.address.toLowerCase()) {
|
|
528
|
+
throw new Error(`verifyConfidentialTransfer: recipient address mismatch — ` +
|
|
529
|
+
`txParams has '${recipient.address}' but buildParams has '${buildParamsRecipient.address}'`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
const buildParamsAmount = buildParamsRecipient?.amount;
|
|
533
|
+
if (buildParamsAmount !== undefined && buildParamsAmount !== amountStr) {
|
|
534
|
+
throw new Error(`verifyConfidentialTransfer: amount mismatch — txParams has '${amountStr}' but buildParams has '${buildParamsAmount}'`);
|
|
535
|
+
}
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
// Parse and decode the raw transaction
|
|
539
|
+
const txBuilder = this.getTransactionBuilder();
|
|
540
|
+
txBuilder.from(txPrebuild.txHex);
|
|
541
|
+
const tx = await txBuilder.build();
|
|
542
|
+
const txJson = tx.toJson();
|
|
543
|
+
let toAddress;
|
|
544
|
+
let tokenContractAddress;
|
|
545
|
+
let encryptedHandle;
|
|
546
|
+
let inputProof;
|
|
547
|
+
try {
|
|
548
|
+
if (txJson.data.startsWith(abstract_eth_1.sendMultisigMethodId)) {
|
|
549
|
+
// sendMultiSig-wrapped path: smart-contract wallet relays the confidentialTransfer call.
|
|
550
|
+
// Token contract address is encoded inside the sendMultiSig calldata.
|
|
551
|
+
const decoded = (0, abstract_eth_1.decodeConfidentialTransferData)(txJson.data);
|
|
552
|
+
toAddress = decoded.toAddress;
|
|
553
|
+
tokenContractAddress = decoded.tokenContractAddress;
|
|
554
|
+
encryptedHandle = decoded.encryptedHandle;
|
|
555
|
+
inputProof = decoded.inputProof;
|
|
556
|
+
}
|
|
557
|
+
else if (txJson.data.startsWith(abstract_eth_1.confidentialTransferWithProofMethodId)) {
|
|
558
|
+
// Direct call path: hot/TSS EOA wallet calls the token contract directly.
|
|
559
|
+
// The transaction's `to` field is the token contract address.
|
|
560
|
+
if (!txJson.to) {
|
|
561
|
+
throw new Error('direct confidentialTransfer call is missing transaction to address');
|
|
562
|
+
}
|
|
563
|
+
const decoded = (0, abstract_eth_1.decodeDirectConfidentialTransferCalldata)(txJson.data);
|
|
564
|
+
toAddress = decoded.toAddress;
|
|
565
|
+
tokenContractAddress = txJson.to;
|
|
566
|
+
encryptedHandle = decoded.encryptedHandle;
|
|
567
|
+
inputProof = decoded.inputProof;
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
catch (e) {
|
|
574
|
+
throw new Error(`verifyConfidentialTransfer: failed to decode confidential transfer calldata — ${e.message}`);
|
|
575
|
+
}
|
|
576
|
+
// 1. Token contract address must match this coin
|
|
577
|
+
if (tokenContractAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
|
|
578
|
+
throw new Error(`verifyConfidentialTransfer: token contract address mismatch — ` +
|
|
579
|
+
`expected ${this.tokenContractAddress}, got ${tokenContractAddress}`);
|
|
580
|
+
}
|
|
581
|
+
// 2. Recipient address must match txParams.recipients[0] or buildParams.recipients[0]
|
|
582
|
+
const expectedRecipient = txParams?.recipients?.[0]?.address ?? txPrebuild.buildParams?.recipients?.[0]?.address;
|
|
583
|
+
if (!expectedRecipient) {
|
|
584
|
+
throw new Error('verifyConfidentialTransfer: missing expected recipient (provide txParams.recipients or txPrebuild.buildParams.recipients)');
|
|
585
|
+
}
|
|
586
|
+
if (toAddress.toLowerCase() !== expectedRecipient.toLowerCase()) {
|
|
587
|
+
throw new Error(`verifyConfidentialTransfer: recipient address mismatch — ` + `expected ${expectedRecipient}, got ${toAddress}`);
|
|
588
|
+
}
|
|
589
|
+
// 3. encryptedHandle must be a non-trivial hex value (not bare '0x')
|
|
590
|
+
if (!encryptedHandle || encryptedHandle === '0x') {
|
|
591
|
+
throw new Error('verifyConfidentialTransfer: encryptedHandle is missing or empty in transaction calldata');
|
|
592
|
+
}
|
|
593
|
+
// 4. inputProof must be a non-trivial hex value
|
|
594
|
+
if (!inputProof || inputProof === '0x') {
|
|
595
|
+
throw new Error('verifyConfidentialTransfer: inputProof is missing or empty in transaction calldata');
|
|
596
|
+
}
|
|
597
|
+
// 5. Verify plaintext intent: txParams amount must be valid and consistent with buildParams
|
|
598
|
+
const rawTxParamsAmount = txParams?.recipients?.[0]?.amount;
|
|
599
|
+
if (rawTxParamsAmount !== undefined) {
|
|
600
|
+
const txParamsAmount = String(rawTxParamsAmount);
|
|
601
|
+
if (!Erc7984Token.isPositiveIntegerString(txParamsAmount)) {
|
|
602
|
+
throw new Error(`verifyConfidentialTransfer: amount must be a positive integer string in base units, got '${txParamsAmount}'`);
|
|
603
|
+
}
|
|
604
|
+
const buildParamsAmount = txPrebuild.buildParams?.recipients?.[0]?.amount;
|
|
605
|
+
if (buildParamsAmount !== undefined && txParamsAmount !== buildParamsAmount) {
|
|
606
|
+
throw new Error(`verifyConfidentialTransfer: amount mismatch — txParams has '${txParamsAmount}' but buildParams has '${buildParamsAmount}'`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
static isPositiveIntegerString(value) {
|
|
612
|
+
return /^\d+$/.test(value) && BigInt(value) > 0n;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Verifies a token enablement transaction for ERC-7984 decryption delegation.
|
|
616
|
+
*
|
|
617
|
+
* TSS path: decodes the raw tx and verifies it calls the ACL contract with
|
|
618
|
+
* calldata that covers all requested token contract addresses.
|
|
619
|
+
*
|
|
620
|
+
* Multisig path: verifies the buildParams recipients carry the correct tokenNames
|
|
621
|
+
* and zero amounts.
|
|
622
|
+
*/
|
|
623
|
+
async verifyEnableTokenTransaction(params) {
|
|
624
|
+
const { txParams, txPrebuild, walletType } = params;
|
|
625
|
+
if (walletType === 'tss') {
|
|
626
|
+
// TSS path: full raw-tx decode
|
|
627
|
+
const enableTokens = txParams.enableTokens;
|
|
628
|
+
if (!enableTokens || enableTokens.length === 0) {
|
|
629
|
+
throw new Error('verifyEnableTokenTransaction: enableTokens must be non-empty for TSS path');
|
|
630
|
+
}
|
|
631
|
+
if (!txPrebuild.txHex) {
|
|
632
|
+
throw new Error('verifyEnableTokenTransaction: missing txHex in txPrebuild');
|
|
633
|
+
}
|
|
634
|
+
// Resolve requested token names → contract addresses
|
|
635
|
+
const requestedAddresses = enableTokens.map((t) => {
|
|
636
|
+
const tokenCoin = this.bitgo.coin(t.name);
|
|
637
|
+
return tokenCoin.tokenContractAddress.toLowerCase();
|
|
638
|
+
});
|
|
639
|
+
// Parse the raw transaction
|
|
640
|
+
const txBuilder = this.getTransactionBuilder();
|
|
641
|
+
txBuilder.from(txPrebuild.txHex);
|
|
642
|
+
const tx = await txBuilder.build();
|
|
643
|
+
const txJson = tx.toJson();
|
|
644
|
+
// Verify transaction targets the correct contract based on calldata shape
|
|
645
|
+
const network = this.getNetwork();
|
|
646
|
+
const aclContractAddress = network?.zamaAclContractAddress;
|
|
647
|
+
if (!aclContractAddress) {
|
|
648
|
+
throw new Error('verifyEnableTokenTransaction: zamaAclContractAddress not configured for this network');
|
|
649
|
+
}
|
|
650
|
+
if (!txJson.to) {
|
|
651
|
+
throw new Error('verifyEnableTokenTransaction: transaction is missing recipient address');
|
|
652
|
+
}
|
|
653
|
+
// Inspect calldata method ID to distinguish root wallet from forwarder wallet:
|
|
654
|
+
// aclMulticallMethodId → root wallet: to = ACL contract directly
|
|
655
|
+
// callFromParentMethodId → forwarder wallet: to = forwarder, ACL address is inside calldata
|
|
656
|
+
const calldataMethodId = txJson.data.slice(0, 10);
|
|
657
|
+
if (calldataMethodId === abstract_eth_1.aclMulticallMethodId) {
|
|
658
|
+
// Root wallet (base address): tx calls the ACL contract directly
|
|
659
|
+
if (txJson.to.toLowerCase() !== aclContractAddress.toLowerCase()) {
|
|
660
|
+
throw new Error(`verifyEnableTokenTransaction: transaction target ${txJson.to} does not match ACL contract ${aclContractAddress}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
else if (calldataMethodId === abstract_eth_1.callFromParentMethodId) {
|
|
664
|
+
// Forwarder wallet: tx calls the forwarder, which calls the ACL via callFromParent.
|
|
665
|
+
// The forwarder address is wallet-specific and cannot be statically verified here;
|
|
666
|
+
// token address correctness is still verified below via calldata decoding.
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
throw new Error(`verifyEnableTokenTransaction: unrecognised calldata method ID ${calldataMethodId}; expected multicall or callFromParent`);
|
|
670
|
+
}
|
|
671
|
+
// Verify value is 0
|
|
672
|
+
if (txJson.value !== '0') {
|
|
673
|
+
throw new Error(`verifyEnableTokenTransaction: expected transaction value 0 but got ${txJson.value}`);
|
|
674
|
+
}
|
|
675
|
+
// Decode token addresses from calldata and verify all requested tokens are present
|
|
676
|
+
const decodedAddresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(txJson.data);
|
|
677
|
+
for (const requested of requestedAddresses) {
|
|
678
|
+
if (!decodedAddresses.includes(requested)) {
|
|
679
|
+
throw new Error(`verifyEnableTokenTransaction: requested token ${requested} not found in delegation calldata`);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
// Multisig path: buildParams-level check
|
|
686
|
+
const recipients = txPrebuild.buildParams?.recipients;
|
|
687
|
+
if (!recipients || recipients.length === 0) {
|
|
688
|
+
throw new Error('verifyEnableTokenTransaction: missing buildParams.recipients for multisig path');
|
|
689
|
+
}
|
|
690
|
+
// Determine requested token names from txParams
|
|
691
|
+
const requestedTokenNames = [];
|
|
692
|
+
if (txParams.enableTokens && txParams.enableTokens.length > 0) {
|
|
693
|
+
requestedTokenNames.push(...txParams.enableTokens.map((t) => t.name));
|
|
694
|
+
}
|
|
695
|
+
else if (txParams.recipients && txParams.recipients.length > 0) {
|
|
696
|
+
requestedTokenNames.push(...txParams.recipients.map((r) => r.tokenName).filter(Boolean));
|
|
697
|
+
}
|
|
698
|
+
// Verify all recipients have tokenName and amount = '0'
|
|
699
|
+
for (const recipient of recipients) {
|
|
700
|
+
if (!recipient.tokenName) {
|
|
701
|
+
throw new Error('verifyEnableTokenTransaction: recipient is missing tokenName in buildParams');
|
|
702
|
+
}
|
|
703
|
+
if (recipient.amount !== '0') {
|
|
704
|
+
throw new Error(`verifyEnableTokenTransaction: expected amount 0 for token enablement but got ${recipient.amount}`);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// Verify requested token names are present in recipients
|
|
708
|
+
if (requestedTokenNames.length > 0) {
|
|
709
|
+
const recipientTokenNames = recipients.map((r) => r.tokenName);
|
|
710
|
+
for (const requested of requestedTokenNames) {
|
|
711
|
+
if (!recipientTokenNames.includes(requested)) {
|
|
712
|
+
throw new Error(`verifyEnableTokenTransaction: requested token ${requested} not found in buildParams recipients`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Override gas limit for ERC-7984 confidential token recovery.
|
|
721
|
+
* Actual on-chain usage is ~506-530k gas based on testnet results.
|
|
722
|
+
* Default: 800,000 (comfortable buffer over observed usage).
|
|
723
|
+
*/
|
|
724
|
+
setGasLimit(userGasLimit) {
|
|
725
|
+
if (!userGasLimit) {
|
|
726
|
+
return 800000;
|
|
727
|
+
}
|
|
728
|
+
return super.setGasLimit(userGasLimit);
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Queries the encrypted balance handle for a wallet address via eth_call to the
|
|
732
|
+
* token contract's confidentialBalanceOf(address) function.
|
|
733
|
+
*
|
|
734
|
+
* @param walletAddress - the wallet contract address to query balance for
|
|
735
|
+
* @param apiKey - optional Etherscan API key
|
|
736
|
+
* @returns bytes32 encrypted handle (0x-prefixed, 66 chars).
|
|
737
|
+
* Note: handles are always non-zero even for zero balances (encrypted domain).
|
|
738
|
+
*/
|
|
739
|
+
async queryConfidentialBalance(walletAddress, apiKey) {
|
|
740
|
+
const methodSignature = abstract_eth_1.optionalDeps.ethAbi.methodID('confidentialBalanceOf', ['address']);
|
|
741
|
+
const encodedArgs = abstract_eth_1.optionalDeps.ethAbi.rawEncode(['address'], [walletAddress]);
|
|
742
|
+
const calldata = Buffer.concat([methodSignature, encodedArgs]).toString('hex');
|
|
743
|
+
const result = await this.recoveryBlockchainExplorerQuery({
|
|
744
|
+
chainid: this.getChainId().toString(),
|
|
745
|
+
module: 'proxy',
|
|
746
|
+
action: 'eth_call',
|
|
747
|
+
to: this.tokenContractAddress,
|
|
748
|
+
data: calldata,
|
|
749
|
+
tag: 'latest',
|
|
750
|
+
}, apiKey);
|
|
751
|
+
if (!result || !result.result) {
|
|
752
|
+
throw new sdk_core_1.RecoveryProviderError(`Could not obtain confidential balance for ${walletAddress} from token ${this.tokenContractAddress}`);
|
|
753
|
+
}
|
|
754
|
+
const handle = result.result;
|
|
755
|
+
if (!handle.startsWith('0x') || handle.length !== 66) {
|
|
756
|
+
throw new sdk_core_1.RecoveryProviderError(`Unexpected confidentialBalanceOf response format: ${handle}`);
|
|
757
|
+
}
|
|
758
|
+
return handle;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Builds a non-BitGo recovery transaction for ERC-7984 confidential tokens.
|
|
762
|
+
*
|
|
763
|
+
* Uses the no-proof handle sweep: confidentialTransfer(recipient, handle) with 2 args.
|
|
764
|
+
* No FHE decryption or proof generation is needed — the wallet transfers its entire
|
|
765
|
+
* encrypted balance handle without knowing the plaintext amount.
|
|
766
|
+
*
|
|
767
|
+
* The outer transaction shape is:
|
|
768
|
+
* tx.to = walletContractAddress
|
|
769
|
+
* tx.data = sendMultiSig(tokenContractAddr, 0, confidentialTransfer(recoveryDest, handle), ...)
|
|
770
|
+
*/
|
|
771
|
+
async recover(params) {
|
|
772
|
+
if (params.isTss === true) {
|
|
773
|
+
throw new Error('ERC-7984 TSS recovery is not yet supported');
|
|
774
|
+
}
|
|
775
|
+
if (_.isUndefined(params.userKey)) {
|
|
776
|
+
throw new Error('missing userKey');
|
|
777
|
+
}
|
|
778
|
+
if (_.isUndefined(params.backupKey)) {
|
|
779
|
+
throw new Error('missing backupKey');
|
|
780
|
+
}
|
|
781
|
+
if (_.isUndefined(params.walletPassphrase) && !params.userKey.startsWith('xpub')) {
|
|
782
|
+
throw new Error('missing wallet passphrase');
|
|
783
|
+
}
|
|
784
|
+
if (_.isUndefined(params.walletContractAddress) || !this.isValidAddress(params.walletContractAddress)) {
|
|
785
|
+
throw new Error('invalid walletContractAddress');
|
|
786
|
+
}
|
|
787
|
+
if (_.isUndefined(params.recoveryDestination) || !this.isValidAddress(params.recoveryDestination)) {
|
|
788
|
+
throw new Error('invalid recoveryDestination');
|
|
789
|
+
}
|
|
790
|
+
const isKrsRecovery = (0, sdk_core_1.getIsKrsRecovery)(params);
|
|
791
|
+
const isUnsignedSweep = params.isUnsignedSweep ?? (0, sdk_core_1.getIsUnsignedSweep)(params);
|
|
792
|
+
if (isKrsRecovery) {
|
|
793
|
+
(0, sdk_core_1.checkKrsProvider)(this, params.krsProvider, { checkCoinFamilySupport: false });
|
|
794
|
+
}
|
|
795
|
+
let userKey = params.userKey.replace(/\s/g, '');
|
|
796
|
+
const backupKey = params.backupKey.replace(/\s/g, '');
|
|
797
|
+
const gasPrice = params.eip1559
|
|
798
|
+
? new abstract_eth_1.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
|
|
799
|
+
: new abstract_eth_1.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice));
|
|
800
|
+
const gasLimit = new abstract_eth_1.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit));
|
|
801
|
+
// Decrypt private keys from KeyCard values
|
|
802
|
+
if (!userKey.startsWith('xpub') && !userKey.startsWith('xprv')) {
|
|
803
|
+
try {
|
|
804
|
+
userKey = await this.bitgo.decrypt({
|
|
805
|
+
input: userKey,
|
|
806
|
+
password: params.walletPassphrase,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
catch (e) {
|
|
810
|
+
throw new Error(`Error decrypting user keychain: ${e.message}`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
let backupKeyAddress;
|
|
814
|
+
let backupSigningKey;
|
|
815
|
+
if (isKrsRecovery || isUnsignedSweep) {
|
|
816
|
+
const backupHDNode = secp256k1_1.bip32.fromBase58(backupKey);
|
|
817
|
+
backupSigningKey = backupHDNode.publicKey;
|
|
818
|
+
backupKeyAddress = `0x${abstract_eth_1.optionalDeps.ethUtil.publicToAddress(backupSigningKey, true).toString('hex')}`;
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
let backupPrv;
|
|
822
|
+
try {
|
|
823
|
+
backupPrv = await this.bitgo.decrypt({
|
|
824
|
+
input: backupKey,
|
|
825
|
+
password: params.walletPassphrase,
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
catch (e) {
|
|
829
|
+
throw new Error(`Error decrypting backup keychain: ${e.message}`);
|
|
830
|
+
}
|
|
831
|
+
const backupHDNode = secp256k1_1.bip32.fromBase58(backupPrv);
|
|
832
|
+
backupSigningKey = backupHDNode.privateKey;
|
|
833
|
+
backupKeyAddress = `0x${abstract_eth_1.optionalDeps.ethUtil.privateToAddress(backupSigningKey).toString('hex')}`;
|
|
834
|
+
}
|
|
835
|
+
await this.assertRecoveryKeysAreWalletSigners(userKey, backupKeyAddress, params.walletContractAddress, params.apiKey);
|
|
836
|
+
const backupKeyNonce = await this.getAddressNonce(backupKeyAddress, params.apiKey);
|
|
837
|
+
const backupKeyBalance = await this.queryAddressBalance(backupKeyAddress, params.apiKey);
|
|
838
|
+
const totalGasNeeded = gasPrice.mul(gasLimit);
|
|
839
|
+
const weiToGwei = 10 ** 9;
|
|
840
|
+
if (backupKeyBalance.lt(totalGasNeeded)) {
|
|
841
|
+
throw new Error(`Backup key address ${backupKeyAddress} has balance ${(backupKeyBalance / weiToGwei).toString()} Gwei.` +
|
|
842
|
+
`This address must have a balance of at least ${(totalGasNeeded / weiToGwei).toString()}` +
|
|
843
|
+
` Gwei to perform recoveries. Try sending some ETH to this address then retry.`);
|
|
844
|
+
}
|
|
845
|
+
// Get the encrypted balance handle (auto-query or user-provided)
|
|
846
|
+
let encryptedHandle;
|
|
847
|
+
if (params.encryptedHandle) {
|
|
848
|
+
encryptedHandle = params.encryptedHandle;
|
|
849
|
+
}
|
|
850
|
+
else {
|
|
851
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
852
|
+
encryptedHandle = await this.queryConfidentialBalance(params.walletContractAddress, params.apiKey);
|
|
853
|
+
}
|
|
854
|
+
// Note: encrypted handles are always non-zero even for zero balances (encrypted domain).
|
|
855
|
+
// The transfer will execute but move 0 tokens if the wallet is empty.
|
|
856
|
+
// Build the inner calldata: confidentialTransfer(recoveryDestination, handle)
|
|
857
|
+
const innerCalldata = (0, abstract_eth_1.buildConfidentialTransferByHandleCalldata)(params.recoveryDestination, encryptedHandle);
|
|
858
|
+
// For sendMultiSig: recipient is the token contract, amount is 0, data carries the confidentialTransfer calldata
|
|
859
|
+
const recipients = [
|
|
860
|
+
{
|
|
861
|
+
address: this.tokenContractAddress,
|
|
862
|
+
amount: '0',
|
|
863
|
+
data: abstract_eth_1.optionalDeps.ethUtil.stripHexPrefix(innerCalldata),
|
|
864
|
+
},
|
|
865
|
+
];
|
|
866
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
867
|
+
const sequenceId = await this.querySequenceId(params.walletContractAddress, params.apiKey);
|
|
868
|
+
let operationHash;
|
|
869
|
+
let signature;
|
|
870
|
+
if (!isUnsignedSweep) {
|
|
871
|
+
operationHash = this.getOperationSha3ForExecuteAndConfirm(recipients, this.getDefaultExpireTime(), sequenceId);
|
|
872
|
+
signature = sdk_core_1.Util.ethSignMsgHash(operationHash, sdk_core_1.Util.xprvToEthPrivateKey(userKey));
|
|
873
|
+
try {
|
|
874
|
+
sdk_core_1.Util.ecRecoverEthAddress(operationHash, signature);
|
|
875
|
+
}
|
|
876
|
+
catch (e) {
|
|
877
|
+
throw new Error('Invalid signature');
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
const txInfo = {
|
|
881
|
+
recipient: recipients[0],
|
|
882
|
+
expireTime: this.getDefaultExpireTime(),
|
|
883
|
+
contractSequenceId: sequenceId,
|
|
884
|
+
operationHash: operationHash,
|
|
885
|
+
signature: signature ?? '',
|
|
886
|
+
gasLimit: gasLimit.toString(10),
|
|
887
|
+
};
|
|
888
|
+
const sendMethodArgs = this.getSendMethodArgs(txInfo);
|
|
889
|
+
const methodSignature = abstract_eth_1.optionalDeps.ethAbi.methodID(this.sendMethodName, _.map(sendMethodArgs, 'type'));
|
|
890
|
+
const encodedArgs = abstract_eth_1.optionalDeps.ethAbi.rawEncode(_.map(sendMethodArgs, 'type'), _.map(sendMethodArgs, 'value'));
|
|
891
|
+
const sendData = Buffer.concat([methodSignature, encodedArgs]);
|
|
892
|
+
let tx = eth_1.Eth.buildTransaction({
|
|
893
|
+
to: params.walletContractAddress,
|
|
894
|
+
nonce: backupKeyNonce,
|
|
895
|
+
value: 0,
|
|
896
|
+
gasPrice: gasPrice,
|
|
897
|
+
gasLimit: gasLimit,
|
|
898
|
+
data: sendData,
|
|
899
|
+
eip1559: params.eip1559,
|
|
900
|
+
replayProtectionOptions: params.replayProtectionOptions,
|
|
901
|
+
});
|
|
902
|
+
if (isUnsignedSweep) {
|
|
903
|
+
return this.formatForOfflineVault(txInfo, tx, userKey, backupKey, gasPrice, gasLimit, params.eip1559, params.replayProtectionOptions, params.apiKey);
|
|
904
|
+
}
|
|
905
|
+
if (!isKrsRecovery) {
|
|
906
|
+
tx = tx.sign(backupSigningKey);
|
|
907
|
+
}
|
|
908
|
+
const signedTx = {
|
|
909
|
+
id: abstract_eth_1.optionalDeps.ethUtil.bufferToHex(tx.hash()),
|
|
910
|
+
tx: tx.serialize().toString('hex'),
|
|
911
|
+
};
|
|
912
|
+
if (isKrsRecovery) {
|
|
913
|
+
signedTx.backupKey = backupKey;
|
|
914
|
+
signedTx.coin = this.getChain();
|
|
915
|
+
}
|
|
916
|
+
return signedTx;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Returns a DecryptionDelegationBuilder for constructing Zama ACL decryption
|
|
920
|
+
* delegation transactions.
|
|
921
|
+
*
|
|
922
|
+
* The builder produces a DecryptionDelegationTxRequest {to, data, value} that is
|
|
923
|
+
* wallet-type-agnostic — WP routes it to the correct signing path:
|
|
924
|
+
* - MPC: submit as a raw TSS transaction
|
|
925
|
+
* - Multisig: wrap in sendMultiSig(walletContract, to, 0, data, ...)
|
|
926
|
+
*
|
|
927
|
+
* Example:
|
|
928
|
+
* const req = coin.getDecryptionDelegationBuilder().build({
|
|
929
|
+
* aclContractAddress: '0xf0Ff...',
|
|
930
|
+
* delegateAddress: enterpriseViewingKey,
|
|
931
|
+
* tokenContractAddresses: [tokenAddress],
|
|
932
|
+
* expiryTimestamp: Math.floor(Date.now() / 1000) + 365 * 86400,
|
|
933
|
+
* });
|
|
934
|
+
*/
|
|
935
|
+
getDecryptionDelegationBuilder() {
|
|
936
|
+
return new abstract_eth_1.DecryptionDelegationBuilder();
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
exports.Erc7984Token = Erc7984Token;
|
|
940
|
+
Erc7984Token.coinNames = {
|
|
941
|
+
Mainnet: 'eth',
|
|
942
|
+
Testnet: 'hteth',
|
|
943
|
+
};
|
|
944
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJjNzk4NFRva2VuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VyYzc5ODRUb2tlbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7R0FFRztBQUNILG1EQVU4QjtBQUM5QixpREFBeUY7QUFDekYsMkRBMkJrQztBQUNsQyxxREFBOEM7QUFDOUMsMENBQTRCO0FBRTVCLCtCQUE0QjtBQUM1QiwrQkFBMkM7QUFJM0MsTUFBYSxZQUFhLFNBQVEsU0FBRztJQVFuQyxZQUFZLEtBQWdCLEVBQUUsV0FBK0I7UUFDM0QsTUFBTSxXQUFXLEdBQUcsZUFBSyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsS0FBSyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUMvQixrRkFBa0Y7UUFDbEYsNEdBQTRHO1FBQzVHLDJFQUEyRTtRQUMzRSxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsTUFBTSxDQUFDLHNCQUFzQixDQUFDLE1BQTBCO1FBQ3RELE9BQU8sQ0FBQyxLQUFnQixFQUFFLEVBQUUsQ0FBQyxJQUFJLFlBQVksQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELE1BQU0sQ0FBQyx1QkFBdUIsQ0FDNUIsZUFBcUM7UUFDbkMsR0FBRyxnQkFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCO1FBQ3hDLEdBQUcsZ0JBQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQjtLQUN6QztRQUVELE1BQU0sV0FBVyxHQUEyQixFQUFFLENBQUM7UUFDL0MsS0FBSyxNQUFNLEtBQUssSUFBSSxZQUFZLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGdCQUFnQixHQUFHLFlBQVksQ0FB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RSxNQUFNLENBQUMsdUJBQXVCO1NBQ3hELENBQUMsQ0FBQztRQUVILElBQUksZUFBZSxFQUFFLENBQUM7WUFDcEIsT0FBTyxJQUFJLENBQUMscUJBQXFCLENBQy9CLE1BQU0sRUFDTixFQUFFLEVBQ0YsT0FBTyxFQUNQLFNBQVMsRUFDVCxRQUFRLEVBQ1IsUUFBUSxFQUNSLE1BQU0sQ0FBQyxPQUFPLEVBQ2QsTUFBTSxDQUFDLHVCQUF1QixFQUM5QixNQUFNLENBQUMsTUFBTSxDQUNQLENBQUM7UUFDWCxDQUFDO1FBRUQsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ25CLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDakMsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFpQjtZQUM3QixFQUFFLEVBQUUsMkJBQVksQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUMvQyxFQUFFLEVBQUUsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUM7U0FDbkMsQ0FBQztRQUVGLElBQUksYUFBYSxFQUFFLENBQUM7WUFDbEIsUUFBUSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7WUFDL0IsUUFBUSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEMsQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7OztPQWdCRztJQUNILDhCQUE4QjtRQUM1QixPQUFPLElBQUksMENBQTJCLEVBQUUsQ0FBQztJQUMzQyxDQUFDOztBQTlqQ0gsb0NBK2pDQztBQTVqQ1Esc0JBQVMsR0FBYztJQUM1QixPQUFPLEVBQUUsS0FBSztJQUNkLE9BQU8sRUFBRSxPQUFPO0NBQ2pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQge1xuICBCaXRHb0Jhc2UsXG4gIENvaW5Db25zdHJ1Y3RvcixcbiAgY2hlY2tLcnNQcm92aWRlcixcbiAgZ2V0SXNLcnNSZWNvdmVyeSxcbiAgZ2V0SXNVbnNpZ25lZFN3ZWVwLFxuICBNUENBbGdvcml0aG0sXG4gIE5hbWVkQ29pbkNvbnN0cnVjdG9yLFxuICBSZWNvdmVyeVByb3ZpZGVyRXJyb3IsXG4gIFV0aWwsXG59IGZyb20gJ0BiaXRnby1iZXRhL3Nkay1jb3JlJztcbmltcG9ydCB7IGNvaW5zLCBFcmM3OTg0VG9rZW5Db25maWcsIEV0aGVyZXVtTmV0d29yaywgdG9rZW5zIH0gZnJvbSAnQGJpdGdvLWJldGEvc3RhdGljcyc7XG5pbXBvcnQge1xuICBDb2luTmFtZXMsXG4gIERlY3J5cHRpb25EZWxlZ2F0aW9uQnVpbGRlcixcbiAgZGVjb2RlVG9rZW5BZGRyZXNzZXNGcm9tRGVsZWdhdGlvbkNhbGxkYXRhLFxuICBkZWNvZGVDb25maWRlbnRpYWxUcmFuc2ZlckRhdGEsXG4gIGRlY29kZURpcmVjdENvbmZpZGVudGlhbFRyYW5zZmVyQ2FsbGRhdGEsXG4gIGRlY29kZUZsdXNoRVJDNzk4NEZvcndhcmRlclRva2VuQ2FsbGRhdGEsXG4gIGRlY29kZVNlbmRNdWx0aVNpZ0ZsdXNoRVJDNzk4NERhdGEsXG4gIHNlbmRNdWx0aXNpZ01ldGhvZElkLFxuICBjb25maWRlbnRpYWxUcmFuc2ZlcldpdGhQcm9vZk1ldGhvZElkLFxuICBidWlsZENvbmZpZGVudGlhbFRyYW5zZmVyQnlIYW5kbGVDYWxsZGF0YSxcbiAgb3B0aW9uYWxEZXBzLFxuICBSZWNvdmVyT3B0aW9ucyxcbiAgUmVjb3ZlcnlJbmZvLFxuICBPZmZsaW5lVmF1bHRUeEluZm8sXG4gIFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgYWNsTXVsdGljYWxsTWV0aG9kSWQsXG4gIGNhbGxGcm9tUGFyZW50TWV0aG9kSWQsXG4gIGRlY29kZVdyYXBDYWxsZGF0YSxcbiAgd3JhcE1ldGhvZElkLFxuICBhc3NlcnRXcmFwQW1vdW50Rml0c1VpbnQ2NCxcbiAgZGVjb2RlVW53cmFwQ2FsbGRhdGEsXG4gIHVud3JhcE1ldGhvZElkLFxuICBkZWNvZGVGaW5hbGl6ZVVud3JhcENhbGxkYXRhLFxuICBmaW5hbGl6ZVVud3JhcE1ldGhvZElkLFxuICBVSU5UNjRfTUFYLFxuICBkZWNvZGVUcmFuc2ZlckRhdGEsXG59IGZyb20gJ0BiaXRnby1iZXRhL2Fic3RyYWN0LWV0aCc7XG5pbXBvcnQgeyBiaXAzMiB9IGZyb20gJ0BiaXRnby1iZXRhL3NlY3AyNTZrMSc7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5cbmltcG9ydCB7IEV0aCB9IGZyb20gJy4vZXRoJztcbmltcG9ydCB7IFRyYW5zYWN0aW9uQnVpbGRlciB9IGZyb20gJy4vbGliJztcblxuZXhwb3J0IHsgRXJjNzk4NFRva2VuQ29uZmlnIH07XG5cbmV4cG9ydCBjbGFzcyBFcmM3OTg0VG9rZW4gZXh0ZW5kcyBFdGgge1xuICBwdWJsaWMgcmVhZG9ubHkgdG9rZW5Db25maWc6IEVyYzc5ODRUb2tlbkNvbmZpZztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNlbmRNZXRob2ROYW1lOiAnc2VuZE11bHRpU2lnJyB8ICdzZW5kTXVsdGlTaWdUb2tlbic7XG4gIHN0YXRpYyBjb2luTmFtZXM6IENvaW5OYW1lcyA9IHtcbiAgICBNYWlubmV0OiAnZXRoJyxcbiAgICBUZXN0bmV0OiAnaHRldGgnLFxuICB9O1xuXG4gIGNvbnN0cnVjdG9yKGJpdGdvOiBCaXRHb0Jhc2UsIHRva2VuQ29uZmlnOiBFcmM3OTg0VG9rZW5Db25maWcpIHtcbiAgICBjb25zdCBzdGF0aWNzQ29pbiA9IGNvaW5zLmdldCh0b2tlbkNvbmZpZy5jb2luKTtcbiAgICBzdXBlcihiaXRnbywgc3RhdGljc0NvaW4pO1xuICAgIHRoaXMudG9rZW5Db25maWcgPSB0b2tlbkNvbmZpZztcbiAgICAvLyBFUkM3OTg0IGNvbmZpZGVudGlhbCB0cmFuc2ZlcnMgdXNlIHNlbmRNdWx0aVNpZyAobm90IHNlbmRNdWx0aVNpZ1Rva2VuKSBiZWNhdXNlXG4gICAgLy8gdGhlIGNhbGxkYXRhIHBhcmFtZXRlciBpcyByZXF1aXJlZCB0byBjYXJyeSBjb25maWRlbnRpYWxUcmFuc2ZlcihyZWNpcGllbnQsIGVuY3J5cHRlZEhhbmRsZSwgaW5wdXRQcm9vZikuXG4gICAgLy8gc2VuZE11bHRpU2lnVG9rZW4gaGFzIG5vIGRhdGEgcGFyYW1ldGVyIGFuZCBjYW5ub3QgY2FycnkgaW5uZXIgY2FsbGRhdGEuXG4gICAgdGhpcy5zZW5kTWV0aG9kTmFtZSA9ICdzZW5kTXVsdGlTaWcnO1xuICB9XG5cbiAgc3RhdGljIGNyZWF0ZVRva2VuQ29uc3RydWN0b3IoY29uZmlnOiBFcmM3OTg0VG9rZW5Db25maWcpOiBDb2luQ29uc3RydWN0b3Ige1xuICAgIHJldHVybiAoYml0Z286IEJpdEdvQmFzZSkgPT4gbmV3IEVyYzc5ODRUb2tlbihiaXRnbywgY29uZmlnKTtcbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGVUb2tlbkNvbnN0cnVjdG9ycyhcbiAgICB0b2tlbkNvbmZpZ3M6IEVyYzc5ODRUb2tlbkNvbmZpZ1tdID0gW1xuICAgICAgLi4udG9rZW5zLmJpdGNvaW4uZXRoLmNvbmZpZGVudGlhbFRva2VucyxcbiAgICAgIC4uLnRva2Vucy50ZXN0bmV0LmV0aC5jb25maWRlbnRpYWxUb2tlbnMsXG4gICAgXVxuICApOiBOYW1lZENvaW5Db25zdHJ1Y3RvcltdIHtcbiAgICBjb25zdCB0b2tlbnNDdG9yczogTmFtZWRDb2luQ29uc3RydWN0b3JbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgdG9rZW4gb2YgdG9rZW5Db25maWdzKSB7XG4gICAgICBjb25zdCB0b2tlbkNvbnN0cnVjdG9yID0gRXJjNzk4NFRva2VuLmNyZWF0ZVRva2VuQ29uc3RydWN0b3IodG9rZW4pO1xuICAgICAgdG9rZW5zQ3RvcnMucHVzaCh7IG5hbWU6IHRva2VuLnR5cGUsIGNvaW5Db25zdHJ1Y3RvcjogdG9rZW5Db25zdHJ1Y3RvciB9KTtcbiAgICAgIHRva2Vuc0N0b3JzLnB1c2goeyBuYW1lOiB0b2tlbi50b2tlbkNvbnRyYWN0QWRkcmVzcywgY29pbkNvbnN0cnVjdG9yOiB0b2tlbkNvbnN0cnVjdG9yIH0pO1xuICAgIH1cbiAgICByZXR1cm4gdG9rZW5zQ3RvcnM7XG4gIH1cblxuICBnZXQgdHlwZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRva2VuQ29uZmlnLnR5cGU7XG4gIH1cblxuICBnZXQgbmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRva2VuQ29uZmlnLm5hbWU7XG4gIH1cblxuICBnZXQgY29pbigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRva2VuQ29uZmlnLmNvaW47XG4gIH1cblxuICBnZXQgbmV0d29yaygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRva2VuQ29uZmlnLm5ldHdvcms7XG4gIH1cblxuICBnZXQgdG9rZW5Db250cmFjdEFkZHJlc3MoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b2tlbkNvbmZpZy50b2tlbkNvbnRyYWN0QWRkcmVzcztcbiAgfVxuXG4gIGdldCBkZWNpbWFsUGxhY2VzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMudG9rZW5Db25maWcuZGVjaW1hbFBsYWNlcztcbiAgfVxuXG4gIGdldENoYWluKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMudG9rZW5Db25maWcudHlwZTtcbiAgfVxuXG4gIGdldEZ1bGxOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdFUkM3OTg0IENvbmZpZGVudGlhbCBUb2tlbic7XG4gIH1cblxuICBnZXRCYXNlRmFjdG9yKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIE1hdGgucG93KDEwLCB0aGlzLnRva2VuQ29uZmlnLmRlY2ltYWxQbGFjZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgZm9yIHNlbmRpbmcgdmFsdWUgb2YgMC5cbiAgICogRVJDLTc5ODQgY29uZmlkZW50aWFsIHRyYW5zZmVycyBhbHdheXMgY2FycnkgYW4gZW5jcnlwdGVkIGFtb3VudDsgemVyby12YWx1ZSBzZW5kcyBhcmUgbm90IG1lYW5pbmdmdWwuXG4gICAqL1xuICB2YWx1ZWxlc3NUcmFuc2ZlckFsbG93ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgZm9yIHNlbmRpbmcgZGF0YSBhbG9uZyB3aXRoIHRyYW5zYWN0aW9ucyB2aWEgdGhlIHN0YW5kYXJkIHRva2VuLXNlbmQgQVBJLlxuICAgKiBSZXR1cm5zIGZhbHNlIGJlY2F1c2UgRVJDLTc5ODQgc2VuZHMgdXNlIGNvbmZpZGVudGlhbFRyYW5zZmVyKCkgY2FsbGRhdGEgYnVpbHRcbiAgICogYnkgV1AsIG5vdCBhbiBhcmJpdHJhcnkgZGF0YSBmaWVsZCBvbiB0aGUgc2VuZCBwYXJhbXMuXG4gICAqIE5vdGU6IHRoaXMgZG9lcyBub3QgcHJldmVudCBjYWxsZGF0YS1iYXNlZCBmbG93cyBsaWtlIGdldERlbGVnYXRpb25CdWlsZGVyKCksXG4gICAqIHdoaWNoIGJ5cGFzcyB0aGUgdG9rZW4tc2VuZCBwYXRoIGVudGlyZWx5LlxuICAgKi9cbiAgdHJhbnNhY3Rpb25EYXRhQWxsb3dlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKi9cbiAgc3VwcG9ydHNUc3MoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKi9cbiAgZ2V0TVBDQWxnb3JpdGhtKCk6IE1QQ0FsZ29yaXRobSB7XG4gICAgcmV0dXJuICdlY2RzYSc7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk6IFRyYW5zYWN0aW9uQnVpbGRlciB7XG4gICAgcmV0dXJuIG5ldyBUcmFuc2FjdGlvbkJ1aWxkZXIoY29pbnMuZ2V0KHRoaXMuZ2V0QmFzZUNoYWluKCkpKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmIChwYXJhbXMudHhQYXJhbXM/LnR5cGUgPT09ICdlbmFibGV0b2tlbicpIHtcbiAgICAgIHJldHVybiB0aGlzLnZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICB9XG4gICAgaWYgKHBhcmFtcy50eFBhcmFtcz8udHlwZSA9PT0gJ3dyYXAnKSB7XG4gICAgICByZXR1cm4gdGhpcy52ZXJpZnlXcmFwVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICB9XG4gICAgaWYgKHBhcmFtcy50eFBhcmFtcz8udHlwZSA9PT0gJ3Vud3JhcCcpIHtcbiAgICAgIHJldHVybiB0aGlzLnZlcmlmeVVud3JhcFRyYW5zYWN0aW9uKHBhcmFtcyk7XG4gICAgfVxuICAgIGlmIChwYXJhbXMudHhQYXJhbXM/LnR5cGUgPT09ICdmaW5hbGl6ZVVud3JhcCcpIHtcbiAgICAgIHJldHVybiB0aGlzLnZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuaXNDb25zb2xpZGF0aW9uVHJhbnNhY3Rpb24ocGFyYW1zKSkge1xuICAgICAgcmV0dXJuIHRoaXMudmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbihwYXJhbXMpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy52ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcihwYXJhbXMpO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0NvbnNvbGlkYXRpb25UcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHZlcmlmaWNhdGlvbiB9ID0gcGFyYW1zO1xuICAgIHJldHVybiAhIShcbiAgICAgIHZlcmlmaWNhdGlvbj8uY29uc29saWRhdGlvblRvQmFzZUFkZHJlc3MgfHxcbiAgICAgIHR4UHJlYnVpbGQ/LmNvbnNvbGlkYXRlSWQgfHxcbiAgICAgIHR4UGFyYW1zPy50eXBlID09PSAnY29uc29saWRhdGUnIHx8XG4gICAgICAvLyBUU1Mgc2lnbmluZyBwYXRoOiByZXNvbHZlRWZmZWN0aXZlVHhQYXJhbXMgc2V0cyB0eXBlIGZyb20gaW50ZW50LmludGVudFR5cGUgd2hpY2ggaXNcbiAgICAgIC8vICdjb25zb2xpZGF0ZVRva2VuJyBmb3IgRVJDLTc5ODQgdG9rZW4gY29uc29saWRhdGlvbnMuIHR4UHJlYnVpbGQgaGFzIG9ubHkgdHhIZXhcbiAgICAgIC8vIChubyBjb25zb2xpZGF0ZUlkKSBpbiB0aGlzIHBhdGguXG4gICAgICB0eFBhcmFtcz8udHlwZSA9PT0gJ2NvbnNvbGlkYXRlVG9rZW4nIHx8XG4gICAgICB0eFBhcmFtcz8ucHJlYnVpbGRUeD8uY29uc29saWRhdGVJZFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpZXMgV3JhcEVSQzc5ODQgKHNoaWVsZCkgdHJhbnNhY3Rpb25zLlxuICAgKlxuICAgKiBUU1MgLyBkaXJlY3Qgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdyYXBwZXIgY29udHJhY3RcbiAgICogICB0eC5kYXRhID0gd3JhcChiYXNlQWRkcmVzcywgYW1vdW50KVxuICAgKlxuICAgKiBNdWx0aXNpZyBzaGFwZTpcbiAgICogICB0eC50byAgID0gd2FsbGV0IGNvbnRyYWN0XG4gICAqICAgdHguZGF0YSA9IHNlbmRNdWx0aVNpZyh3cmFwcGVyLCAwLCB3cmFwKGJhc2VBZGRyZXNzLCBhbW91bnQpLCAuLi4pXG4gICAqXG4gICAqIENoZWNrczogd3JhcHBlciBhZGRyZXNzLCBzZWxmLWRpcmVjdGVkIGB0b2AgPT0gYmFzZSwgYW1vdW50ID4gMCwgYW1vdW50IG1hdGNoZXNcbiAgICogcmVjaXBpZW50cywgYW5kIGZsb29yKGFtb3VudCAvIHJhdGUpIGZpdHMgdWludDY0IHdoZW4gc3RhdGljcyByYXRlIGlzIHByZXNlbnQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZlcmlmeVdyYXBUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldCB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKCF0eFByZWJ1aWxkPy50eEhleCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IG1pc3NpbmcgdHhIZXggaW4gdHhQcmVidWlsZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmZyb20odHhQcmVidWlsZC50eEhleCk7XG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCB0eEpzb24gPSB0eC50b0pzb24oKTtcblxuICAgIGxldCB3cmFwcGVyQWRkcmVzczogc3RyaW5nO1xuICAgIGxldCB3cmFwQ2FsbGRhdGE6IHN0cmluZztcblxuICAgIHRyeSB7XG4gICAgICBpZiAodHhKc29uLmRhdGEudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKHNlbmRNdWx0aXNpZ01ldGhvZElkLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVUcmFuc2ZlckRhdGEodHhKc29uLmRhdGEpO1xuICAgICAgICB3cmFwcGVyQWRkcmVzcyA9IGRlY29kZWQudG87XG4gICAgICAgIHdyYXBDYWxsZGF0YSA9IGRlY29kZWQuZGF0YSBhcyBzdHJpbmc7XG4gICAgICAgIGlmIChkZWNvZGVkLmFtb3VudCAhPT0gJzAnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBleHBlY3RlZCBzZW5kTXVsdGlTaWcgdmFsdWUgMCBidXQgZ290ICR7ZGVjb2RlZC5hbW91bnR9YCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodHhKc29uLmRhdGEudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKHdyYXBNZXRob2RJZC50b0xvd2VyQ2FzZSgpKSkge1xuICAgICAgICB3cmFwcGVyQWRkcmVzcyA9IHR4SnNvbi50byBhcyBzdHJpbmc7XG4gICAgICAgIHdyYXBDYWxsZGF0YSA9IHR4SnNvbi5kYXRhO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bmV4cGVjdGVkIG1ldGhvZCBJRCAke3R4SnNvbi5kYXRhLnNsaWNlKDAsIDEwKX1gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVdyYXBUcmFuc2FjdGlvbjogZmFpbGVkIHRvIGRlY29kZSB3cmFwIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgIH1cblxuICAgIGlmICh3cmFwcGVyQWRkcmVzcy50b0xvd2VyQ2FzZSgpICE9PSB0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeVdyYXBUcmFuc2FjdGlvbjogd3JhcHBlciBhZGRyZXNzIG1pc21hdGNoIOKAlCBgICtcbiAgICAgICAgICBgZXhwZWN0ZWQgJHt0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzfSwgZ290ICR7d3JhcHBlckFkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgdG86IHN0cmluZztcbiAgICBsZXQgYW1vdW50OiBzdHJpbmc7XG4gICAgdHJ5IHtcbiAgICAgICh7IHRvLCBhbW91bnQgfSA9IGRlY29kZVdyYXBDYWxsZGF0YSh3cmFwQ2FsbGRhdGEpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVdyYXBUcmFuc2FjdGlvbjogaW52YWxpZCB3cmFwIGlubmVyIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgIH1cblxuICAgIGlmICghRXJjNzk4NFRva2VuLmlzUG9zaXRpdmVJbnRlZ2VyU3RyaW5nKGFtb3VudCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5V3JhcFRyYW5zYWN0aW9uOiBhbW91bnQgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIgc3RyaW5nLCBnb3QgJyR7YW1vdW50fSdgKTtcbiAgICB9XG5cbiAgICBjb25zdCBiYXNlQWRkcmVzcyA9IHRoaXMuZ2V0V2FsbGV0QmFzZUFkZHJlc3Mod2FsbGV0KTtcbiAgICBpZiAoIWJhc2VBZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeVdyYXBUcmFuc2FjdGlvbjogdW5hYmxlIHRvIGRldGVybWluZSB3YWxsZXQgYmFzZSBhZGRyZXNzJyk7XG4gICAgfVxuICAgIGlmICh0by50b0xvd2VyQ2FzZSgpICE9PSBiYXNlQWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IHdyYXAgcmVjaXBpZW50IG11c3QgZXF1YWwgd2FsbGV0IGJhc2UgYWRkcmVzcyDigJQgZXhwZWN0ZWQgJHtiYXNlQWRkcmVzc30sIGdvdCAke3RvfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgZXhwZWN0ZWRBbW91bnQgPSB0eFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdPy5hbW91bnQgPz8gdHhQcmVidWlsZC5idWlsZFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdPy5hbW91bnQ7XG4gICAgaWYgKGV4cGVjdGVkQW1vdW50ICE9PSB1bmRlZmluZWQgJiYgU3RyaW5nKGV4cGVjdGVkQW1vdW50KSAhPT0gYW1vdW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IGFtb3VudCBtaXNtYXRjaCDigJQgY2FsbGRhdGEgaGFzICcke2Ftb3VudH0nIGJ1dCBwYXJhbXMgaGF2ZSAnJHtleHBlY3RlZEFtb3VudH0nYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCByYXRlID0gdGhpcy50b2tlbkNvbmZpZy5yYXRlO1xuICAgIGlmIChyYXRlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGFzc2VydFdyYXBBbW91bnRGaXRzVWludDY0KGFtb3VudCwgcmF0ZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5V3JhcFRyYW5zYWN0aW9uOiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0eEpzb24udmFsdWUgIT09IHVuZGVmaW5lZCAmJiB0eEpzb24udmFsdWUgIT09ICcwJyAmJiB0eEpzb24udmFsdWUgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5V3JhcFRyYW5zYWN0aW9uOiBleHBlY3RlZCB0cmFuc2FjdGlvbiB2YWx1ZSAwIGJ1dCBnb3QgJHt0eEpzb24udmFsdWV9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpZXMgVW53cmFwRVJDNzk4NCAodW5zaGllbGQgcGhhc2UtMSkgdHJhbnNhY3Rpb25zLlxuICAgKlxuICAgKiBUU1MgLyBkaXJlY3Qgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdyYXBwZXIgY29udHJhY3RcbiAgICogICB0eC5kYXRhID0gdW53cmFwKGJhc2UsIGJhc2UsIGVuY3J5cHRlZEFtb3VudCwgaW5wdXRQcm9vZilcbiAgICpcbiAgICogTXVsdGlzaWcgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdhbGxldCBjb250cmFjdFxuICAgKiAgIHR4LmRhdGEgPSBzZW5kTXVsdGlTaWcod3JhcHBlciwgMCwgdW53cmFwKGJhc2UsIGJhc2UsIC4uLiksIC4uLilcbiAgICpcbiAgICogdjEgaXMgc2VsZi1kaXJlY3RlZCBvbmx5OiBmcm9tID09IHRvID09IHdhbGxldCBiYXNlIGFkZHJlc3MuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZlcmlmeVVud3JhcFRyYW5zYWN0aW9uKHBhcmFtczogVmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyB0eFByZWJ1aWxkLCB3YWxsZXQgfSA9IHBhcmFtcztcblxuICAgIGlmICghdHhQcmVidWlsZD8udHhIZXgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5VW53cmFwVHJhbnNhY3Rpb246IG1pc3NpbmcgdHhIZXggaW4gdHhQcmVidWlsZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmZyb20odHhQcmVidWlsZC50eEhleCk7XG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCB0eEpzb24gPSB0eC50b0pzb24oKTtcblxuICAgIGxldCB3cmFwcGVyQWRkcmVzczogc3RyaW5nO1xuICAgIGxldCB1bndyYXBDYWxsZGF0YTogc3RyaW5nO1xuXG4gICAgdHJ5IHtcbiAgICAgIGlmICh0eEpzb24uZGF0YS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoc2VuZE11bHRpc2lnTWV0aG9kSWQudG9Mb3dlckNhc2UoKSkpIHtcbiAgICAgICAgY29uc3QgZGVjb2RlZCA9IGRlY29kZVRyYW5zZmVyRGF0YSh0eEpzb24uZGF0YSk7XG4gICAgICAgIHdyYXBwZXJBZGRyZXNzID0gZGVjb2RlZC50bztcbiAgICAgICAgdW53cmFwQ2FsbGRhdGEgPSBkZWNvZGVkLmRhdGEgYXMgc3RyaW5nO1xuICAgICAgICBpZiAoZGVjb2RlZC5hbW91bnQgIT09ICcwJykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZXhwZWN0ZWQgc2VuZE11bHRpU2lnIHZhbHVlIDAgYnV0IGdvdCAke2RlY29kZWQuYW1vdW50fWApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHR4SnNvbi5kYXRhLnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aCh1bndyYXBNZXRob2RJZC50b0xvd2VyQ2FzZSgpKSkge1xuICAgICAgICB3cmFwcGVyQWRkcmVzcyA9IHR4SnNvbi50byBhcyBzdHJpbmc7XG4gICAgICAgIHVud3JhcENhbGxkYXRhID0gdHhKc29uLmRhdGE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgbWV0aG9kIElEICR7dHhKc29uLmRhdGEuc2xpY2UoMCwgMTApfWApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5VW53cmFwVHJhbnNhY3Rpb246IGZhaWxlZCB0byBkZWNvZGUgdW53cmFwIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgIH1cblxuICAgIGlmICh3cmFwcGVyQWRkcmVzcy50b0xvd2VyQ2FzZSgpICE9PSB0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiB3cmFwcGVyIGFkZHJlc3MgbWlzbWF0Y2gg4oCUIGV4cGVjdGVkICR7dGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzc30sIGdvdCAke3dyYXBwZXJBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IGZyb206IHN0cmluZztcbiAgICBsZXQgdG86IHN0cmluZztcbiAgICBsZXQgZW5jcnlwdGVkQW1vdW50OiBzdHJpbmc7XG4gICAgbGV0IGlucHV0UHJvb2Y6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgKHsgZnJvbSwgdG8sIGVuY3J5cHRlZEFtb3VudCwgaW5wdXRQcm9vZiB9ID0gZGVjb2RlVW53cmFwQ2FsbGRhdGEodW53cmFwQ2FsbGRhdGEpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiBpbnZhbGlkIHVud3JhcCBpbm5lciBjYWxsZGF0YSDigJQgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBiYXNlQWRkcmVzcyA9IHRoaXMuZ2V0V2FsbGV0QmFzZUFkZHJlc3Mod2FsbGV0KTtcbiAgICBpZiAoIWJhc2VBZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiB1bmFibGUgdG8gZGV0ZXJtaW5lIHdhbGxldCBiYXNlIGFkZHJlc3MnKTtcbiAgICB9XG4gICAgaWYgKGZyb20udG9Mb3dlckNhc2UoKSAhPT0gYmFzZUFkZHJlc3MudG9Mb3dlckNhc2UoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5VW53cmFwVHJhbnNhY3Rpb246IHVud3JhcCBmcm9tIG11c3QgZXF1YWwgd2FsbGV0IGJhc2UgYWRkcmVzcyDigJQgZXhwZWN0ZWQgJHtiYXNlQWRkcmVzc30sIGdvdCAke2Zyb219YFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHRvLnRvTG93ZXJDYXNlKCkgIT09IGJhc2VBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiB1bndyYXAgdG8gbXVzdCBlcXVhbCB3YWxsZXQgYmFzZSBhZGRyZXNzIOKAlCBleHBlY3RlZCAke2Jhc2VBZGRyZXNzfSwgZ290ICR7dG99YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoIWVuY3J5cHRlZEFtb3VudCB8fCBlbmNyeXB0ZWRBbW91bnQgPT09ICcweCcgfHwgL14weDArJC8udGVzdChlbmNyeXB0ZWRBbW91bnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiBlbmNyeXB0ZWRBbW91bnQgaXMgbWlzc2luZyBvciBlbXB0eScpO1xuICAgIH1cbiAgICBpZiAoIWlucHV0UHJvb2YgfHwgaW5wdXRQcm9vZiA9PT0gJzB4Jykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogaW5wdXRQcm9vZiBpcyBtaXNzaW5nIG9yIGVtcHR5Jyk7XG4gICAgfVxuXG4gICAgaWYgKHR4SnNvbi52YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHR4SnNvbi52YWx1ZSAhPT0gJzAnICYmIHR4SnNvbi52YWx1ZSAhPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogZXhwZWN0ZWQgdHJhbnNhY3Rpb24gdmFsdWUgMCBidXQgZ290ICR7dHhKc29uLnZhbHVlfWApO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIEZpbmFsaXplVW53cmFwRVJDNzk4NCAodW5zaGllbGQgcGhhc2UtMikgdHJhbnNhY3Rpb25zLlxuICAgKlxuICAgKiBUU1MgLyBkaXJlY3Qgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdyYXBwZXIgY29udHJhY3RcbiAgICogICB0eC5kYXRhID0gZmluYWxpemVVbndyYXAocmVxdWVzdElkLCBjbGVhcnRleHRBbW91bnQsIGRlY3J5cHRpb25Qcm9vZilcbiAgICpcbiAgICogTXVsdGlzaWcgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdhbGxldCBjb250cmFjdFxuICAgKiAgIHR4LmRhdGEgPSBzZW5kTXVsdGlTaWcod3JhcHBlciwgMCwgZmluYWxpemVVbndyYXAoLi4uKSwgLi4uKVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uKHBhcmFtczogVmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyB0eFBhcmFtcywgdHhQcmVidWlsZCB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKCF0eFByZWJ1aWxkPy50eEhleCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiBtaXNzaW5nIHR4SGV4IGluIHR4UHJlYnVpbGQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5mcm9tKHR4UHJlYnVpbGQudHhIZXgpO1xuICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG5cbiAgICBsZXQgd3JhcHBlckFkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgZmluYWxpemVDYWxsZGF0YTogc3RyaW5nO1xuXG4gICAgdHJ5IHtcbiAgICAgIGlmICh0eEpzb24uZGF0YS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoc2VuZE11bHRpc2lnTWV0aG9kSWQudG9Mb3dlckNhc2UoKSkpIHtcbiAgICAgICAgY29uc3QgZGVjb2RlZCA9IGRlY29kZVRyYW5zZmVyRGF0YSh0eEpzb24uZGF0YSk7XG4gICAgICAgIHdyYXBwZXJBZGRyZXNzID0gZGVjb2RlZC50bztcbiAgICAgICAgZmluYWxpemVDYWxsZGF0YSA9IGRlY29kZWQuZGF0YSBhcyBzdHJpbmc7XG4gICAgICAgIGlmIChkZWNvZGVkLmFtb3VudCAhPT0gJzAnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBleHBlY3RlZCBzZW5kTXVsdGlTaWcgdmFsdWUgMCBidXQgZ290ICR7ZGVjb2RlZC5hbW91bnR9YCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodHhKc29uLmRhdGEudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKGZpbmFsaXplVW53cmFwTWV0aG9kSWQudG9Mb3dlckNhc2UoKSkpIHtcbiAgICAgICAgd3JhcHBlckFkZHJlc3MgPSB0eEpzb24udG8gYXMgc3RyaW5nO1xuICAgICAgICBmaW5hbGl6ZUNhbGxkYXRhID0gdHhKc29uLmRhdGE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgbWV0aG9kIElEICR7dHhKc29uLmRhdGEuc2xpY2UoMCwgMTApfWApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IGZhaWxlZCB0byBkZWNvZGUgZmluYWxpemVVbndyYXAgY2FsbGRhdGEg4oCUICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAod3JhcHBlckFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gdGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiB3cmFwcGVyIGFkZHJlc3MgbWlzbWF0Y2gg4oCUIGV4cGVjdGVkICR7dGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzc30sIGdvdCAke3dyYXBwZXJBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHJlcXVlc3RJZDogc3RyaW5nO1xuICAgIGxldCBjbGVhcnRleHRBbW91bnQ6IHN0cmluZztcbiAgICBsZXQgZGVjcnlwdGlvblByb29mOiBzdHJpbmc7XG4gICAgdHJ5IHtcbiAgICAgICh7IHJlcXVlc3RJZCwgY2xlYXJ0ZXh0QW1vdW50LCBkZWNyeXB0aW9uUHJvb2YgfSA9IGRlY29kZUZpbmFsaXplVW53cmFwQ2FsbGRhdGEoZmluYWxpemVDYWxsZGF0YSkpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IGludmFsaWQgZmluYWxpemVVbndyYXAgaW5uZXIgY2FsbGRhdGEg4oCUICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoIXJlcXVlc3RJZCB8fCByZXF1ZXN0SWQgPT09ICcweCcgfHwgL14weDArJC8udGVzdChyZXF1ZXN0SWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IHJlcXVlc3RJZCBpcyBtaXNzaW5nIG9yIGVtcHR5Jyk7XG4gICAgfVxuICAgIGlmICghRXJjNzk4NFRva2VuLmlzUG9zaXRpdmVJbnRlZ2VyU3RyaW5nKGNsZWFydGV4dEFtb3VudCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IGNsZWFydGV4dEFtb3VudCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciBzdHJpbmcsIGdvdCAnJHtjbGVhcnRleHRBbW91bnR9J2BcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChCaWdJbnQoY2xlYXJ0ZXh0QW1vdW50KSA+IFVJTlQ2NF9NQVgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbjogY2xlYXJ0ZXh0QW1vdW50IGV4Y2VlZHMgdWludDY0Jyk7XG4gICAgfVxuICAgIGlmICghZGVjcnlwdGlvblByb29mIHx8IGRlY3J5cHRpb25Qcm9vZiA9PT0gJzB4Jykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiBkZWNyeXB0aW9uUHJvb2YgaXMgbWlzc2luZyBvciBlbXB0eScpO1xuICAgIH1cblxuICAgIGNvbnN0IGV4cGVjdGVkQW1vdW50ID0gdHhQYXJhbXM/LnJlY2lwaWVudHM/LlswXT8uYW1vdW50ID8/IHR4UHJlYnVpbGQuYnVpbGRQYXJhbXM/LnJlY2lwaWVudHM/LlswXT8uYW1vdW50O1xuICAgIGlmIChleHBlY3RlZEFtb3VudCAhPT0gdW5kZWZpbmVkICYmIFN0cmluZyhleHBlY3RlZEFtb3VudCkgIT09IGNsZWFydGV4dEFtb3VudCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbjogYW1vdW50IG1pc21hdGNoIOKAlCBjYWxsZGF0YSBoYXMgJyR7Y2xlYXJ0ZXh0QW1vdW50fScgYnV0IHBhcmFtcyBoYXZlICcke2V4cGVjdGVkQW1vdW50fSdgXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICh0eEpzb24udmFsdWUgIT09IHVuZGVmaW5lZCAmJiB0eEpzb24udmFsdWUgIT09ICcwJyAmJiB0eEpzb24udmFsdWUgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbjogZXhwZWN0ZWQgdHJhbnNhY3Rpb24gdmFsdWUgMCBidXQgZ290ICR7dHhKc29uLnZhbHVlfWApO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRXYWxsZXRCYXNlQWRkcmVzcyh3YWxsZXQ6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9uc1snd2FsbGV0J10pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghd2FsbGV0KSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjb25zdCBjb2luU3BlY2lmaWMgPSB0eXBlb2Ygd2FsbGV0LmNvaW5TcGVjaWZpYyA9PT0gJ2Z1bmN0aW9uJyA/IHdhbGxldC5jb2luU3BlY2lmaWMoKSA6IHdhbGxldC5jb2luU3BlY2lmaWM7XG4gICAgY29uc3QgZXRoQ29pblNwZWNpZmljID0gY29pblNwZWNpZmljIGFzIHsgYmFzZUFkZHJlc3M/OiBzdHJpbmc7IHJvb3RBZGRyZXNzPzogc3RyaW5nIH0gfCB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIGV0aENvaW5TcGVjaWZpYz8uYmFzZUFkZHJlc3MgPz8gZXRoQ29pblNwZWNpZmljPy5yb290QWRkcmVzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmllcyBFUkMtNzk4NCBmb3J3YXJkZXIgY29uc29saWRhdGlvbiAoZmx1c2gpIHRyYW5zYWN0aW9ucy5cbiAgICpcbiAgICogTXVsdGlzaWcgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdhbGxldCBjb250cmFjdFxuICAgKiAgIHR4LmRhdGEgPSBzZW5kTXVsdGlTaWcoZm9yd2FyZGVyLCAwLCBjYWxsRnJvbVBhcmVudCh0b2tlbiwgMCwgY29uZmlkZW50aWFsVHJhbnNmZXJOb1Byb29mKGJhc2UsIGhhbmRsZSkpLCAuLi4pXG4gICAqXG4gICAqIFRTUyAvIGRpcmVjdCBzaGFwZTpcbiAgICogICB0eC50byAgID0gZm9yd2FyZGVyIGNvbnRyYWN0XG4gICAqICAgdHguZGF0YSA9IGNhbGxGcm9tUGFyZW50KHRva2VuLCAwLCBjb25maWRlbnRpYWxUcmFuc2Zlck5vUHJvb2YoYmFzZSwgaGFuZGxlKSlcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldCB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKCF0eFByZWJ1aWxkPy50eEhleCkge1xuICAgICAgaWYgKCF0eFByZWJ1aWxkPy5jb25zb2xpZGF0ZUlkICYmICF0eFBhcmFtcz8ucHJlYnVpbGRUeD8uY29uc29saWRhdGVJZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb246IG1pc3NpbmcgY29uc29saWRhdGVJZCcpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgY29uc3QgdHhCdWlsZGVyID0gdGhpcy5nZXRUcmFuc2FjdGlvbkJ1aWxkZXIoKTtcbiAgICB0eEJ1aWxkZXIuZnJvbSh0eFByZWJ1aWxkLnR4SGV4KTtcbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIGNvbnN0IHR4SnNvbiA9IHR4LnRvSnNvbigpO1xuXG4gICAgbGV0IHRva2VuQ29udHJhY3RBZGRyZXNzOiBzdHJpbmc7XG4gICAgbGV0IHBhcmVudEFkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgZW5jcnlwdGVkSGFuZGxlOiBzdHJpbmc7XG4gICAgbGV0IGZvcndhcmRlckFkZHJlc3M6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgIHRyeSB7XG4gICAgICBpZiAodHhKc29uLmRhdGEuc3RhcnRzV2l0aChzZW5kTXVsdGlzaWdNZXRob2RJZCkpIHtcbiAgICAgICAgY29uc3QgZGVjb2RlZCA9IGRlY29kZVNlbmRNdWx0aVNpZ0ZsdXNoRVJDNzk4NERhdGEodHhKc29uLmRhdGEpO1xuICAgICAgICBmb3J3YXJkZXJBZGRyZXNzID0gZGVjb2RlZC5mb3J3YXJkZXJBZGRyZXNzO1xuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzcyA9IGRlY29kZWQudG9rZW5Db250cmFjdEFkZHJlc3M7XG4gICAgICAgIHBhcmVudEFkZHJlc3MgPSBkZWNvZGVkLnBhcmVudEFkZHJlc3M7XG4gICAgICAgIGVuY3J5cHRlZEhhbmRsZSA9IGRlY29kZWQuZW5jcnlwdGVkSGFuZGxlO1xuICAgICAgfSBlbHNlIGlmICh0eEpzb24uZGF0YS5zdGFydHNXaXRoKGNhbGxGcm9tUGFyZW50TWV0aG9kSWQpKSB7XG4gICAgICAgIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVGbHVzaEVSQzc5ODRGb3J3YXJkZXJUb2tlbkNhbGxkYXRhKHR4SnNvbi5kYXRhKTtcbiAgICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3MgPSBkZWNvZGVkLnRva2VuQ29udHJhY3RBZGRyZXNzO1xuICAgICAgICBwYXJlbnRBZGRyZXNzID0gZGVjb2RlZC5wYXJlbnRBZGRyZXNzO1xuICAgICAgICBlbmNyeXB0ZWRIYW5kbGUgPSBkZWNvZGVkLmVuY3J5cHRlZEhhbmRsZTtcbiAgICAgICAgZm9yd2FyZGVyQWRkcmVzcyA9IHR4SnNvbi50bztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBtZXRob2QgSUQgJHt0eEpzb24uZGF0YS5zbGljZSgwLCAxMCl9YCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbjogZmFpbGVkIHRvIGRlY29kZSBjb25zb2xpZGF0aW9uIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHRva2VuQ29udHJhY3RBZGRyZXNzLnRvTG93ZXJDYXNlKCkgIT09IHRoaXMudG9rZW5Db250cmFjdEFkZHJlc3MudG9Mb3dlckNhc2UoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbjogdG9rZW4gY29udHJhY3QgYWRkcmVzcyBtaXNtYXRjaCDigJQgYCArXG4gICAgICAgICAgYGV4cGVjdGVkICR7dGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzc30sIGdvdCAke3Rva2VuQ29udHJhY3RBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgYmFzZUFkZHJlc3MgPSB0aGlzLmdldFdhbGxldEJhc2VBZGRyZXNzKHdhbGxldCk7XG4gICAgaWYgKCFiYXNlQWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlDb25maWRlbnRpYWxDb25zb2xpZGF0aW9uOiB1bmFibGUgdG8gZGV0ZXJtaW5lIHdhbGxldCBiYXNlIGFkZHJlc3MnKTtcbiAgICB9XG4gICAgaWYgKHBhcmVudEFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gYmFzZUFkZHJlc3MudG9Mb3dlckNhc2UoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbjogcGFyZW50IGFkZHJlc3MgbWlzbWF0Y2gg4oCUIGV4cGVjdGVkICR7YmFzZUFkZHJlc3N9LCBnb3QgJHtwYXJlbnRBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFlbmNyeXB0ZWRIYW5kbGUgfHwgZW5jcnlwdGVkSGFuZGxlID09PSAnMHgnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb246IGVuY3J5cHRlZEhhbmRsZSBpcyBtaXNzaW5nIG9yIGVtcHR5IGluIHRyYW5zYWN0aW9uIGNhbGxkYXRhJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZXhwZWN0ZWRGb3J3YXJkZXIgPVxuICAgICAgdHhQcmVidWlsZC5yZWNpcGllbnRzPy5bMF0/LmFkZHJlc3MgPz9cbiAgICAgIHR4UHJlYnVpbGQudHhJbmZvPy5yZWNpcGllbnRzPy5bMF0/LmFkZHJlc3MgPz9cbiAgICAgIHR4UGFyYW1zPy5yZWNpcGllbnRzPy5bMF0/LmFkZHJlc3M7XG4gICAgaWYgKGZvcndhcmRlckFkZHJlc3MgJiYgZXhwZWN0ZWRGb3J3YXJkZXIpIHtcbiAgICAgIGlmIChmb3J3YXJkZXJBZGRyZXNzLnRvTG93ZXJDYXNlKCkgIT09IGV4cGVjdGVkRm9yd2FyZGVyLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGB2ZXJpZnlDb25maWRlbnRpYWxDb25zb2xpZGF0aW9uOiBmb3J3YXJkZXIgYWRkcmVzcyBtaXNtYXRjaCDigJQgYCArXG4gICAgICAgICAgICBgZXhwZWN0ZWQgJHtleHBlY3RlZEZvcndhcmRlcn0sIGdvdCAke2ZvcndhcmRlckFkZHJlc3N9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIGEgY29uZmlkZW50aWFsIHRva2VuIHRyYW5zZmVyIChTZW5kRVJDNzk4NCkgdHJhbnNhY3Rpb24uXG4gICAqXG4gICAqIFdpdGggdHhIZXgg4oCUIHR3byBvbi1jaGFpbiBzaGFwZXMgYXJlIHN1cHBvcnRlZDpcbiAgICpcbiAgICogICBzZW5kTXVsdGlTaWctd3JhcHBlZCAobXVsdGlzaWcgLyBzbWFydC1jb250cmFjdCB3YWxsZXQpOlxuICAgKiAgICAgdHgudG8gICA9IHdhbGxldCBjb250cmFjdFxuICAgKiAgICAgdHguZGF0YSA9IHNlbmRNdWx0aVNpZyh0b2tlbkFkZHIsIDAsIGNvbmZpZGVudGlhbFRyYW5zZmVyKHJlY2lwaWVudCwgaGFuZGxlLCBwcm9vZiksIC4uLilcbiAgICogICAgIFRva2VuIGNvbnRyYWN0IGFkZHJlc3MgaXMgZGVjb2RlZCBmcm9tIHRoZSBzZW5kTXVsdGlTaWcgaW5uZXIgY2FsbGRhdGEuXG4gICAqXG4gICAqICAgRGlyZWN0IGNhbGwgKGhvdCAvIFRTUyBFT0Egd2FsbGV0KTpcbiAgICogICAgIHR4LnRvICAgPSB0b2tlbiBjb250cmFjdFxuICAgKiAgICAgdHguZGF0YSA9IGNvbmZpZGVudGlhbFRyYW5zZmVyKHJlY2lwaWVudCwgaGFuZGxlLCBwcm9vZilcbiAgICogICAgIFRva2VuIGNvbnRyYWN0IGFkZHJlc3MgaXMgdGFrZW4gZnJvbSB0eC50by5cbiAgICpcbiAgICogICBGb3IgYm90aCBzaGFwZXMgdGhlIHZlcmlmaWVyIGNoZWNrczpcbiAgICogICAgIDEuIFRva2VuIGNvbnRyYWN0IGFkZHJlc3MgbWF0Y2hlcyB0aGlzIGNvaW4ncyB0b2tlbkNvbnRyYWN0QWRkcmVzcy5cbiAgICogICAgIDIuIERlY29kZWQgcmVjaXBpZW50IG1hdGNoZXMgdHhQYXJhbXMucmVjaXBpZW50c1swXS5hZGRyZXNzIG9yIGJ1aWxkUGFyYW1zLnJlY2lwaWVudHNbMF0uYWRkcmVzcy5cbiAgICogICAgIDMuIGVuY3J5cHRlZEhhbmRsZSBhbmQgaW5wdXRQcm9vZiBhcmUgc3RydWN0dXJhbGx5IHByZXNlbnQgKG5vbi1lbXB0eSkuXG4gICAqICAgICA0LiB0eFBhcmFtcy5yZWNpcGllbnRzWzBdLmFtb3VudCBpcyBhIHBvc2l0aXZlIGludGVnZXIgYW5kIG1hdGNoZXMgYnVpbGRQYXJhbXMgd2hlbiBib3RoIHByZXNlbnQuXG4gICAqXG4gICAqIFdpdGhvdXQgdHhIZXggKGZpcnN0LXNpZ25lciAvIHByZS1zaWduaW5nIHBhdGgpOlxuICAgKiAgMS4gUmVxdWlyZXMgZXhhY3RseSBvbmUgcmVjaXBpZW50IGluIHR4UGFyYW1zLlxuICAgKiAgMi4gVmFsaWRhdGVzIHR4UGFyYW1zLnJlY2lwaWVudHNbMF0uYWRkcmVzcyBpcyBhIHZhbGlkIEV0aGVyZXVtIGFkZHJlc3MuXG4gICAqICAzLiBWYWxpZGF0ZXMgdHhQYXJhbXMucmVjaXBpZW50c1swXS5hbW91bnQgaXMgYSBwb3NpdGl2ZSBpbnRlZ2VyLlxuICAgKiAgNC4gQ3Jvc3MtY2hlY2tzIGFkZHJlc3MgYW5kIGFtb3VudCBhZ2FpbnN0IGJ1aWxkUGFyYW1zIHdoZW4gdGhlIHNlcnZlciBoYXMgc3RvcmVkIHRoZSBpbnRlbnQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyKHBhcmFtczogVmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyB0eFBhcmFtcywgdHhQcmVidWlsZCB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKCF0eFByZWJ1aWxkPy50eEhleCkge1xuICAgICAgLy8gTm8gcmF3IHR4IGF2YWlsYWJsZSAobXVsdGlzaWcgZmlyc3Qtc2lnbmVyIHBhdGgpLlxuICAgICAgLy8gVmFsaWRhdGUgRVJDNzk4NC1zcGVjaWZpYyBpbnZhcmlhbnRzIGZyb20gdHhQYXJhbXMgYW5kIGJ1aWxkUGFyYW1zLlxuICAgICAgY29uc3QgcmVjaXBpZW50cyA9IHR4UGFyYW1zPy5yZWNpcGllbnRzO1xuICAgICAgaWYgKCFyZWNpcGllbnRzIHx8IHJlY2lwaWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IHJlY2lwaWVudHMgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZSBlbnRyeScpO1xuICAgICAgfVxuICAgICAgaWYgKHJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IGNvbmZpZGVudGlhbCB0cmFuc2ZlcnMgc3VwcG9ydCBleGFjdGx5IDEgcmVjaXBpZW50LCBnb3QgJHtyZWNpcGllbnRzLmxlbmd0aH1gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBjb25zdCByZWNpcGllbnQgPSByZWNpcGllbnRzWzBdO1xuICAgICAgaWYgKCFyZWNpcGllbnQuYWRkcmVzcyB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhyZWNpcGllbnQuYWRkcmVzcykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcjogcmVjaXBpZW50IGFkZHJlc3MgaXMgbWlzc2luZyBvciBpbnZhbGlkOiAke3JlY2lwaWVudC5hZGRyZXNzfWApO1xuICAgICAgfVxuICAgICAgY29uc3QgYW1vdW50U3RyID0gU3RyaW5nKHJlY2lwaWVudC5hbW91bnQpO1xuICAgICAgaWYgKCFFcmM3OTg0VG9rZW4uaXNQb3NpdGl2ZUludGVnZXJTdHJpbmcoYW1vdW50U3RyKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBhbW91bnQgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIgc3RyaW5nIGluIGJhc2UgdW5pdHMsIGdvdCAnJHthbW91bnRTdHJ9J2BcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIC8vIENyb3NzLWNoZWNrIGFnYWluc3QgYnVpbGRQYXJhbXMgd2hlbiB0aGUgc2VydmVyIGhhcyBhbHJlYWR5IHN0b3JlZCB0aGUgaW50ZW50XG4gICAgICBjb25zdCBidWlsZFBhcmFtc1JlY2lwaWVudCA9IHR4UHJlYnVpbGQ/LmJ1aWxkUGFyYW1zPy5yZWNpcGllbnRzPy5bMF07XG4gICAgICBpZiAoYnVpbGRQYXJhbXNSZWNpcGllbnQ/LmFkZHJlc3MgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAocmVjaXBpZW50LmFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gYnVpbGRQYXJhbXNSZWNpcGllbnQuYWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiByZWNpcGllbnQgYWRkcmVzcyBtaXNtYXRjaCDigJQgYCArXG4gICAgICAgICAgICAgIGB0eFBhcmFtcyBoYXMgJyR7cmVjaXBpZW50LmFkZHJlc3N9JyBidXQgYnVpbGRQYXJhbXMgaGFzICcke2J1aWxkUGFyYW1zUmVjaXBpZW50LmFkZHJlc3N9J2BcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb25zdCBidWlsZFBhcmFtc0Ftb3VudCA9IGJ1aWxkUGFyYW1zUmVjaXBpZW50Py5hbW91bnQ7XG4gICAgICBpZiAoYnVpbGRQYXJhbXNBbW91bnQgIT09IHVuZGVmaW5lZCAmJiBidWlsZFBhcmFtc0Ftb3VudCAhPT0gYW1vdW50U3RyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IGFtb3VudCBtaXNtYXRjaCDigJQgdHhQYXJhbXMgaGFzICcke2Ftb3VudFN0cn0nIGJ1dCBidWlsZFBhcmFtcyBoYXMgJyR7YnVpbGRQYXJhbXNBbW91bnR9J2BcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIFBhcnNlIGFuZCBkZWNvZGUgdGhlIHJhdyB0cmFuc2FjdGlvblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmZyb20odHhQcmVidWlsZC50eEhleCk7XG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCB0eEpzb24gPSB0eC50b0pzb24oKTtcblxuICAgIGxldCB0b0FkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgdG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgZW5jcnlwdGVkSGFuZGxlOiBzdHJpbmc7XG4gICAgbGV0IGlucHV0UHJvb2Y6IHN0cmluZztcblxuICAgIHRyeSB7XG4gICAgICBpZiAodHhKc29uLmRhdGEuc3RhcnRzV2l0aChzZW5kTXVsdGlzaWdNZXRob2RJZCkpIHtcbiAgICAgICAgLy8gc2VuZE11bHRpU2lnLXdyYXBwZWQgcGF0aDogc21hcnQtY29udHJhY3Qgd2FsbGV0IHJlbGF5cyB0aGUgY29uZmlkZW50aWFsVHJhbnNmZXIgY2FsbC5cbiAgICAgICAgLy8gVG9rZW4gY29udHJhY3QgYWRkcmVzcyBpcyBlbmNvZGVkIGluc2lkZSB0aGUgc2VuZE11bHRpU2lnIGNhbGxkYXRhLlxuICAgICAgICBjb25zdCBkZWNvZGVkID0gZGVjb2RlQ29uZmlkZW50aWFsVHJhbnNmZXJEYXRhKHR4SnNvbi5kYXRhKTtcbiAgICAgICAgdG9BZGRyZXNzID0gZGVjb2RlZC50b0FkZHJlc3M7XG4gICAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzID0gZGVjb2RlZC50b2tlbkNvbnRyYWN0QWRkcmVzcztcbiAgICAgICAgZW5jcnlwdGVkSGFuZGxlID0gZGVjb2RlZC5lbmNyeXB0ZWRIYW5kbGU7XG4gICAgICAgIGlucHV0UHJvb2YgPSBkZWNvZGVkLmlucHV0UHJvb2Y7XG4gICAgICB9IGVsc2UgaWYgKHR4SnNvbi5kYXRhLnN0YXJ0c1dpdGgoY29uZmlkZW50aWFsVHJhbnNmZXJXaXRoUHJvb2ZNZXRob2RJZCkpIHtcbiAgICAgICAgLy8gRGlyZWN0IGNhbGwgcGF0aDogaG90L1RTUyBFT0Egd2FsbGV0IGNhbGxzIHRoZSB0b2tlbiBjb250cmFjdCBkaXJlY3RseS5cbiAgICAgICAgLy8gVGhlIHRyYW5zYWN0aW9uJ3MgYHRvYCBmaWVsZCBpcyB0aGUgdG9rZW4gY29udHJhY3QgYWRkcmVzcy5cbiAgICAgICAgaWYgKCF0eEpzb24udG8pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2RpcmVjdCBjb25maWRlbnRpYWxUcmFuc2ZlciBjYWxsIGlzIG1pc3NpbmcgdHJhbnNhY3Rpb24gdG8gYWRkcmVzcycpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVEaXJlY3RDb25maWRlbnRpYWxUcmFuc2ZlckNhbGxkYXRhKHR4SnNvbi5kYXRhKTtcbiAgICAgICAgdG9BZGRyZXNzID0gZGVjb2RlZC50b0FkZHJlc3M7XG4gICAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzID0gdHhKc29uLnRvO1xuICAgICAgICBlbmNyeXB0ZWRIYW5kbGUgPSBkZWNvZGVkLmVuY3J5cHRlZEhhbmRsZTtcbiAgICAgICAgaW5wdXRQcm9vZiA9IGRlY29kZWQuaW5wdXRQcm9vZjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBtZXRob2QgSUQgJHt0eEpzb24uZGF0YS5zbGljZSgwLCAxMCl9YCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IGZhaWxlZCB0byBkZWNvZGUgY29uZmlkZW50aWFsIHRyYW5zZmVyIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gMS4gVG9rZW4gY29udHJhY3QgYWRkcmVzcyBtdXN0IG1hdGNoIHRoaXMgY29pblxuICAgIGlmICh0b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpICE9PSB0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiB0b2tlbiBjb250cmFjdCBhZGRyZXNzIG1pc21hdGNoIOKAlCBgICtcbiAgICAgICAgICBgZXhwZWN0ZWQgJHt0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzfSwgZ290ICR7dG9rZW5Db250cmFjdEFkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyAyLiBSZWNpcGllbnQgYWRkcmVzcyBtdXN0IG1hdGNoIHR4UGFyYW1zLnJlY2lwaWVudHNbMF0gb3IgYnVpbGRQYXJhbXMucmVjaXBpZW50c1swXVxuICAgIGNvbnN0IGV4cGVjdGVkUmVjaXBpZW50ID0gdHhQYXJhbXM/LnJlY2lwaWVudHM/LlswXT8uYWRkcmVzcyA/PyB0eFByZWJ1aWxkLmJ1aWxkUGFyYW1zPy5yZWNpcGllbnRzPy5bMF0/LmFkZHJlc3M7XG4gICAgaWYgKCFleHBlY3RlZFJlY2lwaWVudCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAndmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IG1pc3NpbmcgZXhwZWN0ZWQgcmVjaXBpZW50IChwcm92aWRlIHR4UGFyYW1zLnJlY2lwaWVudHMgb3IgdHhQcmVidWlsZC5idWlsZFBhcmFtcy5yZWNpcGllbnRzKSdcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICh0b0FkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gZXhwZWN0ZWRSZWNpcGllbnQudG9Mb3dlckNhc2UoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IHJlY2lwaWVudCBhZGRyZXNzIG1pc21hdGNoIOKAlCBgICsgYGV4cGVjdGVkICR7ZXhwZWN0ZWRSZWNpcGllbnR9LCBnb3QgJHt0b0FkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyAzLiBlbmNyeXB0ZWRIYW5kbGUgbXVzdCBiZSBhIG5vbi10cml2aWFsIGhleCB2YWx1ZSAobm90IGJhcmUgJzB4JylcbiAgICBpZiAoIWVuY3J5cHRlZEhhbmRsZSB8fCBlbmNyeXB0ZWRIYW5kbGUgPT09ICcweCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IGVuY3J5cHRlZEhhbmRsZSBpcyBtaXNzaW5nIG9yIGVtcHR5IGluIHRyYW5zYWN0aW9uIGNhbGxkYXRhJyk7XG4gICAgfVxuXG4gICAgLy8gNC4gaW5wdXRQcm9vZiBtdXN0IGJlIGEgbm9uLXRyaXZpYWwgaGV4IHZhbHVlXG4gICAgaWYgKCFpbnB1dFByb29mIHx8IGlucHV0UHJvb2YgPT09ICcweCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IGlucHV0UHJvb2YgaXMgbWlzc2luZyBvciBlbXB0eSBpbiB0cmFuc2FjdGlvbiBjYWxsZGF0YScpO1xuICAgIH1cblxuICAgIC8vIDUuIFZlcmlmeSBwbGFpbnRleHQgaW50ZW50OiB0eFBhcmFtcyBhbW91bnQgbXVzdCBiZSB2YWxpZCBhbmQgY29uc2lzdGVudCB3aXRoIGJ1aWxkUGFyYW1zXG4gICAgY29uc3QgcmF3VHhQYXJhbXNBbW91bnQgPSB0eFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdPy5hbW91bnQ7XG4gICAgaWYgKHJhd1R4UGFyYW1zQW1vdW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHR4UGFyYW1zQW1vdW50ID0gU3RyaW5nKHJhd1R4UGFyYW1zQW1vdW50KTtcbiAgICAgIGlmICghRXJjNzk4NFRva2VuLmlzUG9zaXRpdmVJbnRlZ2VyU3RyaW5nKHR4UGFyYW1zQW1vdW50KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBhbW91bnQgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIgc3RyaW5nIGluIGJhc2UgdW5pdHMsIGdvdCAnJHt0eFBhcmFtc0Ftb3VudH0nYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3QgYnVpbGRQYXJhbXNBbW91bnQgPSB0eFByZWJ1aWxkLmJ1aWxkUGFyYW1zPy5yZWNpcGllbnRzPy5bMF0/LmFtb3VudDtcbiAgICAgIGlmIChidWlsZFBhcmFtc0Ftb3VudCAhPT0gdW5kZWZpbmVkICYmIHR4UGFyYW1zQW1vdW50ICE9PSBidWlsZFBhcmFtc0Ftb3VudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBhbW91bnQgbWlzbWF0Y2gg4oCUIHR4UGFyYW1zIGhhcyAnJHt0eFBhcmFtc0Ftb3VudH0nIGJ1dCBidWlsZFBhcmFtcyBoYXMgJyR7YnVpbGRQYXJhbXNBbW91bnR9J2BcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGlzUG9zaXRpdmVJbnRlZ2VyU3RyaW5nKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gL15cXGQrJC8udGVzdCh2YWx1ZSkgJiYgQmlnSW50KHZhbHVlKSA+IDBuO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIGEgdG9rZW4gZW5hYmxlbWVudCB0cmFuc2FjdGlvbiBmb3IgRVJDLTc5ODQgZGVjcnlwdGlvbiBkZWxlZ2F0aW9uLlxuICAgKlxuICAgKiBUU1MgcGF0aDogZGVjb2RlcyB0aGUgcmF3IHR4IGFuZCB2ZXJpZmllcyBpdCBjYWxscyB0aGUgQUNMIGNvbnRyYWN0IHdpdGhcbiAgICogY2FsbGRhdGEgdGhhdCBjb3ZlcnMgYWxsIHJlcXVlc3RlZCB0b2tlbiBjb250cmFjdCBhZGRyZXNzZXMuXG4gICAqXG4gICAqIE11bHRpc2lnIHBhdGg6IHZlcmlmaWVzIHRoZSBidWlsZFBhcmFtcyByZWNpcGllbnRzIGNhcnJ5IHRoZSBjb3JyZWN0IHRva2VuTmFtZXNcbiAgICogYW5kIHplcm8gYW1vdW50cy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldFR5cGUgfSA9IHBhcmFtcztcblxuICAgIGlmICh3YWxsZXRUeXBlID09PSAndHNzJykge1xuICAgICAgLy8gVFNTIHBhdGg6IGZ1bGwgcmF3LXR4IGRlY29kZVxuICAgICAgY29uc3QgZW5hYmxlVG9rZW5zID0gdHhQYXJhbXMuZW5hYmxlVG9rZW5zO1xuICAgICAgaWYgKCFlbmFibGVUb2tlbnMgfHwgZW5hYmxlVG9rZW5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IGVuYWJsZVRva2VucyBtdXN0IGJlIG5vbi1lbXB0eSBmb3IgVFNTIHBhdGgnKTtcbiAgICAgIH1cbiAgICAgIGlmICghdHhQcmVidWlsZC50eEhleCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IG1pc3NpbmcgdHhIZXggaW4gdHhQcmVidWlsZCcpO1xuICAgICAgfVxuXG4gICAgICAvLyBSZXNvbHZlIHJlcXVlc3RlZCB0b2tlbiBuYW1lcyDihpIgY29udHJhY3QgYWRkcmVzc2VzXG4gICAgICBjb25zdCByZXF1ZXN0ZWRBZGRyZXNzZXMgPSBlbmFibGVUb2tlbnMubWFwKCh0KSA9PiB7XG4gICAgICAgIGNvbnN0IHRva2VuQ29pbiA9IHRoaXMuYml0Z28uY29pbih0Lm5hbWUpIGFzIEVyYzc5ODRUb2tlbjtcbiAgICAgICAgcmV0dXJuIHRva2VuQ29pbi50b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIFBhcnNlIHRoZSByYXcgdHJhbnNhY3Rpb25cbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgICB0eEJ1aWxkZXIuZnJvbSh0eFByZWJ1aWxkLnR4SGV4KTtcbiAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCB0eEpzb24gPSB0eC50b0pzb24oKTtcblxuICAgICAgLy8gVmVyaWZ5IHRyYW5zYWN0aW9uIHRhcmdldHMgdGhlIGNvcnJlY3QgY29udHJhY3QgYmFzZWQgb24gY2FsbGRhdGEgc2hhcGVcbiAgICAgIGNvbnN0IG5ldHdvcmsgPSB0aGlzLmdldE5ldHdvcmsoKSBhcyBFdGhlcmV1bU5ldHdvcms7XG4gICAgICBjb25zdCBhY2xDb250cmFjdEFkZHJlc3MgPSBuZXR3b3JrPy56YW1hQWNsQ29udHJhY3RBZGRyZXNzO1xuICAgICAgaWYgKCFhY2xDb250cmFjdEFkZHJlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlFbmFibGVUb2tlblRyYW5zYWN0aW9uOiB6YW1hQWNsQ29udHJhY3RBZGRyZXNzIG5vdCBjb25maWd1cmVkIGZvciB0aGlzIG5ldHdvcmsnKTtcbiAgICAgIH1cbiAgICAgIGlmICghdHhKc29uLnRvKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogdHJhbnNhY3Rpb24gaXMgbWlzc2luZyByZWNpcGllbnQgYWRkcmVzcycpO1xuICAgICAgfVxuXG4gICAgICAvLyBJbnNwZWN0IGNhbGxkYXRhIG1ldGhvZCBJRCB0byBkaXN0aW5ndWlzaCByb290IHdhbGxldCBmcm9tIGZvcndhcmRlciB3YWxsZXQ6XG4gICAgICAvLyAgIGFjbE11bHRpY2FsbE1ldGhvZElkICAg4oaSIHJvb3Qgd2FsbGV0OiB0byA9IEFDTCBjb250cmFjdCBkaXJlY3RseVxuICAgICAgLy8gICBjYWxsRnJvbVBhcmVudE1ldGhvZElkIOKGkiBmb3J3YXJkZXIgd2FsbGV0OiB0byA9IGZvcndhcmRlciwgQUNMIGFkZHJlc3MgaXMgaW5zaWRlIGNhbGxkYXRhXG4gICAgICBjb25zdCBjYWxsZGF0YU1ldGhvZElkID0gdHhKc29uLmRhdGEuc2xpY2UoMCwgMTApO1xuICAgICAgaWYgKGNhbGxkYXRhTWV0aG9kSWQgPT09IGFjbE11bHRpY2FsbE1ldGhvZElkKSB7XG4gICAgICAgIC8vIFJvb3Qgd2FsbGV0IChiYXNlIGFkZHJlc3MpOiB0eCBjYWxscyB0aGUgQUNMIGNvbnRyYWN0IGRpcmVjdGx5XG4gICAgICAgIGlmICh0eEpzb24udG8udG9Mb3dlckNhc2UoKSAhPT0gYWNsQ29udHJhY3RBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgdmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogdHJhbnNhY3Rpb24gdGFyZ2V0ICR7dHhKc29uLnRvfSBkb2VzIG5vdCBtYXRjaCBBQ0wgY29udHJhY3QgJHthY2xDb250cmFjdEFkZHJlc3N9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoY2FsbGRhdGFNZXRob2RJZCA9PT0gY2FsbEZyb21QYXJlbnRNZXRob2RJZCkge1xuICAgICAgICAvLyBGb3J3YXJkZXIgd2FsbGV0OiB0eCBjYWxscyB0aGUgZm9yd2FyZGVyLCB3aGljaCBjYWxscyB0aGUgQUNMIHZpYSBjYWxsRnJvbVBhcmVudC5cbiAgICAgICAgLy8gVGhlIGZvcndhcmRlciBhZGRyZXNzIGlzIHdhbGxldC1zcGVjaWZpYyBhbmQgY2Fubm90IGJlIHN0YXRpY2FsbHkgdmVyaWZpZWQgaGVyZTtcbiAgICAgICAgLy8gdG9rZW4gYWRkcmVzcyBjb3JyZWN0bmVzcyBpcyBzdGlsbCB2ZXJpZmllZCBiZWxvdyB2aWEgY2FsbGRhdGEgZGVjb2RpbmcuXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IHVucmVjb2duaXNlZCBjYWxsZGF0YSBtZXRob2QgSUQgJHtjYWxsZGF0YU1ldGhvZElkfTsgZXhwZWN0ZWQgbXVsdGljYWxsIG9yIGNhbGxGcm9tUGFyZW50YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBWZXJpZnkgdmFsdWUgaXMgMFxuICAgICAgaWYgKHR4SnNvbi52YWx1ZSAhPT0gJzAnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogZXhwZWN0ZWQgdHJhbnNhY3Rpb24gdmFsdWUgMCBidXQgZ290ICR7dHhKc29uLnZhbHVlfWApO1xuICAgICAgfVxuXG4gICAgICAvLyBEZWNvZGUgdG9rZW4gYWRkcmVzc2VzIGZyb20gY2FsbGRhdGEgYW5kIHZlcmlmeSBhbGwgcmVxdWVzdGVkIHRva2VucyBhcmUgcHJlc2VudFxuICAgICAgY29uc3QgZGVjb2RlZEFkZHJlc3NlcyA9IGRlY29kZVRva2VuQWRkcmVzc2VzRnJvbURlbGVnYXRpb25DYWxsZGF0YSh0eEpzb24uZGF0YSk7XG4gICAgICBmb3IgKGNvbnN0IHJlcXVlc3RlZCBvZiByZXF1ZXN0ZWRBZGRyZXNzZXMpIHtcbiAgICAgICAgaWYgKCFkZWNvZGVkQWRkcmVzc2VzLmluY2x1ZGVzKHJlcXVlc3RlZCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgdmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogcmVxdWVzdGVkIHRva2VuICR7cmVxdWVzdGVkfSBub3QgZm91bmQgaW4gZGVsZWdhdGlvbiBjYWxsZGF0YWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBNdWx0aXNpZyBwYXRoOiBidWlsZFBhcmFtcy1sZXZlbCBjaGVja1xuICAgICAgY29uc3QgcmVjaXBpZW50cyA9IHR4UHJlYnVpbGQuYnVpbGRQYXJhbXM/LnJlY2lwaWVudHMgYXNcbiAgICAgICAgfCBBcnJheTx7IHRva2VuTmFtZT86IHN0cmluZzsgYW1vdW50Pzogc3RyaW5nIH0+XG4gICAgICAgIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKCFyZWNpcGllbnRzIHx8IHJlY2lwaWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogbWlzc2luZyBidWlsZFBhcmFtcy5yZWNpcGllbnRzIGZvciBtdWx0aXNpZyBwYXRoJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIERldGVybWluZSByZXF1ZXN0ZWQgdG9rZW4gbmFtZXMgZnJvbSB0eFBhcmFtc1xuICAgICAgY29uc3QgcmVxdWVzdGVkVG9rZW5OYW1lczogc3RyaW5nW10gPSBbXTtcbiAgICAgIGlmICh0eFBhcmFtcy5lbmFibGVUb2tlbnMgJiYgdHhQYXJhbXMuZW5hYmxlVG9rZW5zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmVxdWVzdGVkVG9rZW5OYW1lcy5wdXNoKC4uLnR4UGFyYW1zLmVuYWJsZVRva2Vucy5tYXAoKHQpID0+IHQubmFtZSkpO1xuICAgICAgfSBlbHNlIGlmICh0eFBhcmFtcy5yZWNpcGllbnRzICYmIHR4UGFyYW1zLnJlY2lwaWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICByZXF1ZXN0ZWRUb2tlbk5hbWVzLnB1c2goLi4udHhQYXJhbXMucmVjaXBpZW50cy5tYXAoKHI6IGFueSkgPT4gci50b2tlbk5hbWUpLmZpbHRlcihCb29sZWFuKSk7XG4gICAgICB9XG5cbiAgICAgIC8vIFZlcmlmeSBhbGwgcmVjaXBpZW50cyBoYXZlIHRva2VuTmFtZSBhbmQgYW1vdW50ID0gJzAnXG4gICAgICBmb3IgKGNvbnN0IHJlY2lwaWVudCBvZiByZWNpcGllbnRzKSB7XG4gICAgICAgIGlmICghcmVjaXBpZW50LnRva2VuTmFtZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogcmVjaXBpZW50IGlzIG1pc3NpbmcgdG9rZW5OYW1lIGluIGJ1aWxkUGFyYW1zJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlY2lwaWVudC5hbW91bnQgIT09ICcwJykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGB2ZXJpZnlFbmFibGVUb2tlblRyYW5zYWN0aW9uOiBleHBlY3RlZCBhbW91bnQgMCBmb3IgdG9rZW4gZW5hYmxlbWVudCBidXQgZ290ICR7cmVjaXBpZW50LmFtb3VudH1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBWZXJpZnkgcmVxdWVzdGVkIHRva2VuIG5hbWVzIGFyZSBwcmVzZW50IGluIHJlY2lwaWVudHNcbiAgICAgIGlmIChyZXF1ZXN0ZWRUb2tlbk5hbWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgcmVjaXBpZW50VG9rZW5OYW1lcyA9IHJlY2lwaWVudHMubWFwKChyKSA9PiByLnRva2VuTmFtZSk7XG4gICAgICAgIGZvciAoY29uc3QgcmVxdWVzdGVkIG9mIHJlcXVlc3RlZFRva2VuTmFtZXMpIHtcbiAgICAgICAgICBpZiAoIXJlY2lwaWVudFRva2VuTmFtZXMuaW5jbHVkZXMocmVxdWVzdGVkKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICBgdmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogcmVxdWVzdGVkIHRva2VuICR7cmVxdWVzdGVkfSBub3QgZm91bmQgaW4gYnVpbGRQYXJhbXMgcmVjaXBpZW50c2BcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBPdmVycmlkZSBnYXMgbGltaXQgZm9yIEVSQy03OTg0IGNvbmZpZGVudGlhbCB0b2tlbiByZWNvdmVyeS5cbiAgICogQWN0dWFsIG9uLWNoYWluIHVzYWdlIGlzIH41MDYtNTMwayBnYXMgYmFzZWQgb24gdGVzdG5ldCByZXN1bHRzLlxuICAgKiBEZWZhdWx0OiA4MDAsMDAwIChjb21mb3J0YWJsZSBidWZmZXIgb3ZlciBvYnNlcnZlZCB1c2FnZSkuXG4gICAqL1xuICBzZXRHYXNMaW1pdCh1c2VyR2FzTGltaXQ/OiBudW1iZXIpOiBudW1iZXIge1xuICAgIGlmICghdXNlckdhc0xpbWl0KSB7XG4gICAgICByZXR1cm4gODAwMDAwO1xuICAgIH1cbiAgICByZXR1cm4gc3VwZXIuc2V0R2FzTGltaXQodXNlckdhc0xpbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyaWVzIHRoZSBlbmNyeXB0ZWQgYmFsYW5jZSBoYW5kbGUgZm9yIGEgd2FsbGV0IGFkZHJlc3MgdmlhIGV0aF9jYWxsIHRvIHRoZVxuICAgKiB0b2tlbiBjb250cmFjdCdzIGNvbmZpZGVudGlhbEJhbGFuY2VPZihhZGRyZXNzKSBmdW5jdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHdhbGxldEFkZHJlc3MgLSB0aGUgd2FsbGV0IGNvbnRyYWN0IGFkZHJlc3MgdG8gcXVlcnkgYmFsYW5jZSBmb3JcbiAgICogQHBhcmFtIGFwaUtleSAtIG9wdGlvbmFsIEV0aGVyc2NhbiBBUEkga2V5XG4gICAqIEByZXR1cm5zIGJ5dGVzMzIgZW5jcnlwdGVkIGhhbmRsZSAoMHgtcHJlZml4ZWQsIDY2IGNoYXJzKS5cbiAgICogICBOb3RlOiBoYW5kbGVzIGFyZSBhbHdheXMgbm9uLXplcm8gZXZlbiBmb3IgemVybyBiYWxhbmNlcyAoZW5jcnlwdGVkIGRvbWFpbikuXG4gICAqL1xuICBhc3luYyBxdWVyeUNvbmZpZGVudGlhbEJhbGFuY2Uod2FsbGV0QWRkcmVzczogc3RyaW5nLCBhcGlLZXk/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IG1ldGhvZFNpZ25hdHVyZSA9IG9wdGlvbmFsRGVwcy5ldGhBYmkubWV0aG9kSUQoJ2NvbmZpZGVudGlhbEJhbGFuY2VPZicsIFsnYWRkcmVzcyddKTtcbiAgICBjb25zdCBlbmNvZGVkQXJncyA9IG9wdGlvbmFsRGVwcy5ldGhBYmkucmF3RW5jb2RlKFsnYWRkcmVzcyddLCBbd2FsbGV0QWRkcmVzc10pO1xuICAgIGNvbnN0IGNhbGxkYXRhID0gQnVmZmVyLmNvbmNhdChbbWV0aG9kU2lnbmF0dXJlLCBlbmNvZGVkQXJnc10pLnRvU3RyaW5nKCdoZXgnKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeShcbiAgICAgIHtcbiAgICAgICAgY2hhaW5pZDogdGhpcy5nZXRDaGFpbklkKCkudG9TdHJpbmcoKSxcbiAgICAgICAgbW9kdWxlOiAncHJveHknLFxuICAgICAgICBhY3Rpb246ICdldGhfY2FsbCcsXG4gICAgICAgIHRvOiB0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzLFxuICAgICAgICBkYXRhOiBjYWxsZGF0YSxcbiAgICAgICAgdGFnOiAnbGF0ZXN0JyxcbiAgICAgIH0sXG4gICAgICBhcGlLZXlcbiAgICApO1xuXG4gICAgaWYgKCFyZXN1bHQgfHwgIXJlc3VsdC5yZXN1bHQpIHtcbiAgICAgIHRocm93IG5ldyBSZWNvdmVyeVByb3ZpZGVyRXJyb3IoXG4gICAgICAgIGBDb3VsZCBub3Qgb2J0YWluIGNvbmZpZGVudGlhbCBiYWxhbmNlIGZvciAke3dhbGxldEFkZHJlc3N9IGZyb20gdG9rZW4gJHt0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgaGFuZGxlID0gcmVzdWx0LnJlc3VsdCBhcyBzdHJpbmc7XG4gICAgaWYgKCFoYW5kbGUuc3RhcnRzV2l0aCgnMHgnKSB8fCBoYW5kbGUubGVuZ3RoICE9PSA2Nikge1xuICAgICAgdGhyb3cgbmV3IFJlY292ZXJ5UHJvdmlkZXJFcnJvcihgVW5leHBlY3RlZCBjb25maWRlbnRpYWxCYWxhbmNlT2YgcmVzcG9uc2UgZm9ybWF0OiAke2hhbmRsZX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaGFuZGxlO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIG5vbi1CaXRHbyByZWNvdmVyeSB0cmFuc2FjdGlvbiBmb3IgRVJDLTc5ODQgY29uZmlkZW50aWFsIHRva2Vucy5cbiAgICpcbiAgICogVXNlcyB0aGUgbm8tcHJvb2YgaGFuZGxlIHN3ZWVwOiBjb25maWRlbnRpYWxUcmFuc2ZlcihyZWNpcGllbnQsIGhhbmRsZSkgd2l0aCAyIGFyZ3MuXG4gICAqIE5vIEZIRSBkZWNyeXB0aW9uIG9yIHByb29mIGdlbmVyYXRpb24gaXMgbmVlZGVkIOKAlCB0aGUgd2FsbGV0IHRyYW5zZmVycyBpdHMgZW50aXJlXG4gICAqIGVuY3J5cHRlZCBiYWxhbmNlIGhhbmRsZSB3aXRob3V0IGtub3dpbmcgdGhlIHBsYWludGV4dCBhbW91bnQuXG4gICAqXG4gICAqIFRoZSBvdXRlciB0cmFuc2FjdGlvbiBzaGFwZSBpczpcbiAgICogICB0eC50byAgID0gd2FsbGV0Q29udHJhY3RBZGRyZXNzXG4gICAqICAgdHguZGF0YSA9IHNlbmRNdWx0aVNpZyh0b2tlbkNvbnRyYWN0QWRkciwgMCwgY29uZmlkZW50aWFsVHJhbnNmZXIocmVjb3ZlcnlEZXN0LCBoYW5kbGUpLCAuLi4pXG4gICAqL1xuICBhc3luYyByZWNvdmVyKHBhcmFtczogUmVjb3Zlck9wdGlvbnMpOiBQcm9taXNlPFJlY292ZXJ5SW5mbyB8IE9mZmxpbmVWYXVsdFR4SW5mbz4ge1xuICAgIGlmIChwYXJhbXMuaXNUc3MgPT09IHRydWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRVJDLTc5ODQgVFNTIHJlY292ZXJ5IGlzIG5vdCB5ZXQgc3VwcG9ydGVkJyk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLnVzZXJLZXkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdXNlcktleScpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy5iYWNrdXBLZXkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgYmFja3VwS2V5Jyk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLndhbGxldFBhc3NwaHJhc2UpICYmICFwYXJhbXMudXNlcktleS5zdGFydHNXaXRoKCd4cHViJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyB3YWxsZXQgcGFzc3BocmFzZScpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MpIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgd2FsbGV0Q29udHJhY3RBZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHJlY292ZXJ5RGVzdGluYXRpb24nKTtcbiAgICB9XG5cbiAgICBjb25zdCBpc0tyc1JlY292ZXJ5ID0gZ2V0SXNLcnNSZWNvdmVyeShwYXJhbXMpO1xuICAgIGNvbnN0IGlzVW5zaWduZWRTd2VlcCA9IHBhcmFtcy5pc1Vuc2lnbmVkU3dlZXAgPz8gZ2V0SXNVbnNpZ25lZFN3ZWVwKHBhcmFtcyk7XG5cbiAgICBpZiAoaXNLcnNSZWNvdmVyeSkge1xuICAgICAgY2hlY2tLcnNQcm92aWRlcih0aGlzLCBwYXJhbXMua3JzUHJvdmlkZXIsIHsgY2hlY2tDb2luRmFtaWx5U3VwcG9ydDogZmFsc2UgfSk7XG4gICAgfVxuXG4gICAgbGV0IHVzZXJLZXkgPSBwYXJhbXMudXNlcktleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuICAgIGNvbnN0IGJhY2t1cEtleSA9IHBhcmFtcy5iYWNrdXBLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcblxuICAgIGNvbnN0IGdhc1ByaWNlID0gcGFyYW1zLmVpcDE1NTlcbiAgICAgID8gbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHBhcmFtcy5laXAxNTU5Lm1heEZlZVBlckdhcylcbiAgICAgIDogbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHRoaXMuc2V0R2FzUHJpY2UocGFyYW1zLmdhc1ByaWNlKSk7XG4gICAgY29uc3QgZ2FzTGltaXQgPSBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4odGhpcy5zZXRHYXNMaW1pdChwYXJhbXMuZ2FzTGltaXQpKTtcblxuICAgIC8vIERlY3J5cHQgcHJpdmF0ZSBrZXlzIGZyb20gS2V5Q2FyZCB2YWx1ZXNcbiAgICBpZiAoIXVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpICYmICF1c2VyS2V5LnN0YXJ0c1dpdGgoJ3hwcnYnKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdXNlcktleSA9IGF3YWl0IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgICAgaW5wdXQ6IHVzZXJLZXksXG4gICAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIHVzZXIga2V5Y2hhaW46ICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgbGV0IGJhY2t1cEtleUFkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgYmFja3VwU2lnbmluZ0tleTogQnVmZmVyO1xuXG4gICAgaWYgKGlzS3JzUmVjb3ZlcnkgfHwgaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICBjb25zdCBiYWNrdXBIRE5vZGUgPSBiaXAzMi5mcm9tQmFzZTU4KGJhY2t1cEtleSk7XG4gICAgICBiYWNrdXBTaWduaW5nS2V5ID0gYmFja3VwSEROb2RlLnB1YmxpY0tleTtcbiAgICAgIGJhY2t1cEtleUFkZHJlc3MgPSBgMHgke29wdGlvbmFsRGVwcy5ldGhVdGlsLnB1YmxpY1RvQWRkcmVzcyhiYWNrdXBTaWduaW5nS2V5LCB0cnVlKS50b1N0cmluZygnaGV4Jyl9YDtcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IGJhY2t1cFBydjogc3RyaW5nO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYmFja3VwUHJ2ID0gYXdhaXQgdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgICBpbnB1dDogYmFja3VwS2V5LFxuICAgICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyBiYWNrdXAga2V5Y2hhaW46ICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGJhY2t1cEhETm9kZSA9IGJpcDMyLmZyb21CYXNlNTgoYmFja3VwUHJ2KTtcbiAgICAgIGJhY2t1cFNpZ25pbmdLZXkgPSBiYWNrdXBIRE5vZGUucHJpdmF0ZUtleSBhcyBCdWZmZXI7XG4gICAgICBiYWNrdXBLZXlBZGRyZXNzID0gYDB4JHtvcHRpb25hbERlcHMuZXRoVXRpbC5wcml2YXRlVG9BZGRyZXNzKGJhY2t1cFNpZ25pbmdLZXkpLnRvU3RyaW5nKCdoZXgnKX1gO1xuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuYXNzZXJ0UmVjb3ZlcnlLZXlzQXJlV2FsbGV0U2lnbmVycyhcbiAgICAgIHVzZXJLZXksXG4gICAgICBiYWNrdXBLZXlBZGRyZXNzLFxuICAgICAgcGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcyxcbiAgICAgIHBhcmFtcy5hcGlLZXlcbiAgICApO1xuXG4gICAgY29uc3QgYmFja3VwS2V5Tm9uY2UgPSBhd2FpdCB0aGlzLmdldEFkZHJlc3NOb25jZShiYWNrdXBLZXlBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcblxuICAgIGNvbnN0IGJhY2t1cEtleUJhbGFuY2UgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2UoYmFja3VwS2V5QWRkcmVzcywgcGFyYW1zLmFwaUtleSk7XG4gICAgY29uc3QgdG90YWxHYXNOZWVkZWQgPSBnYXNQcmljZS5tdWwoZ2FzTGltaXQpO1xuICAgIGNvbnN0IHdlaVRvR3dlaSA9IDEwICoqIDk7XG4gICAgaWYgKGJhY2t1cEtleUJhbGFuY2UubHQodG90YWxHYXNOZWVkZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBCYWNrdXAga2V5IGFkZHJlc3MgJHtiYWNrdXBLZXlBZGRyZXNzfSBoYXMgYmFsYW5jZSAkeyhiYWNrdXBLZXlCYWxhbmNlIC8gd2VpVG9Hd2VpKS50b1N0cmluZygpfSBHd2VpLmAgK1xuICAgICAgICAgIGBUaGlzIGFkZHJlc3MgbXVzdCBoYXZlIGEgYmFsYW5jZSBvZiBhdCBsZWFzdCAkeyh0b3RhbEdhc05lZWRlZCAvIHdlaVRvR3dlaSkudG9TdHJpbmcoKX1gICtcbiAgICAgICAgICBgIEd3ZWkgdG8gcGVyZm9ybSByZWNvdmVyaWVzLiBUcnkgc2VuZGluZyBzb21lIEVUSCB0byB0aGlzIGFkZHJlc3MgdGhlbiByZXRyeS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEdldCB0aGUgZW5jcnlwdGVkIGJhbGFuY2UgaGFuZGxlIChhdXRvLXF1ZXJ5IG9yIHVzZXItcHJvdmlkZWQpXG4gICAgbGV0IGVuY3J5cHRlZEhhbmRsZTogc3RyaW5nO1xuICAgIGlmIChwYXJhbXMuZW5jcnlwdGVkSGFuZGxlKSB7XG4gICAgICBlbmNyeXB0ZWRIYW5kbGUgPSBwYXJhbXMuZW5jcnlwdGVkSGFuZGxlO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwKSk7XG4gICAgICBlbmNyeXB0ZWRIYW5kbGUgPSBhd2FpdCB0aGlzLnF1ZXJ5Q29uZmlkZW50aWFsQmFsYW5jZShwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcbiAgICB9XG5cbiAgICAvLyBOb3RlOiBlbmNyeXB0ZWQgaGFuZGxlcyBhcmUgYWx3YXlzIG5vbi16ZXJvIGV2ZW4gZm9yIHplcm8gYmFsYW5jZXMgKGVuY3J5cHRlZCBkb21haW4pLlxuICAgIC8vIFRoZSB0cmFuc2ZlciB3aWxsIGV4ZWN1dGUgYnV0IG1vdmUgMCB0b2tlbnMgaWYgdGhlIHdhbGxldCBpcyBlbXB0eS5cblxuICAgIC8vIEJ1aWxkIHRoZSBpbm5lciBjYWxsZGF0YTogY29uZmlkZW50aWFsVHJhbnNmZXIocmVjb3ZlcnlEZXN0aW5hdGlvbiwgaGFuZGxlKVxuICAgIGNvbnN0IGlubmVyQ2FsbGRhdGEgPSBidWlsZENvbmZpZGVudGlhbFRyYW5zZmVyQnlIYW5kbGVDYWxsZGF0YShwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbiwgZW5jcnlwdGVkSGFuZGxlKTtcblxuICAgIC8vIEZvciBzZW5kTXVsdGlTaWc6IHJlY2lwaWVudCBpcyB0aGUgdG9rZW4gY29udHJhY3QsIGFtb3VudCBpcyAwLCBkYXRhIGNhcnJpZXMgdGhlIGNvbmZpZGVudGlhbFRyYW5zZmVyIGNhbGxkYXRhXG4gICAgY29uc3QgcmVjaXBpZW50cyA9IFtcbiAgICAgIHtcbiAgICAgICAgYWRkcmVzczogdGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgYW1vdW50OiAnMCcsXG4gICAgICAgIGRhdGE6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnN0cmlwSGV4UHJlZml4KGlubmVyQ2FsbGRhdGEpLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgMTAwMCkpO1xuICAgIGNvbnN0IHNlcXVlbmNlSWQgPSBhd2FpdCB0aGlzLnF1ZXJ5U2VxdWVuY2VJZChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcblxuICAgIGxldCBvcGVyYXRpb25IYXNoOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgbGV0IHNpZ25hdHVyZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGlmICghaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICBvcGVyYXRpb25IYXNoID0gdGhpcy5nZXRPcGVyYXRpb25TaGEzRm9yRXhlY3V0ZUFuZENvbmZpcm0ocmVjaXBpZW50cywgdGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpLCBzZXF1ZW5jZUlkKTtcbiAgICAgIHNpZ25hdHVyZSA9IFV0aWwuZXRoU2lnbk1zZ0hhc2gob3BlcmF0aW9uSGFzaCwgVXRpbC54cHJ2VG9FdGhQcml2YXRlS2V5KHVzZXJLZXkpKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgVXRpbC5lY1JlY292ZXJFdGhBZGRyZXNzKG9wZXJhdGlvbkhhc2gsIHNpZ25hdHVyZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzaWduYXR1cmUnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB0eEluZm8gPSB7XG4gICAgICByZWNpcGllbnQ6IHJlY2lwaWVudHNbMF0sXG4gICAgICBleHBpcmVUaW1lOiB0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCksXG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IHNlcXVlbmNlSWQsXG4gICAgICBvcGVyYXRpb25IYXNoOiBvcGVyYXRpb25IYXNoLFxuICAgICAgc2lnbmF0dXJlOiBzaWduYXR1cmUgPz8gJycsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoMTApLFxuICAgIH07XG5cbiAgICBjb25zdCBzZW5kTWV0aG9kQXJncyA9IHRoaXMuZ2V0U2VuZE1ldGhvZEFyZ3ModHhJbmZvKTtcbiAgICBjb25zdCBtZXRob2RTaWduYXR1cmUgPSBvcHRpb25hbERlcHMuZXRoQWJpLm1ldGhvZElEKHRoaXMuc2VuZE1ldGhvZE5hbWUsIF8ubWFwKHNlbmRNZXRob2RBcmdzLCAndHlwZScpKTtcbiAgICBjb25zdCBlbmNvZGVkQXJncyA9IG9wdGlvbmFsRGVwcy5ldGhBYmkucmF3RW5jb2RlKF8ubWFwKHNlbmRNZXRob2RBcmdzLCAndHlwZScpLCBfLm1hcChzZW5kTWV0aG9kQXJncywgJ3ZhbHVlJykpO1xuICAgIGNvbnN0IHNlbmREYXRhID0gQnVmZmVyLmNvbmNhdChbbWV0aG9kU2lnbmF0dXJlLCBlbmNvZGVkQXJnc10pO1xuXG4gICAgbGV0IHR4ID0gRXRoLmJ1aWxkVHJhbnNhY3Rpb24oe1xuICAgICAgdG86IHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICBub25jZTogYmFja3VwS2V5Tm9uY2UsXG4gICAgICB2YWx1ZTogMCxcbiAgICAgIGdhc1ByaWNlOiBnYXNQcmljZSxcbiAgICAgIGdhc0xpbWl0OiBnYXNMaW1pdCxcbiAgICAgIGRhdGE6IHNlbmREYXRhLFxuICAgICAgZWlwMTU1OTogcGFyYW1zLmVpcDE1NTksXG4gICAgICByZXBsYXlQcm90ZWN0aW9uT3B0aW9uczogcGFyYW1zLnJlcGxheVByb3RlY3Rpb25PcHRpb25zLFxuICAgIH0pO1xuXG4gICAgaWYgKGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgcmV0dXJuIHRoaXMuZm9ybWF0Rm9yT2ZmbGluZVZhdWx0KFxuICAgICAgICB0eEluZm8sXG4gICAgICAgIHR4LFxuICAgICAgICB1c2VyS2V5LFxuICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgIGdhc1ByaWNlLFxuICAgICAgICBnYXNMaW1pdCxcbiAgICAgICAgcGFyYW1zLmVpcDE1NTksXG4gICAgICAgIHBhcmFtcy5yZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyxcbiAgICAgICAgcGFyYW1zLmFwaUtleVxuICAgICAgKSBhcyBhbnk7XG4gICAgfVxuXG4gICAgaWYgKCFpc0tyc1JlY292ZXJ5KSB7XG4gICAgICB0eCA9IHR4LnNpZ24oYmFja3VwU2lnbmluZ0tleSk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2lnbmVkVHg6IFJlY292ZXJ5SW5mbyA9IHtcbiAgICAgIGlkOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleCh0eC5oYXNoKCkpLFxuICAgICAgdHg6IHR4LnNlcmlhbGl6ZSgpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICB9O1xuXG4gICAgaWYgKGlzS3JzUmVjb3ZlcnkpIHtcbiAgICAgIHNpZ25lZFR4LmJhY2t1cEtleSA9IGJhY2t1cEtleTtcbiAgICAgIHNpZ25lZFR4LmNvaW4gPSB0aGlzLmdldENoYWluKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNpZ25lZFR4O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBEZWNyeXB0aW9uRGVsZWdhdGlvbkJ1aWxkZXIgZm9yIGNvbnN0cnVjdGluZyBaYW1hIEFDTCBkZWNyeXB0aW9uXG4gICAqIGRlbGVnYXRpb24gdHJhbnNhY3Rpb25zLlxuICAgKlxuICAgKiBUaGUgYnVpbGRlciBwcm9kdWNlcyBhIERlY3J5cHRpb25EZWxlZ2F0aW9uVHhSZXF1ZXN0IHt0bywgZGF0YSwgdmFsdWV9IHRoYXQgaXNcbiAgICogd2FsbGV0LXR5cGUtYWdub3N0aWMg4oCUIFdQIHJvdXRlcyBpdCB0byB0aGUgY29ycmVjdCBzaWduaW5nIHBhdGg6XG4gICAqIC0gTVBDOiBzdWJtaXQgYXMgYSByYXcgVFNTIHRyYW5zYWN0aW9uXG4gICAqIC0gTXVsdGlzaWc6IHdyYXAgaW4gc2VuZE11bHRpU2lnKHdhbGxldENvbnRyYWN0LCB0bywgMCwgZGF0YSwgLi4uKVxuICAgKlxuICAgKiBFeGFtcGxlOlxuICAgKiAgIGNvbnN0IHJlcSA9IGNvaW4uZ2V0RGVjcnlwdGlvbkRlbGVnYXRpb25CdWlsZGVyKCkuYnVpbGQoe1xuICAgKiAgICAgYWNsQ29udHJhY3RBZGRyZXNzOiAnMHhmMEZmLi4uJyxcbiAgICogICAgIGRlbGVnYXRlQWRkcmVzczogICAgZW50ZXJwcmlzZVZpZXdpbmdLZXksXG4gICAqICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzc2VzOiBbdG9rZW5BZGRyZXNzXSxcbiAgICogICAgIGV4cGlyeVRpbWVzdGFtcDogICAgTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkgKyAzNjUgKiA4NjQwMCxcbiAgICogICB9KTtcbiAgICovXG4gIGdldERlY3J5cHRpb25EZWxlZ2F0aW9uQnVpbGRlcigpOiBEZWNyeXB0aW9uRGVsZWdhdGlvbkJ1aWxkZXIge1xuICAgIHJldHVybiBuZXcgRGVjcnlwdGlvbkRlbGVnYXRpb25CdWlsZGVyKCk7XG4gIH1cbn1cbiJdfQ==
|