UNPKG

bitgo

Version:
380 lines • 67 kB
"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