bitgo
Version:
BitGo JavaScript SDK
574 lines • 107 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const sdk_core_1 = require("@bitgo/sdk-core");
const openpgp = require("openpgp");
const should = require("should");
const _ = require("lodash");
const sdk_test_1 = require("@bitgo/sdk-test");
const bitgo_1 = require("../../../../src/bitgo");
const helpers_1 = require("./helpers");
const sinon = require("sinon");
const nock = require("nock");
describe('test tss helper functions', function () {
let mpc;
let userKeyShare;
let backupKeyShare;
let bitgoKeyShare;
let userKey;
let backupKey;
let bitgoKey;
let userGpgKeypair;
let backupGpgKeypair;
let bitgoGpgKeypair;
let commonKeychain;
before(async function () {
const hdTree = await sdk_core_1.Ed25519BIP32.initialize();
mpc = await sdk_core_1.Eddsa.initialize(hdTree);
userKeyShare = mpc.keyShare(1, 2, 3);
backupKeyShare = mpc.keyShare(2, 2, 3);
bitgoKeyShare = mpc.keyShare(3, 2, 3);
userKey = mpc.keyCombine(userKeyShare.uShare, [backupKeyShare.yShares[1], bitgoKeyShare.yShares[1]]);
backupKey = mpc.keyCombine(backupKeyShare.uShare, [userKeyShare.yShares[2], bitgoKeyShare.yShares[2]]);
bitgoKey = mpc.keyCombine(bitgoKeyShare.uShare, [backupKeyShare.yShares[3], userKeyShare.yShares[3]]);
(userKey.pShare.y + userKey.pShare.chaincode).should.equal(backupKey.pShare.y + backupKey.pShare.chaincode);
(userKey.pShare.y + userKey.pShare.chaincode).should.equal(bitgoKey.pShare.y + bitgoKey.pShare.chaincode);
commonKeychain = userKey.pShare.y + userKey.pShare.chaincode;
userGpgKeypair = await openpgp.generateKey({
userIDs: [
{
name: 'user',
email: 'user@bitgo.com',
},
],
});
backupGpgKeypair = await openpgp.generateKey({
userIDs: [
{
name: 'backup',
email: 'backup@bitgo.com',
},
],
});
bitgoGpgKeypair = await openpgp.generateKey({
userIDs: [
{
name: 'bitgo',
email: 'bitgo@bitgo.com',
},
],
});
});
after(function () {
nock.cleanAll();
});
describe('encryptYShare', function () {
it('should encrypt y share', async function () {
for (let i = 2; i <= 3; i++) {
const encryptedYShare = await (0, sdk_core_1.encryptYShare)({
keyShare: userKeyShare,
recipientIndex: i,
senderGpgPrivateArmor: userGpgKeypair.privateKey,
recipientGpgPublicArmor: bitgoGpgKeypair.publicKey,
});
const decryptedMessage = await (0, sdk_core_1.readSignedMessage)(encryptedYShare.encryptedPrivateShare, userGpgKeypair.publicKey, bitgoGpgKeypair.privateKey);
decryptedMessage.should.equal(userKeyShare.yShares[i].u + userKeyShare.yShares[i].chaincode);
encryptedYShare.i.should.equal(i);
encryptedYShare.j.should.equal(1);
encryptedYShare.publicShare.should.equal(userKeyShare.uShare.y + userKeyShare.yShares[3].v + userKeyShare.uShare.chaincode);
}
});
it('should error for invalid recipient index', async function () {
await (0, sdk_core_1.encryptYShare)({
keyShare: userKeyShare,
recipientIndex: 1,
senderGpgPrivateArmor: userGpgKeypair.privateKey,
recipientGpgPublicArmor: bitgoGpgKeypair.publicKey,
}).should.be.rejectedWith('Invalid recipient');
await (0, sdk_core_1.encryptYShare)({
keyShare: backupKeyShare,
recipientIndex: 2,
senderGpgPrivateArmor: userGpgKeypair.privateKey,
recipientGpgPublicArmor: bitgoGpgKeypair.publicKey,
}).should.be.rejectedWith('Invalid recipient');
await (0, sdk_core_1.encryptYShare)({
keyShare: bitgoKeyShare,
recipientIndex: 3,
senderGpgPrivateArmor: userGpgKeypair.privateKey,
recipientGpgPublicArmor: bitgoGpgKeypair.publicKey,
}).should.be.rejectedWith('Invalid recipient');
});
});
describe('createCombinedKey', function () {
it('should create combined user key', async function () {
const bitgoToUserShare = await (0, sdk_core_1.encryptYShare)({
keyShare: bitgoKeyShare,
recipientIndex: 1,
recipientGpgPublicArmor: userGpgKeypair.publicKey,
senderGpgPrivateArmor: bitgoGpgKeypair.privateKey,
});
const backupToUserShare = await (0, sdk_core_1.encryptYShare)({
keyShare: backupKeyShare,
recipientIndex: 1,
recipientGpgPublicArmor: userGpgKeypair.publicKey,
senderGpgPrivateArmor: backupGpgKeypair.privateKey,
});
const combinedUserKey = await (0, sdk_core_1.createCombinedKey)({
keyShare: userKeyShare,
commonKeychain,
encryptedYShares: [
{
yShare: bitgoToUserShare,
recipientPrivateArmor: userGpgKeypair.privateKey,
senderPublicArmor: bitgoGpgKeypair.publicKey,
},
{
yShare: backupToUserShare,
recipientPrivateArmor: userGpgKeypair.privateKey,
senderPublicArmor: backupGpgKeypair.publicKey,
},
],
});
combinedUserKey.commonKeychain.should.equal(commonKeychain);
combinedUserKey.signingMaterial.uShare.should.deepEqual(userKeyShare.uShare);
combinedUserKey.signingMaterial.backupYShare.should.deepEqual(backupKeyShare.yShares[1]);
combinedUserKey.signingMaterial.bitgoYShare.should.deepEqual(bitgoKeyShare.yShares[1]);
should.not.exist(combinedUserKey.signingMaterial.userYShare);
});
it('should create combined backup key', async function () {
const bitgoToBackupShare = await (0, sdk_core_1.encryptYShare)({
keyShare: bitgoKeyShare,
recipientIndex: 2,
recipientGpgPublicArmor: backupGpgKeypair.publicKey,
senderGpgPrivateArmor: bitgoGpgKeypair.privateKey,
});
const userToBackupShare = await (0, sdk_core_1.encryptYShare)({
keyShare: userKeyShare,
recipientIndex: 2,
recipientGpgPublicArmor: backupGpgKeypair.publicKey,
senderGpgPrivateArmor: userGpgKeypair.privateKey,
});
const combinedBackupKey = await (0, sdk_core_1.createCombinedKey)({
keyShare: backupKeyShare,
commonKeychain,
encryptedYShares: [
{
yShare: bitgoToBackupShare,
recipientPrivateArmor: backupGpgKeypair.privateKey,
senderPublicArmor: bitgoGpgKeypair.publicKey,
},
{
yShare: userToBackupShare,
recipientPrivateArmor: backupGpgKeypair.privateKey,
senderPublicArmor: userGpgKeypair.publicKey,
},
],
});
combinedBackupKey.commonKeychain.should.equal(commonKeychain);
combinedBackupKey.signingMaterial.uShare.should.deepEqual(backupKeyShare.uShare);
combinedBackupKey.signingMaterial.userYShare.should.deepEqual(userKeyShare.yShares[2]);
combinedBackupKey.signingMaterial.bitgoYShare.should.deepEqual(bitgoKeyShare.yShares[2]);
should.not.exist(combinedBackupKey.signingMaterial.backupYShare);
});
it('should fail if common keychains do not match', async function () {
const bitgoToUserShare = await (0, sdk_core_1.encryptYShare)({
keyShare: bitgoKeyShare,
recipientIndex: 1,
recipientGpgPublicArmor: userGpgKeypair.publicKey,
senderGpgPrivateArmor: bitgoGpgKeypair.privateKey,
});
const backupToUserShare = await (0, sdk_core_1.encryptYShare)({
keyShare: backupKeyShare,
recipientIndex: 1,
recipientGpgPublicArmor: userGpgKeypair.publicKey,
senderGpgPrivateArmor: backupGpgKeypair.privateKey,
});
await (0, sdk_core_1.createCombinedKey)({
keyShare: userKeyShare,
commonKeychain: 'nottherightkeychain',
encryptedYShares: [
{
yShare: bitgoToUserShare,
recipientPrivateArmor: userGpgKeypair.privateKey,
senderPublicArmor: bitgoGpgKeypair.publicKey,
},
{
yShare: backupToUserShare,
recipientPrivateArmor: userGpgKeypair.privateKey,
senderPublicArmor: backupGpgKeypair.publicKey,
},
],
}).should.be.rejectedWith('Common keychains do not match');
});
it('should fail if gpg keys are mismatched', async function () {
const bitgoToUserShare = await (0, sdk_core_1.encryptYShare)({
keyShare: bitgoKeyShare,
recipientIndex: 1,
recipientGpgPublicArmor: userGpgKeypair.publicKey,
senderGpgPrivateArmor: bitgoGpgKeypair.privateKey,
});
const backupToUserShare = await (0, sdk_core_1.encryptYShare)({
keyShare: backupKeyShare,
recipientIndex: 1,
recipientGpgPublicArmor: userGpgKeypair.publicKey,
senderGpgPrivateArmor: backupGpgKeypair.privateKey,
});
await (0, sdk_core_1.createCombinedKey)({
keyShare: userKeyShare,
commonKeychain: 'nottherightkeychain',
encryptedYShares: [
{
yShare: bitgoToUserShare,
recipientPrivateArmor: backupGpgKeypair.privateKey,
senderPublicArmor: bitgoGpgKeypair.publicKey,
},
{
yShare: backupToUserShare,
recipientPrivateArmor: userGpgKeypair.privateKey,
senderPublicArmor: backupGpgKeypair.publicKey,
},
],
}).should.be.rejectedWith('Error decrypting message: Session key decryption failed.');
});
});
describe('Eddsa tss signing helper function', async function () {
const bitgo = sdk_test_1.TestBitGo.decorate(bitgo_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
let wallet;
const path = 'm/0';
const validUserSigningMaterial = {
uShare: {
i: 1,
t: 2,
n: 3,
y: '093c8603ad86c41d5ee25a814b88185b435dd3a9ceccf9c9fd691a465ac4a8b0',
seed: 'ca40c789813250c334ddd2ba19050f6ed20b5a08853ceca492358f2711ad4b15',
chaincode: '596d5404a7eb918ee78247b952d06539619884091fdd9e0ff5a665f349e32fca',
},
commonChaincode: '596d5404a7eb918ee78247b952d06539619884091fdd9e0ff5a665f349e32fca',
bitgoYShare: {
i: 1,
j: 3,
y: '59d8000ba5e85fa402f39382960e7d5ede82b1b6e22b146a18b7df238c3a3225',
v: '01ea3f425b1adf8aec6cfe4fc8f9b94755c34657965f32397655dcd784f1b517',
u: '9ce3204a8c9757738967f3f81b463d87267bf6f2c0e5eaf2843167537b872b0b',
chaincode: 'd21dbd8eae5d4789292ecea2efa53e0165b2439d57f5158eb4dd57dc26b59236',
},
backupYShare: {
i: 1,
j: 2,
y: 'e0ae75077715686a121acb41b29a55bde426971154f40a41fc317f7f774a9424',
v: 'f76ef629dfc15ab5e4531e532b5d67f2176637ca752b195876b7e3172459c969',
u: 'fe6b89fb6acfcd7392c35c084f58bde0846b888c4df57e466caf0a3271b06a05',
chaincode: '1c34e5dfbbd4a870f4479caaa5e6a46e3438f976ad5aefd4905b8fe8bca1101e',
},
};
const validUserSignShare = {
xShare: {
i: 1,
y: '4d9343988e68191aac945a6963031dddde3490f9020d0571a6e6c6e15cca0296',
u: '1e159d6a0ae3a8dccc74615113e7c3e25d3080e5e0ffeb0ae04dd6a967268102',
r: 'c8f64cc48926216c3f60e1d8ff1e24eba060d7c1ff020d0fc1d735d4564efd03',
R: '9be2208ee28cd4b2577a9a66f6aab1ed8b08a300969eeb9b203a52aa54d2c23c',
},
rShares: {
3: {
i: 3,
j: 1,
u: 'd675f9099fbef03aa9fcdca4009286f435e56369c374d0042f03cc60b49e690a',
v: '3c090e88ed42da0dd0bade35c8d6b88bc050284536b98e5b27d33ff45da9755b',
r: '7f16224dbf5b02adb6c21380fcb2a8ee00323daae62cac3575a4d328fd23a905',
R: '9be2208ee28cd4b2577a9a66f6aab1ed8b08a300969eeb9b203a52aa54d2c23c',
commitment: '445c8cb1dee0166b6bdd5ad1d0a53fbfe86c4d3a470f184745530a863eedff28',
},
},
};
const validUserToBitgoGShare = {
i: 1,
y: '4d9343988e68191aac945a6963031dddde3490f9020d0571a6e6c6e15cca0296',
gamma: 'ce87a00d17e52b91bc5bb6e275983b84fc1998b2b37f7166c671a019c33d3905',
R: 'aa6e5bad24ad4131b8793dcb95c72e03c5426456ab0b52fc99d61d7103c2f01b',
};
const validBitgoToUserSignShare = {
xShare: {
i: 3,
y: '4d9343988e68191aac945a6963031dddde3490f9020d0571a6e6c6e15cca0296',
u: '1315dbe18069825b4a27188b813eae7ff2917a614499ed553e70d65d4fa4820b',
r: 'd0539375e6566f2fe540cba48c5e56bd1cdf68cfe1f0d527d2b730fe4e879809',
R: 'c883fe2ae9b8da1764cc36a526cfa1a21f81d604320b209867f8de9223f1de32',
},
rShares: {
1: {
i: 1,
j: 3,
u: '9ce3204a8c9757738967f3f81b463d87267bf6f2c0e5eaf2843167537b872b0b',
v: '01ea3f425b1adf8aec6cfe4fc8f9b94755c34657965f32397655dcd784f1b517',
r: '0375e8c5a5691a73c21df00d49d423e3f83fe08d7b5d5af33c5c6aa9cae59d0a',
R: 'c883fe2ae9b8da1764cc36a526cfa1a21f81d604320b209867f8de9223f1de32',
commitment: '62b21f98bf885841ad469145192d4df0697b3f42c581e3e926394eae0b101ecb',
},
},
};
const txRequest = {
txRequestId: 'randomId',
unsignedTxs: [{ signableHex: 'MPC on a Friday night', serializedTxHex: 'MPC on a Friday night' }],
signatureShares: [
{
from: 'bitgo',
to: 'user',
share: validBitgoToUserSignShare.rShares[1].r + validBitgoToUserSignShare.rShares[1].R,
},
],
};
const signablePayload = Buffer.from(txRequest.unsignedTxs[0].signableHex);
const bitgoToUserCommitment = {
from: sdk_core_1.SignatureShareType.BITGO,
to: sdk_core_1.SignatureShareType.USER,
share: validBitgoToUserSignShare.rShares[1].commitment,
type: sdk_core_1.CommitmentType.COMMITMENT,
};
let MPC;
before('initializes', async function () {
const hdTree = await sdk_core_1.Ed25519BIP32.initialize();
MPC = await sdk_core_1.Eddsa.initialize(hdTree);
const baseCoin = bitgo.coin('tsol');
const walletData = {
id: '5b34252f1bf349930e34020a00000000',
coin: 'tsol',
keys: [
'5b3424f91bf349930e34017500000000',
'5b3424f91bf349930e34017600000000',
'5b3424f91bf349930e34017700000000',
],
coinSpecific: {},
};
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, walletData);
});
describe('createUserSignShare:', async function () {
it('should succeed to create User SignShare', async function () {
const signingKey = MPC.keyDerive(validUserSigningMaterial.uShare, [validUserSigningMaterial.bitgoYShare, validUserSigningMaterial.backupYShare], path);
const userSignShare = await (0, sdk_core_1.createUserSignShare)(signablePayload, signingKey.pShare);
userSignShare.should.have.properties(['xShare', 'rShares']);
const { xShare, rShares } = userSignShare;
xShare.should.have.property('i').and.be.a.Number();
xShare.should.have.property('y').and.be.a.String();
xShare.should.have.property('u').and.be.a.String();
xShare.should.have.property('r').and.be.a.String();
xShare.should.have.property('R').and.be.a.String();
rShares.should.have.property('3').and.be.an.Object();
rShares[3].should.have.property('i').and.be.a.Number();
rShares[3].should.have.property('j').and.be.a.Number();
rShares[3].should.have.property('r').and.be.a.String();
rShares[3].should.have.property('R').and.be.a.String();
});
it('should fail if the Pshare doesnt belong to the User', async function () {
const invalidUserSigningMaterial = JSON.parse('{"uShare":{"i":2,"t":2,"n":3,"y":"e2b844934b56f278b4a8a3665d43d14de80732241622ec7a8bd6cffc0f74452a","seed":"5259ee23a364429919f969247323eee2f4af5786457b4af67d423f8944d3a691","chaincode":"7460de17d732969c3bc9bddbac1055aff168fad5668917b8ed3fd9628fc6e4f8"},"bitgoYShare":{"i":2,"j":3,"y":"141fd5cbb901d46b8c2c783f3d4ee968ae91c38f71aba05146b3ba8bd4309596","u":"581cfacb3de956cc434a35a3ac927f7d0a4daaef48a95c162cadb7878ef2270b","chaincode":"67d33063052606f341cae40877709de725abda41f2df7f4765e3f58ce5030e1a"},"backupYShare":{"i":2,"j":1,"y":"9e69e3e92978896e872d71ff7a9e63a963ab0f59583d4fcbe79f82cde9ea6bf9","u":"52a539f79df448a2f5108a5e410377cbd1574b7c3d9864bb310ebf7beb13460d","chaincode":"bda980c34aa06916f25c4c7934ea09a928bff7730a100902f4d53bb9236771a7"}}');
const signingKey = MPC.keyDerive(invalidUserSigningMaterial.uShare, [invalidUserSigningMaterial.bitgoYShare, invalidUserSigningMaterial.backupYShare], path);
await (0, sdk_core_1.createUserSignShare)(signablePayload, signingKey.pShare).should.be.rejectedWith('Invalid PShare, PShare doesnt belong to the User');
});
});
describe('sendSignatureShare:', async function () {
it('should succeed to send Signature Share', async function () {
const signatureShare = { from: 'user', to: 'bitgo', share: '128bytestring' };
await (0, helpers_1.nockSendSignatureShare)({
walletId: wallet.id(),
txRequestId: txRequest.txRequestId,
signatureShare,
signerShare: 'signerShare',
});
const response = await (0, sdk_core_1.sendSignatureShare)(bitgo, wallet.id(), txRequest.txRequestId, signatureShare, sdk_core_1.RequestType.tx, 'signerShare');
response.should.deepEqual(signatureShare);
});
it('should fail to send Signature Share', async function () {
const invalidSignatureShare = { from: 'bitgo', to: 'user', share: '128bytestring' };
const nock = await (0, helpers_1.nockSendSignatureShare)({
walletId: wallet.id(),
txRequestId: txRequest.txRequestId,
signatureShare: invalidSignatureShare,
signerShare: 'signerShare',
}, 400);
await (0, sdk_core_1.sendSignatureShare)(bitgo, wallet.id(), txRequest.txRequestId, invalidSignatureShare, sdk_core_1.RequestType.tx, 'signerShare').should.be.rejectedWith('some error');
nock.isDone().should.equal(true);
});
});
describe('offerUserToBitgoRShare:', async function () {
it('should succeed to send Signature Share', async function () {
const signatureShare = {
from: 'user',
to: 'bitgo',
share: validUserSignShare.rShares[3].r + validUserSignShare.rShares[3].R,
};
const nock = await (0, helpers_1.nockSendSignatureShare)({
walletId: wallet.id(),
txRequestId: txRequest.txRequestId,
signatureShare,
signerShare: 'signerShare',
});
await (0, sdk_core_1.offerUserToBitgoRShare)(bitgo, wallet.id(), txRequest.txRequestId, validUserSignShare, 'signerShare').should.be.fulfilled();
nock.isDone().should.equal(true);
});
it('should fail if no rShare is found', async function () {
const invalidUserSignShare = _.cloneDeep(validUserSignShare);
delete invalidUserSignShare.rShares[3];
await (0, sdk_core_1.offerUserToBitgoRShare)(bitgo, wallet.id(), txRequest.txRequestId, invalidUserSignShare, 'signerShare').should.be.rejectedWith('userToBitgo RShare not found');
});
it('should fail if the rShare found is invalid', async function () {
const invalidUserSignShare = _.cloneDeep(validUserSignShare);
invalidUserSignShare.rShares[3].i = 1;
await (0, sdk_core_1.offerUserToBitgoRShare)(bitgo, wallet.id(), txRequest.txRequestId, invalidUserSignShare, 'signerShare').should.be.rejectedWith('Invalid RShare, is not from User to Bitgo');
const invalidUserSignShare2 = _.cloneDeep(validUserSignShare);
invalidUserSignShare2.rShares[3].j = 3;
await (0, sdk_core_1.offerUserToBitgoRShare)(bitgo, wallet.id(), txRequest.txRequestId, invalidUserSignShare2, 'signerShare').should.be.rejectedWith('Invalid RShare, is not from User to Bitgo');
});
it('should call setRequestTracer', async function () {
const signatureShare = {
from: 'user',
to: 'bitgo',
share: validUserSignShare.rShares[3].r + validUserSignShare.rShares[3].R,
};
const nock = await (0, helpers_1.nockSendSignatureShare)({
walletId: wallet.id(),
txRequestId: txRequest.txRequestId,
signatureShare,
signerShare: 'signerShare',
});
const reqId = new sdk_core_1.RequestTracer();
const setRequestTracerSpy = sinon.spy(bitgo, 'setRequestTracer');
setRequestTracerSpy.withArgs(reqId);
await (0, sdk_core_1.offerUserToBitgoRShare)(bitgo, wallet.id(), txRequest.txRequestId, validUserSignShare, 'signerShare', undefined, reqId).should.be.fulfilled();
nock.isDone().should.equal(true);
sinon.assert.calledOnce(setRequestTracerSpy);
setRequestTracerSpy.restore();
});
});
describe('getBitgoToUserRShare:', async function () {
it('should succeed to get the Bitgo to User RShare', async function () {
const response = { txRequests: [txRequest] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
const bitgoToUserRShare = await (0, sdk_core_1.getBitgoToUserRShare)(bitgo, wallet.id(), txRequest.txRequestId);
bitgoToUserRShare.should.deepEqual(txRequest.signatureShares[0]);
nock.isDone().should.equal(true);
});
it('should fail if there is no bitgo to user RShare', async function () {
const invalidTxRequest = _.cloneDeep(txRequest);
invalidTxRequest.signatureShares[0].to = 'bitgo';
invalidTxRequest.signatureShares[0].from = 'user';
const response = { txRequests: [invalidTxRequest] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
await (0, sdk_core_1.getBitgoToUserRShare)(bitgo, wallet.id(), txRequest.txRequestId).should.be.rejectedWith('Bitgo to User RShare not found for id: ' + txRequest.txRequestId);
nock.isDone().should.equal(true);
});
it('should fail if there is no signaturesShares', async function () {
const invalidTxRequest = _.cloneDeep(txRequest);
invalidTxRequest.signatureShares = [];
const response = { txRequests: [invalidTxRequest] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
await (0, sdk_core_1.getBitgoToUserRShare)(bitgo, wallet.id(), txRequest.txRequestId).should.be.rejectedWith('No signatures shares found for id: ' + txRequest.txRequestId);
nock.isDone().should.equal(true);
});
it('should call setRequestTracer', async function () {
const response = { txRequests: [txRequest] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
const reqId = new sdk_core_1.RequestTracer();
const setRequestTracerSpy = sinon.spy(bitgo, 'setRequestTracer');
setRequestTracerSpy.withArgs(reqId);
const bitgoToUserRShare = await (0, sdk_core_1.getBitgoToUserRShare)(bitgo, wallet.id(), txRequest.txRequestId, reqId);
bitgoToUserRShare.should.deepEqual(txRequest.signatureShares[0]);
nock.isDone().should.equal(true);
sinon.assert.calledOnce(setRequestTracerSpy);
setRequestTracerSpy.restore();
});
});
describe('sendUserToBitgoGShare:', async function () {
it('should succeed to send User to Bitgo GShare', async function () {
const signatureShare = {
from: 'user',
to: 'bitgo',
share: validUserToBitgoGShare.R + validUserToBitgoGShare.gamma,
};
const nock = await (0, helpers_1.nockSendSignatureShare)({
walletId: wallet.id(),
txRequestId: txRequest.txRequestId,
signatureShare,
});
await (0, sdk_core_1.sendUserToBitgoGShare)(bitgo, wallet.id(), txRequest.txRequestId, validUserToBitgoGShare).should.be.fulfilled();
nock.isDone().should.equal(true);
});
it('should fail when the GShare is not from the User', async function () {
const invalidUserToBitgoGShare = _.cloneDeep(validUserToBitgoGShare);
invalidUserToBitgoGShare.i = 3;
await (0, sdk_core_1.sendUserToBitgoGShare)(bitgo, wallet.id(), txRequest.txRequestId, invalidUserToBitgoGShare).should.be.rejectedWith('Invalid GShare, doesnt belong to the User');
});
it('should call setRequestTracer', async function () {
const signatureShare = {
from: 'user',
to: 'bitgo',
share: validUserToBitgoGShare.R + validUserToBitgoGShare.gamma,
};
const nock = await (0, helpers_1.nockSendSignatureShare)({
walletId: wallet.id(),
txRequestId: txRequest.txRequestId,
signatureShare,
});
const reqId = new sdk_core_1.RequestTracer();
const setRequestTracerSpy = sinon.spy(bitgo, 'setRequestTracer');
setRequestTracerSpy.withArgs(reqId);
await (0, sdk_core_1.sendUserToBitgoGShare)(bitgo, wallet.id(), txRequest.txRequestId, validUserToBitgoGShare, undefined, reqId).should.be.fulfilled();
nock.isDone().should.equal(true);
sinon.assert.calledOnce(setRequestTracerSpy);
setRequestTracerSpy.restore();
});
});
describe('getTxRequest:', async function () {
it('should succeed to get txRequest by id', async function () {
const response = { txRequests: [txRequest] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
const txReq = await (0, sdk_core_1.getTxRequest)(bitgo, wallet.id(), txRequest.txRequestId);
txReq.should.deepEqual(txRequest);
nock.isDone().should.equal(true);
});
it('should fail if there are no txRequests', async function () {
const response = { txRequests: [] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
await (0, sdk_core_1.getTxRequest)(bitgo, wallet.id(), txRequest.txRequestId).should.be.rejectedWith('Unable to find TxRequest with id randomId');
nock.isDone().should.equal(true);
});
it('should call setRequestTracer', async function () {
const response = { txRequests: [txRequest] };
const nock = await (0, helpers_1.nockGetTxRequest)({ walletId: wallet.id(), txRequestId: txRequest.txRequestId, response });
const reqId = new sdk_core_1.RequestTracer();
const setRequestTracerSpy = sinon.spy(bitgo, 'setRequestTracer');
setRequestTracerSpy.withArgs(reqId);
const txReq = await (0, sdk_core_1.getTxRequest)(bitgo, wallet.id(), txRequest.txRequestId, reqId);
txReq.should.deepEqual(txRequest);
nock.isDone().should.equal(true);
sinon.assert.calledOnce(setRequestTracerSpy);
setRequestTracerSpy.restore();
});
});
describe('createUserToBitGoGShare:', async function () {
it('should succeed to create a UserToBitGo GShare', async function () {
const userToBitgoGShare = await (0, sdk_core_1.createUserToBitGoGShare)(validUserSignShare, txRequest.signatureShares[0], validUserSigningMaterial.backupYShare, validUserSigningMaterial.bitgoYShare, signablePayload, bitgoToUserCommitment);
userToBitgoGShare.should.deepEqual(validUserToBitgoGShare);
});
it('should fail when XShare doesnt belong to the user', async function () {
const invalidUserSignShare = _.cloneDeep(validUserSignShare);
invalidUserSignShare.xShare.i = 3;
await (0, sdk_core_1.createUserToBitGoGShare)(invalidUserSignShare, txRequest.signatureShares[0], validUserSigningMaterial.backupYShare, validUserSigningMaterial.bitgoYShare, signablePayload, bitgoToUserCommitment).should.be.rejectedWith('Invalid XShare, doesnt belong to the User');
});
it('should fail when commitment is invalid', async function () {
const invalidBitgoToUserCommitment = _.cloneDeep(bitgoToUserCommitment);
invalidBitgoToUserCommitment.share = 'deadbeef';
await (0, sdk_core_1.createUserToBitGoGShare)(validUserSignShare, txRequest.signatureShares[0], validUserSigningMaterial.backupYShare, validUserSigningMaterial.bitgoYShare, signablePayload, invalidBitgoToUserCommitment).should.be.rejectedWith('Could not verify other player share');
});
it('should fail when RShare doesnt belong to Bitgo', async function () {
const invalidBitgoRShare = _.cloneDeep(txRequest.signatureShares[0]);
invalidBitgoRShare.from = 'user';
await (0, sdk_core_1.createUserToBitGoGShare)(validUserSignShare, invalidBitgoRShare, validUserSigningMaterial.backupYShare, validUserSigningMaterial.bitgoYShare, signablePayload, bitgoToUserCommitment).should.be.rejectedWith('Invalid RShare, is not from Bitgo to User');
const invalidBitgoRShare2 = _.cloneDeep(txRequest.signatureShares[0]);
invalidBitgoRShare2.to = 'bitgo';
await (0, sdk_core_1.createUserToBitGoGShare)(validUserSignShare, invalidBitgoRShare2, validUserSigningMaterial.backupYShare, validUserSigningMaterial.bitgoYShare, signablePayload, bitgoToUserCommitment).should.be.rejectedWith('Invalid RShare, is not from Bitgo to User');
});
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRkc2EuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZXN0L3YyL3VuaXQvdHNzL2VkZHNhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsOENBc0J5QjtBQUN6QixtQ0FBbUM7QUFDbkMsaUNBQWtDO0FBQ2xDLDRCQUE0QjtBQUM1Qiw4Q0FBNEM7QUFDNUMsaURBQThDO0FBQzlDLHVDQUFxRTtBQUNyRSwrQkFBK0I7QUFDL0IsNkJBQThCO0FBRTlCLFFBQVEsQ0FBQywyQkFBMkIsRUFBRTtJQUNwQyxJQUFJLEdBQVUsQ0FBQztJQUVmLElBQUksWUFBc0IsQ0FBQztJQUMzQixJQUFJLGNBQXdCLENBQUM7SUFDN0IsSUFBSSxhQUF1QixDQUFDO0lBRTVCLElBQUksT0FBTyxDQUFDO0lBQ1osSUFBSSxTQUFTLENBQUM7SUFDZCxJQUFJLFFBQVEsQ0FBQztJQUViLElBQUksY0FBeUQsQ0FBQztJQUM5RCxJQUFJLGdCQUEyRCxDQUFDO0lBQ2hFLElBQUksZUFBMEQsQ0FBQztJQUUvRCxJQUFJLGNBQXNCLENBQUM7SUFFM0IsTUFBTSxDQUFDLEtBQUs7UUFDVixNQUFNLE1BQU0sR0FBRyxNQUFNLHVCQUFZLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDL0MsR0FBRyxHQUFHLE1BQU0sZ0JBQUssQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFckMsWUFBWSxHQUFHLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNyQyxjQUFjLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLGFBQWEsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFdEMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDLE1BQU0s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QyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDbkQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNuRCxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ25ELE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDbkQsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNyRCxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3ZELE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDdkQsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUN2RCxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDekQsQ0FBQyxDQUFDLENBQUM7WUFFSCxFQUFFLENBQUMscURBQXFELEVBQUUsS0FBSztnQkFDN0QsTUFBTSwwQkFBMEIsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUMzQyxtdkJBQW12QixDQUNwdkIsQ0FBQztnQkFDRixNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUM5QiwwQkFBMEIsQ0FBQyxNQUFNLEVBQ2pDLENBQUMsMEJBQTBCLENBQUMsV0FBVyxFQUFFLDBCQUEwQixDQUFDLFlBQVksQ0FBQyxFQUNqRixJQUFJLENBQ0wsQ0FBQztnQkFDRixNQUFNLElBQUEsOEJBQW1CLEVBQUMsZUFBZSxFQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FDbEYsa0RBQWtELENBQ25ELENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsUUFBUSxDQUFDLHFCQUFxQixFQUFFLEtBQUs7WUFDbkMsRUFBRSxDQUFDLHdDQUF3QyxFQUFFLEtBQUs7Z0JBQ2hELE1BQU0sY0FBYyxHQ