@monolythium/core-sdk 0.3.16 → 0.4.1

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/dist/index.cjs CHANGED
@@ -4,6 +4,8 @@ var blake3_js = require('@noble/hashes/blake3.js');
4
4
  var sha3_js = require('@noble/hashes/sha3.js');
5
5
  var mlDsa_js = require('@noble/post-quantum/ml-dsa.js');
6
6
  var bls12381_js = require('@noble/curves/bls12-381.js');
7
+ var bip39 = require('@scure/bip39');
8
+ var english_js = require('@scure/bip39/wordlists/english.js');
7
9
  require('@noble/post-quantum/ml-kem.js');
8
10
  require('@noble/ciphers/chacha.js');
9
11
  require('@noble/hashes/utils.js');
@@ -437,10 +439,24 @@ var NODE_REGISTRY_SELECTORS = {
437
439
  /** `getOperatorNetworkMetadata(bytes32)` view (PF-6). */
438
440
  getOperatorNetworkMetadata: "0x" + selectorHex("getOperatorNetworkMetadata(bytes32)"),
439
441
  /** `getClusterDiversity(uint32)` view (PF-6). */
440
- getClusterDiversity: "0x" + selectorHex("getClusterDiversity(uint32)")
442
+ getClusterDiversity: "0x" + selectorHex("getClusterDiversity(uint32)"),
443
+ /** `requestClusterJoin(uint32,bytes)` — CJ-1 joining operator posts an admit request. */
444
+ requestClusterJoin: "0x" + selectorHex("requestClusterJoin(uint32,bytes)"),
445
+ /** `voteClusterAdmit(uint32,bytes32,bytes)` — CJ-1 current member admit vote. */
446
+ voteClusterAdmit: "0x" + selectorHex("voteClusterAdmit(uint32,bytes32,bytes)"),
447
+ /** `cancelClusterJoin(uint32,bytes32)` — CJ-1 requester cancellation/refund. */
448
+ cancelClusterJoin: "0x" + selectorHex("cancelClusterJoin(uint32,bytes32)"),
449
+ /** `expireClusterJoin(uint32,bytes32)` — CJ-1 public reaper/refund. */
450
+ expireClusterJoin: "0x" + selectorHex("expireClusterJoin(uint32,bytes32)"),
451
+ /** `getClusterJoinRequest(uint32,bytes32)` — CJ-1 request status view. */
452
+ getClusterJoinRequest: "0x" + selectorHex("getClusterJoinRequest(uint32,bytes32)")
441
453
  };
442
- var NODE_REGISTRY_BLS_PUBKEY_BYTES = 48;
443
- var NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES = 96;
454
+ var NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES = 48;
455
+ var NODE_REGISTRY_BLS_PUBKEY_BYTES = NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES;
456
+ var NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES = 1952;
457
+ var NODE_REGISTRY_CONSENSUS_POP_BYTES = 3309;
458
+ var NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES = 96;
459
+ var NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES = NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES;
444
460
  var NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS = 5;
445
461
  var NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS = 7;
446
462
  var NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID = (1n << 56n) - 1n;
