@dynamic-labs-wallet/core 1.0.56 → 1.0.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs CHANGED
@@ -437,17 +437,17 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
437
437
  // 2-of-2 -> 2-of-2: same-parties refresh — server + rootUser-client both
438
438
  // call `reshareRemainingParty`. Share-set delegation lands here too; the
439
439
  // delegated share is delivered out-of-band, not via the MPC ceremony.
440
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
440
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
441
441
  return {
442
442
  existingClientShareCount: 1,
443
443
  newClientShareCount: 0,
444
444
  existingServerShareCount: 1,
445
445
  newServerShareCount: 0
446
446
  };
447
- // 2-of-3 -> 2-of-3:
447
+ // 2-of-3 -> 2-of-3 and 2-of-2 -> 2-of-3:
448
448
  // -- dynamic server shares: 1 existing, 0 new
449
449
  // -- client shares: 1 existing, 1 new
450
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
450
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
451
451
  return {
452
452
  existingClientShareCount: 1,
453
453
  newClientShareCount: 1,
@@ -464,46 +464,16 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
464
464
  existingServerShareCount: 2,
465
465
  newServerShareCount: 0
466
466
  };
467
- // 2-of-2 -> 2-of-3:
468
- // -- dynamic server shares: 1 existing, 0 new
469
- // -- client shares: 1 existing, 1 new
470
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
471
- return {
472
- existingClientShareCount: 1,
473
- newClientShareCount: 1,
474
- existingServerShareCount: 1,
475
- newServerShareCount: 0
476
- };
477
- // 2-of-2 -> 3-of-5:
467
+ // 2-of-2 -> 3-of-5 and 2-of-3 -> 3-of-5:
478
468
  // -- dynamic server shares: 1 existing, 1 new
479
469
  // -- client shares: 1 existing, 2 new
480
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
470
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
481
471
  return {
482
472
  existingClientShareCount: 1,
483
473
  newClientShareCount: 2,
484
474
  existingServerShareCount: 1,
485
475
  newServerShareCount: 1
486
476
  };
487
- // 2-of-3 -> 3-of-5:
488
- // -- dynamic server shares: 1 existing, 1 new
489
- // -- client shares: 1 existing, 2 new
490
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
491
- return {
492
- existingClientShareCount: 1,
493
- newClientShareCount: 2,
494
- existingServerShareCount: 1,
495
- newServerShareCount: 1
496
- };
497
- // 2-of-3 -> 2-of-2:
498
- // -- dynamic server shares: 1 existing, 0 new
499
- // -- client shares: 1 existing, 0 new
500
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
501
- return {
502
- existingClientShareCount: 1,
503
- newClientShareCount: 0,
504
- existingServerShareCount: 1,
505
- newServerShareCount: 0
506
- };
507
477
  // 3-of-5 -> 2-of-3:
508
478
  // -- dynamic server shares: 1 existing, 0 new
509
479
  // -- client shares: 2 existing, 0 new
@@ -530,20 +500,20 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
530
500
  * }} The number of existing and new client and server shares needed
