@@ -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,261 @@ 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 (
538+ 'details' ,
539+ 'Round mismatch: expected 2, got 3' ,
540+ ) ;
541+
542+ // repeating round 1
543+ const repeatRoundResponse = await agent
544+ . post ( `/api/${ coin } /mpcv2/round` )
545+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
546+ . send ( {
547+ source : 'user' ,
548+ encryptedData : userRound1Response . body . encryptedData ,
549+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
550+ round : 1 ,
551+ bitgoGpgPub : userRound1Response . body . gpgPub ,
552+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
553+ } ) ;
554+
555+ repeatRoundResponse . status . should . equal ( 422 ) ;
556+ repeatRoundResponse . body . should . have . property (
557+ 'details' ,
558+ 'Round mismatch: expected 2, got 1' ,
559+ ) ;
560+ } ) ;
561+
562+ it ( 'should throw error if broadcastMessages or p2pMessages does not contain all required messages' , async ( ) => {
563+ const userInitResponse = await agent
564+ . post ( `/api/${ coin } /mpcv2/initialize` )
565+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
566+ . send ( { source : 'user' } ) ;
567+
568+ const backupInitResponse = await agent
569+ . post ( `/api/${ coin } /mpcv2/initialize` )
570+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
571+ . send ( { source : 'backup' } ) ;
572+
573+ // round 1
574+ const userRound1Response = await agent
575+ . post ( `/api/${ coin } /mpcv2/round` )
576+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
577+ . send ( {
578+ source : 'user' ,
579+ encryptedData : userInitResponse . body . encryptedData ,
580+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
581+ round : 1 ,
582+ bitgoGpgPub : userInitResponse . body . gpgPub ,
583+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
584+ } ) ;
585+
586+ // round 2 with missing broadcastMessages
587+ const response = await agent
588+ . post ( `/api/${ coin } /mpcv2/round` )
589+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
590+ . send ( {
591+ source : 'user' ,
592+ encryptedData : userInitResponse . body . encryptedData ,
593+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
594+ round : 2 ,
595+ } ) ;
596+
597+ response . status . should . equal ( 400 ) ;
598+ response . body . should . have . property (
599+ 'details' ,
600+ 'At least one of broadcastMessages or p2pMessages must be provided' ,
601+ ) ;
602+
603+ // round 2 with missing p2pMessages
604+ const response2 = await agent
605+ . post ( `/api/${ coin } /mpcv2/round` )
606+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
607+ . send ( {
608+ source : 'user' ,
609+ encryptedData : userRound1Response . body . encryptedData ,
610+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
611+ round : 2 ,
612+ p2pMessages : { } ,
613+ } ) ;
614+
615+ response2 . status . should . equal ( 400 ) ;
616+ response2 . body . should . have . property (
617+ 'details' ,
618+ 'p2pMessages did not contain all required messages' ,
619+ ) ;
620+
621+ // round 2 with missing broadcastMessages
622+ const response3 = await agent
623+ . post ( `/api/${ coin } /mpcv2/round` )
624+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
625+ . send ( {
626+ source : 'user' ,
627+ encryptedData : userRound1Response . body . encryptedData ,
628+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
629+ round : 2 ,
630+ broadcastMessages : { } ,
631+ } ) ;
632+
633+ response3 . status . should . equal ( 400 ) ;
634+ response3 . body . should . have . property (
635+ 'details' ,
636+ 'broadcastMessages did not contain all required messages' ,
637+ ) ;
638+ } ) ;
639+
640+ it ( 'should throw error if counterPartyGpgPub does not match expected value' , async ( ) => {
641+ const userInitResponse = await agent
642+ . post ( `/api/${ coin } /mpcv2/initialize` )
643+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
644+ . send ( { source : 'user' } ) ;
645+
646+ const backupInitResponse = await agent
647+ . post ( `/api/${ coin } /mpcv2/initialize` )
648+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
649+ . send ( { source : 'backup' } ) ;
650+
651+ // round 1
652+ const userRound1Response = await agent
653+ . post ( `/api/${ coin } /mpcv2/round` )
654+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
655+ . send ( {
656+ source : 'user' ,
657+ encryptedData : userInitResponse . body . encryptedData ,
658+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
659+ round : 1 ,
660+ bitgoGpgPub : userInitResponse . body . gpgPub ,
661+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
662+ } ) ;
663+
664+ // round 2 with incorrect counterPartyGpgPub
665+ const response = await agent
666+ . post ( `/api/${ coin } /mpcv2/round` )
667+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
668+ . send ( {
669+ source : 'user' ,
670+ encryptedData : userRound1Response . body . encryptedData ,
671+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
672+ round : 2 ,
673+ bitgoGpgPub : userRound1Response . body . gpgPub ,
674+ counterPartyGpgPub : 'incorrect-gpg-pub' ,
675+ broadcastMessages : {
676+ bitgo : { } ,
677+ counterParty : { } ,
678+ } ,
679+ } ) ;
680+
681+ response . status . should . equal ( 422 ) ;
682+ response . body . should . have . property (
683+ 'details' ,
684+ `Counterparty GPG public key mismatch: expected ${ backupInitResponse . body . gpgPub } , got incorrect-gpg-pub` ,
685+ ) ;
686+ } ) ;
687+
688+ it ( 'should throw error if encrypted state misses the required messages' , async ( ) => {
689+ const userInitResponse = await agent
690+ . post ( `/api/${ coin } /mpcv2/initialize` )
691+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
692+ . send ( { source : 'user' } ) ;
693+
694+ const backupInitResponse = await agent
695+ . post ( `/api/${ coin } /mpcv2/initialize` )
696+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
697+ . send ( { source : 'backup' } ) ;
698+
699+ // round 1
700+ const userRound1Response = await agent
701+ . post ( `/api/${ coin } /mpcv2/round` )
702+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
703+ . send ( {
704+ source : 'user' ,
705+ encryptedData : userInitResponse . body . encryptedData ,
706+ encryptedDataKey : userInitResponse . body . encryptedDataKey ,
707+ round : 1 ,
708+ bitgoGpgPub : userInitResponse . body . gpgPub ,
709+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
710+ } ) ;
711+
712+ // round 2 with missing p2pMessages
713+ const response = await agent
714+ . post ( `/api/${ coin } /mpcv2/round` )
715+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
716+ . send ( {
717+ source : 'user' ,
718+ encryptedData : '' ,
719+ encryptedDataKey : userRound1Response . body . encryptedDataKey ,
720+ round : 2 ,
721+ bitgoGpgPub : userRound1Response . body . gpgPub ,
722+ counterPartyGpgPub : backupInitResponse . body . gpgPub ,
723+ p2pMessages : { } ,
724+ } ) ;
725+
726+ response . status . should . equal ( 400 ) ;
727+ response . body . should . have . property (
728+ 'details' ,
729+ 'p2pMessages did not contain all required messages' ,
730+ ) ;
731+ } ) ;
473732} ) ;
0 commit comments