@bitgo/sdk-coin-tempo 1.12.4 → 1.13.0
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/lib/constants.d.ts +3 -0
- package/dist/src/lib/constants.d.ts.map +1 -1
- package/dist/src/lib/constants.js +5 -2
- package/dist/src/tempo.d.ts +34 -11
- package/dist/src/tempo.d.ts.map +1 -1
- package/dist/src/tempo.js +189 -17
- package/dist/test/unit/tempo.d.ts +2 -0
- package/dist/test/unit/tempo.d.ts.map +1 -0
- package/dist/test/unit/tempo.js +207 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
7
|
+
const should_1 = __importDefault(require("should"));
|
|
8
|
+
const sdk_api_1 = require("@bitgo/sdk-api");
|
|
9
|
+
const sdk_test_1 = require("@bitgo/sdk-test");
|
|
10
|
+
const statics_1 = require("@bitgo/statics");
|
|
11
|
+
const tempo_1 = require("../../src/tempo");
|
|
12
|
+
const PATH_USD_ADDRESS = '0x20c0000000000000000000000000000000000000';
|
|
13
|
+
// secp256k1 generator point G (33 bytes) + 32-byte chaincode — valid commonKeyChain for deriveUnhardened
|
|
14
|
+
const TEST_BACKUP_KEY = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' +
|
|
15
|
+
'0000000000000000000000000000000000000000000000000000000000000001';
|
|
16
|
+
const TEST_RECOVERY_DESTINATION = '0x80151ebf635e6ec8a5455258f617be6cda1fbd7e';
|
|
17
|
+
describe('Tempo Recovery', function () {
|
|
18
|
+
let bitgo;
|
|
19
|
+
let basecoin;
|
|
20
|
+
let sandbox;
|
|
21
|
+
before(function () {
|
|
22
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
|
|
23
|
+
bitgo.safeRegister('tempo', (b) => {
|
|
24
|
+
const mockStaticsCoin = {
|
|
25
|
+
name: 'tempo',
|
|
26
|
+
fullName: 'Tempo',
|
|
27
|
+
family: statics_1.CoinFamily.TEMPO,
|
|
28
|
+
network: { type: 'mainnet' },
|
|
29
|
+
features: [],
|
|
30
|
+
};
|
|
31
|
+
return tempo_1.Tempo.createInstance(b, mockStaticsCoin);
|
|
32
|
+
});
|
|
33
|
+
bitgo.initializeTestVars();
|
|
34
|
+
basecoin = bitgo.coin('tempo');
|
|
35
|
+
});
|
|
36
|
+
beforeEach(function () {
|
|
37
|
+
sandbox = sinon_1.default.createSandbox();
|
|
38
|
+
});
|
|
39
|
+
afterEach(function () {
|
|
40
|
+
sandbox.restore();
|
|
41
|
+
});
|
|
42
|
+
describe('queryTempoRpc (via recoveryBlockchainExplorerQuery)', function () {
|
|
43
|
+
function mockFetch(responseBody) {
|
|
44
|
+
return sandbox.stub(global, 'fetch').resolves({
|
|
45
|
+
ok: true,
|
|
46
|
+
json: async () => responseBody,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
it('returns { result: "0" } for account/balance without calling RPC', async function () {
|
|
50
|
+
const fetchStub = mockFetch({});
|
|
51
|
+
const result = await basecoin.recoveryBlockchainExplorerQuery({
|
|
52
|
+
module: 'account',
|
|
53
|
+
action: 'balance',
|
|
54
|
+
address: '0xabc',
|
|
55
|
+
});
|
|
56
|
+
result.should.deepEqual({ result: '0' });
|
|
57
|
+
fetchStub.called.should.equal(false);
|
|
58
|
+
});
|
|
59
|
+
it('calls eth_call with balanceOf selector for account/tokenbalance', async function () {
|
|
60
|
+
const fetchStub = mockFetch({ result: '0x4e20' }); // 20000 decimal
|
|
61
|
+
const result = await basecoin.recoveryBlockchainExplorerQuery({
|
|
62
|
+
module: 'account',
|
|
63
|
+
action: 'tokenbalance',
|
|
64
|
+
address: '0x1234567890123456789012345678901234567890',
|
|
65
|
+
contractaddress: PATH_USD_ADDRESS,
|
|
66
|
+
tag: 'latest',
|
|
67
|
+
});
|
|
68
|
+
result.should.deepEqual({ result: '20000' });
|
|
69
|
+
const body = JSON.parse(fetchStub.firstCall.args[1].body);
|
|
70
|
+
body.method.should.equal('eth_call');
|
|
71
|
+
body.params[0].data.should.startWith('0x70a08231');
|
|
72
|
+
});
|
|
73
|
+
it('calls eth_getTransactionCount for account/txlist and parses nonce', async function () {
|
|
74
|
+
mockFetch({ result: '0x5' });
|
|
75
|
+
const result = await basecoin.recoveryBlockchainExplorerQuery({
|
|
76
|
+
module: 'account',
|
|
77
|
+
action: 'txlist',
|
|
78
|
+
address: '0xabc',
|
|
79
|
+
});
|
|
80
|
+
result.should.deepEqual({ nonce: 5 });
|
|
81
|
+
});
|
|
82
|
+
it('returns { result: "0" } when RPC returns null body.result', async function () {
|
|
83
|
+
mockFetch({ result: null });
|
|
84
|
+
const result = await basecoin.recoveryBlockchainExplorerQuery({
|
|
85
|
+
module: 'account',
|
|
86
|
+
action: 'tokenbalance',
|
|
87
|
+
address: '0xabc',
|
|
88
|
+
contractaddress: PATH_USD_ADDRESS,
|
|
89
|
+
});
|
|
90
|
+
result.should.deepEqual({ result: '0' });
|
|
91
|
+
});
|
|
92
|
+
it('returns { result: "0" } when RPC returns malformed body.result', async function () {
|
|
93
|
+
mockFetch({ result: 'not-a-number' });
|
|
94
|
+
const result = await basecoin.recoveryBlockchainExplorerQuery({
|
|
95
|
+
module: 'account',
|
|
96
|
+
action: 'tokenbalance',
|
|
97
|
+
address: '0xabc',
|
|
98
|
+
contractaddress: PATH_USD_ADDRESS,
|
|
99
|
+
});
|
|
100
|
+
result.should.deepEqual({ result: '0' });
|
|
101
|
+
});
|
|
102
|
+
it('throws when the RPC returns an error field', async function () {
|
|
103
|
+
mockFetch({ error: { message: 'execution reverted' } });
|
|
104
|
+
await basecoin
|
|
105
|
+
.recoveryBlockchainExplorerQuery({
|
|
106
|
+
module: 'account',
|
|
107
|
+
action: 'tokenbalance',
|
|
108
|
+
address: '0xabc',
|
|
109
|
+
contractaddress: PATH_USD_ADDRESS,
|
|
110
|
+
})
|
|
111
|
+
.should.be.rejectedWith('Tempo RPC error: execution reverted');
|
|
112
|
+
});
|
|
113
|
+
it('throws for unsupported module/action', async function () {
|
|
114
|
+
await basecoin
|
|
115
|
+
.recoveryBlockchainExplorerQuery({ module: 'proxy', action: 'eth_blockNumber' })
|
|
116
|
+
.should.be.rejectedWith('queryTempoRpc: unsupported module=proxy action=eth_blockNumber');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('buildUnsignedSweepTxnTSS — gas margin calculation', function () {
|
|
120
|
+
function stubBalanceAndNonce(balance, nonce = 0) {
|
|
121
|
+
sandbox.stub(basecoin, 'queryAddressTokenBalance').resolves(balance);
|
|
122
|
+
sandbox.stub(basecoin, 'getAddressNonce').resolves(nonce);
|
|
123
|
+
}
|
|
124
|
+
it('deducts gasLimit × maxFeePerGas / 10^12 from pathUSD balance', async function () {
|
|
125
|
+
// gasMargin = 1_000_000 * 20_000_000_000 * 1.75 / 10^12 = 35_000
|
|
126
|
+
// sweepAmount = 1_000_000 - 35_000 = 965_000
|
|
127
|
+
stubBalanceAndNonce('1000000');
|
|
128
|
+
const result = (await basecoin.buildUnsignedSweepTxnTSS({
|
|
129
|
+
backupKey: TEST_BACKUP_KEY,
|
|
130
|
+
recoveryDestination: TEST_RECOVERY_DESTINATION,
|
|
131
|
+
tokenContractAddress: PATH_USD_ADDRESS,
|
|
132
|
+
gasLimit: 1000000,
|
|
133
|
+
eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
|
|
134
|
+
}));
|
|
135
|
+
should_1.default.exist(result.txRequests);
|
|
136
|
+
result.txRequests[0].transactions[0].unsignedTx.should.have.property('serializedTxHex');
|
|
137
|
+
});
|
|
138
|
+
it('uses smaller margin when gasLimit is halved', async function () {
|
|
139
|
+
// gasMargin = 500_000 * 20_000_000_000 * 1.75 / 10^12 = 17_500
|
|
140
|
+
// sweepAmount = 50_000 - 17_500 = 32_500
|
|
141
|
+
stubBalanceAndNonce('50000');
|
|
142
|
+
const result = (await basecoin.buildUnsignedSweepTxnTSS({
|
|
143
|
+
backupKey: TEST_BACKUP_KEY,
|
|
144
|
+
recoveryDestination: TEST_RECOVERY_DESTINATION,
|
|
145
|
+
tokenContractAddress: PATH_USD_ADDRESS,
|
|
146
|
+
gasLimit: 500000,
|
|
147
|
+
eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
|
|
148
|
+
}));
|
|
149
|
+
should_1.default.exist(result.txRequests);
|
|
150
|
+
});
|
|
151
|
+
it('throws when balance exactly equals the gas margin', async function () {
|
|
152
|
+
// gasMargin = 1_000_000 * 20_000_000_000 / 10^12 = 20_000; balance = 20_000 → sweepAmount = 0
|
|
153
|
+
stubBalanceAndNonce('20000');
|
|
154
|
+
await basecoin
|
|
155
|
+
.buildUnsignedSweepTxnTSS({
|
|
156
|
+
backupKey: TEST_BACKUP_KEY,
|
|
157
|
+
recoveryDestination: TEST_RECOVERY_DESTINATION,
|
|
158
|
+
tokenContractAddress: PATH_USD_ADDRESS,
|
|
159
|
+
gasLimit: 1000000,
|
|
160
|
+
eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
|
|
161
|
+
})
|
|
162
|
+
.should.be.rejectedWith(/Insufficient balance/);
|
|
163
|
+
});
|
|
164
|
+
it('does not deduct margin when sweeping a non-pathUSD token', async function () {
|
|
165
|
+
const otherToken = '0x1111111111111111111111111111111111111111';
|
|
166
|
+
stubBalanceAndNonce('500');
|
|
167
|
+
const result = (await basecoin.buildUnsignedSweepTxnTSS({
|
|
168
|
+
backupKey: TEST_BACKUP_KEY,
|
|
169
|
+
recoveryDestination: TEST_RECOVERY_DESTINATION,
|
|
170
|
+
tokenContractAddress: otherToken,
|
|
171
|
+
gasLimit: 1000000,
|
|
172
|
+
eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
|
|
173
|
+
}));
|
|
174
|
+
// Full balance of 500 swept; no margin deducted
|
|
175
|
+
should_1.default.exist(result.txRequests);
|
|
176
|
+
});
|
|
177
|
+
it('returns correct UnsignedSweepTxMPCv2 structure', async function () {
|
|
178
|
+
stubBalanceAndNonce('1000000');
|
|
179
|
+
const result = (await basecoin.buildUnsignedSweepTxnTSS({
|
|
180
|
+
backupKey: TEST_BACKUP_KEY,
|
|
181
|
+
recoveryDestination: TEST_RECOVERY_DESTINATION,
|
|
182
|
+
tokenContractAddress: PATH_USD_ADDRESS,
|
|
183
|
+
gasLimit: 1000000,
|
|
184
|
+
eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
|
|
185
|
+
}));
|
|
186
|
+
const tx = result.txRequests[0].transactions[0];
|
|
187
|
+
tx.unsignedTx.derivationPath.should.equal('m/0');
|
|
188
|
+
tx.unsignedTx.coinSpecific.commonKeyChain.should.equal(TEST_BACKUP_KEY);
|
|
189
|
+
tx.signatureShares.should.deepEqual([]);
|
|
190
|
+
tx.nonce.should.equal(0);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
describe('recoverTSS — unsigned sweep dispatch', function () {
|
|
194
|
+
it('routes to buildUnsignedSweepTxnTSS when keys are plain public keys', async function () {
|
|
195
|
+
const buildStub = sandbox.stub(basecoin, 'buildUnsignedSweepTxnTSS').resolves({ txRequests: [] });
|
|
196
|
+
sandbox.stub(basecoin, 'validateRecoveryParams').returns(undefined);
|
|
197
|
+
await basecoin.recoverTSS({
|
|
198
|
+
userKey: TEST_BACKUP_KEY,
|
|
199
|
+
backupKey: TEST_BACKUP_KEY,
|
|
200
|
+
isTss: true,
|
|
201
|
+
recoveryDestination: TEST_RECOVERY_DESTINATION,
|
|
202
|
+
});
|
|
203
|
+
buildStub.calledOnce.should.equal(true);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVtcG8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L3VuaXQvdGVtcG8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxrREFBMEI7QUFDMUIsb0RBQTRCO0FBQzVCLDRDQUEwQztBQUMxQyw4Q0FBMEQ7QUFFMUQsNENBQXlFO0FBQ3pFLDJDQUF3QztBQUN4QyxNQUFNLGdCQUFnQixHQUFHLDRDQUE0QyxDQUFDO0FBRXRFLHlHQUF5RztBQUN6RyxNQUFNLGVBQWUsR0FDbkIsb0VBQW9FO0lBQ3BFLGtFQUFrRSxDQUFDO0FBQ3JFLE1BQU0seUJBQXlCLEdBQUcsNENBQTRDLENBQUM7QUFFL0UsUUFBUSxDQUFDLGdCQUFnQixFQUFFO0lBQ3pCLElBQUksS0FBbUIsQ0FBQztJQUN4QixJQUFJLFFBQWUsQ0FBQztJQUNwQixJQUFJLE9BQTJCLENBQUM7SUFFaEMsTUFBTSxDQUFDO1FBQ0wsS0FBSyxHQUFHLG9CQUFTLENBQUMsUUFBUSxDQUFDLGtCQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN0RCxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQVksRUFBRSxFQUFFO1lBQzNDLE1BQU0sZUFBZSxHQUE4QjtnQkFDakQsSUFBSSxFQUFFLE9BQU87Z0JBQ2IsUUFBUSxFQUFFLE9BQU87Z0JBQ2pCLE1BQU0sRUFBRSxvQkFBVSxDQUFDLEtBQUs7Z0JBQ3hCLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUU7Z0JBQzVCLFFBQVEsRUFBRSxFQUFFO2FBQ04sQ0FBQztZQUNULE9BQU8sYUFBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFDbEQsQ0FBQyxDQUFDLENBQUM7UUFDSCxLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMzQixRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQVUsQ0FB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QyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsc0NBQXNDLEVBQUU7UUFDL0MsRUFBRSxDQUFDLG9FQUFvRSxFQUFFLEtBQUs7WUFDNUUsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFlLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN6RyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQWUsRUFBRSx3QkFBd0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUUzRSxNQUFPLFFBQWdCLENBQUMsVUFBVSxDQUFDO2dCQUNqQyxPQUFPLEVBQUUsZUFBZTtnQkFDeEIsU0FBUyxFQUFFLGVBQWU7Z0JBQzFCLEtBQUssRUFBRSxJQUFJO2dCQUNYLG1CQUFtQixFQUFFLHlCQUF5QjthQUMvQyxDQUFDLENBQUM7WUFFSCxTQUFTLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCB7IEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvL3Nkay1hcGknO1xuaW1wb3J0IHsgVGVzdEJpdEdvLCBUZXN0Qml0R29BUEkgfSBmcm9tICdAYml0Z28vc2RrLXRlc3QnO1xuaW1wb3J0IHsgQml0R29CYXNlIH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IEJhc2VDb2luIGFzIFN0YXRpY3NCYXNlQ29pbiwgQ29pbkZhbWlseSB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCB7IFRlbXBvIH0gZnJvbSAnLi4vLi4vc3JjL3RlbXBvJztcbmNvbnN0IFBBVEhfVVNEX0FERFJFU1MgPSAnMHgyMGMwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJztcblxuLy8gc2VjcDI1NmsxIGdlbmVyYXRvciBwb2ludCBHICgzMyBieXRlcykgKyAzMi1ieXRlIGNoYWluY29kZSDigJQgdmFsaWQgY29tbW9uS2V5Q2hhaW4gZm9yIGRlcml2ZVVuaGFyZGVuZWRcbmNvbnN0IFRFU1RfQkFDS1VQX0tFWSA9XG4gICcwMjc5YmU2NjdlZjlkY2JiYWM1NWEwNjI5NWNlODcwYjA3MDI5YmZjZGIyZGNlMjhkOTU5ZjI4MTViMTZmODE3OTgnICtcbiAgJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEnO1xuY29uc3QgVEVTVF9SRUNPVkVSWV9ERVNUSU5BVElPTiA9ICcweDgwMTUxZWJmNjM1ZTZlYzhhNTQ1NTI1OGY2MTdiZTZjZGExZmJkN2UnO1xuXG5kZXNjcmliZSgnVGVtcG8gUmVjb3ZlcnknLCBmdW5jdGlvbiAoKSB7XG4gIGxldCBiaXRnbzogVGVzdEJpdEdvQVBJO1xuICBsZXQgYmFzZWNvaW46IFRlbXBvO1xuICBsZXQgc2FuZGJveDogc2lub24uU2lub25TYW5kYm94O1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R29BUEksIHsgZW52OiAnbW9jaycgfSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0ZW1wbycsIChiOiBCaXRHb0Jhc2UpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tTdGF0aWNzQ29pbjogUmVhZG9ubHk8U3RhdGljc0Jhc2VDb2luPiA9IHtcbiAgICAgICAgbmFtZTogJ3RlbXBvJyxcbiAgICAgICAgZnVsbE5hbWU6ICdUZW1wbycsXG4gICAgICAgIGZhbWlseTogQ29pbkZhbWlseS5URU1QTyxcbiAgICAgICAgbmV0d29yazogeyB0eXBlOiAnbWFpbm5ldCcgfSxcbiAgICAgICAgZmVhdHVyZXM6IFtdLFxuICAgICAgfSBhcyBhbnk7XG4gICAgICByZXR1cm4gVGVtcG8uY3JlYXRlSW5zdGFuY2UoYiwgbW9ja1N0YXRpY3NDb2luKTtcbiAgICB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBiYXNlY29pbiA9IGJpdGdvLmNvaW4oJ3RlbXBvJykgYXMgVGVtcG87XG4gIH0pO1xuXG4gIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgIHNhbmRib3ggPSBzaW5vbi5jcmVhdGVTYW5kYm94KCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgc2FuZGJveC5yZXN0b3JlKCk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdxdWVyeVRlbXBvUnBjICh2aWEgcmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSknLCBmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gbW9ja0ZldGNoKHJlc3BvbnNlQm9keTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBzaW5vbi5TaW5vblN0dWIge1xuICAgICAgcmV0dXJuIHNhbmRib3guc3R1YihnbG9iYWwsICdmZXRjaCcgYXMgYW55KS5yZXNvbHZlcyh7XG4gICAgICAgIG9rOiB0cnVlLFxuICAgICAgICBqc29uOiBhc3luYyAoKSA9PiByZXNwb25zZUJvZHksXG4gICAgICB9IGFzIGFueSk7XG4gICAgfVxuXG4gICAgaXQoJ3JldHVybnMgeyByZXN1bHQ6IFwiMFwiIH0gZm9yIGFjY291bnQvYmFsYW5jZSB3aXRob3V0IGNhbGxpbmcgUlBDJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmV0Y2hTdHViID0gbW9ja0ZldGNoKHt9KTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAnYmFsYW5jZScsXG4gICAgICAgIGFkZHJlc3M6ICcweGFiYycsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZGVlcEVxdWFsKHsgcmVzdWx0OiAnMCcgfSk7XG4gICAgICBmZXRjaFN0dWIuY2FsbGVkLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnY2FsbHMgZXRoX2NhbGwgd2l0aCBiYWxhbmNlT2Ygc2VsZWN0b3IgZm9yIGFjY291bnQvdG9rZW5iYWxhbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmV0Y2hTdHViID0gbW9ja0ZldGNoKHsgcmVzdWx0OiAnMHg0ZTIwJyB9KTsgLy8gMjAwMDAgZGVjaW1hbFxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSh7XG4gICAgICAgIG1vZHVsZTogJ2FjY291bnQnLFxuICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICBhZGRyZXNzOiAnMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwJyxcbiAgICAgICAgY29udHJhY3RhZGRyZXNzOiBQQVRIX1VTRF9BRERSRVNTLFxuICAgICAgICB0YWc6ICdsYXRlc3QnLFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmRlZXBFcXVhbCh7IHJlc3VsdDogJzIwMDAwJyB9KTtcbiAgICAgIGNvbnN0IGJvZHkgPSBKU09OLnBhcnNlKGZldGNoU3R1Yi5maXJzdENhbGwuYXJnc1sxXS5ib2R5KTtcbiAgICAgIGJvZHkubWV0aG9kLnNob3VsZC5lcXVhbCgnZXRoX2NhbGwnKTtcbiAgICAgIGJvZHkucGFyYW1zWzBdLmRhdGEuc2hvdWxkLnN0YXJ0V2l0aCgnMHg3MGEwODIzMScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbGxzIGV0aF9nZXRUcmFuc2FjdGlvbkNvdW50IGZvciBhY2NvdW50L3R4bGlzdCBhbmQgcGFyc2VzIG5vbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbW9ja0ZldGNoKHsgcmVzdWx0OiAnMHg1JyB9KTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAndHhsaXN0JyxcbiAgICAgICAgYWRkcmVzczogJzB4YWJjJyxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5kZWVwRXF1YWwoeyBub25jZTogNSB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdyZXR1cm5zIHsgcmVzdWx0OiBcIjBcIiB9IHdoZW4gUlBDIHJldHVybnMgbnVsbCBib2R5LnJlc3VsdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG1vY2tGZXRjaCh7IHJlc3VsdDogbnVsbCB9KTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAndG9rZW5iYWxhbmNlJyxcbiAgICAgICAgYWRkcmVzczogJzB4YWJjJyxcbiAgICAgICAgY29udHJhY3RhZGRyZXNzOiBQQVRIX1VTRF9BRERSRVNTLFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmRlZXBFcXVhbCh7IHJlc3VsdDogJzAnIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3JldHVybnMgeyByZXN1bHQ6IFwiMFwiIH0gd2hlbiBSUEMgcmV0dXJucyBtYWxmb3JtZWQgYm9keS5yZXN1bHQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBtb2NrRmV0Y2goeyByZXN1bHQ6ICdub3QtYS1udW1iZXInIH0pO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSh7XG4gICAgICAgIG1vZHVsZTogJ2FjY291bnQnLFxuICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICBhZGRyZXNzOiAnMHhhYmMnLFxuICAgICAgICBjb250cmFjdGFkZHJlc3M6IFBBVEhfVVNEX0FERFJFU1MsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZGVlcEVxdWFsKHsgcmVzdWx0OiAnMCcgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgndGhyb3dzIHdoZW4gdGhlIFJQQyByZXR1cm5zIGFuIGVycm9yIGZpZWxkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbW9ja0ZldGNoKHsgZXJyb3I6IHsgbWVzc2FnZTogJ2V4ZWN1dGlvbiByZXZlcnRlZCcgfSB9KTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC5yZWNvdmVyeUJsb2NrY2hhaW5FeHBsb3JlclF1ZXJ5KHtcbiAgICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICAgIGFkZHJlc3M6ICcweGFiYycsXG4gICAgICAgICAgY29udHJhY3RhZGRyZXNzOiBQQVRIX1VTRF9BRERSRVNTLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnVGVtcG8gUlBDIGVycm9yOiBleGVjdXRpb24gcmV2ZXJ0ZWQnKTtcbiAgICB9KTtcblxuICAgIGl0KCd0aHJvd3MgZm9yIHVuc3VwcG9ydGVkIG1vZHVsZS9hY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSh7IG1vZHVsZTogJ3Byb3h5JywgYWN0aW9uOiAnZXRoX2Jsb2NrTnVtYmVyJyB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgncXVlcnlUZW1wb1JwYzogdW5zdXBwb3J0ZWQgbW9kdWxlPXByb3h5IGFjdGlvbj1ldGhfYmxvY2tOdW1iZXInKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2J1aWxkVW5zaWduZWRTd2VlcFR4blRTUyDigJQgZ2FzIG1hcmdpbiBjYWxjdWxhdGlvbicsIGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBzdHViQmFsYW5jZUFuZE5vbmNlKGJhbGFuY2U6IHN0cmluZywgbm9uY2UgPSAwKSB7XG4gICAgICBzYW5kYm94LnN0dWIoYmFzZWNvaW4gYXMgYW55LCAncXVlcnlBZGRyZXNzVG9rZW5CYWxhbmNlJykucmVzb2x2ZXMoYmFsYW5jZSk7XG4gICAgICBzYW5kYm94LnN0dWIoYmFzZWNvaW4gYXMgYW55LCAnZ2V0QWRkcmVzc05vbmNlJykucmVzb2x2ZXMobm9uY2UpO1xuICAgIH1cblxuICAgIGl0KCdkZWR1Y3RzIGdhc0xpbWl0IMOXIG1heEZlZVBlckdhcyAvIDEwXjEyIGZyb20gcGF0aFVTRCBiYWxhbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gZ2FzTWFyZ2luID0gMV8wMDBfMDAwICogMjBfMDAwXzAwMF8wMDAgKiAxLjc1IC8gMTBeMTIgPSAzNV8wMDBcbiAgICAgIC8vIHN3ZWVwQW1vdW50ID0gMV8wMDBfMDAwIC0gMzVfMDAwID0gOTY1XzAwMFxuICAgICAgc3R1YkJhbGFuY2VBbmROb25jZSgnMTAwMDAwMCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBURVNUX1JFQ09WRVJZX0RFU1RJTkFUSU9OLFxuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgZ2FzTGltaXQ6IDFfMDAwXzAwMCxcbiAgICAgICAgZWlwMTU1OTogeyBtYXhGZWVQZXJHYXM6IDIwXzAwMF8wMDBfMDAwLCBtYXhQcmlvcml0eUZlZVBlckdhczogMTBfMDAwXzAwMF8wMDAgfSxcbiAgICAgIH0pKSBhcyBhbnk7XG4gICAgICBzaG91bGQuZXhpc3QocmVzdWx0LnR4UmVxdWVzdHMpO1xuICAgICAgcmVzdWx0LnR4UmVxdWVzdHNbMF0udHJhbnNhY3Rpb25zWzBdLnVuc2lnbmVkVHguc2hvdWxkLmhhdmUucHJvcGVydHkoJ3NlcmlhbGl6ZWRUeEhleCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3VzZXMgc21hbGxlciBtYXJnaW4gd2hlbiBnYXNMaW1pdCBpcyBoYWx2ZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBnYXNNYXJnaW4gPSA1MDBfMDAwICogMjBfMDAwXzAwMF8wMDAgKiAxLjc1IC8gMTBeMTIgPSAxN181MDBcbiAgICAgIC8vIHN3ZWVwQW1vdW50ID0gNTBfMDAwIC0gMTdfNTAwID0gMzJfNTAwXG4gICAgICBzdHViQmFsYW5jZUFuZE5vbmNlKCc1MDAwMCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBURVNUX1JFQ09WRVJZX0RFU1RJTkFUSU9OLFxuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgZ2FzTGltaXQ6IDUwMF8wMDAsXG4gICAgICAgIGVpcDE1NTk6IHsgbWF4RmVlUGVyR2FzOiAyMF8wMDBfMDAwXzAwMCwgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IDEwXzAwMF8wMDBfMDAwIH0sXG4gICAgICB9KSkgYXMgYW55O1xuICAgICAgc2hvdWxkLmV4aXN0KHJlc3VsdC50eFJlcXVlc3RzKTtcbiAgICB9KTtcblxuICAgIGl0KCd0aHJvd3Mgd2hlbiBiYWxhbmNlIGV4YWN0bHkgZXF1YWxzIHRoZSBnYXMgbWFyZ2luJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gZ2FzTWFyZ2luID0gMV8wMDBfMDAwICogMjBfMDAwXzAwMF8wMDAgLyAxMF4xMiA9IDIwXzAwMDsgYmFsYW5jZSA9IDIwXzAwMCDihpIgc3dlZXBBbW91bnQgPSAwXG4gICAgICBzdHViQmFsYW5jZUFuZE5vbmNlKCcyMDAwMCcpO1xuICAgICAgYXdhaXQgKGJhc2Vjb2luIGFzIGFueSlcbiAgICAgICAgLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgICAgYmFja3VwS2V5OiBURVNUX0JBQ0tVUF9LRVksXG4gICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogVEVTVF9SRUNPVkVSWV9ERVNUSU5BVElPTixcbiAgICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgICBnYXNMaW1pdDogMV8wMDBfMDAwLFxuICAgICAgICAgIGVpcDE1NTk6IHsgbWF4RmVlUGVyR2FzOiAyMF8wMDBfMDAwXzAwMCwgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IDEwXzAwMF8wMDBfMDAwIH0sXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9JbnN1ZmZpY2llbnQgYmFsYW5jZS8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2RvZXMgbm90IGRlZHVjdCBtYXJnaW4gd2hlbiBzd2VlcGluZyBhIG5vbi1wYXRoVVNEIHRva2VuJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgb3RoZXJUb2tlbiA9ICcweDExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEnO1xuICAgICAgc3R1YkJhbGFuY2VBbmROb25jZSgnNTAwJyk7XG4gICAgICBjb25zdCByZXN1bHQgPSAoYXdhaXQgKGJhc2Vjb2luIGFzIGFueSkuYnVpbGRVbnNpZ25lZFN3ZWVwVHhuVFNTKHtcbiAgICAgICAgYmFja3VwS2V5OiBURVNUX0JBQ0tVUF9LRVksXG4gICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IFRFU1RfUkVDT1ZFUllfREVTVElOQVRJT04sXG4gICAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBvdGhlclRva2VuLFxuICAgICAgICBnYXNMaW1pdDogMV8wMDBfMDAwLFxuICAgICAgICBlaXAxNTU5OiB7IG1heEZlZVBlckdhczogMjBfMDAwXzAwMF8wMDAsIG1heFByaW9yaXR5RmVlUGVyR2FzOiAxMF8wMDBfMDAwXzAwMCB9LFxuICAgICAgfSkpIGFzIGFueTtcbiAgICAgIC8vIEZ1bGwgYmFsYW5jZSBvZiA1MDAgc3dlcHQ7IG5vIG1hcmdpbiBkZWR1Y3RlZFxuICAgICAgc2hvdWxkLmV4aXN0KHJlc3VsdC50eFJlcXVlc3RzKTtcbiAgICB9KTtcblxuICAgIGl0KCdyZXR1cm5zIGNvcnJlY3QgVW5zaWduZWRTd2VlcFR4TVBDdjIgc3RydWN0dXJlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgc3R1YkJhbGFuY2VBbmROb25jZSgnMTAwMDAwMCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBURVNUX1JFQ09WRVJZX0RFU1RJTkFUSU9OLFxuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgZ2FzTGltaXQ6IDFfMDAwXzAwMCxcbiAgICAgICAgZWlwMTU1OTogeyBtYXhGZWVQZXJHYXM6IDIwXzAwMF8wMDBfMDAwLCBtYXhQcmlvcml0eUZlZVBlckdhczogMTBfMDAwXzAwMF8wMDAgfSxcbiAgICAgIH0pKSBhcyBhbnk7XG4gICAgICBjb25zdCB0eCA9IHJlc3VsdC50eFJlcXVlc3RzWzBdLnRyYW5zYWN0aW9uc1swXTtcbiAgICAgIHR4LnVuc2lnbmVkVHguZGVyaXZhdGlvblBhdGguc2hvdWxkLmVxdWFsKCdtLzAnKTtcbiAgICAgIHR4LnVuc2lnbmVkVHguY29pblNwZWNpZmljLmNvbW1vbktleUNoYWluLnNob3VsZC5lcXVhbChURVNUX0JBQ0tVUF9LRVkpO1xuICAgICAgdHguc2lnbmF0dXJlU2hhcmVzLnNob3VsZC5kZWVwRXF1YWwoW10pO1xuICAgICAgdHgubm9uY2Uuc2hvdWxkLmVxdWFsKDApO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncmVjb3ZlclRTUyDigJQgdW5zaWduZWQgc3dlZXAgZGlzcGF0Y2gnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3JvdXRlcyB0byBidWlsZFVuc2lnbmVkU3dlZXBUeG5UU1Mgd2hlbiBrZXlzIGFyZSBwbGFpbiBwdWJsaWMga2V5cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJ1aWxkU3R1YiA9IHNhbmRib3guc3R1YihiYXNlY29pbiBhcyBhbnksICdidWlsZFVuc2lnbmVkU3dlZXBUeG5UU1MnKS5yZXNvbHZlcyh7IHR4UmVxdWVzdHM6IFtdIH0pO1xuICAgICAgc2FuZGJveC5zdHViKGJhc2Vjb2luIGFzIGFueSwgJ3ZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMnKS5yZXR1cm5zKHVuZGVmaW5lZCk7XG5cbiAgICAgIGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLnJlY292ZXJUU1Moe1xuICAgICAgICB1c2VyS2V5OiBURVNUX0JBQ0tVUF9LRVksXG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICBpc1RzczogdHJ1ZSxcbiAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogVEVTVF9SRUNPVkVSWV9ERVNUSU5BVElPTixcbiAgICAgIH0pO1xuXG4gICAgICBidWlsZFN0dWIuY2FsbGVkT25jZS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
|