@cloak.dev/sdk 0.1.3 → 0.1.5
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 +270 -62
- package/dist/index.d.cts +1054 -920
- package/dist/index.d.ts +1054 -920
- package/dist/index.js +263 -62
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -877,6 +877,71 @@ function parseRelayErrorResponse(responseText) {
|
|
|
877
877
|
return { isRootNotFound: false };
|
|
878
878
|
}
|
|
879
879
|
}
|
|
880
|
+
var UtxoAlreadySpentError = class extends Error {
|
|
881
|
+
constructor(message, spentUtxoCommitments = []) {
|
|
882
|
+
super(message);
|
|
883
|
+
this.spentUtxoCommitments = spentUtxoCommitments;
|
|
884
|
+
this.name = "UtxoAlreadySpentError";
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
var SanctionsQuoteError = class extends Error {
|
|
888
|
+
constructor(message, onChainCode, subKind) {
|
|
889
|
+
super(message);
|
|
890
|
+
this.onChainCode = onChainCode;
|
|
891
|
+
this.subKind = subKind;
|
|
892
|
+
this.name = "SanctionsQuoteError";
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
var RelayInternalError = class extends Error {
|
|
896
|
+
constructor(message, relayMessage, httpStatus, cachedTreeFromChain) {
|
|
897
|
+
super(message);
|
|
898
|
+
this.relayMessage = relayMessage;
|
|
899
|
+
this.httpStatus = httpStatus;
|
|
900
|
+
this.cachedTreeFromChain = cachedTreeFromChain;
|
|
901
|
+
this.name = "RelayInternalError";
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
function classifyRelayError(responseText, httpStatus) {
|
|
905
|
+
let inner = "";
|
|
906
|
+
try {
|
|
907
|
+
const parsed = JSON.parse(responseText);
|
|
908
|
+
inner = parsed?.message ?? "";
|
|
909
|
+
} catch {
|
|
910
|
+
inner = responseText;
|
|
911
|
+
}
|
|
912
|
+
const haystack = inner.toLowerCase();
|
|
913
|
+
if (haystack.includes("0x1020") || haystack.includes("doublespend")) {
|
|
914
|
+
return new UtxoAlreadySpentError(
|
|
915
|
+
"This shielded balance was already spent. The UTXO's nullifier is registered on-chain \u2014 typically means you spent it via another session or device. Run verifyUtxos() to reconcile local state."
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
if (haystack.includes("0x10b0") || haystack.includes("rangequoteexpired")) {
|
|
919
|
+
return new SanctionsQuoteError(
|
|
920
|
+
"Range sanctions quote expired before the on-chain program processed the transaction. The relay's quote-expiry window is too short relative to proof-gen + confirmation latency, or on-chain clock drifted. Retry the send; the relay will issue a fresh quote.",
|
|
921
|
+
4272,
|
|
922
|
+
"expired"
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
if (haystack.includes("0x10b2") || haystack.includes("rangequotewalletmismatch")) {
|
|
926
|
+
return new SanctionsQuoteError(
|
|
927
|
+
"Range sanctions quote's wallet doesn't match the on-chain expected wallet. Indicates a relay config drift \u2014 the sender used for quote signing doesn't match the program's pool.range_signer / fee payer. Relay operators must fix; caller retry will not help.",
|
|
928
|
+
4274,
|
|
929
|
+
"wallet_mismatch"
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
if (haystack.includes("0x10b3") || haystack.includes("rangequotemissinged25519")) {
|
|
933
|
+
return new SanctionsQuoteError(
|
|
934
|
+
"Transaction reached the on-chain program without the required Ed25519 sanctions quote instruction. This is a relay bug \u2014 the relay constructed the tx without attaching the signed quote. Caller retry will not help.",
|
|
935
|
+
4275,
|
|
936
|
+
"missing_ix"
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
return new RelayInternalError(
|
|
940
|
+
`Relay returned ${httpStatus ?? "an error"}: ${inner || responseText}`,
|
|
941
|
+
inner || responseText,
|
|
942
|
+
httpStatus
|
|
943
|
+
);
|
|
944
|
+
}
|
|
880
945
|
var ShieldPoolErrors = {
|
|
881
946
|
// Root management errors
|
|
882
947
|
4096: "Invalid Merkle root",
|
|
@@ -4173,6 +4238,63 @@ async function decryptComplianceMetadataWithMasterKey(encrypted, masterComplianc
|
|
|
4173
4238
|
return decryptWithSharedSecret(payload, sharedSecret);
|
|
4174
4239
|
}
|
|
4175
4240
|
|
|
4241
|
+
// src/utils/verify-utxos.ts
|
|
4242
|
+
async function verifyUtxos(utxos, connection, programId, commitment = "confirmed") {
|
|
4243
|
+
const checkable = [];
|
|
4244
|
+
const skipped = [];
|
|
4245
|
+
for (const utxo of utxos) {
|
|
4246
|
+
if (utxo.commitment === void 0 || utxo.mintAddress === void 0 || utxo.keypair === void 0 || utxo.keypair.privateKey === void 0) {
|
|
4247
|
+
skipped.push(utxo);
|
|
4248
|
+
continue;
|
|
4249
|
+
}
|
|
4250
|
+
try {
|
|
4251
|
+
const nullifierBig = await computeNullifier(utxo);
|
|
4252
|
+
const nullifierHex = nullifierBig.toString(16).padStart(64, "0");
|
|
4253
|
+
const nullifierBytes = Buffer.from(nullifierHex, "hex");
|
|
4254
|
+
const { pool } = getShieldPoolPDAs(programId, utxo.mintAddress);
|
|
4255
|
+
const [pda] = getNullifierPDA(pool, nullifierBytes, programId);
|
|
4256
|
+
checkable.push({ utxo, pda });
|
|
4257
|
+
} catch {
|
|
4258
|
+
skipped.push(utxo);
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4261
|
+
if (checkable.length === 0) {
|
|
4262
|
+
return { spent: [], unspent: [], skipped };
|
|
4263
|
+
}
|
|
4264
|
+
const CHUNK = 100;
|
|
4265
|
+
const infos = [];
|
|
4266
|
+
for (let i = 0; i < checkable.length; i += CHUNK) {
|
|
4267
|
+
const page = checkable.slice(i, i + CHUNK).map((e) => e.pda);
|
|
4268
|
+
const pageInfos = await connection.getMultipleAccountsInfo(page, commitment);
|
|
4269
|
+
infos.push(...pageInfos);
|
|
4270
|
+
}
|
|
4271
|
+
const spent = [];
|
|
4272
|
+
const unspent = [];
|
|
4273
|
+
for (let i = 0; i < checkable.length; i++) {
|
|
4274
|
+
if (infos[i] !== null) {
|
|
4275
|
+
spent.push(checkable[i].utxo);
|
|
4276
|
+
} else {
|
|
4277
|
+
unspent.push(checkable[i].utxo);
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
return { spent, unspent, skipped };
|
|
4281
|
+
}
|
|
4282
|
+
async function preflightNullifiers(utxos, connection, programId, commitment = "confirmed") {
|
|
4283
|
+
if (utxos.length === 0) return;
|
|
4284
|
+
const result = await verifyUtxos(utxos, connection, programId, commitment);
|
|
4285
|
+
if (result.spent.length > 0) {
|
|
4286
|
+
const allCommitments = result.spent.map(
|
|
4287
|
+
(u) => u.commitment !== void 0 ? u.commitment.toString(16).padStart(64, "0") : "<unknown>"
|
|
4288
|
+
);
|
|
4289
|
+
const preview = allCommitments.slice(0, 5);
|
|
4290
|
+
const extra = allCommitments.length > preview.length ? ` (+${allCommitments.length - preview.length} more)` : "";
|
|
4291
|
+
throw new UtxoAlreadySpentError(
|
|
4292
|
+
`Pre-flight detected ${allCommitments.length} already-spent UTXO(s). First spent commitment(s): ${preview.join(", ")}${extra}. Call verifyUtxos() and remove these from local state before retrying.`,
|
|
4293
|
+
allCommitments
|
|
4294
|
+
);
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4176
4298
|
// src/services/risk-oracle.ts
|
|
4177
4299
|
function buildRangeRiskScoreJob(OracleJob, walletAddress) {
|
|
4178
4300
|
return OracleJob.fromObject({
|
|
@@ -4517,13 +4639,19 @@ async function buildMerkleTree(commitments, height = MERKLE_TREE_HEIGHT2) {
|
|
|
4517
4639
|
}
|
|
4518
4640
|
|
|
4519
4641
|
// src/utils/relay-client.ts
|
|
4520
|
-
import
|
|
4642
|
+
import _bs58 from "bs58";
|
|
4643
|
+
var bs58 = _bs58.default || _bs58;
|
|
4521
4644
|
var TRANSACT_TAG = 0;
|
|
4522
4645
|
var TRANSACT_SWAP_TAG = 1;
|
|
4523
|
-
var DEPOSIT_TAG = 1;
|
|
4524
4646
|
var PROOF_LEN = 256;
|
|
4525
4647
|
var PUBLIC_INPUTS_LEN = 264;
|
|
4526
4648
|
var COMMITMENTS_OFFSET = 168;
|
|
4649
|
+
function isAllZero(b) {
|
|
4650
|
+
for (let i = 0; i < b.length; i++) {
|
|
4651
|
+
if (b[i] !== 0) return false;
|
|
4652
|
+
}
|
|
4653
|
+
return true;
|
|
4654
|
+
}
|
|
4527
4655
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
4528
4656
|
var DEFAULT_MAX_RETRIES = 3;
|
|
4529
4657
|
async function fetchWithRetry(url, options = {}) {
|
|
@@ -4661,24 +4789,20 @@ async function buildMerkleTreeFromRelay(relayUrl, options) {
|
|
|
4661
4789
|
function extractCommitmentsFromInstruction(data) {
|
|
4662
4790
|
if (data.length === 0) return [];
|
|
4663
4791
|
const tag = data[0];
|
|
4664
|
-
if (tag
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
if (
|
|
4677
|
-
|
|
4678
|
-
const commitment = data.slice(1 + 8, 1 + 8 + 32);
|
|
4679
|
-
return [commitment];
|
|
4680
|
-
}
|
|
4681
|
-
return [];
|
|
4792
|
+
if (tag !== TRANSACT_TAG && tag !== TRANSACT_SWAP_TAG) return [];
|
|
4793
|
+
const publicInputsStart = 1 + PROOF_LEN;
|
|
4794
|
+
const publicInputsEnd = publicInputsStart + PUBLIC_INPUTS_LEN;
|
|
4795
|
+
if (data.length < publicInputsEnd) return [];
|
|
4796
|
+
const publicInputs = data.slice(publicInputsStart, publicInputsEnd);
|
|
4797
|
+
const c0 = publicInputs.slice(COMMITMENTS_OFFSET, COMMITMENTS_OFFSET + 32);
|
|
4798
|
+
const c1 = publicInputs.slice(
|
|
4799
|
+
COMMITMENTS_OFFSET + 32,
|
|
4800
|
+
COMMITMENTS_OFFSET + 64
|
|
4801
|
+
);
|
|
4802
|
+
const out = [];
|
|
4803
|
+
if (!isAllZero(c0)) out.push(c0);
|
|
4804
|
+
if (!isAllZero(c1)) out.push(c1);
|
|
4805
|
+
return out;
|
|
4682
4806
|
}
|
|
4683
4807
|
function isBrowser() {
|
|
4684
4808
|
return typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
@@ -6298,6 +6422,7 @@ async function transact(params, options) {
|
|
|
6298
6422
|
if (outputUtxos.length > 2) {
|
|
6299
6423
|
throw new Error("Maximum 2 output UTXOs allowed");
|
|
6300
6424
|
}
|
|
6425
|
+
await preflightNullifiers(inputUtxos, connection, programId);
|
|
6301
6426
|
const mint = inputUtxos.find((u) => u.amount > 0)?.mintAddress ?? outputUtxos.find((u) => u.amount > 0)?.mintAddress ?? NATIVE_SOL_MINT;
|
|
6302
6427
|
const paddedInputs = [...inputUtxos];
|
|
6303
6428
|
while (paddedInputs.length < 2) {
|
|
@@ -6368,7 +6493,7 @@ async function transact(params, options) {
|
|
|
6368
6493
|
}
|
|
6369
6494
|
merkleTree = null;
|
|
6370
6495
|
}
|
|
6371
|
-
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree)) {
|
|
6496
|
+
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree) && !hasCachedTree) {
|
|
6372
6497
|
try {
|
|
6373
6498
|
const shouldRequestRelaySync = forceSync || requiredRelayIndex >= 0;
|
|
6374
6499
|
const syncTimeoutMs = shouldRequestRelaySync ? Math.min(3e4, relayRequestTimeoutMs()) : 3500;
|
|
@@ -6393,7 +6518,7 @@ async function transact(params, options) {
|
|
|
6393
6518
|
merkleTree = null;
|
|
6394
6519
|
}
|
|
6395
6520
|
}
|
|
6396
|
-
if (merkleTree && treeState) {
|
|
6521
|
+
if (merkleTree && treeState && !hasCachedTree) {
|
|
6397
6522
|
const relayRoot = merkleTree.root().toString(16).padStart(64, "0");
|
|
6398
6523
|
const lengthDiff = treeState.nextIndex - merkleTree.length;
|
|
6399
6524
|
if (merkleTree.length === 0) {
|
|
@@ -6524,7 +6649,7 @@ async function transact(params, options) {
|
|
|
6524
6649
|
const disableNearTipFallbackEnv = typeof process !== "undefined" && !!process.env && (process.env.CLOAK_DISABLE_NEAR_TIP_ONCHAIN_PROOF === "1" || process.env.CLOAK_DISABLE_NEAR_TIP_ONCHAIN_PROOF === "true");
|
|
6525
6650
|
const hasSiblingHints = !!utxo.siblingCommitment || !!utxo.leftSiblingCommitment;
|
|
6526
6651
|
const baseNearTipEligible = chainDistanceFromTip !== null && chainDistanceFromTip >= 0 && chainDistanceFromTip <= nearTipMaxDistance;
|
|
6527
|
-
|
|
6652
|
+
let allowNearTipOnChainFallback = relayTreeDisabledForMint && !disableNearTipFallbackEnv && baseNearTipEligible && (forceEnableNearTipFallbackEnv || useSiblingInfo && hasSiblingHints);
|
|
6528
6653
|
if (!relayTreeDisabledForMint && !useSiblingInfo) {
|
|
6529
6654
|
onProgress?.(`Relay tree missing index ${utxo.index} (length: ${treeLength}) with sibling cache disabled; proof may require retry after relay sync.`);
|
|
6530
6655
|
} else if (!relayTreeDisabledForMint && relayUrl && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
@@ -6535,9 +6660,10 @@ async function transact(params, options) {
|
|
|
6535
6660
|
onProgress?.(`Relay tree is lagging (missing index ${utxo.index}, length: ${treeLength}); using guarded on-chain proof fallback.`);
|
|
6536
6661
|
}
|
|
6537
6662
|
if (relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
6538
|
-
|
|
6539
|
-
`Relay tree missing
|
|
6663
|
+
onProgress?.(
|
|
6664
|
+
`Relay tree missing index ${utxo.index} (tree length: ${treeLength}) \u2014 falling through to on-chain proof.`
|
|
6540
6665
|
);
|
|
6666
|
+
allowNearTipOnChainFallback = true;
|
|
6541
6667
|
}
|
|
6542
6668
|
if (allowNearTipOnChainFallback && relayTreeDisabledForMint) {
|
|
6543
6669
|
onProgress?.(
|
|
@@ -6771,11 +6897,19 @@ async function transact(params, options) {
|
|
|
6771
6897
|
onProgress?.(`Merkle proof error (stale sibling data), will regenerate with fresh tree...`);
|
|
6772
6898
|
lastError = new Error(`Circuit assertion failed: ${errorMsg}`);
|
|
6773
6899
|
if (forceChainIndexing) {
|
|
6774
|
-
onProgress?.("On-chain
|
|
6775
|
-
|
|
6900
|
+
onProgress?.("On-chain frontier proof failed; escalating to full chain tree rebuild...");
|
|
6901
|
+
try {
|
|
6902
|
+
merkleTree = await buildMerkleTreeFromChain(connection, programId, pdas.merkleTree, onProgress);
|
|
6903
|
+
onProgress?.(`Chain tree rebuilt with ${merkleTree.length} leaves.`);
|
|
6904
|
+
} catch (chainBuildErr) {
|
|
6905
|
+
onProgress?.(`Chain tree rebuild failed (${chainBuildErr?.message?.slice(0, 80)}); returning to relay-sync mode.`);
|
|
6906
|
+
forceChainIndexing = false;
|
|
6907
|
+
merkleTree = null;
|
|
6908
|
+
}
|
|
6909
|
+
} else {
|
|
6910
|
+
merkleTree = null;
|
|
6776
6911
|
}
|
|
6777
6912
|
treeState = null;
|
|
6778
|
-
merkleTree = null;
|
|
6779
6913
|
useSiblingInfo = false;
|
|
6780
6914
|
const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(submissionAttempts, 4)), 5e3);
|
|
6781
6915
|
if (waitMs > 0) {
|
|
@@ -7116,25 +7250,68 @@ async function transact(params, options) {
|
|
|
7116
7250
|
}
|
|
7117
7251
|
}
|
|
7118
7252
|
if (lastError) {
|
|
7253
|
+
const classified = classifyRelayError(lastError.message);
|
|
7254
|
+
const isMerkleClass = !(classified instanceof UtxoAlreadySpentError) && !(classified instanceof SanctionsQuoteError) && !isRootNotFoundError2(lastError);
|
|
7255
|
+
if (!IS_BROWSER2 && isMerkleClass && relayUrl) {
|
|
7256
|
+
onProgress?.(
|
|
7257
|
+
"All relay-tree attempts failed. Rebuilding merkle tree from chain as last resort..."
|
|
7258
|
+
);
|
|
7259
|
+
try {
|
|
7260
|
+
const [merkleTreePda] = PublicKey6.findProgramAddressSync(
|
|
7261
|
+
[Buffer.from("merkle_tree"), mint.toBuffer()],
|
|
7262
|
+
programId
|
|
7263
|
+
);
|
|
7264
|
+
const chainTree = await buildMerkleTreeFromChain(
|
|
7265
|
+
connection,
|
|
7266
|
+
programId,
|
|
7267
|
+
merkleTreePda,
|
|
7268
|
+
onProgress
|
|
7269
|
+
);
|
|
7270
|
+
const chainRootHex = chainTree.root().toString(16).padStart(64, "0");
|
|
7271
|
+
onProgress?.(
|
|
7272
|
+
`Chain-rebuilt tree root: ${chainRootHex.substring(0, 16)}... \u2014 attached to error for caller retry`
|
|
7273
|
+
);
|
|
7274
|
+
throw new RelayInternalError(
|
|
7275
|
+
`All relay-tree attempts failed. Chain-rebuilt tree available (root ${chainRootHex.substring(0, 16)}...). Retry this call with options.cachedMerkleTree = err.cachedTreeFromChain. Original error: ${lastError.message}`,
|
|
7276
|
+
lastError.message,
|
|
7277
|
+
void 0,
|
|
7278
|
+
chainTree
|
|
7279
|
+
);
|
|
7280
|
+
} catch (e) {
|
|
7281
|
+
if (e instanceof RelayInternalError) throw e;
|
|
7282
|
+
onProgress?.(
|
|
7283
|
+
`Chain-replay fallback failed: ${e instanceof Error ? e.message : String(e)}`
|
|
7284
|
+
);
|
|
7285
|
+
}
|
|
7286
|
+
}
|
|
7119
7287
|
if (isRootNotFoundError2(lastError)) {
|
|
7120
|
-
throw new Error(
|
|
7288
|
+
throw new Error(
|
|
7289
|
+
`Transaction failed after ${maxRootRetries + 1} retries: ${lastError.message}`
|
|
7290
|
+
);
|
|
7121
7291
|
}
|
|
7122
|
-
throw
|
|
7292
|
+
throw classified;
|
|
7123
7293
|
}
|
|
7124
7294
|
if (relayUrl && outputCommitments.length >= 2) {
|
|
7125
|
-
const
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7295
|
+
const hasOnChainIndices = commitmentIndices[0] >= 0 && commitmentIndices[1] >= 0;
|
|
7296
|
+
if (!hasOnChainIndices) {
|
|
7297
|
+
const reconcileSeedIndices = lastObservedNextIndexForOutputs !== null ? [lastObservedNextIndexForOutputs, lastObservedNextIndexForOutputs + 1] : commitmentIndices;
|
|
7298
|
+
const reconciledIndices = await reconcileCommitmentIndicesWithRelay(
|
|
7299
|
+
relayUrl,
|
|
7300
|
+
mint,
|
|
7301
|
+
reconcileSeedIndices,
|
|
7302
|
+
[outputCommitments[0], outputCommitments[1]],
|
|
7303
|
+
onProgress
|
|
7304
|
+
);
|
|
7305
|
+
if (reconciledIndices[0] !== commitmentIndices[0] || reconciledIndices[1] !== commitmentIndices[1]) {
|
|
7306
|
+
onProgress?.(
|
|
7307
|
+
`Adjusted commitment indices after relay reconciliation: [${commitmentIndices[0]}, ${commitmentIndices[1]}] -> [${reconciledIndices[0]}, ${reconciledIndices[1]}]`
|
|
7308
|
+
);
|
|
7309
|
+
commitmentIndices = reconciledIndices;
|
|
7310
|
+
}
|
|
7311
|
+
} else {
|
|
7134
7312
|
onProgress?.(
|
|
7135
|
-
`
|
|
7313
|
+
`Using on-chain commitment indices [${commitmentIndices[0]}, ${commitmentIndices[1]}] (skipping relay reconciliation).`
|
|
7136
7314
|
);
|
|
7137
|
-
commitmentIndices = reconciledIndices;
|
|
7138
7315
|
}
|
|
7139
7316
|
}
|
|
7140
7317
|
const siblingCommitments = [
|
|
@@ -7416,6 +7593,7 @@ async function swapUtxo(params, options) {
|
|
|
7416
7593
|
if (inputUtxos.length > 2) {
|
|
7417
7594
|
throw new Error("Maximum 2 input UTXOs allowed");
|
|
7418
7595
|
}
|
|
7596
|
+
await preflightNullifiers(inputUtxos, connection, programId);
|
|
7419
7597
|
const outputMintAccount = await connection.getAccountInfo(outputMint, {
|
|
7420
7598
|
commitment: "confirmed"
|
|
7421
7599
|
});
|
|
@@ -7487,7 +7665,7 @@ async function swapUtxo(params, options) {
|
|
|
7487
7665
|
}
|
|
7488
7666
|
merkleTree = null;
|
|
7489
7667
|
}
|
|
7490
|
-
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree)) {
|
|
7668
|
+
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree) && !hasCachedTree) {
|
|
7491
7669
|
try {
|
|
7492
7670
|
const shouldRequestRelaySync = forceSync || requiredRelayIndex >= 0;
|
|
7493
7671
|
const syncTimeoutMs = shouldRequestRelaySync ? Math.min(3e4, relayRequestTimeoutMs()) : 3500;
|
|
@@ -7512,7 +7690,7 @@ async function swapUtxo(params, options) {
|
|
|
7512
7690
|
merkleTree = null;
|
|
7513
7691
|
}
|
|
7514
7692
|
}
|
|
7515
|
-
if (merkleTree && merkleState) {
|
|
7693
|
+
if (merkleTree && merkleState && !hasCachedTree) {
|
|
7516
7694
|
const relayRoot = merkleTree.root().toString(16).padStart(64, "0");
|
|
7517
7695
|
const lengthDiff = merkleState.nextIndex - merkleTree.length;
|
|
7518
7696
|
if (merkleTree.length === 0) {
|
|
@@ -7640,7 +7818,7 @@ async function swapUtxo(params, options) {
|
|
|
7640
7818
|
const disableNearTipFallbackEnv = typeof process !== "undefined" && !!process.env && (process.env.CLOAK_DISABLE_NEAR_TIP_ONCHAIN_PROOF === "1" || process.env.CLOAK_DISABLE_NEAR_TIP_ONCHAIN_PROOF === "true");
|
|
7641
7819
|
const hasSiblingHints = !!utxo.siblingCommitment || !!utxo.leftSiblingCommitment;
|
|
7642
7820
|
const baseNearTipEligible = chainDistanceFromTip !== null && chainDistanceFromTip >= 0 && chainDistanceFromTip <= nearTipMaxDistance;
|
|
7643
|
-
|
|
7821
|
+
let allowNearTipOnChainFallback = relayTreeDisabledForMint && !disableNearTipFallbackEnv && baseNearTipEligible && (forceEnableNearTipFallbackEnv || useSiblingInfo && hasSiblingHints);
|
|
7644
7822
|
if (!relayTreeDisabledForMint && !useSiblingInfo) {
|
|
7645
7823
|
onProgress?.(`Relay tree missing index ${utxo.index} (length: ${treeLength}) with sibling cache disabled; proof may require retry after relay sync.`);
|
|
7646
7824
|
} else if (!relayTreeDisabledForMint && relayUrl && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
@@ -7651,9 +7829,10 @@ async function swapUtxo(params, options) {
|
|
|
7651
7829
|
onProgress?.(`Relay tree is lagging (missing index ${utxo.index}, length: ${treeLength}); using guarded on-chain proof fallback.`);
|
|
7652
7830
|
}
|
|
7653
7831
|
if (relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
7654
|
-
|
|
7655
|
-
`Relay tree missing
|
|
7832
|
+
onProgress?.(
|
|
7833
|
+
`Relay tree missing index ${utxo.index} (tree length: ${treeLength}) \u2014 falling through to on-chain proof.`
|
|
7656
7834
|
);
|
|
7835
|
+
allowNearTipOnChainFallback = true;
|
|
7657
7836
|
}
|
|
7658
7837
|
if (allowNearTipOnChainFallback && relayTreeDisabledForMint) {
|
|
7659
7838
|
onProgress?.(
|
|
@@ -7857,10 +8036,18 @@ async function swapUtxo(params, options) {
|
|
|
7857
8036
|
onProgress?.(`Merkle proof error (stale sibling data), will regenerate with fresh tree...`);
|
|
7858
8037
|
lastError = new Error(`Circuit assertion failed: ${errorMsg}`);
|
|
7859
8038
|
if (forceChainIndexing) {
|
|
7860
|
-
onProgress?.("On-chain
|
|
7861
|
-
|
|
8039
|
+
onProgress?.("On-chain frontier proof failed; escalating to full chain tree rebuild...");
|
|
8040
|
+
try {
|
|
8041
|
+
merkleTree = await buildMerkleTreeFromChain(connection, programId, pdas.merkleTree, onProgress);
|
|
8042
|
+
onProgress?.(`Chain tree rebuilt with ${merkleTree.length} leaves.`);
|
|
8043
|
+
} catch (chainBuildErr) {
|
|
8044
|
+
onProgress?.(`Chain tree rebuild failed (${chainBuildErr?.message?.slice(0, 80)}); returning to relay-sync mode.`);
|
|
8045
|
+
forceChainIndexing = false;
|
|
8046
|
+
merkleTree = null;
|
|
8047
|
+
}
|
|
8048
|
+
} else {
|
|
8049
|
+
merkleTree = null;
|
|
7862
8050
|
}
|
|
7863
|
-
merkleTree = null;
|
|
7864
8051
|
merkleState = null;
|
|
7865
8052
|
useSiblingInfo = false;
|
|
7866
8053
|
const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(attempt, 4)), 5e3);
|
|
@@ -8055,19 +8242,26 @@ async function swapUtxo(params, options) {
|
|
|
8055
8242
|
throw new Error(`Swap transaction failed: ${lastError.message}`);
|
|
8056
8243
|
}
|
|
8057
8244
|
if (relayUrl && outputCommitments.length >= 2) {
|
|
8058
|
-
const
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8245
|
+
const hasOnChainIndices = commitmentIndices[0] >= 0 && commitmentIndices[1] >= 0;
|
|
8246
|
+
if (!hasOnChainIndices) {
|
|
8247
|
+
const reconcileSeedIndices = lastObservedNextIndexForOutputs !== null ? [lastObservedNextIndexForOutputs, lastObservedNextIndexForOutputs + 1] : commitmentIndices;
|
|
8248
|
+
const reconciledIndices = await reconcileCommitmentIndicesWithRelay(
|
|
8249
|
+
relayUrl,
|
|
8250
|
+
swapPoolMint,
|
|
8251
|
+
reconcileSeedIndices,
|
|
8252
|
+
[outputCommitments[0], outputCommitments[1]],
|
|
8253
|
+
onProgress
|
|
8254
|
+
);
|
|
8255
|
+
if (reconciledIndices[0] !== commitmentIndices[0] || reconciledIndices[1] !== commitmentIndices[1]) {
|
|
8256
|
+
onProgress?.(
|
|
8257
|
+
`Adjusted swap commitment indices after relay reconciliation: [${commitmentIndices[0]}, ${commitmentIndices[1]}] -> [${reconciledIndices[0]}, ${reconciledIndices[1]}]`
|
|
8258
|
+
);
|
|
8259
|
+
commitmentIndices = reconciledIndices;
|
|
8260
|
+
}
|
|
8261
|
+
} else {
|
|
8067
8262
|
onProgress?.(
|
|
8068
|
-
`
|
|
8263
|
+
`Using on-chain swap commitment indices [${commitmentIndices[0]}, ${commitmentIndices[1]}] (skipping relay reconciliation).`
|
|
8069
8264
|
);
|
|
8070
|
-
commitmentIndices = reconciledIndices;
|
|
8071
8265
|
}
|
|
8072
8266
|
}
|
|
8073
8267
|
const siblingCommitments = [
|
|
@@ -8130,11 +8324,12 @@ async function swapWithChange(inputUtxos, swapAmount, outputMint, recipientAta,
|
|
|
8130
8324
|
}
|
|
8131
8325
|
|
|
8132
8326
|
// src/core/scanner.ts
|
|
8133
|
-
import
|
|
8327
|
+
import _bs582 from "bs58";
|
|
8134
8328
|
import {
|
|
8135
8329
|
PublicKey as PublicKey7
|
|
8136
8330
|
} from "@solana/web3.js";
|
|
8137
8331
|
import { getAssociatedTokenAddressSync as getAssociatedTokenAddressSync2 } from "@solana/spl-token";
|
|
8332
|
+
var bs582 = _bs582.default || _bs582;
|
|
8138
8333
|
var TRANSACT_TAG2 = 0;
|
|
8139
8334
|
var TRANSACT_SWAP_TAG2 = 1;
|
|
8140
8335
|
var PROOF_LEN2 = 256;
|
|
@@ -9223,7 +9418,7 @@ var SimpleWallet = class {
|
|
|
9223
9418
|
};
|
|
9224
9419
|
|
|
9225
9420
|
// src/index.ts
|
|
9226
|
-
var VERSION = "1.
|
|
9421
|
+
var VERSION = "0.1.5";
|
|
9227
9422
|
var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
9228
9423
|
export {
|
|
9229
9424
|
CLOAK_PROGRAM_ID,
|
|
@@ -9240,12 +9435,15 @@ export {
|
|
|
9240
9435
|
MemoryStorageAdapter,
|
|
9241
9436
|
MerkleTree,
|
|
9242
9437
|
NATIVE_SOL_MINT,
|
|
9438
|
+
RelayInternalError,
|
|
9243
9439
|
RelayService,
|
|
9244
9440
|
RootNotFoundError,
|
|
9245
9441
|
SCANNER_SUPPORTS_TRANSACT_SWAP,
|
|
9246
9442
|
SIGN_IN_MESSAGE,
|
|
9443
|
+
SanctionsQuoteError,
|
|
9247
9444
|
ShieldPoolErrors,
|
|
9248
9445
|
SimpleWallet,
|
|
9446
|
+
UtxoAlreadySpentError,
|
|
9249
9447
|
UtxoWallet,
|
|
9250
9448
|
VARIABLE_FEE_DENOMINATOR,
|
|
9251
9449
|
VARIABLE_FEE_NUMERATOR,
|
|
@@ -9264,6 +9462,7 @@ export {
|
|
|
9264
9462
|
calculateRelayFee,
|
|
9265
9463
|
chainNoteFromBase64,
|
|
9266
9464
|
chainNoteToBase64,
|
|
9465
|
+
classifyRelayError,
|
|
9267
9466
|
cleanupStalePendingOperations,
|
|
9268
9467
|
clearPendingDeposits,
|
|
9269
9468
|
clearPendingWithdrawals,
|
|
@@ -9376,6 +9575,7 @@ export {
|
|
|
9376
9575
|
partialWithdraw,
|
|
9377
9576
|
poseidonHash,
|
|
9378
9577
|
preflightCheck,
|
|
9578
|
+
preflightNullifiers,
|
|
9379
9579
|
prepareEncryptedOutput,
|
|
9380
9580
|
prepareEncryptedOutputForRecipient,
|
|
9381
9581
|
proofToBytes,
|
|
@@ -9423,6 +9623,7 @@ export {
|
|
|
9423
9623
|
validateWithdrawableNote,
|
|
9424
9624
|
verifyAllCircuits,
|
|
9425
9625
|
verifyCircuitIntegrity,
|
|
9626
|
+
verifyUtxos,
|
|
9426
9627
|
waitForRoot,
|
|
9427
9628
|
withTiming
|
|
9428
9629
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloak.dev/sdk",
|
|
3
3
|
"description": "Shield, send, and swap on Solana privately — TypeScript SDK with UTXO-based zero-knowledge transactions",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"web3",
|
|
48
48
|
"blockchain"
|
|
49
49
|
],
|
|
50
|
-
"author": "Cloak
|
|
50
|
+
"author": "Cloak",
|
|
51
51
|
"license": "Apache-2.0",
|
|
52
52
|
"repository": {
|
|
53
53
|
"type": "git",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"@jup-ag/api": "^6.0.48",
|
|
62
62
|
"@lightprotocol/hasher.rs": "^0.2.1",
|
|
63
63
|
"@noble/hashes": "^1.8.0",
|
|
64
|
-
"@solana/spl-token": "
|
|
65
|
-
"@solana/web3.js": "^1.
|
|
64
|
+
"@solana/spl-token": "0.4.14",
|
|
65
|
+
"@solana/web3.js": "^1.98.0",
|
|
66
66
|
"bs58": "^6.0.0",
|
|
67
|
-
"circomlibjs": "
|
|
67
|
+
"circomlibjs": "0.1.7",
|
|
68
68
|
"ffjavascript": "^0.3.0",
|
|
69
|
-
"snarkjs": "
|
|
69
|
+
"snarkjs": "0.7.6",
|
|
70
70
|
"tweetnacl": "^1.0.3",
|
|
71
71
|
"tweetnacl-util": "^0.15.1",
|
|
72
|
-
"yaml": "^2.8.
|
|
72
|
+
"yaml": "^2.8.3"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@coral-xyz/anchor": "^0.32.1",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"@switchboard-xyz/common": "^5.6.1",
|
|
88
88
|
"@switchboard-xyz/on-demand": "^3.8.2",
|
|
89
|
-
"@solana/spl-token": "
|
|
90
|
-
"@solana/web3.js": "
|
|
89
|
+
"@solana/spl-token": ">=0.4.9",
|
|
90
|
+
"@solana/web3.js": ">=1.98.0"
|
|
91
91
|
},
|
|
92
92
|
"peerDependenciesMeta": {
|
|
93
93
|
"@switchboard-xyz/common": {
|