@ocash/sdk 0.1.4-rc.3 → 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/index.cjs CHANGED
@@ -3419,7 +3419,7 @@ var MemoryStore = class {
3419
3419
  async getMerkleLeaf(chainId, cid) {
3420
3420
  const rows = this.merkleLeavesByChain.get(chainId);
3421
3421
  const row = rows?.[cid];
3422
- if (!row) return void 0;
3422
+ if (!row || row.cid !== cid) return void 0;
3423
3423
  return { chainId, cid: row.cid, commitment: row.commitment };
3424
3424
  }
3425
3425
  /**
@@ -4436,7 +4436,7 @@ var KeyValueStore = class {
4436
4436
  if (!this.merkleLeafCids[String(chainId)]?.has(cid)) return void 0;
4437
4437
  const raw = await this.options.client.get(this.sharedRecordKey("merkleLeaves", chainId, cid));
4438
4438
  const row = this.parseJson(raw, null);
4439
- if (!row) return void 0;
4439
+ if (!row || row.cid !== cid) return void 0;
4440
4440
  return { chainId, cid: row.cid, commitment: row.commitment };
4441
4441
  }
4442
4442
  async appendMerkleLeaves(chainId, leaves) {
@@ -5198,10 +5198,10 @@ var ProofEngine = class {
5198
5198
  merkle_root_index: parsed.merkle_root_index ?? context.merkle_root_index,
5199
5199
  relayer: parsed.relayer ?? context.relayer,
5200
5200
  recipient: parsed.recipient ?? context.recipient,
5201
- withdraw_amount: parsed.withdraw_amount ? BigInt(parsed.withdraw_amount) : context.withdraw_amount,
5201
+ withdraw_amount: parsed.withdraw_amount != null ? BigInt(parsed.withdraw_amount) : context.withdraw_amount,
5202
5202
  extra_data: parsed.extra_data ?? context.extra_data,
5203
- relayer_fee: parsed.relayer_fee ? BigInt(parsed.relayer_fee) : context.relayer_fee,
5204
- gas_drop_value: parsed.gas_drop_value ? BigInt(parsed.gas_drop_value) : context.gas_drop_value,
5203
+ relayer_fee: parsed.relayer_fee != null ? BigInt(parsed.relayer_fee) : context.relayer_fee,
5204
+ gas_drop_value: parsed.gas_drop_value != null ? BigInt(parsed.gas_drop_value) : context.gas_drop_value,
5205
5205
  array_hash_digest: parsed.array_hash_digest ?? context.array_hash_digest,
5206
5206
  gnark_output: parsed.gnark_output,
5207
5207
  witness_json: parsed.witness_json,
@@ -6324,11 +6324,32 @@ var SyncEngine = class {
6324
6324
  };
6325
6325
 
6326
6326
  // src/planner/planner.ts
6327
+ var import_viem8 = require("viem");
6328
+
6329
+ // src/utils/validators.ts
6327
6330
  var import_viem7 = require("viem");
6328
6331
  var requireHex = (value, name) => {
6329
6332
  if (isHexStrict(value, { minBytes: 1 })) return value;
6330
6333
  throw new SdkError("CONFIG", `${name} must be a hex string starting with 0x`);
6331
6334
  };
6335
+ var requireNumber = (value, name) => {
6336
+ if (typeof value === "number" && Number.isFinite(value)) return value;
6337
+ throw new SdkError("CONFIG", `${name} must be a finite number`);
6338
+ };
6339
+ var requireAddress = (value, name) => {
6340
+ if (typeof value !== "string") {
6341
+ throw new SdkError("CONFIG", `${name} must be a string address`);
6342
+ }
6343
+ return (0, import_viem7.getAddress)(value);
6344
+ };
6345
+ var requireBigint = (value, name) => {
6346
+ if (typeof value === "bigint") return value;
6347
+ if (typeof value === "string" && value.length) return BigInt(value);
6348
+ if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
6349
+ throw new SdkError("CONFIG", `${name} must be a bigint-compatible value`);
6350
+ };
6351
+
6352
+ // src/planner/planner.ts
6332
6353
  var parsePlanInput = (input) => {
6333
6354
  const action = input.action;
6334
6355
  if (action !== "transfer" && action !== "withdraw") {
@@ -6357,7 +6378,7 @@ var parsePlanInput = (input) => {
6357
6378
  if (gasDropValue != null && typeof gasDropValue !== "bigint") throw new SdkError("CONFIG", "gasDropValue must be bigint");
6358
6379
  return { action, chainId, assetId, amount, recipient, gasDropValue, payIncludesFee, relayerUrl: relayerUrl ?? void 0 };
6359
6380
  };
6360
- var tokenFeeKey = (token) => (0, import_viem7.toHex)(BigInt(token.id), { size: 32 }).toLowerCase();
6381
+ var tokenFeeKey = (token) => (0, import_viem8.toHex)(BigInt(token.id), { size: 32 }).toLowerCase();
6361
6382
  var selectTransferInputs = (utxos, required, maxInputs = 3) => {
6362
6383
  const sorted = [...utxos].sort((a, b) => b.amount > a.amount ? 1 : b.amount < a.amount ? -1 : 0);
6363
6384
  const selected = [];
@@ -6397,7 +6418,7 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
6397
6418
  total = records.reduce((acc, cur) => acc + cur, 0n);
6398
6419
  fee = BigInt(feeCount) * relayerFee.transfer;
6399
6420
  relayFee = fee;
6400
- if (import_viem7.maxUint256 === expectedOutput) {
6421
+ if (import_viem8.maxUint256 === expectedOutput) {
6401
6422
  cost = total;
6402
6423
  outputAmount = total - fee;
6403
6424
  if (outputAmount < 0n) {
@@ -6406,9 +6427,12 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
6406
6427
  }
6407
6428
  } else {
6408
6429
  cost = expectedIsWithFee ? expectedOutput : expectedOutput + fee;
6430
+ outputAmount = expectedIsWithFee ? expectedOutput - fee : expectedOutput;
6431
+ if (outputAmount < 0n) outputAmount = 0n;
6409
6432
  }
6410
6433
  if (total < cost) {
6411
6434
  cost = 0n;
6435
+ outputAmount = 0n;
6412
6436
  }
6413
6437
  break;
6414
6438
  }
@@ -6419,7 +6443,7 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
6419
6443
  const withdrawFeeDenominator = bpsBase + withdrawFeeBps;
6420
6444
  total = records.reduce((acc, cur) => acc + cur, 0n);
6421
6445
  fee = BigInt(feeCount - 1) * relayerFee.transfer;
6422
- if (import_viem7.maxUint256 === expectedOutput) {
6446
+ if (import_viem8.maxUint256 === expectedOutput) {
6423
6447
  const withdrawBase = (total - fee) * bpsBase / withdrawFeeDenominator;
6424
6448
  outputAmount = withdrawBase - relayFeePay;
6425
6449
  relayFee = fee + relayFeePay;
@@ -6490,7 +6514,7 @@ var estimateRecords = (input) => {
6490
6514
  const payRecords = [];
6491
6515
  let payInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...payRecords], input.expectedOutput, input.action, input.relayerFee, input.expectedIsWithFee);
6492
6516
  const maxRecords = [];
6493
- let maxInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem7.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6517
+ let maxInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem8.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6494
6518
  for (const record of sorted) {
6495
6519
  const isExceedPay = input.expectedIsWithFee ? payInfo.cost >= input.expectedOutput : payInfo.outputAmount >= input.expectedOutput;
6496
6520
  if (payInfo.cost === 0n || !isExceedPay) {
@@ -6498,7 +6522,7 @@ var estimateRecords = (input) => {
6498
6522
  payInfo = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...payRecords], input.expectedOutput, input.action, input.relayerFee, input.expectedIsWithFee);
6499
6523
  }
6500
6524
  maxRecords.push(record);
6501
- const tempMax = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem7.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6525
+ const tempMax = recordsFee({ withdrawFeeBps: input.withdrawFeeBps }, [...maxRecords], import_viem8.maxUint256, input.action, input.relayerFee, input.expectedIsWithFee);
6502
6526
  if (maxInfo.cost === 0n || tempMax.outputAmount > maxInfo.outputAmount) {
6503
6527
  maxInfo = tempMax;
6504
6528
  }
@@ -6663,7 +6687,7 @@ var Planner = class {
6663
6687
  const records = utxos.map((u) => u.amount).filter((v) => v > 0n);
6664
6688
  const estimates = estimateRecords({
6665
6689
  records,
6666
- expectedOutput: import_viem7.maxUint256,
6690
+ expectedOutput: import_viem8.maxUint256,
6667
6691
  action: input.action,
6668
6692
  relayerFee: { transfer: transferFee, withdraw: relayerFee },
6669
6693
  withdrawFeeBps: token.withdrawFeeBps,
@@ -6894,27 +6918,6 @@ var Planner = class {
6894
6918
  };
6895
6919
 
6896
6920
  // src/tx/txBuilder.ts
6897
- var import_viem8 = require("viem");
6898
- var requireNumber = (value, name) => {
6899
- if (typeof value === "number" && Number.isFinite(value)) return value;
6900
- throw new SdkError("CONFIG", `Missing ${name}`);
6901
- };
6902
- var requireHex2 = (value, name) => {
6903
- if (isHexStrict(value, { minBytes: 1 })) return value;
6904
- throw new SdkError("CONFIG", `Missing ${name}`);
6905
- };
6906
- var requireAddress = (value, name) => {
6907
- if (typeof value !== "string") {
6908
- throw new SdkError("CONFIG", `Missing ${name}`);
6909
- }
6910
- return (0, import_viem8.getAddress)(value);
6911
- };
6912
- var requireBigint = (value, name) => {
6913
- if (typeof value === "bigint") return value;
6914
- if (typeof value === "string" && value.length) return BigInt(value);
6915
- if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
6916
- throw new SdkError("CONFIG", `Missing ${name}`);
6917
- };
6918
6921
  var TxBuilder = class {
6919
6922
  /**
6920
6923
  * Build relayer request for transfer proofs.
@@ -6928,7 +6931,7 @@ var TxBuilder = class {
6928
6931
  if (!Array.isArray(extraData) || extraData.length !== 3) {
6929
6932
  throw new SdkError("CONFIG", "Transfer requires extra_data as bytes[3]");
6930
6933
  }
6931
- extraData.forEach((entry, idx) => requireHex2(entry, `extra_data[${idx}]`));
6934
+ extraData.forEach((entry, idx) => requireHex(entry, `extra_data[${idx}]`));
6932
6935
  const request = {
6933
6936
  kind: "relayer",
6934
6937
  method: "POST",
@@ -6961,7 +6964,7 @@ var TxBuilder = class {
6961
6964
  if (Array.isArray(extraData)) {
6962
6965
  throw new SdkError("CONFIG", "Withdraw requires extra_data as bytes");
6963
6966
  }
6964
- const extraDataHex = requireHex2(extraData, "extra_data");
6967
+ const extraDataHex = requireHex(extraData, "extra_data");
6965
6968
  const request = {
6966
6969
  kind: "relayer",
6967
6970
  method: "POST",
@@ -7470,44 +7473,64 @@ var MerkleEngine = class _MerkleEngine {
7470
7473
  await this.hydrateFromStorage(input.chainId);
7471
7474
  const canUseLocal = this.mode !== "remote";
7472
7475
  if (canUseLocal) {
7473
- const version = contractTreeElements > 0 ? await this.storage?.getChairmanMerkleVersion?.(input.chainId, contractTreeElements) : void 0;
7474
- const hasDb = typeof this.storage?.getMerkleLeaf === "function" && typeof this.storage?.getChairmanMerkleNode === "function" && (contractTreeElements === 0 || !!version);
7475
- if (hasDb) {
7476
+ const hasMerkleLeaf = typeof this.storage?.getMerkleLeaf === "function";
7477
+ const hasChairmanNode = typeof this.storage?.getChairmanMerkleNode === "function";
7478
+ if (hasMerkleLeaf && hasChairmanNode) {
7476
7479
  const state = this.ensureChainState(input.chainId);
7477
- if (contractTreeElements > 0 && state.mergedElements < contractTreeElements) {
7478
- if (this.mode === "local") {
7479
- throw new SdkError("MERKLE", "Local merkle db is behind contract", {
7480
- chainId: input.chainId,
7481
- cids,
7482
- localMergedElements: state.mergedElements,
7483
- contractTreeElements
7484
- });
7485
- }
7486
- } else {
7487
- try {
7488
- const proof = [];
7489
- for (const cid of cids) {
7490
- if (cid >= contractTreeElements) {
7491
- proof.push({ leaf_index: cid, path: new Array(this.treeDepth + 1).fill("0") });
7492
- continue;
7493
- }
7494
- const path = await this.buildLocalProofPath(input.chainId, cid, version);
7495
- proof.push({ leaf_index: cid, path });
7480
+ let version = contractTreeElements > 0 ? await this.storage?.getChairmanMerkleVersion?.(input.chainId, contractTreeElements) : void 0;
7481
+ let effectiveTreeElements = contractTreeElements;
7482
+ if (!version && contractTreeElements > 0 && state.mergedElements > 0) {
7483
+ const latest = await this.storage?.getLatestChairmanMerkleVersion?.(input.chainId);
7484
+ if (latest && latest.version > 0) {
7485
+ const allCovered = needsTreeProof.every((cid) => cid < latest.version);
7486
+ if (allCovered) {
7487
+ version = latest;
7488
+ effectiveTreeElements = latest.version;
7496
7489
  }
7497
- const effectiveRoot = contractTreeElements > 0 ? _MerkleEngine.normalizeHex32(version.rootHash, "version.rootHash") : getZeroHash(this.treeDepth);
7498
- return {
7499
- proof,
7500
- merkle_root: effectiveRoot,
7501
- latest_cid: totalElements > 0n ? Number(totalElements - 1n) : -1
7502
- };
7503
- } catch (error) {
7490
+ }
7491
+ }
7492
+ const hasDb = contractTreeElements === 0 || !!version;
7493
+ if (hasDb) {
7494
+ if (effectiveTreeElements > 0 && state.mergedElements < effectiveTreeElements) {
7504
7495
  if (this.mode === "local") {
7505
- throw new SdkError("MERKLE", "Local merkle proof build failed", { chainId: input.chainId, cids }, error);
7496
+ throw new SdkError("MERKLE", "Local merkle db is behind contract", {
7497
+ chainId: input.chainId,
7498
+ cids,
7499
+ localMergedElements: state.mergedElements,
7500
+ contractTreeElements: effectiveTreeElements
7501
+ });
7506
7502
  }
7503
+ } else {
7504
+ try {
7505
+ const proof = [];
7506
+ for (const cid of cids) {
7507
+ if (cid >= effectiveTreeElements) {
7508
+ proof.push({ leaf_index: cid, path: new Array(this.treeDepth + 1).fill("0") });
7509
+ continue;
7510
+ }
7511
+ const path = await this.buildLocalProofPath(input.chainId, cid, version);
7512
+ proof.push({ leaf_index: cid, path });
7513
+ }
7514
+ const effectiveRoot = effectiveTreeElements > 0 ? _MerkleEngine.normalizeHex32(version.rootHash, "version.rootHash") : getZeroHash(this.treeDepth);
7515
+ const effectiveLatestCid = effectiveTreeElements > 0 ? effectiveTreeElements - 1 : -1;
7516
+ return {
7517
+ proof,
7518
+ merkle_root: effectiveRoot,
7519
+ latest_cid: effectiveLatestCid
7520
+ };
7521
+ } catch (error) {
7522
+ if (this.mode === "local") {
7523
+ throw new SdkError("MERKLE", "Local merkle proof build failed", { chainId: input.chainId, cids }, error);
7524
+ }
7525
+ }
7526
+ }
7527
+ } else {
7528
+ if (this.mode === "local" && needsTreeProof.length) {
7529
+ throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter_or_version" });
7507
7530
  }
7508
7531
  }
7509
7532
  } else if (this.mode === "local" && needsTreeProof.length) {
7510
- throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter_or_version" });
7533
+ throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter" });
7511
7534
  }
7512
7535
  }
7513
7536
  if (needsTreeProof.length === 0) {