@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 +88 -65
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +82 -59
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +88 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +82 -59
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +121 -87
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +115 -81
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -3352,7 +3352,7 @@ var MemoryStore = class {
|
|
|
3352
3352
|
async getMerkleLeaf(chainId, cid) {
|
|
3353
3353
|
const rows = this.merkleLeavesByChain.get(chainId);
|
|
3354
3354
|
const row = rows?.[cid];
|
|
3355
|
-
if (!row) return void 0;
|
|
3355
|
+
if (!row || row.cid !== cid) return void 0;
|
|
3356
3356
|
return { chainId, cid: row.cid, commitment: row.commitment };
|
|
3357
3357
|
}
|
|
3358
3358
|
/**
|
|
@@ -4369,7 +4369,7 @@ var KeyValueStore = class {
|
|
|
4369
4369
|
if (!this.merkleLeafCids[String(chainId)]?.has(cid)) return void 0;
|
|
4370
4370
|
const raw = await this.options.client.get(this.sharedRecordKey("merkleLeaves", chainId, cid));
|
|
4371
4371
|
const row = this.parseJson(raw, null);
|
|
4372
|
-
if (!row) return void 0;
|
|
4372
|
+
if (!row || row.cid !== cid) return void 0;
|
|
4373
4373
|
return { chainId, cid: row.cid, commitment: row.commitment };
|
|
4374
4374
|
}
|
|
4375
4375
|
async appendMerkleLeaves(chainId, leaves) {
|
|
@@ -5131,10 +5131,10 @@ var ProofEngine = class {
|
|
|
5131
5131
|
merkle_root_index: parsed.merkle_root_index ?? context.merkle_root_index,
|
|
5132
5132
|
relayer: parsed.relayer ?? context.relayer,
|
|
5133
5133
|
recipient: parsed.recipient ?? context.recipient,
|
|
5134
|
-
withdraw_amount: parsed.withdraw_amount ? BigInt(parsed.withdraw_amount) : context.withdraw_amount,
|
|
5134
|
+
withdraw_amount: parsed.withdraw_amount != null ? BigInt(parsed.withdraw_amount) : context.withdraw_amount,
|
|
5135
5135
|
extra_data: parsed.extra_data ?? context.extra_data,
|
|
5136
|
-
relayer_fee: parsed.relayer_fee ? BigInt(parsed.relayer_fee) : context.relayer_fee,
|
|
5137
|
-
gas_drop_value: parsed.gas_drop_value ? BigInt(parsed.gas_drop_value) : context.gas_drop_value,
|
|
5136
|
+
relayer_fee: parsed.relayer_fee != null ? BigInt(parsed.relayer_fee) : context.relayer_fee,
|
|
5137
|
+
gas_drop_value: parsed.gas_drop_value != null ? BigInt(parsed.gas_drop_value) : context.gas_drop_value,
|
|
5138
5138
|
array_hash_digest: parsed.array_hash_digest ?? context.array_hash_digest,
|
|
5139
5139
|
gnark_output: parsed.gnark_output,
|
|
5140
5140
|
witness_json: parsed.witness_json,
|
|
@@ -6258,10 +6258,31 @@ var SyncEngine = class {
|
|
|
6258
6258
|
|
|
6259
6259
|
// src/planner/planner.ts
|
|
6260
6260
|
import { maxUint256, toHex as toHex4 } from "viem";
|
|
6261
|
+
|
|
6262
|
+
// src/utils/validators.ts
|
|
6263
|
+
import { getAddress as getAddress2 } from "viem";
|
|
6261
6264
|
var requireHex = (value, name) => {
|
|
6262
6265
|
if (isHexStrict(value, { minBytes: 1 })) return value;
|
|
6263
6266
|
throw new SdkError("CONFIG", `${name} must be a hex string starting with 0x`);
|
|
6264
6267
|
};
|
|
6268
|
+
var requireNumber = (value, name) => {
|
|
6269
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
6270
|
+
throw new SdkError("CONFIG", `${name} must be a finite number`);
|
|
6271
|
+
};
|
|
6272
|
+
var requireAddress = (value, name) => {
|
|
6273
|
+
if (typeof value !== "string") {
|
|
6274
|
+
throw new SdkError("CONFIG", `${name} must be a string address`);
|
|
6275
|
+
}
|
|
6276
|
+
return getAddress2(value);
|
|
6277
|
+
};
|
|
6278
|
+
var requireBigint = (value, name) => {
|
|
6279
|
+
if (typeof value === "bigint") return value;
|
|
6280
|
+
if (typeof value === "string" && value.length) return BigInt(value);
|
|
6281
|
+
if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
|
|
6282
|
+
throw new SdkError("CONFIG", `${name} must be a bigint-compatible value`);
|
|
6283
|
+
};
|
|
6284
|
+
|
|
6285
|
+
// src/planner/planner.ts
|
|
6265
6286
|
var parsePlanInput = (input) => {
|
|
6266
6287
|
const action = input.action;
|
|
6267
6288
|
if (action !== "transfer" && action !== "withdraw") {
|
|
@@ -6339,9 +6360,12 @@ var recordsFee = (input, _records, expectedOutput, action, relayerFee, expectedI
|
|
|
6339
6360
|
}
|
|
6340
6361
|
} else {
|
|
6341
6362
|
cost = expectedIsWithFee ? expectedOutput : expectedOutput + fee;
|
|
6363
|
+
outputAmount = expectedIsWithFee ? expectedOutput - fee : expectedOutput;
|
|
6364
|
+
if (outputAmount < 0n) outputAmount = 0n;
|
|
6342
6365
|
}
|
|
6343
6366
|
if (total < cost) {
|
|
6344
6367
|
cost = 0n;
|
|
6368
|
+
outputAmount = 0n;
|
|
6345
6369
|
}
|
|
6346
6370
|
break;
|
|
6347
6371
|
}
|
|
@@ -6827,27 +6851,6 @@ var Planner = class {
|
|
|
6827
6851
|
};
|
|
6828
6852
|
|
|
6829
6853
|
// src/tx/txBuilder.ts
|
|
6830
|
-
import { getAddress as getAddress2 } from "viem";
|
|
6831
|
-
var requireNumber = (value, name) => {
|
|
6832
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
6833
|
-
throw new SdkError("CONFIG", `Missing ${name}`);
|
|
6834
|
-
};
|
|
6835
|
-
var requireHex2 = (value, name) => {
|
|
6836
|
-
if (isHexStrict(value, { minBytes: 1 })) return value;
|
|
6837
|
-
throw new SdkError("CONFIG", `Missing ${name}`);
|
|
6838
|
-
};
|
|
6839
|
-
var requireAddress = (value, name) => {
|
|
6840
|
-
if (typeof value !== "string") {
|
|
6841
|
-
throw new SdkError("CONFIG", `Missing ${name}`);
|
|
6842
|
-
}
|
|
6843
|
-
return getAddress2(value);
|
|
6844
|
-
};
|
|
6845
|
-
var requireBigint = (value, name) => {
|
|
6846
|
-
if (typeof value === "bigint") return value;
|
|
6847
|
-
if (typeof value === "string" && value.length) return BigInt(value);
|
|
6848
|
-
if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
|
|
6849
|
-
throw new SdkError("CONFIG", `Missing ${name}`);
|
|
6850
|
-
};
|
|
6851
6854
|
var TxBuilder = class {
|
|
6852
6855
|
/**
|
|
6853
6856
|
* Build relayer request for transfer proofs.
|
|
@@ -6861,7 +6864,7 @@ var TxBuilder = class {
|
|
|
6861
6864
|
if (!Array.isArray(extraData) || extraData.length !== 3) {
|
|
6862
6865
|
throw new SdkError("CONFIG", "Transfer requires extra_data as bytes[3]");
|
|
6863
6866
|
}
|
|
6864
|
-
extraData.forEach((entry, idx) =>
|
|
6867
|
+
extraData.forEach((entry, idx) => requireHex(entry, `extra_data[${idx}]`));
|
|
6865
6868
|
const request = {
|
|
6866
6869
|
kind: "relayer",
|
|
6867
6870
|
method: "POST",
|
|
@@ -6894,7 +6897,7 @@ var TxBuilder = class {
|
|
|
6894
6897
|
if (Array.isArray(extraData)) {
|
|
6895
6898
|
throw new SdkError("CONFIG", "Withdraw requires extra_data as bytes");
|
|
6896
6899
|
}
|
|
6897
|
-
const extraDataHex =
|
|
6900
|
+
const extraDataHex = requireHex(extraData, "extra_data");
|
|
6898
6901
|
const request = {
|
|
6899
6902
|
kind: "relayer",
|
|
6900
6903
|
method: "POST",
|
|
@@ -7403,44 +7406,64 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7403
7406
|
await this.hydrateFromStorage(input.chainId);
|
|
7404
7407
|
const canUseLocal = this.mode !== "remote";
|
|
7405
7408
|
if (canUseLocal) {
|
|
7406
|
-
const
|
|
7407
|
-
const
|
|
7408
|
-
if (
|
|
7409
|
+
const hasMerkleLeaf = typeof this.storage?.getMerkleLeaf === "function";
|
|
7410
|
+
const hasChairmanNode = typeof this.storage?.getChairmanMerkleNode === "function";
|
|
7411
|
+
if (hasMerkleLeaf && hasChairmanNode) {
|
|
7409
7412
|
const state = this.ensureChainState(input.chainId);
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
} else {
|
|
7420
|
-
try {
|
|
7421
|
-
const proof = [];
|
|
7422
|
-
for (const cid of cids) {
|
|
7423
|
-
if (cid >= contractTreeElements) {
|
|
7424
|
-
proof.push({ leaf_index: cid, path: new Array(this.treeDepth + 1).fill("0") });
|
|
7425
|
-
continue;
|
|
7426
|
-
}
|
|
7427
|
-
const path2 = await this.buildLocalProofPath(input.chainId, cid, version);
|
|
7428
|
-
proof.push({ leaf_index: cid, path: path2 });
|
|
7413
|
+
let version = contractTreeElements > 0 ? await this.storage?.getChairmanMerkleVersion?.(input.chainId, contractTreeElements) : void 0;
|
|
7414
|
+
let effectiveTreeElements = contractTreeElements;
|
|
7415
|
+
if (!version && contractTreeElements > 0 && state.mergedElements > 0) {
|
|
7416
|
+
const latest = await this.storage?.getLatestChairmanMerkleVersion?.(input.chainId);
|
|
7417
|
+
if (latest && latest.version > 0) {
|
|
7418
|
+
const allCovered = needsTreeProof.every((cid) => cid < latest.version);
|
|
7419
|
+
if (allCovered) {
|
|
7420
|
+
version = latest;
|
|
7421
|
+
effectiveTreeElements = latest.version;
|
|
7429
7422
|
}
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
};
|
|
7436
|
-
} catch (error) {
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
const hasDb = contractTreeElements === 0 || !!version;
|
|
7426
|
+
if (hasDb) {
|
|
7427
|
+
if (effectiveTreeElements > 0 && state.mergedElements < effectiveTreeElements) {
|
|
7437
7428
|
if (this.mode === "local") {
|
|
7438
|
-
throw new SdkError("MERKLE", "Local merkle
|
|
7429
|
+
throw new SdkError("MERKLE", "Local merkle db is behind contract", {
|
|
7430
|
+
chainId: input.chainId,
|
|
7431
|
+
cids,
|
|
7432
|
+
localMergedElements: state.mergedElements,
|
|
7433
|
+
contractTreeElements: effectiveTreeElements
|
|
7434
|
+
});
|
|
7439
7435
|
}
|
|
7436
|
+
} else {
|
|
7437
|
+
try {
|
|
7438
|
+
const proof = [];
|
|
7439
|
+
for (const cid of cids) {
|
|
7440
|
+
if (cid >= effectiveTreeElements) {
|
|
7441
|
+
proof.push({ leaf_index: cid, path: new Array(this.treeDepth + 1).fill("0") });
|
|
7442
|
+
continue;
|
|
7443
|
+
}
|
|
7444
|
+
const path2 = await this.buildLocalProofPath(input.chainId, cid, version);
|
|
7445
|
+
proof.push({ leaf_index: cid, path: path2 });
|
|
7446
|
+
}
|
|
7447
|
+
const effectiveRoot = effectiveTreeElements > 0 ? _MerkleEngine.normalizeHex32(version.rootHash, "version.rootHash") : getZeroHash(this.treeDepth);
|
|
7448
|
+
const effectiveLatestCid = effectiveTreeElements > 0 ? effectiveTreeElements - 1 : -1;
|
|
7449
|
+
return {
|
|
7450
|
+
proof,
|
|
7451
|
+
merkle_root: effectiveRoot,
|
|
7452
|
+
latest_cid: effectiveLatestCid
|
|
7453
|
+
};
|
|
7454
|
+
} catch (error) {
|
|
7455
|
+
if (this.mode === "local") {
|
|
7456
|
+
throw new SdkError("MERKLE", "Local merkle proof build failed", { chainId: input.chainId, cids }, error);
|
|
7457
|
+
}
|
|
7458
|
+
}
|
|
7459
|
+
}
|
|
7460
|
+
} else {
|
|
7461
|
+
if (this.mode === "local" && needsTreeProof.length) {
|
|
7462
|
+
throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter_or_version" });
|
|
7440
7463
|
}
|
|
7441
7464
|
}
|
|
7442
7465
|
} else if (this.mode === "local" && needsTreeProof.length) {
|
|
7443
|
-
throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "
|
|
7466
|
+
throw new SdkError("MERKLE", "Local merkle db unavailable", { chainId: input.chainId, cids, reason: "missing_adapter" });
|
|
7444
7467
|
}
|
|
7445
7468
|
}
|
|
7446
7469
|
if (needsTreeProof.length === 0) {
|
|
@@ -8719,6 +8742,9 @@ function hydrateWalletState(state) {
|
|
|
8719
8742
|
}
|
|
8720
8743
|
|
|
8721
8744
|
// src/store/fileStore.ts
|
|
8745
|
+
function isEnoent(err) {
|
|
8746
|
+
return !!err && typeof err === "object" && "code" in err && err.code === "ENOENT";
|
|
8747
|
+
}
|
|
8722
8748
|
var FileStore = class {
|
|
8723
8749
|
/**
|
|
8724
8750
|
* Create a FileStore with a base directory and optional limits.
|
|
@@ -8781,26 +8807,28 @@ var FileStore = class {
|
|
|
8781
8807
|
return path.join(this.options.baseDir, `shared.merkle.${chainId}.jsonl`);
|
|
8782
8808
|
}
|
|
8783
8809
|
async readMerkleFile(filePath) {
|
|
8810
|
+
let raw;
|
|
8784
8811
|
try {
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
for (const line of lines) {
|
|
8789
|
-
try {
|
|
8790
|
-
const row = JSON.parse(line);
|
|
8791
|
-
const cid = Number(row?.cid);
|
|
8792
|
-
const commitment2 = row?.commitment;
|
|
8793
|
-
if (!Number.isFinite(cid) || cid < 0) continue;
|
|
8794
|
-
if (typeof commitment2 !== "string" || !commitment2.startsWith("0x")) continue;
|
|
8795
|
-
out.push({ cid: Math.floor(cid), commitment: commitment2 });
|
|
8796
|
-
} catch {
|
|
8797
|
-
}
|
|
8798
|
-
}
|
|
8799
|
-
out.sort((a, b) => a.cid - b.cid);
|
|
8800
|
-
return out.length ? out : void 0;
|
|
8801
|
-
} catch {
|
|
8812
|
+
raw = await readFile(filePath, "utf8");
|
|
8813
|
+
} catch (err) {
|
|
8814
|
+
if (!isEnoent(err)) throw err;
|
|
8802
8815
|
return void 0;
|
|
8803
8816
|
}
|
|
8817
|
+
const out = [];
|
|
8818
|
+
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
8819
|
+
for (const line of lines) {
|
|
8820
|
+
try {
|
|
8821
|
+
const row = JSON.parse(line);
|
|
8822
|
+
const cid = Number(row?.cid);
|
|
8823
|
+
const commitment2 = row?.commitment;
|
|
8824
|
+
if (!Number.isFinite(cid) || cid < 0) continue;
|
|
8825
|
+
if (typeof commitment2 !== "string" || !commitment2.startsWith("0x")) continue;
|
|
8826
|
+
out.push({ cid: Math.floor(cid), commitment: commitment2 });
|
|
8827
|
+
} catch {
|
|
8828
|
+
}
|
|
8829
|
+
}
|
|
8830
|
+
out.sort((a, b) => a.cid - b.cid);
|
|
8831
|
+
return out.length ? out : void 0;
|
|
8804
8832
|
}
|
|
8805
8833
|
/**
|
|
8806
8834
|
* Infer the next merkle cid from the tail of the jsonl file.
|
|
@@ -8817,10 +8845,14 @@ var FileStore = class {
|
|
|
8817
8845
|
}
|
|
8818
8846
|
const last = JSON.parse(lines[lines.length - 1]);
|
|
8819
8847
|
const cid = Number(last?.cid);
|
|
8820
|
-
|
|
8848
|
+
if (!Number.isFinite(cid)) {
|
|
8849
|
+
throw new Error(`corrupted merkle jsonl: missing or non-numeric cid in tail of ${this.merkleFilePath(chainId)}`);
|
|
8850
|
+
}
|
|
8851
|
+
const next = Math.max(0, Math.floor(cid) + 1);
|
|
8821
8852
|
this.merkleNextCid.set(chainId, next);
|
|
8822
8853
|
return next;
|
|
8823
|
-
} catch {
|
|
8854
|
+
} catch (err) {
|
|
8855
|
+
if (!isEnoent(err)) throw err;
|
|
8824
8856
|
this.merkleNextCid.set(chainId, 0);
|
|
8825
8857
|
return 0;
|
|
8826
8858
|
}
|
|
@@ -8847,7 +8879,8 @@ var FileStore = class {
|
|
|
8847
8879
|
for (const [k, v] of hydrated.utxos.entries()) this.utxos.set(k, v);
|
|
8848
8880
|
const operations = Array.isArray(parsed.operations) ? parsed.operations : [];
|
|
8849
8881
|
this.operations = operations;
|
|
8850
|
-
} catch {
|
|
8882
|
+
} catch (err) {
|
|
8883
|
+
if (!isEnoent(err)) throw err;
|
|
8851
8884
|
}
|
|
8852
8885
|
try {
|
|
8853
8886
|
const raw = await readFile(this.sharedFilePath(), "utf8");
|
|
@@ -8879,7 +8912,8 @@ var FileStore = class {
|
|
|
8879
8912
|
if (entryNullifiersRaw && typeof entryNullifiersRaw === "object") {
|
|
8880
8913
|
this.entryNullifiers = entryNullifiersRaw;
|
|
8881
8914
|
}
|
|
8882
|
-
} catch {
|
|
8915
|
+
} catch (err) {
|
|
8916
|
+
if (!isEnoent(err)) throw err;
|
|
8883
8917
|
}
|
|
8884
8918
|
const pruned = this.pruneOperations();
|
|
8885
8919
|
if (pruned) void this.saveWallet().catch(() => void 0);
|
|
@@ -9150,7 +9184,7 @@ var FileStore = class {
|
|
|
9150
9184
|
async getMerkleLeaf(chainId, cid) {
|
|
9151
9185
|
const rows = await this.getMerkleLeaves(chainId);
|
|
9152
9186
|
const row = rows?.[cid];
|
|
9153
|
-
if (!row) return void 0;
|
|
9187
|
+
if (!row || row.cid !== cid) return void 0;
|
|
9154
9188
|
return { chainId, cid: row.cid, commitment: row.commitment };
|
|
9155
9189
|
}
|
|
9156
9190
|
/**
|