531
501
  */ const getServerWalletReshareConfig = ({ oldThresholdSignatureScheme, newThresholdSignatureScheme })=>{
532
502
  switch(true){
533
- // 2-of-2 -> 2-of-2:
534
- // -- dyanmic server shares: 1 existing, 0 new
503
+ // 2-of-2 -> 2-of-2 and 2-of-3 -> 2-of-2:
504
+ // -- dynamic server shares: 1 existing, 0 new
535
505
  // -- external server shares: 1 existing, 0 new
536
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
506
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
537
507
  return {
538
508
  existingExternalServerShareCount: 1,
539
509
  newExternalServerShareCount: 0,
540
510
  existingDynamicServerShareCount: 1,
541
511
  newDynamicServerShareCount: 0
542
512
  };
543
- // 2-of-3 -> 2-of-3:
544
- // -- dyanmic server shares: 1 existing, 0 new
513
+ // 2-of-3 -> 2-of-3 and 2-of-2 -> 2-of-3:
514
+ // -- dynamic server shares: 1 existing, 0 new
545
515
  // -- external server shares: 1 existing, 1 new
546
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
516
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
547
517
  return {
548
518
  existingExternalServerShareCount: 1,
549
519
  newExternalServerShareCount: 1,
@@ -551,7 +521,7 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
551
521
  newDynamicServerShareCount: 0
552
522
  };
553
523
  // 3-of-5 -> 3-of-5:
554
- // -- dyanmic server shares: 2 existing, 0 new
524
+ // -- dynamic server shares: 2 existing, 0 new
555
525
  // -- external server shares: 1 existing, 2 new
556
526
  case oldThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
557
527
  return {
@@ -560,46 +530,16 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
560
530
  existingDynamicServerShareCount: 2,
561
531
  newDynamicServerShareCount: 0
562
532
  };
563
- // 2-of-2 -> 2-of-3:
564
- // -- dyanmic server shares: 1 existing, 0 new
565
- // -- external server shares: 1 existing, 1 new
566
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
567
- return {
568
- existingExternalServerShareCount: 1,
569
- newExternalServerShareCount: 1,
570
- existingDynamicServerShareCount: 1,
571
- newDynamicServerShareCount: 0
572
- };
573
- // 2-of-2 -> 3-of-5:
574
- // -- dyanmic server shares: 1 existing, 1 new
575
- // -- external server shares: 1 existing, 2 new
576
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
577
- return {
578
- existingExternalServerShareCount: 1,
579
- newExternalServerShareCount: 2,
580
- existingDynamicServerShareCount: 1,
581
- newDynamicServerShareCount: 1
582
- };
583
- // 2-of-3 -> 3-of-5:
584
- // -- dyanmic server shares: 1 existing, 1 new
533
+ // 2-of-2 -> 3-of-5 and 2-of-3 -> 3-of-5:
534
+ // -- dynamic server shares: 1 existing, 1 new
585
535
  // -- external server shares: 1 existing, 2 new
586
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
536
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
587
537
  return {
588
538
  existingExternalServerShareCount: 1,
589
539
  newExternalServerShareCount: 2,
590
540
  existingDynamicServerShareCount: 1,
591
541
  newDynamicServerShareCount: 1
592
542
  };
593
- // 2-of-3 -> 2-of-2:
594
- // -- dyanmic server shares: 1 existing, 0 new
595
- // -- external server shares: 1 existing, 0 new
596
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
597
- return {
598
- existingExternalServerShareCount: 1,
599
- newExternalServerShareCount: 0,
600
- existingDynamicServerShareCount: 1,
601
- newDynamicServerShareCount: 0
602
- };
603
543
  // 3-of-5 -> 2-of-3:
604
544
  // -- dyanmic server shares: 1 existing, 0 new
605
545
  // -- external server shares: 2 existing, 0 new
@@ -982,7 +922,7 @@ const getRequiredExternalKeyShareId = (ks)=>{
982
922
  * before it is posted and surfaces in Datadog exactly as the recovery path does.
983
923
  */ const assertDynamicLocationsHaveExternalKeyShareId = (locations)=>locations.filter((location)=>location.location === BackupLocation.DYNAMIC).forEach((location)=>getRequiredExternalKeyShareId(location));
984
924
 
985
- var version = "1.0.56";
925
+ var version = "1.0.58";
986
926
 
987
927
  class BaseClient {
988
928
  /**
@@ -2150,6 +2090,33 @@ const serializeMessageForForwardMPC = ({ message, isFormatted = false, chainName
2150
2090
  return serializedMessage;
2151
2091
  };
2152
2092
 
2093
+ // Mirrors forward-mpc-client's ErrorCode values (the /utils subpath does not
2094
+ // export the ErrorCode const, so the codes are inlined here).
2095
+ const RECOVERED_CONNECTION_CHURN_CODES = new Set([
2096
+ 'CONNECTION_FAILED',
2097
+ 'CONNECTION_TIMEOUT',
2098
+ 'NOT_CONNECTED',
2099
+ 'TRANSPORT_CLOSED',
2100
+ 'HANDSHAKE_FAILED'
2101
+ ]);
2102
+ /**
2103
+ * Returns true when a classified Forward MPC error is recovered connection
2104
+ * churn that should be logged at `warn` rather than `error`.
2105
+ *
2106
+ * The Forward MPC enclave is an optimization side-channel: the client retries
2107
+ * connections internally, and `shouldFallback` is true for every Forward MPC
2108
+ * failure mode — relay-based MPC is a fully functional safety net, so a
2109
+ * connection-lifecycle failure never blocks a user operation on its own.
2110
+ * Terminal failures (both paths failing) are logged at the operation sites.
2111
+ *
2112
+ * Churn covers rate-limited upgrades and the transport-lifecycle error codes
2113
+ * (connect/reconnect failures, timeouts, socket closes, and handshake-request
2114
+ * timeouts — production evidence shows these concentrate on hostile/flaky
2115
+ * networks). Attestation failures, HANDSHAKE_INVALID_RESPONSE, SERVER_ERROR,
2116
+ * and unclassified errors are NOT churn: they indicate enclave tampering or
2117
+ * protocol breakage and must stay at `error` so monitors can page on them.
2118
+ */ const isRecoveredForwardMpcConnectionChurn = (classification)=>classification.errorType === 'RATE_LIMITED' || classification.errorCode !== undefined && RECOVERED_CONNECTION_CHURN_CODES.has(classification.errorCode);
2119
+
2153
2120
  /**
2154
2121
  * Normalizes an unknown thrown value into flat, log-friendly fields.
2155
2122
  *
@@ -2398,6 +2365,7 @@ exports.getVersionNamespace = getVersionNamespace;
2398
2365
  exports.getVersionWithoutNamespace = getVersionWithoutNamespace;
2399
2366
  exports.handleAxiosError = handleAxiosError;
2400
2367
  exports.isEvmCompatibleChain = isEvmCompatibleChain;
2368
+ exports.isRecoveredForwardMpcConnectionChurn = isRecoveredForwardMpcConnectionChurn;
2401
2369
  exports.parseNamespacedVersion = parseNamespacedVersion;
2402
2370
  exports.serializeError = serializeError;
2403
2371
  exports.serializeMessageForForwardMPC = serializeMessageForForwardMPC;
package/index.esm.js CHANGED
@@ -437,17 +437,17 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
437
437
  // 2-of-2 -> 2-of-2: same-parties refresh — server + rootUser-client both
438
438
  // call `reshareRemainingParty`. Share-set delegation lands here too; the
439
439
  // delegated share is delivered out-of-band, not via the MPC ceremony.
440
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
440
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
441
441
  return {
442
442
  existingClientShareCount: 1,
443
443
  newClientShareCount: 0,
444
444
  existingServerShareCount: 1,
445
445
  newServerShareCount: 0
446
446
  };
447
- // 2-of-3 -> 2-of-3:
447
+ // 2-of-3 -> 2-of-3 and 2-of-2 -> 2-of-3:
448
448
  // -- dynamic server shares: 1 existing, 0 new
449
449
  // -- client shares: 1 existing, 1 new
450
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
450
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
451
451
  return {
452
452
  existingClientShareCount: 1,
453
453
  newClientShareCount: 1,
@@ -464,46 +464,16 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
464
464
  existingServerShareCount: 2,
465
465
  newServerShareCount: 0
466
466
  };
467
- // 2-of-2 -> 2-of-3:
468
- // -- dynamic server shares: 1 existing, 0 new
469
- // -- client shares: 1 existing, 1 new
470
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
471
- return {
472
- existingClientShareCount: 1,
473
- newClientShareCount: 1,
474
- existingServerShareCount: 1,
475
- newServerShareCount: 0
476
- };
477
- // 2-of-2 -> 3-of-5:
467
+ // 2-of-2 -> 3-of-5 and 2-of-3 -> 3-of-5:
478
468
  // -- dynamic server shares: 1 existing, 1 new
479
469
  // -- client shares: 1 existing, 2 new
480
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
470
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
481
471
  return {
482
472
  existingClientShareCount: 1,
483
473
  newClientShareCount: 2,
484
474
  existingServerShareCount: 1,
485
475
  newServerShareCount: 1
486
476
  };
487
- // 2-of-3 -> 3-of-5:
488
- // -- dynamic server shares: 1 existing, 1 new
489
- // -- client shares: 1 existing, 2 new
490
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
491
- return {
492
- existingClientShareCount: 1,
493
- newClientShareCount: 2,
494
- existingServerShareCount: 1,
495
- newServerShareCount: 1
496
- };
497
- // 2-of-3 -> 2-of-2:
498
- // -- dynamic server shares: 1 existing, 0 new
499
- // -- client shares: 1 existing, 0 new
500
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
501
- return {
502
- existingClientShareCount: 1,
503
- newClientShareCount: 0,
504
- existingServerShareCount: 1,
505
- newServerShareCount: 0
506
- };
507
477
  // 3-of-5 -> 2-of-3:
508
478
  // -- dynamic server shares: 1 existing, 0 new
509
479
  // -- client shares: 2 existing, 0 new
@@ -530,20 +500,20 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
530
500
  * }} The number of existing and new client and server shares needed
531
501
  */ const getServerWalletReshareConfig = ({ oldThresholdSignatureScheme, newThresholdSignatureScheme })=>{
532
502
  switch(true){
533
- // 2-of-2 -> 2-of-2:
534
- // -- dyanmic server shares: 1 existing, 0 new
503
+ // 2-of-2 -> 2-of-2 and 2-of-3 -> 2-of-2:
504
+ // -- dynamic server shares: 1 existing, 0 new
535
505
  // -- external server shares: 1 existing, 0 new
536
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
506
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
537
507
  return {
538
508
  existingExternalServerShareCount: 1,
539
509
  newExternalServerShareCount: 0,
540
510
  existingDynamicServerShareCount: 1,
541
511
  newDynamicServerShareCount: 0
542
512
  };
543
- // 2-of-3 -> 2-of-3:
544
- // -- dyanmic server shares: 1 existing, 0 new
513
+ // 2-of-3 -> 2-of-3 and 2-of-2 -> 2-of-3:
514
+ // -- dynamic server shares: 1 existing, 0 new
545
515
  // -- external server shares: 1 existing, 1 new
546
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
516
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
547
517
  return {
548
518
  existingExternalServerShareCount: 1,
549
519
  newExternalServerShareCount: 1,
@@ -551,7 +521,7 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
551
521
  newDynamicServerShareCount: 0
552
522
  };
553
523
  // 3-of-5 -> 3-of-5:
554
- // -- dyanmic server shares: 2 existing, 0 new
524
+ // -- dynamic server shares: 2 existing, 0 new
555
525
  // -- external server shares: 1 existing, 2 new
556
526
  case oldThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
557
527
  return {
@@ -560,46 +530,16 @@ const getDynamicServerThreshold = (thresholdSignatureScheme)=>{
560
530
  existingDynamicServerShareCount: 2,
561
531
  newDynamicServerShareCount: 0
562
532
  };
563
- // 2-of-2 -> 2-of-3:
564
- // -- dyanmic server shares: 1 existing, 0 new
565
- // -- external server shares: 1 existing, 1 new
566
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE:
567
- return {
568
- existingExternalServerShareCount: 1,
569
- newExternalServerShareCount: 1,
570
- existingDynamicServerShareCount: 1,
571
- newDynamicServerShareCount: 0
572
- };
573
- // 2-of-2 -> 3-of-5:
574
- // -- dyanmic server shares: 1 existing, 1 new
575
- // -- external server shares: 1 existing, 2 new
576
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
577
- return {
578
- existingExternalServerShareCount: 1,
579
- newExternalServerShareCount: 2,
580
- existingDynamicServerShareCount: 1,
581
- newDynamicServerShareCount: 1
582
- };
583
- // 2-of-3 -> 3-of-5:
584
- // -- dyanmic server shares: 1 existing, 1 new
533
+ // 2-of-2 -> 3-of-5 and 2-of-3 -> 3-of-5:
534
+ // -- dynamic server shares: 1 existing, 1 new
585
535
  // -- external server shares: 1 existing, 2 new
586
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
536
+ case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE || oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.THREE_OF_FIVE:
587
537
  return {
588
538
  existingExternalServerShareCount: 1,
589
539
  newExternalServerShareCount: 2,
590
540
  existingDynamicServerShareCount: 1,
591
541
  newDynamicServerShareCount: 1
592
542
  };
593
- // 2-of-3 -> 2-of-2:
594
- // -- dyanmic server shares: 1 existing, 0 new
595
- // -- external server shares: 1 existing, 0 new
596
- case oldThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_THREE && newThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO:
597
- return {
598
- existingExternalServerShareCount: 1,
599
- newExternalServerShareCount: 0,
600
- existingDynamicServerShareCount: 1,
601
- newDynamicServerShareCount: 0
602
- };
603
543
  // 3-of-5 -> 2-of-3:
604
544
  // -- dyanmic server shares: 1 existing, 0 new
605
545
  // -- external server shares: 2 existing, 0 new
@@ -982,7 +922,7 @@ const getRequiredExternalKeyShareId = (ks)=>{
982
922
  * before it is posted and surfaces in Datadog exactly as the recovery path does.
983
923
  */ const assertDynamicLocationsHaveExternalKeyShareId = (locations)=>locations.filter((location)=>location.location === BackupLocation.DYNAMIC).forEach((location)=>getRequiredExternalKeyShareId(location));
984
924
 
985
- var version = "1.0.56";
925
+ var version = "1.0.58";
986
926
 
987
927
  class BaseClient {
988
928
  /**
@@ -2150,6 +2090,33 @@ const serializeMessageForForwardMPC = ({ message, isFormatted = false, chainName
2150
2090
  return serializedMessage;
2151
2091
  };
2152
2092
 
2093
+ // Mirrors forward-mpc-client's ErrorCode values (the /utils subpath does not
2094
+ // export the ErrorCode const, so the codes are inlined here).
2095
+ const RECOVERED_CONNECTION_CHURN_CODES = new Set([
2096
+ 'CONNECTION_FAILED',
2097
+ 'CONNECTION_TIMEOUT',
2098
+ 'NOT_CONNECTED',
2099
+ 'TRANSPORT_CLOSED',
2100
+ 'HANDSHAKE_FAILED'
2101
+ ]);
2102
+ /**
2103
+ * Returns true when a classified Forward MPC error is recovered connection
2104
+ * churn that should be logged at `warn` rather than `error`.
2105
+ *
2106
+ * The Forward MPC enclave is an optimization side-channel: the client retries
2107
+ * connections internally, and `shouldFallback` is true for every Forward MPC
2108
+ * failure mode — relay-based MPC is a fully functional safety net, so a
2109
+ * connection-lifecycle failure never blocks a user operation on its own.
2110
+ * Terminal failures (both paths failing) are logged at the operation sites.
2111
+ *
2112
+ * Churn covers rate-limited upgrades and the transport-lifecycle error codes
2113
+ * (connect/reconnect failures, timeouts, socket closes, and handshake-request
2114
+ * timeouts — production evidence shows these concentrate on hostile/flaky
2115
+ * networks). Attestation failures, HANDSHAKE_INVALID_RESPONSE, SERVER_ERROR,
2116
+ * and unclassified errors are NOT churn: they indicate enclave tampering or
2117
+ * protocol breakage and must stay at `error` so monitors can page on them.
2118
+ */ const isRecoveredForwardMpcConnectionChurn = (classification)=>classification.errorType === 'RATE_LIMITED' || classification.errorCode !== undefined && RECOVERED_CONNECTION_CHURN_CODES.has(classification.errorCode);
2119
+
2153
2120
  /**
2154
2121
  * Normalizes an unknown thrown value into flat, log-friendly fields.
2155
2122
  *
@@ -2297,4 +2264,4 @@ const handleAxiosError = (error, message, context, _logger)=>{
2297
2264
  throw new WalletApiError(resolvedStatus, STATUS_MESSAGES[resolvedStatus]);
2298
2265
  };
2299
2266
 
2300
- export { AuthMode, BITCOIN_ADDRESS_TYPE_CONFIG, BITCOIN_DERIVATION_PATHS, BROWSER_SDK_ROUTE_PREFIX, BackupLocation, BitcoinAddressType, BitcoinNetwork, BusinessAccountClient, BusinessAccountMemberRole, BusinessAccountSignerType, CreateRoomPartiesOptions, DELEGATED_SHARE_COUNT, DYNAMIC_AUTH_BASE_API_URL_MAP, DYNAMIC_AUTH_DEV_BASE_API_URL, DYNAMIC_AUTH_PREPROD_BASE_API_URL, DYNAMIC_AUTH_PROD_BASE_API_URL, DYNAMIC_CLIENT_RELAY_REDCOAST_API_KEY_MAP, DYNAMIC_CLIENT_RELAY_REDCOAST_APP_ID_MAP, DYNAMIC_FORWARD_MPC_DEV_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_ENCLAVE_ATTESTATION_CONFIG_MAP, DYNAMIC_FORWARD_MPC_ENCLAVE_URL_MAP, DYNAMIC_FORWARD_MPC_PREPROD_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_PROD_ENCLAVE_URL, DYNAMIC_KEYSHARES_RELAY_MAP, DYNAMIC_KEYSHARES_RELAY_PREPROD_BASE_API_URL, DYNAMIC_KEYSHARES_RELAY_PROD_BASE_API_URL, DynamicApiClient, DynamicClientSessionSignature, DynamicElevatedAccessTokenHeader, DynamicForwardMPCHeader, DynamicMfaTokenHeader, DynamicRequestIdHeader, DynamicSessionPublicKeyHeader, DynamicTraceElapsedTimeHeader, DynamicTraceIdHeader, ENCRYPTED_SHARES_STORAGE_SUFFIX, ENVIRONMENT_ENUM, EVM_COMPATIBLE_CHAINS, FEATURE_FLAGS, IFRAME_DOMAIN_MAP, Logger, MIDNIGHT_DERIVATION_PATHS, MPC_CHAIN_CONFIG, MPC_CONFIG, MPC_RELAY_DEV_API_URL, MPC_RELAY_PREPROD_API_URL, MPC_RELAY_PROD_API_URL, MPC_RELAY_URL_MAP, NoopLogger, PREPROD_RELAY_API_KEY, PREPROD_RELAY_APP_ID, PROD_RELAY_API_KEY, PROD_RELAY_APP_ID, RELAY_API_KEY_HEADER, RELAY_APP_ID_HEADER, SDK_NAMESPACE, SERVER_SDK_ROUTE_PREFIX, SOLANA_RPC_URL, SuccessEventType, ThresholdSignatureScheme, URL_PATTERNS, WalletApiError, WalletOperation, WalletReadyState, assertDynamicLocationsHaveExternalKeyShareId, chain, chainEnumToVerifiedCredentialName, formatNamespacedVersion, getBitcoinChainConfig, getClientThreshold, getDynamicServerThreshold, getEnvironmentFromUrl, getMPCChainConfig, getRequiredExternalKeyShareId, getReshareConfig, getServerWalletReshareConfig, getTSSConfig, getVersionNamespace, getVersionWithoutNamespace, handleAxiosError, isEvmCompatibleChain, parseNamespacedVersion, serializeError, serializeMessageForForwardMPC, verifiedCredentialNameToChainEnum };
2267
+ export { AuthMode, BITCOIN_ADDRESS_TYPE_CONFIG, BITCOIN_DERIVATION_PATHS, BROWSER_SDK_ROUTE_PREFIX, BackupLocation, BitcoinAddressType, BitcoinNetwork, BusinessAccountClient, BusinessAccountMemberRole, BusinessAccountSignerType, CreateRoomPartiesOptions, DELEGATED_SHARE_COUNT, DYNAMIC_AUTH_BASE_API_URL_MAP, DYNAMIC_AUTH_DEV_BASE_API_URL, DYNAMIC_AUTH_PREPROD_BASE_API_URL, DYNAMIC_AUTH_PROD_BASE_API_URL, DYNAMIC_CLIENT_RELAY_REDCOAST_API_KEY_MAP, DYNAMIC_CLIENT_RELAY_REDCOAST_APP_ID_MAP, DYNAMIC_FORWARD_MPC_DEV_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_ENCLAVE_ATTESTATION_CONFIG_MAP, DYNAMIC_FORWARD_MPC_ENCLAVE_URL_MAP, DYNAMIC_FORWARD_MPC_PREPROD_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_PROD_ENCLAVE_URL, DYNAMIC_KEYSHARES_RELAY_MAP, DYNAMIC_KEYSHARES_RELAY_PREPROD_BASE_API_URL, DYNAMIC_KEYSHARES_RELAY_PROD_BASE_API_URL, DynamicApiClient, DynamicClientSessionSignature, DynamicElevatedAccessTokenHeader, DynamicForwardMPCHeader, DynamicMfaTokenHeader, DynamicRequestIdHeader, DynamicSessionPublicKeyHeader, DynamicTraceElapsedTimeHeader, DynamicTraceIdHeader, ENCRYPTED_SHARES_STORAGE_SUFFIX, ENVIRONMENT_ENUM, EVM_COMPATIBLE_CHAINS, FEATURE_FLAGS, IFRAME_DOMAIN_MAP, Logger, MIDNIGHT_DERIVATION_PATHS, MPC_CHAIN_CONFIG, MPC_CONFIG, MPC_RELAY_DEV_API_URL, MPC_RELAY_PREPROD_API_URL, MPC_RELAY_PROD_API_URL, MPC_RELAY_URL_MAP, NoopLogger, PREPROD_RELAY_API_KEY, PREPROD_RELAY_APP_ID, PROD_RELAY_API_KEY, PROD_RELAY_APP_ID, RELAY_API_KEY_HEADER, RELAY_APP_ID_HEADER, SDK_NAMESPACE, SERVER_SDK_ROUTE_PREFIX, SOLANA_RPC_URL, SuccessEventType, ThresholdSignatureScheme, URL_PATTERNS, WalletApiError, WalletOperation, WalletReadyState, assertDynamicLocationsHaveExternalKeyShareId, chain, chainEnumToVerifiedCredentialName, formatNamespacedVersion, getBitcoinChainConfig, getClientThreshold, getDynamicServerThreshold, getEnvironmentFromUrl, getMPCChainConfig, getRequiredExternalKeyShareId, getReshareConfig, getServerWalletReshareConfig, getTSSConfig, getVersionNamespace, getVersionWithoutNamespace, handleAxiosError, isEvmCompatibleChain, isRecoveredForwardMpcConnectionChurn, parseNamespacedVersion, serializeError, serializeMessageForForwardMPC, verifiedCredentialNameToChainEnum };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@dynamic-labs-wallet/core",
3
- "version": "1.0.56",
3
+ "version": "1.0.58",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@dynamic-labs/sdk-api-core": "^0.0.984",
8
- "@dynamic-labs-wallet/primitives": "1.0.56",
8
+ "@dynamic-labs-wallet/primitives": "1.0.58",
9
9
  "axios": "1.16.0",
10
10
  "uuid": "11.1.0"
11
11
  },
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/mpc/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,wBAAwB,EAA+B,MAAM,gBAAgB,CAAC;AACrH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAErE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,gBACnB,kBAAkB,KAC9B;IAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IAAC,gBAAgB,EAAE,gBAAgB,CAAA;CAQhE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,cAAe,MAAM,kBAAkB,aAAa;oBAhB7D,MAAM,EAAE;sBAAoB,gBAAgB;CA+BhE,CAAC;AAEF,eAAO,MAAM,YAAY,6BAA8B,wBAAwB;;;CAG9E,CAAC;AAEF,eAAO,MAAM,kBAAkB,6BAA8B,wBAAwB,WAEpF,CAAC;AAEF,eAAO,MAAM,yBAAyB,6BAA8B,wBAAwB,WAE3F,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,kEAG1B;IACD,2BAA2B,EAAE,wBAAwB,CAAC;IACtD,2BAA2B,EAAE,wBAAwB,CAAC;IAGtD,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC,KAAG;IACF,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;CAsG7B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,kEAGtC;IACD,2BAA2B,EAAE,wBAAwB,CAAC;IACtD,2BAA2B,EAAE,wBAAwB,CAAC;CACvD,KAAG;IACF,gCAAgC,EAAE,MAAM,CAAC;IACzC,2BAA2B,EAAE,MAAM,CAAC;IACpC,+BAA+B,EAAE,MAAM,CAAC;IACxC,0BAA0B,EAAE,MAAM,CAAC;CAsGpC,CAAC;AAEF,eAAO,MAAM,YAAY;;;;CAIxB,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAWpE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/mpc/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,wBAAwB,EAA+B,MAAM,gBAAgB,CAAC;AACrH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAErE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,gBACnB,kBAAkB,KAC9B;IAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IAAC,gBAAgB,EAAE,gBAAgB,CAAA;CAQhE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,cAAe,MAAM,kBAAkB,aAAa;oBAhB7D,MAAM,EAAE;sBAAoB,gBAAgB;CA+BhE,CAAC;AAEF,eAAO,MAAM,YAAY,6BAA8B,wBAAwB;;;CAG9E,CAAC;AAEF,eAAO,MAAM,kBAAkB,6BAA8B,wBAAwB,WAEpF,CAAC;AAEF,eAAO,MAAM,yBAAyB,6BAA8B,wBAAwB,WAE3F,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,kEAG1B;IACD,2BAA2B,EAAE,wBAAwB,CAAC;IACtD,2BAA2B,EAAE,wBAAwB,CAAC;IAGtD,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC,KAAG;IACF,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;CAwE7B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,kEAGtC;IACD,2BAA2B,EAAE,wBAAwB,CAAC;IACtD,2BAA2B,EAAE,wBAAwB,CAAC;CACvD,KAAG;IACF,gCAAgC,EAAE,MAAM,CAAC;IACzC,2BAA2B,EAAE,MAAM,CAAC;IACpC,+BAA+B,EAAE,MAAM,CAAC;IACxC,0BAA0B,EAAE,MAAM,CAAC;CAwEpC,CAAC;AAEF,eAAO,MAAM,YAAY;;;;CAIxB,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAWpE"}
@@ -1,7 +1,26 @@
1
+ import type { ForwardMpcErrorClassification } from '@dynamic-labs-wallet/forward-mpc-client/utils';
1
2
  /**
2
3
  * Re-export error classification utilities from forward-mpc-client.
3
4
  * These utilities help standardize Forward MPC error handling across the SDK.
4
5
  */
5
6
  export { classifyForwardMpcError, isForwardMpcError, isAttestationError, } from '@dynamic-labs-wallet/forward-mpc-client/utils';
6
7
  export type { ForwardMpcErrorType, ForwardMpcErrorClassification } from '@dynamic-labs-wallet/forward-mpc-client/utils';
8
+ /**
9
+ * Returns true when a classified Forward MPC error is recovered connection
10
+ * churn that should be logged at `warn` rather than `error`.
11
+ *
12
+ * The Forward MPC enclave is an optimization side-channel: the client retries
13
+ * connections internally, and `shouldFallback` is true for every Forward MPC
14
+ * failure mode — relay-based MPC is a fully functional safety net, so a
15
+ * connection-lifecycle failure never blocks a user operation on its own.
16
+ * Terminal failures (both paths failing) are logged at the operation sites.
17
+ *
18
+ * Churn covers rate-limited upgrades and the transport-lifecycle error codes
19
+ * (connect/reconnect failures, timeouts, socket closes, and handshake-request
20
+ * timeouts — production evidence shows these concentrate on hostile/flaky
21
+ * networks). Attestation failures, HANDSHAKE_INVALID_RESPONSE, SERVER_ERROR,
22
+ * and unclassified errors are NOT churn: they indicate enclave tampering or
23
+ * protocol breakage and must stay at `error` so monitors can page on them.
24
+ */
25
+ export declare const isRecoveredForwardMpcConnectionChurn: (classification: ForwardMpcErrorClassification) => boolean;
7
26
  //# sourceMappingURL=forwardMpcErrorHandling.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"forwardMpcErrorHandling.d.ts","sourceRoot":"","sources":["../../src/utils/forwardMpcErrorHandling.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,+CAA+C,CAAC;AAEvD,YAAY,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,+CAA+C,CAAC"}
1
+ {"version":3,"file":"forwardMpcErrorHandling.d.ts","sourceRoot":"","sources":["../../src/utils/forwardMpcErrorHandling.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,+CAA+C,CAAC;AAEnG;;;GAGG;AACH,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,+CAA+C,CAAC;AAEvD,YAAY,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,+CAA+C,CAAC;AAYxH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oCAAoC,mBAAoB,6BAA6B,KAAG,OAEO,CAAC"}