@bitpay-labs/bitcore-wallet-service 11.11.2 → 11.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/lib/common/constants.ts +1 -1
- package/src/lib/common/utils.ts +18 -1
- package/src/lib/model/tsskeygen.ts +16 -0
- package/src/lib/routes/maintenance.ts +11 -2
- package/src/lib/routes/middleware/authTssRequest.ts +28 -16
- package/src/lib/routes/middleware/verifyTssMessage.ts +4 -1
- package/src/lib/routes/services.ts +7 -1
- package/src/lib/routes/tss.ts +33 -30
- package/src/lib/server.ts +62 -17
- package/src/lib/storage.ts +39 -0
- package/src/lib/tss.ts +111 -7
- package/test/expressapp.test.ts +99 -0
- package/test/integration/server.test.ts +53 -1
- package/test/integration/tss.test.ts +428 -0
- package/ts_build/package.json +4 -4
- package/ts_build/src/lib/common/constants.d.ts +1 -1
- package/ts_build/src/lib/common/constants.js +1 -1
- package/ts_build/src/lib/common/index.d.ts +2 -1
- package/ts_build/src/lib/common/index.d.ts.map +1 -1
- package/ts_build/src/lib/common/utils.d.ts +1 -0
- package/ts_build/src/lib/common/utils.d.ts.map +1 -1
- package/ts_build/src/lib/common/utils.js +16 -1
- package/ts_build/src/lib/common/utils.js.map +1 -1
- package/ts_build/src/lib/model/tsskeygen.d.ts +10 -0
- package/ts_build/src/lib/model/tsskeygen.d.ts.map +1 -1
- package/ts_build/src/lib/model/tsskeygen.js +3 -0
- package/ts_build/src/lib/model/tsskeygen.js.map +1 -1
- package/ts_build/src/lib/routes/maintenance.d.ts.map +1 -1
- package/ts_build/src/lib/routes/maintenance.js +12 -4
- package/ts_build/src/lib/routes/maintenance.js.map +1 -1
- package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts +6 -2
- package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts.map +1 -1
- package/ts_build/src/lib/routes/middleware/authTssRequest.js +21 -14
- package/ts_build/src/lib/routes/middleware/authTssRequest.js.map +1 -1
- package/ts_build/src/lib/routes/middleware/verifyTssMessage.d.ts.map +1 -1
- package/ts_build/src/lib/routes/middleware/verifyTssMessage.js +2 -1
- package/ts_build/src/lib/routes/middleware/verifyTssMessage.js.map +1 -1
- package/ts_build/src/lib/routes/services.d.ts.map +1 -1
- package/ts_build/src/lib/routes/services.js +6 -1
- package/ts_build/src/lib/routes/services.js.map +1 -1
- package/ts_build/src/lib/routes/tss.d.ts.map +1 -1
- package/ts_build/src/lib/routes/tss.js +32 -30
- package/ts_build/src/lib/routes/tss.js.map +1 -1
- package/ts_build/src/lib/server.d.ts +23 -2
- package/ts_build/src/lib/server.d.ts.map +1 -1
- package/ts_build/src/lib/server.js +20 -3
- package/ts_build/src/lib/server.js.map +1 -1
- package/ts_build/src/lib/storage.d.ts +9 -0
- package/ts_build/src/lib/storage.d.ts.map +1 -1
- package/ts_build/src/lib/storage.js +26 -0
- package/ts_build/src/lib/storage.js.map +1 -1
- package/ts_build/src/lib/tss.d.ts +12 -0
- package/ts_build/src/lib/tss.d.ts.map +1 -1
- package/ts_build/src/lib/tss.js +64 -5
- package/ts_build/src/lib/tss.js.map +1 -1
- package/ts_build/test/expressapp.test.js +90 -0
- package/ts_build/test/expressapp.test.js.map +1 -1
- package/ts_build/test/integration/server.test.js +47 -0
- package/ts_build/test/integration/server.test.js.map +1 -1
- package/ts_build/test/integration/tss.test.d.ts.map +1 -1
- package/ts_build/test/integration/tss.test.js +344 -0
- package/ts_build/test/integration/tss.test.js.map +1 -1
package/src/lib/tss.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
import { BitcoreLib } from '@bitpay-labs/crypto-wallet-core';
|
|
3
3
|
import { Constants } from './common/constants';
|
|
4
|
+
import { Utils } from './common/utils';
|
|
4
5
|
import { Errors } from './errors/errordefinitions';
|
|
5
6
|
import logger from './logger';
|
|
6
7
|
import { TssKeyGenModel } from './model/tsskeygen';
|
|
@@ -553,7 +554,10 @@ class TssKeyGenClass {
|
|
|
553
554
|
// }
|
|
554
555
|
}
|
|
555
556
|
|
|
556
|
-
/**
|
|
557
|
+
/**
|
|
558
|
+
* Store the BWS join secret for the TSS keygen session
|
|
559
|
+
* @deprecated Use storeBwsJoinSecrets instead.
|
|
560
|
+
*/
|
|
557
561
|
async storeBwsJoinSecret(params: {
|
|
558
562
|
/** Session ID */
|
|
559
563
|
id: string;
|
|
@@ -587,10 +591,77 @@ class TssKeyGenClass {
|
|
|
587
591
|
}
|
|
588
592
|
}
|
|
589
593
|
|
|
590
|
-
/**
|
|
594
|
+
/**
|
|
595
|
+
* Store the party-encrypted BWS join secrets for a wallet on `chain`:`network` created with the TSS key.
|
|
596
|
+
* This can be called after the key generation session has expired to create additional wallets (e.g. other EVM chains) for the same key.
|
|
597
|
+
*/
|
|
598
|
+
async storeBwsJoinSecrets(params: {
|
|
599
|
+
/** Session ID */
|
|
600
|
+
id: string;
|
|
601
|
+
/** Blockchain (e.g., 'btc', 'eth') */
|
|
602
|
+
chain: string;
|
|
603
|
+
/** Network (e.g., 'livenet', 'testnet') */
|
|
604
|
+
network: string;
|
|
605
|
+
/** Party encrypted BWS join secrets, keyed by partyId or by the party's keygen session copayer ID */
|
|
606
|
+
secrets: { [party: string]: string };
|
|
607
|
+
/** Copayer ID of the submitting party (must be the session creator) */
|
|
608
|
+
copayerId: string;
|
|
609
|
+
}) {
|
|
610
|
+
const { id, copayerId } = params;
|
|
611
|
+
const { chain, network } = getSecretChainNetwork(params.chain, params.network);
|
|
612
|
+
if (!params.secrets || typeof params.secrets !== 'object' || Array.isArray(params.secrets)) {
|
|
613
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Invalid BWS join secrets provided');
|
|
614
|
+
}
|
|
615
|
+
const storage = WalletService.getStorage();
|
|
616
|
+
const session = await storage.fetchTssKeyGenSession({ id });
|
|
617
|
+
|
|
618
|
+
if (!session) {
|
|
619
|
+
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (session.participants.indexOf(copayerId) !== 0) {
|
|
623
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Only the session creator can store the BWS join secret');
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Only store secrets keyed by partyId for the other parties (1..n-1)
|
|
627
|
+
const secrets: { [partyId: number]: string } = {};
|
|
628
|
+
for (const [party, secret] of Object.entries(params.secrets)) {
|
|
629
|
+
const partyId = /^\d+$/.test(party) ? parseInt(party) : session.participants.indexOf(party);
|
|
630
|
+
if (!(partyId > 0 && partyId < session.n) || typeof secret !== 'string' || !secret) {
|
|
631
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Invalid BWS join secret for party ' + party);
|
|
632
|
+
}
|
|
633
|
+
if (secrets[partyId]) {
|
|
634
|
+
// Malformed secrets objects may be keyed by both partyId (number) and copayerId (string).
|
|
635
|
+
// While this technically won't break anything (only 1 secret will be stored), it indicates
|
|
636
|
+
// a malformation which could signal a broader issue with the client.
|
|
637
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Multiple BWS join secret for party ' + party);
|
|
638
|
+
}
|
|
639
|
+
secrets[partyId] = secret;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (Object.keys(secrets).length !== session.n - 1) {
|
|
643
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Missing BWS join secrets for some parties');
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const result = await storage.storeTssKeyBwsJoinSecrets({ id, chain, network, secrets });
|
|
647
|
+
if (!result.result.ok) {
|
|
648
|
+
logger.error('Failed to store TSS key generation BWS join secrets %o %o', id, result);
|
|
649
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Failed to store TSS key generation BWS join secrets');
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Get the BWS join secret for the TSS keygen session.
|
|
655
|
+
* If chain & network are given, returns the requesting party's encrypted secret for that chain & network.
|
|
656
|
+
* Otherwise, returns the legacy (< v1.3) unencrypted secret.
|
|
657
|
+
*/
|
|
591
658
|
async getBwsJoinSecret(params: {
|
|
592
659
|
/** Session ID */
|
|
593
660
|
id: string;
|
|
661
|
+
/** Blockchain (e.g., 'btc', 'eth'). Omitted by legacy clients */
|
|
662
|
+
chain?: string;
|
|
663
|
+
/** Network (e.g., 'livenet', 'testnet'). Omitted by legacy clients */
|
|
664
|
+
network?: string;
|
|
594
665
|
/** Copayer ID of the requesting party */
|
|
595
666
|
copayerId: string;
|
|
596
667
|
}): Promise<string> {
|
|
@@ -600,16 +671,42 @@ class TssKeyGenClass {
|
|
|
600
671
|
if (!session) {
|
|
601
672
|
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
602
673
|
}
|
|
603
|
-
|
|
674
|
+
const partyId = session.participants.indexOf(copayerId);
|
|
675
|
+
if (partyId === -1) {
|
|
604
676
|
throw Errors.TSS_NON_PARTICIPANT;
|
|
605
677
|
}
|
|
606
|
-
|
|
678
|
+
|
|
679
|
+
if (params.chain == null && params.network == null) {
|
|
680
|
+
// Legacy clients don't send chain & network
|
|
681
|
+
if (!session.bwsJoinSecret) {
|
|
682
|
+
throw Errors.TSS_BWS_JOIN_SECRET_NOT_FOUND;
|
|
683
|
+
}
|
|
684
|
+
return session.bwsJoinSecret;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Note: sessions < v1.3 can have chain-specific secrets too (i.e. wallets created with an existing TSS key)
|
|
688
|
+
const { chain, network } = getSecretChainNetwork(params.chain, params.network);
|
|
689
|
+
const secret = session.bwsJoinSecrets?.[`${chain}:${network}`]?.[partyId];
|
|
690
|
+
if (typeof secret !== 'string') {
|
|
607
691
|
throw Errors.TSS_BWS_JOIN_SECRET_NOT_FOUND;
|
|
608
692
|
}
|
|
609
|
-
return
|
|
693
|
+
return secret;
|
|
610
694
|
}
|
|
611
695
|
};
|
|
612
696
|
|
|
697
|
+
/** Validate and normalize the chain & network used to key the BWS join secrets */
|
|
698
|
+
function getSecretChainNetwork(chain: string, network: string) {
|
|
699
|
+
chain = typeof chain === 'string' ? chain.toLowerCase() : chain;
|
|
700
|
+
if (!Utils.checkValueInCollection(chain, Constants.CHAINS)) {
|
|
701
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Invalid chain provided');
|
|
702
|
+
}
|
|
703
|
+
network = typeof network === 'string' ? Utils.getNetworkName(chain, Utils.getGenericName(network.toLowerCase())) : network;
|
|
704
|
+
if (!Utils.checkValueInCollection(network, Constants.NETWORKS[chain])) {
|
|
705
|
+
throw Errors.TSS_GENERIC_ERROR.withMessage('Invalid network provided');
|
|
706
|
+
}
|
|
707
|
+
return { chain, network };
|
|
708
|
+
}
|
|
709
|
+
|
|
613
710
|
export const TssKeyGen = new TssKeyGenClass();
|
|
614
711
|
|
|
615
712
|
class TssSignClass {
|
|
@@ -748,7 +845,8 @@ class TssSignClass {
|
|
|
748
845
|
if (session.isExpired()) {
|
|
749
846
|
throw Errors.TSS_SESSION_EXPIRED;
|
|
750
847
|
}
|
|
751
|
-
|
|
848
|
+
// 1-of-N sessions won't have messages for other recipients
|
|
849
|
+
if (session.m > 1 && !this._isValidBroadcastMessage({ message }) && !this._isValidP2pMessage({ message })) {
|
|
752
850
|
throw Errors.TSS_INVALID_MESSAGE.withMessage('Invalid message provided');
|
|
753
851
|
}
|
|
754
852
|
|
|
@@ -903,8 +1001,10 @@ class TssSignClass {
|
|
|
903
1001
|
id: string;
|
|
904
1002
|
/** Signature to store */
|
|
905
1003
|
signature: ITssSigMessageObject['signature'];
|
|
1004
|
+
/** Copayer ID of the sender */
|
|
1005
|
+
copayerId: string;
|
|
906
1006
|
}): Promise<void> {
|
|
907
|
-
const { id, signature } = params;
|
|
1007
|
+
const { id, signature, copayerId } = params;
|
|
908
1008
|
if (!signature) {
|
|
909
1009
|
throw Errors.TSS_NO_FINAL_SIGNATURE;
|
|
910
1010
|
}
|
|
@@ -917,6 +1017,10 @@ class TssSignClass {
|
|
|
917
1017
|
if (!session) {
|
|
918
1018
|
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
919
1019
|
}
|
|
1020
|
+
const party = session.participants.find(p => p.copayerId === copayerId);
|
|
1021
|
+
if (!party) {
|
|
1022
|
+
throw Errors.TSS_NON_PARTICIPANT;
|
|
1023
|
+
}
|
|
920
1024
|
|
|
921
1025
|
const verifySig = (sig1, sig2) => {
|
|
922
1026
|
return sig1.r === sig2.r &&
|
package/test/expressapp.test.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { ExpressApp } from '../src/lib/expressapp';
|
|
|
13
13
|
import { ClientError } from '../src/lib/errors/clienterror';
|
|
14
14
|
import { BitcoreLib } from '@bitpay-labs/crypto-wallet-core';
|
|
15
15
|
import * as TestData from './testdata';
|
|
16
|
+
import { Stats } from '../src/lib/stats';
|
|
16
17
|
|
|
17
18
|
const Defaults = Common.Defaults;
|
|
18
19
|
const should = chai.should();
|
|
@@ -65,6 +66,104 @@ describe('ExpressApp', function() {
|
|
|
65
66
|
httpServer.close();
|
|
66
67
|
});
|
|
67
68
|
|
|
69
|
+
describe('Public query validation', function() {
|
|
70
|
+
let runStats, getFiatRate;
|
|
71
|
+
|
|
72
|
+
beforeEach(function() {
|
|
73
|
+
runStats = sandbox.stub(Stats.prototype, 'run').callsArgWith(0, null, {});
|
|
74
|
+
getFiatRate = sinon.stub().callsArgWith(1, null, {});
|
|
75
|
+
sandbox.stub(WalletService, 'initialize').callsArg(1);
|
|
76
|
+
sandbox.stub(WalletService, 'getInstance').returns({ getFiatRate } as any);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const targets = [
|
|
80
|
+
{ path: '/v1/stats/', parameter: 'network' },
|
|
81
|
+
{ path: '/v1/stats/', parameter: 'coin' },
|
|
82
|
+
{ path: '/v1/fiatrates/USD/', parameter: 'coin' }
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const { path, parameter } of targets) {
|
|
86
|
+
const value = parameter === 'network' ? 'livenet' : 'btc';
|
|
87
|
+
// Cover operator objects, bracket arrays, and duplicate parameters.
|
|
88
|
+
const invalidQueries = [
|
|
89
|
+
`${parameter}[$regex]=.*`,
|
|
90
|
+
`${parameter}[]=${value}`,
|
|
91
|
+
`${parameter}=${value}&${parameter}=${value}`
|
|
92
|
+
];
|
|
93
|
+
for (const query of invalidQueries) {
|
|
94
|
+
it(`should reject ${path}?${query} before accessing data`, function(done) {
|
|
95
|
+
start(ExpressApp, function() {
|
|
96
|
+
request({ url: testHost + ':' + testPort + config.basePath + path + '?' + query, json: true }, function(err, res, body) {
|
|
97
|
+
should.not.exist(err);
|
|
98
|
+
res.statusCode.should.equal(400);
|
|
99
|
+
body.code.should.equal('BADREQUEST');
|
|
100
|
+
runStats.called.should.equal(false);
|
|
101
|
+
getFiatRate.called.should.equal(false);
|
|
102
|
+
done();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const query of ['', '?coin=&network=']) {
|
|
110
|
+
it(`should preserve stats defaults for ${query || 'omitted parameters'}`, function(done) {
|
|
111
|
+
start(ExpressApp, function() {
|
|
112
|
+
request({ url: testHost + ':' + testPort + config.basePath + '/v1/stats/' + query, json: true }, function(err, res) {
|
|
113
|
+
should.not.exist(err);
|
|
114
|
+
res.statusCode.should.equal(200);
|
|
115
|
+
runStats.calledOnce.should.equal(true);
|
|
116
|
+
runStats.firstCall.thisValue.coin.should.equal('btc');
|
|
117
|
+
runStats.firstCall.thisValue.network.should.equal('livenet');
|
|
118
|
+
done();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
it('should pass valid stats filters through unchanged', function(done) {
|
|
125
|
+
start(ExpressApp, function() {
|
|
126
|
+
const query = '?coin=eth&network=testnet&from=2026-01-01&to=2026-02-01';
|
|
127
|
+
request({ url: testHost + ':' + testPort + config.basePath + '/v1/stats/' + query, json: true }, function(err, res) {
|
|
128
|
+
should.not.exist(err);
|
|
129
|
+
res.statusCode.should.equal(200);
|
|
130
|
+
runStats.calledOnce.should.equal(true);
|
|
131
|
+
const stats = runStats.firstCall.thisValue;
|
|
132
|
+
stats.coin.should.equal('eth');
|
|
133
|
+
stats.network.should.equal('testnet');
|
|
134
|
+
stats.from.should.equal('2026-01-01');
|
|
135
|
+
stats.to.should.equal('2026-02-01');
|
|
136
|
+
done();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
for (const query of ['', '?coin=']) {
|
|
142
|
+
it(`should preserve the fiat coin default for ${query || 'omitted parameters'}`, function(done) {
|
|
143
|
+
start(ExpressApp, function() {
|
|
144
|
+
request({ url: testHost + ':' + testPort + config.basePath + '/v1/fiatrates/USD/' + query, json: true }, function(err, res) {
|
|
145
|
+
should.not.exist(err);
|
|
146
|
+
res.statusCode.should.equal(200);
|
|
147
|
+
getFiatRate.calledOnceWithExactly({ code: 'USD', coin: 'btc', ts: null }, sinon.match.func).should.equal(true);
|
|
148
|
+
done();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
it('should pass a valid fiat coin and numeric timestamp through unchanged', function(done) {
|
|
155
|
+
start(ExpressApp, function() {
|
|
156
|
+
const query = '?coin=eth&ts=1700000000000';
|
|
157
|
+
request({ url: testHost + ':' + testPort + config.basePath + '/v1/fiatrates/EUR/' + query, json: true }, function(err, res) {
|
|
158
|
+
should.not.exist(err);
|
|
159
|
+
res.statusCode.should.equal(200);
|
|
160
|
+
getFiatRate.calledOnceWithExactly({ code: 'EUR', coin: 'eth', ts: 1700000000000 }, sinon.match.func).should.equal(true);
|
|
161
|
+
done();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
68
167
|
it('/v2/wallets', function(done) {
|
|
69
168
|
const server = {
|
|
70
169
|
getStatus: sinon.stub().callsArgWith(1, null, {}),
|
|
@@ -21,6 +21,7 @@ import * as TestData from '../testdata';
|
|
|
21
21
|
import helpers from './helpers';
|
|
22
22
|
import { ClientError } from '../../src/lib/errors/clienterror';
|
|
23
23
|
import { ExpressApp } from '../../src/lib/expressapp';
|
|
24
|
+
import { type JoinWalletOpts } from '../../src/lib/server';
|
|
24
25
|
|
|
25
26
|
const should = chai.should();
|
|
26
27
|
config.moralis = config.moralis ?? {
|
|
@@ -1120,7 +1121,7 @@ describe('Wallet service', function() {
|
|
|
1120
1121
|
xPubKey: TestData.copayers[0].xPubKey_44H_0H_0H,
|
|
1121
1122
|
requestPubKey: TestData.copayers[0].pubKey_1H_0,
|
|
1122
1123
|
};
|
|
1123
|
-
server.joinWallet(copayerOpts, function(err) {
|
|
1124
|
+
server.joinWallet(copayerOpts as JoinWalletOpts, function(err) {
|
|
1124
1125
|
should.exist(err);
|
|
1125
1126
|
err.message.should.contain('argument: copayerSignature missing');
|
|
1126
1127
|
done();
|
|
@@ -1774,6 +1775,57 @@ describe('Wallet service', function() {
|
|
|
1774
1775
|
wallet.copayers.length.should.equal(0);
|
|
1775
1776
|
});
|
|
1776
1777
|
});
|
|
1778
|
+
|
|
1779
|
+
describe('TSS wallets (concurrent join)', function() {
|
|
1780
|
+
it('should keep a copayer that joins while the wallet is being registered', async function() {
|
|
1781
|
+
const server = new WalletService();
|
|
1782
|
+
const copayerIds = [0, 1].map(i => Model.Copayer.xPubToCopayerId('btc', TestData.copayers[i].xPubKey_44H_0H_0H));
|
|
1783
|
+
|
|
1784
|
+
const session = TssKeyGenModel.create({
|
|
1785
|
+
id: 'tss-join-during-register-test-session',
|
|
1786
|
+
message: { partyId: 0, broadcastMessages: [], p2pMessages: [], publicKey: 'dummy', round: 0 },
|
|
1787
|
+
n: 2,
|
|
1788
|
+
copayerId: copayerIds[0],
|
|
1789
|
+
version: Defaults.TSS_KEYGEN_SCHEME_VERSION
|
|
1790
|
+
});
|
|
1791
|
+
session.participants[1] = copayerIds[1];
|
|
1792
|
+
session.sharedPublicKey = 'dummy-shared-public-key';
|
|
1793
|
+
await server.storage.db.collection('tss_keygen').deleteMany({ id: session.id });
|
|
1794
|
+
await server.storage.storeTssKeyGenSession({ doc: session });
|
|
1795
|
+
|
|
1796
|
+
const walletId = await util.promisify(server.createWallet).call(server, {
|
|
1797
|
+
name: 'tss wallet',
|
|
1798
|
+
m: 1,
|
|
1799
|
+
n: 1,
|
|
1800
|
+
pubKey: TestData.keyPair.pub,
|
|
1801
|
+
coin: 'btc',
|
|
1802
|
+
tssKeyId: session.id,
|
|
1803
|
+
});
|
|
1804
|
+
const [creatorOpts, joinerOpts] = [0, 1].map(i => helpers.getSignedCopayerOpts({
|
|
1805
|
+
walletId,
|
|
1806
|
+
name: 'copayer ' + (i + 1),
|
|
1807
|
+
xPubKey: TestData.copayers[i].xPubKey_44H_0H_0H,
|
|
1808
|
+
requestPubKey: TestData.copayers[i].pubKey_1H_0,
|
|
1809
|
+
}));
|
|
1810
|
+
const { copayerId } = await util.promisify(server.joinWallet).call(server, creatorOpts);
|
|
1811
|
+
const creatorServer = await helpers.getAuthServer(copayerId);
|
|
1812
|
+
creatorServer.checkWalletSync = function(a, b, simple, cb) {
|
|
1813
|
+
if (simple) return cb(null, false);
|
|
1814
|
+
return cb(null, true);
|
|
1815
|
+
};
|
|
1816
|
+
|
|
1817
|
+
blockchainExplorer.register = sinon.stub().callsFake((wallet, cb) => server.joinWallet(joinerOpts, cb));
|
|
1818
|
+
await util.promisify(creatorServer.getStatus).call(creatorServer, { includeExtendedInfo: true });
|
|
1819
|
+
|
|
1820
|
+
blockchainExplorer.register.calledOnce.should.equal(true);
|
|
1821
|
+
const registeredWallet = blockchainExplorer.register.firstCall.args[0];
|
|
1822
|
+
const wallet = await util.promisify(server.storage.fetchWallet).call(server.storage, walletId);
|
|
1823
|
+
wallet.copayers.length.should.equal(2);
|
|
1824
|
+
wallet.beRegistered.should.equal(true);
|
|
1825
|
+
wallet.beAuthPrivateKey2.should.equal(registeredWallet.beAuthPrivateKey2);
|
|
1826
|
+
wallet.beAuthPublicKey2.should.equal(registeredWallet.beAuthPublicKey2);
|
|
1827
|
+
});
|
|
1828
|
+
});
|
|
1777
1829
|
});
|
|
1778
1830
|
|
|
1779
1831
|
describe('#removeWallet', function() {
|