@bitgo-beta/sdk-coin-eth 4.4.1-beta.192 → 4.4.1-beta.1921
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 +1 -1
- package/dist/src/erc20Token.d.ts.map +1 -1
- package/dist/src/erc20Token.js +49 -28
- package/dist/src/erc721Token.d.ts +60 -0
- package/dist/src/erc721Token.d.ts.map +1 -0
- package/dist/src/erc721Token.js +334 -0
- package/dist/src/erc7984Token.d.ts +118 -0
- package/dist/src/erc7984Token.d.ts.map +1 -0
- package/dist/src/erc7984Token.js +459 -0
- package/dist/src/eth.d.ts +10 -8
- package/dist/src/eth.d.ts.map +1 -1
- package/dist/src/eth.js +54 -39
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -2
- package/dist/src/lib/index.d.ts +1 -0
- package/dist/src/lib/index.d.ts.map +1 -1
- package/dist/src/lib/index.js +7 -2
- 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 -5
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -1
- package/dist/src/lib/transactionBuilder.js +17 -7
- package/dist/src/lib/transferBuilders/index.d.ts +2 -2
- package/dist/src/lib/transferBuilders/index.d.ts.map +1 -1
- package/dist/src/lib/transferBuilders/index.js +3 -2
- package/dist/src/register.d.ts +2 -0
- package/dist/src/register.d.ts.map +1 -1
- package/dist/src/register.js +36 -2
- package/dist/test/fixtures/eth.d.ts +39 -0
- package/dist/test/fixtures/eth.d.ts.map +1 -0
- package/dist/test/fixtures/eth.js +262 -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 +1034 -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 +2568 -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 +73 -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 +285 -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 +17 -13
- package/.eslintignore +0 -5
- package/.mocharc.yml +0 -8
- package/CHANGELOG.md +0 -717
|
@@ -0,0 +1,1034 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
/**
|
|
40
|
+
* Unit tests for Erc7984Token.
|
|
41
|
+
*
|
|
42
|
+
* Covers:
|
|
43
|
+
* - getTokenEnablementConfig
|
|
44
|
+
* - verifyTransaction (TSS and multisig paths)
|
|
45
|
+
* - verifyTransaction (confidential transfer / SendERC7984 path)
|
|
46
|
+
* - decodeTokenAddressesFromDelegationCalldata (round-trip and forwarder-wrapped)
|
|
47
|
+
*/
|
|
48
|
+
const should_1 = __importDefault(require("should"));
|
|
49
|
+
const sdk_api_1 = require("@bitgo-beta/sdk-api");
|
|
50
|
+
const sdk_test_1 = require("@bitgo-beta/sdk-test");
|
|
51
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
52
|
+
const abstract_eth_1 = require("@bitgo-beta/abstract-eth");
|
|
53
|
+
const getBuilder_1 = require("./getBuilder");
|
|
54
|
+
const register_1 = require("../../src/register");
|
|
55
|
+
const testData = __importStar(require("../resources/eth"));
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Constants
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Hoodi ACL contract address (Networks.test.hoodi.zamaAclContractAddress)
|
|
60
|
+
const ZAMA_ACL_ADDRESS = '0x6d3faf6f86e1ff9f3b0831dda920aba1cbd5bd68';
|
|
61
|
+
const DELEGATE_ADDRESS = '0x1111111111111111111111111111111111111111';
|
|
62
|
+
// hteth:ctest1 token contract address (from statics/erc7984Tokens.ts)
|
|
63
|
+
const CTEST1_TOKEN_ADDRESS = '0x7b1d59bbcd291daa59cb6c8c5bc04de1afc4aba1';
|
|
64
|
+
// hteth:cusdt token contract address (from statics/erc7984Tokens.ts)
|
|
65
|
+
const CUSDT_TOKEN_ADDRESS = '0x2debbe0487ef921df4457f9e36ed05be2df1ac75';
|
|
66
|
+
const WRONG_TOKEN_ADDRESS = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef';
|
|
67
|
+
const WRONG_ACL_ADDRESS = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
68
|
+
const FORWARDER_ADDRESS = '0x1234567890123456789012345678901234567890';
|
|
69
|
+
const EXPIRY = Math.floor(Date.now() / 1000) + 365 * 86400;
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Helpers
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Builds a root-wallet delegation tx hex (to = ACL, data = multicall).
|
|
75
|
+
*/
|
|
76
|
+
async function buildDelegationTxHex(aclAddress, tokenAddresses, value = '0') {
|
|
77
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
78
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '200000' });
|
|
79
|
+
txBuilder.counter(1);
|
|
80
|
+
txBuilder.type(sdk_core_1.TransactionType.ContractCall);
|
|
81
|
+
txBuilder.contract(aclAddress);
|
|
82
|
+
const calldata = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, tokenAddresses, EXPIRY);
|
|
83
|
+
txBuilder.data(calldata);
|
|
84
|
+
if (value !== '0') {
|
|
85
|
+
txBuilder.value(value);
|
|
86
|
+
}
|
|
87
|
+
const tx = await txBuilder.build();
|
|
88
|
+
return tx.toBroadcastFormat();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Builds a forwarder delegation tx hex (to = forwarder, data = callFromParent(ACL, 0, multicall)).
|
|
92
|
+
* This mirrors what DecryptionDelegationBuilder.build() returns when forwarderAddress is set.
|
|
93
|
+
*/
|
|
94
|
+
async function buildForwarderDelegationTxHex(forwarderAddress, aclAddress, tokenAddresses) {
|
|
95
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
96
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '200000' });
|
|
97
|
+
txBuilder.counter(1);
|
|
98
|
+
txBuilder.type(sdk_core_1.TransactionType.ContractCall);
|
|
99
|
+
txBuilder.contract(forwarderAddress);
|
|
100
|
+
const innerCalldata = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, tokenAddresses, EXPIRY);
|
|
101
|
+
const outerCalldata = (0, abstract_eth_1.wrapInCallFromParent)(aclAddress, innerCalldata);
|
|
102
|
+
txBuilder.data(outerCalldata);
|
|
103
|
+
const tx = await txBuilder.build();
|
|
104
|
+
return tx.toBroadcastFormat();
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Tests
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
describe('Erc7984Token', function () {
|
|
110
|
+
let bitgo;
|
|
111
|
+
let coin;
|
|
112
|
+
before(function () {
|
|
113
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'test' });
|
|
114
|
+
bitgo.initializeTestVars();
|
|
115
|
+
(0, register_1.register)(bitgo);
|
|
116
|
+
coin = bitgo.coin('hteth:ctest1');
|
|
117
|
+
});
|
|
118
|
+
// -------------------------------------------------------------------------
|
|
119
|
+
describe('getTokenEnablementConfig', function () {
|
|
120
|
+
it('should return requiresTokenEnablement: true', function () {
|
|
121
|
+
const config = coin.getTokenEnablementConfig();
|
|
122
|
+
config.requiresTokenEnablement.should.equal(true);
|
|
123
|
+
});
|
|
124
|
+
it('should return supportsMultipleTokenEnablements: true', function () {
|
|
125
|
+
const config = coin.getTokenEnablementConfig();
|
|
126
|
+
config.supportsMultipleTokenEnablements.should.equal(true);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
// -------------------------------------------------------------------------
|
|
130
|
+
describe('verifyTransaction – non-enable-token', function () {
|
|
131
|
+
it('should route to confidential transfer path when type is not enabletoken', async function () {
|
|
132
|
+
// Non-enabletoken transactions route to verifyConfidentialTransfer.
|
|
133
|
+
// Empty recipients triggers our ERC7984-specific validation error,
|
|
134
|
+
// confirming the override only intercepts the enabletoken type.
|
|
135
|
+
await coin
|
|
136
|
+
.verifyTransaction({
|
|
137
|
+
txParams: { recipients: [] },
|
|
138
|
+
txPrebuild: {},
|
|
139
|
+
wallet: {},
|
|
140
|
+
})
|
|
141
|
+
.should.be.rejectedWith(/recipients must contain at least one entry/);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
// -------------------------------------------------------------------------
|
|
145
|
+
describe('verifyTransaction – TSS path', function () {
|
|
146
|
+
it('should verify a valid single-token delegation tx', async function () {
|
|
147
|
+
const txHex = await buildDelegationTxHex(ZAMA_ACL_ADDRESS, [CTEST1_TOKEN_ADDRESS]);
|
|
148
|
+
const result = await coin.verifyTransaction({
|
|
149
|
+
txParams: {
|
|
150
|
+
type: 'enabletoken',
|
|
151
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
152
|
+
},
|
|
153
|
+
txPrebuild: { txHex },
|
|
154
|
+
wallet: {},
|
|
155
|
+
walletType: 'tss',
|
|
156
|
+
});
|
|
157
|
+
result.should.equal(true);
|
|
158
|
+
});
|
|
159
|
+
it('should verify a valid multi-token delegation tx', async function () {
|
|
160
|
+
const txHex = await buildDelegationTxHex(ZAMA_ACL_ADDRESS, [CTEST1_TOKEN_ADDRESS, CUSDT_TOKEN_ADDRESS]);
|
|
161
|
+
const result = await coin.verifyTransaction({
|
|
162
|
+
txParams: {
|
|
163
|
+
type: 'enabletoken',
|
|
164
|
+
enableTokens: [{ name: 'hteth:ctest1' }, { name: 'hteth:cusdt' }],
|
|
165
|
+
},
|
|
166
|
+
txPrebuild: { txHex },
|
|
167
|
+
wallet: {},
|
|
168
|
+
walletType: 'tss',
|
|
169
|
+
});
|
|
170
|
+
result.should.equal(true);
|
|
171
|
+
});
|
|
172
|
+
it('should throw when ACL address does not match', async function () {
|
|
173
|
+
const txHex = await buildDelegationTxHex(WRONG_ACL_ADDRESS, [CTEST1_TOKEN_ADDRESS]);
|
|
174
|
+
await coin
|
|
175
|
+
.verifyTransaction({
|
|
176
|
+
txParams: {
|
|
177
|
+
type: 'enabletoken',
|
|
178
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
179
|
+
},
|
|
180
|
+
txPrebuild: { txHex },
|
|
181
|
+
wallet: {},
|
|
182
|
+
walletType: 'tss',
|
|
183
|
+
})
|
|
184
|
+
.should.be.rejectedWith(/does not match ACL contract/);
|
|
185
|
+
});
|
|
186
|
+
it('should throw when calldata contains wrong token address', async function () {
|
|
187
|
+
const txHex = await buildDelegationTxHex(ZAMA_ACL_ADDRESS, [WRONG_TOKEN_ADDRESS]);
|
|
188
|
+
await coin
|
|
189
|
+
.verifyTransaction({
|
|
190
|
+
txParams: {
|
|
191
|
+
type: 'enabletoken',
|
|
192
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
193
|
+
},
|
|
194
|
+
txPrebuild: { txHex },
|
|
195
|
+
wallet: {},
|
|
196
|
+
walletType: 'tss',
|
|
197
|
+
})
|
|
198
|
+
.should.be.rejectedWith(/not found in delegation calldata/);
|
|
199
|
+
});
|
|
200
|
+
it('should verify a valid forwarder delegation tx (callFromParent shape)', async function () {
|
|
201
|
+
const txHex = await buildForwarderDelegationTxHex(FORWARDER_ADDRESS, ZAMA_ACL_ADDRESS, [CTEST1_TOKEN_ADDRESS]);
|
|
202
|
+
const result = await coin.verifyTransaction({
|
|
203
|
+
txParams: {
|
|
204
|
+
type: 'enabletoken',
|
|
205
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
206
|
+
},
|
|
207
|
+
txPrebuild: { txHex },
|
|
208
|
+
wallet: {},
|
|
209
|
+
walletType: 'tss',
|
|
210
|
+
});
|
|
211
|
+
result.should.equal(true);
|
|
212
|
+
});
|
|
213
|
+
it('should verify a forwarder delegation tx with multiple tokens', async function () {
|
|
214
|
+
const txHex = await buildForwarderDelegationTxHex(FORWARDER_ADDRESS, ZAMA_ACL_ADDRESS, [
|
|
215
|
+
CTEST1_TOKEN_ADDRESS,
|
|
216
|
+
CUSDT_TOKEN_ADDRESS,
|
|
217
|
+
]);
|
|
218
|
+
const result = await coin.verifyTransaction({
|
|
219
|
+
txParams: {
|
|
220
|
+
type: 'enabletoken',
|
|
221
|
+
enableTokens: [{ name: 'hteth:ctest1' }, { name: 'hteth:cusdt' }],
|
|
222
|
+
},
|
|
223
|
+
txPrebuild: { txHex },
|
|
224
|
+
wallet: {},
|
|
225
|
+
walletType: 'tss',
|
|
226
|
+
});
|
|
227
|
+
result.should.equal(true);
|
|
228
|
+
});
|
|
229
|
+
it('should throw when forwarder calldata contains wrong token address', async function () {
|
|
230
|
+
const txHex = await buildForwarderDelegationTxHex(FORWARDER_ADDRESS, ZAMA_ACL_ADDRESS, [WRONG_TOKEN_ADDRESS]);
|
|
231
|
+
await coin
|
|
232
|
+
.verifyTransaction({
|
|
233
|
+
txParams: {
|
|
234
|
+
type: 'enabletoken',
|
|
235
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
236
|
+
},
|
|
237
|
+
txPrebuild: { txHex },
|
|
238
|
+
wallet: {},
|
|
239
|
+
walletType: 'tss',
|
|
240
|
+
})
|
|
241
|
+
.should.be.rejectedWith(/not found in delegation calldata/);
|
|
242
|
+
});
|
|
243
|
+
it('should throw when calldata has unrecognised method ID', async function () {
|
|
244
|
+
// Build a tx with arbitrary calldata that is neither multicall nor callFromParent
|
|
245
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
246
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '200000' });
|
|
247
|
+
txBuilder.counter(1);
|
|
248
|
+
txBuilder.type(sdk_core_1.TransactionType.ContractCall);
|
|
249
|
+
txBuilder.contract(ZAMA_ACL_ADDRESS);
|
|
250
|
+
txBuilder.data('0xdeadbeef');
|
|
251
|
+
const tx = await txBuilder.build();
|
|
252
|
+
const txHex = tx.toBroadcastFormat();
|
|
253
|
+
await coin
|
|
254
|
+
.verifyTransaction({
|
|
255
|
+
txParams: {
|
|
256
|
+
type: 'enabletoken',
|
|
257
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
258
|
+
},
|
|
259
|
+
txPrebuild: { txHex },
|
|
260
|
+
wallet: {},
|
|
261
|
+
walletType: 'tss',
|
|
262
|
+
})
|
|
263
|
+
.should.be.rejectedWith(/unrecognised calldata method ID/);
|
|
264
|
+
});
|
|
265
|
+
it('should throw when transaction value is not 0', async function () {
|
|
266
|
+
const txHex = await buildDelegationTxHex(ZAMA_ACL_ADDRESS, [CTEST1_TOKEN_ADDRESS], '1');
|
|
267
|
+
await coin
|
|
268
|
+
.verifyTransaction({
|
|
269
|
+
txParams: {
|
|
270
|
+
type: 'enabletoken',
|
|
271
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
272
|
+
},
|
|
273
|
+
txPrebuild: { txHex },
|
|
274
|
+
wallet: {},
|
|
275
|
+
walletType: 'tss',
|
|
276
|
+
})
|
|
277
|
+
.should.be.rejectedWith(/expected transaction value 0/);
|
|
278
|
+
});
|
|
279
|
+
it('should throw when enableTokens is empty', async function () {
|
|
280
|
+
const txHex = await buildDelegationTxHex(ZAMA_ACL_ADDRESS, [CTEST1_TOKEN_ADDRESS]);
|
|
281
|
+
await coin
|
|
282
|
+
.verifyTransaction({
|
|
283
|
+
txParams: {
|
|
284
|
+
type: 'enabletoken',
|
|
285
|
+
enableTokens: [],
|
|
286
|
+
},
|
|
287
|
+
txPrebuild: { txHex },
|
|
288
|
+
wallet: {},
|
|
289
|
+
walletType: 'tss',
|
|
290
|
+
})
|
|
291
|
+
.should.be.rejectedWith(/enableTokens must be non-empty/);
|
|
292
|
+
});
|
|
293
|
+
it('should throw when txHex is missing', async function () {
|
|
294
|
+
await coin
|
|
295
|
+
.verifyTransaction({
|
|
296
|
+
txParams: {
|
|
297
|
+
type: 'enabletoken',
|
|
298
|
+
enableTokens: [{ name: 'hteth:ctest1' }],
|
|
299
|
+
},
|
|
300
|
+
txPrebuild: {},
|
|
301
|
+
wallet: {},
|
|
302
|
+
walletType: 'tss',
|
|
303
|
+
})
|
|
304
|
+
.should.be.rejectedWith(/missing txHex/);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
// -------------------------------------------------------------------------
|
|
308
|
+
describe('verifyTransaction – multisig path', function () {
|
|
309
|
+
it('should verify valid buildParams recipients', async function () {
|
|
310
|
+
const result = await coin.verifyTransaction({
|
|
311
|
+
txParams: {
|
|
312
|
+
type: 'enabletoken',
|
|
313
|
+
recipients: [{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '0' }],
|
|
314
|
+
},
|
|
315
|
+
txPrebuild: {
|
|
316
|
+
buildParams: {
|
|
317
|
+
type: 'enabletoken',
|
|
318
|
+
recipients: [{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '0' }],
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
wallet: {},
|
|
322
|
+
walletType: 'onchain',
|
|
323
|
+
});
|
|
324
|
+
result.should.equal(true);
|
|
325
|
+
});
|
|
326
|
+
it('should verify multiple token recipients', async function () {
|
|
327
|
+
const result = await coin.verifyTransaction({
|
|
328
|
+
txParams: {
|
|
329
|
+
type: 'enabletoken',
|
|
330
|
+
recipients: [
|
|
331
|
+
{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '0' },
|
|
332
|
+
{ tokenName: 'hteth:cusdt', address: '0xabc', amount: '0' },
|
|
333
|
+
],
|
|
334
|
+
},
|
|
335
|
+
txPrebuild: {
|
|
336
|
+
buildParams: {
|
|
337
|
+
type: 'enabletoken',
|
|
338
|
+
recipients: [
|
|
339
|
+
{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '0' },
|
|
340
|
+
{ tokenName: 'hteth:cusdt', address: '0xabc', amount: '0' },
|
|
341
|
+
],
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
wallet: {},
|
|
345
|
+
walletType: 'onchain',
|
|
346
|
+
});
|
|
347
|
+
result.should.equal(true);
|
|
348
|
+
});
|
|
349
|
+
it('should throw when buildParams recipients have wrong tokenName', async function () {
|
|
350
|
+
await coin
|
|
351
|
+
.verifyTransaction({
|
|
352
|
+
txParams: {
|
|
353
|
+
type: 'enabletoken',
|
|
354
|
+
recipients: [{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '0' }],
|
|
355
|
+
},
|
|
356
|
+
txPrebuild: {
|
|
357
|
+
buildParams: {
|
|
358
|
+
type: 'enabletoken',
|
|
359
|
+
recipients: [{ tokenName: 'hteth:wrongtoken', address: '0xabc', amount: '0' }],
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
wallet: {},
|
|
363
|
+
walletType: 'onchain',
|
|
364
|
+
})
|
|
365
|
+
.should.be.rejectedWith(/not found in buildParams recipients/);
|
|
366
|
+
});
|
|
367
|
+
it('should throw when amount is not 0', async function () {
|
|
368
|
+
await coin
|
|
369
|
+
.verifyTransaction({
|
|
370
|
+
txParams: {
|
|
371
|
+
type: 'enabletoken',
|
|
372
|
+
recipients: [{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '0' }],
|
|
373
|
+
},
|
|
374
|
+
txPrebuild: {
|
|
375
|
+
buildParams: {
|
|
376
|
+
type: 'enabletoken',
|
|
377
|
+
recipients: [{ tokenName: 'hteth:ctest1', address: '0xabc', amount: '100' }],
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
wallet: {},
|
|
381
|
+
walletType: 'onchain',
|
|
382
|
+
})
|
|
383
|
+
.should.be.rejectedWith(/expected amount 0/);
|
|
384
|
+
});
|
|
385
|
+
it('should throw when recipients is missing', async function () {
|
|
386
|
+
await coin
|
|
387
|
+
.verifyTransaction({
|
|
388
|
+
txParams: {
|
|
389
|
+
type: 'enabletoken',
|
|
390
|
+
},
|
|
391
|
+
txPrebuild: {
|
|
392
|
+
buildParams: {},
|
|
393
|
+
},
|
|
394
|
+
wallet: {},
|
|
395
|
+
walletType: 'onchain',
|
|
396
|
+
})
|
|
397
|
+
.should.be.rejectedWith(/missing buildParams.recipients/);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
// ---------------------------------------------------------------------------
|
|
402
|
+
// verifyTransaction – confidential transfer (SendERC7984) tests
|
|
403
|
+
// ---------------------------------------------------------------------------
|
|
404
|
+
/**
|
|
405
|
+
* Build a raw signed sendMultiSig tx hex that wraps a confidentialTransfer call.
|
|
406
|
+
* The wallet contract (sendMultiSig wrapper) is `walletContractAddress`.
|
|
407
|
+
*/
|
|
408
|
+
async function buildConfidentialTransferTxHex(opts) {
|
|
409
|
+
const key = testData.KEYPAIR_PRV.getKeys().prv;
|
|
410
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
411
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '12100000' });
|
|
412
|
+
txBuilder.counter(1);
|
|
413
|
+
txBuilder.contract(opts.walletContractAddress);
|
|
414
|
+
txBuilder.type(sdk_core_1.TransactionType.SendERC7984);
|
|
415
|
+
const transferBuilder = txBuilder.transfer();
|
|
416
|
+
transferBuilder
|
|
417
|
+
.from('0x19645032c7f1533395d44a629462e751084d3e4d')
|
|
418
|
+
.to(opts.recipientAddress)
|
|
419
|
+
.tokenContractAddress(opts.tokenContractAddress)
|
|
420
|
+
.encryptedHandle(opts.encryptedHandle)
|
|
421
|
+
.inputProof(opts.inputProof)
|
|
422
|
+
.contractSequenceId(1)
|
|
423
|
+
.expirationTime(Math.floor(Date.now() / 1000) + 3600)
|
|
424
|
+
.key(key);
|
|
425
|
+
txBuilder.sign({ key: testData.PRIVATE_KEY });
|
|
426
|
+
const tx = await txBuilder.build();
|
|
427
|
+
return tx.toBroadcastFormat();
|
|
428
|
+
}
|
|
429
|
+
describe('verifyTransaction – confidential transfer (SendERC7984)', function () {
|
|
430
|
+
// Wallet contract that wraps the sendMultiSig call
|
|
431
|
+
const WALLET_CONTRACT = '0x8f977e912ef500548a0c3be6ddde9899f1199b81';
|
|
432
|
+
// Recipient of the confidential transfer
|
|
433
|
+
const RECIPIENT = '0x19645032c7f1533395d44a629462e751084d3e4c';
|
|
434
|
+
// Encrypted handle: synthetic 32 bytes
|
|
435
|
+
const HANDLE = '0x' + 'ab'.repeat(32);
|
|
436
|
+
// Input proof: synthetic 50 bytes
|
|
437
|
+
const PROOF = '0x' + 'cd'.repeat(50);
|
|
438
|
+
// A different recipient to trigger mismatch
|
|
439
|
+
const WRONG_RECIPIENT = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
440
|
+
// A different token contract to trigger mismatch
|
|
441
|
+
const WRONG_TOKEN = '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
|
|
442
|
+
let bitgo;
|
|
443
|
+
let coin;
|
|
444
|
+
before(function () {
|
|
445
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'test' });
|
|
446
|
+
bitgo.initializeTestVars();
|
|
447
|
+
(0, register_1.register)(bitgo);
|
|
448
|
+
coin = bitgo.coin('hteth:ctest1');
|
|
449
|
+
});
|
|
450
|
+
// Representative plaintext amount in base units (e.g., 1 cTEST1 = 1_000_000 units at 6 decimals)
|
|
451
|
+
const AMOUNT = '1000000';
|
|
452
|
+
it('should verify a valid confidential transfer transaction with matching amounts', async function () {
|
|
453
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
454
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
455
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
456
|
+
recipientAddress: RECIPIENT,
|
|
457
|
+
encryptedHandle: HANDLE,
|
|
458
|
+
inputProof: PROOF,
|
|
459
|
+
});
|
|
460
|
+
const result = await coin.verifyTransaction({
|
|
461
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
462
|
+
txPrebuild: { txHex, buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] } },
|
|
463
|
+
wallet: {},
|
|
464
|
+
});
|
|
465
|
+
result.should.equal(true);
|
|
466
|
+
});
|
|
467
|
+
it('should throw when no recipient info is provided in either txParams or buildParams', async function () {
|
|
468
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
469
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
470
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
471
|
+
recipientAddress: RECIPIENT,
|
|
472
|
+
encryptedHandle: HANDLE,
|
|
473
|
+
inputProof: PROOF,
|
|
474
|
+
});
|
|
475
|
+
await coin
|
|
476
|
+
.verifyTransaction({
|
|
477
|
+
txParams: {},
|
|
478
|
+
txPrebuild: { txHex },
|
|
479
|
+
wallet: {},
|
|
480
|
+
})
|
|
481
|
+
.should.be.rejectedWith(/missing expected recipient/);
|
|
482
|
+
});
|
|
483
|
+
it('should verify successfully using buildParams.recipients when txParams has no recipients', async function () {
|
|
484
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
485
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
486
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
487
|
+
recipientAddress: RECIPIENT,
|
|
488
|
+
encryptedHandle: HANDLE,
|
|
489
|
+
inputProof: PROOF,
|
|
490
|
+
});
|
|
491
|
+
const result = await coin.verifyTransaction({
|
|
492
|
+
txParams: {},
|
|
493
|
+
txPrebuild: {
|
|
494
|
+
txHex,
|
|
495
|
+
buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
496
|
+
},
|
|
497
|
+
wallet: {},
|
|
498
|
+
});
|
|
499
|
+
result.should.equal(true);
|
|
500
|
+
});
|
|
501
|
+
it('should throw when token contract address does not match this coin', async function () {
|
|
502
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
503
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
504
|
+
tokenContractAddress: WRONG_TOKEN,
|
|
505
|
+
recipientAddress: RECIPIENT,
|
|
506
|
+
encryptedHandle: HANDLE,
|
|
507
|
+
inputProof: PROOF,
|
|
508
|
+
});
|
|
509
|
+
await coin
|
|
510
|
+
.verifyTransaction({
|
|
511
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
512
|
+
txPrebuild: { txHex },
|
|
513
|
+
wallet: {},
|
|
514
|
+
})
|
|
515
|
+
.should.be.rejectedWith(/token contract address mismatch/);
|
|
516
|
+
});
|
|
517
|
+
it('should throw when recipient address does not match txParams', async function () {
|
|
518
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
519
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
520
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
521
|
+
recipientAddress: RECIPIENT,
|
|
522
|
+
encryptedHandle: HANDLE,
|
|
523
|
+
inputProof: PROOF,
|
|
524
|
+
});
|
|
525
|
+
await coin
|
|
526
|
+
.verifyTransaction({
|
|
527
|
+
txParams: { recipients: [{ address: WRONG_RECIPIENT, amount: AMOUNT }] },
|
|
528
|
+
txPrebuild: { txHex },
|
|
529
|
+
wallet: {},
|
|
530
|
+
})
|
|
531
|
+
.should.be.rejectedWith(/recipient address mismatch/);
|
|
532
|
+
});
|
|
533
|
+
it('should throw when calldata is not a confidential transfer', async function () {
|
|
534
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
535
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '200000' });
|
|
536
|
+
txBuilder.counter(1);
|
|
537
|
+
txBuilder.type(sdk_core_1.TransactionType.ContractCall);
|
|
538
|
+
txBuilder.contract(WALLET_CONTRACT);
|
|
539
|
+
txBuilder.data('0xdeadbeef00000000000000000000000000000000000000000000000000000000');
|
|
540
|
+
const tx = await txBuilder.build();
|
|
541
|
+
const txHex = tx.toBroadcastFormat();
|
|
542
|
+
await coin
|
|
543
|
+
.verifyTransaction({
|
|
544
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
545
|
+
txPrebuild: { txHex },
|
|
546
|
+
wallet: {},
|
|
547
|
+
})
|
|
548
|
+
.should.be.rejectedWith(/failed to decode confidential transfer calldata/);
|
|
549
|
+
});
|
|
550
|
+
it('should throw when txParams amount does not match buildParams amount (with txHex)', async function () {
|
|
551
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
552
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
553
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
554
|
+
recipientAddress: RECIPIENT,
|
|
555
|
+
encryptedHandle: HANDLE,
|
|
556
|
+
inputProof: PROOF,
|
|
557
|
+
});
|
|
558
|
+
await coin
|
|
559
|
+
.verifyTransaction({
|
|
560
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: '9999999' }] },
|
|
561
|
+
txPrebuild: {
|
|
562
|
+
txHex,
|
|
563
|
+
buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
564
|
+
},
|
|
565
|
+
wallet: {},
|
|
566
|
+
})
|
|
567
|
+
.should.be.rejectedWith(/amount mismatch/);
|
|
568
|
+
});
|
|
569
|
+
it('should throw when txParams amount is 0 (with txHex)', async function () {
|
|
570
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
571
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
572
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
573
|
+
recipientAddress: RECIPIENT,
|
|
574
|
+
encryptedHandle: HANDLE,
|
|
575
|
+
inputProof: PROOF,
|
|
576
|
+
});
|
|
577
|
+
await coin
|
|
578
|
+
.verifyTransaction({
|
|
579
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: '0' }] },
|
|
580
|
+
txPrebuild: { txHex },
|
|
581
|
+
wallet: {},
|
|
582
|
+
})
|
|
583
|
+
.should.be.rejectedWith(/amount must be a positive integer string/);
|
|
584
|
+
});
|
|
585
|
+
// ── First-signer (no txHex) tests ──────────────────────────────────────────
|
|
586
|
+
it('should verify valid first-signer params when no txHex is present', async function () {
|
|
587
|
+
const result = await coin.verifyTransaction({
|
|
588
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
589
|
+
txPrebuild: {},
|
|
590
|
+
wallet: {},
|
|
591
|
+
});
|
|
592
|
+
result.should.equal(true);
|
|
593
|
+
});
|
|
594
|
+
it('should verify first-signer params when txParams and buildParams amounts match', async function () {
|
|
595
|
+
const result = await coin.verifyTransaction({
|
|
596
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
597
|
+
txPrebuild: { buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] } },
|
|
598
|
+
wallet: {},
|
|
599
|
+
});
|
|
600
|
+
result.should.equal(true);
|
|
601
|
+
});
|
|
602
|
+
it('should throw when recipients is empty and no txHex is present', async function () {
|
|
603
|
+
await coin
|
|
604
|
+
.verifyTransaction({
|
|
605
|
+
txParams: { recipients: [] },
|
|
606
|
+
txPrebuild: {},
|
|
607
|
+
wallet: {},
|
|
608
|
+
})
|
|
609
|
+
.should.be.rejectedWith(/recipients must contain at least one entry/);
|
|
610
|
+
});
|
|
611
|
+
it('should throw when recipient address is invalid and no txHex is present', async function () {
|
|
612
|
+
await coin
|
|
613
|
+
.verifyTransaction({
|
|
614
|
+
txParams: { recipients: [{ address: 'not-an-address', amount: AMOUNT }] },
|
|
615
|
+
txPrebuild: {},
|
|
616
|
+
wallet: {},
|
|
617
|
+
})
|
|
618
|
+
.should.be.rejectedWith(/recipient address is missing or invalid/);
|
|
619
|
+
});
|
|
620
|
+
it('should throw when amount is 0 and no txHex is present', async function () {
|
|
621
|
+
await coin
|
|
622
|
+
.verifyTransaction({
|
|
623
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: '0' }] },
|
|
624
|
+
txPrebuild: {},
|
|
625
|
+
wallet: {},
|
|
626
|
+
})
|
|
627
|
+
.should.be.rejectedWith(/amount must be a positive integer string/);
|
|
628
|
+
});
|
|
629
|
+
it('should throw when amount is empty and no txHex is present', async function () {
|
|
630
|
+
await coin
|
|
631
|
+
.verifyTransaction({
|
|
632
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: '' }] },
|
|
633
|
+
txPrebuild: {},
|
|
634
|
+
wallet: {},
|
|
635
|
+
})
|
|
636
|
+
.should.be.rejectedWith(/amount must be a positive integer string/);
|
|
637
|
+
});
|
|
638
|
+
it('should throw when txParams and buildParams amounts mismatch and no txHex is present', async function () {
|
|
639
|
+
await coin
|
|
640
|
+
.verifyTransaction({
|
|
641
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: '9999999' }] },
|
|
642
|
+
txPrebuild: { buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] } },
|
|
643
|
+
wallet: {},
|
|
644
|
+
})
|
|
645
|
+
.should.be.rejectedWith(/amount mismatch/);
|
|
646
|
+
});
|
|
647
|
+
it('should throw when txParams and buildParams recipient addresses mismatch and no txHex is present', async function () {
|
|
648
|
+
await coin
|
|
649
|
+
.verifyTransaction({
|
|
650
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
651
|
+
txPrebuild: {
|
|
652
|
+
buildParams: { recipients: [{ address: WRONG_RECIPIENT, amount: AMOUNT }] },
|
|
653
|
+
},
|
|
654
|
+
wallet: {},
|
|
655
|
+
})
|
|
656
|
+
.should.be.rejectedWith(/recipient address mismatch/);
|
|
657
|
+
});
|
|
658
|
+
it('should verify when txHex absent and buildParams has matching recipient address', async function () {
|
|
659
|
+
const result = await coin.verifyTransaction({
|
|
660
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
661
|
+
txPrebuild: {
|
|
662
|
+
buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
663
|
+
},
|
|
664
|
+
wallet: {},
|
|
665
|
+
});
|
|
666
|
+
result.should.equal(true);
|
|
667
|
+
});
|
|
668
|
+
it('should verify decoded recipient against buildParams when txParams.recipients is absent', async function () {
|
|
669
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
670
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
671
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
672
|
+
recipientAddress: RECIPIENT,
|
|
673
|
+
encryptedHandle: HANDLE,
|
|
674
|
+
inputProof: PROOF,
|
|
675
|
+
});
|
|
676
|
+
// No recipients in txParams — falls back to buildParams for recipient verification
|
|
677
|
+
const result = await coin.verifyTransaction({
|
|
678
|
+
txParams: {},
|
|
679
|
+
txPrebuild: {
|
|
680
|
+
txHex,
|
|
681
|
+
buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
682
|
+
},
|
|
683
|
+
wallet: {},
|
|
684
|
+
});
|
|
685
|
+
result.should.equal(true);
|
|
686
|
+
});
|
|
687
|
+
it('should throw when decoded recipient does not match buildParams recipient (txParams absent)', async function () {
|
|
688
|
+
const txHex = await buildConfidentialTransferTxHex({
|
|
689
|
+
walletContractAddress: WALLET_CONTRACT,
|
|
690
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
691
|
+
recipientAddress: RECIPIENT,
|
|
692
|
+
encryptedHandle: HANDLE,
|
|
693
|
+
inputProof: PROOF,
|
|
694
|
+
});
|
|
695
|
+
await coin
|
|
696
|
+
.verifyTransaction({
|
|
697
|
+
txParams: {},
|
|
698
|
+
txPrebuild: {
|
|
699
|
+
txHex,
|
|
700
|
+
buildParams: { recipients: [{ address: WRONG_RECIPIENT, amount: AMOUNT }] },
|
|
701
|
+
},
|
|
702
|
+
wallet: {},
|
|
703
|
+
})
|
|
704
|
+
.should.be.rejectedWith(/recipient address mismatch/);
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
// ---------------------------------------------------------------------------
|
|
708
|
+
// verifyTransaction – direct confidentialTransfer (hot/TSS EOA wallet) tests
|
|
709
|
+
// ---------------------------------------------------------------------------
|
|
710
|
+
/**
|
|
711
|
+
* Builds a raw tx hex where the EOA calls confidentialTransfer directly on the token
|
|
712
|
+
* contract (no sendMultiSig wrapper). This is the hot/TSS wallet path.
|
|
713
|
+
*/
|
|
714
|
+
async function buildDirectConfidentialTransferTxHex(opts) {
|
|
715
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
716
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '200000' });
|
|
717
|
+
txBuilder.counter(1);
|
|
718
|
+
txBuilder.type(sdk_core_1.TransactionType.ContractCall);
|
|
719
|
+
// tx.to = token contract (EOA calls it directly)
|
|
720
|
+
txBuilder.contract(opts.tokenContractAddress);
|
|
721
|
+
// Inner calldata: confidentialTransfer(address, bytes32, bytes) — no sendMultiSig wrapper
|
|
722
|
+
const calldata = new abstract_eth_1.TransferBuilderERC7984()
|
|
723
|
+
.to(opts.recipientAddress)
|
|
724
|
+
.tokenContractAddress(opts.tokenContractAddress)
|
|
725
|
+
.encryptedHandle(opts.encryptedHandle)
|
|
726
|
+
.inputProof(opts.inputProof)
|
|
727
|
+
.build();
|
|
728
|
+
txBuilder.data(calldata);
|
|
729
|
+
const tx = await txBuilder.build();
|
|
730
|
+
return tx.toBroadcastFormat();
|
|
731
|
+
}
|
|
732
|
+
describe('verifyTransaction – direct confidentialTransfer (hot/TSS EOA wallet)', function () {
|
|
733
|
+
const RECIPIENT = '0x19645032c7f1533395d44a629462e751084d3e4c';
|
|
734
|
+
const HANDLE = '0x' + 'ab'.repeat(32);
|
|
735
|
+
const PROOF = '0x' + 'cd'.repeat(50);
|
|
736
|
+
const WRONG_RECIPIENT = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
737
|
+
const WRONG_TOKEN = '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
|
|
738
|
+
const AMOUNT = '1000000';
|
|
739
|
+
let bitgo;
|
|
740
|
+
let coin;
|
|
741
|
+
before(function () {
|
|
742
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'test' });
|
|
743
|
+
bitgo.initializeTestVars();
|
|
744
|
+
(0, register_1.register)(bitgo);
|
|
745
|
+
coin = bitgo.coin('hteth:ctest1');
|
|
746
|
+
});
|
|
747
|
+
it('should verify a valid direct confidentialTransfer tx', async function () {
|
|
748
|
+
const txHex = await buildDirectConfidentialTransferTxHex({
|
|
749
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
750
|
+
recipientAddress: RECIPIENT,
|
|
751
|
+
encryptedHandle: HANDLE,
|
|
752
|
+
inputProof: PROOF,
|
|
753
|
+
});
|
|
754
|
+
const result = await coin.verifyTransaction({
|
|
755
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
756
|
+
txPrebuild: { txHex, buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] } },
|
|
757
|
+
wallet: {},
|
|
758
|
+
});
|
|
759
|
+
result.should.equal(true);
|
|
760
|
+
});
|
|
761
|
+
it('should verify using buildParams.recipients when txParams has no recipients', async function () {
|
|
762
|
+
const txHex = await buildDirectConfidentialTransferTxHex({
|
|
763
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
764
|
+
recipientAddress: RECIPIENT,
|
|
765
|
+
encryptedHandle: HANDLE,
|
|
766
|
+
inputProof: PROOF,
|
|
767
|
+
});
|
|
768
|
+
const result = await coin.verifyTransaction({
|
|
769
|
+
txParams: {},
|
|
770
|
+
txPrebuild: {
|
|
771
|
+
txHex,
|
|
772
|
+
buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
773
|
+
},
|
|
774
|
+
wallet: {},
|
|
775
|
+
});
|
|
776
|
+
result.should.equal(true);
|
|
777
|
+
});
|
|
778
|
+
it('should throw when token contract address (tx.to) does not match this coin', async function () {
|
|
779
|
+
const txHex = await buildDirectConfidentialTransferTxHex({
|
|
780
|
+
tokenContractAddress: WRONG_TOKEN,
|
|
781
|
+
recipientAddress: RECIPIENT,
|
|
782
|
+
encryptedHandle: HANDLE,
|
|
783
|
+
inputProof: PROOF,
|
|
784
|
+
});
|
|
785
|
+
await coin
|
|
786
|
+
.verifyTransaction({
|
|
787
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
788
|
+
txPrebuild: { txHex },
|
|
789
|
+
wallet: {},
|
|
790
|
+
})
|
|
791
|
+
.should.be.rejectedWith(/token contract address mismatch/);
|
|
792
|
+
});
|
|
793
|
+
it('should throw when recipient address does not match txParams', async function () {
|
|
794
|
+
const txHex = await buildDirectConfidentialTransferTxHex({
|
|
795
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
796
|
+
recipientAddress: RECIPIENT,
|
|
797
|
+
encryptedHandle: HANDLE,
|
|
798
|
+
inputProof: PROOF,
|
|
799
|
+
});
|
|
800
|
+
await coin
|
|
801
|
+
.verifyTransaction({
|
|
802
|
+
txParams: { recipients: [{ address: WRONG_RECIPIENT, amount: AMOUNT }] },
|
|
803
|
+
txPrebuild: { txHex },
|
|
804
|
+
wallet: {},
|
|
805
|
+
})
|
|
806
|
+
.should.be.rejectedWith(/recipient address mismatch/);
|
|
807
|
+
});
|
|
808
|
+
it('should throw when no recipient info is provided in either txParams or buildParams', async function () {
|
|
809
|
+
const txHex = await buildDirectConfidentialTransferTxHex({
|
|
810
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
811
|
+
recipientAddress: RECIPIENT,
|
|
812
|
+
encryptedHandle: HANDLE,
|
|
813
|
+
inputProof: PROOF,
|
|
814
|
+
});
|
|
815
|
+
await coin
|
|
816
|
+
.verifyTransaction({
|
|
817
|
+
txParams: {},
|
|
818
|
+
txPrebuild: { txHex },
|
|
819
|
+
wallet: {},
|
|
820
|
+
})
|
|
821
|
+
.should.be.rejectedWith(/missing expected recipient/);
|
|
822
|
+
});
|
|
823
|
+
it('should throw when txParams amount does not match buildParams amount', async function () {
|
|
824
|
+
const txHex = await buildDirectConfidentialTransferTxHex({
|
|
825
|
+
tokenContractAddress: CTEST1_TOKEN_ADDRESS,
|
|
826
|
+
recipientAddress: RECIPIENT,
|
|
827
|
+
encryptedHandle: HANDLE,
|
|
828
|
+
inputProof: PROOF,
|
|
829
|
+
});
|
|
830
|
+
await coin
|
|
831
|
+
.verifyTransaction({
|
|
832
|
+
txParams: { recipients: [{ address: RECIPIENT, amount: '9999999' }] },
|
|
833
|
+
txPrebuild: {
|
|
834
|
+
txHex,
|
|
835
|
+
buildParams: { recipients: [{ address: RECIPIENT, amount: AMOUNT }] },
|
|
836
|
+
},
|
|
837
|
+
wallet: {},
|
|
838
|
+
})
|
|
839
|
+
.should.be.rejectedWith(/amount mismatch/);
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
// ---------------------------------------------------------------------------
|
|
843
|
+
// decodeTokenAddressesFromDelegationCalldata tests
|
|
844
|
+
// ---------------------------------------------------------------------------
|
|
845
|
+
describe('decodeTokenAddressesFromDelegationCalldata', function () {
|
|
846
|
+
it('should decode a single-token multicall calldata', function () {
|
|
847
|
+
const calldata = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, [CTEST1_TOKEN_ADDRESS], EXPIRY);
|
|
848
|
+
const addresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(calldata);
|
|
849
|
+
addresses.should.deepEqual([CTEST1_TOKEN_ADDRESS.toLowerCase()]);
|
|
850
|
+
});
|
|
851
|
+
it('should decode a multi-token multicall calldata', function () {
|
|
852
|
+
const calldata = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, [CTEST1_TOKEN_ADDRESS, CUSDT_TOKEN_ADDRESS], EXPIRY);
|
|
853
|
+
const addresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(calldata);
|
|
854
|
+
addresses.should.deepEqual([CTEST1_TOKEN_ADDRESS.toLowerCase(), CUSDT_TOKEN_ADDRESS.toLowerCase()]);
|
|
855
|
+
});
|
|
856
|
+
it('should return addresses in lowercase', function () {
|
|
857
|
+
const mixedCase = '0x7B1D59bbCD291daA59cB6C8C5bc04De1AFC4aBA1';
|
|
858
|
+
const calldata = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, [mixedCase], EXPIRY);
|
|
859
|
+
const addresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(calldata);
|
|
860
|
+
addresses[0].should.equal(mixedCase.toLowerCase());
|
|
861
|
+
});
|
|
862
|
+
it('should handle callFromParent-wrapped multicall calldata', function () {
|
|
863
|
+
const inner = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, [CTEST1_TOKEN_ADDRESS, CUSDT_TOKEN_ADDRESS], EXPIRY);
|
|
864
|
+
const wrapped = (0, abstract_eth_1.wrapInCallFromParent)(ZAMA_ACL_ADDRESS, inner);
|
|
865
|
+
const addresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(wrapped);
|
|
866
|
+
addresses.should.deepEqual([CTEST1_TOKEN_ADDRESS.toLowerCase(), CUSDT_TOKEN_ADDRESS.toLowerCase()]);
|
|
867
|
+
});
|
|
868
|
+
it('should work with calldata missing 0x prefix', function () {
|
|
869
|
+
const calldata = (0, abstract_eth_1.buildMulticallDelegationCalldata)(DELEGATE_ADDRESS, [CTEST1_TOKEN_ADDRESS], EXPIRY);
|
|
870
|
+
const noPrefix = calldata.slice(2); // strip 0x
|
|
871
|
+
const addresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(noPrefix);
|
|
872
|
+
addresses.should.deepEqual([CTEST1_TOKEN_ADDRESS.toLowerCase()]);
|
|
873
|
+
});
|
|
874
|
+
it('should throw for unrecognised calldata', function () {
|
|
875
|
+
should_1.default.throws(() => (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)('0xdeadbeef00000000'), /Not a valid delegation calldata/);
|
|
876
|
+
});
|
|
877
|
+
});
|
|
878
|
+
// ---------------------------------------------------------------------------
|
|
879
|
+
// verifyTransaction – confidential consolidation (FlushERC7984ForwarderToken)
|
|
880
|
+
// ---------------------------------------------------------------------------
|
|
881
|
+
const MULTISIG_WALLET_CONTRACT = '0x3b58684525564b38a381e46a731703ed03f32122';
|
|
882
|
+
const CONSOLIDATION_FORWARDER = '0xf4bcb366bb5e34ebbee51fae5de98cc876c0146f';
|
|
883
|
+
const CONSOLIDATION_BASE_ADDRESS = '0x3b58684525564b38a381e46a731703ed03f32122';
|
|
884
|
+
const CONSOLIDATION_HANDLE = '0x65df136b609ab395c1a99ae46f7939c7f8b20dff4bff0000000088bb0050';
|
|
885
|
+
const DUMMY_MULTISIG_SIGNATURE = '0x' + '00'.repeat(65);
|
|
886
|
+
async function buildMultisigConsolidationTxHex() {
|
|
887
|
+
const flushCalldata = (0, abstract_eth_1.buildFlushERC7984ForwarderTokenCalldata)(CTEST1_TOKEN_ADDRESS, CONSOLIDATION_BASE_ADDRESS, CONSOLIDATION_HANDLE);
|
|
888
|
+
const sendData = (0, abstract_eth_1.sendMultiSigData)(CONSOLIDATION_FORWARDER, '0', flushCalldata, Math.floor(Date.now() / 1000) + 3600, 14, DUMMY_MULTISIG_SIGNATURE);
|
|
889
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
890
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '12100000' });
|
|
891
|
+
txBuilder.counter(1);
|
|
892
|
+
txBuilder.type(sdk_core_1.TransactionType.ContractCall);
|
|
893
|
+
txBuilder.contract(MULTISIG_WALLET_CONTRACT);
|
|
894
|
+
txBuilder.data(sendData);
|
|
895
|
+
const tx = await txBuilder.build();
|
|
896
|
+
return tx.toBroadcastFormat();
|
|
897
|
+
}
|
|
898
|
+
async function buildDirectConsolidationTxHex() {
|
|
899
|
+
const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
|
|
900
|
+
txBuilder.fee({ fee: '1000000000', gasLimit: '200000' });
|
|
901
|
+
txBuilder.counter(1);
|
|
902
|
+
txBuilder.type(sdk_core_1.TransactionType.FlushERC7984ForwarderToken);
|
|
903
|
+
txBuilder.contract(CONSOLIDATION_FORWARDER);
|
|
904
|
+
txBuilder.forwarderAddress(CONSOLIDATION_FORWARDER);
|
|
905
|
+
txBuilder.tokenContractAddress(CTEST1_TOKEN_ADDRESS);
|
|
906
|
+
txBuilder.parentAddress(CONSOLIDATION_BASE_ADDRESS);
|
|
907
|
+
txBuilder.encryptedHandle(CONSOLIDATION_HANDLE);
|
|
908
|
+
const tx = await txBuilder.build();
|
|
909
|
+
return tx.toBroadcastFormat();
|
|
910
|
+
}
|
|
911
|
+
describe('verifyTransaction – confidential consolidation (FlushERC7984ForwarderToken)', function () {
|
|
912
|
+
let bitgo;
|
|
913
|
+
let coin;
|
|
914
|
+
before(function () {
|
|
915
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'test' });
|
|
916
|
+
bitgo.initializeTestVars();
|
|
917
|
+
(0, register_1.register)(bitgo);
|
|
918
|
+
coin = bitgo.coin('hteth:ctest1');
|
|
919
|
+
});
|
|
920
|
+
it('should verify a valid multisig consolidation tx (sendMultiSig → callFromParent → confidentialTransferNoProof)', async function () {
|
|
921
|
+
const txHex = await buildMultisigConsolidationTxHex();
|
|
922
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
923
|
+
coinSpecific: { baseAddress: CONSOLIDATION_BASE_ADDRESS },
|
|
924
|
+
});
|
|
925
|
+
const result = await coin.verifyTransaction({
|
|
926
|
+
txParams: { type: 'consolidate' },
|
|
927
|
+
txPrebuild: {
|
|
928
|
+
consolidateId: '6a44ebc0326e1be45c1d797542c8c634',
|
|
929
|
+
txHex,
|
|
930
|
+
recipients: [{ address: CONSOLIDATION_FORWARDER, amount: '0' }],
|
|
931
|
+
},
|
|
932
|
+
wallet,
|
|
933
|
+
});
|
|
934
|
+
result.should.equal(true);
|
|
935
|
+
});
|
|
936
|
+
it('should verify a valid direct callFromParent consolidation tx (TSS shape)', async function () {
|
|
937
|
+
const txHex = await buildDirectConsolidationTxHex();
|
|
938
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
939
|
+
coinSpecific: { baseAddress: CONSOLIDATION_BASE_ADDRESS },
|
|
940
|
+
});
|
|
941
|
+
const result = await coin.verifyTransaction({
|
|
942
|
+
txParams: { type: 'consolidate' },
|
|
943
|
+
txPrebuild: {
|
|
944
|
+
consolidateId: '6a44ebc0326e1be45c1d797542c8c634',
|
|
945
|
+
txHex,
|
|
946
|
+
},
|
|
947
|
+
wallet,
|
|
948
|
+
verification: { consolidationToBaseAddress: true },
|
|
949
|
+
});
|
|
950
|
+
result.should.equal(true);
|
|
951
|
+
});
|
|
952
|
+
it('should reject multisig consolidation when parent address does not match wallet base address', async function () {
|
|
953
|
+
const txHex = await buildMultisigConsolidationTxHex();
|
|
954
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
955
|
+
coinSpecific: { baseAddress: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' },
|
|
956
|
+
});
|
|
957
|
+
await coin
|
|
958
|
+
.verifyTransaction({
|
|
959
|
+
txParams: { type: 'consolidate' },
|
|
960
|
+
txPrebuild: { consolidateId: 'abc123', txHex },
|
|
961
|
+
wallet,
|
|
962
|
+
})
|
|
963
|
+
.should.be.rejectedWith(/parent address mismatch/);
|
|
964
|
+
});
|
|
965
|
+
it('should verify multisig consolidation using forwarder address from txPrebuild.txInfo.recipients', async function () {
|
|
966
|
+
const txHex = await buildMultisigConsolidationTxHex();
|
|
967
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
968
|
+
coinSpecific: { baseAddress: CONSOLIDATION_BASE_ADDRESS },
|
|
969
|
+
});
|
|
970
|
+
// No top-level recipients; forwarder comes from txInfo.recipients
|
|
971
|
+
const result = await coin.verifyTransaction({
|
|
972
|
+
txParams: { type: 'consolidate' },
|
|
973
|
+
txPrebuild: {
|
|
974
|
+
consolidateId: '6a44ebc0326e1be45c1d797542c8c634',
|
|
975
|
+
txHex,
|
|
976
|
+
txInfo: { recipients: [{ address: CONSOLIDATION_FORWARDER, amount: '0' }] },
|
|
977
|
+
},
|
|
978
|
+
wallet,
|
|
979
|
+
});
|
|
980
|
+
result.should.equal(true);
|
|
981
|
+
});
|
|
982
|
+
it('should reject multisig consolidation when txInfo.recipients forwarder address does not match tx forwarder', async function () {
|
|
983
|
+
const txHex = await buildMultisigConsolidationTxHex();
|
|
984
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
985
|
+
coinSpecific: { baseAddress: CONSOLIDATION_BASE_ADDRESS },
|
|
986
|
+
});
|
|
987
|
+
await coin
|
|
988
|
+
.verifyTransaction({
|
|
989
|
+
txParams: { type: 'consolidate' },
|
|
990
|
+
txPrebuild: {
|
|
991
|
+
consolidateId: 'abc123',
|
|
992
|
+
txHex,
|
|
993
|
+
txInfo: { recipients: [{ address: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', amount: '0' }] },
|
|
994
|
+
},
|
|
995
|
+
wallet,
|
|
996
|
+
})
|
|
997
|
+
.should.be.rejectedWith(/forwarder address mismatch/);
|
|
998
|
+
});
|
|
999
|
+
// TSS MPCv2 signing path — resolveEffectiveTxParams sets type from intent.intentType ('consolidateToken'),
|
|
1000
|
+
// and txPrebuild has only txHex (no consolidateId, no recipients). This was the broken path before
|
|
1001
|
+
// isConsolidationTransaction was updated to recognise 'consolidateToken'.
|
|
1002
|
+
it('should verify a valid direct callFromParent consolidation tx when type is consolidateToken (TSS MPCv2 signing path)', async function () {
|
|
1003
|
+
const txHex = await buildDirectConsolidationTxHex();
|
|
1004
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
1005
|
+
coinSpecific: { baseAddress: CONSOLIDATION_BASE_ADDRESS },
|
|
1006
|
+
});
|
|
1007
|
+
const result = await coin.verifyTransaction({
|
|
1008
|
+
txParams: {
|
|
1009
|
+
type: 'consolidateToken',
|
|
1010
|
+
recipients: [{ address: CONSOLIDATION_FORWARDER, amount: '0' }],
|
|
1011
|
+
},
|
|
1012
|
+
txPrebuild: { txHex },
|
|
1013
|
+
wallet,
|
|
1014
|
+
});
|
|
1015
|
+
result.should.equal(true);
|
|
1016
|
+
});
|
|
1017
|
+
it('should reject callFromParent consolidation with type consolidateToken when parent address does not match wallet base address', async function () {
|
|
1018
|
+
const txHex = await buildDirectConsolidationTxHex();
|
|
1019
|
+
const wallet = new sdk_core_1.Wallet(bitgo, coin, {
|
|
1020
|
+
coinSpecific: { baseAddress: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' },
|
|
1021
|
+
});
|
|
1022
|
+
await coin
|
|
1023
|
+
.verifyTransaction({
|
|
1024
|
+
txParams: {
|
|
1025
|
+
type: 'consolidateToken',
|
|
1026
|
+
recipients: [{ address: CONSOLIDATION_FORWARDER, amount: '0' }],
|
|
1027
|
+
},
|
|
1028
|
+
txPrebuild: { txHex },
|
|
1029
|
+
wallet,
|
|
1030
|
+
})
|
|
1031
|
+
.should.be.rejectedWith(/parent address mismatch/);
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJjNzk4NFRva2VuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC91bml0L2VyYzc5ODRUb2tlbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7Ozs7OztHQVFHO0FBQ0gsb0RBQTRCO0FBQzVCLGlEQUErQztBQUMvQyxtREFBK0Q7QUFDL0QsbURBQStEO0FBQy9ELDJEQU9rQztBQUdsQyw2Q0FBMEM7QUFDMUMsaURBQThDO0FBQzlDLDJEQUE2QztBQUU3Qyw4RUFBOEU7QUFDOUUsWUFBWTtBQUNaLDhFQUE4RTtBQUU5RSwwRUFBMEU7QUFDMUUsTUFBTSxnQkFBZ0IsR0FBRyw0Q0FBNEMsQ0FBQztBQUN0RSxNQUFNLGdCQUFnQixHQUFHLDRDQUE0QyxDQUFDO0FBRXRFLHNFQUFzRTtBQUN0RSxNQUFNLG9CQUFvQixHQUFHLDRDQUE0QyxDQUFDO0FBQzFFLHFFQUFxRTtBQUNyRSxNQUFNLG1CQUFtQixHQUFHLDRDQUE0QyxDQUFDO0FBRXpFLE1BQU0sbUJBQW1CLEdBQUcsNENBQTRDLENBQUM7QUFDekUsTUFBTSxpQkFBaUIsR0FBRyw0Q0FBNEMsQ0FBQztBQUN2RSxNQUFNLGlCQUFpQixHQUFHLDRDQUE0QyxDQUFDO0FBRXZFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxLQUFLLENBQUM7QUFFM0QsOEVBQThFO0FBQzlFLFVBQVU7QUFDViw4RUFBOEU7QUFFOUU7O0dBRUc7QUFDSCxLQUFLLFVBQVUsb0JBQW9CLENBQUMsVUFBa0IsRUFBRSxjQUF3QixFQUFFLEtBQUssR0FBRyxHQUFHO0lBQzNGLE1BQU0sU0FBUyxHQUFHLElBQUEsdUJBQVUsRUFBQyxPQUFPLENBQXVCLENBQUM7SUFDNUQsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFF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QUFFLGtCQUFrQjtnQkFDeEIsVUFBVSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDO2FBQ3pEO1lBQ1IsVUFBVSxFQUFFLEVBQUUsS0FBSyxFQUFTO1lBQzVCLE1BQU07U0FDUCxDQUFDLENBQUM7UUFDSCxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM1QixDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQyw4SEFBOEgsRUFBRSxLQUFLO1FBQ3RJLE1BQU0sS0FBSyxHQUFHLE1BQU0sNkJBQTZCLEVBQUUsQ0FBQztRQUNwRCxNQUFNLE1BQU0sR0FBRyxJQUFJLGlCQUFNLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRTtZQUNyQyxZQUFZLEVBQUUsRUFBRSxXQUFXLEVBQUUsNENBQTRDLEVBQUU7U0FDNUUsQ0FBQyxDQUFDO1FBRUgsTUFBTSxJQUFJO2FBQ1AsaUJBQWlCLENBQUM7WUFDakIsUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSxrQkFBa0I7Z0JBQ3hCLFVBQVUsRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQzthQUN6RDtZQUNSLFVBQVUsRUFBRSxFQUFFLEtBQUssRUFBUztZQUM1QixNQUFNO1NBQ1AsQ0FBQzthQUNELE1BQU0sQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLHlCQUF5QixDQUFDLENBQUM7SUFDdkQsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVW5pdCB0ZXN0cyBmb3IgRXJjNzk4NFRva2VuLlxuICpcbiAqIENvdmVyczpcbiAqICAgLSBnZXRUb2tlbkVuYWJsZW1lbnRDb25maWdcbiAqICAgLSB2ZXJpZnlUcmFuc2FjdGlvbiAoVFNTIGFuZCBtdWx0aXNpZyBwYXRocylcbiAqICAgLSB2ZXJpZnlUcmFuc2FjdGlvbiAoY29uZmlkZW50aWFsIHRyYW5zZmVyIC8gU2VuZEVSQzc5ODQgcGF0aClcbiAqICAgLSBkZWNvZGVUb2tlbkFkZHJlc3Nlc0Zyb21EZWxlZ2F0aW9uQ2FsbGRhdGEgKHJvdW5kLXRyaXAgYW5kIGZvcndhcmRlci13cmFwcGVkKVxuICovXG5pbXBvcnQgc2hvdWxkIGZyb20gJ3Nob3VsZCc7XG5pbXBvcnQgeyBCaXRHb0FQSSB9IGZyb20gJ0BiaXRnby1iZXRhL3Nkay1hcGknO1xuaW1wb3J0IHsgVGVzdEJpdEdvLCBUZXN0Qml0R29BUEkgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstdGVzdCc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvblR5cGUsIFdhbGxldCB9IGZyb20gJ0BiaXRnby1iZXRhL3Nkay1jb3JlJztcbmltcG9ydCB7XG4gIGJ1aWxkTXVsdGljYWxsRGVsZWdhdGlvbkNhbGxkYXRhLFxuICBidWlsZEZsdXNoRVJDNzk4NEZvcndhcmRlclRva2VuQ2FsbGRhdGEsXG4gIHNlbmRNdWx0aVNpZ0RhdGEsXG4gIHdyYXBJbkNhbGxGcm9tUGFyZW50LFxuICBkZWNvZGVUb2tlbkFkZHJlc3Nlc0Zyb21EZWxlZ2F0aW9uQ2FsbGRhdGEsXG4gIFRyYW5zZmVyQnVpbGRlckVSQzc5ODQsXG59IGZyb20gJ0BiaXRnby1iZXRhL2Fic3RyYWN0LWV0aCc7XG5pbXBvcnQgeyBFcmM3OTg0VG9rZW4gfSBmcm9tICcuLi8uLi9zcmMvZXJjNzk4NFRva2VuJztcbmltcG9ydCB7IFRyYW5zYWN0aW9uQnVpbGRlciB9IGZyb20gJy4uLy4uL3NyYy9saWInO1xuaW1wb3J0IHsgZ2V0QnVpbGRlciB9IGZyb20gJy4vZ2V0QnVpbGRlcic7XG5pbXBvcnQgeyByZWdpc3RlciB9IGZyb20gJy4uLy4uL3NyYy9yZWdpc3Rlcic7XG5pbXBvcnQgKiBhcyB0ZXN0RGF0YSBmcm9tICcuLi9yZXNvdXJjZXMvZXRoJztcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBDb25zdGFudHNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vLyBIb29kaSBBQ0wgY29udHJhY3QgYWRkcmVzcyAoTmV0d29ya3MudGVzdC5ob29kaS56YW1hQWNsQ29udHJhY3RBZGRyZXNzKVxuY29uc3QgWkFNQV9BQ0xfQUREUkVTUyA9ICcweDZkM2ZhZjZmODZlMWZmOWYzYjA4MzFkZGE5MjBhYmExY2JkNWJkNjgnO1xuY29uc3QgREVMRUdBVEVfQUREUkVTUyA9ICcweDExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEnO1xuXG4vLyBodGV0aDpjdGVzdDEgdG9rZW4gY29udHJhY3QgYWRkcmVzcyAoZnJvbSBzdGF0aWNzL2VyYzc5ODRUb2tlbnMudHMpXG5jb25zdCBDVEVTVDFfVE9LRU5fQUREUkVTUyA9ICcweDdiMWQ1OWJiY2QyOTFkYWE1OWNiNmM4YzViYzA0ZGUxYWZjNGFiYTEnO1xuLy8gaHRldGg6Y3VzZHQgdG9rZW4gY29udHJhY3QgYWRkcmVzcyAoZnJvbSBzdGF0aWNzL2VyYzc5ODRUb2tlbnMudHMpXG5jb25zdCBDVVNEVF9UT0tFTl9BRERSRVNTID0gJzB4MmRlYmJlMDQ4N2VmOTIxZGY0NDU3ZjllMzZlZDA1YmUyZGYxYWM3NSc7XG5cbmNvbnN0IFdST05HX1RPS0VOX0FERFJFU1MgPSAnMHhkZWFkYmVlZmRlYWRiZWVmZGVhZGJlZWZkZWFkYmVlZmRlYWRiZWVmJztcbmNvbnN0IFdST05HX0FDTF9BRERSRVNTID0gJzB4YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSc7XG5jb25zdCBGT1JXQVJERVJfQUREUkVTUyA9ICcweDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAnO1xuXG5jb25zdCBFWFBJUlkgPSBNYXRoLmZsb29yKERhdGUubm93KCkgLyAxMDAwKSArIDM2NSAqIDg2NDAwO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEhlbHBlcnNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIEJ1aWxkcyBhIHJvb3Qtd2FsbGV0IGRlbGVnYXRpb24gdHggaGV4ICh0byA9IEFDTCwgZGF0YSA9IG11bHRpY2FsbCkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkRGVsZWdhdGlvblR4SGV4KGFjbEFkZHJlc3M6IHN0cmluZywgdG9rZW5BZGRyZXNzZXM6IHN0cmluZ1tdLCB2YWx1ZSA9ICcwJyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHR4QnVpbGRlciA9IGdldEJ1aWxkZXIoJ2h0ZXRoJykgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICB0eEJ1aWxkZXIuZmVlKHsgZmVlOiAnMTAwMDAwMDAwMCcsIGdhc0xpbWl0OiAnMjAwMDAwJyB9KTtcbiAgdHhCdWlsZGVyLmNvdW50ZXIoMSk7XG4gIHR4QnVpbGRlci50eXBlKFRyYW5zYWN0aW9uVHlwZS5Db250cmFjdENhbGwpO1xuICB0eEJ1aWxkZXIuY29udHJhY3QoYWNsQWRkcmVzcyk7XG4gIGNvbnN0IGNhbGxkYXRhID0gYnVpbGRNdWx0aWNhbGxEZWxlZ2F0aW9uQ2FsbGRhdGEoREVMRUdBVEVfQUREUkVTUywgdG9rZW5BZGRyZXNzZXMsIEVYUElSWSk7XG4gIHR4QnVpbGRlci5kYXRhKGNhbGxkYXRhKTtcbiAgaWYgKHZhbHVlICE9PSAnMCcpIHtcbiAgICB0eEJ1aWxkZXIudmFsdWUodmFsdWUpO1xuICB9XG4gIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIHJldHVybiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xufVxuXG4vKipcbiAqIEJ1aWxkcyBhIGZvcndhcmRlciBkZWxlZ2F0aW9uIHR4IGhleCAodG8gPSBmb3J3YXJkZXIsIGRhdGEgPSBjYWxsRnJvbVBhcmVudChBQ0wsIDAsIG11bHRpY2FsbCkpLlxuICogVGhpcyBtaXJyb3JzIHdoYXQgRGVjcnlwdGlvbkRlbGVnYXRpb25CdWlsZGVyLmJ1aWxkKCkgcmV0dXJucyB3aGVuIGZvcndhcmRlckFkZHJlc3MgaXMgc2V0LlxuICovXG5hc3luYyBmdW5jdGlvbiBidWlsZEZvcndhcmRlckRlbGVnYXRpb25UeEhleChcbiAgZm9yd2FyZGVyQWRkcmVzczogc3RyaW5nLFxuICBhY2xBZGRyZXNzOiBzdHJpbmcsXG4gIHRva2VuQWRkcmVzc2VzOiBzdHJpbmdbXVxuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgdHhCdWlsZGVyID0gZ2V0QnVpbGRlcignaHRldGgnKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gIHR4QnVpbGRlci5mZWUoeyBmZWU6ICcxMDAwMDAwMDAwJywgZ2FzTGltaXQ6ICcyMDAwMDAnIH0pO1xuICB0eEJ1aWxkZXIuY291bnRlcigxKTtcbiAgdHhCdWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbCk7XG4gIHR4QnVpbGRlci5jb250cmFjdChmb3J3YXJkZXJBZGRyZXNzKTtcbiAgY29uc3QgaW5uZXJDYWxsZGF0YSA9IGJ1aWxkTXVsdGljYWxsRGVsZWdhdGlvbkNhbGxkYXRhKERFTEVHQVRFX0FERFJFU1MsIHRva2VuQWRkcmVzc2VzLCBFWFBJUlkpO1xuICBjb25zdCBvdXRlckNhbGxkYXRhID0gd3JhcEluQ2FsbEZyb21QYXJlbnQoYWNsQWRkcmVzcywgaW5uZXJDYWxsZGF0YSk7XG4gIHR4QnVpbGRlci5kYXRhKG91dGVyQ2FsbGRhdGEpO1xuICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICByZXR1cm4gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUZXN0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmRlc2NyaWJlKCdFcmM3OTg0VG9rZW4nLCBmdW5jdGlvbiAoKSB7XG4gIGxldCBiaXRnbzogVGVzdEJpdEdvQVBJO1xuICBsZXQgY29pbjogRXJjNzk4NFRva2VuO1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R29BUEksIHsgZW52OiAndGVzdCcgfSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgcmVnaXN0ZXIoYml0Z28pO1xuICAgIGNvaW4gPSBiaXRnby5jb2luKCdodGV0aDpjdGVzdDEnKSBhcyBFcmM3OTg0VG9rZW47XG4gIH0pO1xuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgZGVzY3JpYmUoJ2dldFRva2VuRW5hYmxlbWVudENvbmZpZycsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIHJldHVybiByZXF1aXJlc1Rva2VuRW5hYmxlbWVudDogdHJ1ZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNvbmZpZyA9IGNvaW4uZ2V0VG9rZW5FbmFibGVtZW50Q29uZmlnKCk7XG4gICAgICBjb25maWcucmVxdWlyZXNUb2tlbkVuYWJsZW1lbnQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gc3VwcG9ydHNNdWx0aXBsZVRva2VuRW5hYmxlbWVudHM6IHRydWUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBjb25maWcgPSBjb2luLmdldFRva2VuRW5hYmxlbWVudENvbmZpZygpO1xuICAgICAgY29uZmlnLnN1cHBvcnRzTXVsdGlwbGVUb2tlbkVuYWJsZW1lbnRzLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICBkZXNjcmliZSgndmVyaWZ5VHJhbnNhY3Rpb24g4oCTIG5vbi1lbmFibGUtdG9rZW4nLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCByb3V0ZSB0byBjb25maWRlbnRpYWwgdHJhbnNmZXIgcGF0aCB3aGVuIHR5cGUgaXMgbm90IGVuYWJsZXRva2VuJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gTm9uLWVuYWJsZXRva2VuIHRyYW5zYWN0aW9ucyByb3V0ZSB0byB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2Zlci5cbiAgICAgIC8vIEVtcHR5IHJlY2lwaWVudHMgdHJpZ2dlcnMgb3VyIEVSQzc5ODQtc3BlY2lmaWMgdmFsaWRhdGlvbiBlcnJvcixcbiAgICAgIC8vIGNvbmZpcm1pbmcgdGhlIG92ZXJyaWRlIG9ubHkgaW50ZXJjZXB0cyB0aGUgZW5hYmxldG9rZW4gdHlwZS5cbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbXSB9LFxuICAgICAgICAgIHR4UHJlYnVpbGQ6IHt9IGFzIGFueSxcbiAgICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3JlY2lwaWVudHMgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZSBlbnRyeS8pO1xuICAgIH0pO1xuICB9KTtcblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIGRlc2NyaWJlKCd2ZXJpZnlUcmFuc2FjdGlvbiDigJMgVFNTIHBhdGgnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgYSB2YWxpZCBzaW5nbGUtdG9rZW4gZGVsZWdhdGlvbiB0eCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREZWxlZ2F0aW9uVHhIZXgoWkFNQV9BQ0xfQUREUkVTUywgW0NURVNUMV9UT0tFTl9BRERSRVNTXSk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfV0sXG4gICAgICAgIH0sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSBhcyBhbnksXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICB3YWxsZXRUeXBlOiAndHNzJyxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IGEgdmFsaWQgbXVsdGktdG9rZW4gZGVsZWdhdGlvbiB0eCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREZWxlZ2F0aW9uVHhIZXgoWkFNQV9BQ0xfQUREUkVTUywgW0NURVNUMV9UT0tFTl9BRERSRVNTLCBDVVNEVF9UT0tFTl9BRERSRVNTXSk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfSwgeyBuYW1lOiAnaHRldGg6Y3VzZHQnIH1dLFxuICAgICAgICB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0VHlwZTogJ3RzcycsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gQUNMIGFkZHJlc3MgZG9lcyBub3QgbWF0Y2gnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkRGVsZWdhdGlvblR4SGV4KFdST05HX0FDTF9BRERSRVNTLCBbQ1RFU1QxX1RPS0VOX0FERFJFU1NdKTtcbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICd0c3MnLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvZG9lcyBub3QgbWF0Y2ggQUNMIGNvbnRyYWN0Lyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gY2FsbGRhdGEgY29udGFpbnMgd3JvbmcgdG9rZW4gYWRkcmVzcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREZWxlZ2F0aW9uVHhIZXgoWkFNQV9BQ0xfQUREUkVTUywgW1dST05HX1RPS0VOX0FERFJFU1NdKTtcbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICd0c3MnLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvbm90IGZvdW5kIGluIGRlbGVnYXRpb24gY2FsbGRhdGEvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IGEgdmFsaWQgZm9yd2FyZGVyIGRlbGVnYXRpb24gdHggKGNhbGxGcm9tUGFyZW50IHNoYXBlKScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGRGb3J3YXJkZXJEZWxlZ2F0aW9uVHhIZXgoRk9SV0FSREVSX0FERFJFU1MsIFpBTUFfQUNMX0FERFJFU1MsIFtDVEVTVDFfVE9LRU5fQUREUkVTU10pO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdodGV0aDpjdGVzdDEnIH1dLFxuICAgICAgICB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0VHlwZTogJ3RzcycsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZlcmlmeSBhIGZvcndhcmRlciBkZWxlZ2F0aW9uIHR4IHdpdGggbXVsdGlwbGUgdG9rZW5zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZEZvcndhcmRlckRlbGVnYXRpb25UeEhleChGT1JXQVJERVJfQUREUkVTUywgWkFNQV9BQ0xfQUREUkVTUywgW1xuICAgICAgICBDVEVTVDFfVE9LRU5fQUREUkVTUyxcbiAgICAgICAgQ1VTRFRfVE9LRU5fQUREUkVTUyxcbiAgICAgIF0pO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdodGV0aDpjdGVzdDEnIH0sIHsgbmFtZTogJ2h0ZXRoOmN1c2R0JyB9XSxcbiAgICAgICAgfSxcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgIHdhbGxldFR5cGU6ICd0c3MnLFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGZvcndhcmRlciBjYWxsZGF0YSBjb250YWlucyB3cm9uZyB0b2tlbiBhZGRyZXNzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZEZvcndhcmRlckRlbGVnYXRpb25UeEhleChGT1JXQVJERVJfQUREUkVTUywgWkFNQV9BQ0xfQUREUkVTUywgW1dST05HX1RPS0VOX0FERFJFU1NdKTtcbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICd0c3MnLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvbm90IGZvdW5kIGluIGRlbGVnYXRpb24gY2FsbGRhdGEvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiBjYWxsZGF0YSBoYXMgdW5yZWNvZ25pc2VkIG1ldGhvZCBJRCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIEJ1aWxkIGEgdHggd2l0aCBhcmJpdHJhcnkgY2FsbGRhdGEgdGhhdCBpcyBuZWl0aGVyIG11bHRpY2FsbCBub3IgY2FsbEZyb21QYXJlbnRcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGdldEJ1aWxkZXIoJ2h0ZXRoJykgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICAgICAgdHhCdWlsZGVyLmZlZSh7IGZlZTogJzEwMDAwMDAwMDAnLCBnYXNMaW1pdDogJzIwMDAwMCcgfSk7XG4gICAgICB0eEJ1aWxkZXIuY291bnRlcigxKTtcbiAgICAgIHR4QnVpbGRlci50eXBlKFRyYW5zYWN0aW9uVHlwZS5Db250cmFjdENhbGwpO1xuICAgICAgdHhCdWlsZGVyLmNvbnRyYWN0KFpBTUFfQUNMX0FERFJFU1MpO1xuICAgICAgdHhCdWlsZGVyLmRhdGEoJzB4ZGVhZGJlZWYnKTtcbiAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCB0eEhleCA9IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICd0c3MnLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvdW5yZWNvZ25pc2VkIGNhbGxkYXRhIG1ldGhvZCBJRC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIHRyYW5zYWN0aW9uIHZhbHVlIGlzIG5vdCAwJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZERlbGVnYXRpb25UeEhleChaQU1BX0FDTF9BRERSRVNTLCBbQ1RFU1QxX1RPS0VOX0FERFJFU1NdLCAnMScpO1xuICAgICAgYXdhaXQgY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAnaHRldGg6Y3Rlc3QxJyB9XSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSBhcyBhbnksXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgICAgd2FsbGV0VHlwZTogJ3RzcycsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9leHBlY3RlZCB0cmFuc2FjdGlvbiB2YWx1ZSAwLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gZW5hYmxlVG9rZW5zIGlzIGVtcHR5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZERlbGVnYXRpb25UeEhleChaQU1BX0FDTF9BRERSRVNTLCBbQ1RFU1QxX1RPS0VOX0FERFJFU1NdKTtcbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW10sXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICd0c3MnLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvZW5hYmxlVG9rZW5zIG11c3QgYmUgbm9uLWVtcHR5Lyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdHhIZXggaXMgbWlzc2luZycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ2h0ZXRoOmN0ZXN0MScgfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7fSBhcyBhbnksXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgICAgd2FsbGV0VHlwZTogJ3RzcycsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9taXNzaW5nIHR4SGV4Lyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgZGVzY3JpYmUoJ3ZlcmlmeVRyYW5zYWN0aW9uIOKAkyBtdWx0aXNpZyBwYXRoJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHZhbGlkIGJ1aWxkUGFyYW1zIHJlY2lwaWVudHMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgIHJlY2lwaWVudHM6IFt7IHRva2VuTmFtZTogJ2h0ZXRoOmN0ZXN0MScsIGFkZHJlc3M6ICcweGFiYycsIGFtb3VudDogJzAnIH1dIGFzIGFueSxcbiAgICAgICAgfSxcbiAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgIGJ1aWxkUGFyYW1zOiB7XG4gICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgICAgcmVjaXBpZW50czogW3sgdG9rZW5OYW1lOiAnaHRldGg6Y3Rlc3QxJywgYWRkcmVzczogJzB4YWJjJywgYW1vdW50OiAnMCcgfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSBhcyBhbnksXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICB3YWxsZXRUeXBlOiAnb25jaGFpbicsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZlcmlmeSBtdWx0aXBsZSB0b2tlbiByZWNpcGllbnRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAgICB7IHRva2VuTmFtZTogJ2h0ZXRoOmN0ZXN0MScsIGFkZHJlc3M6ICcweGFiYycsIGFtb3VudDogJzAnIH0sXG4gICAgICAgICAgICB7IHRva2VuTmFtZTogJ2h0ZXRoOmN1c2R0JywgYWRkcmVzczogJzB4YWJjJywgYW1vdW50OiAnMCcgfSxcbiAgICAgICAgICBdIGFzIGFueSxcbiAgICAgICAgfSxcbiAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgIGJ1aWxkUGFyYW1zOiB7XG4gICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgICAgcmVjaXBpZW50czogW1xuICAgICAgICAgICAgICB7IHRva2VuTmFtZTogJ2h0ZXRoOmN0ZXN0MScsIGFkZHJlc3M6ICcweGFiYycsIGFtb3VudDogJzAnIH0sXG4gICAgICAgICAgICAgIHsgdG9rZW5OYW1lOiAnaHRldGg6Y3VzZHQnLCBhZGRyZXNzOiAnMHhhYmMnLCBhbW91bnQ6ICcwJyB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgIHdhbGxldFR5cGU6ICdvbmNoYWluJyxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiBidWlsZFBhcmFtcyByZWNpcGllbnRzIGhhdmUgd3JvbmcgdG9rZW5OYW1lJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgICAgcmVjaXBpZW50czogW3sgdG9rZW5OYW1lOiAnaHRldGg6Y3Rlc3QxJywgYWRkcmVzczogJzB4YWJjJywgYW1vdW50OiAnMCcgfV0gYXMgYW55LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgYnVpbGRQYXJhbXM6IHtcbiAgICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgICAgcmVjaXBpZW50czogW3sgdG9rZW5OYW1lOiAnaHRldGg6d3Jvbmd0b2tlbicsIGFkZHJlc3M6ICcweGFiYycsIGFtb3VudDogJzAnIH1dLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgICAgICB3YWxsZXRUeXBlOiAnb25jaGFpbicsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9ub3QgZm91bmQgaW4gYnVpbGRQYXJhbXMgcmVjaXBpZW50cy8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGFtb3VudCBpcyBub3QgMCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIHJlY2lwaWVudHM6IFt7IHRva2VuTmFtZTogJ2h0ZXRoOmN0ZXN0MScsIGFkZHJlc3M6ICcweGFiYycsIGFtb3VudDogJzAnIH1dIGFzIGFueSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICAgIGJ1aWxkUGFyYW1zOiB7XG4gICAgICAgICAgICAgIHR5cGU6ICdlbmFibGV0b2tlbicsXG4gICAgICAgICAgICAgIHJlY2lwaWVudHM6IFt7IHRva2VuTmFtZTogJ2h0ZXRoOmN0ZXN0MScsIGFkZHJlc3M6ICcweGFiYycsIGFtb3VudDogJzEwMCcgfV0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICdvbmNoYWluJyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2V4cGVjdGVkIGFtb3VudCAwLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gcmVjaXBpZW50cyBpcyBtaXNzaW5nJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgYnVpbGRQYXJhbXM6IHt9LFxuICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIHdhbGxldFR5cGU6ICdvbmNoYWluJyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL21pc3NpbmcgYnVpbGRQYXJhbXMucmVjaXBpZW50cy8pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIHZlcmlmeVRyYW5zYWN0aW9uIOKAkyBjb25maWRlbnRpYWwgdHJhbnNmZXIgKFNlbmRFUkM3OTg0KSB0ZXN0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogQnVpbGQgYSByYXcgc2lnbmVkIHNlbmRNdWx0aVNpZyB0eCBoZXggdGhhdCB3cmFwcyBhIGNvbmZpZGVudGlhbFRyYW5zZmVyIGNhbGwuXG4gKiBUaGUgd2FsbGV0IGNvbnRyYWN0IChzZW5kTXVsdGlTaWcgd3JhcHBlcikgaXMgYHdhbGxldENvbnRyYWN0QWRkcmVzc2AuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkQ29uZmlkZW50aWFsVHJhbnNmZXJUeEhleChvcHRzOiB7XG4gIHdhbGxldENvbnRyYWN0QWRkcmVzczogc3RyaW5nO1xuICB0b2tlbkNvbnRyYWN0QWRkcmVzczogc3RyaW5nO1xuICByZWNpcGllbnRBZGRyZXNzOiBzdHJpbmc7XG4gIGVuY3J5cHRlZEhhbmRsZTogc3RyaW5nO1xuICBpbnB1dFByb29mOiBzdHJpbmc7XG59KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3Qga2V5ID0gdGVzdERhdGEuS0VZUEFJUl9QUlYuZ2V0S2V5cygpLnBydiBhcyBzdHJpbmc7XG4gIGNvbnN0IHR4QnVpbGRlciA9IGdldEJ1aWxkZXIoJ2h0ZXRoJykgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICB0eEJ1aWxkZXIuZmVlKHsgZmVlOiAnMTAwMDAwMDAwMCcsIGdhc0xpbWl0OiAnMTIxMDAwMDAnIH0pO1xuICB0eEJ1aWxkZXIuY291bnRlcigxKTtcbiAgdHhCdWlsZGVyLmNvbnRyYWN0KG9wdHMud2FsbGV0Q29udHJhY3RBZGRyZXNzKTtcbiAgdHhCdWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLlNlbmRFUkM3OTg0KTtcblxuICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSB0eEJ1aWxkZXIudHJhbnNmZXIoKSBhcyBUcmFuc2ZlckJ1aWxkZXJFUkM3OTg0O1xuICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAuZnJvbSgnMHgxOTY0NTAzMmM3ZjE1MzMzOTVkNDRhNjI5NDYyZTc1MTA4NGQzZTRkJylcbiAgICAudG8ob3B0cy5yZWNpcGllbnRBZGRyZXNzKVxuICAgIC50b2tlbkNvbnRyYWN0QWRkcmVzcyhvcHRzLnRva2VuQ29udHJhY3RBZGRyZXNzKVxuICAgIC5lbmNyeXB0ZWRIYW5kbGUob3B0cy5lbmNyeXB0ZWRIYW5kbGUpXG4gICAgLmlucHV0UHJvb2Yob3B0cy5pbnB1dFByb29mKVxuICAgIC5jb250cmFjdFNlcXVlbmNlSWQoMSlcbiAgICAuZXhwaXJhdGlvblRpbWUoTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkgKyAzNjAwKVxuICAgIC5rZXkoa2V5KTtcblxuICB0eEJ1aWxkZXIuc2lnbih7IGtleTogdGVzdERhdGEuUFJJVkFURV9LRVkgfSk7XG4gIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIHJldHVybiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xufVxuXG5kZXNjcmliZSgndmVyaWZ5VHJhbnNhY3Rpb24g4oCTIGNvbmZpZGVudGlhbCB0cmFuc2ZlciAoU2VuZEVSQzc5ODQpJywgZnVuY3Rpb24gKCkge1xuICAvLyBXYWxsZXQgY29udHJhY3QgdGhhdCB3cmFwcyB0aGUgc2VuZE11bHRpU2lnIGNhbGxcbiAgY29uc3QgV0FMTEVUX0NPTlRSQUNUID0gJzB4OGY5NzdlOTEyZWY1MDA1NDhhMGMzYmU2ZGRkZTk4OTlmMTE5OWI4MSc7XG4gIC8vIFJlY2lwaWVudCBvZiB0aGUgY29uZmlkZW50aWFsIHRyYW5zZmVyXG4gIGNvbnN0IFJFQ0lQSUVOVCA9ICcweDE5NjQ1MDMyYzdmMTUzMzM5NWQ0NGE2Mjk0NjJlNzUxMDg0ZDNlNGMnO1xuICAvLyBFbmNyeXB0ZWQgaGFuZGxlOiBzeW50aGV0aWMgMzIgYnl0ZXNcbiAgY29uc3QgSEFORExFID0gJzB4JyArICdhYicucmVwZWF0KDMyKTtcbiAgLy8gSW5wdXQgcHJvb2Y6IHN5bnRoZXRpYyA1MCBieXRlc1xuICBjb25zdCBQUk9PRiA9ICcweCcgKyAnY2QnLnJlcGVhdCg1MCk7XG4gIC8vIEEgZGlmZmVyZW50IHJlY2lwaWVudCB0byB0cmlnZ2VyIG1pc21hdGNoXG4gIGNvbnN0IFdST05HX1JFQ0lQSUVOVCA9ICcweGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEnO1xuICAvLyBBIGRpZmZlcmVudCB0b2tlbiBjb250cmFjdCB0byB0cmlnZ2VyIG1pc21hdGNoXG4gIGNvbnN0IFdST05HX1RPS0VOID0gJzB4YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYic7XG5cbiAgbGV0IGJpdGdvOiBUZXN0Qml0R29BUEk7XG4gIGxldCBjb2luOiBFcmM3OTg0VG9rZW47XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICd0ZXN0JyB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICByZWdpc3RlcihiaXRnbyk7XG4gICAgY29pbiA9IGJpdGdvLmNvaW4oJ2h0ZXRoOmN0ZXN0MScpIGFzIEVyYzc5ODRUb2tlbjtcbiAgfSk7XG5cbiAgLy8gUmVwcmVzZW50YXRpdmUgcGxhaW50ZXh0IGFtb3VudCBpbiBiYXNlIHVuaXRzIChlLmcuLCAxIGNURVNUMSA9IDFfMDAwXzAwMCB1bml0cyBhdCA2IGRlY2ltYWxzKVxuICBjb25zdCBBTU9VTlQgPSAnMTAwMDAwMCc7XG5cbiAgaXQoJ3Nob3VsZCB2ZXJpZnkgYSB2YWxpZCBjb25maWRlbnRpYWwgdHJhbnNmZXIgdHJhbnNhY3Rpb24gd2l0aCBtYXRjaGluZyBhbW91bnRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGRDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogV0FMTEVUX0NPTlRSQUNULFxuICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IENURVNUMV9UT0tFTl9BRERSRVNTLFxuICAgICAgcmVjaXBpZW50QWRkcmVzczogUkVDSVBJRU5ULFxuICAgICAgZW5jcnlwdGVkSGFuZGxlOiBIQU5ETEUsXG4gICAgICBpbnB1dFByb29mOiBQUk9PRixcbiAgICB9KTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgdHhQcmVidWlsZDogeyB0eEhleCwgYnVpbGRQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9IH0gYXMgYW55LFxuICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgfSk7XG4gICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIG5vIHJlY2lwaWVudCBpbmZvIGlzIHByb3ZpZGVkIGluIGVpdGhlciB0eFBhcmFtcyBvciBidWlsZFBhcmFtcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkQ29uZmlkZW50aWFsVHJhbnNmZXJUeEhleCh7XG4gICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IFdBTExFVF9DT05UUkFDVCxcbiAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBDVEVTVDFfVE9LRU5fQUREUkVTUyxcbiAgICAgIHJlY2lwaWVudEFkZHJlc3M6IFJFQ0lQSUVOVCxcbiAgICAgIGVuY3J5cHRlZEhhbmRsZTogSEFORExFLFxuICAgICAgaW5wdXRQcm9vZjogUFJPT0YsXG4gICAgfSk7XG5cbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczoge30sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSBhcyBhbnksXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgfSlcbiAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9taXNzaW5nIGV4cGVjdGVkIHJlY2lwaWVudC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHZlcmlmeSBzdWNjZXNzZnVsbHkgdXNpbmcgYnVpbGRQYXJhbXMucmVjaXBpZW50cyB3aGVuIHR4UGFyYW1zIGhhcyBubyByZWNpcGllbnRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGRDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogV0FMTEVUX0NPTlRSQUNULFxuICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IENURVNUMV9UT0tFTl9BRERSRVNTLFxuICAgICAgcmVjaXBpZW50QWRkcmVzczogUkVDSVBJRU5ULFxuICAgICAgZW5jcnlwdGVkSGFuZGxlOiBIQU5ETEUsXG4gICAgICBpbnB1dFByb29mOiBQUk9PRixcbiAgICB9KTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgdHhQYXJhbXM6IHt9LFxuICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICB0eEhleCxcbiAgICAgICAgYnVpbGRQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgfSBhcyBhbnksXG4gICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICB9KTtcbiAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdG9rZW4gY29udHJhY3QgYWRkcmVzcyBkb2VzIG5vdCBtYXRjaCB0aGlzIGNvaW4nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZENvbmZpZGVudGlhbFRyYW5zZmVyVHhIZXgoe1xuICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBXQUxMRVRfQ09OVFJBQ1QsXG4gICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogV1JPTkdfVE9LRU4sXG4gICAgICByZWNpcGllbnRBZGRyZXNzOiBSRUNJUElFTlQsXG4gICAgICBlbmNyeXB0ZWRIYW5kbGU6IEhBTkRMRSxcbiAgICAgIGlucHV0UHJvb2Y6IFBST09GLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvdG9rZW4gY29udHJhY3QgYWRkcmVzcyBtaXNtYXRjaC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gcmVjaXBpZW50IGFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggdHhQYXJhbXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZENvbmZpZGVudGlhbFRyYW5zZmVyVHhIZXgoe1xuICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBXQUxMRVRfQ09OVFJBQ1QsXG4gICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogQ1RFU1QxX1RPS0VOX0FERFJFU1MsXG4gICAgICByZWNpcGllbnRBZGRyZXNzOiBSRUNJUElFTlQsXG4gICAgICBlbmNyeXB0ZWRIYW5kbGU6IEhBTkRMRSxcbiAgICAgIGlucHV0UHJvb2Y6IFBST09GLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogV1JPTkdfUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvcmVjaXBpZW50IGFkZHJlc3MgbWlzbWF0Y2gvKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGNhbGxkYXRhIGlzIG5vdCBhIGNvbmZpZGVudGlhbCB0cmFuc2ZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBnZXRCdWlsZGVyKCdodGV0aCcpIGFzIFRyYW5zYWN0aW9uQnVpbGRlcjtcbiAgICB0eEJ1aWxkZXIuZmVlKHsgZmVlOiAnMTAwMDAwMDAwMCcsIGdhc0xpbWl0OiAnMjAwMDAwJyB9KTtcbiAgICB0eEJ1aWxkZXIuY291bnRlcigxKTtcbiAgICB0eEJ1aWxkZXIudHlwZShUcmFuc2FjdGlvblR5cGUuQ29udHJhY3RDYWxsKTtcbiAgICB0eEJ1aWxkZXIuY29udHJhY3QoV0FMTEVUX0NPTlRSQUNUKTtcbiAgICB0eEJ1aWxkZXIuZGF0YSgnMHhkZWFkYmVlZjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyk7XG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCB0eEhleCA9IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSBhcyBhbnksXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgfSlcbiAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9mYWlsZWQgdG8gZGVjb2RlIGNvbmZpZGVudGlhbCB0cmFuc2ZlciBjYWxsZGF0YS8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdHhQYXJhbXMgYW1vdW50IGRvZXMgbm90IG1hdGNoIGJ1aWxkUGFyYW1zIGFtb3VudCAod2l0aCB0eEhleCknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZENvbmZpZGVudGlhbFRyYW5zZmVyVHhIZXgoe1xuICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBXQUxMRVRfQ09OVFJBQ1QsXG4gICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogQ1RFU1QxX1RPS0VOX0FERFJFU1MsXG4gICAgICByZWNpcGllbnRBZGRyZXNzOiBSRUNJUElFTlQsXG4gICAgICBlbmNyeXB0ZWRIYW5kbGU6IEhBTkRMRSxcbiAgICAgIGlucHV0UHJvb2Y6IFBST09GLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6ICc5OTk5OTk5JyB9XSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgdHhIZXgsXG4gICAgICAgICAgYnVpbGRQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2Ftb3VudCBtaXNtYXRjaC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdHhQYXJhbXMgYW1vdW50IGlzIDAgKHdpdGggdHhIZXgpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGRDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogV0FMTEVUX0NPTlRSQUNULFxuICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IENURVNUMV9UT0tFTl9BRERSRVNTLFxuICAgICAgcmVjaXBpZW50QWRkcmVzczogUkVDSVBJRU5ULFxuICAgICAgZW5jcnlwdGVkSGFuZGxlOiBIQU5ETEUsXG4gICAgICBpbnB1dFByb29mOiBQUk9PRixcbiAgICB9KTtcblxuICAgIGF3YWl0IGNvaW5cbiAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zOiB7IHJlY2lwaWVudHM6IFt7IGFkZHJlc3M6IFJFQ0lQSUVOVCwgYW1vdW50OiAnMCcgfV0gfSxcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2Ftb3VudCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciBzdHJpbmcvKTtcbiAgfSk7XG5cbiAgLy8g4pSA4pSAIEZpcnN0LXNpZ25lciAobm8gdHhIZXgpIHRlc3RzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGl0KCdzaG91bGQgdmVyaWZ5IHZhbGlkIGZpcnN0LXNpZ25lciBwYXJhbXMgd2hlbiBubyB0eEhleCBpcyBwcmVzZW50JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgdHhQcmVidWlsZDoge30gYXMgYW55LFxuICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgfSk7XG4gICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB2ZXJpZnkgZmlyc3Qtc2lnbmVyIHBhcmFtcyB3aGVuIHR4UGFyYW1zIGFuZCBidWlsZFBhcmFtcyBhbW91bnRzIG1hdGNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgdHhQcmVidWlsZDogeyBidWlsZFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0gfSBhcyBhbnksXG4gICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICB9KTtcbiAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gcmVjaXBpZW50cyBpcyBlbXB0eSBhbmQgbm8gdHhIZXggaXMgcHJlc2VudCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbXSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7fSBhcyBhbnksXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgfSlcbiAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9yZWNpcGllbnRzIG11c3QgY29udGFpbiBhdCBsZWFzdCBvbmUgZW50cnkvKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIHJlY2lwaWVudCBhZGRyZXNzIGlzIGludmFsaWQgYW5kIG5vIHR4SGV4IGlzIHByZXNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogJ25vdC1hbi1hZGRyZXNzJywgYW1vdW50OiBBTU9VTlQgfV0gfSxcbiAgICAgICAgdHhQcmVidWlsZDoge30gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvcmVjaXBpZW50IGFkZHJlc3MgaXMgbWlzc2luZyBvciBpbnZhbGlkLyk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdGhyb3cgd2hlbiBhbW91bnQgaXMgMCBhbmQgbm8gdHhIZXggaXMgcHJlc2VudCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogJzAnIH1dIH0sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHt9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2Ftb3VudCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciBzdHJpbmcvKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGFtb3VudCBpcyBlbXB0eSBhbmQgbm8gdHhIZXggaXMgcHJlc2VudCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogJycgfV0gfSxcbiAgICAgICAgdHhQcmVidWlsZDoge30gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvYW1vdW50IG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIHN0cmluZy8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdHhQYXJhbXMgYW5kIGJ1aWxkUGFyYW1zIGFtb3VudHMgbWlzbWF0Y2ggYW5kIG5vIHR4SGV4IGlzIHByZXNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6ICc5OTk5OTk5JyB9XSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IGJ1aWxkUGFyYW1zOiB7IHJlY2lwaWVudHM6IFt7IGFkZHJlc3M6IFJFQ0lQSUVOVCwgYW1vdW50OiBBTU9VTlQgfV0gfSB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2Ftb3VudCBtaXNtYXRjaC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdHhQYXJhbXMgYW5kIGJ1aWxkUGFyYW1zIHJlY2lwaWVudCBhZGRyZXNzZXMgbWlzbWF0Y2ggYW5kIG5vIHR4SGV4IGlzIHByZXNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgYnVpbGRQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogV1JPTkdfUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3JlY2lwaWVudCBhZGRyZXNzIG1pc21hdGNoLyk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdmVyaWZ5IHdoZW4gdHhIZXggYWJzZW50IGFuZCBidWlsZFBhcmFtcyBoYXMgbWF0Y2hpbmcgcmVjaXBpZW50IGFkZHJlc3MnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0sXG4gICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgIGJ1aWxkUGFyYW1zOiB7IHJlY2lwaWVudHM6IFt7IGFkZHJlc3M6IFJFQ0lQSUVOVCwgYW1vdW50OiBBTU9VTlQgfV0gfSxcbiAgICAgIH0gYXMgYW55LFxuICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgfSk7XG4gICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB2ZXJpZnkgZGVjb2RlZCByZWNpcGllbnQgYWdhaW5zdCBidWlsZFBhcmFtcyB3aGVuIHR4UGFyYW1zLnJlY2lwaWVudHMgaXMgYWJzZW50JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGRDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogV0FMTEVUX0NPTlRSQUNULFxuICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IENURVNUMV9UT0tFTl9BRERSRVNTLFxuICAgICAgcmVjaXBpZW50QWRkcmVzczogUkVDSVBJRU5ULFxuICAgICAgZW5jcnlwdGVkSGFuZGxlOiBIQU5ETEUsXG4gICAgICBpbnB1dFByb29mOiBQUk9PRixcbiAgICB9KTtcblxuICAgIC8vIE5vIHJlY2lwaWVudHMgaW4gdHhQYXJhbXMg4oCUIGZhbGxzIGJhY2sgdG8gYnVpbGRQYXJhbXMgZm9yIHJlY2lwaWVudCB2ZXJpZmljYXRpb25cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiB7fSxcbiAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgdHhIZXgsXG4gICAgICAgIGJ1aWxkUGFyYW1zOiB7IHJlY2lwaWVudHM6IFt7IGFkZHJlc3M6IFJFQ0lQSUVOVCwgYW1vdW50OiBBTU9VTlQgfV0gfSxcbiAgICAgIH0gYXMgYW55LFxuICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgfSk7XG4gICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGRlY29kZWQgcmVjaXBpZW50IGRvZXMgbm90IG1hdGNoIGJ1aWxkUGFyYW1zIHJlY2lwaWVudCAodHhQYXJhbXMgYWJzZW50KScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkQ29uZmlkZW50aWFsVHJhbnNmZXJUeEhleCh7XG4gICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IFdBTExFVF9DT05UUkFDVCxcbiAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBDVEVTVDFfVE9LRU5fQUREUkVTUyxcbiAgICAgIHJlY2lwaWVudEFkZHJlc3M6IFJFQ0lQSUVOVCxcbiAgICAgIGVuY3J5cHRlZEhhbmRsZTogSEFORExFLFxuICAgICAgaW5wdXRQcm9vZjogUFJPT0YsXG4gICAgfSk7XG5cbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczoge30sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICB0eEhleCxcbiAgICAgICAgICBidWlsZFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBXUk9OR19SRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvcmVjaXBpZW50IGFkZHJlc3MgbWlzbWF0Y2gvKTtcbiAgfSk7XG59KTtcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyB2ZXJpZnlUcmFuc2FjdGlvbiDigJMgZGlyZWN0IGNvbmZpZGVudGlhbFRyYW5zZmVyIChob3QvVFNTIEVPQSB3YWxsZXQpIHRlc3RzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBCdWlsZHMgYSByYXcgdHggaGV4IHdoZXJlIHRoZSBFT0EgY2FsbHMgY29uZmlkZW50aWFsVHJhbnNmZXIgZGlyZWN0bHkgb24gdGhlIHRva2VuXG4gKiBjb250cmFjdCAobm8gc2VuZE11bHRpU2lnIHdyYXBwZXIpLiBUaGlzIGlzIHRoZSBob3QvVFNTIHdhbGxldCBwYXRoLlxuICovXG5hc3luYyBmdW5jdGlvbiBidWlsZERpcmVjdENvbmZpZGVudGlhbFRyYW5zZmVyVHhIZXgob3B0czoge1xuICB0b2tlbkNvbnRyYWN0QWRkcmVzczogc3RyaW5nO1xuICByZWNpcGllbnRBZGRyZXNzOiBzdHJpbmc7XG4gIGVuY3J5cHRlZEhhbmRsZTogc3RyaW5nO1xuICBpbnB1dFByb29mOiBzdHJpbmc7XG59KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgdHhCdWlsZGVyID0gZ2V0QnVpbGRlcignaHRldGgnKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gIHR4QnVpbGRlci5mZWUoeyBmZWU6ICcxMDAwMDAwMDAwJywgZ2FzTGltaXQ6ICcyMDAwMDAnIH0pO1xuICB0eEJ1aWxkZXIuY291bnRlcigxKTtcbiAgdHhCdWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbCk7XG4gIC8vIHR4LnRvID0gdG9rZW4gY29udHJhY3QgKEVPQSBjYWxscyBpdCBkaXJlY3RseSlcbiAgdHhCdWlsZGVyLmNvbnRyYWN0KG9wdHMudG9rZW5Db250cmFjdEFkZHJlc3MpO1xuICAvLyBJbm5lciBjYWxsZGF0YTogY29uZmlkZW50aWFsVHJhbnNmZXIoYWRkcmVzcywgYnl0ZXMzMiwgYnl0ZXMpIOKAlCBubyBzZW5kTXVsdGlTaWcgd3JhcHBlclxuICBjb25zdCBjYWxsZGF0YSA9IG5ldyBUcmFuc2ZlckJ1aWxkZXJFUkM3OTg0KClcbiAgICAudG8ob3B0cy5yZWNpcGllbnRBZGRyZXNzKVxuICAgIC50b2tlbkNvbnRyYWN0QWRkcmVzcyhvcHRzLnRva2VuQ29udHJhY3RBZGRyZXNzKVxuICAgIC5lbmNyeXB0ZWRIYW5kbGUob3B0cy5lbmNyeXB0ZWRIYW5kbGUpXG4gICAgLmlucHV0UHJvb2Yob3B0cy5pbnB1dFByb29mKVxuICAgIC5idWlsZCgpO1xuICB0eEJ1aWxkZXIuZGF0YShjYWxsZGF0YSk7XG4gIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIHJldHVybiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xufVxuXG5kZXNjcmliZSgndmVyaWZ5VHJhbnNhY3Rpb24g4oCTIGRpcmVjdCBjb25maWRlbnRpYWxUcmFuc2ZlciAoaG90L1RTUyBFT0Egd2FsbGV0KScsIGZ1bmN0aW9uICgpIHtcbiAgY29uc3QgUkVDSVBJRU5UID0gJzB4MTk2NDUwMzJjN2YxNTMzMzk1ZDQ0YTYyOTQ2MmU3NTEwODRkM2U0Yyc7XG4gIGNvbnN0IEhBTkRMRSA9ICcweCcgKyAnYWInLnJlcGVhdCgzMik7XG4gIGNvbnN0IFBST09GID0gJzB4JyArICdjZCcucmVwZWF0KDUwKTtcbiAgY29uc3QgV1JPTkdfUkVDSVBJRU5UID0gJzB4YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSc7XG4gIGNvbnN0IFdST05HX1RPS0VOID0gJzB4YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYic7XG4gIGNvbnN0IEFNT1VOVCA9ICcxMDAwMDAwJztcblxuICBsZXQgYml0Z286IFRlc3RCaXRHb0FQSTtcbiAgbGV0IGNvaW46IEVyYzc5ODRUb2tlbjtcblxuICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvQVBJLCB7IGVudjogJ3Rlc3QnIH0pO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIHJlZ2lzdGVyKGJpdGdvKTtcbiAgICBjb2luID0gYml0Z28uY29pbignaHRldGg6Y3Rlc3QxJykgYXMgRXJjNzk4NFRva2VuO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHZlcmlmeSBhIHZhbGlkIGRpcmVjdCBjb25maWRlbnRpYWxUcmFuc2ZlciB0eCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkRGlyZWN0Q29uZmlkZW50aWFsVHJhbnNmZXJUeEhleCh7XG4gICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogQ1RFU1QxX1RPS0VOX0FERFJFU1MsXG4gICAgICByZWNpcGllbnRBZGRyZXNzOiBSRUNJUElFTlQsXG4gICAgICBlbmNyeXB0ZWRIYW5kbGU6IEhBTkRMRSxcbiAgICAgIGlucHV0UHJvb2Y6IFBST09GLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgdHhQcmVidWlsZDogeyB0eEhleCwgYnVpbGRQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9IH0gYXMgYW55LFxuICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgfSk7XG4gICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB2ZXJpZnkgdXNpbmcgYnVpbGRQYXJhbXMucmVjaXBpZW50cyB3aGVuIHR4UGFyYW1zIGhhcyBubyByZWNpcGllbnRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREaXJlY3RDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBDVEVTVDFfVE9LRU5fQUREUkVTUyxcbiAgICAgIHJlY2lwaWVudEFkZHJlc3M6IFJFQ0lQSUVOVCxcbiAgICAgIGVuY3J5cHRlZEhhbmRsZTogSEFORExFLFxuICAgICAgaW5wdXRQcm9vZjogUFJPT0YsXG4gICAgfSk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICB0eFBhcmFtczoge30sXG4gICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgIHR4SGV4LFxuICAgICAgICBidWlsZFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0sXG4gICAgICB9IGFzIGFueSxcbiAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgIH0pO1xuICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdGhyb3cgd2hlbiB0b2tlbiBjb250cmFjdCBhZGRyZXNzICh0eC50bykgZG9lcyBub3QgbWF0Y2ggdGhpcyBjb2luJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREaXJlY3RDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBXUk9OR19UT0tFTixcbiAgICAgIHJlY2lwaWVudEFkZHJlc3M6IFJFQ0lQSUVOVCxcbiAgICAgIGVuY3J5cHRlZEhhbmRsZTogSEFORExFLFxuICAgICAgaW5wdXRQcm9vZjogUFJPT0YsXG4gICAgfSk7XG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogUkVDSVBJRU5ULCBhbW91bnQ6IEFNT1VOVCB9XSB9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvdG9rZW4gY29udHJhY3QgYWRkcmVzcyBtaXNtYXRjaC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gcmVjaXBpZW50IGFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggdHhQYXJhbXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZERpcmVjdENvbmZpZGVudGlhbFRyYW5zZmVyVHhIZXgoe1xuICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IENURVNUMV9UT0tFTl9BRERSRVNTLFxuICAgICAgcmVjaXBpZW50QWRkcmVzczogUkVDSVBJRU5ULFxuICAgICAgZW5jcnlwdGVkSGFuZGxlOiBIQU5ETEUsXG4gICAgICBpbnB1dFByb29mOiBQUk9PRixcbiAgICB9KTtcbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBXUk9OR19SRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSBhcyBhbnksXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgfSlcbiAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9yZWNpcGllbnQgYWRkcmVzcyBtaXNtYXRjaC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IHdoZW4gbm8gcmVjaXBpZW50IGluZm8gaXMgcHJvdmlkZWQgaW4gZWl0aGVyIHR4UGFyYW1zIG9yIGJ1aWxkUGFyYW1zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREaXJlY3RDb25maWRlbnRpYWxUcmFuc2ZlclR4SGV4KHtcbiAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBDVEVTVDFfVE9LRU5fQUREUkVTUyxcbiAgICAgIHJlY2lwaWVudEFkZHJlc3M6IFJFQ0lQSUVOVCxcbiAgICAgIGVuY3J5cHRlZEhhbmRsZTogSEFORExFLFxuICAgICAgaW5wdXRQcm9vZjogUFJPT0YsXG4gICAgfSk7XG4gICAgYXdhaXQgY29pblxuICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXM6IHt9LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvbWlzc2luZyBleHBlY3RlZCByZWNpcGllbnQvKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIHR4UGFyYW1zIGFtb3VudCBkb2VzIG5vdCBtYXRjaCBidWlsZFBhcmFtcyBhbW91bnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgdHhIZXggPSBhd2FpdCBidWlsZERpcmVjdENvbmZpZGVudGlhbFRyYW5zZmVyVHhIZXgoe1xuICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IENURVNUMV9UT0tFTl9BRERSRVNTLFxuICAgICAgcmVjaXBpZW50QWRkcmVzczogUkVDSVBJRU5ULFxuICAgICAgZW5jcnlwdGVkSGFuZGxlOiBIQU5ETEUsXG4gICAgICBpbnB1dFByb29mOiBQUk9PRixcbiAgICB9KTtcbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogJzk5OTk5OTknIH1dIH0sXG4gICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICB0eEhleCxcbiAgICAgICAgICBidWlsZFBhcmFtczogeyByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBSRUNJUElFTlQsIGFtb3VudDogQU1PVU5UIH1dIH0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvYW1vdW50IG1pc21hdGNoLyk7XG4gIH0pO1xufSk7XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gZGVjb2RlVG9rZW5BZGRyZXNzZXNGcm9tRGVsZWdhdGlvbkNhbGxkYXRhIHRlc3RzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuZGVzY3JpYmUoJ2RlY29kZVRva2VuQWRkcmVzc2VzRnJvbURlbGVnYXRpb25DYWxsZGF0YScsIGZ1bmN0aW9uICgpIHtcbiAgaXQoJ3Nob3VsZCBkZWNvZGUgYSBzaW5nbGUtdG9rZW4gbXVsdGljYWxsIGNhbGxkYXRhJywgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IGNhbGxkYXRhID0gYnVpbGRNdWx0aWNhbGxEZWxlZ2F0aW9uQ2FsbGRhdGEoREVMRUdBVEVfQUREUkVTUywgW0NURVNUMV9UT0tFTl9BRERSRVNTXSwgRVhQSVJZKTtcbiAgICBjb25zdCBhZGRyZXNzZXMgPSBkZWNvZGVUb2tlbkFkZHJlc3Nlc0Zyb21EZWxlZ2F0aW9uQ2FsbGRhdGEoY2FsbGRhdGEpO1xuICAgIGFkZHJlc3Nlcy5zaG91bGQuZGVlcEVxdWFsKFtDVEVTVDFfVE9LRU5fQUREUkVTUy50b0xvd2VyQ2FzZSgpXSk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgZGVjb2RlIGEgbXVsdGktdG9rZW4gbXVsdGljYWxsIGNhbGxkYXRhJywgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IGNhbGxkYXRhID0gYnVpbGRNdWx0aWNhbGxEZWxlZ2F0aW9uQ2FsbGRhdGEoXG4gICAgICBERUxFR0FURV9BRERSRVNTLFxuICAgICAgW0NURVNUMV9UT0tFTl9BRERSRVNTLCBDVVNEVF9UT0tFTl9BRERSRVNTXSxcbiAgICAgIEVYUElSWVxuICAgICk7XG4gICAgY29uc3QgYWRkcmVzc2VzID0gZGVjb2RlVG9rZW5BZGRyZXNzZXNGcm9tRGVsZWdhdGlvbkNhbGxkYXRhKGNhbGxkYXRhKTtcbiAgICBhZGRyZXNzZXMuc2hvdWxkLmRlZXBFcXVhbChbQ1RFU1QxX1RPS0VOX0FERFJFU1MudG9Mb3dlckNhc2UoKSwgQ1VTRFRfVE9LRU5fQUREUkVTUy50b0xvd2VyQ2FzZSgpXSk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIGFkZHJlc3NlcyBpbiBsb3dlcmNhc2UnLCBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgbWl4ZWRDYXNlID0gJzB4N0IxRDU5YmJDRDI5MWRhQTU5Y0I2QzhDNWJjMDREZTFBRkM0YUJBMSc7XG4gICAgY29uc3QgY2FsbGRhdGEgPSBidWlsZE11bHRpY2FsbERlbGVnYXRpb25DYWxsZGF0YShERUxFR0FURV9BRERSRVNTLCBbbWl4ZWRDYXNlXSwgRVhQSVJZKTtcbiAgICBjb25zdCBhZGRyZXNzZXMgPSBkZWNvZGVUb2tlbkFkZHJlc3Nlc0Zyb21EZWxlZ2F0aW9uQ2FsbGRhdGEoY2FsbGRhdGEpO1xuICAgIGFkZHJlc3Nlc1swXS5zaG91bGQuZXF1YWwobWl4ZWRDYXNlLnRvTG93ZXJDYXNlKCkpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGhhbmRsZSBjYWxsRnJvbVBhcmVudC13cmFwcGVkIG11bHRpY2FsbCBjYWxsZGF0YScsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBpbm5lciA9IGJ1aWxkTXVsdGljYWxsRGVsZWdhdGlvbkNhbGxkYXRhKFxuICAgICAgREVMRUdBVEVfQUREUkVTUyxcbiAgICAgIFtDVEVTVDFfVE9LRU5fQUREUkVTUywgQ1VTRFRfVE9LRU5fQUREUkVTU10sXG4gICAgICBFWFBJUllcbiAgICApO1xuICAgIGNvbnN0IHdyYXBwZWQgPSB3cmFwSW5DYWxsRnJvbVBhcmVudChaQU1BX0FDTF9BRERSRVNTLCBpbm5lcik7XG4gICAgY29uc3QgYWRkcmVzc2VzID0gZGVjb2RlVG9rZW5BZGRyZXNzZXNGcm9tRGVsZWdhdGlvbkNhbGxkYXRhKHdyYXBwZWQpO1xuICAgIGFkZHJlc3Nlcy5zaG91bGQuZGVlcEVxdWFsKFtDVEVTVDFfVE9LRU5fQUREUkVTUy50b0xvd2VyQ2FzZSgpLCBDVVNEVF9UT0tFTl9BRERSRVNTLnRvTG93ZXJDYXNlKCldKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB3b3JrIHdpdGggY2FsbGRhdGEgbWlzc2luZyAweCBwcmVmaXgnLCBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgY2FsbGRhdGEgPSBidWlsZE11bHRpY2FsbERlbGVnYXRpb25DYWxsZGF0YShERUxFR0FURV9BRERSRVNTLCBbQ1RFU1QxX1RPS0VOX0FERFJFU1NdLCBFWFBJUlkpO1xuICAgIGNvbnN0IG5vUHJlZml4ID0gY2FsbGRhdGEuc2xpY2UoMik7IC8vIHN0cmlwIDB4XG4gICAgY29uc3QgYWRkcmVzc2VzID0gZGVjb2RlVG9rZW5BZGRyZXNzZXNGcm9tRGVsZWdhdGlvbkNhbGxkYXRhKG5vUHJlZml4KTtcbiAgICBhZGRyZXNzZXMuc2hvdWxkLmRlZXBFcXVhbChbQ1RFU1QxX1RPS0VOX0FERFJFU1MudG9Mb3dlckNhc2UoKV0pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHRocm93IGZvciB1bnJlY29nbmlzZWQgY2FsbGRhdGEnLCBmdW5jdGlvbiAoKSB7XG4gICAgc2hvdWxkLnRocm93cyhcbiAgICAgICgpID0+IGRlY29kZVRva2VuQWRkcmVzc2VzRnJvbURlbGVnYXRpb25DYWxsZGF0YSgnMHhkZWFkYmVlZjAwMDAwMDAwJyksXG4gICAgICAvTm90IGEgdmFsaWQgZGVsZWdhdGlvbiBjYWxsZGF0YS9cbiAgICApO1xuICB9KTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIHZlcmlmeVRyYW5zYWN0aW9uIOKAkyBjb25maWRlbnRpYWwgY29uc29saWRhdGlvbiAoRmx1c2hFUkM3OTg0Rm9yd2FyZGVyVG9rZW4pXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuY29uc3QgTVVMVElTSUdfV0FMTEVUX0NPTlRSQUNUID0gJzB4M2I1ODY4NDUyNTU2NGIzOGEzODFlNDZhNzMxNzAzZWQwM2YzMjEyMic7XG5jb25zdCBDT05TT0xJREFUSU9OX0ZPUldBUkRFUiA9ICcweGY0YmNiMzY2YmI1ZTM0ZWJiZWU1MWZhZTVkZTk4Y2M4NzZjMDE0NmYnO1xuY29uc3QgQ09OU09MSURBVElPTl9CQVNFX0FERFJFU1MgPSAnMHgzYjU4Njg0NTI1NTY0YjM4YTM4MWU0NmE3MzE3MDNlZDAzZjMyMTIyJztcbmNvbnN0IENPTlNPTElEQVRJT05fSEFORExFID0gJzB4NjVkZjEzNmI2MDlhYjM5NWMxYTk5YWU0NmY3OTM5YzdmOGIyMGRmZjRiZmYwMDAwMDAwMDg4YmIwMDUwJztcbmNvbnN0IERVTU1ZX01VTFRJU0lHX1NJR05BVFVSRSA9ICcweCcgKyAnMDAnLnJlcGVhdCg2NSk7XG5cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkTXVsdGlzaWdDb25zb2xpZGF0aW9uVHhIZXgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgZmx1c2hDYWxsZGF0YSA9IGJ1aWxkRmx1c2hFUkM3OTg0Rm9yd2FyZGVyVG9rZW5DYWxsZGF0YShcbiAgICBDVEVTVDFfVE9LRU5fQUREUkVTUyxcbiAgICBDT05TT0xJREFUSU9OX0JBU0VfQUREUkVTUyxcbiAgICBDT05TT0xJREFUSU9OX0hBTkRMRVxuICApO1xuICBjb25zdCBzZW5kRGF0YSA9IHNlbmRNdWx0aVNpZ0RhdGEoXG4gICAgQ09OU09MSURBVElPTl9GT1JXQVJERVIsXG4gICAgJzAnLFxuICAgIGZsdXNoQ2FsbGRhdGEsXG4gICAgTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkgKyAzNjAwLFxuICAgIDE0LFxuICAgIERVTU1ZX01VTFRJU0lHX1NJR05BVFVSRVxuICApO1xuXG4gIGNvbnN0IHR4QnVpbGRlciA9IGdldEJ1aWxkZXIoJ2h0ZXRoJykgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICB0eEJ1aWxkZXIuZmVlKHsgZmVlOiAnMTAwMDAwMDAwMCcsIGdhc0xpbWl0OiAnMTIxMDAwMDAnIH0pO1xuICB0eEJ1aWxkZXIuY291bnRlcigxKTtcbiAgdHhCdWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbCk7XG4gIHR4QnVpbGRlci5jb250cmFjdChNVUxUSVNJR19XQUxMRVRfQ09OVFJBQ1QpO1xuICB0eEJ1aWxkZXIuZGF0YShzZW5kRGF0YSk7XG4gIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIHJldHVybiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBidWlsZERpcmVjdENvbnNvbGlkYXRpb25UeEhleCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB0eEJ1aWxkZXIgPSBnZXRCdWlsZGVyKCdodGV0aCcpIGFzIFRyYW5zYWN0aW9uQnVpbGRlcjtcbiAgdHhCdWlsZGVyLmZlZSh7IGZlZTogJzEwMDAwMDAwMDAnLCBnYXNMaW1pdDogJzIwMDAwMCcgfSk7XG4gIHR4QnVpbGRlci5jb3VudGVyKDEpO1xuICB0eEJ1aWxkZXIudHlwZShUcmFuc2FjdGlvblR5cGUuRmx1c2hFUkM3OTg0Rm9yd2FyZGVyVG9rZW4pO1xuICB0eEJ1aWxkZXIuY29udHJhY3QoQ09OU09MSURBVElPTl9GT1JXQVJERVIpO1xuICB0eEJ1aWxkZXIuZm9yd2FyZGVyQWRkcmVzcyhDT05TT0xJREFUSU9OX0ZPUldBUkRFUik7XG4gIHR4QnVpbGRlci50b2tlbkNvbnRyYWN0QWRkcmVzcyhDVEVTVDFfVE9LRU5fQUREUkVTUyk7XG4gIHR4QnVpbGRlci5wYXJlbnRBZGRyZXNzKENPTlNPTElEQVRJT05fQkFTRV9BRERSRVNTKTtcbiAgdHhCdWlsZGVyLmVuY3J5cHRlZEhhbmRsZShDT05TT0xJREFUSU9OX0hBTkRMRSk7XG4gIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIHJldHVybiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xufVxuXG5kZXNjcmliZSgndmVyaWZ5VHJhbnNhY3Rpb24g4oCTIGNvbmZpZGVudGlhbCBjb25zb2xpZGF0aW9uIChGbHVzaEVSQzc5ODRGb3J3YXJkZXJUb2tlbiknLCBmdW5jdGlvbiAoKSB7XG4gIGxldCBiaXRnbzogVGVzdEJpdEdvQVBJO1xuICBsZXQgY29pbjogRXJjNzk4NFRva2VuO1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R29BUEksIHsgZW52OiAndGVzdCcgfSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgcmVnaXN0ZXIoYml0Z28pO1xuICAgIGNvaW4gPSBiaXRnby5jb2luKCdodGV0aDpjdGVzdDEnKSBhcyBFcmM3OTg0VG9rZW47XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdmVyaWZ5IGEgdmFsaWQgbXVsdGlzaWcgY29uc29saWRhdGlvbiB0eCAoc2VuZE11bHRpU2lnIOKGkiBjYWxsRnJvbVBhcmVudCDihpIgY29uZmlkZW50aWFsVHJhbnNmZXJOb1Byb29mKScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkTXVsdGlzaWdDb25zb2xpZGF0aW9uVHhIZXgoKTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYmFzZUFkZHJlc3M6IENPTlNPTElEQVRJT05fQkFTRV9BRERSRVNTIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiB7IHR5cGU6ICdjb25zb2xpZGF0ZScgfSBhcyBhbnksXG4gICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgIGNvbnNvbGlkYXRlSWQ6ICc2YTQ0ZWJjMDMyNmUxYmU0NWMxZDc5NzU0MmM4YzYzNCcsXG4gICAgICAgIHR4SGV4LFxuICAgICAgICByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBDT05TT0xJREFUSU9OX0ZPUldBUkRFUiwgYW1vdW50OiAnMCcgfV0sXG4gICAgICB9IGFzIGFueSxcbiAgICAgIHdhbGxldCxcbiAgICB9KTtcbiAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHZlcmlmeSBhIHZhbGlkIGRpcmVjdCBjYWxsRnJvbVBhcmVudCBjb25zb2xpZGF0aW9uIHR4IChUU1Mgc2hhcGUpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREaXJlY3RDb25zb2xpZGF0aW9uVHhIZXgoKTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYmFzZUFkZHJlc3M6IENPTlNPTElEQVRJT05fQkFTRV9BRERSRVNTIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiB7IHR5cGU6ICdjb25zb2xpZGF0ZScgfSBhcyBhbnksXG4gICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgIGNvbnNvbGlkYXRlSWQ6ICc2YTQ0ZWJjMDMyNmUxYmU0NWMxZDc5NzU0MmM4YzYzNCcsXG4gICAgICAgIHR4SGV4LFxuICAgICAgfSBhcyBhbnksXG4gICAgICB3YWxsZXQsXG4gICAgICB2ZXJpZmljYXRpb246IHsgY29uc29saWRhdGlvblRvQmFzZUFkZHJlc3M6IHRydWUgfSxcbiAgICB9KTtcbiAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJlamVjdCBtdWx0aXNpZyBjb25zb2xpZGF0aW9uIHdoZW4gcGFyZW50IGFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggd2FsbGV0IGJhc2UgYWRkcmVzcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkTXVsdGlzaWdDb25zb2xpZGF0aW9uVHhIZXgoKTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYmFzZUFkZHJlc3M6ICcweGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEnIH0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczogeyB0eXBlOiAnY29uc29saWRhdGUnIH0gYXMgYW55LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IGNvbnNvbGlkYXRlSWQ6ICdhYmMxMjMnLCB0eEhleCB9IGFzIGFueSxcbiAgICAgICAgd2FsbGV0LFxuICAgICAgfSlcbiAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9wYXJlbnQgYWRkcmVzcyBtaXNtYXRjaC8pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHZlcmlmeSBtdWx0aXNpZyBjb25zb2xpZGF0aW9uIHVzaW5nIGZvcndhcmRlciBhZGRyZXNzIGZyb20gdHhQcmVidWlsZC50eEluZm8ucmVjaXBpZW50cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eEhleCA9IGF3YWl0IGJ1aWxkTXVsdGlzaWdDb25zb2xpZGF0aW9uVHhIZXgoKTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYmFzZUFkZHJlc3M6IENPTlNPTElEQVRJT05fQkFTRV9BRERSRVNTIH0sXG4gICAgfSk7XG5cbiAgICAvLyBObyB0b3AtbGV2ZWwgcmVjaXBpZW50czsgZm9yd2FyZGVyIGNvbWVzIGZyb20gdHhJbmZvLnJlY2lwaWVudHNcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiB7IHR5cGU6ICdjb25zb2xpZGF0ZScgfSBhcyBhbnksXG4gICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgIGNvbnNvbGlkYXRlSWQ6ICc2YTQ0ZWJjMDMyNmUxYmU0NWMxZDc5NzU0MmM4YzYzNCcsXG4gICAgICAgIHR4SGV4LFxuICAgICAgICB0eEluZm86IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogQ09OU09MSURBVElPTl9GT1JXQVJERVIsIGFtb3VudDogJzAnIH1dIH0sXG4gICAgICB9IGFzIGFueSxcbiAgICAgIHdhbGxldCxcbiAgICB9KTtcbiAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJlamVjdCBtdWx0aXNpZyBjb25zb2xpZGF0aW9uIHdoZW4gdHhJbmZvLnJlY2lwaWVudHMgZm9yd2FyZGVyIGFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggdHggZm9yd2FyZGVyJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGRNdWx0aXNpZ0NvbnNvbGlkYXRpb25UeEhleCgpO1xuICAgIGNvbnN0IHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGNvaW4sIHtcbiAgICAgIGNvaW5TcGVjaWZpYzogeyBiYXNlQWRkcmVzczogQ09OU09MSURBVElPTl9CQVNFX0FERFJFU1MgfSxcbiAgICB9KTtcblxuICAgIGF3YWl0IGNvaW5cbiAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zOiB7IHR5cGU6ICdjb25zb2xpZGF0ZScgfSBhcyBhbnksXG4gICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICBjb25zb2xpZGF0ZUlkOiAnYWJjMTIzJyxcbiAgICAgICAgICB0eEhleCxcbiAgICAgICAgICB0eEluZm86IHsgcmVjaXBpZW50czogW3sgYWRkcmVzczogJzB4YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYScsIGFtb3VudDogJzAnIH1dIH0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQsXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2ZvcndhcmRlciBhZGRyZXNzIG1pc21hdGNoLyk7XG4gIH0pO1xuXG4gIC8vIFRTUyBNUEN2MiBzaWduaW5nIHBhdGgg4oCUIHJlc29sdmVFZmZlY3RpdmVUeFBhcmFtcyBzZXRzIHR5cGUgZnJvbSBpbnRlbnQuaW50ZW50VHlwZSAoJ2NvbnNvbGlkYXRlVG9rZW4nKSxcbiAgLy8gYW5kIHR4UHJlYnVpbGQgaGFzIG9ubHkgdHhIZXggKG5vIGNvbnNvbGlkYXRlSWQsIG5vIHJlY2lwaWVudHMpLiBUaGlzIHdhcyB0aGUgYnJva2VuIHBhdGggYmVmb3JlXG4gIC8vIGlzQ29uc29saWRhdGlvblRyYW5zYWN0aW9uIHdhcyB1cGRhdGVkIHRvIHJlY29nbmlzZSAnY29uc29saWRhdGVUb2tlbicuXG4gIGl0KCdzaG91bGQgdmVyaWZ5IGEgdmFsaWQgZGlyZWN0IGNhbGxGcm9tUGFyZW50IGNvbnNvbGlkYXRpb24gdHggd2hlbiB0eXBlIGlzIGNvbnNvbGlkYXRlVG9rZW4gKFRTUyBNUEN2MiBzaWduaW5nIHBhdGgpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREaXJlY3RDb25zb2xpZGF0aW9uVHhIZXgoKTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYmFzZUFkZHJlc3M6IENPTlNPTElEQVRJT05fQkFTRV9BRERSRVNTIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgIHR5cGU6ICdjb25zb2xpZGF0ZVRva2VuJyxcbiAgICAgICAgcmVjaXBpZW50czogW3sgYWRkcmVzczogQ09OU09MSURBVElPTl9GT1JXQVJERVIsIGFtb3VudDogJzAnIH1dLFxuICAgICAgfSBhcyBhbnksXG4gICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgd2FsbGV0LFxuICAgIH0pO1xuICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmVqZWN0IGNhbGxGcm9tUGFyZW50IGNvbnNvbGlkYXRpb24gd2l0aCB0eXBlIGNvbnNvbGlkYXRlVG9rZW4gd2hlbiBwYXJlbnQgYWRkcmVzcyBkb2VzIG5vdCBtYXRjaCB3YWxsZXQgYmFzZSBhZGRyZXNzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYXdhaXQgYnVpbGREaXJlY3RDb25zb2xpZGF0aW9uVHhIZXgoKTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYmFzZUFkZHJlc3M6ICcweGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEnIH0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBjb2luXG4gICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgIHR5cGU6ICdjb25zb2xpZGF0ZVRva2VuJyxcbiAgICAgICAgICByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiBDT05TT0xJREFUSU9OX0ZPUldBUkRFUiwgYW1vdW50OiAnMCcgfV0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0gYXMgYW55LFxuICAgICAgICB3YWxsZXQsXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3BhcmVudCBhZGRyZXNzIG1pc21hdGNoLyk7XG4gIH0pO1xufSk7XG4iXX0=
|