bitgo
Version:
BitGo JavaScript SDK
573 lines • 86.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBitGoPartyGpgKeyPrv = getBitGoPartyGpgKeyPrv;
exports.getUserPartyGpgKeyPublic = getUserPartyGpgKeyPublic;
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const fs = require("fs");
const common_1 = require("../common");
const openpgp = require("openpgp");
const nock = require("nock");
const sdk_test_1 = require("@bitgo/sdk-test");
const src_1 = require("../../../../../../src");
const createKeccakHash = require('keccak');
describe('signTxRequest:', function () {
let tssUtils;
let wallet;
let bitgo;
let baseCoin;
let bitgoGpgKey;
const coinName = 'hteth';
const reqId = new sdk_core_1.RequestTracer();
const txRequestId = 'randomTxReqId';
const signableHex = 'e27aecaea559fbedc9ae8a22b0ab6654c2d686403c2aeb434b302545c94eed3b';
const txRequest = {
txRequestId,
enterpriseId: '4517abfb-f567-4b7a-9f91-407509d29403',
transactions: [
{
unsignedTx: {
serializedTxHex: 'TOO MANY SECRETS',
signableHex,
derivationPath: 'm/0', // Needs this when key derivation is supported
},
state: 'pendingSignature',
signatureShares: [],
},
],
unsignedTxs: [],
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
state: 'pendingUserSignature',
walletType: 'hot',
walletId: 'walletId',
policiesChecked: true,
version: 1,
userId: 'userId',
apiVersion: 'full',
};
const txRequestForMessageSigning = {
txRequestId,
enterpriseId: '4517abfb-f567-4b7a-9f91-407509d29403',
messages: [
{
messageRaw: 'TOO MANY SECRETS',
derivationPath: 'm/0',
state: 'pendingSignature',
signatureShares: [],
},
],
unsignedTxs: [],
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
state: 'pendingUserSignature',
walletType: 'hot',
walletId: 'walletId',
policiesChecked: true,
version: 1,
userId: 'userId',
apiVersion: 'full',
};
const vector = {
party1: 0,
party2: 2,
party3: 1,
};
// To generate the fixtures, run DKG as in the dklsDkg.ts tests and save the resulting party.getKeyShare in a file by doing fs.writeSync(party.getKeyShare()).
const shareFiles = [
`${__dirname}/fixtures/userShare`,
`${__dirname}/fixtures/backupShare`,
`${__dirname}/fixtures/bitgoShare`,
];
let bitgoParty;
before(async () => {
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
const bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
bitgoGpgKey = await openpgp.generateKey({
userIDs: [
{
name: 'bitgo',
},
],
curve: 'secp256k1',
config: {
rejectCurves: new Set(),
},
});
const constants = {
mpc: {
bitgoPublicKey: bitgoGpgKey.publicKey,
bitgoMPCv2PublicKey: bitgoGpgKey.publicKey,
},
};
nock(bgUrl).get('/api/v1/client/constants').times(20).reply(200, { ttl: 3600, constants });
baseCoin = bitgo.coin(coinName);
let hashFn;
try {
hashFn = baseCoin.getHashFunction();
}
catch (err) {
hashFn = createKeccakHash('keccak256');
}
const hashBuffer = hashFn.update(Buffer.from(signableHex, 'hex')).digest();
// Nock out both the user and bitgo side responses to create valid signatures
bitgoParty = new sdk_lib_mpc_1.DklsDsg.Dsg(fs.readFileSync(shareFiles[vector.party2]), vector.party2, txRequest.transactions[0].unsignedTx.derivationPath, hashBuffer);
// // Round 1 ////
const walletData = {
id: txRequest.walletId,
enterprise: txRequest.enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
multisigTypeVersion: 'MPCv2',
};
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, walletData);
tssUtils = new sdk_core_1.ECDSAUtils.EcdsaMPCv2Utils(bitgo, baseCoin, wallet);
});
beforeEach(async function () {
await nockGetBitgoPublicKeyBasedOnFeatureFlags(coinName, txRequest.enterpriseId, bitgoGpgKey);
});
after(function () {
nock.cleanAll();
});
afterEach(function () {
bitgoParty.endSession();
nock.cleanAll();
});
it('successfully signs a txRequest with user key for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs when recipientSource is explicit and txParams.recipients is non-empty', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
recipientSource: sdk_core_1.TssTxRecipientSource.Explicit,
txParams: {
recipients: [{ address: '0x0000000000000000000000000000000000000001', amount: '1' }],
},
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('rejects when recipientSource is explicit and txParams.recipients is empty', async function () {
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
// Cast bypasses the compile-time non-empty recipients constraint to exercise the runtime guard.
await tssUtils
.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
recipientSource: sdk_core_1.TssTxRecipientSource.Explicit,
txParams: { recipients: [] },
})
.should.be.rejectedWith('recipientSource "explicit" requires txParams.recipients with at least one recipient.');
});
it('successfully signs a txRequest with backup key for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey, 1),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 1),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const backupShare = fs.readFileSync(shareFiles[vector.party3]);
const backupPrvBase64 = Buffer.from(backupShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: backupPrvBase64,
mpcv2PartyId: 1,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest with a message for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequestForMessageSigning, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequestForMessageSigning, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequestForMessageSigning),
await nockSendTxRequest(txRequestForMessageSigning),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest for a dkls hot wallet after receiving multiple 429 errors', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 0, 3),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
describe('v2 encryption (offline rounds with adata)', function () {
it('e2e: 3-round offline signing with v2 encrypted keys preserves adata context binding', async function () {
const walletPassphrase = 'testpassphrase';
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
const encryptedPrv = await bitgo.encryptAsync({
input: userPrvBase64,
password: walletPassphrase,
encryptionVersion: 2,
});
JSON.parse(encryptedPrv).v.should.equal(2);
const round1Result = await tssUtils.createOfflineRound1Share({
txRequest,
prv: userPrvBase64,
walletPassphrase,
encryptedPrv,
});
const r1SessionEnvelope = JSON.parse(round1Result.encryptedRound1Session);
r1SessionEnvelope.v.should.equal(2);
r1SessionEnvelope.should.have.property('adata');
r1SessionEnvelope.should.have.property('hkdfSalt');
r1SessionEnvelope.adata.should.containEql('DKLS23_SIGNING_ROUND1_STATE');
const r1GpgEnvelope = JSON.parse(round1Result.encryptedUserGpgPrvKey);
r1GpgEnvelope.v.should.equal(2);
r1GpgEnvelope.should.have.property('adata');
r1GpgEnvelope.adata.should.containEql('DKLS23_SIGNING_USER_GPG_KEY');
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey);
const transactions = (0, common_1.getRoute)('ecdsa');
const round1TxRequestResponse = await bitgo
.post(bitgo.url(`/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, 2))
.send({
signatureShares: [round1Result.signatureShareRound1],
signerGpgPublicKey: round1Result.userGpgPubKey,
})
.result();
const round1TxReq = {
...txRequest,
transactions: [
{
...txRequest.transactions[0],
signatureShares: round1TxRequestResponse.transactions[0].signatureShares,
},
],
};
const round2Result = await tssUtils.createOfflineRound2Share({
txRequest: round1TxReq,
prv: userPrvBase64,
walletPassphrase,
bitgoPublicGpgKey: bitgoGpgKey.publicKey,
encryptedUserGpgPrvKey: round1Result.encryptedUserGpgPrvKey,
encryptedRound1Session: round1Result.encryptedRound1Session,
});
const r2Envelope = JSON.parse(round2Result.encryptedRound2Session);
r2Envelope.v.should.equal(2);
r2Envelope.should.have.property('adata');
r2Envelope.adata.should.containEql('DKLS23_SIGNING_ROUND2_STATE');
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey);
const round2TxRequestResponse = await bitgo
.post(bitgo.url(`/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, 2))
.send({
signatureShares: [round2Result.signatureShareRound2],
signerGpgPublicKey: round1Result.userGpgPubKey,
})
.result();
const round2TxReq = {
...txRequest,
transactions: [
{
...txRequest.transactions[0],
signatureShares: round2TxRequestResponse.transactions[0].signatureShares,
},
],
};
const round3Result = await tssUtils.createOfflineRound3Share({
txRequest: round2TxReq,
prv: userPrvBase64,
walletPassphrase,
bitgoPublicGpgKey: bitgoGpgKey.publicKey,
encryptedUserGpgPrvKey: round1Result.encryptedUserGpgPrvKey,
encryptedRound2Session: round2Result.encryptedRound2Session,
});
round3Result.should.have.property('signatureShareRound3');
});
it('validateAdata accepts v2 envelopes with matching adata and domain separator', async function () {
const adata = 'txhash:m/0/1';
const domainSep = 'DKLS23_SIGNING_ROUND1_STATE';
const ct = await bitgo.encryptAsync({
input: 'test-data',
password: 'testpass',
encryptionVersion: 2,
adata: `${domainSep}:${adata}`,
});
tssUtils.validateAdata(adata, ct, domainSep);
});
it('validateAdata rejects v2 envelopes with mismatched adata', async function () {
const domainSep = 'DKLS23_SIGNING_ROUND1_STATE';
const ct = await bitgo.encryptAsync({
input: 'test-data',
password: 'testpass',
encryptionVersion: 2,
adata: `${domainSep}:context-A`,
});
(() => tssUtils.validateAdata('context-B', ct, domainSep)).should.throw(/Adata does not match/);
});
});
it('fails to signs a txRequest for a dkls hot wallet after receiving over 3 429 errors', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 0, 4),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils
.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
})
.should.be.rejectedWith('Too many requests, slow down!');
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.false();
});
});
function getBitGoPartyGpgKeyPrv(key) {
return {
partyId: 2,
gpgKey: key.privateKey,
};
}
function getUserPartyGpgKeyPublic(userPubKey, partyId = 0) {
return {
partyId: partyId,
gpgKey: userPubKey,
};
}
async function nockTxRequestResponseSignatureShareRoundOne(bitgoSession, txRequest, bitgoGpgKey, partyId = 0) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.persist(true)
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round1Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
const signatureShare = JSON.parse(body.signatureShares[0].share);
const deserializedMessages = sdk_lib_mpc_1.DklsTypes.deserializeMessages({
p2pMessages: [],
broadcastMessages: [
{
from: signatureShare.data.msg1.from,
payload: signatureShare.data.msg1.message,
},
],
});
if (signatureShare.type === 'round1Input') {
const bitgoToUserRound1BroadcastMsg = await bitgoSession.init();
const bitgoToUserRound2Msg = bitgoSession.handleIncomingMessages({
p2pMessages: [],
broadcastMessages: deserializedMessages.broadcastMessages,
});
const serializedBitGoToUserRound1And2Msgs = sdk_lib_mpc_1.DklsTypes.serializeMessages({
p2pMessages: bitgoToUserRound2Msg.p2pMessages,
broadcastMessages: [bitgoToUserRound1BroadcastMsg],
});
const authEncMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages(serializedBitGoToUserRound1And2Msgs, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const bitgoToUserSignatureShare = {
type: 'round1Output',
data: {
msg1: {
from: authEncMessages.broadcastMessages[0].from,
signature: authEncMessages.broadcastMessages[0].payload.signature,
message: authEncMessages.broadcastMessages[0].payload.message,
},
msg2: {
from: authEncMessages.p2pMessages[0].from,
to: authEncMessages.p2pMessages[0].to,
encryptedMessage: authEncMessages.p2pMessages[0].payload.encryptedMessage,
signature: authEncMessages.p2pMessages[0].payload.signature,
},
},
};
return {
txRequestId: txRequest.txRequestId,
transactions: [
{
signatureShares: [
{
from: sdk_core_1.SignatureShareType.BITGO,
to: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
share: JSON.stringify(bitgoToUserSignatureShare),
},
],
},
],
};
}
});
}
async function nockTxRequestResponseSignatureShareRoundTwo(bitgoSession, txRequest, bitgoGpgKey, partyId = 0, rateLimitErrorCount = 0) {
const transactions = (0, common_1.getRoute)('ecdsa');
const scope = nock('https://bitgo.fakeurl');
if (rateLimitErrorCount > 0) {
scope
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round2Input')
.times(rateLimitErrorCount)
.reply(429, {
error: 'Too many requests, slow down!',
name: 'TooManyRequests',
requestId: 'cm5qx01lh0013b2ek2sxl4w00',
context: {},
});
}
return scope
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round2Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
const parsedSignatureShare = JSON.parse(body.signatureShares[0].share);
const serializedMessages = await sdk_lib_mpc_1.DklsComms.decryptAndVerifyIncomingMessages({
p2pMessages: [
{
from: parsedSignatureShare.data.msg2.from,
to: parsedSignatureShare.data.msg2.to,
payload: {
encryptedMessage: parsedSignatureShare.data.msg2.encryptedMessage,
signature: parsedSignatureShare.data.msg2.signature,
},
},
{
from: parsedSignatureShare.data.msg3.from,
to: parsedSignatureShare.data.msg3.to,
payload: {
encryptedMessage: parsedSignatureShare.data.msg3.encryptedMessage,
signature: parsedSignatureShare.data.msg3.signature,
},
},
],
broadcastMessages: [],
}, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const deserializedMessages = sdk_lib_mpc_1.DklsTypes.deserializeMessages({
p2pMessages: [serializedMessages.p2pMessages[0]],
broadcastMessages: [],
});
if (parsedSignatureShare.type === 'round2Input') {
const bitgoToUserRound3Msg = bitgoSession.handleIncomingMessages(deserializedMessages);
const serializedBitGoToUserRound3Msgs = sdk_lib_mpc_1.DklsTypes.serializeMessages(bitgoToUserRound3Msg);
const authEncMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages(serializedBitGoToUserRound3Msgs, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const bitgoToUserSignatureShare = {
type: 'round2Output',
data: {
msg3: {
from: authEncMessages.p2pMessages[0].from,
to: authEncMessages.p2pMessages[0].to,
encryptedMessage: authEncMessages.p2pMessages[0].payload.encryptedMessage,
signature: authEncMessages.p2pMessages[0].payload.signature,
},
},
};
return {
txRequestId: txRequest.txRequestId,
transactions: [
{
signatureShares: [
{
from: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
to: sdk_core_1.SignatureShareType.BITGO,
share: 'some old share we dont care about',
},
{
from: sdk_core_1.SignatureShareType.BITGO,
to: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
share: JSON.stringify(bitgoToUserSignatureShare),
},
],
},
],
};
}
});
}
async function nockTxRequestResponseSignatureShareRoundThree(txRequest) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round3Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
return {
txRequestId: txRequest.txRequestId,
};
});
}
async function nockSendTxRequest(txRequest) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/send`)
.times(1)
.reply(200, {
txRequestId: txRequest.txRequestId,
});
}
async function nockGetBitgoPublicKeyBasedOnFeatureFlags(coin, enterpriseId, bitgoGpgKeyPair) {
const bitgoGPGPublicKeyResponse = {
name: 'irrelevant',
publicKey: bitgoGpgKeyPair.publicKey,
mpcv2PublicKey: bitgoGpgKeyPair.publicKey,
enterpriseId,
};
nock('https://bitgo.fakeurl')
.get(`/api/v2/${coin}/tss/pubkey`)
.times(4)
.query({ enterpriseId })
.reply(200, bitgoGPGPublicKeyResponse);
return bitgoGPGPublicKeyResponse;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnblR4UmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Rlc3QvdjIvdW5pdC9pbnRlcm5hbC90c3NVdGlscy9lY2RzYU1QQ3YyL3NpZ25UeFJlcXVlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpY0Esd0RBS0M7QUFFRCw0REFLQztBQTVjRCw4Q0FXeUI7QUFDekIsb0RBQW1FO0FBQ25FLHlCQUF5QjtBQUN6QixzQ0FBcUM7QUFTckMsbUNBQW1DO0FBQ25DLDZCQUE4QjtBQUM5Qiw4Q0FBd0Q7QUFDeEQsK0NBQThDO0FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBTzNDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRTtJQUN6QixJQUFJLFFBQW9DLENBQUM7SUFDekMsSUFBSSxNQUFjLENBQUM7SUFDbkIsSUFBSSxLQUF5QixDQUFDO0lBQzlCLElBQUksUUFBa0IsQ0FBQztJQUN2QixJQUFJLFdBQThDLENBQUM7SUFDbkQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBRXpCLE1BQU0sS0FBSyxHQUFHLElBQUksd0JBQWEsRUFBRSxDQUFDO0lBQ2xDLE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQztJQUNwQyxNQUFNLFdBQVcsR0FBRyxrRUFBa0UsQ0FBQztJQUN2RixNQUFNLFNBQVMsR0FBYztRQUMzQixXQUFXO1FBQ1gsWUFBWSxFQUFFLHNDQUFzQztRQUNwRCxZQUFZLEVBQUU7WUFDWjtnQkFDRSxVQUFVLEVBQUU7b0JBQ1YsZUFBZSxFQUFFLGtCQUFrQjtvQkFDbkMsV0FBVztvQkFDWCxjQUFjLEVBQUUsS0FBSyxFQUFFLDhDQUE4QztpQkFDdEU7Z0JBQ0QsS0FBSyxFQUFFLGtCQUFrQjtnQkFDekIsZUFBZSxFQUFFLEVBQUU7YUFDcEI7U0FDRjtRQUNELFdBQVcsRUFBRSxFQUFFO1FBQ2YsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMs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