@monolythium/core-sdk 0.4.1 → 0.4.3
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/crypto/index.cjs +139 -78
- package/dist/crypto/index.cjs.map +1 -1
- package/dist/crypto/index.d.cts +3 -252
- package/dist/crypto/index.d.ts +3 -252
- package/dist/crypto/index.js +139 -78
- package/dist/crypto/index.js.map +1 -1
- package/dist/index.cjs +849 -302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -7
- package/dist/index.d.ts +32 -7
- package/dist/index.js +838 -303
- package/dist/index.js.map +1 -1
- package/dist/{submission-CP-5JXh5.d.cts → submission-DFg1Hujc.d.cts} +301 -46
- package/dist/{submission-CP-5JXh5.d.ts → submission-DFg1Hujc.d.ts} +301 -46
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var blake3_js = require('@noble/hashes/blake3.js');
|
|
4
4
|
var sha3_js = require('@noble/hashes/sha3.js');
|
|
5
|
+
var mlKem_js = require('@noble/post-quantum/ml-kem.js');
|
|
6
|
+
var chacha_js = require('@noble/ciphers/chacha.js');
|
|
7
|
+
require('@noble/hashes/utils.js');
|
|
5
8
|
var mlDsa_js = require('@noble/post-quantum/ml-dsa.js');
|
|
6
9
|
var bls12381_js = require('@noble/curves/bls12-381.js');
|
|
7
10
|
var bip39 = require('@scure/bip39');
|
|
8
11
|
var english_js = require('@scure/bip39/wordlists/english.js');
|
|
9
|
-
require('@noble/post-quantum/ml-kem.js');
|
|
10
|
-
require('@noble/ciphers/chacha.js');
|
|
11
|
-
require('@noble/hashes/utils.js');
|
|
12
12
|
|
|
13
13
|
// src/error.ts
|
|
14
14
|
var SdkError = class _SdkError extends Error {
|
|
@@ -449,17 +449,26 @@ var NODE_REGISTRY_SELECTORS = {
|
|
|
449
449
|
/** `expireClusterJoin(uint32,bytes32)` — CJ-1 public reaper/refund. */
|
|
450
450
|
expireClusterJoin: "0x" + selectorHex("expireClusterJoin(uint32,bytes32)"),
|
|
451
451
|
/** `getClusterJoinRequest(uint32,bytes32)` — CJ-1 request status view. */
|
|
452
|
-
getClusterJoinRequest: "0x" + selectorHex("getClusterJoinRequest(uint32,bytes32)")
|
|
452
|
+
getClusterJoinRequest: "0x" + selectorHex("getClusterJoinRequest(uint32,bytes32)"),
|
|
453
|
+
/** `formCluster(bytes,bytes,bytes)` — no-foundation cluster formation by roster consent. */
|
|
454
|
+
formCluster: "0x" + selectorHex("formCluster(bytes,bytes,bytes)")
|
|
453
455
|
};
|
|
454
|
-
var
|
|
455
|
-
var
|
|
456
|
+
var NODE_REGISTRY_CLUSTER_MEMBER_REF_BYTES = 48;
|
|
457
|
+
var NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES = NODE_REGISTRY_CLUSTER_MEMBER_REF_BYTES;
|
|
458
|
+
var NODE_REGISTRY_BLS_PUBKEY_BYTES = NODE_REGISTRY_CLUSTER_MEMBER_REF_BYTES;
|
|
456
459
|
var NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES = 1952;
|
|
460
|
+
var NODE_REGISTRY_CONSENSUS_SIGNATURE_BYTES = 3309;
|
|
457
461
|
var NODE_REGISTRY_CONSENSUS_POP_BYTES = 3309;
|
|
458
462
|
var NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES = 96;
|
|
459
463
|
var NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES = NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES;
|
|
460
464
|
var NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS = 5;
|
|
461
465
|
var NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS = 7;
|
|
462
466
|
var NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID = (1n << 56n) - 1n;
|
|
467
|
+
var NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT = 7;
|
|
468
|
+
var NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT = 3;
|
|
469
|
+
var NODE_REGISTRY_FORM_CLUSTER_MEMBER_COUNT = NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT + NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT;
|
|
470
|
+
var NODE_REGISTRY_FORM_CLUSTER_THRESHOLD = 7;
|
|
471
|
+
var NODE_REGISTRY_FORM_CLUSTER_MESSAGE_DOMAIN = "PROTOCORE_NODE_REGISTRY_CLUSTER_FORM_V1\0";
|
|
463
472
|
var PENDING_CHANGE_KIND_CODES = {
|
|
464
473
|
add: 1,
|
|
465
474
|
remove: 2,
|
|
@@ -695,6 +704,70 @@ function encodeGetClusterJoinRequestCalldata(args) {
|
|
|
695
704
|
)
|
|
696
705
|
);
|
|
697
706
|
}
|
|
707
|
+
function formClusterMessage(activePubkeys, standbyPubkeys) {
|
|
708
|
+
const active = expectLength2(
|
|
709
|
+
toBytes(activePubkeys),
|
|
710
|
+
NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT * NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
|
|
711
|
+
"activePubkeys"
|
|
712
|
+
);
|
|
713
|
+
const standby = expectLength2(
|
|
714
|
+
toBytes(standbyPubkeys),
|
|
715
|
+
NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT * NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
|
|
716
|
+
"standbyPubkeys"
|
|
717
|
+
);
|
|
718
|
+
return blake3_js.blake3(
|
|
719
|
+
concatBytes(
|
|
720
|
+
new TextEncoder().encode(NODE_REGISTRY_FORM_CLUSTER_MESSAGE_DOMAIN),
|
|
721
|
+
u16BeBytes(NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT),
|
|
722
|
+
u16BeBytes(NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT),
|
|
723
|
+
u16BeBytes(NODE_REGISTRY_FORM_CLUSTER_THRESHOLD),
|
|
724
|
+
u32BeBytes(active.length),
|
|
725
|
+
active,
|
|
726
|
+
u32BeBytes(standby.length),
|
|
727
|
+
standby
|
|
728
|
+
)
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
function formClusterMessageHex(activePubkeys, standbyPubkeys) {
|
|
732
|
+
return bytesToHex(formClusterMessage(activePubkeys, standbyPubkeys));
|
|
733
|
+
}
|
|
734
|
+
function encodeFormClusterCalldata(args) {
|
|
735
|
+
const activePubkeys = expectLength2(
|
|
736
|
+
toBytes(args.activePubkeys),
|
|
737
|
+
NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT * NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
|
|
738
|
+
"activePubkeys"
|
|
739
|
+
);
|
|
740
|
+
const standbyPubkeys = expectLength2(
|
|
741
|
+
toBytes(args.standbyPubkeys),
|
|
742
|
+
NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT * NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES,
|
|
743
|
+
"standbyPubkeys"
|
|
744
|
+
);
|
|
745
|
+
const signatures = expectLength2(
|
|
746
|
+
toBytes(args.signatures),
|
|
747
|
+
NODE_REGISTRY_FORM_CLUSTER_MEMBER_COUNT * NODE_REGISTRY_CONSENSUS_SIGNATURE_BYTES,
|
|
748
|
+
"signatures"
|
|
749
|
+
);
|
|
750
|
+
const activePadded = padToWord(activePubkeys);
|
|
751
|
+
const standbyPadded = padToWord(standbyPubkeys);
|
|
752
|
+
const signaturesPadded = padToWord(signatures);
|
|
753
|
+
const activeOffset = 3n * 32n;
|
|
754
|
+
const standbyOffset = activeOffset + 32n + BigInt(activePadded.length);
|
|
755
|
+
const signaturesOffset = standbyOffset + 32n + BigInt(standbyPadded.length);
|
|
756
|
+
return bytesToHex(
|
|
757
|
+
concatBytes(
|
|
758
|
+
hexToBytes(NODE_REGISTRY_SELECTORS.formCluster),
|
|
759
|
+
uint64Word(activeOffset, "activePubkeysOffset"),
|
|
760
|
+
uint64Word(standbyOffset, "standbyPubkeysOffset"),
|
|
761
|
+
uint64Word(signaturesOffset, "signaturesOffset"),
|
|
762
|
+
uint64Word(BigInt(activePubkeys.length), "activePubkeysLength"),
|
|
763
|
+
activePadded,
|
|
764
|
+
uint64Word(BigInt(standbyPubkeys.length), "standbyPubkeysLength"),
|
|
765
|
+
standbyPadded,
|
|
766
|
+
uint64Word(BigInt(signatures.length), "signaturesLength"),
|
|
767
|
+
signaturesPadded
|
|
768
|
+
)
|
|
769
|
+
);
|
|
770
|
+
}
|
|
698
771
|
function decodeClusterJoinRequest(returnData) {
|
|
699
772
|
const bytes = expectLength2(toBytes(returnData), 8 * 32, "clusterJoinRequest");
|
|
700
773
|
const word = (i) => bytes.slice(i * 32, (i + 1) * 32);
|
|
@@ -798,7 +871,7 @@ function deriveClusterAnchorAddress(roster, threshold) {
|
|
|
798
871
|
throw new NodeRegistryError("threshold must be a uint16");
|
|
799
872
|
}
|
|
800
873
|
const members = roster.map(
|
|
801
|
-
(m, i) => expectLength2(toBytes(m),
|
|
874
|
+
(m, i) => expectLength2(toBytes(m), NODE_REGISTRY_CLUSTER_MEMBER_REF_BYTES, `roster[${i}]`)
|
|
802
875
|
);
|
|
803
876
|
members.sort(compareBytes);
|
|
804
877
|
const parts = [
|
|
@@ -863,6 +936,16 @@ function u64BeBytes(value) {
|
|
|
863
936
|
}
|
|
864
937
|
return out;
|
|
865
938
|
}
|
|
939
|
+
function u32BeBytes(value) {
|
|
940
|
+
const n = expectUint32(value, "uint32");
|
|
941
|
+
return Uint8Array.from([n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255]);
|
|
942
|
+
}
|
|
943
|
+
function u16BeBytes(value) {
|
|
944
|
+
if (!Number.isInteger(value) || value < 0 || value > 65535) {
|
|
945
|
+
throw new NodeRegistryError("uint16 value out of range");
|
|
946
|
+
}
|
|
947
|
+
return Uint8Array.from([value >>> 8 & 255, value & 255]);
|
|
948
|
+
}
|
|
866
949
|
function compareBytes(a, b) {
|
|
867
950
|
const len = Math.min(a.length, b.length);
|
|
868
951
|
for (let i = 0; i < len; i++) {
|
|
@@ -1059,59 +1142,6 @@ function parseBigint(value, label) {
|
|
|
1059
1142
|
return BigInt(value);
|
|
1060
1143
|
}
|
|
1061
1144
|
|
|
1062
|
-
// src/crypto/submission.ts
|
|
1063
|
-
async function fetchEncryptionKey(client) {
|
|
1064
|
-
const result = await client.call(
|
|
1065
|
-
"lyth_getEncryptionKey",
|
|
1066
|
-
[]
|
|
1067
|
-
);
|
|
1068
|
-
return {
|
|
1069
|
-
algo: result.algo ?? "ml-kem-768",
|
|
1070
|
-
epoch: typeof result.epoch === "string" ? BigInt(result.epoch) : BigInt(result.epoch),
|
|
1071
|
-
encapsulationKey: hexToBytes2(result.encapsulationKey, "encapsulationKey")
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
var ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE = "encrypted mempool submission unavailable until MB-3 threshold decryption is active";
|
|
1075
|
-
async function buildEncryptedSubmission(_args) {
|
|
1076
|
-
await Promise.resolve();
|
|
1077
|
-
throw new Error(ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE);
|
|
1078
|
-
}
|
|
1079
|
-
async function submitEncryptedEnvelope(client, envelopeWireHex) {
|
|
1080
|
-
return client.call("lyth_submitEncrypted", [envelopeWireHex]);
|
|
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
|
-
}
|
|
1114
|
-
|
|
1115
1145
|
// src/crypto/bincode.ts
|
|
1116
1146
|
var BincodeWriter = class {
|
|
1117
1147
|
#chunks = [];
|
|
@@ -1159,17 +1189,656 @@ var BincodeWriter = class {
|
|
|
1159
1189
|
this.#chunks.push(value >> 8 * i & 255);
|
|
1160
1190
|
}
|
|
1161
1191
|
}
|
|
1162
|
-
#big(value, bytes) {
|
|
1163
|
-
let v = typeof value === "bigint" ? value : BigInt(value);
|
|
1164
|
-
if (v < 0n || v >= 1n << BigInt(bytes * 8)) {
|
|
1165
|
-
throw new Error(`integer out of u${bytes * 8} range`);
|
|
1166
|
-
}
|
|
1167
|
-
for (let i = 0; i < bytes; i++) {
|
|
1168
|
-
this.#chunks.push(Number(v & 0xffn));
|
|
1169
|
-
v >>= 8n;
|
|
1170
|
-
}
|
|
1192
|
+
#big(value, bytes) {
|
|
1193
|
+
let v = typeof value === "bigint" ? value : BigInt(value);
|
|
1194
|
+
if (v < 0n || v >= 1n << BigInt(bytes * 8)) {
|
|
1195
|
+
throw new Error(`integer out of u${bytes * 8} range`);
|
|
1196
|
+
}
|
|
1197
|
+
for (let i = 0; i < bytes; i++) {
|
|
1198
|
+
this.#chunks.push(Number(v & 0xffn));
|
|
1199
|
+
v >>= 8n;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
// src/crypto/tx.ts
|
|
1205
|
+
function encodeTransactionForHash(fields, tag) {
|
|
1206
|
+
const n = normalizeTxFields(fields);
|
|
1207
|
+
return concatBytes2(
|
|
1208
|
+
Uint8Array.of(tag),
|
|
1209
|
+
bigintToBeBytes(n.chainId, 8, "chainId"),
|
|
1210
|
+
bigintToBeBytes(n.nonce, 8, "nonce"),
|
|
1211
|
+
bigintToBeBytes(n.maxPriorityFeePerGas, 32, "maxPriorityFeePerGas"),
|
|
1212
|
+
bigintToBeBytes(n.maxFeePerGas, 32, "maxFeePerGas"),
|
|
1213
|
+
bigintToBeBytes(n.gasLimit, 8, "gasLimit"),
|
|
1214
|
+
n.to === null ? Uint8Array.of(0) : concatBytes2(Uint8Array.of(1), n.to),
|
|
1215
|
+
bigintToBeBytes(n.value, 32, "value"),
|
|
1216
|
+
bigintToBeBytes(BigInt(n.input.length), 4, "input.length"),
|
|
1217
|
+
n.input,
|
|
1218
|
+
new Uint8Array(4),
|
|
1219
|
+
// access_list length
|
|
1220
|
+
encodeExtensionsForHash(n.extensions)
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
function bincodeSignedTransaction(fields, signature, publicKey) {
|
|
1224
|
+
const n = normalizeTxFields(fields);
|
|
1225
|
+
const sig = expectBytes(signature, ML_DSA_65_SIGNATURE_LEN, "ML-DSA-65 signature");
|
|
1226
|
+
const pk = expectBytes(publicKey, ML_DSA_65_PUBLIC_KEY_LEN, "ML-DSA-65 public key");
|
|
1227
|
+
const w = new BincodeWriter();
|
|
1228
|
+
w.u64(n.chainId);
|
|
1229
|
+
w.u64(n.nonce);
|
|
1230
|
+
w.bytes(uint256Be(n.maxPriorityFeePerGas, "maxPriorityFeePerGas"));
|
|
1231
|
+
w.bytes(uint256Be(n.maxFeePerGas, "maxFeePerGas"));
|
|
1232
|
+
w.u64(n.gasLimit);
|
|
1233
|
+
if (n.to === null) {
|
|
1234
|
+
w.u8(0);
|
|
1235
|
+
} else {
|
|
1236
|
+
w.u8(1);
|
|
1237
|
+
w.bytes(n.to);
|
|
1238
|
+
}
|
|
1239
|
+
w.bytes(uint256Be(n.value, "value"));
|
|
1240
|
+
w.bytes(n.input);
|
|
1241
|
+
w.u64(0n);
|
|
1242
|
+
w.u64(BigInt(n.extensions.length));
|
|
1243
|
+
for (const ext of n.extensions) bincodeTypedExtensionInto(w, ext);
|
|
1244
|
+
bincodeMlDsa65OpaqueInto(w, sig);
|
|
1245
|
+
bincodeMlDsa65OpaqueInto(w, pk);
|
|
1246
|
+
return w.toBytes();
|
|
1247
|
+
}
|
|
1248
|
+
function normalizeTxFields(fields) {
|
|
1249
|
+
return {
|
|
1250
|
+
chainId: parseBigint(fields.chainId, "chainId"),
|
|
1251
|
+
nonce: parseBigint(fields.nonce, "nonce"),
|
|
1252
|
+
maxPriorityFeePerGas: parseBigint(fields.maxPriorityFeePerGas, "maxPriorityFeePerGas"),
|
|
1253
|
+
maxFeePerGas: parseBigint(fields.maxFeePerGas, "maxFeePerGas"),
|
|
1254
|
+
gasLimit: parseBigint(fields.gasLimit, "gasLimit"),
|
|
1255
|
+
to: normalizeTo(fields.to),
|
|
1256
|
+
value: parseBigint(fields.value, "value"),
|
|
1257
|
+
input: normalizeBytes(fields.input ?? new Uint8Array(0), "input"),
|
|
1258
|
+
extensions: normalizeExtensions(fields.extensions)
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
function normalizeTo(value) {
|
|
1262
|
+
if (value === null) return null;
|
|
1263
|
+
const bytes = normalizeBytes(value, "to");
|
|
1264
|
+
return expectBytes(bytes, 20, "to");
|
|
1265
|
+
}
|
|
1266
|
+
function normalizeBytes(value, label) {
|
|
1267
|
+
if (typeof value === "string") return hexToBytes2(value, label);
|
|
1268
|
+
return value instanceof Uint8Array ? value : Uint8Array.from(value);
|
|
1269
|
+
}
|
|
1270
|
+
function normalizeExtensions(value) {
|
|
1271
|
+
if (value === void 0) return [];
|
|
1272
|
+
return value.map((ext, index) => {
|
|
1273
|
+
if (!Number.isInteger(ext.kind) || ext.kind < 0 || ext.kind > 255) {
|
|
1274
|
+
throw new Error(`extensions[${index}].kind out of u8 range`);
|
|
1275
|
+
}
|
|
1276
|
+
const body = normalizeBytes("bodyHex" in ext ? ext.bodyHex : ext.body, `extensions[${index}].body`);
|
|
1277
|
+
if (body.length > 4294967295) {
|
|
1278
|
+
throw new Error(`extensions[${index}].body exceeds u32 length`);
|
|
1279
|
+
}
|
|
1280
|
+
return { kind: ext.kind, body };
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
function encodeExtensionsForHash(extensions) {
|
|
1284
|
+
const chunks = [bigintToBeBytes(BigInt(extensions.length), 4, "extensions.length")];
|
|
1285
|
+
for (const ext of extensions) {
|
|
1286
|
+
chunks.push(
|
|
1287
|
+
Uint8Array.of(ext.kind),
|
|
1288
|
+
bigintToBeBytes(BigInt(ext.body.length), 4, "extension.body.length"),
|
|
1289
|
+
ext.body
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
return concatBytes2(...chunks);
|
|
1293
|
+
}
|
|
1294
|
+
function uint256Be(value, label) {
|
|
1295
|
+
if (value < 0n || value >= 1n << 256n) throw new Error(`${label} out of u256 range`);
|
|
1296
|
+
const out = new Uint8Array(32);
|
|
1297
|
+
let v = value;
|
|
1298
|
+
for (let i = 31; i >= 0; i--) {
|
|
1299
|
+
out[i] = Number(v & 0xffn);
|
|
1300
|
+
v >>= 8n;
|
|
1301
|
+
}
|
|
1302
|
+
return out;
|
|
1303
|
+
}
|
|
1304
|
+
function bincodeMlDsa65OpaqueInto(w, raw) {
|
|
1305
|
+
w.enumVariant(ENUM_VARIANT_INDEX_ML_DSA_65);
|
|
1306
|
+
w.u16(STANDARD_ALGO_NUMBER_ML_DSA_65);
|
|
1307
|
+
w.bytes(raw);
|
|
1308
|
+
}
|
|
1309
|
+
function bincodeTypedExtensionInto(w, ext) {
|
|
1310
|
+
w.u8(ext.kind);
|
|
1311
|
+
w.bytes(ext.body);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// src/crypto/ml-dsa.ts
|
|
1315
|
+
var ML_DSA_65_SEED_LEN = 32;
|
|
1316
|
+
var ML_DSA_65_SIGNING_KEY_LEN = 4032;
|
|
1317
|
+
var ML_DSA_65_PUBLIC_KEY_LEN = 1952;
|
|
1318
|
+
var ML_DSA_65_SIGNATURE_LEN = 3309;
|
|
1319
|
+
var STANDARD_ALGO_NUMBER_ML_DSA_65 = 1001;
|
|
1320
|
+
var ENUM_VARIANT_INDEX_ML_DSA_65 = 2;
|
|
1321
|
+
var ADDRESS_DERIVATION_DOMAIN = "MONO_ADDRESS_BLAKE3_20_V1";
|
|
1322
|
+
var ADDRESS_DERIVATION_DOMAIN_BYTES = new TextEncoder().encode(ADDRESS_DERIVATION_DOMAIN);
|
|
1323
|
+
var MlDsa65Backend = class _MlDsa65Backend {
|
|
1324
|
+
#secretKey;
|
|
1325
|
+
#publicKey;
|
|
1326
|
+
#addressBytes;
|
|
1327
|
+
constructor(secretKey, publicKey) {
|
|
1328
|
+
this.#secretKey = expectBytes(secretKey, ML_DSA_65_SIGNING_KEY_LEN, "ML-DSA-65 secret key").slice();
|
|
1329
|
+
this.#publicKey = expectBytes(publicKey, ML_DSA_65_PUBLIC_KEY_LEN, "ML-DSA-65 public key").slice();
|
|
1330
|
+
this.#addressBytes = mlDsa65AddressBytes(this.#publicKey);
|
|
1331
|
+
}
|
|
1332
|
+
static fromSeed(seed) {
|
|
1333
|
+
const kp = mlDsa_js.ml_dsa65.keygen(expectBytes(seed, ML_DSA_65_SEED_LEN, "ML-DSA-65 seed"));
|
|
1334
|
+
return new _MlDsa65Backend(kp.secretKey, kp.publicKey);
|
|
1335
|
+
}
|
|
1336
|
+
publicKey() {
|
|
1337
|
+
return this.#publicKey.slice();
|
|
1338
|
+
}
|
|
1339
|
+
addressBytes() {
|
|
1340
|
+
return this.#addressBytes.slice();
|
|
1341
|
+
}
|
|
1342
|
+
getAddress() {
|
|
1343
|
+
return bytesToHex2(this.#addressBytes);
|
|
1344
|
+
}
|
|
1345
|
+
sign(message) {
|
|
1346
|
+
return mlDsa_js.ml_dsa65.sign(message, this.#secretKey, { extraEntropy: false });
|
|
1347
|
+
}
|
|
1348
|
+
signPrehash(digest) {
|
|
1349
|
+
return this.sign(expectBytes(digest, 32, "prehash"));
|
|
1350
|
+
}
|
|
1351
|
+
verify(message, signature) {
|
|
1352
|
+
return mlDsa_js.ml_dsa65.verify(
|
|
1353
|
+
expectBytes(signature, ML_DSA_65_SIGNATURE_LEN, "ML-DSA-65 signature"),
|
|
1354
|
+
message,
|
|
1355
|
+
this.#publicKey
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
signEvmTx(fields) {
|
|
1359
|
+
const txHashPreimage = encodeTransactionForHash(fields, 1);
|
|
1360
|
+
const sighash = sha3_js.keccak_256(txHashPreimage);
|
|
1361
|
+
const signature = this.sign(sighash);
|
|
1362
|
+
const wireBytes = bincodeSignedTransaction(fields, signature, this.#publicKey);
|
|
1363
|
+
const txHash = sha3_js.keccak_256(
|
|
1364
|
+
concatBytes2(
|
|
1365
|
+
encodeTransactionForHash(fields, 2),
|
|
1366
|
+
signature,
|
|
1367
|
+
this.#publicKey
|
|
1368
|
+
)
|
|
1369
|
+
);
|
|
1370
|
+
return {
|
|
1371
|
+
wireHex: bytesToHex2(wireBytes).slice(2),
|
|
1372
|
+
wireBytes,
|
|
1373
|
+
sighash,
|
|
1374
|
+
txHash
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
function mlDsa65AddressFromPublicKey(publicKey) {
|
|
1379
|
+
return bytesToHex2(mlDsa65AddressBytes(publicKey));
|
|
1380
|
+
}
|
|
1381
|
+
function mlDsa65AddressBytes(publicKey) {
|
|
1382
|
+
const bytes = expectBytes(publicKey, ML_DSA_65_PUBLIC_KEY_LEN, "ML-DSA-65 public key");
|
|
1383
|
+
return blake3_js.blake3(concatBytes2(
|
|
1384
|
+
ADDRESS_DERIVATION_DOMAIN_BYTES,
|
|
1385
|
+
bigintToBeBytes(BigInt(STANDARD_ALGO_NUMBER_ML_DSA_65), 2, "ML-DSA-65 algo id"),
|
|
1386
|
+
bytes
|
|
1387
|
+
)).slice(0, 20);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
// src/crypto/envelope.ts
|
|
1391
|
+
new TextEncoder().encode("protocore/v2/mempool/dkg-mlkem768/1");
|
|
1392
|
+
var MempoolClass = {
|
|
1393
|
+
Transfer: 0,
|
|
1394
|
+
ContractCall: 1,
|
|
1395
|
+
CLOBOp: 3};
|
|
1396
|
+
function bincodeNonceAad(aad) {
|
|
1397
|
+
const w = new BincodeWriter();
|
|
1398
|
+
w.bytes(expectBytes(aad.sender, 20, "NonceAad.sender"));
|
|
1399
|
+
w.u64(aad.nonce);
|
|
1400
|
+
w.u64(aad.chainId);
|
|
1401
|
+
w.enumVariant(aad.class);
|
|
1402
|
+
w.u128(aad.maxFeePerGas);
|
|
1403
|
+
w.u128(aad.maxPriorityFeePerGas);
|
|
1404
|
+
w.u64(aad.gasLimit);
|
|
1405
|
+
return w.toBytes();
|
|
1406
|
+
}
|
|
1407
|
+
function bincodeDecryptHint(hint) {
|
|
1408
|
+
const w = new BincodeWriter();
|
|
1409
|
+
w.u64(hint.epoch);
|
|
1410
|
+
w.u16(hint.scheme);
|
|
1411
|
+
return w.toBytes();
|
|
1412
|
+
}
|
|
1413
|
+
function bincodeEncryptedEnvelope(env) {
|
|
1414
|
+
const w = new BincodeWriter();
|
|
1415
|
+
w.rawBytes(bincodeNonceAad(env.nonceAad));
|
|
1416
|
+
w.bytes(env.ciphertext);
|
|
1417
|
+
w.rawBytes(bincodeDecryptHint(env.decryptionHint));
|
|
1418
|
+
bincodeMlDsa65OpaqueInto2(w, expectBytes(env.senderPubkey, ML_DSA_65_PUBLIC_KEY_LEN, "senderPubkey"));
|
|
1419
|
+
bincodeMlDsa65OpaqueInto2(w, expectBytes(env.outerSignature, ML_DSA_65_SIGNATURE_LEN, "outerSignature"));
|
|
1420
|
+
w.bytes(expectBytes(env.sender, 20, "sender"));
|
|
1421
|
+
return w.toBytes();
|
|
1422
|
+
}
|
|
1423
|
+
function outerSigDigest(nonceAad, ciphertext, decryptionHint, senderPubkey) {
|
|
1424
|
+
const aad = bincodeNonceAad(nonceAad);
|
|
1425
|
+
const hint = bincodeDecryptHint(decryptionHint);
|
|
1426
|
+
return sha3_js.keccak_256(concatBytes2(aad, ciphertext, hint, expectBytes(senderPubkey, ML_DSA_65_PUBLIC_KEY_LEN, "senderPubkey")));
|
|
1427
|
+
}
|
|
1428
|
+
function bincodeMlDsa65OpaqueInto2(w, raw) {
|
|
1429
|
+
w.enumVariant(ENUM_VARIANT_INDEX_ML_DSA_65);
|
|
1430
|
+
w.u16(STANDARD_ALGO_NUMBER_ML_DSA_65);
|
|
1431
|
+
w.bytes(raw);
|
|
1432
|
+
}
|
|
1433
|
+
var SEAL_EK_LEN = 1184;
|
|
1434
|
+
var SEAL_KEY_LEN = 32;
|
|
1435
|
+
var SEAL_NONCE_LEN = 12;
|
|
1436
|
+
var SEAL_COMMIT_LEN = 32;
|
|
1437
|
+
var SEAL_SECRET_LEN = 32;
|
|
1438
|
+
var SEAL_SHARE_LEN = 1 + SEAL_SECRET_LEN;
|
|
1439
|
+
var CLUSTER_MLKEM_SHAMIR = 3;
|
|
1440
|
+
var COMMIT_DOMAIN = new TextEncoder().encode("lythiumseal/commit/v1");
|
|
1441
|
+
var KEK_DOMAIN = new TextEncoder().encode("lythiumseal/kek/v1");
|
|
1442
|
+
var NONCE_DOMAIN = new TextEncoder().encode("lythiumseal/nonce/v1");
|
|
1443
|
+
var BODY_AAD_DOMAIN = new TextEncoder().encode("lythiumseal/body/v1");
|
|
1444
|
+
var SHARE_AAD_DOMAIN = new TextEncoder().encode("lythiumseal/share/v1");
|
|
1445
|
+
var ROSTER_DOMAIN = new TextEncoder().encode("lythiumseal/roster/v1");
|
|
1446
|
+
function cryptoRandomSource() {
|
|
1447
|
+
return {
|
|
1448
|
+
fillBytes(dest) {
|
|
1449
|
+
crypto.getRandomValues(dest);
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
function u32le(n) {
|
|
1454
|
+
const out = new Uint8Array(4);
|
|
1455
|
+
out[0] = n & 255;
|
|
1456
|
+
out[1] = n >>> 8 & 255;
|
|
1457
|
+
out[2] = n >>> 16 & 255;
|
|
1458
|
+
out[3] = n >>> 24 & 255;
|
|
1459
|
+
return out;
|
|
1460
|
+
}
|
|
1461
|
+
function u64le(n) {
|
|
1462
|
+
const out = new Uint8Array(8);
|
|
1463
|
+
let v = n;
|
|
1464
|
+
for (let i = 0; i < 8; i++) {
|
|
1465
|
+
out[i] = Number(v & 0xffn);
|
|
1466
|
+
v >>= 8n;
|
|
1467
|
+
}
|
|
1468
|
+
return out;
|
|
1469
|
+
}
|
|
1470
|
+
function framed(field2) {
|
|
1471
|
+
return concatBytes2(u32le(field2.length), field2);
|
|
1472
|
+
}
|
|
1473
|
+
function keyCommitment(key) {
|
|
1474
|
+
return sha3_js.shake256(concatBytes2(framed(COMMIT_DOMAIN), key), { dkLen: SEAL_COMMIT_LEN });
|
|
1475
|
+
}
|
|
1476
|
+
function deriveKek(sharedSecret, domain, clusterId, epoch, opIndex) {
|
|
1477
|
+
const input = concatBytes2(
|
|
1478
|
+
framed(KEK_DOMAIN),
|
|
1479
|
+
framed(sharedSecret),
|
|
1480
|
+
framed(domain),
|
|
1481
|
+
u32le(clusterId),
|
|
1482
|
+
u64le(epoch),
|
|
1483
|
+
Uint8Array.of(opIndex)
|
|
1484
|
+
);
|
|
1485
|
+
return sha3_js.shake256(input, { dkLen: SEAL_KEY_LEN });
|
|
1486
|
+
}
|
|
1487
|
+
function deriveNonce(domain, context) {
|
|
1488
|
+
const input = concatBytes2(framed(NONCE_DOMAIN), framed(domain), framed(context));
|
|
1489
|
+
return sha3_js.shake256(input, { dkLen: SEAL_NONCE_LEN });
|
|
1490
|
+
}
|
|
1491
|
+
function bodyAad(ctx, k, n) {
|
|
1492
|
+
return concatBytes2(
|
|
1493
|
+
BODY_AAD_DOMAIN,
|
|
1494
|
+
u32le(ctx.clusterId),
|
|
1495
|
+
u64le(ctx.epoch),
|
|
1496
|
+
Uint8Array.of(k),
|
|
1497
|
+
Uint8Array.of(n),
|
|
1498
|
+
ctx.rosterHash
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
function shareAad(ctx, opIndex) {
|
|
1502
|
+
return concatBytes2(
|
|
1503
|
+
SHARE_AAD_DOMAIN,
|
|
1504
|
+
u32le(ctx.clusterId),
|
|
1505
|
+
u64le(ctx.epoch),
|
|
1506
|
+
Uint8Array.of(opIndex),
|
|
1507
|
+
ctx.rosterHash
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
function aeadSeal(key, nonce, plaintext, aad) {
|
|
1511
|
+
const cipher = chacha_js.chacha20poly1305(key, nonce, aad);
|
|
1512
|
+
const ct = cipher.encrypt(plaintext);
|
|
1513
|
+
return { nonce, ct, commitment: keyCommitment(key) };
|
|
1514
|
+
}
|
|
1515
|
+
function gfMul(a, b) {
|
|
1516
|
+
let product = 0;
|
|
1517
|
+
let x = a & 255;
|
|
1518
|
+
let y = b & 255;
|
|
1519
|
+
for (let i = 0; i < 8; i++) {
|
|
1520
|
+
const mask = -(y & 1) & 255;
|
|
1521
|
+
product ^= x & mask;
|
|
1522
|
+
const high = -(x >> 7 & 1) & 255;
|
|
1523
|
+
x = x << 1 & 255;
|
|
1524
|
+
x ^= 27 & high;
|
|
1525
|
+
y >>= 1;
|
|
1526
|
+
}
|
|
1527
|
+
return product & 255;
|
|
1528
|
+
}
|
|
1529
|
+
function polyEval(coeffs, x) {
|
|
1530
|
+
let acc = 0;
|
|
1531
|
+
for (let i = coeffs.length - 1; i >= 0; i--) {
|
|
1532
|
+
acc = gfMul(acc, x) ^ coeffs[i];
|
|
1533
|
+
}
|
|
1534
|
+
return acc & 255;
|
|
1535
|
+
}
|
|
1536
|
+
function shamirSplit(secret, t, n, rng) {
|
|
1537
|
+
const byteCoeffs = [];
|
|
1538
|
+
for (let j = 0; j < SEAL_SECRET_LEN; j++) {
|
|
1539
|
+
const c = new Uint8Array(t);
|
|
1540
|
+
c[0] = secret[j];
|
|
1541
|
+
if (t > 1) {
|
|
1542
|
+
const tail = new Uint8Array(t - 1);
|
|
1543
|
+
rng.fillBytes(tail);
|
|
1544
|
+
c.set(tail, 1);
|
|
1545
|
+
}
|
|
1546
|
+
byteCoeffs.push(c);
|
|
1547
|
+
}
|
|
1548
|
+
const shares = [];
|
|
1549
|
+
for (let k = 0; k < n; k++) {
|
|
1550
|
+
const x = k + 1 & 255;
|
|
1551
|
+
const value = new Uint8Array(SEAL_SECRET_LEN);
|
|
1552
|
+
for (let j = 0; j < SEAL_SECRET_LEN; j++) {
|
|
1553
|
+
value[j] = polyEval(byteCoeffs[j], x);
|
|
1554
|
+
}
|
|
1555
|
+
shares.push({ index: x, value });
|
|
1556
|
+
}
|
|
1557
|
+
return shares;
|
|
1558
|
+
}
|
|
1559
|
+
function shareToBytes(s) {
|
|
1560
|
+
const out = new Uint8Array(SEAL_SHARE_LEN);
|
|
1561
|
+
out[0] = s.index;
|
|
1562
|
+
out.set(s.value, 1);
|
|
1563
|
+
return out;
|
|
1564
|
+
}
|
|
1565
|
+
function sealRosterHash(keccak2562, clusterId, t, n, roster) {
|
|
1566
|
+
const chunks = [ROSTER_DOMAIN, u32le(clusterId), Uint8Array.of(t), Uint8Array.of(n)];
|
|
1567
|
+
for (const { operatorIndex, ek } of roster) {
|
|
1568
|
+
chunks.push(Uint8Array.of(operatorIndex), ek);
|
|
1569
|
+
}
|
|
1570
|
+
return keccak2562(concatBytes2(...chunks));
|
|
1571
|
+
}
|
|
1572
|
+
function encodeSealEnvelope(env) {
|
|
1573
|
+
const chunks = [];
|
|
1574
|
+
chunks.push(u32le(env.clusterId));
|
|
1575
|
+
chunks.push(u64le(env.epoch));
|
|
1576
|
+
chunks.push(expectBytes(env.rosterHash, 32, "rosterHash"));
|
|
1577
|
+
chunks.push(Uint8Array.of(env.t));
|
|
1578
|
+
chunks.push(Uint8Array.of(env.n));
|
|
1579
|
+
pushAeadBody(chunks, env.aeadBody);
|
|
1580
|
+
chunks.push(u64le(BigInt(env.recipients.length)));
|
|
1581
|
+
for (const r of env.recipients) {
|
|
1582
|
+
chunks.push(Uint8Array.of(r.operatorIndex));
|
|
1583
|
+
chunks.push(u64le(BigInt(r.kemCt.length)));
|
|
1584
|
+
chunks.push(r.kemCt);
|
|
1585
|
+
pushAeadBody(chunks, r.wrapped);
|
|
1586
|
+
}
|
|
1587
|
+
return concatBytes2(...chunks);
|
|
1588
|
+
}
|
|
1589
|
+
function pushAeadBody(chunks, body) {
|
|
1590
|
+
chunks.push(expectBytes(body.nonce, SEAL_NONCE_LEN, "aead nonce"));
|
|
1591
|
+
chunks.push(u64le(BigInt(body.ct.length)));
|
|
1592
|
+
chunks.push(body.ct);
|
|
1593
|
+
chunks.push(expectBytes(body.commitment, SEAL_COMMIT_LEN, "aead commitment"));
|
|
1594
|
+
}
|
|
1595
|
+
function sealToCluster(args) {
|
|
1596
|
+
const { plaintext, recipientEks, t, clusterId } = args;
|
|
1597
|
+
const epoch = args.epoch;
|
|
1598
|
+
const rosterHash = expectBytes(args.rosterHash, 32, "rosterHash");
|
|
1599
|
+
const rng = args.rng ?? cryptoRandomSource();
|
|
1600
|
+
const n = recipientEks.length;
|
|
1601
|
+
if (!Number.isInteger(t) || t < 1 || t > n || n < 1 || n > 255) {
|
|
1602
|
+
throw new Error(`invalid threshold/recipient count: t=${t} n=${n}`);
|
|
1603
|
+
}
|
|
1604
|
+
for (let i = 0; i < n; i++) {
|
|
1605
|
+
expectBytes(recipientEks[i], SEAL_EK_LEN, `recipientEks[${i}]`);
|
|
1606
|
+
}
|
|
1607
|
+
const ctx = { clusterId, epoch, rosterHash };
|
|
1608
|
+
const bodyKey = new Uint8Array(SEAL_KEY_LEN);
|
|
1609
|
+
rng.fillBytes(bodyKey);
|
|
1610
|
+
const aad = bodyAad(ctx, t, n);
|
|
1611
|
+
const bodyNonce = deriveNonce(new TextEncoder().encode("body"), aad);
|
|
1612
|
+
const aeadBody = aeadSeal(bodyKey, bodyNonce, plaintext, aad);
|
|
1613
|
+
const shares = shamirSplit(bodyKey, t, n, rng);
|
|
1614
|
+
const recipients = [];
|
|
1615
|
+
for (let i = 0; i < n; i++) {
|
|
1616
|
+
const opIndex = i + 1 & 255;
|
|
1617
|
+
const m = new Uint8Array(32);
|
|
1618
|
+
rng.fillBytes(m);
|
|
1619
|
+
const { cipherText: kemCt, sharedSecret } = mlKem_js.ml_kem768.encapsulate(recipientEks[i], m);
|
|
1620
|
+
const kek = deriveKek(sharedSecret, rosterHash, clusterId, epoch, opIndex);
|
|
1621
|
+
const sAad = shareAad(ctx, opIndex);
|
|
1622
|
+
const wrapNonce = deriveNonce(new TextEncoder().encode("share"), sAad);
|
|
1623
|
+
const wrapped = aeadSeal(kek, wrapNonce, shareToBytes(shares[i]), sAad);
|
|
1624
|
+
recipients.push({ operatorIndex: opIndex, kemCt, wrapped });
|
|
1625
|
+
sharedSecret.fill(0);
|
|
1626
|
+
kek.fill(0);
|
|
1627
|
+
}
|
|
1628
|
+
bodyKey.fill(0);
|
|
1629
|
+
return {
|
|
1630
|
+
clusterId,
|
|
1631
|
+
epoch,
|
|
1632
|
+
rosterHash,
|
|
1633
|
+
t,
|
|
1634
|
+
n,
|
|
1635
|
+
aeadBody,
|
|
1636
|
+
recipients
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
// src/crypto/seal.ts
|
|
1641
|
+
var CLUSTER_MLKEM_SHAMIR_ALGO = "cluster-mlkem768-shamir";
|
|
1642
|
+
function parseClusterSealKeys(source) {
|
|
1643
|
+
const n = source.roster.length;
|
|
1644
|
+
if (n === 0) {
|
|
1645
|
+
throw new Error("cluster seal roster is empty");
|
|
1646
|
+
}
|
|
1647
|
+
if (source.n !== n) {
|
|
1648
|
+
throw new Error(`cluster seal roster n=${source.n} disagrees with ${n} entries`);
|
|
1649
|
+
}
|
|
1650
|
+
if (!Number.isInteger(source.t) || source.t < 2 || source.t > n) {
|
|
1651
|
+
throw new Error(`cluster seal threshold t=${source.t} out of range 2..=${n}`);
|
|
1652
|
+
}
|
|
1653
|
+
const sorted = [...source.roster].sort((a, b) => a.operatorIndex - b.operatorIndex);
|
|
1654
|
+
const recipientEks = [];
|
|
1655
|
+
const hashInput = [];
|
|
1656
|
+
for (let i = 0; i < n; i++) {
|
|
1657
|
+
const entry = sorted[i];
|
|
1658
|
+
if (entry.operatorIndex !== i + 1) {
|
|
1659
|
+
throw new Error(
|
|
1660
|
+
`cluster seal roster operator indices must be 1..=${n}; got ${entry.operatorIndex} at slot ${i + 1}`
|
|
1661
|
+
);
|
|
1662
|
+
}
|
|
1663
|
+
const ek = expectBytes(hexToBytes2(entry.mlKemEk, `operator ${entry.operatorIndex} mlKemEk`), SEAL_EK_LEN, `operator ${entry.operatorIndex} ek`);
|
|
1664
|
+
recipientEks.push(ek);
|
|
1665
|
+
hashInput.push({ operatorIndex: entry.operatorIndex, ek });
|
|
1666
|
+
}
|
|
1667
|
+
const recomputed = sealRosterHash(keccak256, source.clusterId, source.t, n, hashInput);
|
|
1668
|
+
if (source.rosterHash !== void 0) {
|
|
1669
|
+
const supplied = expectBytes(hexToBytes2(source.rosterHash, "rosterHash"), 32, "rosterHash");
|
|
1670
|
+
if (!bytesEqual(supplied, recomputed)) {
|
|
1671
|
+
throw new Error(
|
|
1672
|
+
`cluster seal roster hash mismatch: source ${bytesToHex2(supplied)} != recomputed ${bytesToHex2(recomputed)} (the roster hash does not commit to this ek set)`
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
return {
|
|
1677
|
+
algo: source.algo ?? CLUSTER_MLKEM_SHAMIR_ALGO,
|
|
1678
|
+
clusterId: source.clusterId,
|
|
1679
|
+
epoch: toBigInt(source.epoch),
|
|
1680
|
+
rosterHash: recomputed,
|
|
1681
|
+
t: source.t,
|
|
1682
|
+
n,
|
|
1683
|
+
recipientEks
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
async function sealTransaction(args) {
|
|
1687
|
+
const keys = args.clusterSealKeys;
|
|
1688
|
+
const senderPubkey = expectBytes(args.senderPubkey, ML_DSA_65_PUBLIC_KEY_LEN, "senderPubkey");
|
|
1689
|
+
const senderAddress = expectBytes(args.senderAddress, 20, "senderAddress");
|
|
1690
|
+
const env = sealToCluster({
|
|
1691
|
+
plaintext: args.signedTxBincode,
|
|
1692
|
+
recipientEks: keys.recipientEks,
|
|
1693
|
+
t: keys.t,
|
|
1694
|
+
clusterId: keys.clusterId,
|
|
1695
|
+
epoch: keys.epoch,
|
|
1696
|
+
rosterHash: keys.rosterHash,
|
|
1697
|
+
rng: args.rng
|
|
1698
|
+
});
|
|
1699
|
+
const ciphertext = encodeSealEnvelope(env);
|
|
1700
|
+
const decryptionHint = { epoch: keys.epoch, scheme: CLUSTER_MLKEM_SHAMIR };
|
|
1701
|
+
const digest = outerSigDigest(args.aad, ciphertext, decryptionHint, senderPubkey);
|
|
1702
|
+
const outerSignature = expectBytes(
|
|
1703
|
+
await args.signOuterDigest(digest),
|
|
1704
|
+
ML_DSA_65_SIGNATURE_LEN,
|
|
1705
|
+
"outerSignature"
|
|
1706
|
+
);
|
|
1707
|
+
const envelope = {
|
|
1708
|
+
nonceAad: args.aad,
|
|
1709
|
+
ciphertext,
|
|
1710
|
+
decryptionHint,
|
|
1711
|
+
senderPubkey,
|
|
1712
|
+
outerSignature,
|
|
1713
|
+
sender: senderAddress
|
|
1714
|
+
};
|
|
1715
|
+
const envelopeWireBytes = bincodeEncryptedEnvelope(envelope);
|
|
1716
|
+
return {
|
|
1717
|
+
envelopeWireHex: `0x${bytesToHex2(envelopeWireBytes).slice(2)}`,
|
|
1718
|
+
envelopeWireBytes,
|
|
1719
|
+
ciphertextBytes: ciphertext.length
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
function keccak256(input) {
|
|
1723
|
+
return sha3_js.keccak_256(input);
|
|
1724
|
+
}
|
|
1725
|
+
function toBigInt(value) {
|
|
1726
|
+
if (typeof value === "bigint") return value;
|
|
1727
|
+
return BigInt(value);
|
|
1728
|
+
}
|
|
1729
|
+
function bytesEqual(a, b) {
|
|
1730
|
+
if (a.length !== b.length) return false;
|
|
1731
|
+
for (let i = 0; i < a.length; i++) {
|
|
1732
|
+
if (a[i] !== b[i]) return false;
|
|
1733
|
+
}
|
|
1734
|
+
return true;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// src/crypto/submission.ts
|
|
1738
|
+
async function fetchEncryptionKey(client) {
|
|
1739
|
+
const result = await client.call(
|
|
1740
|
+
"lyth_getEncryptionKey",
|
|
1741
|
+
[]
|
|
1742
|
+
);
|
|
1743
|
+
return {
|
|
1744
|
+
algo: result.algo ?? "ml-kem-768",
|
|
1745
|
+
epoch: typeof result.epoch === "string" ? BigInt(result.epoch) : BigInt(result.epoch),
|
|
1746
|
+
encapsulationKey: hexToBytes2(result.encapsulationKey, "encapsulationKey")
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
var ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE = "private submission requires cluster seal keys; pass clusterSealKeysSource or enable lyth_getClusterSealKeys";
|
|
1750
|
+
async function buildEncryptedSubmission(args) {
|
|
1751
|
+
const signed = args.backend.signEvmTx(args.tx);
|
|
1752
|
+
const clusterSealKeys = await resolveClusterSealKeys(args);
|
|
1753
|
+
const aad = nonceAadForTx(args.tx, args.backend.addressBytes(), args.class);
|
|
1754
|
+
const sealed = await sealTransaction({
|
|
1755
|
+
signedTxBincode: signed.wireBytes,
|
|
1756
|
+
clusterSealKeys,
|
|
1757
|
+
aad,
|
|
1758
|
+
senderAddress: args.backend.addressBytes(),
|
|
1759
|
+
senderPubkey: args.backend.publicKey(),
|
|
1760
|
+
signOuterDigest: (digest) => args.backend.signPrehash(digest)
|
|
1761
|
+
});
|
|
1762
|
+
return {
|
|
1763
|
+
envelopeWireHex: sealed.envelopeWireHex,
|
|
1764
|
+
innerSighashHex: bytesToHex2(signed.sighash),
|
|
1765
|
+
innerTxHashHex: bytesToHex2(signed.txHash),
|
|
1766
|
+
innerWireBytes: signed.wireBytes.length
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
async function submitEncryptedEnvelope(client, envelopeWireHex) {
|
|
1770
|
+
return client.call("lyth_submitEncrypted", [envelopeWireHex]);
|
|
1771
|
+
}
|
|
1772
|
+
function buildPlaintextSubmission(args) {
|
|
1773
|
+
const signed = args.backend.signEvmTx(args.tx);
|
|
1774
|
+
return {
|
|
1775
|
+
signedTxWireHex: `0x${signed.wireHex}`,
|
|
1776
|
+
innerTxHashHex: bytesToHex2(signed.txHash),
|
|
1777
|
+
innerSighashHex: bytesToHex2(signed.sighash),
|
|
1778
|
+
innerWireBytes: signed.wireBytes.length
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
async function submitPlaintextTransaction(client, signedTxWireHex, expectedTxHashHex) {
|
|
1782
|
+
const returned = await client.call("mesh_submitTx", [signedTxWireHex]);
|
|
1783
|
+
const returnedBytes = hexToBytes2(returned, "mesh_submitTx tx hash");
|
|
1784
|
+
if (returnedBytes.length !== 32) {
|
|
1785
|
+
throw new Error(
|
|
1786
|
+
`mesh_submitTx tx hash must be 32 bytes, got ${returnedBytes.length}`
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
const expectedBytes = hexToBytes2(expectedTxHashHex, "expected tx hash");
|
|
1790
|
+
if (!bytesEqual2(returnedBytes, expectedBytes)) {
|
|
1791
|
+
throw new Error(
|
|
1792
|
+
`mesh_submitTx returned tx hash ${bytesToHex2(returnedBytes)} but the locally computed canonical hash is ${bytesToHex2(expectedBytes)}`
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
return bytesToHex2(returnedBytes);
|
|
1796
|
+
}
|
|
1797
|
+
function bytesEqual2(a, b) {
|
|
1798
|
+
if (a.length !== b.length) return false;
|
|
1799
|
+
for (let i = 0; i < a.length; i++) {
|
|
1800
|
+
if (a[i] !== b[i]) return false;
|
|
1801
|
+
}
|
|
1802
|
+
return true;
|
|
1803
|
+
}
|
|
1804
|
+
async function resolveClusterSealKeys(args) {
|
|
1805
|
+
if (args.clusterSealKeys !== void 0) return args.clusterSealKeys;
|
|
1806
|
+
if (args.clusterSealKeysSource !== void 0) {
|
|
1807
|
+
return parseClusterSealKeys(args.clusterSealKeysSource);
|
|
1808
|
+
}
|
|
1809
|
+
if (args.client === void 0) {
|
|
1810
|
+
throw new Error(ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE);
|
|
1171
1811
|
}
|
|
1172
|
-
|
|
1812
|
+
const clusterId = args.clusterId ?? 0;
|
|
1813
|
+
const result = await args.client.call(
|
|
1814
|
+
"lyth_getClusterSealKeys",
|
|
1815
|
+
[clusterId]
|
|
1816
|
+
);
|
|
1817
|
+
return parseClusterSealKeys({ ...result, clusterId: result.clusterId ?? clusterId });
|
|
1818
|
+
}
|
|
1819
|
+
function nonceAadForTx(tx, sender, mempoolClass) {
|
|
1820
|
+
return {
|
|
1821
|
+
sender,
|
|
1822
|
+
nonce: parseBigint(tx.nonce, "nonce"),
|
|
1823
|
+
chainId: parseBigint(tx.chainId, "chainId"),
|
|
1824
|
+
class: mempoolClass ?? inferMempoolClass(tx),
|
|
1825
|
+
maxFeePerGas: parseBigint(tx.maxFeePerGas, "maxFeePerGas"),
|
|
1826
|
+
maxPriorityFeePerGas: parseBigint(tx.maxPriorityFeePerGas, "maxPriorityFeePerGas"),
|
|
1827
|
+
gasLimit: parseBigint(tx.gasLimit, "gasLimit")
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
function inferMempoolClass(tx) {
|
|
1831
|
+
if (tx.to === null || hasInput(tx.input)) return MempoolClass.ContractCall;
|
|
1832
|
+
return MempoolClass.Transfer;
|
|
1833
|
+
}
|
|
1834
|
+
function hasInput(input) {
|
|
1835
|
+
if (input === void 0) return false;
|
|
1836
|
+
if (typeof input === "string") {
|
|
1837
|
+
const stripped = input.startsWith("0x") || input.startsWith("0X") ? input.slice(2) : input;
|
|
1838
|
+
return stripped.length > 0;
|
|
1839
|
+
}
|
|
1840
|
+
return input.length > 0;
|
|
1841
|
+
}
|
|
1173
1842
|
|
|
1174
1843
|
// src/mrv.ts
|
|
1175
1844
|
var MRV_FORMAT_VERSION = 1;
|
|
@@ -1672,6 +2341,7 @@ async function submitMrvCallNativeTx(client, backend, contractAddress, input, op
|
|
|
1672
2341
|
}
|
|
1673
2342
|
async function submitMrvEncryptedNativeTxGated(client, backend, plan, options) {
|
|
1674
2343
|
const submission = await buildEncryptedSubmission({
|
|
2344
|
+
backend,
|
|
1675
2345
|
tx: plan.tx,
|
|
1676
2346
|
encryptionKey: options.encryptionKey ?? await fetchEncryptionKey(client),
|
|
1677
2347
|
class: options.class
|
|
@@ -2029,192 +2699,6 @@ function isIdentifier(value) {
|
|
|
2029
2699
|
return /^[a-z][a-z0-9_]*$/.test(value);
|
|
2030
2700
|
}
|
|
2031
2701
|
|
|
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;
|
|
2145
|
-
var ML_DSA_65_PUBLIC_KEY_LEN = 1952;
|
|
2146
|
-
var ML_DSA_65_SIGNATURE_LEN = 3309;
|
|
2147
|
-
var STANDARD_ALGO_NUMBER_ML_DSA_65 = 1001;
|
|
2148
|
-
var ENUM_VARIANT_INDEX_ML_DSA_65 = 5;
|
|
2149
|
-
var ADDRESS_DERIVATION_DOMAIN = "MONO_ADDRESS_BLAKE3_20_V1";
|
|
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
|
-
};
|
|
2206
|
-
function mlDsa65AddressFromPublicKey(publicKey) {
|
|
2207
|
-
return bytesToHex2(mlDsa65AddressBytes(publicKey));
|
|
2208
|
-
}
|
|
2209
|
-
function mlDsa65AddressBytes(publicKey) {
|
|
2210
|
-
const bytes = expectBytes(publicKey, ML_DSA_65_PUBLIC_KEY_LEN, "ML-DSA-65 public key");
|
|
2211
|
-
return blake3_js.blake3(concatBytes2(
|
|
2212
|
-
ADDRESS_DERIVATION_DOMAIN_BYTES,
|
|
2213
|
-
bigintToBeBytes(BigInt(STANDARD_ALGO_NUMBER_ML_DSA_65), 2, "ML-DSA-65 algo id"),
|
|
2214
|
-
bytes
|
|
2215
|
-
)).slice(0, 20);
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2218
2702
|
// src/registry.ts
|
|
2219
2703
|
var BLS_PUBLIC_KEY_BYTE_LENGTH = 48;
|
|
2220
2704
|
var TESTNET_69420 = {
|
|
@@ -2222,8 +2706,8 @@ var TESTNET_69420 = {
|
|
|
2222
2706
|
network: "testnet-69420",
|
|
2223
2707
|
display_name: "Monolythium Testnet",
|
|
2224
2708
|
description: "Public Monolythium testnet. Testnet state may reset without notice; do not store value on this network.",
|
|
2225
|
-
genesis_hash: "
|
|
2226
|
-
binary_sha: "
|
|
2709
|
+
genesis_hash: "0x6a2bb3c8a6701bedcddc0447583bb24f34b77310e3aa77c62ca303a453e9f7ba",
|
|
2710
|
+
binary_sha: "c283c75d",
|
|
2227
2711
|
rpc: [
|
|
2228
2712
|
{
|
|
2229
2713
|
url: "http://178.105.12.9:8545",
|
|
@@ -6781,7 +7265,7 @@ function verifyBoundedReceiptProof(proof) {
|
|
|
6781
7265
|
}
|
|
6782
7266
|
const actualRoot = computeNoEvmReceiptsRoot(receipts);
|
|
6783
7267
|
const expectedRoot = decodeHash(proof.receiptsRoot, "receiptsRoot");
|
|
6784
|
-
if (!
|
|
7268
|
+
if (!bytesEqual3(expectedRoot, decodeHash(actualRoot, "computedReceiptsRoot"))) {
|
|
6785
7269
|
throw new NoEvmReceiptProofError(
|
|
6786
7270
|
"receipts_root_mismatch",
|
|
6787
7271
|
`receiptsRoot mismatch: expected ${proof.receiptsRoot}, computed ${actualRoot}`
|
|
@@ -6789,7 +7273,7 @@ function verifyBoundedReceiptProof(proof) {
|
|
|
6789
7273
|
}
|
|
6790
7274
|
const actualTargetHash = computeNoEvmTargetReceiptHash(targetReceipt);
|
|
6791
7275
|
const expectedTargetHash = decodeHash(proof.targetReceiptHash, "targetReceiptHash");
|
|
6792
|
-
if (!
|
|
7276
|
+
if (!bytesEqual3(expectedTargetHash, decodeHash(actualTargetHash, "computedTargetReceiptHash"))) {
|
|
6793
7277
|
throw new NoEvmReceiptProofError(
|
|
6794
7278
|
"target_receipt_hash_mismatch",
|
|
6795
7279
|
`targetReceiptHash mismatch: expected ${proof.targetReceiptHash}, computed ${actualTargetHash}`
|
|
@@ -6846,7 +7330,7 @@ function verifyCompactReceiptProof(proof) {
|
|
|
6846
7330
|
const targetReceipt = decodeHexBytes(targetReceiptBytes, "targetReceiptBytes");
|
|
6847
7331
|
const actualTargetHash = computeNoEvmTargetReceiptHash(targetReceipt);
|
|
6848
7332
|
const expectedTargetHash = decodeHash(proof.targetReceiptHash, "targetReceiptHash");
|
|
6849
|
-
if (!
|
|
7333
|
+
if (!bytesEqual3(expectedTargetHash, decodeHash(actualTargetHash, "computedTargetReceiptHash"))) {
|
|
6850
7334
|
throw new NoEvmReceiptProofError(
|
|
6851
7335
|
"target_receipt_hash_mismatch",
|
|
6852
7336
|
`targetReceiptHash mismatch: expected ${proof.targetReceiptHash}, computed ${actualTargetHash}`
|
|
@@ -6857,7 +7341,7 @@ function verifyCompactReceiptProof(proof) {
|
|
|
6857
7341
|
compactProof.leafHash,
|
|
6858
7342
|
"compactInclusionProof.leafHash"
|
|
6859
7343
|
);
|
|
6860
|
-
if (!
|
|
7344
|
+
if (!bytesEqual3(expectedLeafHashBytes, actualLeafHashBytes)) {
|
|
6861
7345
|
throw new NoEvmReceiptProofError(
|
|
6862
7346
|
"compact_leaf_hash_mismatch",
|
|
6863
7347
|
`compactInclusionProof.leafHash mismatch: expected ${compactProof.leafHash}, computed ${bytesToHex6(
|
|
@@ -6867,7 +7351,7 @@ function verifyCompactReceiptProof(proof) {
|
|
|
6867
7351
|
}
|
|
6868
7352
|
const compactRootBytes = decodeHash(compactProof.root, "compactInclusionProof.root");
|
|
6869
7353
|
const receiptsRootBytes = decodeHash(proof.receiptsRoot, "receiptsRoot");
|
|
6870
|
-
if (!
|
|
7354
|
+
if (!bytesEqual3(receiptsRootBytes, compactRootBytes)) {
|
|
6871
7355
|
throw new NoEvmReceiptProofError(
|
|
6872
7356
|
"compact_root_mismatch",
|
|
6873
7357
|
`receiptsRoot must equal compactInclusionProof.root: receiptsRoot ${proof.receiptsRoot}, compact root ${compactProof.root}`
|
|
@@ -6890,7 +7374,7 @@ function verifyCompactReceiptProof(proof) {
|
|
|
6890
7374
|
siblingHashes,
|
|
6891
7375
|
pathSides
|
|
6892
7376
|
);
|
|
6893
|
-
if (!
|
|
7377
|
+
if (!bytesEqual3(actualRootBytes, compactRootBytes)) {
|
|
6894
7378
|
throw new NoEvmReceiptProofError(
|
|
6895
7379
|
"compact_path_mismatch",
|
|
6896
7380
|
`compact inclusion path mismatch: expected ${compactProof.root}, computed ${bytesToHex6(
|
|
@@ -7044,7 +7528,7 @@ function validateCoveringSnapshotObject(snapshot, archiveContentHash, proofBlock
|
|
|
7044
7528
|
"archiveProof.coveringSnapshot.checkpointTo must match blockHeight"
|
|
7045
7529
|
);
|
|
7046
7530
|
}
|
|
7047
|
-
if (!
|
|
7531
|
+
if (!bytesEqual3(checkpointContentHash, archiveContentHash)) {
|
|
7048
7532
|
throw new NoEvmReceiptProofError(
|
|
7049
7533
|
"invalid_proof_shape",
|
|
7050
7534
|
"archiveProof.coveringSnapshot.checkpointContentHash must match archiveProof.contentHash"
|
|
@@ -7243,7 +7727,7 @@ function validateFinalityBlockReference(blockReference, round, proofBlockHash) {
|
|
|
7243
7727
|
);
|
|
7244
7728
|
if (proofBlockHash !== void 0) {
|
|
7245
7729
|
const blockHash = decodeHash(proofBlockHash, "blockHash");
|
|
7246
|
-
if (!
|
|
7730
|
+
if (!bytesEqual3(digest, blockHash)) {
|
|
7247
7731
|
throw new NoEvmReceiptProofError(
|
|
7248
7732
|
"invalid_proof_shape",
|
|
7249
7733
|
"finalityEvidence.blockReference.digest must match blockHash"
|
|
@@ -7593,7 +8077,7 @@ function assertHashBytes(value, field2) {
|
|
|
7593
8077
|
function isRecord3(value) {
|
|
7594
8078
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7595
8079
|
}
|
|
7596
|
-
function
|
|
8080
|
+
function bytesEqual3(a, b) {
|
|
7597
8081
|
if (a.length !== b.length) return false;
|
|
7598
8082
|
let diff = 0;
|
|
7599
8083
|
for (let index = 0; index < a.length; index++) {
|
|
@@ -7875,25 +8359,50 @@ function clusterJoinRequestExists(view) {
|
|
|
7875
8359
|
return view.status !== "none" || view.owner.toLowerCase() !== ZERO_ADDRESS || view.bondLythoshi !== 0n;
|
|
7876
8360
|
}
|
|
7877
8361
|
async function readClusterJoinRequest(client, args) {
|
|
7878
|
-
const
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
{
|
|
7884
|
-
to: nodeRegistryAddressHex(),
|
|
7885
|
-
data
|
|
7886
|
-
},
|
|
7887
|
-
"latest"
|
|
8362
|
+
const clusterId = parseUint32(args.clusterId, "clusterId");
|
|
8363
|
+
const operatorId = normalizeOperatorId(args.operatorId);
|
|
8364
|
+
const envelope = await client.call("lyth_getClusterJoinRequest", [
|
|
8365
|
+
Number(clusterId),
|
|
8366
|
+
operatorId
|
|
7888
8367
|
]);
|
|
7889
|
-
return
|
|
8368
|
+
return adaptNativeClusterJoinRequest(envelope.request);
|
|
7890
8369
|
}
|
|
7891
8370
|
async function preflightClusterJoinRequest(client, args) {
|
|
7892
8371
|
try {
|
|
7893
8372
|
return await readClusterJoinRequest(client, args);
|
|
7894
8373
|
} catch (cause) {
|
|
7895
8374
|
throw new Error(
|
|
7896
|
-
`CJ-1
|
|
8375
|
+
`CJ-1 lyth_getClusterJoinRequest is not exposed or failed on the connected chain: ${errorMessage(cause)}`
|
|
8376
|
+
);
|
|
8377
|
+
}
|
|
8378
|
+
}
|
|
8379
|
+
async function previewRequestClusterJoin(client, args) {
|
|
8380
|
+
const clusterId = parseUint32(args.clusterId, "clusterId");
|
|
8381
|
+
try {
|
|
8382
|
+
return await client.call("lyth_previewRequestClusterJoin", [{
|
|
8383
|
+
from: args.from,
|
|
8384
|
+
clusterId: Number(clusterId),
|
|
8385
|
+
operatorPubkey: bytesToHex2(normalizeConsensusPubkey(args.operatorPubkey, "operatorPubkey")),
|
|
8386
|
+
bondLythoshi: parseU256(args.bondLythoshi, "bondLythoshi").toString(10)
|
|
8387
|
+
}]);
|
|
8388
|
+
} catch (cause) {
|
|
8389
|
+
throw new Error(
|
|
8390
|
+
`CJ-1 request preview is not exposed or failed on the connected chain: ${errorMessage(cause)}`
|
|
8391
|
+
);
|
|
8392
|
+
}
|
|
8393
|
+
}
|
|
8394
|
+
async function previewVoteClusterAdmit(client, args) {
|
|
8395
|
+
const clusterId = parseUint32(args.clusterId, "clusterId");
|
|
8396
|
+
try {
|
|
8397
|
+
return await client.call("lyth_previewVoteClusterAdmit", [{
|
|
8398
|
+
from: args.from,
|
|
8399
|
+
clusterId: Number(clusterId),
|
|
8400
|
+
operatorId: normalizeOperatorId(args.operatorId),
|
|
8401
|
+
voterPubkey: bytesToHex2(normalizeConsensusPubkey(args.voterPubkey, "voterPubkey"))
|
|
8402
|
+
}]);
|
|
8403
|
+
} catch (cause) {
|
|
8404
|
+
throw new Error(
|
|
8405
|
+
`CJ-1 admit-vote preview is not exposed or failed on the connected chain: ${errorMessage(cause)}`
|
|
7897
8406
|
);
|
|
7898
8407
|
}
|
|
7899
8408
|
}
|
|
@@ -7952,18 +8461,15 @@ async function submitRequestClusterJoin(args) {
|
|
|
7952
8461
|
const clusterId = parseUint32(args.clusterId, "clusterId");
|
|
7953
8462
|
const operatorPubkey = normalizeConsensusPubkey(args.operatorPubkey, "operatorPubkey");
|
|
7954
8463
|
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
8464
|
const backend = pqm1MnemonicToMlDsa65Backend(args.mnemonic);
|
|
7966
8465
|
const senderAddress = addressToTypedBech32("user", backend.addressBytes());
|
|
8466
|
+
const preview = await previewRequestClusterJoin(args.client, {
|
|
8467
|
+
from: senderAddress,
|
|
8468
|
+
clusterId,
|
|
8469
|
+
operatorPubkey,
|
|
8470
|
+
bondLythoshi: args.bondLythoshi
|
|
8471
|
+
});
|
|
8472
|
+
assertPreviewOk("requestClusterJoin", preview);
|
|
7967
8473
|
const [chainId, nonce, quote] = await Promise.all([
|
|
7968
8474
|
args.client.ethChainId(),
|
|
7969
8475
|
args.client.lythGetTransactionCount(senderAddress),
|
|
@@ -7982,15 +8488,15 @@ async function submitRequestClusterJoin(args) {
|
|
|
7982
8488
|
async function submitVoteClusterAdmit(args) {
|
|
7983
8489
|
const clusterId = parseUint32(args.clusterId, "clusterId");
|
|
7984
8490
|
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
8491
|
const backend = pqm1MnemonicToMlDsa65Backend(args.mnemonic);
|
|
7993
8492
|
const senderAddress = addressToTypedBech32("user", backend.addressBytes());
|
|
8493
|
+
const preview = await previewVoteClusterAdmit(args.client, {
|
|
8494
|
+
from: senderAddress,
|
|
8495
|
+
clusterId,
|
|
8496
|
+
operatorId: operatorIdHex,
|
|
8497
|
+
voterPubkey: args.voterPubkey
|
|
8498
|
+
});
|
|
8499
|
+
assertPreviewOk("voteClusterAdmit", preview);
|
|
7994
8500
|
const [chainId, nonce, quote] = await Promise.all([
|
|
7995
8501
|
args.client.ethChainId(),
|
|
7996
8502
|
args.client.lythGetTransactionCount(senderAddress),
|
|
@@ -8021,6 +8527,40 @@ async function submitClusterJoinTx(client, backend, tx, clusterId, operatorIdHex
|
|
|
8021
8527
|
signedTxWireBytes: plaintext.innerWireBytes
|
|
8022
8528
|
};
|
|
8023
8529
|
}
|
|
8530
|
+
function adaptNativeClusterJoinRequest(request) {
|
|
8531
|
+
return {
|
|
8532
|
+
owner: request.owner ?? ZERO_ADDRESS,
|
|
8533
|
+
requestEpoch: parseBigint(request.requestEpoch, "requestEpoch"),
|
|
8534
|
+
requestNonce: request.requestNonce === void 0 ? void 0 : parseBigint(request.requestNonce, "requestNonce"),
|
|
8535
|
+
snapshotThreshold: request.snapshotThreshold,
|
|
8536
|
+
snapshotN: request.snapshotN,
|
|
8537
|
+
voteCount: request.voteCount,
|
|
8538
|
+
statusCode: request.statusCode,
|
|
8539
|
+
status: clusterJoinStatus(request.status),
|
|
8540
|
+
bondLythoshi: parseBigint(request.bondLythoshi, "bondLythoshi"),
|
|
8541
|
+
sealRosterPending: request.sealRosterPending
|
|
8542
|
+
};
|
|
8543
|
+
}
|
|
8544
|
+
function clusterJoinStatus(status) {
|
|
8545
|
+
switch (status) {
|
|
8546
|
+
case "none":
|
|
8547
|
+
case "open":
|
|
8548
|
+
case "admitted":
|
|
8549
|
+
case "cancelled":
|
|
8550
|
+
case "expired":
|
|
8551
|
+
return status;
|
|
8552
|
+
default:
|
|
8553
|
+
return "unknown";
|
|
8554
|
+
}
|
|
8555
|
+
}
|
|
8556
|
+
function previewError(action, preview) {
|
|
8557
|
+
const reason = preview.reason ? `: ${preview.reason}` : "";
|
|
8558
|
+
const message = preview.message ? ` (${preview.message})` : "";
|
|
8559
|
+
return new Error(`${action} preview rejected${reason}${message}`);
|
|
8560
|
+
}
|
|
8561
|
+
function assertPreviewOk(action, preview) {
|
|
8562
|
+
if (!preview.ok) throw previewError(action, preview);
|
|
8563
|
+
}
|
|
8024
8564
|
function normalizeConsensusPubkey(value, label) {
|
|
8025
8565
|
const bytes = typeof value === "string" ? hexToBytes2(value, label) : value;
|
|
8026
8566
|
return expectBytes(bytes, NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES, label).slice();
|
|
@@ -9014,11 +9554,6 @@ function wordToBigint(word) {
|
|
|
9014
9554
|
}
|
|
9015
9555
|
return out;
|
|
9016
9556
|
}
|
|
9017
|
-
new TextEncoder().encode("protocore/v2/mempool/dkg-mlkem768/1");
|
|
9018
|
-
var MempoolClass = {
|
|
9019
|
-
CLOBOp: 3};
|
|
9020
|
-
|
|
9021
|
-
// src/market-actions.ts
|
|
9022
9557
|
var CLOB_MARKET_ID_DOMAIN_TAG = 193;
|
|
9023
9558
|
var NATIVE_MARKET_MODULE_ADDRESS_BYTES = "0x4d41524b45545f4e41544956455f4d4f445f5631";
|
|
9024
9559
|
var NATIVE_MARKET_MODULE_ADDRESS = addressToTypedBech32(
|
|
@@ -10349,7 +10884,7 @@ var MONOLYTHIUM_NETWORKS = {
|
|
|
10349
10884
|
};
|
|
10350
10885
|
|
|
10351
10886
|
// src/index.ts
|
|
10352
|
-
var version = "0.4.
|
|
10887
|
+
var version = "0.4.3";
|
|
10353
10888
|
|
|
10354
10889
|
exports.ADDRESS_HRP = ADDRESS_HRP;
|
|
10355
10890
|
exports.ADDRESS_KIND_HRPS = ADDRESS_KIND_HRPS;
|
|
@@ -10424,12 +10959,19 @@ exports.NATIVE_MARKET_ORDER_BOOK_STREAM_TOPIC = NATIVE_MARKET_ORDER_BOOK_STREAM_
|
|
|
10424
10959
|
exports.NODE_REGISTRY_BLS_PUBKEY_BYTES = NODE_REGISTRY_BLS_PUBKEY_BYTES;
|
|
10425
10960
|
exports.NODE_REGISTRY_CAPABILITIES = NODE_REGISTRY_CAPABILITIES;
|
|
10426
10961
|
exports.NODE_REGISTRY_CAPABILITY_MASK = NODE_REGISTRY_CAPABILITY_MASK;
|
|
10962
|
+
exports.NODE_REGISTRY_CLUSTER_MEMBER_REF_BYTES = NODE_REGISTRY_CLUSTER_MEMBER_REF_BYTES;
|
|
10427
10963
|
exports.NODE_REGISTRY_CONSENSUS_POP_BYTES = NODE_REGISTRY_CONSENSUS_POP_BYTES;
|
|
10428
10964
|
exports.NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES = NODE_REGISTRY_CONSENSUS_PUBKEY_BYTES;
|
|
10965
|
+
exports.NODE_REGISTRY_CONSENSUS_SIGNATURE_BYTES = NODE_REGISTRY_CONSENSUS_SIGNATURE_BYTES;
|
|
10429
10966
|
exports.NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES = NODE_REGISTRY_DKG_ATTESTATION_SIG_BYTES;
|
|
10430
10967
|
exports.NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS = NODE_REGISTRY_DKG_RESHARE_MAX_SIGNERS;
|
|
10431
10968
|
exports.NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS = NODE_REGISTRY_DKG_RESHARE_MIN_SIGNERS;
|
|
10432
10969
|
exports.NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES = NODE_REGISTRY_DKG_THRESHOLD_SIG_BYTES;
|
|
10970
|
+
exports.NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT = NODE_REGISTRY_FORM_CLUSTER_ACTIVE_COUNT;
|
|
10971
|
+
exports.NODE_REGISTRY_FORM_CLUSTER_MEMBER_COUNT = NODE_REGISTRY_FORM_CLUSTER_MEMBER_COUNT;
|
|
10972
|
+
exports.NODE_REGISTRY_FORM_CLUSTER_MESSAGE_DOMAIN = NODE_REGISTRY_FORM_CLUSTER_MESSAGE_DOMAIN;
|
|
10973
|
+
exports.NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT = NODE_REGISTRY_FORM_CLUSTER_STANDBY_COUNT;
|
|
10974
|
+
exports.NODE_REGISTRY_FORM_CLUSTER_THRESHOLD = NODE_REGISTRY_FORM_CLUSTER_THRESHOLD;
|
|
10433
10975
|
exports.NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES = NODE_REGISTRY_LEGACY_CLUSTER_MEMBER_PUBKEY_BYTES;
|
|
10434
10976
|
exports.NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID = NODE_REGISTRY_PENDING_CHANGE_MAX_INTENT_ID;
|
|
10435
10977
|
exports.NODE_REGISTRY_PUBLIC_SERVICE_MASK = NODE_REGISTRY_PUBLIC_SERVICE_MASK;
|
|
@@ -10607,6 +11149,7 @@ exports.encodeDelegateCalldata = encodeDelegateCalldata;
|
|
|
10607
11149
|
exports.encodeDisableCalldata = encodeDisableCalldata;
|
|
10608
11150
|
exports.encodeEnableCalldata = encodeEnableCalldata;
|
|
10609
11151
|
exports.encodeExpireClusterJoinCalldata = encodeExpireClusterJoinCalldata;
|
|
11152
|
+
exports.encodeFormClusterCalldata = encodeFormClusterCalldata;
|
|
10610
11153
|
exports.encodeGetClusterJoinRequestCalldata = encodeGetClusterJoinRequestCalldata;
|
|
10611
11154
|
exports.encodeHasPubkeyCalldata = encodeHasPubkeyCalldata;
|
|
10612
11155
|
exports.encodeLockBridgeConfigCalldata = encodeLockBridgeConfigCalldata;
|
|
@@ -10684,6 +11227,8 @@ exports.encodeVoteClusterAdmitCalldata = encodeVoteClusterAdmitCalldata;
|
|
|
10684
11227
|
exports.exportBridgeRouteCatalogueJson = exportBridgeRouteCatalogueJson;
|
|
10685
11228
|
exports.fetchChainInfoLatest = fetchChainInfoLatest;
|
|
10686
11229
|
exports.fetchChainRegistryLatest = fetchChainRegistryLatest;
|
|
11230
|
+
exports.formClusterMessage = formClusterMessage;
|
|
11231
|
+
exports.formClusterMessageHex = formClusterMessageHex;
|
|
10687
11232
|
exports.formatLyth = formatLyth;
|
|
10688
11233
|
exports.formatLythoshi = formatLythoshi;
|
|
10689
11234
|
exports.formatNativeReceiptFeeDisplay = formatNativeReceiptFeeDisplay;
|
|
@@ -10742,6 +11287,8 @@ exports.parseNativeDecodedEvent = parseNativeDecodedEvent;
|
|
|
10742
11287
|
exports.parseQuantity = parseQuantity;
|
|
10743
11288
|
exports.parseQuantityBig = parseQuantityBig;
|
|
10744
11289
|
exports.preflightClusterJoinRequest = preflightClusterJoinRequest;
|
|
11290
|
+
exports.previewRequestClusterJoin = previewRequestClusterJoin;
|
|
11291
|
+
exports.previewVoteClusterAdmit = previewVoteClusterAdmit;
|
|
10745
11292
|
exports.proverMarketStateFromByte = proverMarketStateFromByte;
|
|
10746
11293
|
exports.pubkeyRegistryAddressHex = pubkeyRegistryAddressHex;
|
|
10747
11294
|
exports.quoteOperatorFee = quoteOperatorFee;
|