@@ -510,7 +526,7 @@ function encodeSubmitPendingChangeCalldata(args) {
510
526
  const { kind, kindCode } = normalizePendingChangeKind(args.kind);
511
527
  const targetPubkey = expectLength2(
512
528
  toBytes(args.targetPubkey),
513
- NODE_REGISTRY_BLS_PUBKEY_BYTES,
529
+ NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
514
530
  "targetPubkey"
515
531
  );
516
532
  const effectiveEpoch = toUint64(args.effectiveEpoch, "effectiveEpoch");
@@ -524,8 +540,7 @@ function encodeSubmitPendingChangeCalldata(args) {
524
540
  if (kind !== "rotate" && intentId !== 0n) {
525
541
  throw new NodeRegistryError("only rotate pending changes may carry a non-zero intentId");
526
542
  }
527
- const targetTail = new Uint8Array(32);
528
- targetTail.set(targetPubkey.slice(32, 48), 0);
543
+ const targetPubkeyPadded = padToWord(targetPubkey);
529
544
  return bytesToHex(
530
545
  concatBytes(
531
546
  hexToBytes(NODE_REGISTRY_SELECTORS.submitPendingChange),
@@ -533,55 +548,59 @@ function encodeSubmitPendingChangeCalldata(args) {
533
548
  uint64Word(4n * 32n, "targetPubkeyOffset"),
534
549
  uint64Word(effectiveEpoch, "effectiveEpoch"),
535
550
  uint64Word(intentId, "intentId"),
536
- uint64Word(BigInt(NODE_REGISTRY_BLS_PUBKEY_BYTES), "targetPubkeyLength"),
537
- targetPubkey.slice(0, 32),
538
- targetTail
551
+ uint64Word(BigInt(targetPubkey.length), "targetPubkeyLength"),
552
+ targetPubkeyPadded
539
553
  )
540
554
  );
541
555
  }
542
556
  function encodeCancelPendingChangeCalldata(args) {
543
557
  const targetPubkey = expectLength2(
544
558
  toBytes(args.targetPubkey),
545
- NODE_REGISTRY_BLS_PUBKEY_BYTES,
559
+ NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
546
560
  "targetPubkey"
547
561
  );
548
- const targetTail = new Uint8Array(32);
549
- targetTail.set(targetPubkey.slice(32, 48), 0);
562
+ const targetPubkeyPadded = padToWord(targetPubkey);
550
563
  return bytesToHex(
551
564
  concatBytes(
552
565
  hexToBytes(NODE_REGISTRY_SELECTORS.cancelPendingChange),
553
566
  uint64Word(args.epoch, "epoch"),
554
567
  uint64Word(2n * 32n, "targetPubkeyOffset"),
555
- uint64Word(BigInt(NODE_REGISTRY_BLS_PUBKEY_BYTES), "targetPubkeyLength"),
556
- targetPubkey.slice(0, 32),
557
- targetTail
568
+ uint64Word(BigInt(targetPubkey.length), "targetPubkeyLength"),
569
+ targetPubkeyPadded
558
570
  )
559
571
  );
560
572
  }
561
- function parseDkgResharePublicKeys(blsPublicKeys) {
562
- const keys = toBytes(blsPublicKeys);
563
- if (keys.length % NODE_REGISTRY_BLS_PUBKEY_BYTES !== 0) {
564
- throw new NodeRegistryError("blsPublicKeys length must be a multiple of 48 bytes");
573
+ function parseDkgResharePublicKeys(consensusPublicKeys) {
574
+ const keys = toBytes(consensusPublicKeys);
575
+ if (keys.length % NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES !== 0) {
576
+ throw new NodeRegistryError(
577
+ `consensusPublicKeys length must be a multiple of ${NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES} bytes`
578
+ );
565
579
  }
566
- const signerCount = keys.length / NODE_REGISTRY_BLS_PUBKEY_BYTES;
580
+ const signerCount = keys.length / NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES;
567
581
  if (signerCount < NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS || signerCount > NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS) {
568
582
  throw new NodeRegistryError(
569
- `blsPublicKeys must contain ${NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS}..${NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS} signers`
583
+ `consensusPublicKeys must contain ${NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS}..${NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS} signers`
570
584
  );
571
585
  }
572
586
  const out = [];
573
587
  const seen = /* @__PURE__ */ new Set();
574
- for (let offset = 0; offset < keys.length; offset += NODE_REGISTRY_BLS_PUBKEY_BYTES) {
575
- const key = keys.slice(offset, offset + NODE_REGISTRY_BLS_PUBKEY_BYTES);
588
+ for (let offset = 0; offset < keys.length; offset += NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES) {
589
+ const key = keys.slice(offset, offset + NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES);
576
590
  const keyHex = bytesToHex(key);
577
591
  if (seen.has(keyHex)) {
578
- throw new NodeRegistryError("blsPublicKeys contains a duplicate signer pubkey");
592
+ throw new NodeRegistryError("consensusPublicKeys contains a duplicate signer pubkey");
579
593
  }
580
594
  seen.add(keyHex);
581
595
  out.push(key);
582
596
  }
583
597
  return out;
584
598
  }
599
+ function dkgReshareConsensusPublicKeys(args) {
600
+ if (args.consensusPublicKeys !== void 0) return args.consensusPublicKeys;
601
+ if (args.blsPublicKeys !== void 0) return args.blsPublicKeys;
602
+ throw new NodeRegistryError("consensusPublicKeys is required");
603
+ }
585
604
  function encodeAttestDkgReshareCalldata(args) {
586
605
  const intentId = toUint64(args.intentId, "intentId");
587
606
  if (intentId === 0n) {
@@ -590,10 +609,10 @@ function encodeAttestDkgReshareCalldata(args) {
590
609
  if (intentId > NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID) {
591
610
  throw new NodeRegistryError("intentId must be <= 2^56-1");
592
611
  }
593
- const publicKeys = concatBytes(...parseDkgResharePublicKeys(args.blsPublicKeys));
612
+ const publicKeys = concatBytes(...parseDkgResharePublicKeys(dkgReshareConsensusPublicKeys(args)));
594
613
  const thresholdSig = expectLength2(
595
614
  toBytes(args.thresholdSig),
596
- NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES,
615
+ NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES,
597
616
  "thresholdSig"
598
617
  );
599
618
  const keysPadded = padToWord(publicKeys);
@@ -604,15 +623,94 @@ function encodeAttestDkgReshareCalldata(args) {
604
623
  concatBytes(
605
624
  hexToBytes(NODE_REGISTRY_SELECTORS.attestDkgReshare),
606
625
  uint64Word(intentId, "intentId"),
607
- uint64Word(offsetKeys, "blsPublicKeysOffset"),
626
+ uint64Word(offsetKeys, "consensusPublicKeysOffset"),
608
627
  uint64Word(offsetSig, "thresholdSigOffset"),
609
- uint64Word(BigInt(publicKeys.length), "blsPublicKeysLength"),
628
+ uint64Word(BigInt(publicKeys.length), "consensusPublicKeysLength"),
610
629
  keysPadded,
611
630
  uint64Word(BigInt(thresholdSig.length), "thresholdSigLength"),
612
631
  sigPadded
613
632
  )
614
633
  );
615
634
  }
635
+ function encodeRequestClusterJoinCalldata(args) {
636
+ const operatorPubkey = expectLength2(
637
+ toBytes(args.operatorPubkey),
638
+ NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
639
+ "operatorPubkey"
640
+ );
641
+ const operatorPubkeyPadded = padToWord(operatorPubkey);
642
+ return bytesToHex(
643
+ concatBytes(
644
+ hexToBytes(NODE_REGISTRY_SELECTORS.requestClusterJoin),
645
+ uint32Word(toUint32(args.clusterId, "clusterId")),
646
+ uint64Word(2n * 32n, "operatorPubkeyOffset"),
647
+ uint64Word(BigInt(operatorPubkey.length), "operatorPubkeyLength"),
648
+ operatorPubkeyPadded
649
+ )
650
+ );
651
+ }
652
+ function encodeVoteClusterAdmitCalldata(args) {
653
+ const operatorId = expectLength2(toBytes(args.operatorId), 32, "operatorId");
654
+ const voterPubkey = expectLength2(
655
+ toBytes(args.voterPubkey),
656
+ NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
657
+ "voterPubkey"
658
+ );
659
+ const voterPubkeyPadded = padToWord(voterPubkey);
660
+ return bytesToHex(
661
+ concatBytes(
662
+ hexToBytes(NODE_REGISTRY_SELECTORS.voteClusterAdmit),
663
+ uint32Word(toUint32(args.clusterId, "clusterId")),
664
+ operatorId,
665
+ uint64Word(3n * 32n, "voterPubkeyOffset"),
666
+ uint64Word(BigInt(voterPubkey.length), "voterPubkeyLength"),
667
+ voterPubkeyPadded
668
+ )
669
+ );
670
+ }
671
+ function encodeCancelClusterJoinCalldata(args) {
672
+ return bytesToHex(
673
+ concatBytes(
674
+ hexToBytes(NODE_REGISTRY_SELECTORS.cancelClusterJoin),
675
+ uint32Word(toUint32(args.clusterId, "clusterId")),
676
+ expectLength2(toBytes(args.operatorId), 32, "operatorId")
677
+ )
678
+ );
679
+ }
680
+ function encodeExpireClusterJoinCalldata(args) {
681
+ return bytesToHex(
682
+ concatBytes(
683
+ hexToBytes(NODE_REGISTRY_SELECTORS.expireClusterJoin),
684
+ uint32Word(toUint32(args.clusterId, "clusterId")),
685
+ expectLength2(toBytes(args.operatorId), 32, "operatorId")
686
+ )
687
+ );
688
+ }
689
+ function encodeGetClusterJoinRequestCalldata(args) {
690
+ return bytesToHex(
691
+ concatBytes(
692
+ hexToBytes(NODE_REGISTRY_SELECTORS.getClusterJoinRequest),
693
+ uint32Word(toUint32(args.clusterId, "clusterId")),
694
+ expectLength2(toBytes(args.operatorId), 32, "operatorId")
695
+ )
696
+ );
697
+ }
698
+ function decodeClusterJoinRequest(returnData) {
699
+ const bytes = expectLength2(toBytes(returnData), 8 * 32, "clusterJoinRequest");
700
+ const word = (i) => bytes.slice(i * 32, (i + 1) * 32);
701
+ const statusCode = numberFromWord(word(5), "status", 255);
702
+ return {
703
+ owner: bytesToHex(word(0).slice(12, 32)),
704
+ requestEpoch: u64FromWord(word(1)),
705
+ snapshotThreshold: numberFromWord(word(2), "snapshotThreshold", 65535),
706
+ snapshotN: numberFromWord(word(3), "snapshotN", 65535),
707
+ voteCount: numberFromWord(word(4), "voteCount", 65535),
708
+ statusCode,
709
+ status: clusterJoinRequestStatusLabel(statusCode),
710
+ bondLythoshi: uintFromWord(word(6)),
711
+ sealRosterPending: numberFromWord(word(7), "sealRosterPending", 1) === 1
712
+ };
713
+ }
616
714
  function encodeReportServiceProbeCalldata(args) {
617
715
  if (!isValidPublicServiceProbeMask(args.serviceMask)) {
618
716
  throw new NodeRegistryError(
@@ -699,7 +797,9 @@ function deriveClusterAnchorAddress(roster, threshold) {
699
797
  if (!Number.isInteger(threshold) || threshold < 0 || threshold > 65535) {
700
798
  throw new NodeRegistryError("threshold must be a uint16");
701
799
  }
702
- const members = roster.map((m, i) => expectLength2(toBytes(m), 48, `roster[${i}]`));
800
+ const members = roster.map(
801
+ (m, i) => expectLength2(toBytes(m), NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES, `roster[${i}]`)
802
+ );
703
803
  members.sort(compareBytes);
704
804
  const parts = [
705
805
  new TextEncoder().encode(MULTISIG_ADDRESS_DERIVATION_DOMAIN),
@@ -724,6 +824,36 @@ function u64FromWord(word) {
724
824
  }
725
825
  return v;
726
826
  }
827
+ function uintFromWord(word) {
828
+ let v = 0n;
829
+ for (const byte of word) {
830
+ v = v << 8n | BigInt(byte);
831
+ }
832
+ return v;
833
+ }
834
+ function numberFromWord(word, name, max) {
835
+ const value = uintFromWord(word);
836
+ if (value > BigInt(max)) {
837
+ throw new NodeRegistryError(`${name} must be <= ${max}`);
838
+ }
839
+ return Number(value);
840
+ }
841
+ function clusterJoinRequestStatusLabel(status) {
842
+ switch (status) {
843
+ case 0:
844
+ return "none";
845
+ case 1:
846
+ return "open";
847
+ case 2:
848
+ return "admitted";
849
+ case 3:
850
+ return "cancelled";
851
+ case 4:
852
+ return "expired";
853
+ default:
854
+ return "unknown";
855
+ }
856
+ }
727
857
  function u64BeBytes(value) {
728
858
  const out = new Uint8Array(8);
729
859
  let n = value;
@@ -755,6 +885,27 @@ function expectUint32(value, name) {
755
885
  }
756
886
  return value;
757
887
  }
888
+ function toUint32(value, name) {
889
+ let parsed;
890
+ if (typeof value === "bigint") {
891
+ parsed = value;
892
+ } else if (typeof value === "number") {
893
+ if (!Number.isSafeInteger(value)) {
894
+ throw new NodeRegistryError(`${name} must be a safe integer`);
895
+ }
896
+ parsed = BigInt(value);
897
+ } else {
898
+ const trimmed = value.trim();
899
+ if (!/^\d+$/u.test(trimmed)) {
900
+ throw new NodeRegistryError(`${name} must be a decimal uint32`);
901
+ }
902
+ parsed = BigInt(trimmed);
903
+ }
904
+ if (parsed < 0n || parsed > 0xffffffffn) {
905
+ throw new NodeRegistryError(`${name} must fit uint32`);
906
+ }
907
+ return Number(parsed);
908
+ }
758
909
  function uint32Word(value) {
759
910
  const out = new Uint8Array(32);
760
911
  const n = expectUint32(value, "uint32");
@@ -897,6 +1048,16 @@ function bigintToBeBytes(value, bytes, label) {
897
1048
  }
898
1049
  return out;
899
1050
  }
1051
+ function parseBigint(value, label) {
1052
+ if (value === void 0) throw new Error(`${label} missing`);
1053
+ if (typeof value === "bigint") return value;
1054
+ if (typeof value === "number") {
1055
+ if (!Number.isSafeInteger(value) || value < 0) throw new Error(`${label} must be a non-negative safe integer`);
1056
+ return BigInt(value);
1057
+ }
1058
+ if (value.startsWith("0x") || value.startsWith("0X")) return BigInt(value);
1059
+ return BigInt(value);
1060
+ }
900
1061
 
901
1062
  // src/crypto/submission.ts
902
1063
  async function fetchEncryptionKey(client) {
@@ -918,6 +1079,38 @@ async function buildEncryptedSubmission(_args) {
918
1079
  async function submitEncryptedEnvelope(client, envelopeWireHex) {
919
1080
  return client.call("lyth_submitEncrypted", [envelopeWireHex]);
920
1081
  }
1082
+ function buildPlaintextSubmission(args) {
1083
+ const signed = args.backend.signEvmTx(args.tx);
1084
+ return {
1085
+ signedTxWireHex: `0x${signed.wireHex}`,
1086
+ innerTxHashHex: bytesToHex2(signed.txHash),
1087
+ innerSighashHex: bytesToHex2(signed.sighash),
1088
+ innerWireBytes: signed.wireBytes.length
1089
+ };
1090
+ }
1091
+ async function submitPlaintextTransaction(client, signedTxWireHex, expectedTxHashHex) {
1092
+ const returned = await client.call("mesh_submitTx", [signedTxWireHex]);
1093
+ const returnedBytes = hexToBytes2(returned, "mesh_submitTx tx hash");
1094
+ if (returnedBytes.length !== 32) {
1095
+ throw new Error(
1096
+ `mesh_submitTx tx hash must be 32 bytes, got ${returnedBytes.length}`
1097
+ );
1098
+ }
1099
+ const expectedBytes = hexToBytes2(expectedTxHashHex, "expected tx hash");
1100
+ if (!bytesEqual(returnedBytes, expectedBytes)) {
1101
+ throw new Error(
1102
+ `mesh_submitTx returned tx hash ${bytesToHex2(returnedBytes)} but the locally computed canonical hash is ${bytesToHex2(expectedBytes)}`
1103
+ );
1104
+ }
1105
+ return bytesToHex2(returnedBytes);
1106
+ }
1107
+ function bytesEqual(a, b) {
1108
+ if (a.length !== b.length) return false;
1109
+ for (let i = 0; i < a.length; i++) {
1110
+ if (a[i] !== b[i]) return false;
1111
+ }
1112
+ return true;
1113
+ }
921
1114
 
922
1115
  // src/crypto/bincode.ts
923
1116
  var BincodeWriter = class {
@@ -1835,11 +2028,181 @@ function concatBytes3(...parts) {
1835
2028
  function isIdentifier(value) {
1836
2029
  return /^[a-z][a-z0-9_]*$/.test(value);
1837
2030
  }
2031
+
2032
+ // src/crypto/tx.ts
2033
+ function encodeTransactionForHash(fields, tag) {
2034
+ const n = normalizeTxFields(fields);
2035
+ return concatBytes2(
2036
+ Uint8Array.of(tag),
2037
+ bigintToBeBytes(n.chainId, 8, "chainId"),
2038
+ bigintToBeBytes(n.nonce, 8, "nonce"),
2039
+ bigintToBeBytes(n.maxPriorityFeePerGas, 32, "maxPriorityFeePerGas"),
2040
+ bigintToBeBytes(n.maxFeePerGas, 32, "maxFeePerGas"),
2041
+ bigintToBeBytes(n.gasLimit, 8, "gasLimit"),
2042
+ n.to === null ? Uint8Array.of(0) : concatBytes2(Uint8Array.of(1), n.to),
2043
+ bigintToBeBytes(n.value, 32, "value"),
2044
+ bigintToBeBytes(BigInt(n.input.length), 4, "input.length"),
2045
+ n.input,
2046
+ new Uint8Array(4),
2047
+ // access_list length
2048
+ encodeExtensionsForHash(n.extensions)
2049
+ );
2050
+ }
2051
+ function bincodeSignedTransaction(fields, signature, publicKey) {
2052
+ const n = normalizeTxFields(fields);
2053
+ const sig = expectBytes(signature, ML_DSA_65_SIGNATURE_LEN, "ML-DSA-65 signature");
2054
+ const pk = expectBytes(publicKey, ML_DSA_65_PUBLIC_KEY_LEN, "ML-DSA-65 public key");
2055
+ const w = new BincodeWriter();
2056
+ w.u64(n.chainId);
2057
+ w.u64(n.nonce);
2058
+ w.bytes(uint256Be(n.maxPriorityFeePerGas, "maxPriorityFeePerGas"));
2059
+ w.bytes(uint256Be(n.maxFeePerGas, "maxFeePerGas"));
2060
+ w.u64(n.gasLimit);
2061
+ if (n.to === null) {
2062
+ w.u8(0);
2063
+ } else {
2064
+ w.u8(1);
2065
+ w.bytes(n.to);
2066
+ }
2067
+ w.bytes(uint256Be(n.value, "value"));
2068
+ w.bytes(n.input);
2069
+ w.u64(0n);
2070
+ w.u64(BigInt(n.extensions.length));
2071
+ for (const ext of n.extensions) bincodeTypedExtensionInto(w, ext);
2072
+ bincodeMlDsa65OpaqueInto(w, sig);
2073
+ bincodeMlDsa65OpaqueInto(w, pk);
2074
+ return w.toBytes();
2075
+ }
2076
+ function normalizeTxFields(fields) {
2077
+ return {
2078
+ chainId: parseBigint(fields.chainId, "chainId"),
2079
+ nonce: parseBigint(fields.nonce, "nonce"),
2080
+ maxPriorityFeePerGas: parseBigint(fields.maxPriorityFeePerGas, "maxPriorityFeePerGas"),
2081
+ maxFeePerGas: parseBigint(fields.maxFeePerGas, "maxFeePerGas"),
2082
+ gasLimit: parseBigint(fields.gasLimit, "gasLimit"),
2083
+ to: normalizeTo(fields.to),
2084
+ value: parseBigint(fields.value, "value"),
2085
+ input: normalizeBytes(fields.input ?? new Uint8Array(0), "input"),
2086
+ extensions: normalizeExtensions(fields.extensions)
2087
+ };
2088
+ }
2089
+ function normalizeTo(value) {
2090
+ if (value === null) return null;
2091
+ const bytes = normalizeBytes(value, "to");
2092
+ return expectBytes(bytes, 20, "to");
2093
+ }
2094
+ function normalizeBytes(value, label) {
2095
+ if (typeof value === "string") return hexToBytes2(value, label);
2096
+ return value instanceof Uint8Array ? value : Uint8Array.from(value);
2097
+ }
2098
+ function normalizeExtensions(value) {
2099
+ if (value === void 0) return [];
2100
+ return value.map((ext, index) => {
2101
+ if (!Number.isInteger(ext.kind) || ext.kind < 0 || ext.kind > 255) {
2102
+ throw new Error(`extensions[${index}].kind out of u8 range`);
2103
+ }
2104
+ const body = normalizeBytes("bodyHex" in ext ? ext.bodyHex : ext.body, `extensions[${index}].body`);
2105
+ if (body.length > 4294967295) {
2106
+ throw new Error(`extensions[${index}].body exceeds u32 length`);
2107
+ }
2108
+ return { kind: ext.kind, body };
2109
+ });
2110
+ }
2111
+ function encodeExtensionsForHash(extensions) {
2112
+ const chunks = [bigintToBeBytes(BigInt(extensions.length), 4, "extensions.length")];
2113
+ for (const ext of extensions) {
2114
+ chunks.push(
2115
+ Uint8Array.of(ext.kind),
2116
+ bigintToBeBytes(BigInt(ext.body.length), 4, "extension.body.length"),
2117
+ ext.body
2118
+ );
2119
+ }
2120
+ return concatBytes2(...chunks);
2121
+ }
2122
+ function uint256Be(value, label) {
2123
+ if (value < 0n || value >= 1n << 256n) throw new Error(`${label} out of u256 range`);
2124
+ const out = new Uint8Array(32);
2125
+ let v = value;
2126
+ for (let i = 31; i >= 0; i--) {
2127
+ out[i] = Number(v & 0xffn);
2128
+ v >>= 8n;
2129
+ }
2130
+ return out;
2131
+ }
2132
+ function bincodeMlDsa65OpaqueInto(w, raw) {
2133
+ w.enumVariant(ENUM_VARIANT_INDEX_ML_DSA_65);
2134
+ w.u16(STANDARD_ALGO_NUMBER_ML_DSA_65);
2135
+ w.bytes(raw);
2136
+ }
2137
+ function bincodeTypedExtensionInto(w, ext) {
2138
+ w.u8(ext.kind);
2139
+ w.bytes(ext.body);
2140
+ }
2141
+
2142
+ // src/crypto/ml-dsa.ts
2143
+ var ML_DSA_65_SEED_LEN = 32;
2144
+ var ML_DSA_65_SIGNING_KEY_LEN = 4032;
1838
2145
  var ML_DSA_65_PUBLIC_KEY_LEN = 1952;
1839
2146
  var ML_DSA_65_SIGNATURE_LEN = 3309;
1840
2147
  var STANDARD_ALGO_NUMBER_ML_DSA_65 = 1001;
2148
+ var ENUM_VARIANT_INDEX_ML_DSA_65 = 5;
1841
2149
  var ADDRESS_DERIVATION_DOMAIN = "MONO_ADDRESS_BLAKE3_20_V1";
1842
2150
  var ADDRESS_DERIVATION_DOMAIN_BYTES = new TextEncoder().encode(ADDRESS_DERIVATION_DOMAIN);
2151
+ var MlDsa65Backend = class _MlDsa65Backend {
2152
+ #secretKey;
2153
+ #publicKey;
2154
+ #addressBytes;
2155
+ constructor(secretKey, publicKey) {
2156
+ this.#secretKey = expectBytes(secretKey, ML_DSA_65_SIGNING_KEY_LEN, "ML-DSA-65 secret key").slice();
2157
+ this.#publicKey = expectBytes(publicKey, ML_DSA_65_PUBLIC_KEY_LEN, "ML-DSA-65 public key").slice();
2158
+ this.#addressBytes = mlDsa65AddressBytes(this.#publicKey);
2159
+ }
2160
+ static fromSeed(seed) {
2161
+ const kp = mlDsa_js.ml_dsa65.keygen(expectBytes(seed, ML_DSA_65_SEED_LEN, "ML-DSA-65 seed"));
2162
+ return new _MlDsa65Backend(kp.secretKey, kp.publicKey);
2163
+ }
2164
+ publicKey() {
2165
+ return this.#publicKey.slice();
2166
+ }
2167
+ addressBytes() {
2168
+ return this.#addressBytes.slice();
2169
+ }
2170
+ getAddress() {
2171
+ return bytesToHex2(this.#addressBytes);
2172
+ }
2173
+ sign(message) {
2174
+ return mlDsa_js.ml_dsa65.sign(message, this.#secretKey, { extraEntropy: false });
2175
+ }
2176
+ signPrehash(digest) {
2177
+ return this.sign(expectBytes(digest, 32, "prehash"));
2178
+ }
2179
+ verify(message, signature) {
2180
+ return mlDsa_js.ml_dsa65.verify(
2181
+ expectBytes(signature, ML_DSA_65_SIGNATURE_LEN, "ML-DSA-65 signature"),
2182
+ message,
2183
+ this.#publicKey
2184
+ );
2185
+ }
2186
+ signEvmTx(fields) {
2187
+ const txHashPreimage = encodeTransactionForHash(fields, 1);
2188
+ const sighash = sha3_js.keccak_256(txHashPreimage);
2189
+ const signature = this.sign(sighash);
2190
+ const wireBytes = bincodeSignedTransaction(fields, signature, this.#publicKey);
2191
+ const txHash = sha3_js.keccak_256(
2192
+ concatBytes2(
2193
+ encodeTransactionForHash(fields, 2),
2194
+ signature,
2195
+ this.#publicKey
2196
+ )
2197
+ );
2198
+ return {
2199
+ wireHex: bytesToHex2(wireBytes).slice(2),
2200
+ wireBytes,
2201
+ sighash,
2202
+ txHash
2203
+ };
2204
+ }
2205
+ };
1843
2206
  function mlDsa65AddressFromPublicKey(publicKey) {
1844
2207
  return bytesToHex2(mlDsa65AddressBytes(publicKey));
1845
2208
  }
@@ -3447,11 +3810,15 @@ var RpcClient = class _RpcClient {
3447
3810
  const params = status === void 0 ? operator == null ? [] : [operator] : [operator ?? null, status];
3448
3811
  return this.call("lyth_getClusterResignations", params);
3449
3812
  }
3450
- /** `lyth_getBlsRoundCertificate` — round-advancement BLS aggregate. */
3813
+ /** `lyth_getRoundCertificate` — round-advancement certificate. */
3814
+ async lythGetRoundCertificate(round) {
3815
+ return this.call("lyth_getRoundCertificate", [encodeRpcInteger(round)]);
3816
+ }
3817
+ /** @deprecated Use lythGetRoundCertificate. */
3451
3818
  async lythGetBlsRoundCertificate(round) {
3452
- return this.call("lyth_getBlsRoundCertificate", [encodeRpcInteger(round)]);
3819
+ return this.lythGetRoundCertificate(round);
3453
3820
  }
3454
- /** `lyth_getLeaderCertificate` — leader-vote BLS aggregate for a block ref. */
3821
+ /** `lyth_getLeaderCertificate` — leader-vote certificate for a block ref. */
3455
3822
  async lythGetLeaderCertificate(round, authority, digest) {
3456
3823
  return this.call("lyth_getLeaderCertificate", [encodeRpcInteger(round), authority, digest]);
3457
3824
  }
@@ -4049,7 +4416,9 @@ function normalizeOperatorInfo(value) {
4049
4416
  (v, i) => parseRpcNumber(v, `operator info activeClusterIds[${i}]`)
4050
4417
  ),
4051
4418
  operatorKeyFingerprint: parseStringNullable(row["operatorKeyFingerprint"]),
4052
- blsKeyFingerprint: parseStringNullable(row["blsKeyFingerprint"]),
4419
+ consensusKeyFingerprint: parseStringNullable(
4420
+ row["consensusKeyFingerprint"] ?? row["blsKeyFingerprint"]
4421
+ ),
4053
4422
  lifecycleState: String(row["lifecycleState"]),
4054
4423
  capability: capability && typeof capability === "object" && !Array.isArray(capability) ? capability : {}
4055
4424
  };
@@ -4058,7 +4427,7 @@ function normalizeClusterMember(value, label) {
4058
4427
  const row = expectObject(value, label);
4059
4428
  return {
4060
4429
  operatorId: String(row["operatorId"]),
4061
- blsPubkey: String(row["blsPubkey"]),
4430
+ consensusPubkey: String(row["consensusPubkey"] ?? row["blsPubkey"]),
4062
4431
  state: String(row["state"])
4063
4432
  };
4064
4433
  }
@@ -4124,7 +4493,7 @@ function normalizeOperatorAuthority(value) {
4124
4493
  schemaVersion: parseRpcNumber(row["schemaVersion"], "operator authority schemaVersion"),
4125
4494
  operatorId: String(row["operatorId"]),
4126
4495
  authorityIndex: parseRpcNumber(row["authorityIndex"], "operator authority authorityIndex"),
4127
- blsPubkey: String(row["blsPubkey"]),
4496
+ consensusPubkey: String(row["consensusPubkey"] ?? row["blsPubkey"]),
4128
4497
  active: Boolean(row["active"])
4129
4498
  };
4130
4499
  }
@@ -5870,7 +6239,7 @@ var NO_EVM_COMPACT_INCLUSION_TREE_ALGORITHM = "binary-keccak-receipt-tree";
5870
6239
  var NO_EVM_ARCHIVE_PROOF_SCHEMA = "mono.no_evm_receipt_archive_binding.v1";
5871
6240
  var NO_EVM_ARCHIVE_SIGNATURE_SCHEME = "mono.snapshot.sig.v1";
5872
6241
  var NO_EVM_FINALITY_EVIDENCE_SCHEMA = "mono.no_evm_receipt_finality.v1";
5873
- var NO_EVM_FINALITY_EVIDENCE_SOURCE = "blsRoundCertificate";
6242
+ var NO_EVM_FINALITY_EVIDENCE_SOURCE = "roundCertificate";
5874
6243
  var EMPTY_ROOT_DOMAIN_BYTES = new TextEncoder().encode(NO_EVM_RECEIPTS_ROOT_DOMAIN);
5875
6244
  var LEAF_DOMAIN_BYTES = new TextEncoder().encode(NO_EVM_RECEIPT_LEAF_DOMAIN);
5876
6245
  var NODE_DOMAIN_BYTES = new TextEncoder().encode(NO_EVM_RECEIPT_NODE_DOMAIN);
@@ -6412,7 +6781,7 @@ function verifyBoundedReceiptProof(proof) {
6412
6781
  }
6413
6782
  const actualRoot = computeNoEvmReceiptsRoot(receipts);
6414
6783
  const expectedRoot = decodeHash(proof.receiptsRoot, "receiptsRoot");
6415
- if (!bytesEqual(expectedRoot, decodeHash(actualRoot, "computedReceiptsRoot"))) {
6784
+ if (!bytesEqual2(expectedRoot, decodeHash(actualRoot, "computedReceiptsRoot"))) {
6416
6785
  throw new NoEvmReceiptProofError(
6417
6786
  "receipts_root_mismatch",
6418
6787
  `receiptsRoot mismatch: expected ${proof.receiptsRoot}, computed ${actualRoot}`
@@ -6420,7 +6789,7 @@ function verifyBoundedReceiptProof(proof) {
6420
6789
  }
6421
6790
  const actualTargetHash = computeNoEvmTargetReceiptHash(targetReceipt);
6422
6791
  const expectedTargetHash = decodeHash(proof.targetReceiptHash, "targetReceiptHash");
6423
- if (!bytesEqual(expectedTargetHash, decodeHash(actualTargetHash, "computedTargetReceiptHash"))) {
6792
+ if (!bytesEqual2(expectedTargetHash, decodeHash(actualTargetHash, "computedTargetReceiptHash"))) {
6424
6793
  throw new NoEvmReceiptProofError(
6425
6794
  "target_receipt_hash_mismatch",
6426
6795
  `targetReceiptHash mismatch: expected ${proof.targetReceiptHash}, computed ${actualTargetHash}`
@@ -6477,7 +6846,7 @@ function verifyCompactReceiptProof(proof) {
6477
6846
  const targetReceipt = decodeHexBytes(targetReceiptBytes, "targetReceiptBytes");
6478
6847
  const actualTargetHash = computeNoEvmTargetReceiptHash(targetReceipt);
6479
6848
  const expectedTargetHash = decodeHash(proof.targetReceiptHash, "targetReceiptHash");
6480
- if (!bytesEqual(expectedTargetHash, decodeHash(actualTargetHash, "computedTargetReceiptHash"))) {
6849
+ if (!bytesEqual2(expectedTargetHash, decodeHash(actualTargetHash, "computedTargetReceiptHash"))) {
6481
6850
  throw new NoEvmReceiptProofError(
6482
6851
  "target_receipt_hash_mismatch",
6483
6852
  `targetReceiptHash mismatch: expected ${proof.targetReceiptHash}, computed ${actualTargetHash}`
@@ -6488,7 +6857,7 @@ function verifyCompactReceiptProof(proof) {
6488
6857
  compactProof.leafHash,
6489
6858
  "compactInclusionProof.leafHash"
6490
6859
  );
6491
- if (!bytesEqual(expectedLeafHashBytes, actualLeafHashBytes)) {
6860
+ if (!bytesEqual2(expectedLeafHashBytes, actualLeafHashBytes)) {
6492
6861
  throw new NoEvmReceiptProofError(
6493
6862
  "compact_leaf_hash_mismatch",
6494
6863
  `compactInclusionProof.leafHash mismatch: expected ${compactProof.leafHash}, computed ${bytesToHex6(
@@ -6498,7 +6867,7 @@ function verifyCompactReceiptProof(proof) {
6498
6867
  }
6499
6868
  const compactRootBytes = decodeHash(compactProof.root, "compactInclusionProof.root");
6500
6869
  const receiptsRootBytes = decodeHash(proof.receiptsRoot, "receiptsRoot");
6501
- if (!bytesEqual(receiptsRootBytes, compactRootBytes)) {
6870
+ if (!bytesEqual2(receiptsRootBytes, compactRootBytes)) {
6502
6871
  throw new NoEvmReceiptProofError(
6503
6872
  "compact_root_mismatch",
6504
6873
  `receiptsRoot must equal compactInclusionProof.root: receiptsRoot ${proof.receiptsRoot}, compact root ${compactProof.root}`
@@ -6521,7 +6890,7 @@ function verifyCompactReceiptProof(proof) {
6521
6890
  siblingHashes,
6522
6891
  pathSides
6523
6892
  );
6524
- if (!bytesEqual(actualRootBytes, compactRootBytes)) {
6893
+ if (!bytesEqual2(actualRootBytes, compactRootBytes)) {
6525
6894
  throw new NoEvmReceiptProofError(
6526
6895
  "compact_path_mismatch",
6527
6896
  `compact inclusion path mismatch: expected ${compactProof.root}, computed ${bytesToHex6(
@@ -6675,7 +7044,7 @@ function validateCoveringSnapshotObject(snapshot, archiveContentHash, proofBlock
6675
7044
  "archiveProof.coveringSnapshot.checkpointTo must match blockHeight"
6676
7045
  );
6677
7046
  }
6678
- if (!bytesEqual(checkpointContentHash, archiveContentHash)) {
7047
+ if (!bytesEqual2(checkpointContentHash, archiveContentHash)) {
6679
7048
  throw new NoEvmReceiptProofError(
6680
7049
  "invalid_proof_shape",
6681
7050
  "archiveProof.coveringSnapshot.checkpointContentHash must match archiveProof.contentHash"
@@ -6874,7 +7243,7 @@ function validateFinalityBlockReference(blockReference, round, proofBlockHash) {
6874
7243
  );
6875
7244
  if (proofBlockHash !== void 0) {
6876
7245
  const blockHash = decodeHash(proofBlockHash, "blockHash");
6877
- if (!bytesEqual(digest, blockHash)) {
7246
+ if (!bytesEqual2(digest, blockHash)) {
6878
7247
  throw new NoEvmReceiptProofError(
6879
7248
  "invalid_proof_shape",
6880
7249
  "finalityEvidence.blockReference.digest must match blockHash"
@@ -7224,7 +7593,7 @@ function assertHashBytes(value, field2) {
7224
7593
  function isRecord3(value) {
7225
7594
  return typeof value === "object" && value !== null && !Array.isArray(value);
7226
7595
  }
7227
- function bytesEqual(a, b) {
7596
+ function bytesEqual2(a, b) {
7228
7597
  if (a.length !== b.length) return false;
7229
7598
  let diff = 0;
7230
7599
  for (let index = 0; index < a.length; index++) {
@@ -7432,6 +7801,251 @@ function assertWholeNumber(field2, value) {
7432
7801
  throw new Error(`${field2} must be a whole number`);
7433
7802
  }
7434
7803
  }
7804
+ var PQM1_ALGO_TAG_MLDSA65 = 1;
7805
+ var PQM1_VERSION_V1 = 1;
7806
+ var PQM1_PAYLOAD_LEN = 32;
7807
+ var PQM1_V1_MNEMONIC_WORDS = 24;
7808
+ var PQM1_V1_MLDSA65_DOMAIN_TAG = "monolythium.pqm1.v1.mldsa65";
7809
+ var Pqm1Error = class extends Error {
7810
+ constructor(kind, message) {
7811
+ super(message);
7812
+ this.kind = kind;
7813
+ this.name = "Pqm1Error";
7814
+ }
7815
+ kind;
7816
+ };
7817
+ var DOMAIN_BYTES = new TextEncoder().encode(PQM1_V1_MLDSA65_DOMAIN_TAG);
7818
+ function normalizeMnemonic(mnemonic) {
7819
+ return mnemonic.trim().toLowerCase().replace(/\s+/g, " ");
7820
+ }
7821
+ function ensureSupportedPayload(bytes) {
7822
+ if (bytes.length !== PQM1_PAYLOAD_LEN) {
7823
+ throw new Pqm1Error("badPayloadLength", `PQM-1 payload must be ${PQM1_PAYLOAD_LEN} bytes, got ${bytes.length}`);
7824
+ }
7825
+ if (bytes[0] !== PQM1_ALGO_TAG_MLDSA65) {
7826
+ throw new Pqm1Error("unsupportedAlgorithm", `unsupported PQM-1 algorithm tag 0x${bytes[0].toString(16).padStart(2, "0")}`);
7827
+ }
7828
+ if (bytes[1] !== PQM1_VERSION_V1) {
7829
+ throw new Pqm1Error("unsupportedVersion", `unsupported PQM-1 version 0x${bytes[1].toString(16).padStart(2, "0")}`);
7830
+ }
7831
+ }
7832
+ function parsePqm1Payload(payload) {
7833
+ const bytes = expectBytes(payload, PQM1_PAYLOAD_LEN, "PQM-1 payload").slice();
7834
+ ensureSupportedPayload(bytes);
7835
+ return {
7836
+ algoTag: PQM1_ALGO_TAG_MLDSA65,
7837
+ version: PQM1_VERSION_V1,
7838
+ entropy: bytes.slice(2),
7839
+ bytes
7840
+ };
7841
+ }
7842
+ function pqm1MnemonicToPayload(mnemonic) {
7843
+ const normalized = normalizeMnemonic(mnemonic);
7844
+ const words = normalized.length === 0 ? [] : normalized.split(" ");
7845
+ if (words.length !== PQM1_V1_MNEMONIC_WORDS) {
7846
+ throw new Pqm1Error("badWordCount", `PQM-1 mnemonic must be ${PQM1_V1_MNEMONIC_WORDS} words, got ${words.length}`);
7847
+ }
7848
+ let payload;
7849
+ try {
7850
+ payload = bip39.mnemonicToEntropy(normalized, english_js.wordlist);
7851
+ } catch (e) {
7852
+ throw new Pqm1Error("bip39Decode", `invalid PQM-1 mnemonic: ${e.message}`);
7853
+ }
7854
+ return parsePqm1Payload(payload);
7855
+ }
7856
+ function derivePqm1MlDsa65SeedFromPayload(payload) {
7857
+ const parsed = parsePqm1Payload(payload);
7858
+ return sha3_js.shake256(concatBytes2(DOMAIN_BYTES, parsed.bytes), { dkLen: ML_DSA_65_SEED_LEN });
7859
+ }
7860
+ function pqm1MnemonicToMlDsa65Seed(mnemonic) {
7861
+ return derivePqm1MlDsa65SeedFromPayload(pqm1MnemonicToPayload(mnemonic).bytes);
7862
+ }
7863
+ function pqm1MnemonicToMlDsa65Backend(mnemonic) {
7864
+ return MlDsa65Backend.fromSeed(pqm1MnemonicToMlDsa65Seed(mnemonic));
7865
+ }
7866
+
7867
+ // src/cluster-join.ts
7868
+ var DEFAULT_CLUSTER_JOIN_EXECUTION_UNIT_LIMIT = REGISTRY_DEFAULT_EXECUTION_UNIT_LIMIT;
7869
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
7870
+ var MAX_UINT32 = (1n << 32n) - 1n;
7871
+ function deriveClusterJoinOperatorId(operatorPubkey) {
7872
+ return bytesToHex2(blake3_js.blake3(normalizeConsensusPubkey(operatorPubkey, "operatorPubkey")));
7873
+ }
7874
+ function clusterJoinRequestExists(view) {
7875
+ return view.status !== "none" || view.owner.toLowerCase() !== ZERO_ADDRESS || view.bondLythoshi !== 0n;
7876
+ }
7877
+ async function readClusterJoinRequest(client, args) {
7878
+ const data = encodeGetClusterJoinRequestCalldata({
7879
+ clusterId: args.clusterId,
7880
+ operatorId: normalizeOperatorId(args.operatorId)
7881
+ });
7882
+ const output = await client.call("eth_call", [
7883
+ {
7884
+ to: nodeRegistryAddressHex(),
7885
+ data
7886
+ },
7887
+ "latest"
7888
+ ]);
7889
+ return decodeClusterJoinRequest(output);
7890
+ }
7891
+ async function preflightClusterJoinRequest(client, args) {
7892
+ try {
7893
+ return await readClusterJoinRequest(client, args);
7894
+ } catch (cause) {
7895
+ throw new Error(
7896
+ `CJ-1 getClusterJoinRequest is not exposed or failed on the connected chain: ${errorMessage(cause)}`
7897
+ );
7898
+ }
7899
+ }
7900
+ function resolveClusterJoinExecutionFee(quote, options = {}) {
7901
+ const quoted = parseBigint(quote.executionUnitPriceLythoshi, "executionUnitPriceLythoshi");
7902
+ const floor = options.minPriceLythoshi === void 0 ? MIN_EXECUTION_UNIT_PRICE_LYTHOSHI : parseBigint(options.minPriceLythoshi, "minPriceLythoshi");
7903
+ const multiplier = options.safetyMultiplier === void 0 ? EXECUTION_UNIT_PRICE_SAFETY_MULTIPLIER : parseBigint(options.safetyMultiplier, "safetyMultiplier");
7904
+ if (multiplier <= 0n) throw new Error("safetyMultiplier must be greater than zero");
7905
+ const base = quoted > floor ? quoted : floor;
7906
+ const maxFeePerGas = base * multiplier;
7907
+ const tip = options.priorityTipLythoshi === void 0 ? maxFeePerGas : clampPriorityTip(options.priorityTipLythoshi, maxFeePerGas);
7908
+ return {
7909
+ maxFeePerGas,
7910
+ maxPriorityFeePerGas: tip,
7911
+ gasLimit: options.executionUnitLimit ?? DEFAULT_CLUSTER_JOIN_EXECUTION_UNIT_LIMIT
7912
+ };
7913
+ }
7914
+ function buildRequestClusterJoinTxFields(args) {
7915
+ return {
7916
+ chainId: args.chainId,
7917
+ nonce: args.nonce,
7918
+ maxFeePerGas: parseBigint(args.fee.maxFeePerGas, "maxFeePerGas"),
7919
+ maxPriorityFeePerGas: parseBigint(args.fee.maxPriorityFeePerGas, "maxPriorityFeePerGas"),
7920
+ gasLimit: parseBigint(
7921
+ args.fee.gasLimit ?? DEFAULT_CLUSTER_JOIN_EXECUTION_UNIT_LIMIT,
7922
+ "gasLimit"
7923
+ ),
7924
+ to: nodeRegistryAddressHex(),
7925
+ value: parseU256(args.bondLythoshi, "bondLythoshi"),
7926
+ input: encodeRequestClusterJoinCalldata({
7927
+ clusterId: args.clusterId,
7928
+ operatorPubkey: normalizeConsensusPubkey(args.operatorPubkey, "operatorPubkey")
7929
+ })
7930
+ };
7931
+ }
7932
+ function buildVoteClusterAdmitTxFields(args) {
7933
+ return {
7934
+ chainId: args.chainId,
7935
+ nonce: args.nonce,
7936
+ maxFeePerGas: parseBigint(args.fee.maxFeePerGas, "maxFeePerGas"),
7937
+ maxPriorityFeePerGas: parseBigint(args.fee.maxPriorityFeePerGas, "maxPriorityFeePerGas"),
7938
+ gasLimit: parseBigint(
7939
+ args.fee.gasLimit ?? DEFAULT_CLUSTER_JOIN_EXECUTION_UNIT_LIMIT,
7940
+ "gasLimit"
7941
+ ),
7942
+ to: nodeRegistryAddressHex(),
7943
+ value: 0n,
7944
+ input: encodeVoteClusterAdmitCalldata({
7945
+ clusterId: args.clusterId,
7946
+ operatorId: normalizeOperatorId(args.operatorId),
7947
+ voterPubkey: normalizeConsensusPubkey(args.voterPubkey, "voterPubkey")
7948
+ })
7949
+ };
7950
+ }
7951
+ async function submitRequestClusterJoin(args) {
7952
+ const clusterId = parseUint32(args.clusterId, "clusterId");
7953
+ const operatorPubkey = normalizeConsensusPubkey(args.operatorPubkey, "operatorPubkey");
7954
+ const operatorIdHex = deriveClusterJoinOperatorId(operatorPubkey);
7955
+ const existing = await preflightClusterJoinRequest(args.client, {
7956
+ clusterId,
7957
+ operatorId: operatorIdHex
7958
+ });
7959
+ if (existing.status === "open") {
7960
+ throw new Error("cluster join request is already open for this operator");
7961
+ }
7962
+ if (existing.status === "admitted") {
7963
+ throw new Error("operator is already admitted for this cluster request");
7964
+ }
7965
+ const backend = pqm1MnemonicToMlDsa65Backend(args.mnemonic);
7966
+ const senderAddress = addressToTypedBech32("user", backend.addressBytes());
7967
+ const [chainId, nonce, quote] = await Promise.all([
7968
+ args.client.ethChainId(),
7969
+ args.client.lythGetTransactionCount(senderAddress),
7970
+ args.client.lythExecutionUnitPrice()
7971
+ ]);
7972
+ const tx = buildRequestClusterJoinTxFields({
7973
+ chainId,
7974
+ nonce,
7975
+ fee: resolveClusterJoinExecutionFee(quote, args),
7976
+ clusterId,
7977
+ operatorPubkey,
7978
+ bondLythoshi: args.bondLythoshi
7979
+ });
7980
+ return submitClusterJoinTx(args.client, backend, tx, clusterId, operatorIdHex);
7981
+ }
7982
+ async function submitVoteClusterAdmit(args) {
7983
+ const clusterId = parseUint32(args.clusterId, "clusterId");
7984
+ const operatorIdHex = normalizeOperatorId(args.operatorId);
7985
+ const existing = await preflightClusterJoinRequest(args.client, {
7986
+ clusterId,
7987
+ operatorId: operatorIdHex
7988
+ });
7989
+ if (!clusterJoinRequestExists(existing) || existing.status !== "open") {
7990
+ throw new Error("candidate cluster join request is not open for voting");
7991
+ }
7992
+ const backend = pqm1MnemonicToMlDsa65Backend(args.mnemonic);
7993
+ const senderAddress = addressToTypedBech32("user", backend.addressBytes());
7994
+ const [chainId, nonce, quote] = await Promise.all([
7995
+ args.client.ethChainId(),
7996
+ args.client.lythGetTransactionCount(senderAddress),
7997
+ args.client.lythExecutionUnitPrice()
7998
+ ]);
7999
+ const tx = buildVoteClusterAdmitTxFields({
8000
+ chainId,
8001
+ nonce,
8002
+ fee: resolveClusterJoinExecutionFee(quote, args),
8003
+ clusterId,
8004
+ operatorId: operatorIdHex,
8005
+ voterPubkey: args.voterPubkey
8006
+ });
8007
+ return submitClusterJoinTx(args.client, backend, tx, clusterId, operatorIdHex);
8008
+ }
8009
+ async function submitClusterJoinTx(client, backend, tx, clusterId, operatorIdHex) {
8010
+ const plaintext = buildPlaintextSubmission({ backend, tx });
8011
+ const txHash = await submitPlaintextTransaction(
8012
+ client,
8013
+ plaintext.signedTxWireHex,
8014
+ plaintext.innerTxHashHex
8015
+ );
8016
+ return {
8017
+ txHash,
8018
+ clusterId: clusterId.toString(10),
8019
+ operatorIdHex,
8020
+ innerSighashHex: plaintext.innerSighashHex,
8021
+ signedTxWireBytes: plaintext.innerWireBytes
8022
+ };
8023
+ }
8024
+ function normalizeConsensusPubkey(value, label) {
8025
+ const bytes = typeof value === "string" ? hexToBytes2(value, label) : value;
8026
+ return expectBytes(bytes, NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES, label).slice();
8027
+ }
8028
+ function normalizeOperatorId(value) {
8029
+ const bytes = typeof value === "string" ? hexToBytes2(value, "operatorId") : value;
8030
+ return bytesToHex2(expectBytes(bytes, 32, "operatorId"));
8031
+ }
8032
+ function parseUint32(value, label) {
8033
+ const parsed = parseBigint(value, label);
8034
+ if (parsed < 0n || parsed > MAX_UINT32) {
8035
+ throw new Error(`${label} out of 32-bit range`);
8036
+ }
8037
+ return parsed;
8038
+ }
8039
+ function parseU256(value, label) {
8040
+ const parsed = parseBigint(value, label);
8041
+ if (parsed < 0n || parsed >= 1n << 256n) {
8042
+ throw new Error(`${label} out of 256-bit range`);
8043
+ }
8044
+ return parsed;
8045
+ }
8046
+ function errorMessage(cause) {
8047
+ return cause instanceof Error ? cause.message : String(cause);
8048
+ }
7435
8049
  var ORACLE_EVENT_SIGS = {
7436
8050
  oracleRoundFinalized: "OracleRoundFinalized(bytes32,uint64,uint256,uint64,uint32)",
7437
8051
  observationSubmitted: "ObservationSubmitted(bytes32,uint64,address,uint256,uint64)",
@@ -9735,7 +10349,7 @@ var MONOLYTHIUM_NETWORKS = {
9735
10349
  };
9736
10350
 
9737
10351
  // src/index.ts
9738
- var version = "0.3.16";
10352
+ var version = "0.4.1";
9739
10353
 
9740
10354
  exports.ADDRESS_HRP = ADDRESS_HRP;
9741
10355
  exports.ADDRESS_KIND_HRPS = ADDRESS_KIND_HRPS;
@@ -9755,6 +10369,7 @@ exports.CHAIN_REGISTRY_RAW_BASE = CHAIN_REGISTRY_RAW_BASE;
9755
10369
  exports.CLOB_MARKET_ID_DOMAIN_TAG = CLOB_MARKET_ID_DOMAIN_TAG;
9756
10370
  exports.CLOB_SELECTORS = CLOB_SELECTORS;
9757
10371
  exports.CLUSTER_FORMED_EVENT_SIG = CLUSTER_FORMED_EVENT_SIG;
10372
+ exports.DEFAULT_CLUSTER_JOIN_EXECUTION_UNIT_LIMIT = DEFAULT_CLUSTER_JOIN_EXECUTION_UNIT_LIMIT;
9758
10373
  exports.DELEGATION_REVERT_TAGS = DELEGATION_REVERT_TAGS;
9759
10374
  exports.DELEGATION_SELECTORS = DELEGATION_SELECTORS;
9760
10375
  exports.DIVERSITY_SCORE_MAX = DIVERSITY_SCORE_MAX;
@@ -9809,9 +10424,13 @@ exports.NATIVE_MARKET_ORDER_BOOK_STREAM_TOPIC = NATIVE_MARKET_ORDER_BOOK_STREAM_
9809
10424
  exports.NODE_REGISTRY_BLS_PUBKEY_BYTES = NODE_REGISTRY_BLS_PUBKEY_BYTES;
9810
10425
  exports.NODE_REGISTRY_CAPABILITIES = NODE_REGISTRY_CAPABILITIES;
9811
10426
  exports.NODE_REGISTRY_CAPABILITY_MASK = NODE_REGISTRY_CAPABILITY_MASK;
10427
+ exports.NODE_REGISTRY_CONSENSUS_POP_BYTES = NODE_REGISTRY_CONSENSUS_POP_BYTES;
10428
+ exports.NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES = NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES;
10429
+ exports.NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES = NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES;
9812
10430
  exports.NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS = NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS;
9813
10431
  exports.NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS = NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS;
9814
10432
  exports.NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES = NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES;
10433
+ exports.NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES = NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES;
9815
10434
  exports.NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID = NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID;
9816
10435
  exports.NODE_REGISTRY_PUBLIC_SERVICE_MASK = NODE_REGISTRY_PUBLIC_SERVICE_MASK;
9817
10436
  exports.NODE_REGISTRY_SELECTORS = NODE_REGISTRY_SELECTORS;
@@ -9929,6 +10548,8 @@ exports.buildPlaceLimitOrderViaPlan = buildPlaceLimitOrderViaPlan;
9929
10548
  exports.buildPlaceSpotLimitOrderPlan = buildPlaceSpotLimitOrderPlan;
9930
10549
  exports.buildPlaceSpotMarketOrderExPlan = buildPlaceSpotMarketOrderExPlan;
9931
10550
  exports.buildPlaceSpotMarketOrderPlan = buildPlaceSpotMarketOrderPlan;
10551
+ exports.buildRequestClusterJoinTxFields = buildRequestClusterJoinTxFields;
10552
+ exports.buildVoteClusterAdmitTxFields = buildVoteClusterAdmitTxFields;
9932
10553
  exports.categoryRoot = categoryRoot;
9933
10554
  exports.checkMrvFeeDisplayConformance = checkMrvFeeDisplayConformance;
9934
10555
  exports.checkMrvStructuredFeeConformance = checkMrvStructuredFeeConformance;
@@ -9936,6 +10557,7 @@ exports.checkNativeDevkitCompatibility = checkNativeDevkitCompatibility;
9936
10557
  exports.clampPriorityTip = clampPriorityTip;
9937
10558
  exports.clobAddressHex = clobAddressHex;
9938
10559
  exports.clusterApyPercent = clusterApyPercent;
10560
+ exports.clusterJoinRequestExists = clusterJoinRequestExists;
9939
10561
  exports.compareNativeDevVersions = compareNativeDevVersions;
9940
10562
  exports.composeClaimBoundMessage = composeClaimBoundMessage;
9941
10563
  exports.computeNoEvmDacFinalityMessage = computeNoEvmDacFinalityMessage;
@@ -9947,6 +10569,7 @@ exports.computeQuoteLiquidity = computeQuoteLiquidity;
9947
10569
  exports.consumeNativeEvents = consumeNativeEvents;
9948
10570
  exports.decodeClusterDiversity = decodeClusterDiversity;
9949
10571
  exports.decodeClusterFormedEvent = decodeClusterFormedEvent;
10572
+ exports.decodeClusterJoinRequest = decodeClusterJoinRequest;
9950
10573
  exports.decodeHasPubkeyReturn = decodeHasPubkeyReturn;
9951
10574
  exports.decodeLookupPubkeyReturn = decodeLookupPubkeyReturn;
9952
10575
  exports.decodeNativeAgentStateResponse = decodeNativeAgentStateResponse;
@@ -9962,6 +10585,7 @@ exports.delegationAddressHex = delegationAddressHex;
9962
10585
  exports.denyRootFor = denyRootFor;
9963
10586
  exports.deriveClobMarketId = deriveClobMarketId;
9964
10587
  exports.deriveClusterAnchorAddress = deriveClusterAnchorAddress;
10588
+ exports.deriveClusterJoinOperatorId = deriveClusterJoinOperatorId;
9965
10589
  exports.deriveFeedId = deriveFeedId;
9966
10590
  exports.deriveMrvContractAddress = deriveMrvContractAddress;
9967
10591
  exports.deriveNativeSpotMarketId = deriveNativeSpotMarketId;
@@ -9971,6 +10595,7 @@ exports.encodeAttestDkgReshareCalldata = encodeAttestDkgReshareCalldata;
9971
10595
  exports.encodeBlockSelector = encodeBlockSelector;
9972
10596
  exports.encodeBridgeChallengeCalldata = encodeBridgeChallengeCalldata;
9973
10597
  exports.encodeBridgeClaimCalldata = encodeBridgeClaimCalldata;
10598
+ exports.encodeCancelClusterJoinCalldata = encodeCancelClusterJoinCalldata;
9974
10599
  exports.encodeCancelOrderCalldata = encodeCancelOrderCalldata;
9975
10600
  exports.encodeCancelPendingChangeCalldata = encodeCancelPendingChangeCalldata;
9976
10601
  exports.encodeClaimCalldata = encodeClaimCalldata;
@@ -9981,6 +10606,8 @@ exports.encodeCreateRequestCanonical = encodeCreateRequestCanonical;
9981
10606
  exports.encodeDelegateCalldata = encodeDelegateCalldata;
9982
10607
  exports.encodeDisableCalldata = encodeDisableCalldata;
9983
10608
  exports.encodeEnableCalldata = encodeEnableCalldata;
10609
+ exports.encodeExpireClusterJoinCalldata = encodeExpireClusterJoinCalldata;
10610
+ exports.encodeGetClusterJoinRequestCalldata = encodeGetClusterJoinRequestCalldata;
9984
10611
  exports.encodeHasPubkeyCalldata = encodeHasPubkeyCalldata;
9985
10612
  exports.encodeLockBridgeConfigCalldata = encodeLockBridgeConfigCalldata;
9986
10613
  exports.encodeLookupPubkeyCalldata = encodeLookupPubkeyCalldata;
@@ -10041,6 +10668,7 @@ exports.encodeRecoverOperatorNodeCalldata = encodeRecoverOperatorNodeCalldata;
10041
10668
  exports.encodeRedelegateCalldata = encodeRedelegateCalldata;
10042
10669
  exports.encodeRegisterPubkeyCalldata = encodeRegisterPubkeyCalldata;
10043
10670
  exports.encodeReportServiceProbeCalldata = encodeReportServiceProbeCalldata;
10671
+ exports.encodeRequestClusterJoinCalldata = encodeRequestClusterJoinCalldata;
10044
10672
  exports.encodeSetAutoCompoundCalldata = encodeSetAutoCompoundCalldata;
10045
10673
  exports.encodeSetBridgeResumeCooldownCalldata = encodeSetBridgeResumeCooldownCalldata;
10046
10674
  exports.encodeSetBridgeRouteFinalityCalldata = encodeSetBridgeRouteFinalityCalldata;
@@ -10052,6 +10680,7 @@ exports.encodeSetTickSizeCalldata = encodeSetTickSizeCalldata;
10052
10680
  exports.encodeSubmitBridgeProofCalldata = encodeSubmitBridgeProofCalldata;
10053
10681
  exports.encodeSubmitPendingChangeCalldata = encodeSubmitPendingChangeCalldata;
10054
10682
  exports.encodeUndelegateCalldata = encodeUndelegateCalldata;
10683
+ exports.encodeVoteClusterAdmitCalldata = encodeVoteClusterAdmitCalldata;
10055
10684
  exports.exportBridgeRouteCatalogueJson = exportBridgeRouteCatalogueJson;
10056
10685
  exports.fetchChainInfoLatest = fetchChainInfoLatest;
10057
10686
  exports.fetchChainRegistryLatest = fetchChainRegistryLatest;
@@ -10112,13 +10741,16 @@ exports.parseNameCategory = parseNameCategory;
10112
10741
  exports.parseNativeDecodedEvent = parseNativeDecodedEvent;
10113
10742
  exports.parseQuantity = parseQuantity;
10114
10743
  exports.parseQuantityBig = parseQuantityBig;
10744
+ exports.preflightClusterJoinRequest = preflightClusterJoinRequest;
10115
10745
  exports.proverMarketStateFromByte = proverMarketStateFromByte;
10116
10746
  exports.pubkeyRegistryAddressHex = pubkeyRegistryAddressHex;
10117
10747
  exports.quoteOperatorFee = quoteOperatorFee;
10118
10748
  exports.rankBridgeRoutes = rankBridgeRoutes;
10119
10749
  exports.rankMarketsByVolume = rankMarketsByVolume;
10750
+ exports.readClusterJoinRequest = readClusterJoinRequest;
10120
10751
  exports.requestSighash = requestSighash;
10121
10752
  exports.requireTypedAddress = requireTypedAddress;
10753
+ exports.resolveClusterJoinExecutionFee = resolveClusterJoinExecutionFee;
10122
10754
  exports.resolveExecutionFee = resolveExecutionFee;
10123
10755
  exports.resolveMaxExecutionUnitPrice = resolveMaxExecutionUnitPrice;
10124
10756
  exports.resolveRegistryExecutionFee = resolveRegistryExecutionFee;
@@ -10130,7 +10762,9 @@ exports.spendingPolicyAddressHex = spendingPolicyAddressHex;
10130
10762
  exports.submitMrvCallNativeTx = submitMrvCallNativeTx;
10131
10763
  exports.submitMrvDeployNativeTx = submitMrvDeployNativeTx;
10132
10764
  exports.submitMrvDeployPayloadNativeTx = submitMrvDeployPayloadNativeTx;
10765
+ exports.submitRequestClusterJoin = submitRequestClusterJoin;
10133
10766
  exports.submitSighash = submitSighash;
10767
+ exports.submitVoteClusterAdmit = submitVoteClusterAdmit;
10134
10768
  exports.transactionFeeExposure = transactionFeeExposure;
10135
10769
  exports.typedBech32ToAddress = typedBech32ToAddress;
10136
10770
  exports.validateAddress = validateAddress;