@@ -18,7 +18,7 @@ describe('postMpcV2Key', () => {
1818
1919 // test config
2020 const kmsUrl = 'http://kms.invalid' ;
21- const coin = 'tsol ' ;
21+ const coin = 'hteth ' ;
2222 const accessToken = 'test-token' ;
2323
2424 // sinon stubs
@@ -48,15 +48,7 @@ describe('postMpcV2Key', () => {
4848 agent = request . agent ( app ) ;
4949 } ) ;
5050
51- afterEach ( ( ) => {
52- nock . cleanAll ( ) ;
53- } ) ;
54-
55- after ( ( ) => {
56- configStub . restore ( ) ;
57- } ) ;
58-
59- it ( 'should be able to create a new MPC V2 wallet' , async ( ) => {
51+ beforeEach ( ( ) => {
6052 // nocks for KMS responses
6153 nock ( kmsUrl )
6254 . post ( `/generateDataKey` )
@@ -93,7 +85,17 @@ describe('postMpcV2Key', () => {
9385 . persist ( ) ;
9486
9587 nock ( kmsUrl ) . post ( `/postKey` ) . reply ( 200 , { } ) . persist ( ) ;
88+ } ) ;
9689
90+ afterEach ( ( ) => {
91+ nock . cleanAll ( ) ;
92+ } ) ;
93+
94+ after ( ( ) => {
95+ configStub . restore ( ) ;
96+ } ) ;
97+
98+ it ( 'should be able to create a new MPC V2 wallet' , async ( ) => {
9799 // mocking bitgo's GPG key generation session
98100 const bitgoGpgKey = await bitgoSdk . generateGPGKeyPair ( 'secp256k1' ) ;
99101 const bitgoGpgPub = {
@@ -470,4 +472,255 @@ describe('postMpcV2Key', () => {
470472 ) ;
471473 userFinalizeResponse . body . commonKeychain . should . equal ( bitgoCommonKeychain ) ;
472474 } ) ;
475+
476+ it ( 'should throw an error if round number is invalid' , async ( ) => {
477+ const response = await agent
478+ . post ( `/api/${ coin } /mpcv2/round` )
479+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
480+ . send ( {
481+ source : 'user' ,
482+ encryptedData : '' ,
483+ encryptedDataKey : '' ,
484+ round : 5 ,
485+ p2pMessages : {
486+ bitgo : { } ,
487+ counterParty : { } ,
488+ } ,
489+ } ) ;
490+
491+ response . status . should . equal ( 400 ) ;
492+ response . body . should . have . property ( 'details' , 'Round must be between 1 and 4' ) ;
493+ } ) ;
494+
495+ it ( 'should throw error if round number is not sequential' , async ( ) => {
496+ const userInitResponse = await agent
497+ . post ( `/api/${ coin } /mpcv2/initialize` )
498+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
499+ . send ( { source : 'user' } ) ;
500+
501+ const backupInitResponse = await agent
502+ . post ( `/api/${ coin } /mpcv2/initialize` )
503+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
504+ . send ( { source : 'backup' } ) ;
505+
506+ // round 1
507+ const userRound1Response = await agent
508+ . post ( `/api/${ coin } /mpcv2/round` )
509+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
510+ . send ( {
511+ source : 'user' ,
512+ encryptedData : userInitResponse . body . encryptedData ,
513+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
514+ round : 1 ,
515+ bitgoGpgPub : userInitResponse . body . gpgPub ,
516+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
517+ } ) ;
518+
519+ // round 3 without round 2
520+ const skipRoundResponse = await agent
521+ . post ( `/api/${ coin } /mpcv2/round` )
522+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
523+ . send ( {
524+ source : 'user' ,
525+ encryptedData : userRound1Response . body . encryptedData ,
526+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
527+ round : 3 ,
528+ bitgoGpgPub : userRound1Response . body . gpgPub ,
529+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
530+ p2pMessages : {
531+ bitgo : { } ,
532+ counterParty : { } ,
533+ } ,
534+ } ) ;
535+
536+ skipRoundResponse . status . should . equal ( 422 ) ;
537+ skipRoundResponse . body . should . have . property ( 'details' , 'Round mismatch: expected 2, got 3' ) ;
538+
539+ // repeating round 1
540+ const repeatRoundResponse = await agent
541+ . post ( `/api/${ coin } /mpcv2/round` )
542+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
543+ . send ( {
544+ source : 'user' ,
545+ encryptedData : userRound1Response . body . encryptedData ,
546+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
547+ round : 1 ,
548+ bitgoGpgPub : userRound1Response . body . gpgPub ,
549+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
550+ } ) ;
551+
552+ repeatRoundResponse . status . should . equal ( 422 ) ;
553+ repeatRoundResponse . body . should . have . property ( 'details' , 'Round mismatch: expected 2, got 1' ) ;
554+ } ) ;
555+
556+ it ( 'should throw error if broadcastMessages or p2pMessages does not contain all required messages' , async ( ) => {
557+ const userInitResponse = await agent
558+ . post ( `/api/${ coin } /mpcv2/initialize` )
559+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
560+ . send ( { source : 'user' } ) ;
561+
562+ const backupInitResponse = await agent
563+ . post ( `/api/${ coin } /mpcv2/initialize` )
564+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
565+ . send ( { source : 'backup' } ) ;
566+
567+ // round 1
568+ const userRound1Response = await agent
569+ . post ( `/api/${ coin } /mpcv2/round` )
570+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
571+ . send ( {
572+ source : 'user' ,
573+ encryptedData : userInitResponse . body . encryptedData ,
574+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
575+ round : 1 ,
576+ bitgoGpgPub : userInitResponse . body . gpgPub ,
577+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
578+ } ) ;
579+
580+ // round 2 with missing broadcastMessages
581+ const response = await agent
582+ . post ( `/api/${ coin } /mpcv2/round` )
583+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
584+ . send ( {
585+ source : 'user' ,
586+ encryptedData : userInitResponse . body . encryptedData ,
587+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
588+ round : 2 ,
589+ } ) ;
590+
591+ response . status . should . equal ( 400 ) ;
592+ response . body . should . have . property (
593+ 'details' ,
594+ 'At least one of broadcastMessages or p2pMessages must be provided' ,
595+ ) ;
596+
597+ // round 2 with missing p2pMessages
598+ const response2 = await agent
599+ . post ( `/api/${ coin } /mpcv2/round` )
600+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
601+ . send ( {
602+ source : 'user' ,
603+ encryptedData : userRound1Response . body . encryptedData ,
604+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
605+ round : 2 ,
606+ p2pMessages : { } ,
607+ } ) ;
608+
609+ response2 . status . should . equal ( 400 ) ;
610+ response2 . body . should . have . property (
611+ 'details' ,
612+ 'p2pMessages did not contain all required messages' ,
613+ ) ;
614+
615+ // round 2 with missing broadcastMessages
616+ const response3 = await agent
617+ . post ( `/api/${ coin } /mpcv2/round` )
618+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
619+ . send ( {
620+ source : 'user' ,
621+ encryptedData : userRound1Response . body . encryptedData ,
622+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
623+ round : 2 ,
624+ broadcastMessages : { } ,
625+ } ) ;
626+
627+ response3 . status . should . equal ( 400 ) ;
628+ response3 . body . should . have . property (
629+ 'details' ,
630+ 'broadcastMessages did not contain all required messages' ,
631+ ) ;
632+ } ) ;
633+
634+ it ( 'should throw error if counterPartyGpgPub does not match expected value' , async ( ) => {
635+ const userInitResponse = await agent
636+ . post ( `/api/${ coin } /mpcv2/initialize` )
637+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
638+ . send ( { source : 'user' } ) ;
639+
640+ const backupInitResponse = await agent
641+ . post ( `/api/${ coin } /mpcv2/initialize` )
642+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
643+ . send ( { source : 'backup' } ) ;
644+
645+ // round 1
646+ const userRound1Response = await agent
647+ . post ( `/api/${ coin } /mpcv2/round` )
648+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
649+ . send ( {
650+ source : 'user' ,
651+ encryptedData : userInitResponse . body . encryptedData ,
652+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
653+ round : 1 ,
654+ bitgoGpgPub : userInitResponse . body . gpgPub ,
655+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
656+ } ) ;
657+
658+ // round 2 with incorrect counterPartyGpgPub
659+ const response = await agent
660+ . post ( `/api/${ coin } /mpcv2/round` )
661+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
662+ . send ( {
663+ source : 'user' ,
664+ encryptedData : userRound1Response . body . encryptedData ,
665+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
666+ round : 2 ,
667+ bitgoGpgPub : userRound1Response . body . gpgPub ,
668+ counterPartyGpgPub : 'incorrect-gpg-pub' ,
669+ broadcastMessages : {
670+ bitgo : { } ,
671+ counterParty : { } ,
672+ } ,
673+ } ) ;
674+
675+ response . status . should . equal ( 422 ) ;
676+ response . body . should . have . property (
677+ 'details' ,
678+ `Counterparty GPG public key mismatch: expected ${ backupInitResponse . body . gpgPub } , got incorrect-gpg-pub` ,
679+ ) ;
680+ } ) ;
681+
682+ it ( 'should throw error if encrypted state misses the required messages' , async ( ) => {
683+ const userInitResponse = await agent
684+ . post ( `/api/${ coin } /mpcv2/initialize` )
685+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
686+ . send ( { source : 'user' } ) ;
687+
688+ const backupInitResponse = await agent
689+ . post ( `/api/${ coin } /mpcv2/initialize` )
690+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
691+ . send ( { source : 'backup' } ) ;
692+
693+ // round 1
694+ const userRound1Response = await agent
695+ . post ( `/api/${ coin } /mpcv2/round` )
696+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
697+ . send ( {
698+ source : 'user' ,
699+ encryptedData : userInitResponse . body . encryptedData ,
700+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
701+ round : 1 ,
702+ bitgoGpgPub : userInitResponse . body . gpgPub ,
703+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
704+ } ) ;
705+
706+ // round 2 with missing p2pMessages
707+ const response = await agent
708+ . post ( `/api/${ coin } /mpcv2/round` )
709+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
710+ . send ( {
711+ source : 'user' ,
712+ encryptedData : '' ,
713+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
714+ round : 2 ,
715+ bitgoGpgPub : userRound1Response . body . gpgPub ,
716+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
717+ p2pMessages : { } ,
718+ } ) ;
719+
720+ response . status . should . equal ( 400 ) ;
721+ response . body . should . have . property (
722+ 'details' ,
723+ 'p2pMessages did not contain all required messages' ,
724+ ) ;
725+ } ) ;
473726} ) ;
0 commit comments