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