@ocash/sdk 0.1.4-rc.2 → 0.1.4-rc.4

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/node.cjs CHANGED
@@ -3421,7 +3421,7 @@ var MemoryStore = class {
3421
3421
  async getMerkleLeaf(chainId, cid) {
3422
3422
  const rows = this.merkleLeavesByChain.get(chainId);
3423
3423
  const row = rows?.[cid];
3424
- if (!row) return void 0;
3424
+ if (!row || row.cid !== cid) return void 0;
3425
3425
  return { chainId, cid: row.cid, commitment: row.commitment };
3426
3426
  }
3427
3427
  /**
@@ -4438,7 +4438,7 @@ var KeyValueStore = class {
4438
4438
  if (!this.merkleLeafCids[String(chainId)]?.has(cid)) return void 0;
4439
4439
  const raw = await this.options.client.get(this.sharedRecordKey("merkleLeaves", chainId, cid));
4440
4440
  const row = this.parseJson(raw, null);
4441
- if (!row) return void 0;
4441
+ if (!row || row.cid !== cid) return void 0;
4442
4442
  return { chainId, cid: row.cid, commitment: row.commitment };
4443
4443
  }
4444
4444
  async appendMerkleLeaves(chainId, leaves) {
@@ -5200,10 +5200,10 @@ var ProofEngine = class {
5200
5200
  merkle_root_index: parsed.merkle_root_index ?? context.merkle_root_index,
5201
5201
  relayer: parsed.relayer ?? context.relayer,
5202
5202
  recipient: parsed.recipient ?? context.recipient,
5203
- withdraw_amount: parsed.withdraw_amount ? BigInt(parsed.withdraw_amount) : context.withdraw_amount,
5203
+ withdraw_amount: parsed.withdraw_amount != null ? BigInt(parsed.withdraw_amount) : context.withdraw_amount,
5204
5204
  extra_data: parsed.extra_data ?? context.extra_data,
5205
- relayer_fee: parsed.relayer_fee ? BigInt(parsed.relayer_fee) : context.relayer_fee,
5206
- gas_drop_value: parsed.gas_drop_value ? BigInt(parsed.gas_drop_value) : context.gas_drop_value,
5205
+ relayer_fee: parsed.relayer_fee != null ? BigInt(parsed.relayer_fee) : context.relayer_fee,
5206
+ gas_drop_value: parsed.gas_drop_value != null ? BigInt(parsed.gas_drop_value) : context.gas_drop_value,
5207
5207
  array_hash_digest: parsed.array_hash_digest ?? context.array_hash_digest,
5208
5208
  gnark_output: parsed.gnark_output,
5209
5209
  witness_json: parsed.witness_json,
@@ -6326,11 +6326,32 @@ var SyncEngine = class {
6326
6326
  };
6327
6327
 
6328
6328
  // src/planner/planner.ts
6329
+ var import_viem8 = require("viem");
6330
+
6331
+ // src/utils/validators.ts
6329
6332
  var import_viem7 = require("viem");
6330
6333
  var requireHex = (value, name) => {
6331
6334
  if (isHexStrict(value, { minBytes: 1 })) return value;
6332
6335
  throw new SdkError("CONFIG", `${name} must be a hex string starting with 0x`);
6333
6336
  };
6337
+ var requireNumber = (value, name) => {
6338
+ if (typeof value === "number" && Number.isFinite(value)) return value;
6339
+ throw new SdkError("CONFIG", `${name} must be a finite number`);
6340
+ };
6341
+ var requireAddress = (value, name) => {
6342
+ if (typeof value !== "string") {
6343
+ throw new SdkError("CONFIG", `${name} must be a string address`);
6344
+ }
6345
+ return (0, import_viem7.getAddress)(value);
6346
+ };
6347
+ var requireBigint = (value, name) => {
6348
+ if (typeof value === "bigint") return value;
6349
+ if (typeof value === "string" && value.length) return BigInt(value);
6350
+ if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
6351
+ throw new SdkError("CONFIG", `${name} must be a bigint-compatible value`);
6352
+ };
6353
+
6354
+ // src/planner/planner.ts
6334
6355
  var parsePlanInput = (input) => {
6335
6356
  const action = input.action;
6336
6357
  if (action !== "transfer" && action !== "withdraw") {
@@ -6359,7 +6380,7 @@ var parsePlanInput = (input) => {
6359
6380
  if (gasDropValue != null && typeof gasDropValue !== "bigint") throw new SdkError("CONFIG", "gasDropValue must be bigint");
6360
6381
  return { action, chainId, assetId, amount, recipient, gasDropValue, payIncludesFee, relayerUrl: relayerUrl ?? void 0 };
6361
6382
  };
6362
- var tokenFeeKey = (token) => (0, import_viem7.toHex)(BigInt(token.id), { size: 32 }).toLowerCase();
6383
+ var tokenFeeKey = (token) => (0, import_viem8.toHex)(BigInt(token.id), { size: 32 }).toLowerCase();
6363
6384
  var selectTransferInputs = (utxos, required, maxInputs = 3) => {
6364
6385
  const sorted = [...utxos].sort((a, b) => b.amount > a.amount ? 1 : b.amount < a.amount ? -1 : 0);
6365
6386
  const selected = [];
@@ -6399,7 +6420,7 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
6399
6420
  total = records.reduce((acc, cur) => acc + cur, 0n);
6400
6421
  fee = BigInt(feeCount) * relayerFee.transfer;
6401
6422
  relayFee = fee;
6402
- if (import_viem7.maxUint256 === expectedOutput) {
6423
+ if (import_viem8.maxUint256 === expectedOutput) {
6403
6424
  cost = total;
6404
6425
  outputAmount = total - fee;
6405
6426
  if (outputAmount < 0n) {
@@ -6408,9 +6429,12 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
6408
6429
  }
6409
6430
  } else {
6410
6431
  cost = expectedIsWithFee ? expectedOutput : expectedOutput + fee;
6432
+ outputAmount = expectedIsWithFee ? expectedOutput - fee : expectedOutput;
6433
+ if (outputAmount < 0n) outputAmount = 0n;
6411
6434
  }
6412
6435
  if (total < cost) {
6413
6436
  cost = 0n;
6437
+ outputAmount = 0n;
6414
6438
  }
6415
6439
  break;
6416
6440
  }
@@ -6421,7 +6445,7 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
6421
6445
  const withdrawFeeDenominator = bpsBase + withdrawFeeBps;
6422
6446
  total = records.reduce((acc, cur) => acc + cur, 0n);
6423
6447
  fee = BigInt(feeCount - 1) * relayerFee.transfer;
6424
- if (import_viem7.maxUint256 === expectedOutput) {
6448
+ if (import_viem8.maxUint256 === expectedOutput) {
6425
6449
  const withdrawBase = (total - fee) * bpsBase / withdrawFeeDenominator;
6426
6450
  outputAmount = withdrawBase - relayFeePay;
6427
6451
  relayFee = fee + relayFeePay;
@@ -6492,7 +6516,7 @@ var estimateRecords = (input) => {
6492
6516
  const payRecords = [];
6493
6517
  let payInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...payRecords], input.expectedOutput, input.action, input.relayerFee, input.expectedIsWithFee);
6494
6518
  const maxRecords = [];
6495
- let maxInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem7.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6519
+ let maxInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem8.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6496
6520
  for (const record of sorted) {
6497
6521
  const isExceedPay = input.expectedIsWithFee ? payInfo.cost >= input.expectedOutput : payInfo.outputAmount >= input.expectedOutput;
6498
6522
  if (payInfo.cost === 0n || !isExceedPay) {
@@ -6500,7 +6524,7 @@ var estimateRecords = (input) => {
6500
6524
  payInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...payRecords], input.expectedOutput, input.action, input.relayerFee, input.expectedIsWithFee);
6501
6525
  }
6502
6526
  maxRecords.push(record);
6503
- const tempMax = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem7.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6527
+ const tempMax = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem8.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6504
6528
  if (maxInfo.cost === 0n || tempMax.outputAmount > maxInfo.outputAmount) {
6505
6529
  maxInfo = tempMax;
6506
6530
  }
@@ -6665,7 +6689,7 @@ var Planner = class {
6665
6689
  const records = utxos.map((u) => u.amount).filter((v) => v > 0n);
6666
6690
  const estimates = estimateRecords({
6667
6691
  records,
6668
- expectedOutput: import_viem7.maxUint256,
6692
+ expectedOutput: import_viem8.maxUint256,
6669
6693
  action: input.action,
6670
6694
  relayerFee: { transfer: transferFee, withdraw: relayerFee },
6671
6695
  withdrawFeeBps: token.withdrawFeeBps,
@@ -6896,27 +6920,6 @@ var Planner = class {
6896
6920
  };
6897
6921
 
6898
6922
  // src/tx/txBuilder.ts
6899
- var import_viem8 = require("viem");
6900
- var requireNumber = (value, name) => {
6901
- if (typeof value === "number" && Number.isFinite(value)) return value;
6902
- throw new SdkError("CONFIG", `Missing ${name}`);
6903
- };
6904
- var requireHex2 = (value, name) => {
6905
- if (isHexStrict(value, { minBytes: 1 })) return value;
6906
- throw new SdkError("CONFIG", `Missing ${name}`);
6907
- };
6908
- var requireAddress = (value, name) => {
6909
- if (typeof value !== "string") {
6910
- throw new SdkError("CONFIG", `Missing ${name}`);
6911
- }
6912
- return (0, import_viem8.getAddress)(value);
6913
- };
6914
- var requireBigint = (value, name) => {
6915
- if (typeof value === "bigint") return value;
6916
- if (typeof value === "string" && value.length) return BigInt(value);
6917
- if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
6918
- throw new SdkError("CONFIG", `Missing ${name}`);
6919
- };
6920
6923
  var TxBuilder = class {
6921
6924
  /**
6922
6925
  * Build relayer request for transfer proofs.
@@ -6930,7 +6933,7 @@ var TxBuilder = class {
6930
6933
  if (!Array.isArray(extraData) || extraData.length !== 3) {
6931
6934
  throw new SdkError("CONFIG", "Transfer requires extra_data as bytes[3]");
6932
6935
  }
6933
- extraData.forEach((entry, idx) => requireHex2(entry, `extra_data[${idx}]`));
6936
+ extraData.forEach((entry, idx) => requireHex(entry, `extra_data[${idx}]`));
6934
6937
  const request = {
6935
6938
  kind: "relayer",
6936
6939
  method: "POST",
@@ -6963,7 +6966,7 @@ var TxBuilder = class {
6963
6966
  if (Array.isArray(extraData)) {
6964
6967
  throw new SdkError("CONFIG", "Withdraw requires extra_data as bytes");
6965
6968
  }
6966
- const extraDataHex = requireHex2(extraData, "extra_data");
6969
+ const extraDataHex = requireHex(extraData, "extra_data");
6967
6970
  const request = {
6968
6971
  kind: "relayer",
6969
6972
  method: "POST",
@@ -7364,7 +7367,7 @@ var MerkleEngine = class _MerkleEngine {
7364
7367
  const isZero = BigInt(onChainNorm) === 0n;
7365
7368
  if (!isZero && onChainNorm !== result.rootHash) {
7366
7369
  const target = state.mergedElements;
7367
- await this.rollback(chainId, target);
7370
+ await this._rollback(chainId, target);
7368
7371
  throw new SdkError("MERKLE", "Local merkle root mismatch with on-chain root \u2014 rolled back", {
7369
7372
  chainId,
7370
7373
  rootIndex,
@@ -7397,21 +7400,31 @@ var MerkleEngine = class _MerkleEngine {
7397
7400
  }
7398
7401
  // ── Rollback (tree O(1) + sync cursor reset) ──
7399
7402
  /**
7400
- * Unified rollback: rewind tree to a previous batch boundary AND reset the
7401
- * sync cursor so memo sync restarts from the same point.
7403
+ * Public rollback: step back one batch (32 elements) from the current position.
7404
+ * Upper-layer code calls this on any error to reset and retry.
7402
7405
  *
7403
7406
  * What gets rolled back:
7404
7407
  * - ChairmanMerkle tree version pointer (O(1) — old nodes still in storage)
7405
7408
  * - Pending leaves buffer (cleared)
7406
7409
  * - Sync cursor: memo + merkle fields (nullifier left unchanged — independent)
7407
7410
  *
7411
+ * @returns true if rollback succeeded, false if already at 0 or target version doesn't exist.
7412
+ */
7413
+ async rollback(chainId) {
7414
+ const state = this.ensureChainState(chainId);
7415
+ const target = Math.max(0, state.mergedElements - SUBTREE_SIZE);
7416
+ return this._rollback(chainId, target);
7417
+ }
7418
+ /**
7419
+ * Internal rollback to an exact batch boundary.
7420
+ *
7408
7421
  * @param targetMergedElements Must be a non-negative multiple of 32.
7409
7422
  * Pass 0 to reset to the empty tree.
7410
7423
  * @returns true if rollback succeeded, false if the target version doesn't exist.
7411
7424
  */
7412
- async rollback(chainId, targetMergedElements) {
7425
+ async _rollback(chainId, targetMergedElements) {
7413
7426
  if (targetMergedElements < 0 || targetMergedElements % SUBTREE_SIZE !== 0) {
7414
- throw new SdkError("MERKLE", "rollback target must be a non-negative multiple of 32", { targetMergedElements });
7427
+ throw new SdkError("MERKLE", "_rollback target must be a non-negative multiple of 32", { targetMergedElements });
7415
7428
  }
7416
7429
  const state = this.ensureChainState(chainId);
7417
7430
  const pending = this.ensurePendingLeaves(chainId);
@@ -7462,44 +7475,64 @@ var MerkleEngine = class _MerkleEngine {
7462
7475
  await this.hydrateFromStorage(input.chainId);
7463
7476
  const canUseLocal = this.mode !== "remote";
7464
7477
  if (canUseLocal) {
7465
- const version = contractTreeElements > 0 ? await this.storage?.getChairmanMerkleVersion?.(input.chainId, contractTreeElements) : void 0;
7466
- const hasDb = typeof this.storage?.getMerkleLeaf === "function" && typeof this.storage?.getChairmanMerkleNode === "function" && (contractTreeElements === 0 || !!version);
7467
- if (hasDb) {
7478
+ const hasMerkleLeaf = typeof this.storage?.getMerkleLeaf === "function";
7479
+ const hasChairmanNode = typeof this.storage?.getChairmanMerkleNode === "function";
7480
+ if (hasMerkleLeaf && hasChairmanNode) {
7468
7481
  const state = this.ensureChainState(input.chainId);
7469
- if (contractTreeElements > 0 && state.mergedElements < contractTreeElements) {
7470
- if (this.mode === "local") {
7471
- throw new SdkError("MERKLE", "Local merkle db is behind contract", {
7472
- chainId: input.chainId,
7473
- cids,
7474
- localMergedElements: state.mergedElements,
7475
- contractTreeElements
7476
- });
7477
- }
7478
- } else {
7479
- try {
7480
- const proof = [];
7481
- for (const cid of cids) {
7482
- if (cid >= contractTreeElements) {
7483
- proof.push({ leaf_index: cid, path: new Array(this.treeDepth + 1).fill("0") });
7484
- continue;
7485
- }
7486
- const path2 = await this.buildLocalProofPath(input.chainId, cid, version);
7487
- proof.push({ leaf_index: cid, path: path2 });
7482
+ let version = contractTreeElements > 0 ? await this.storage?.getChairmanMerkleVersion?.(input.chainId, contractTreeElements) : void 0;
7483
+ let effectiveTreeElements = contractTreeElements;
7484
+ if (!version && contractTreeElements > 0 && state.mergedElements > 0) {
7485
+ const latest = await this.storage?.getLatestChairmanMerkleVersion?.(input.chainId);
7486
+ if (latest && latest.version > 0) {
7487
+ const allCovered = needsTreeProof.every((cid) => cid < latest.version);
7488
+ if (allCovered) {
7489
+ version = latest;
7490
+ effectiveTreeElements = latest.version;
7488
7491
  }
7489
- const effectiveRoot = contractTreeElements > 0 ? _MerkleEngine.normalizeHex32(version.rootHash, "version.rootHash") : getZeroHash(this.treeDepth);
7490
- return {
7491
- proof,
7492
- merkle_root: effectiveRoot,
7493
- latest_cid: totalElements > 0n ? Number(totalElements - 1n) : -1
7494
- };
7495
- } catch (error) {
7492
+ }
7493
+ }
7494
+ const hasDb = contractTreeElements === 0 || !!version;
7495
+ if (hasDb) {
7496
+ if (effectiveTreeElements > 0 && state.mergedElements < effectiveTreeElements) {
7496
7497
  if (this.mode === "local") {
7497
- throw new SdkError("MERKLE", "Local merkle proof build failed", { chainId: input.chainId, cids }, error);
7498
+ throw new SdkError("MERKLE", "Local merkle db is behind contract", {
7499
+ chainId: input.chainId,
7500
+ cids,
7501
+ localMergedElements: state.mergedElements,
7502
+ contractTreeElements: effectiveTreeElements
7503
+ });
7504
+ }
7505
+ } else {
7506
+ try {
7507
+ const proof = [];
7508
+ for (const cid of cids) {
7509
+ if (cid >= effectiveTreeElements) {
7510
+ proof.push({ leaf_index: cid, path: new Array(this.treeDepth + 1).fill("0") });
7511
+ continue;
7512
+ }
7513
+ const path2 = await this.buildLocalProofPath(input.chainId, cid, version);
7514
+ proof.push({ leaf_index: cid, path: path2 });
7515
+ }
7516
+ const effectiveRoot = effectiveTreeElements > 0 ? _MerkleEngine.normalizeHex32(version.rootHash, "version.rootHash") : getZeroHash(this.treeDepth);
7517
+ const effectiveLatestCid = effectiveTreeElements > 0 ? effectiveTreeElements - 1 : -1;
7518
+ return {
7519
+ proof,
7520
+ merkle_root: effectiveRoot,
7521
+ latest_cid: effectiveLatestCid
7522
+ };
7523
+ } catch (error) {
7524
+ if (this.mode === "local") {
7525
+ throw new SdkError("MERKLE", "Local merkle proof build failed", { chainId: input.chainId, cids }, error);
7526
+ }
7498
7527
  }
7499
7528
  }
7529
+ } else {
7530
+ if (this.mode === "local" && needsTreeProof.length) {
7531
+ throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter_or_version" });
7532
+ }
7500
7533
  }
7501
7534
  } else if (this.mode === "local" && needsTreeProof.length) {
7502
- throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter_or_version" });
7535
+ throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter" });
7503
7536
  }
7504
7537
  }
7505
7538
  if (needsTreeProof.length === 0) {
@@ -8778,6 +8811,9 @@ function hydrateWalletState(state) {
8778
8811
  }
8779
8812
 
8780
8813
  // src/store/fileStore.ts
8814
+ function isEnoent(err) {
8815
+ return !!err && typeof err === "object" && "code" in err && err.code === "ENOENT";
8816
+ }
8781
8817
  var FileStore = class {
8782
8818
  /**
8783
8819
  * Create a FileStore with a base directory and optional limits.
@@ -8840,26 +8876,28 @@ var FileStore = class {
8840
8876
  return import_node_path.default.join(this.options.baseDir, `shared.merkle.${chainId}.jsonl`);
8841
8877
  }
8842
8878
  async readMerkleFile(filePath) {
8879
+ let raw;
8843
8880
  try {
8844
- const raw = await (0, import_promises.readFile)(filePath, "utf8");
8845
- const out = [];
8846
- const lines = raw.split("\n").filter((l) => l.trim().length > 0);
8847
- for (const line of lines) {
8848
- try {
8849
- const row = JSON.parse(line);
8850
- const cid = Number(row?.cid);
8851
- const commitment2 = row?.commitment;
8852
- if (!Number.isFinite(cid) || cid < 0) continue;
8853
- if (typeof commitment2 !== "string" || !commitment2.startsWith("0x")) continue;
8854
- out.push({ cid: Math.floor(cid), commitment: commitment2 });
8855
- } catch {
8856
- }
8857
- }
8858
- out.sort((a, b) => a.cid - b.cid);
8859
- return out.length ? out : void 0;
8860
- } catch {
8881
+ raw = await (0, import_promises.readFile)(filePath, "utf8");
8882
+ } catch (err) {
8883
+ if (!isEnoent(err)) throw err;
8861
8884
  return void 0;
8862
8885
  }
8886
+ const out = [];
8887
+ const lines = raw.split("\n").filter((l) => l.trim().length > 0);
8888
+ for (const line of lines) {
8889
+ try {
8890
+ const row = JSON.parse(line);
8891
+ const cid = Number(row?.cid);
8892
+ const commitment2 = row?.commitment;
8893
+ if (!Number.isFinite(cid) || cid < 0) continue;
8894
+ if (typeof commitment2 !== "string" || !commitment2.startsWith("0x")) continue;
8895
+ out.push({ cid: Math.floor(cid), commitment: commitment2 });
8896
+ } catch {
8897
+ }
8898
+ }
8899
+ out.sort((a, b) => a.cid - b.cid);
8900
+ return out.length ? out : void 0;
8863
8901
  }
8864
8902
  /**
8865
8903
  * Infer the next merkle cid from the tail of the jsonl file.
@@ -8876,10 +8914,14 @@ var FileStore = class {
8876
8914
  }
8877
8915
  const last = JSON.parse(lines[lines.length - 1]);
8878
8916
  const cid = Number(last?.cid);
8879
- const next = Number.isFinite(cid) ? Math.max(0, Math.floor(cid) + 1) : 0;
8917
+ if (!Number.isFinite(cid)) {
8918
+ throw new Error(`corrupted merkle jsonl: missing or non-numeric cid in tail of ${this.merkleFilePath(chainId)}`);
8919
+ }
8920
+ const next = Math.max(0, Math.floor(cid) + 1);
8880
8921
  this.merkleNextCid.set(chainId, next);
8881
8922
  return next;
8882
- } catch {
8923
+ } catch (err) {
8924
+ if (!isEnoent(err)) throw err;
8883
8925
  this.merkleNextCid.set(chainId, 0);
8884
8926
  return 0;
8885
8927
  }
@@ -8906,7 +8948,8 @@ var FileStore = class {
8906
8948
  for (const [k, v] of hydrated.utxos.entries()) this.utxos.set(k, v);
8907
8949
  const operations = Array.isArray(parsed.operations) ? parsed.operations : [];
8908
8950
  this.operations = operations;
8909
- } catch {
8951
+ } catch (err) {
8952
+ if (!isEnoent(err)) throw err;
8910
8953
  }
8911
8954
  try {
8912
8955
  const raw = await (0, import_promises.readFile)(this.sharedFilePath(), "utf8");
@@ -8938,7 +8981,8 @@ var FileStore = class {
8938
8981
  if (entryNullifiersRaw && typeof entryNullifiersRaw === "object") {
8939
8982
  this.entryNullifiers = entryNullifiersRaw;
8940
8983
  }
8941
- } catch {
8984
+ } catch (err) {
8985
+ if (!isEnoent(err)) throw err;
8942
8986
  }
8943
8987
  const pruned = this.pruneOperations();
8944
8988
  if (pruned) void this.saveWallet().catch(() => void 0);
@@ -9209,7 +9253,7 @@ var FileStore = class {
9209
9253
  async getMerkleLeaf(chainId, cid) {
9210
9254
  const rows = await this.getMerkleLeaves(chainId);
9211
9255
  const row = rows?.[cid];
9212
- if (!row) return void 0;
9256
+ if (!row || row.cid !== cid) return void 0;
9213
9257
  return { chainId, cid: row.cid, commitment: row.commitment };
9214
9258
  }
9215
9259
  /**