Skip to content

Commit 7598526

Browse files
committed
test(mbe): add keychain nocks for walletPubs fetch in handler tests
The walletPubs logic fetches all 3 keychains after getWalletAndSigningKeychain. Tests using nock.disableNetConnect() were missing mocks for the backup and bitgo keychain requests, causing 500s in success-path tests. Ticket: WCN-447 Session-Id: 79c78e55-7d60-4e54-b656-da465c33eb23 Task-Id: 7abc45de-23d0-4914-8dad-885882f82710
1 parent b619d16 commit 7598526

2 files changed

Lines changed: 408 additions & 0 deletions

File tree

src/__tests__/api/master/accelerate.test.ts

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
3434
type: 'independent',
3535
};
3636

37+
const mockBitgoKeychain = {
38+
id: 'bitgo-key-id',
39+
pub: 'xpub661MyMwAqRbcHtYNxRNuEtDFmPMRzBVPDfBXNu2RUBVFNz8MnWQgkrMZCNB',
40+
type: 'bitgo',
41+
};
42+
3743
before(() => {
3844
nock.disableNetConnect();
3945
nock.enableNetConnect('127.0.0.1');
@@ -68,11 +74,26 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
6874
.matchHeader('authorization', `Bearer ${accessToken}`)
6975
.reply(200, mockWalletData);
7076

77+
// Signing keychain fetched by getWalletAndSigningKeychain
7178
const keychainGetNock = nock(bitgoApiUrl)
7279
.get(`/api/v2/${coin}/key/user-key-id`)
7380
.matchHeader('authorization', `Bearer ${accessToken}`)
7481
.reply(200, mockUserKeychain);
7582

83+
// All 3 keychains fetched for walletPubs
84+
nock(bitgoApiUrl)
85+
.get(`/api/v2/${coin}/key/user-key-id`)
86+
.matchHeader('authorization', `Bearer ${accessToken}`)
87+
.reply(200, mockUserKeychain);
88+
nock(bitgoApiUrl)
89+
.get(`/api/v2/${coin}/key/backup-key-id`)
90+
.matchHeader('authorization', `Bearer ${accessToken}`)
91+
.reply(200, mockBackupKeychain);
92+
nock(bitgoApiUrl)
93+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
94+
.matchHeader('authorization', `Bearer ${accessToken}`)
95+
.reply(200, mockBitgoKeychain);
96+
7697
const accelerateTransactionStub = sinon
7798
.stub(Wallet.prototype, 'accelerateTransaction')
7899
.resolves({
@@ -117,11 +138,26 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
117138
.matchHeader('authorization', `Bearer ${accessToken}`)
118139
.reply(200, mockWalletData);
119140

141+
// Signing keychain fetched by getWalletAndSigningKeychain
120142
const keychainGetNock = nock(bitgoApiUrl)
121143
.get(`/api/v2/${coin}/key/backup-key-id`)
122144
.matchHeader('authorization', `Bearer ${accessToken}`)
123145
.reply(200, mockBackupKeychain);
124146

147+
// All 3 keychains fetched for walletPubs
148+
nock(bitgoApiUrl)
149+
.get(`/api/v2/${coin}/key/user-key-id`)
150+
.matchHeader('authorization', `Bearer ${accessToken}`)
151+
.reply(200, mockUserKeychain);
152+
nock(bitgoApiUrl)
153+
.get(`/api/v2/${coin}/key/backup-key-id`)
154+
.matchHeader('authorization', `Bearer ${accessToken}`)
155+
.reply(200, mockBackupKeychain);
156+
nock(bitgoApiUrl)
157+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
158+
.matchHeader('authorization', `Bearer ${accessToken}`)
159+
.reply(200, mockBitgoKeychain);
160+
125161
const accelerateTransactionStub = sinon
126162
.stub(Wallet.prototype, 'accelerateTransaction')
127163
.resolves({
@@ -157,11 +193,26 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
157193
.matchHeader('authorization', `Bearer ${accessToken}`)
158194
.reply(200, mockWalletData);
159195

196+
// Signing keychain fetched by getWalletAndSigningKeychain
160197
const keychainGetNock = nock(bitgoApiUrl)
161198
.get(`/api/v2/${coin}/key/user-key-id`)
162199
.matchHeader('authorization', `Bearer ${accessToken}`)
163200
.reply(200, mockUserKeychain);
164201

202+
// All 3 keychains fetched for walletPubs
203+
nock(bitgoApiUrl)
204+
.get(`/api/v2/${coin}/key/user-key-id`)
205+
.matchHeader('authorization', `Bearer ${accessToken}`)
206+
.reply(200, mockUserKeychain);
207+
nock(bitgoApiUrl)
208+
.get(`/api/v2/${coin}/key/backup-key-id`)
209+
.matchHeader('authorization', `Bearer ${accessToken}`)
210+
.reply(200, mockBackupKeychain);
211+
nock(bitgoApiUrl)
212+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
213+
.matchHeader('authorization', `Bearer ${accessToken}`)
214+
.reply(200, mockBitgoKeychain);
215+
165216
const accelerateTransactionStub = sinon
166217
.stub(Wallet.prototype, 'accelerateTransaction')
167218
.resolves({
@@ -324,11 +375,26 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
324375
.matchHeader('authorization', `Bearer ${accessToken}`)
325376
.reply(200, mockWalletData);
326377

378+
// Signing keychain fetched by getWalletAndSigningKeychain
327379
const keychainGetNock = nock(bitgoApiUrl)
328380
.get(`/api/v2/${coin}/key/user-key-id`)
329381
.matchHeader('authorization', `Bearer ${accessToken}`)
330382
.reply(200, mockUserKeychain);
331383

384+
// All 3 keychains fetched for walletPubs
385+
nock(bitgoApiUrl)
386+
.get(`/api/v2/${coin}/key/user-key-id`)
387+
.matchHeader('authorization', `Bearer ${accessToken}`)
388+
.reply(200, mockUserKeychain);
389+
nock(bitgoApiUrl)
390+
.get(`/api/v2/${coin}/key/backup-key-id`)
391+
.matchHeader('authorization', `Bearer ${accessToken}`)
392+
.reply(200, mockBackupKeychain);
393+
nock(bitgoApiUrl)
394+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
395+
.matchHeader('authorization', `Bearer ${accessToken}`)
396+
.reply(200, mockBitgoKeychain);
397+
332398
const accelerateTransactionStub = sinon
333399
.stub(Wallet.prototype, 'accelerateTransaction')
334400
.rejects(new Error('Insufficient funds for acceleration'));
@@ -408,4 +474,128 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
408474
response.body.should.have.property('error', 'Internal Server Error');
409475
response.body.should.have.property('details');
410476
});
477+
478+
it('should pass walletPubs (all 3 xpubs) to AWM for UTXO signing', async () => {
479+
nock(bitgoApiUrl)
480+
.get(`/api/v2/${coin}/wallet/${walletId}`)
481+
.matchHeader('authorization', `Bearer ${accessToken}`)
482+
.reply(200, mockWalletData);
483+
484+
// Signing keychain (user) — fetched once by getWalletAndSigningKeychain
485+
nock(bitgoApiUrl)
486+
.get(`/api/v2/${coin}/key/user-key-id`)
487+
.matchHeader('authorization', `Bearer ${accessToken}`)
488+
.reply(200, mockUserKeychain);
489+
490+
// All 3 keychains fetched for walletPubs
491+
nock(bitgoApiUrl)
492+
.get(`/api/v2/${coin}/key/user-key-id`)
493+
.matchHeader('authorization', `Bearer ${accessToken}`)
494+
.reply(200, mockUserKeychain);
495+
496+
nock(bitgoApiUrl)
497+
.get(`/api/v2/${coin}/key/backup-key-id`)
498+
.matchHeader('authorization', `Bearer ${accessToken}`)
499+
.reply(200, mockBackupKeychain);
500+
501+
nock(bitgoApiUrl)
502+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
503+
.matchHeader('authorization', `Bearer ${accessToken}`)
504+
.reply(200, mockBitgoKeychain);
505+
506+
let capturedSignBody: any;
507+
const awmSignNock = nock(advancedWalletManagerUrl)
508+
.post(`/api/${coin}/multisig/sign`, (body) => {
509+
capturedSignBody = body;
510+
return true;
511+
})
512+
.reply(200, {
513+
halfSigned: { txHex: 'signed-tx-hex' },
514+
source: 'user',
515+
pub: mockUserKeychain.pub,
516+
});
517+
518+
// Stub accelerateTransaction to call customSigningFunction so the AWM request is made
519+
sinon.stub(Wallet.prototype, 'accelerateTransaction').callsFake(async (params: any) => {
520+
await params.customSigningFunction({ txPrebuild: { txHex: 'prebuilt-tx' } });
521+
return { txid: 'accelerated-tx-id', tx: '0100000001abcdef...', status: 'signed' };
522+
});
523+
524+
const response = await agent
525+
.post(`/api/v1/${coin}/advancedwallet/${walletId}/accelerate`)
526+
.set('Authorization', `Bearer ${accessToken}`)
527+
.send({
528+
pubkey: mockUserKeychain.pub,
529+
source: 'user',
530+
cpfpTxIds: ['b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26'],
531+
cpfpFeeRate: 50,
532+
});
533+
534+
response.status.should.equal(200);
535+
awmSignNock.done();
536+
capturedSignBody.should.have.property('walletPubs');
537+
capturedSignBody.walletPubs.should.deepEqual([
538+
mockUserKeychain.pub,
539+
mockBackupKeychain.pub,
540+
mockBitgoKeychain.pub,
541+
]);
542+
});
543+
544+
it('should omit walletPubs from AWM request when any keychain is missing a pub', async () => {
545+
nock(bitgoApiUrl)
546+
.get(`/api/v2/${coin}/wallet/${walletId}`)
547+
.matchHeader('authorization', `Bearer ${accessToken}`)
548+
.reply(200, mockWalletData);
549+
550+
nock(bitgoApiUrl)
551+
.get(`/api/v2/${coin}/key/user-key-id`)
552+
.matchHeader('authorization', `Bearer ${accessToken}`)
553+
.reply(200, mockUserKeychain);
554+
555+
nock(bitgoApiUrl)
556+
.get(`/api/v2/${coin}/key/user-key-id`)
557+
.matchHeader('authorization', `Bearer ${accessToken}`)
558+
.reply(200, mockUserKeychain);
559+
560+
nock(bitgoApiUrl)
561+
.get(`/api/v2/${coin}/key/backup-key-id`)
562+
.matchHeader('authorization', `Bearer ${accessToken}`)
563+
.reply(200, { id: 'backup-key-id' }); // no pub
564+
565+
nock(bitgoApiUrl)
566+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
567+
.matchHeader('authorization', `Bearer ${accessToken}`)
568+
.reply(200, mockBitgoKeychain);
569+
570+
let capturedSignBody: any;
571+
const awmSignNock = nock(advancedWalletManagerUrl)
572+
.post(`/api/${coin}/multisig/sign`, (body) => {
573+
capturedSignBody = body;
574+
return true;
575+
})
576+
.reply(200, {
577+
halfSigned: { txHex: 'signed-tx-hex' },
578+
source: 'user',
579+
pub: mockUserKeychain.pub,
580+
});
581+
582+
sinon.stub(Wallet.prototype, 'accelerateTransaction').callsFake(async (params: any) => {
583+
await params.customSigningFunction({ txPrebuild: { txHex: 'prebuilt-tx' } });
584+
return { txid: 'accelerated-tx-id', tx: '0100000001abcdef...', status: 'signed' };
585+
});
586+
587+
const response = await agent
588+
.post(`/api/v1/${coin}/advancedwallet/${walletId}/accelerate`)
589+
.set('Authorization', `Bearer ${accessToken}`)
590+
.send({
591+
pubkey: mockUserKeychain.pub,
592+
source: 'user',
593+
cpfpTxIds: ['b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26'],
594+
cpfpFeeRate: 50,
595+
});
596+
597+
response.status.should.equal(200);
598+
awmSignNock.done();
599+
capturedSignBody.should.not.have.property('walletPubs');
600+
});
411601
});

0 commit comments

Comments
 (0)