@@ -5,7 +5,12 @@ import nock from 'nock';
55import { app as expressApp } from '../../../masterBitGoExpressApp' ;
66import { AppMode , MasterExpressConfig , TlsMode } from '../../../shared/types' ;
77import { Trx } from '@bitgo-beta/sdk-coin-trx' ;
8- import { BitGoAPITestHarness , DEFAULT_ASYNC_MODE_CONFIG } from './testUtils' ;
8+ import {
9+ BitGoAPITestHarness ,
10+ DEFAULT_ASYNC_MODE_CONFIG ,
11+ makeMasterExpressTestConfig ,
12+ nockAsyncMultisigRecoveryJob ,
13+ } from './testUtils' ;
914
1015describe ( 'POST /api/v1/:coin/advancedwallet/recoveryconsolidations' , ( ) => {
1116 let agent : request . SuperAgentTest ;
@@ -619,4 +624,115 @@ describe('POST /api/v1/:coin/advancedwallet/recoveryconsolidations', () => {
619624 response . status . should . equal ( 400 ) ;
620625 response . body . should . have . property ( 'error' ) ;
621626 } ) ;
627+
628+ describe ( 'Async mode' , ( ) => {
629+ const jobId = 'recovery-consolidation-job-id-123' ;
630+ let asyncAgent : request . SuperAgentTest ;
631+
632+ before ( ( ) => {
633+ const asyncConfig = makeMasterExpressTestConfig ( advancedWalletManagerUrl , {
634+ asyncEnabled : true ,
635+ overrides : { recoveryMode : true } ,
636+ } ) ;
637+ asyncAgent = request . agent ( expressApp ( asyncConfig ) ) ;
638+ } ) ;
639+
640+ it ( 'should return 202 + jobId for a single-tx onchain consolidation recovery' , async ( ) => {
641+ nock ( solRpcBase )
642+ . post ( '/' , ( b ) => b . method === 'getBalance' && b . params [ 0 ] === solWalletAddress2 )
643+ . reply ( 200 , { jsonrpc : '2.0' , result : { context : { slot : 1 } , value : 1000000000 } , id : 1 } ) ;
644+ nock ( solRpcBase )
645+ . post ( '/' , ( b ) => b . method === 'getLatestBlockhash' )
646+ . reply ( 200 , {
647+ jsonrpc : '2.0' ,
648+ result : {
649+ context : { slot : 2792 } ,
650+ value : {
651+ blockhash : 'EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N' ,
652+ lastValidBlockHeight : 3090 ,
653+ } ,
654+ } ,
655+ id : 1 ,
656+ } ) ;
657+ nock ( solRpcBase )
658+ . post ( '/' , ( b ) => b . method === 'getAccountInfo' && b . params [ 0 ] === solDurableNoncePubKey )
659+ . reply ( 200 , solDurableNonceAccountInfo ) ;
660+ nock ( solRpcBase )
661+ . post ( '/' , ( b ) => b . method === 'getFeeForMessage' )
662+ . reply ( 200 , { jsonrpc : '2.0' , result : { context : { slot : 1 } , value : 5000 } , id : 1 } ) ;
663+
664+ const { bridgeNock, awmRecoveryNock } = nockAsyncMultisigRecoveryJob ( {
665+ coin : 'sol' ,
666+ advancedWalletManagerUrl,
667+ jobId,
668+ } ) ;
669+
670+ const response = await asyncAgent
671+ . post ( `/api/v1/sol/advancedwallet/recoveryconsolidations` )
672+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
673+ . send ( {
674+ multisigType : 'onchain' as const ,
675+ userPub : solBitgoKey ,
676+ backupPub : solBitgoKey ,
677+ bitgoPub : solBitgoKey ,
678+ startingScanIndex : 2 ,
679+ endingScanIndex : 3 ,
680+ durableNonces : {
681+ publicKeys : [ solDurableNoncePubKey , solDurableNoncePubKey2 , solDurableNoncePubKey3 ] ,
682+ secretKey : solDurableNoncePrivKey ,
683+ } ,
684+ } ) ;
685+
686+ response . status . should . equal ( 202 ) ;
687+ response . body . should . have . property ( 'jobId' , jobId ) ;
688+ response . body . should . have . property ( 'status' , 'pending' ) ;
689+ bridgeNock . done ( ) ;
690+ awmRecoveryNock . isDone ( ) . should . be . false ( ) ;
691+ } ) ;
692+
693+ it ( 'should reject async mode when more than one consolidation tx is built' , async ( ) => {
694+ const tronBalanceWithToken = {
695+ data : [ { balance : 200_000_000 , trc20 : [ { [ trxTokenContractAddress ] : '1000000' } ] } ] ,
696+ } ;
697+ nock ( tronBase ) . get ( `/v1/accounts/${ TRX_ADDR_1 } ` ) . reply ( 200 , tronBalanceWithToken ) ;
698+ nock ( tronBase ) . post ( '/wallet/triggersmartcontract' ) . reply ( 200 , { transaction : TRON_MOCK_TX } ) ;
699+ nock ( tronBase ) . get ( `/v1/accounts/${ TRX_ADDR_2 } ` ) . reply ( 200 , tronBalanceWithToken ) ;
700+ nock ( tronBase ) . post ( '/wallet/triggersmartcontract' ) . reply ( 200 , { transaction : TRON_MOCK_TX } ) ;
701+
702+ const response = await asyncAgent
703+ . post ( `/api/v1/trx/advancedwallet/recoveryconsolidations` )
704+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
705+ . send ( {
706+ multisigType : 'onchain' as const ,
707+ userPub : mockUserPub ,
708+ backupPub : mockBackupPub ,
709+ bitgoPub : mockBitgoPub ,
710+ tokenContractAddress : trxTokenContractAddress ,
711+ startingScanIndex : 1 ,
712+ endingScanIndex : 3 ,
713+ } ) ;
714+
715+ response . status . should . equal ( 400 ) ;
716+ response . body . details . should . containEql (
717+ 'Async mode supports a single consolidation recovery only' ,
718+ ) ;
719+ } ) ;
720+
721+ it ( 'should reject async mode for MPC (tss) consolidation recovery' , async ( ) => {
722+ const response = await asyncAgent
723+ . post ( `/api/v1/tsui/advancedwallet/recoveryconsolidations` )
724+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
725+ . send ( {
726+ multisigType : 'tss' as const ,
727+ commonKeychain : suiBitgoKey ,
728+ startingScanIndex : 1 ,
729+ endingScanIndex : 2 ,
730+ } ) ;
731+
732+ response . status . should . equal ( 400 ) ;
733+ response . body . details . should . containEql (
734+ 'Async mode is not yet supported for TSS/MPC recovery consolidations' ,
735+ ) ;
736+ } ) ;
737+ } ) ;
622738} ) ;
0 commit comments