bitgo
Version:
BitGo JavaScript SDK
380 lines • 67 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const nock = require("nock");
const stakingWallet_1 = require("../../fixtures/staking/stakingWallet");
const opethFixtures = require("../../fixtures/staking/topethStakingFixtures");
const avaxpStakingFixtures = require("../../fixtures/staking/tavaxpStakingFixtures");
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_test_1 = require("@bitgo/sdk-test");
const src_1 = require("../../../../src");
const sinon = require("sinon");
describe('non-TSS Staking Wallet', function () {
const microservicesUri = sdk_core_1.Environments['mock'].uri;
let bitgo;
let ethBaseCoin;
let maticBaseCoin;
let btcBaseCoin;
let topethWctBaseCoin;
let tavaxpBaseCoin;
let enterprise;
let ethWalletData;
let btcWalletData;
let topethWctStakingWalletData;
let tavaxpStakingWalletData;
let btcDescriptorWalletData;
let ethStakingWallet;
let maticStakingWallet;
let btcStakingWallet;
let topethWctStakingWallet;
let tavaxpStakingWallet;
before(function () {
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock', microservicesUri });
bitgo.initializeTestVars();
ethBaseCoin = bitgo.coin('eth');
ethBaseCoin.keychains();
maticBaseCoin = bitgo.coin('matic');
maticBaseCoin.keychains();
btcBaseCoin = bitgo.coin('btc');
btcBaseCoin.keychains();
topethWctBaseCoin = bitgo.coin('topeth:wct');
tavaxpBaseCoin = bitgo.coin('tavaxp');
enterprise = new sdk_core_1.Enterprise(bitgo, ethBaseCoin, {
id: '5cf940949449412d00f53b3d92dbcaa3',
name: 'Test Enterprise',
});
ethWalletData = {
id: 'walletId',
coin: 'eth',
enterprise: enterprise.id,
keys: ['5b3424f91bf349930e340175'],
coinSpecific: { walletVersion: 2 },
};
const maticWalletData = {
id: 'maticWalletId',
coin: 'matic',
enterprise: enterprise.id,
keys: ['5b3424f91bf349930e340175'],
};
btcWalletData = {
id: 'btcWalletId',
coin: 'btc',
enterprise: enterprise.id,
keys: ['5b3424f91bf349930e340175'],
coinSpecific: {},
};
btcDescriptorWalletData = {
id: 'btcDescriptorWalletId',
coin: 'btc',
enterprise: enterprise.id,
keys: ['5b3424f91bf349930e340175'],
coinSpecific: {},
};
topethWctStakingWalletData = {
approvalsRequired: 0,
balance: 0,
balanceString: '',
coinSpecific: {},
confirmedBalance: 0,
confirmedBalanceString: '',
keys: [],
label: '',
multisigType: 'onchain',
pendingApprovals: [],
spendableBalance: 0,
spendableBalanceString: '',
id: 'topethWctStakingWalletId',
coin: 'topeth:wct',
enterprise: enterprise.id,
};
tavaxpStakingWalletData = {
approvalsRequired: 0,
balance: 0,
balanceString: '',
coinSpecific: {},
confirmedBalance: 0,
confirmedBalanceString: '',
keys: [],
label: '',
multisigType: 'onchain',
pendingApprovals: [],
spendableBalance: 0,
spendableBalanceString: '',
id: 'tavaxpStakingWalletId',
coin: 'tavaxp',
enterprise: enterprise.id,
};
const ethWallet = new sdk_core_1.Wallet(bitgo, ethBaseCoin, ethWalletData);
const maticWallet = new sdk_core_1.Wallet(bitgo, maticBaseCoin, maticWalletData);
const btcWallet = new sdk_core_1.Wallet(bitgo, btcBaseCoin, btcWalletData);
topethWctStakingWallet = new sdk_core_1.Wallet(bitgo, topethWctBaseCoin, topethWctStakingWalletData).toStakingWallet();
tavaxpStakingWallet = new sdk_core_1.Wallet(bitgo, tavaxpBaseCoin, tavaxpStakingWalletData).toStakingWallet();
ethStakingWallet = ethWallet.toStakingWallet();
maticStakingWallet = maticWallet.toStakingWallet();
btcStakingWallet = btcWallet.toStakingWallet();
});
const sandbox = sinon.createSandbox();
afterEach(function () {
sandbox.verifyAndRestore();
});
describe('buildSignAndSend', function () {
it('should build, sign and send transaction', async function () {
const walletPassphrase = 'passphrase';
const transaction = stakingWallet_1.default.transaction('READY', stakingWallet_1.default.buildParams);
// BUILD
nock(microservicesUri)
.get(`/api/staking/v1/${ethStakingWallet.coin}/wallets/${ethStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`)
.query({ expandBuildParams: true })
.reply(200, transaction);
const prebuildTransaction = sandbox.stub(sdk_core_1.Wallet.prototype, 'prebuildTransaction');
const txPrebuild = {
walletId: ethStakingWallet.walletId,
txHex: 'hex',
buildParams: transaction.buildParams,
};
prebuildTransaction.resolves(txPrebuild);
prebuildTransaction.calledOnceWithExactly(transaction.buildParams);
// SIGN
const getKeysForSigning = sandbox.stub(sdk_core_1.Keychains.prototype, 'getKeysForSigning');
const keyChain = {
id: 'id',
pub: 'pub',
type: 'independent',
};
getKeysForSigning.resolves([keyChain]);
getKeysForSigning.calledOnce;
const signTransaction = sandbox.stub(sdk_core_1.Wallet.prototype, 'signTransaction');
const signed = {
halfSigned: {
txHex: 'hex',
payload: 'payload',
txBase64: 'base64',
},
};
signTransaction.resolves(signed);
signTransaction.calledOnceWithExactly({
txPrebuild: txPrebuild,
walletPassphrase: walletPassphrase,
keychain: keyChain,
});
// SEND
nock(microservicesUri)
.post(`/api/staking/v1/${ethStakingWallet.coin}/wallets/${ethStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`, _.matches(signed))
.reply(200, transaction);
// skipping validation because mock data is not a valid transaction
sinon.stub(sdk_core_1.StakingWallet.prototype, 'validateBuiltStakingTransaction').resolves();
const stakingTransaction = await ethStakingWallet.buildSignAndSend({ walletPassphrase: walletPassphrase }, transaction);
stakingTransaction.should.deepEqual(transaction);
sinon.restore();
});
it('should throw error when buildParams are not expanded', async function () {
const walletPassphrase = 'passphrase';
const transaction = stakingWallet_1.default.transaction('READY');
// BUILD
nock(microservicesUri)
.get(`/api/staking/v1/${ethStakingWallet.coin}/wallets/${ethStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`)
.query({ expandBuildParams: true })
.reply(200, transaction);
await ethStakingWallet
.buildSignAndSend({ walletPassphrase: walletPassphrase }, transaction)
.should.rejectedWith(`Staking transaction ${transaction.id} build params not expanded`);
});
});
describe('token buildSignAndSend', function () {
afterEach(function () {
sandbox.verifyAndRestore();
});
it('should build, sign and send transaction', async function () {
const walletPassphrase = 'passphrase';
const transaction = stakingWallet_1.default.transaction('READY', stakingWallet_1.default.buildParams);
// BUILD
nock(microservicesUri)
.get(`/api/staking/v1/${maticStakingWallet.coin}/wallets/${maticStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`)
.query({ expandBuildParams: true })
.reply(200, transaction);
const prebuildTransaction = sandbox.stub(sdk_core_1.Wallet.prototype, 'prebuildTransaction');
const txPrebuild = {
walletId: maticStakingWallet.walletId,
txHex: 'hex',
buildParams: transaction.buildParams,
};
prebuildTransaction.resolves(txPrebuild);
prebuildTransaction.calledOnceWithExactly(transaction.buildParams);
// SIGN
const getKeysForSigning = sandbox.stub(sdk_core_1.Keychains.prototype, 'getKeysForSigning');
const keyChain = {
id: 'id',
pub: 'pub',
type: 'independent',
};
getKeysForSigning.resolves([keyChain]);
getKeysForSigning.calledOnce;
const signTransaction = sandbox.stub(sdk_core_1.Wallet.prototype, 'signTransaction');
const signed = {
halfSigned: {
txHex: 'hex',
payload: 'payload',
txBase64: 'base64',
},
};
signTransaction.resolves(signed);
signTransaction.calledOnceWithExactly({
txPrebuild: txPrebuild,
walletPassphrase: walletPassphrase,
keychain: keyChain,
});
const type = maticStakingWallet.wallet.baseCoin.tokenConfig?.type;
const coin = maticStakingWallet.wallet.baseCoin.tokenConfig?.coin;
// get wallet for building and signing
nock(microservicesUri).get(`/api/v2/${coin}/wallet/${maticStakingWallet.walletId}`).reply(200, ethWalletData);
// SEND
nock(microservicesUri)
.post(`/api/staking/v1/${type}/wallets/${maticStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`, _.matches(signed))
.reply(200, transaction);
// skipping validation because mock data is not a valid transaction
sinon.stub(sdk_core_1.StakingWallet.prototype, 'validateBuiltStakingTransaction').resolves();
const stakingTransaction = await maticStakingWallet.buildSignAndSend({ walletPassphrase: walletPassphrase }, transaction);
stakingTransaction.should.deepEqual(transaction);
sinon.restore();
});
});
describe('BTC staking', function () {
it('btc delegation transaction', async function () {
const transaction = stakingWallet_1.default.transaction('READY', stakingWallet_1.default.buildParams, false);
nock(microservicesUri)
.get(`/api/staking/v1/${btcStakingWallet.coin}/wallets/${btcStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`)
.query({ expandBuildParams: true })
.reply(200, transaction);
const prebuildTransaction = sandbox.stub(sdk_core_1.Wallet.prototype, 'prebuildTransaction');
const descriptor = sandbox.stub(sdk_core_1.StakingWallet.prototype, 'getDescriptorWallet');
await btcStakingWallet.build(transaction);
prebuildTransaction.calledOnceWithExactly(transaction.buildParams).should.be.true;
descriptor.notCalled.should.be.true;
});
it('btc undelegation transaction', async function () {
const transaction = stakingWallet_1.default.transaction('READY', stakingWallet_1.default.btcUnstakingBuildParams, false, 'undelegate_withdraw');
nock(microservicesUri)
.get(`/api/staking/v1/${btcStakingWallet.coin}/wallets/${btcStakingWallet.walletId}/requests/${transaction.stakingRequestId}/transactions/${transaction.id}`)
.query({ expandBuildParams: true })
.reply(200, transaction);
nock(microservicesUri)
.get(`/api/v2/btc/wallet/${btcDescriptorWalletData.id}`)
.reply(200, btcDescriptorWalletData);
const prebuildTransaction = sandbox.stub(sdk_core_1.Wallet.prototype, 'prebuildTransaction');
await btcStakingWallet.build(transaction);
prebuildTransaction.calledOnceWithExactly(transaction.buildParams).should.be.true;
});
});
describe('Opeth:WCT Staking', function () {
it('should skip transaction validation when skipTransactionVerification is true', async function () {
const unsignedTransaction = {
walletId: topethWctStakingWallet.walletId,
...opethFixtures.unsignedStakingTransaction,
// Using a modified txHex that would normally cause validation to fail
txHex: '0x02f9019083aa37dc718206a882089e83030d40941d1a245741bd7d603747a23d30f4c91682a2992680b901643912521500000000000000000000000086bb6dca2cd6f9a0189c478bbb8f7ee2fef07c89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000067ebedc3000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000140d63efb5b24314f6f62dbadb383dba2e49d7ee0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0808080',
};
const stakingTransaction = opethFixtures.updatedStakingRequest;
nock(microservicesUri)
.get(`/api/staking/v1/${topethWctStakingWallet.coin}/wallets/${topethWctStakingWallet.walletId}/requests/${stakingTransaction.stakingRequestId}/transactions/${stakingTransaction.id}`)
.query({ expandBuildParams: true })
.reply(200, stakingTransaction);
nock(microservicesUri)
.get(`/api/v2/topeth/wallet/${topethWctStakingWallet.walletId}`)
.reply(200, topethWctStakingWalletData);
nock(microservicesUri)
.post(`/api/v2/topeth/wallet/${topethWctStakingWallet.walletId}/tx/build`)
.reply(200, unsignedTransaction);
// Mock the sign method to verify we reach it without validation error
const signStub = sinon.stub(topethWctStakingWallet, 'sign').resolves({
transaction: stakingTransaction,
signed: { halfSigned: { txHex: 'signed-hex' } },
});
// Mock validateBuiltStakingTransaction to verify it's not called
const validateStub = sinon.stub(sdk_core_1.StakingWallet.prototype, 'validateBuiltStakingTransaction');
// Call buildAndSign with skipTransactionVerification=true
await topethWctStakingWallet.buildAndSign({
walletPassphrase: 'passphrase',
transactionVerificationOptions: { skipTransactionVerification: true },
}, stakingTransaction);
// Verify that validation was skipped
validateStub.called.should.be.false;
signStub.calledOnce.should.be.true;
// Restore stubs
validateStub.restore();
signStub.restore();
});
it('should return true for isSendCallRequired for topethWctStakingWallet', function () {
// Access the private method using type assertion
const isSendCallRequired = topethWctStakingWallet.isSendCallRequired();
// Check that isSendCallRequired returns true because this is not ETH TSS
isSendCallRequired.should.equal(true);
});
it('should build and validate transaction', async function () {
const unsignedTransaction = {
walletId: topethWctStakingWallet.walletId,
...opethFixtures.unsignedStakingTransaction,
};
const stakingTransaction = opethFixtures.updatedStakingRequest;
nock(microservicesUri)
.get(`/api/staking/v1/${topethWctStakingWallet.coin}/wallets/${topethWctStakingWallet.walletId}/requests/${stakingTransaction.stakingRequestId}/transactions/${stakingTransaction.id}`)
.query({ expandBuildParams: true })
.reply(200, stakingTransaction);
nock(microservicesUri)
.get(`/api/v2/topeth/wallet/${topethWctStakingWallet.walletId}`)
.reply(200, topethWctStakingWalletData);
nock(microservicesUri)
.post(`/api/v2/topeth/wallet/${topethWctStakingWallet.walletId}/tx/build`)
.reply(200, unsignedTransaction);
// tx validation happens before signing, so we can skip it
sinon.stub(topethWctStakingWallet, 'sign').resolves();
await topethWctStakingWallet.buildAndSign({ walletPassphrase: 'passphrase' }, stakingTransaction);
});
it('should throw an error if unsigned transaction does not match the staking transaction', async function () {
const unsignedTransaction = {
walletId: topethWctStakingWallet.walletId,
...opethFixtures.unsignedStakingTransaction,
txHex: '0x02f9019083aa37dc718206a882089e83030d40941d1a245741bd7d603747a23d30f4c91682a2992680b901643912521500000000000000000000000086bb6dca2cd6f9a0189c478bbb8f7ee2fef07c89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000067ebedc3000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000140d63efb5b24314f6f62dbadb383dba2e49d7ee0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0808080',
};
const stakingTransaction = opethFixtures.updatedStakingRequest;
nock(microservicesUri)
.get(`/api/staking/v1/${topethWctStakingWallet.coin}/wallets/${topethWctStakingWallet.walletId}/requests/${stakingTransaction.stakingRequestId}/transactions/${stakingTransaction.id}`)
.query({ expandBuildParams: true })
.reply(200, stakingTransaction);
nock(microservicesUri)
.get(`/api/v2/topeth/wallet/${topethWctStakingWallet.walletId}`)
.reply(200, topethWctStakingWalletData);
nock(microservicesUri)
.post(`/api/v2/topeth/wallet/${topethWctStakingWallet.walletId}/tx/build`)
.reply(200, unsignedTransaction);
const expectedErrorMessage = 'Staking transaction validation failed before signing: ' +
'Unexpected recipient address found in built transaction: 0x86bb6dca2cd6f9a0189c478bbb8f7ee2fef07c89; ' +
'Expected recipient address not found in built transaction: 0x75bb6dca2cd6f9a0189c478bbb8f7ee2fef07c78';
await topethWctStakingWallet
.buildAndSign({ walletPassphrase: 'passphrase' }, stakingTransaction)
.should.be.rejectedWith(expectedErrorMessage);
});
});
describe('TAVAXP Staking', function () {
it('should build and validate transaction', async function () {
const unsignedTransaction = {
walletId: tavaxpStakingWallet.walletId,
...avaxpStakingFixtures.unsignedStakingTransaction,
};
const stakingTransaction = avaxpStakingFixtures.updatedStakingRequest;
nock(microservicesUri)
.get(`/api/staking/v1/${tavaxpStakingWallet.coin}/wallets/${tavaxpStakingWallet.walletId}/requests/${stakingTransaction.stakingRequestId}/transactions/${stakingTransaction.id}`)
.query({ expandBuildParams: true })
.reply(200, stakingTransaction);
nock(microservicesUri)
.get(`/api/v2/tavaxp/wallet/${tavaxpStakingWallet.walletId}`)
.reply(200, tavaxpStakingWalletData);
nock(microservicesUri)
.post(`/api/v2/tavaxp/wallet/${tavaxpStakingWallet.walletId}/tx/build`)
.reply(200, unsignedTransaction);
// tx validation happens before signing, so we can skip it
sinon.stub(tavaxpStakingWallet, 'sign').resolves();
await tavaxpStakingWallet.buildAndSign({ walletPassphrase: 'passphrase' }, stakingTransaction);
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Rha2luZ1dhbGxldE5vblRTUy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Rlc3QvdjIvdW5pdC9zdGFraW5nL3N0YWtpbmdXYWxsZXROb25UU1MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSw0QkFBNEI7QUFFNUIsNkJBQThCO0FBQzlCLHdFQUE0RDtBQUM1RCw4RUFBOEU7QUFDOUUscUZBQXFGO0FBRXJGLDhDQVd5QjtBQUN6Qiw4Q0FBNEM7QUFDNUMseUNBQXdDO0FBQ3hDLCtCQUErQjtBQUUvQixRQUFRLENBQUMsd0JBQXdCLEVBQUU7SUFDakMsTUFBTSxnQkFBZ0IsR0FBRyx1QkFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsQ0FBQztJQUNsRCxJQUFJLEtBQUssQ0FBQztJQUNWLElBQUksV0FBVyxDQUFDO0lBQ2hCLElBQUksYUFBYSxDQUFDO0lBQ2xCLElBQUksV0FBVyxDQUFDO0lBQ2hCLElBQUksaUJBQWlCLENBQUM7SUFDdEIsSUFBSSxjQUFjLENBQUM7SUFDbkIsSUFBSSxVQUFVLENBQUM7SUFDZixJQUFJLGFBQWtCLENBQUM7SUFDdkIsSUFBSSxhQUFrQixDQUFDO0lBQ3ZCLElBQUksMEJBQXNDLENBQUM7SUFDM0MsSUFBSSx1QkFBbUMsQ0FBQztJQUN4QyxJQUFJLHVCQUE0QixDQUFDO0lBQ2pDLElBQUksZ0JBQStCLENBQUM7SUFDcEMsSUFBSSxrQkFBaUMsQ0FBQztJQUN0QyxJQUFJLGdCQUErQixDQUFDO0lBQ3BDLElBQUksc0JBQXFDLENBQUM7SUFDMUMsSUFBSSxtQkFBa0MsQ0FBQztJQUV2QyxNQUFNLENBQUM7UUFDTCxLQUFLLEdBQUcsb0JBQVMsQ0FBQyxRQUFRLENBQUMsV0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxnQkFBZ0IsRUFBUyxDQUFDLENBQUM7UUFDNUUsS0FBSyxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDM0IsV0FBVyxHQUFHLEtBQUss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bUIsQ0FBQyxDQUFDO1lBRW5DLDBEQUEwRDtZQUMxRCxLQUFLLENBQUMsSUFBSSxDQUFDLG1CQUFtQixFQUFFLE1BQU0sQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBRW5ELE1BQU0sbUJBQW1CLENBQUMsWUFBWSxDQUFDLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFFLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUNqRyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5cbmltcG9ydCBub2NrID0gcmVxdWlyZSgnbm9jaycpO1xuaW1wb3J0IGZpeHR1cmVzIGZyb20gJy4uLy4uL2ZpeHR1cmVzL3N0YWtpbmcvc3Rha2luZ1dhbGxldCc7XG5pbXBvcnQgKiBhcyBvcGV0aEZpeHR1cmVzIGZyb20gJy4uLy4uL2ZpeHR1cmVzL3N0YWtpbmcvdG9wZXRoU3Rha2luZ0ZpeHR1cmVzJztcbmltcG9ydCAqIGFzIGF2YXhwU3Rha2luZ0ZpeHR1cmVzIGZyb20gJy4uLy4uL2ZpeHR1cmVzL3N0YWtpbmcvdGF2YXhwU3Rha2luZ0ZpeHR1cmVzJztcblxuaW1wb3J0IHtcbiAgRW50ZXJwcmlzZSxcbiAgRW52aXJvbm1lbnRzLFxuICBLZXljaGFpbixcbiAgS2V5Y2hhaW5zLFxuICBQcmVidWlsZFRyYW5zYWN0aW9uUmVzdWx0LFxuICBTdGFraW5nVHJhbnNhY3Rpb24sXG4gIFN0YWtpbmdXYWxsZXQsXG4gIFdhbGxldCxcbiAgV2FsbGV0Q29pblNwZWNpZmljLFxuICBXYWxsZXREYXRhLFxufSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgVGVzdEJpdEdvIH0gZnJvbSAnQGJpdGdvL3Nkay10ZXN0JztcbmltcG9ydCB7IEJpdEdvIH0gZnJvbSAnLi4vLi4vLi4vLi4vc3JjJztcbmltcG9ydCAqIGFzIHNpbm9uIGZyb20gJ3Npbm9uJztcblxuZGVzY3JpYmUoJ25vbi1UU1MgU3Rha2luZyBXYWxsZXQnLCBmdW5jdGlvbiAoKSB7XG4gIGNvbnN0IG1pY3Jvc2VydmljZXNVcmkgPSBFbnZpcm9ubWVudHNbJ21vY2snXS51cmk7XG4gIGxldCBiaXRnbztcbiAgbGV0IGV0aEJhc2VDb2luO1xuICBsZXQgbWF0aWNCYXNlQ29pbjtcbiAgbGV0IGJ0Y0Jhc2VDb2luO1xuICBsZXQgdG9wZXRoV2N0QmFzZUNvaW47XG4gIGxldCB0YXZheHBCYXNlQ29pbjtcbiAgbGV0IGVudGVycHJpc2U7XG4gIGxldCBldGhXYWxsZXREYXRhOiBhbnk7XG4gIGxldCBidGNXYWxsZXREYXRhOiBhbnk7XG4gIGxldCB0b3BldGhXY3RTdGFraW5nV2FsbGV0RGF0YTogV2FsbGV0RGF0YTtcbiAgbGV0IHRhdmF4cFN0YWtpbmdXYWxsZXREYXRhOiBXYWxsZXREYXRhO1xuICBsZXQgYnRjRGVzY3JpcHRvcldhbGxldERhdGE6IGFueTtcbiAgbGV0IGV0aFN0YWtpbmdXYWxsZXQ6IFN0YWtpbmdXYWxsZXQ7XG4gIGxldCBtYXRpY1N0YWtpbmdXYWxsZXQ6IFN0YWtpbmdXYWxsZXQ7XG4gIGxldCBidGNTdGFraW5nV2FsbGV0OiBTdGFraW5nV2FsbGV0O1xuICBsZXQgdG9wZXRoV2N0U3Rha2luZ1dhbGxldDogU3Rha2luZ1dhbGxldDtcbiAgbGV0IHRhdmF4cFN0YWtpbmdXYWxsZXQ6IFN0YWtpbmdXYWxsZXQ7XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHbywgeyBlbnY6ICdtb2NrJywgbWljcm9zZXJ2aWNlc1VyaSB9IGFzIGFueSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgZXRoQmFzZUNvaW4gPSBiaXRnby5jb2luKCdldGgnKTtcbiAgICBldGhCYXNlQ29pbi5rZXljaGFpbnMoKTtcbiAgICBtYXRpY0Jhc2VDb2luID0gYml0Z28uY29pbignbWF0aWMnKTtcbiAgICBtYXRpY0Jhc2VDb2luLmtleWNoYWlucygpO1xuICAgIGJ0Y0Jhc2VDb2luID0gYml0Z28uY29pbignYnRjJyk7XG4gICAgYnRjQmFzZUNvaW4ua2V5Y2hhaW5zKCk7XG4gICAgdG9wZXRoV2N0QmFzZUNvaW4gPSBiaXRnby5jb2luKCd0b3BldGg6d2N0Jyk7XG4gICAgdGF2YXhwQmFzZUNvaW4gPSBiaXRnby5jb2luKCd0YXZheHAnKTtcblxuICAgIGVudGVycHJpc2UgPSBuZXcgRW50ZXJwcmlzZShiaXRnbywgZXRoQmFzZUNvaW4sIHtcbiAgICAgIGlkOiAnNWNmOTQwOTQ5NDQ5NDEyZDAwZjUzYjNkOTJkYmNhYTMnLFxuICAgICAgbmFtZTogJ1Rlc3QgRW50ZXJwcmlzZScsXG4gICAgfSk7XG4gICAgZXRoV2FsbGV0RGF0YSA9IHtcbiAgICAgIGlkOiAnd2FsbGV0SWQnLFxuICAgICAgY29pbjogJ2V0aCcsXG4gICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlLmlkLFxuICAgICAga2V5czogWyc1YjM0MjRmOTFiZjM0OTkzMGUzNDAxNzUnXSxcbiAgICAgIGNvaW5TcGVjaWZpYzogeyB3YWxsZXRWZXJzaW9uOiAyIH0sXG4gICAgfTtcbiAgICBjb25zdCBtYXRpY1dhbGxldERhdGEgPSB7XG4gICAgICBpZDogJ21hdGljV2FsbGV0SWQnLFxuICAgICAgY29pbjogJ21hdGljJyxcbiAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2UuaWQsXG4gICAgICBrZXlzOiBbJzViMzQyNGY5MWJmMzQ5OTMwZTM0MDE3NSddLFxuICAgIH07XG4gICAgYnRjV2FsbGV0RGF0YSA9IHtcbiAgICAgIGlkOiAnYnRjV2FsbGV0SWQnLFxuICAgICAgY29pbjogJ2J0YycsXG4gICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlLmlkLFxuICAgICAga2V5czogWyc1YjM0MjRmOTFiZjM0OTkzMGUzNDAxNzUnXSxcbiAgICAgIGNvaW5TcGVjaWZpYzoge30sXG4gICAgfTtcbiAgICBidGNEZXNjcmlwdG9yV2FsbGV0RGF0YSA9IHtcbiAgICAgIGlkOiAnYnRjRGVzY3JpcHRvcldhbGxldElkJyxcbiAgICAgIGNvaW46ICdidGMnLFxuICAgICAgZW50ZXJwcmlzZTogZW50ZXJwcmlzZS5pZCxcbiAgICAgIGtleXM6IFsnNWIzNDI0ZjkxYmYzNDk5MzBlMzQwMTc1J10sXG4gICAgICBjb2luU3BlY2lmaWM6IHt9LFxuICAgIH07XG5cbiAgICB0b3BldGhXY3RTdGFraW5nV2FsbGV0RGF0YSA9IHtcbiAgICAgIGFwcHJvdmFsc1JlcXVpcmVkOiAwLFxuICAgICAgYmFsYW5jZTogMCxcbiAgICAgIGJhbGFuY2VTdHJpbmc6ICcnLFxuICAgICAgY29pblNwZWNpZmljOiB7fSBhcyBXYWxsZXRDb2luU3BlY2lmaWMsXG4gICAgICBjb25maXJtZWRCYWxhbmNlOiAwLFxuICAgICAgY29uZmlybWVkQmFsYW5jZVN0cmluZzogJycsXG4gICAgICBrZXlzOiBbXSxcbiAgICAgIGxhYmVsOiAnJyxcbiAgICAgIG11bHRpc2lnVHlwZTogJ29uY2hhaW4nLFxuICAgICAgcGVuZGluZ0FwcHJvdmFsczogW10sXG4gICAgICBzcGVuZGFibGVCYWxhbmNlOiAwLFxuICAgICAgc3BlbmRhYmxlQmFsYW5jZVN0cmluZzogJycsXG4gICAgICBpZDogJ3RvcGV0aFdjdFN0YWtpbmdXYWxsZXRJZCcsXG4gICAgICBjb2luOiAndG9wZXRoOndjdCcsXG4gICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlLmlkLFxuICAgIH07XG5cbiAgICB0YXZheHBTdGFraW5nV2FsbGV0RGF0YSA9IHtcbiAgICAgIGFwcHJvdmFsc1JlcXVpcmVkOiAwLFxuICAgICAgYmFsYW5jZTogMCxcbiAgICAgIGJhbGFuY2VTdHJpbmc6ICcnLFxuICAgICAgY29pblNwZWNpZmljOiB7fSBhcyBXYWxsZXRDb2luU3BlY2lmaWMsXG4gICAgICBjb25maXJtZWRCYWxhbmNlOiAwLFxuICAgICAgY29uZmlybWVkQmFsYW5jZVN0cmluZzogJycsXG4gICAgICBrZXlzOiBbXSxcbiAgICAgIGxhYmVsOiAnJyxcbiAgICAgIG11bHRpc2lnVHlwZTogJ29uY2hhaW4nLFxuICAgICAgcGVuZGluZ0FwcHJvdmFsczogW10sXG4gICAgICBzcGVuZGFibGVCYWxhbmNlOiAwLFxuICAgICAgc3BlbmRhYmxlQmFsYW5jZVN0cmluZzogJycsXG4gICAgICBpZDogJ3RhdmF4cFN0YWtpbmdXYWxsZXRJZCcsXG4gICAgICBjb2luOiAndGF2YXhwJyxcbiAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2UuaWQsXG4gICAgfTtcblxuICAgIGNvbnN0IGV0aFdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGV0aEJhc2VDb2luLCBldGhXYWxsZXREYXRhKTtcbiAgICBjb25zdCBtYXRpY1dhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIG1hdGljQmFzZUNvaW4sIG1hdGljV2FsbGV0RGF0YSk7XG4gICAgY29uc3QgYnRjV2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYnRjQmFzZUNvaW4sIGJ0Y1dhbGxldERhdGEpO1xuICAgIHRvcGV0aFdjdFN0YWtpbmdXYWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCB0b3BldGhXY3RCYXNlQ29pbiwgdG9wZXRoV2N0U3Rha2luZ1dhbGxldERhdGEpLnRvU3Rha2luZ1dhbGxldCgpO1xuICAgIHRhdmF4cFN0YWtpbmdXYWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCB0YXZheHBCYXNlQ29pbiwgdGF2YXhwU3Rha2luZ1dhbGxldERhdGEpLnRvU3Rha2luZ1dhbGxldCgpO1xuXG4gICAgZXRoU3Rha2luZ1dhbGxldCA9IGV0aFdhbGxldC50b1N0YWtpbmdXYWxsZXQoKTtcbiAgICBtYXRpY1N0YWtpbmdXYWxsZXQgPSBtYXRpY1dhbGxldC50b1N0YWtpbmdXYWxsZXQoKTtcbiAgICBidGNTdGFraW5nV2FsbGV0ID0gYnRjV2FsbGV0LnRvU3Rha2luZ1dhbGxldCgpO1xuICB9KTtcblxuICBjb25zdCBzYW5kYm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuXG4gIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgc2FuZGJveC52ZXJpZnlBbmRSZXN0b3JlKCk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdidWlsZFNpZ25BbmRTZW5kJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgYnVpbGQsIHNpZ24gYW5kIHNlbmQgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB3YWxsZXRQYXNzcGhyYXNlID0gJ3Bhc3NwaHJhc2UnO1xuICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBmaXh0dXJlcy50cmFuc2FjdGlvbignUkVBRFknLCBmaXh0dXJlcy5idWlsZFBhcmFtcyk7XG5cbiAgICAgIC8vIEJVSUxEXG4gICAgICBub2NrKG1pY3Jvc2VydmljZXNVcmkpXG4gICAgICAgIC5nZXQoXG4gICAgICAgICAgYC9hcGkvc3Rha2luZy92MS8ke2V0aFN0YWtpbmdXYWxsZXQuY29pbn0vd2FsbGV0cy8ke2V0aFN0YWtpbmdXYWxsZXQud2FsbGV0SWR9L3JlcXVlc3RzLyR7dHJhbnNhY3Rpb24uc3Rha2luZ1JlcXVlc3RJZH0vdHJhbnNhY3Rpb25zLyR7dHJhbnNhY3Rpb24uaWR9YFxuICAgICAgICApXG4gICAgICAgIC5xdWVyeSh7IGV4cGFuZEJ1aWxkUGFyYW1zOiB0cnVlIH0pXG4gICAgICAgIC5yZXBseSgyMDAsIHRyYW5zYWN0aW9uKTtcblxuICAgICAgY29uc3QgcHJlYnVpbGRUcmFuc2FjdGlvbiA9IHNhbmRib3guc3R1YihXYWxsZXQucHJvdG90eXBlLCAncHJlYnVpbGRUcmFuc2FjdGlvbicpO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgd2FsbGV0SWQ6IGV0aFN0YWtpbmdXYWxsZXQud2FsbGV0SWQsXG4gICAgICAgIHR4SGV4OiAnaGV4JyxcbiAgICAgICAgYnVpbGRQYXJhbXM6IHRyYW5zYWN0aW9uLmJ1aWxkUGFyYW1zLFxuICAgICAgfTtcbiAgICAgIHByZWJ1aWxkVHJhbnNhY3Rpb24ucmVzb2x2ZXModHhQcmVidWlsZCk7XG4gICAgICBwcmVidWlsZFRyYW5zYWN0aW9uLmNhbGxlZE9uY2VXaXRoRXhhY3RseSh0cmFuc2FjdGlvbi5idWlsZFBhcmFtcyk7XG5cbiAgICAgIC8vIFNJR05cbiAgICAgIGNvbnN0IGdldEtleXNGb3JTaWduaW5nID0gc2FuZGJveC5zdHViKEtleWNoYWlucy5wcm90b3R5cGUsICdnZXRLZXlzRm9yU2lnbmluZycpO1xuICAgICAgY29uc3Qga2V5Q2hhaW46IEtleWNoYWluID0ge1xuICAgICAgICBpZDogJ2lkJyxcbiAgICAgICAgcHViOiAncHViJyxcbiAgICAgICAgdHlwZTogJ2luZGVwZW5kZW50JyxcbiAgICAgIH07XG4gICAgICBnZXRLZXlzRm9yU2lnbmluZy5yZXNvbHZlcyhba2V5Q2hhaW5dKTtcbiAgICAgIGdldEtleXNGb3JTaWduaW5nLmNhbGxlZE9uY2U7XG5cbiAgICAgIGNvbnN0IHNpZ25UcmFuc2FjdGlvbiA9IHNhbmRib3guc3R1YihXYWxsZXQucHJvdG90eXBlLCAnc2lnblRyYW5zYWN0aW9uJyk7XG4gICAgICBjb25zdCBzaWduZWQgPSB7XG4gICAgICAgIGhhbGZTaWduZWQ6IHtcbiAgICAgICAgICB0eEhleDogJ2hleCcsXG4gICAgICAgICAgcGF5bG9hZDogJ3BheWxvYWQnLFxuICAgICAgICAgIHR4QmFzZTY0OiAnYmFzZTY0JyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBzaWduVHJhbnNhY3Rpb24ucmVzb2x2ZXMoc2lnbmVkKTtcbiAgICAgIHNpZ25UcmFuc2FjdGlvbi5jYWxsZWRPbmNlV2l0aEV4YWN0bHkoe1xuICAgICAgICB0eFByZWJ1aWxkOiB0eFByZWJ1aWxkLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICBrZXljaGFpbjoga2V5Q2hhaW4sXG4gICAgICB9KTtcblxuICAgICAgLy8gU0VORFxuICAgICAgbm9jayhtaWNyb3NlcnZpY2VzVXJpKVxuICAgICAgICAucG9zdChcbiAgICAgICAgICBgL2FwaS9zdGFraW5nL3YxLyR7ZXRoU3Rha2luZ1dhbGxldC5jb2lufS93YWxsZXRzLyR7ZXRoU3Rha2luZ1dhbGxldC53YWxsZXRJZH0vcmVxdWVzdHMvJHt0cmFuc2FjdGlvbi5zdGFraW5nUmVxdWVzdElkfS90cmFuc2FjdGlvbnMvJHt0cmFuc2FjdGlvbi5pZH1gLFxuICAgICAgICAgIF8ubWF0Y2hlcyhzaWduZWQpXG4gICAgICAgIClcbiAgICAgICAgLnJlcGx5KDIwMCwgdHJhbnNhY3Rpb24pO1xuXG4gICAgICAvLyBza2lwcGluZyB2YWxpZGF0aW9uIGJlY2F1c2UgbW9jayBkYXRhIGlzIG5vdCBhIHZhbGlkIHRyYW5zYWN0aW9uXG4gICAgICBzaW5vbi5zdHViKFN0YWtpbmdXYWxsZXQucHJvdG90eXBlLCA8YW55Pid2YWxpZGF0ZUJ1aWx0U3Rha2luZ1RyYW5zYWN0aW9uJykucmVzb2x2ZXMoKTtcblxuICAgICAgY29uc3Qgc3Rha2luZ1RyYW5zYWN0aW9uID0gYXdhaXQgZXRoU3Rha2luZ1dhbGxldC5idWlsZFNpZ25BbmRTZW5kKFxuICAgICAgICB7IHdhbGxldFBhc3NwaHJhc2U6IHdhbGxldFBhc3NwaHJhc2UgfSxcbiAgICAgICAgdHJhbnNhY3Rpb25cbiAgICAgICk7XG5cbiAgICAgIHN0YWtpbmdUcmFuc2FjdGlvbi5zaG91bGQuZGVlcEVxdWFsKHRyYW5zYWN0aW9uKTtcbiAgICAgIHNpbm9uLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3Igd2hlbiBidWlsZFBhcmFtcyBhcmUgbm90IGV4cGFuZGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgd2FsbGV0UGFzc3BocmFzZSA9ICdwYXNzcGhyYXNlJztcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gZml4dHVyZXMudHJhbnNhY3Rpb24oJ1JFQURZJyk7XG5cbiAgICAgIC8vIEJVSUxEXG4gICAgICBub2NrKG1pY3Jvc2VydmljZXNVcmkpXG4gICAgICAgIC5nZXQoXG4gICAgICAgICAgYC9hcGkvc3Rha2luZy92MS8ke2V0aFN0YWtpbmdXYWxsZXQuY29pbn0vd2FsbGV0cy8ke2V0aFN0YWtpbmdXYWxsZXQud2FsbGV0SWR9L3JlcXVlc3RzLyR7dHJhbnNhY3Rpb24uc3Rha2luZ1JlcXVlc3RJZH0vdHJhbnNhY3Rpb25zLyR7dHJhbnNhY3Rpb24uaWR9YFxuICAgICAgICApXG4gICAgICAgIC5xdWVyeSh7IGV4cGFuZEJ1aWxkUGFyYW1zOiB0cnVlIH0pXG4gICAgICAgIC5yZXBseSgyMDAsIHRyYW5zYWN0aW9uKTtcblxuICAgICAgYXdhaXQgZXRoU3Rha2luZ1dhbGxldFxuICAgICAgICAuYnVpbGRTaWduQW5kU2VuZCh7IHdhbGxldFBhc3NwaHJhc2U6IHdhbGxldFBhc3NwaHJhc2UgfSwgdHJhbnNhY3Rpb24pXG4gICAgICAgIC5zaG91bGQucmVqZWN0ZWRXaXRoKGBTdGFraW5nIHRyYW5zYWN0aW9uICR7dHJhbnNhY3Rpb24uaWR9IGJ1aWxkIHBhcmFtcyBub3QgZXhwYW5kZWRgKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3Rva2VuIGJ1aWxkU2lnbkFuZFNlbmQnLCBmdW5jdGlvbiAoKSB7XG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHNhbmRib3gudmVyaWZ5QW5kUmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBidWlsZCwgc2lnbiBhbmQgc2VuZCB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHdhbGx