@@ -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