@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.cjs
CHANGED
|
@@ -301,12 +301,15 @@ __export(index_exports, {
|
|
|
301
301
|
MemoryStorageAdapter: () => MemoryStorageAdapter,
|
|
302
302
|
MerkleTree: () => MerkleTree,
|
|
303
303
|
NATIVE_SOL_MINT: () => NATIVE_SOL_MINT,
|
|
304
|
+
RelayInternalError: () => RelayInternalError,
|
|
304
305
|
RelayService: () => RelayService,
|
|
305
306
|
RootNotFoundError: () => RootNotFoundError,
|
|
306
307
|
SCANNER_SUPPORTS_TRANSACT_SWAP: () => SCANNER_SUPPORTS_TRANSACT_SWAP,
|
|
307
308
|
SIGN_IN_MESSAGE: () => SIGN_IN_MESSAGE,
|
|
309
|
+
SanctionsQuoteError: () => SanctionsQuoteError,
|
|
308
310
|
ShieldPoolErrors: () => ShieldPoolErrors,
|
|
309
311
|
SimpleWallet: () => SimpleWallet,
|
|
312
|
+
UtxoAlreadySpentError: () => UtxoAlreadySpentError,
|
|
310
313
|
UtxoWallet: () => UtxoWallet,
|
|
311
314
|
VARIABLE_FEE_DENOMINATOR: () => VARIABLE_FEE_DENOMINATOR,
|
|
312
315
|
VARIABLE_FEE_NUMERATOR: () => VARIABLE_FEE_NUMERATOR,
|
|
@@ -325,6 +328,7 @@ __export(index_exports, {
|
|
|
325
328
|
calculateRelayFee: () => calculateRelayFee,
|
|
326
329
|
chainNoteFromBase64: () => chainNoteFromBase64,
|
|
327
330
|
chainNoteToBase64: () => chainNoteToBase64,
|
|
331
|
+
classifyRelayError: () => classifyRelayError,
|
|
328
332
|
cleanupStalePendingOperations: () => cleanupStalePendingOperations,
|
|
329
333
|
clearPendingDeposits: () => clearPendingDeposits,
|
|
330
334
|
clearPendingWithdrawals: () => clearPendingWithdrawals,
|
|
@@ -437,6 +441,7 @@ __export(index_exports, {
|
|
|
437
441
|
partialWithdraw: () => partialWithdraw,
|
|
438
442
|
poseidonHash: () => poseidonHash,
|
|
439
443
|
preflightCheck: () => preflightCheck,
|
|
444
|
+
preflightNullifiers: () => preflightNullifiers,
|
|
440
445
|
prepareEncryptedOutput: () => prepareEncryptedOutput,
|
|
441
446
|
prepareEncryptedOutputForRecipient: () => prepareEncryptedOutputForRecipient,
|
|
442
447
|
proofToBytes: () => proofToBytes,
|
|
@@ -484,6 +489,7 @@ __export(index_exports, {
|
|
|
484
489
|
validateWithdrawableNote: () => validateWithdrawableNote,
|
|
485
490
|
verifyAllCircuits: () => verifyAllCircuits,
|
|
486
491
|
verifyCircuitIntegrity: () => verifyCircuitIntegrity,
|
|
492
|
+
verifyUtxos: () => verifyUtxos,
|
|
487
493
|
waitForRoot: () => waitForRoot,
|
|
488
494
|
withTiming: () => withTiming
|
|
489
495
|
});
|
|
@@ -1339,6 +1345,71 @@ function parseRelayErrorResponse(responseText) {
|
|
|
1339
1345
|
return { isRootNotFound: false };
|
|
1340
1346
|
}
|
|
1341
1347
|
}
|
|
1348
|
+
var UtxoAlreadySpentError = class extends Error {
|
|
1349
|
+
constructor(message, spentUtxoCommitments = []) {
|
|
1350
|
+
super(message);
|
|
1351
|
+
this.spentUtxoCommitments = spentUtxoCommitments;
|
|
1352
|
+
this.name = "UtxoAlreadySpentError";
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
var SanctionsQuoteError = class extends Error {
|
|
1356
|
+
constructor(message, onChainCode, subKind) {
|
|
1357
|
+
super(message);
|
|
1358
|
+
this.onChainCode = onChainCode;
|
|
1359
|
+
this.subKind = subKind;
|
|
1360
|
+
this.name = "SanctionsQuoteError";
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
var RelayInternalError = class extends Error {
|
|
1364
|
+
constructor(message, relayMessage, httpStatus, cachedTreeFromChain) {
|
|
1365
|
+
super(message);
|
|
1366
|
+
this.relayMessage = relayMessage;
|
|
1367
|
+
this.httpStatus = httpStatus;
|
|
1368
|
+
this.cachedTreeFromChain = cachedTreeFromChain;
|
|
1369
|
+
this.name = "RelayInternalError";
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
function classifyRelayError(responseText, httpStatus) {
|
|
1373
|
+
let inner = "";
|
|
1374
|
+
try {
|
|
1375
|
+
const parsed = JSON.parse(responseText);
|
|
1376
|
+
inner = parsed?.message ?? "";
|
|
1377
|
+
} catch {
|
|
1378
|
+
inner = responseText;
|
|
1379
|
+
}
|
|
1380
|
+
const haystack = inner.toLowerCase();
|
|
1381
|
+
if (haystack.includes("0x1020") || haystack.includes("doublespend")) {
|
|
1382
|
+
return new UtxoAlreadySpentError(
|
|
1383
|
+
"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."
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
if (haystack.includes("0x10b0") || haystack.includes("rangequoteexpired")) {
|
|
1387
|
+
return new SanctionsQuoteError(
|
|
1388
|
+
"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.",
|
|
1389
|
+
4272,
|
|
1390
|
+
"expired"
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
if (haystack.includes("0x10b2") || haystack.includes("rangequotewalletmismatch")) {
|
|
1394
|
+
return new SanctionsQuoteError(
|
|
1395
|
+
"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.",
|
|
1396
|
+
4274,
|
|
1397
|
+
"wallet_mismatch"
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
if (haystack.includes("0x10b3") || haystack.includes("rangequotemissinged25519")) {
|
|
1401
|
+
return new SanctionsQuoteError(
|
|
1402
|
+
"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.",
|
|
1403
|
+
4275,
|
|
1404
|
+
"missing_ix"
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
return new RelayInternalError(
|
|
1408
|
+
`Relay returned ${httpStatus ?? "an error"}: ${inner || responseText}`,
|
|
1409
|
+
inner || responseText,
|
|
1410
|
+
httpStatus
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1342
1413
|
var ShieldPoolErrors = {
|
|
1343
1414
|
// Root management errors
|
|
1344
1415
|
4096: "Invalid Merkle root",
|
|
@@ -4635,6 +4706,64 @@ async function decryptComplianceMetadataWithMasterKey(encrypted, masterComplianc
|
|
|
4635
4706
|
return decryptWithSharedSecret(payload, sharedSecret);
|
|
4636
4707
|
}
|
|
4637
4708
|
|
|
4709
|
+
// src/utils/verify-utxos.ts
|
|
4710
|
+
init_utxo();
|
|
4711
|
+
async function verifyUtxos(utxos, connection, programId, commitment = "confirmed") {
|
|
4712
|
+
const checkable = [];
|
|
4713
|
+
const skipped = [];
|
|
4714
|
+
for (const utxo of utxos) {
|
|
4715
|
+
if (utxo.commitment === void 0 || utxo.mintAddress === void 0 || utxo.keypair === void 0 || utxo.keypair.privateKey === void 0) {
|
|
4716
|
+
skipped.push(utxo);
|
|
4717
|
+
continue;
|
|
4718
|
+
}
|
|
4719
|
+
try {
|
|
4720
|
+
const nullifierBig = await computeNullifier2(utxo);
|
|
4721
|
+
const nullifierHex = nullifierBig.toString(16).padStart(64, "0");
|
|
4722
|
+
const nullifierBytes = Buffer.from(nullifierHex, "hex");
|
|
4723
|
+
const { pool } = getShieldPoolPDAs(programId, utxo.mintAddress);
|
|
4724
|
+
const [pda] = getNullifierPDA(pool, nullifierBytes, programId);
|
|
4725
|
+
checkable.push({ utxo, pda });
|
|
4726
|
+
} catch {
|
|
4727
|
+
skipped.push(utxo);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
if (checkable.length === 0) {
|
|
4731
|
+
return { spent: [], unspent: [], skipped };
|
|
4732
|
+
}
|
|
4733
|
+
const CHUNK = 100;
|
|
4734
|
+
const infos = [];
|
|
4735
|
+
for (let i = 0; i < checkable.length; i += CHUNK) {
|
|
4736
|
+
const page = checkable.slice(i, i + CHUNK).map((e) => e.pda);
|
|
4737
|
+
const pageInfos = await connection.getMultipleAccountsInfo(page, commitment);
|
|
4738
|
+
infos.push(...pageInfos);
|
|
4739
|
+
}
|
|
4740
|
+
const spent = [];
|
|
4741
|
+
const unspent = [];
|
|
4742
|
+
for (let i = 0; i < checkable.length; i++) {
|
|
4743
|
+
if (infos[i] !== null) {
|
|
4744
|
+
spent.push(checkable[i].utxo);
|
|
4745
|
+
} else {
|
|
4746
|
+
unspent.push(checkable[i].utxo);
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
return { spent, unspent, skipped };
|
|
4750
|
+
}
|
|
4751
|
+
async function preflightNullifiers(utxos, connection, programId, commitment = "confirmed") {
|
|
4752
|
+
if (utxos.length === 0) return;
|
|
4753
|
+
const result = await verifyUtxos(utxos, connection, programId, commitment);
|
|
4754
|
+
if (result.spent.length > 0) {
|
|
4755
|
+
const allCommitments = result.spent.map(
|
|
4756
|
+
(u) => u.commitment !== void 0 ? u.commitment.toString(16).padStart(64, "0") : "<unknown>"
|
|
4757
|
+
);
|
|
4758
|
+
const preview = allCommitments.slice(0, 5);
|
|
4759
|
+
const extra = allCommitments.length > preview.length ? ` (+${allCommitments.length - preview.length} more)` : "";
|
|
4760
|
+
throw new UtxoAlreadySpentError(
|
|
4761
|
+
`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.`,
|
|
4762
|
+
allCommitments
|
|
4763
|
+
);
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
|
|
4638
4767
|
// src/services/risk-oracle.ts
|
|
4639
4768
|
function buildRangeRiskScoreJob(OracleJob, walletAddress) {
|
|
4640
4769
|
return OracleJob.fromObject({
|
|
@@ -4978,12 +5107,18 @@ async function buildMerkleTree(commitments, height = MERKLE_TREE_HEIGHT2) {
|
|
|
4978
5107
|
|
|
4979
5108
|
// src/utils/relay-client.ts
|
|
4980
5109
|
var import_bs58 = __toESM(require("bs58"), 1);
|
|
5110
|
+
var bs58 = import_bs58.default.default || import_bs58.default;
|
|
4981
5111
|
var TRANSACT_TAG = 0;
|
|
4982
5112
|
var TRANSACT_SWAP_TAG = 1;
|
|
4983
|
-
var DEPOSIT_TAG = 1;
|
|
4984
5113
|
var PROOF_LEN = 256;
|
|
4985
5114
|
var PUBLIC_INPUTS_LEN = 264;
|
|
4986
5115
|
var COMMITMENTS_OFFSET = 168;
|
|
5116
|
+
function isAllZero(b) {
|
|
5117
|
+
for (let i = 0; i < b.length; i++) {
|
|
5118
|
+
if (b[i] !== 0) return false;
|
|
5119
|
+
}
|
|
5120
|
+
return true;
|
|
5121
|
+
}
|
|
4987
5122
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
4988
5123
|
var DEFAULT_MAX_RETRIES = 3;
|
|
4989
5124
|
async function fetchWithRetry(url, options = {}) {
|
|
@@ -5121,24 +5256,20 @@ async function buildMerkleTreeFromRelay(relayUrl, options) {
|
|
|
5121
5256
|
function extractCommitmentsFromInstruction(data) {
|
|
5122
5257
|
if (data.length === 0) return [];
|
|
5123
5258
|
const tag = data[0];
|
|
5124
|
-
if (tag
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
if (
|
|
5137
|
-
|
|
5138
|
-
const commitment = data.slice(1 + 8, 1 + 8 + 32);
|
|
5139
|
-
return [commitment];
|
|
5140
|
-
}
|
|
5141
|
-
return [];
|
|
5259
|
+
if (tag !== TRANSACT_TAG && tag !== TRANSACT_SWAP_TAG) return [];
|
|
5260
|
+
const publicInputsStart = 1 + PROOF_LEN;
|
|
5261
|
+
const publicInputsEnd = publicInputsStart + PUBLIC_INPUTS_LEN;
|
|
5262
|
+
if (data.length < publicInputsEnd) return [];
|
|
5263
|
+
const publicInputs = data.slice(publicInputsStart, publicInputsEnd);
|
|
5264
|
+
const c0 = publicInputs.slice(COMMITMENTS_OFFSET, COMMITMENTS_OFFSET + 32);
|
|
5265
|
+
const c1 = publicInputs.slice(
|
|
5266
|
+
COMMITMENTS_OFFSET + 32,
|
|
5267
|
+
COMMITMENTS_OFFSET + 64
|
|
5268
|
+
);
|
|
5269
|
+
const out = [];
|
|
5270
|
+
if (!isAllZero(c0)) out.push(c0);
|
|
5271
|
+
if (!isAllZero(c1)) out.push(c1);
|
|
5272
|
+
return out;
|
|
5142
5273
|
}
|
|
5143
5274
|
function isBrowser() {
|
|
5144
5275
|
return typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
@@ -5177,7 +5308,7 @@ async function buildMerkleTreeFromChain(connection, programId, merkleTree, onPro
|
|
|
5177
5308
|
for (const ix of tx.transaction.message.instructions) {
|
|
5178
5309
|
if (!("programId" in ix) || !("data" in ix)) continue;
|
|
5179
5310
|
if (ix.programId.toBase58() !== programIdBase58) continue;
|
|
5180
|
-
const data =
|
|
5311
|
+
const data = bs58.decode(ix.data);
|
|
5181
5312
|
const extracted = extractCommitmentsFromInstruction(data);
|
|
5182
5313
|
for (const commitment of extracted) {
|
|
5183
5314
|
commitments.push(BigInt("0x" + Buffer.from(commitment).toString("hex")));
|
|
@@ -6745,6 +6876,7 @@ async function transact(params, options) {
|
|
|
6745
6876
|
if (outputUtxos.length > 2) {
|
|
6746
6877
|
throw new Error("Maximum 2 output UTXOs allowed");
|
|
6747
6878
|
}
|
|
6879
|
+
await preflightNullifiers(inputUtxos, connection, programId);
|
|
6748
6880
|
const mint = inputUtxos.find((u) => u.amount > 0)?.mintAddress ?? outputUtxos.find((u) => u.amount > 0)?.mintAddress ?? NATIVE_SOL_MINT;
|
|
6749
6881
|
const paddedInputs = [...inputUtxos];
|
|
6750
6882
|
while (paddedInputs.length < 2) {
|
|
@@ -6815,7 +6947,7 @@ async function transact(params, options) {
|
|
|
6815
6947
|
}
|
|
6816
6948
|
merkleTree = null;
|
|
6817
6949
|
}
|
|
6818
|
-
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree)) {
|
|
6950
|
+
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree) && !hasCachedTree) {
|
|
6819
6951
|
try {
|
|
6820
6952
|
const shouldRequestRelaySync = forceSync || requiredRelayIndex >= 0;
|
|
6821
6953
|
const syncTimeoutMs = shouldRequestRelaySync ? Math.min(3e4, relayRequestTimeoutMs()) : 3500;
|
|
@@ -6840,7 +6972,7 @@ async function transact(params, options) {
|
|
|
6840
6972
|
merkleTree = null;
|
|
6841
6973
|
}
|
|
6842
6974
|
}
|
|
6843
|
-
if (merkleTree && treeState) {
|
|
6975
|
+
if (merkleTree && treeState && !hasCachedTree) {
|
|
6844
6976
|
const relayRoot = merkleTree.root().toString(16).padStart(64, "0");
|
|
6845
6977
|
const lengthDiff = treeState.nextIndex - merkleTree.length;
|
|
6846
6978
|
if (merkleTree.length === 0) {
|
|
@@ -6971,7 +7103,7 @@ async function transact(params, options) {
|
|
|
6971
7103
|
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");
|
|
6972
7104
|
const hasSiblingHints = !!utxo.siblingCommitment || !!utxo.leftSiblingCommitment;
|
|
6973
7105
|
const baseNearTipEligible = chainDistanceFromTip !== null && chainDistanceFromTip >= 0 && chainDistanceFromTip <= nearTipMaxDistance;
|
|
6974
|
-
|
|
7106
|
+
let allowNearTipOnChainFallback = relayTreeDisabledForMint && !disableNearTipFallbackEnv && baseNearTipEligible && (forceEnableNearTipFallbackEnv || useSiblingInfo && hasSiblingHints);
|
|
6975
7107
|
if (!relayTreeDisabledForMint && !useSiblingInfo) {
|
|
6976
7108
|
onProgress?.(`Relay tree missing index ${utxo.index} (length: ${treeLength}) with sibling cache disabled; proof may require retry after relay sync.`);
|
|
6977
7109
|
} else if (!relayTreeDisabledForMint && relayUrl && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
@@ -6982,9 +7114,10 @@ async function transact(params, options) {
|
|
|
6982
7114
|
onProgress?.(`Relay tree is lagging (missing index ${utxo.index}, length: ${treeLength}); using guarded on-chain proof fallback.`);
|
|
6983
7115
|
}
|
|
6984
7116
|
if (relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
6985
|
-
|
|
6986
|
-
`Relay tree missing
|
|
7117
|
+
onProgress?.(
|
|
7118
|
+
`Relay tree missing index ${utxo.index} (tree length: ${treeLength}) \u2014 falling through to on-chain proof.`
|
|
6987
7119
|
);
|
|
7120
|
+
allowNearTipOnChainFallback = true;
|
|
6988
7121
|
}
|
|
6989
7122
|
if (allowNearTipOnChainFallback && relayTreeDisabledForMint) {
|
|
6990
7123
|
onProgress?.(
|
|
@@ -7218,11 +7351,19 @@ async function transact(params, options) {
|
|
|
7218
7351
|
onProgress?.(`Merkle proof error (stale sibling data), will regenerate with fresh tree...`);
|
|
7219
7352
|
lastError = new Error(`Circuit assertion failed: ${errorMsg}`);
|
|
7220
7353
|
if (forceChainIndexing) {
|
|
7221
|
-
onProgress?.("On-chain
|
|
7222
|
-
|
|
7354
|
+
onProgress?.("On-chain frontier proof failed; escalating to full chain tree rebuild...");
|
|
7355
|
+
try {
|
|
7356
|
+
merkleTree = await buildMerkleTreeFromChain(connection, programId, pdas.merkleTree, onProgress);
|
|
7357
|
+
onProgress?.(`Chain tree rebuilt with ${merkleTree.length} leaves.`);
|
|
7358
|
+
} catch (chainBuildErr) {
|
|
7359
|
+
onProgress?.(`Chain tree rebuild failed (${chainBuildErr?.message?.slice(0, 80)}); returning to relay-sync mode.`);
|
|
7360
|
+
forceChainIndexing = false;
|
|
7361
|
+
merkleTree = null;
|
|
7362
|
+
}
|
|
7363
|
+
} else {
|
|
7364
|
+
merkleTree = null;
|
|
7223
7365
|
}
|
|
7224
7366
|
treeState = null;
|
|
7225
|
-
merkleTree = null;
|
|
7226
7367
|
useSiblingInfo = false;
|
|
7227
7368
|
const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(submissionAttempts, 4)), 5e3);
|
|
7228
7369
|
if (waitMs > 0) {
|
|
@@ -7563,25 +7704,68 @@ async function transact(params, options) {
|
|
|
7563
7704
|
}
|
|
7564
7705
|
}
|
|
7565
7706
|
if (lastError) {
|
|
7707
|
+
const classified = classifyRelayError(lastError.message);
|
|
7708
|
+
const isMerkleClass = !(classified instanceof UtxoAlreadySpentError) && !(classified instanceof SanctionsQuoteError) && !isRootNotFoundError2(lastError);
|
|
7709
|
+
if (!IS_BROWSER2 && isMerkleClass && relayUrl) {
|
|
7710
|
+
onProgress?.(
|
|
7711
|
+
"All relay-tree attempts failed. Rebuilding merkle tree from chain as last resort..."
|
|
7712
|
+
);
|
|
7713
|
+
try {
|
|
7714
|
+
const [merkleTreePda] = import_web37.PublicKey.findProgramAddressSync(
|
|
7715
|
+
[Buffer.from("merkle_tree"), mint.toBuffer()],
|
|
7716
|
+
programId
|
|
7717
|
+
);
|
|
7718
|
+
const chainTree = await buildMerkleTreeFromChain(
|
|
7719
|
+
connection,
|
|
7720
|
+
programId,
|
|
7721
|
+
merkleTreePda,
|
|
7722
|
+
onProgress
|
|
7723
|
+
);
|
|
7724
|
+
const chainRootHex = chainTree.root().toString(16).padStart(64, "0");
|
|
7725
|
+
onProgress?.(
|
|
7726
|
+
`Chain-rebuilt tree root: ${chainRootHex.substring(0, 16)}... \u2014 attached to error for caller retry`
|
|
7727
|
+
);
|
|
7728
|
+
throw new RelayInternalError(
|
|
7729
|
+
`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}`,
|
|
7730
|
+
lastError.message,
|
|
7731
|
+
void 0,
|
|
7732
|
+
chainTree
|
|
7733
|
+
);
|
|
7734
|
+
} catch (e) {
|
|
7735
|
+
if (e instanceof RelayInternalError) throw e;
|
|
7736
|
+
onProgress?.(
|
|
7737
|
+
`Chain-replay fallback failed: ${e instanceof Error ? e.message : String(e)}`
|
|
7738
|
+
);
|
|
7739
|
+
}
|
|
7740
|
+
}
|
|
7566
7741
|
if (isRootNotFoundError2(lastError)) {
|
|
7567
|
-
throw new Error(
|
|
7742
|
+
throw new Error(
|
|
7743
|
+
`Transaction failed after ${maxRootRetries + 1} retries: ${lastError.message}`
|
|
7744
|
+
);
|
|
7568
7745
|
}
|
|
7569
|
-
throw
|
|
7746
|
+
throw classified;
|
|
7570
7747
|
}
|
|
7571
7748
|
if (relayUrl && outputCommitments.length >= 2) {
|
|
7572
|
-
const
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7749
|
+
const hasOnChainIndices = commitmentIndices[0] >= 0 && commitmentIndices[1] >= 0;
|
|
7750
|
+
if (!hasOnChainIndices) {
|
|
7751
|
+
const reconcileSeedIndices = lastObservedNextIndexForOutputs !== null ? [lastObservedNextIndexForOutputs, lastObservedNextIndexForOutputs + 1] : commitmentIndices;
|
|
7752
|
+
const reconciledIndices = await reconcileCommitmentIndicesWithRelay(
|
|
7753
|
+
relayUrl,
|
|
7754
|
+
mint,
|
|
7755
|
+
reconcileSeedIndices,
|
|
7756
|
+
[outputCommitments[0], outputCommitments[1]],
|
|
7757
|
+
onProgress
|
|
7758
|
+
);
|
|
7759
|
+
if (reconciledIndices[0] !== commitmentIndices[0] || reconciledIndices[1] !== commitmentIndices[1]) {
|
|
7760
|
+
onProgress?.(
|
|
7761
|
+
`Adjusted commitment indices after relay reconciliation: [${commitmentIndices[0]}, ${commitmentIndices[1]}] -> [${reconciledIndices[0]}, ${reconciledIndices[1]}]`
|
|
7762
|
+
);
|
|
7763
|
+
commitmentIndices = reconciledIndices;
|
|
7764
|
+
}
|
|
7765
|
+
} else {
|
|
7581
7766
|
onProgress?.(
|
|
7582
|
-
`
|
|
7767
|
+
`Using on-chain commitment indices [${commitmentIndices[0]}, ${commitmentIndices[1]}] (skipping relay reconciliation).`
|
|
7583
7768
|
);
|
|
7584
|
-
commitmentIndices = reconciledIndices;
|
|
7585
7769
|
}
|
|
7586
7770
|
}
|
|
7587
7771
|
const siblingCommitments = [
|
|
@@ -7863,6 +8047,7 @@ async function swapUtxo(params, options) {
|
|
|
7863
8047
|
if (inputUtxos.length > 2) {
|
|
7864
8048
|
throw new Error("Maximum 2 input UTXOs allowed");
|
|
7865
8049
|
}
|
|
8050
|
+
await preflightNullifiers(inputUtxos, connection, programId);
|
|
7866
8051
|
const outputMintAccount = await connection.getAccountInfo(outputMint, {
|
|
7867
8052
|
commitment: "confirmed"
|
|
7868
8053
|
});
|
|
@@ -7934,7 +8119,7 @@ async function swapUtxo(params, options) {
|
|
|
7934
8119
|
}
|
|
7935
8120
|
merkleTree = null;
|
|
7936
8121
|
}
|
|
7937
|
-
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree)) {
|
|
8122
|
+
if (needsTreeForProof && relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && (forceRefresh || !merkleTree) && !hasCachedTree) {
|
|
7938
8123
|
try {
|
|
7939
8124
|
const shouldRequestRelaySync = forceSync || requiredRelayIndex >= 0;
|
|
7940
8125
|
const syncTimeoutMs = shouldRequestRelaySync ? Math.min(3e4, relayRequestTimeoutMs()) : 3500;
|
|
@@ -7959,7 +8144,7 @@ async function swapUtxo(params, options) {
|
|
|
7959
8144
|
merkleTree = null;
|
|
7960
8145
|
}
|
|
7961
8146
|
}
|
|
7962
|
-
if (merkleTree && merkleState) {
|
|
8147
|
+
if (merkleTree && merkleState && !hasCachedTree) {
|
|
7963
8148
|
const relayRoot = merkleTree.root().toString(16).padStart(64, "0");
|
|
7964
8149
|
const lengthDiff = merkleState.nextIndex - merkleTree.length;
|
|
7965
8150
|
if (merkleTree.length === 0) {
|
|
@@ -8087,7 +8272,7 @@ async function swapUtxo(params, options) {
|
|
|
8087
8272
|
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");
|
|
8088
8273
|
const hasSiblingHints = !!utxo.siblingCommitment || !!utxo.leftSiblingCommitment;
|
|
8089
8274
|
const baseNearTipEligible = chainDistanceFromTip !== null && chainDistanceFromTip >= 0 && chainDistanceFromTip <= nearTipMaxDistance;
|
|
8090
|
-
|
|
8275
|
+
let allowNearTipOnChainFallback = relayTreeDisabledForMint && !disableNearTipFallbackEnv && baseNearTipEligible && (forceEnableNearTipFallbackEnv || useSiblingInfo && hasSiblingHints);
|
|
8091
8276
|
if (!relayTreeDisabledForMint && !useSiblingInfo) {
|
|
8092
8277
|
onProgress?.(`Relay tree missing index ${utxo.index} (length: ${treeLength}) with sibling cache disabled; proof may require retry after relay sync.`);
|
|
8093
8278
|
} else if (!relayTreeDisabledForMint && relayUrl && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
@@ -8098,9 +8283,10 @@ async function swapUtxo(params, options) {
|
|
|
8098
8283
|
onProgress?.(`Relay tree is lagging (missing index ${utxo.index}, length: ${treeLength}); using guarded on-chain proof fallback.`);
|
|
8099
8284
|
}
|
|
8100
8285
|
if (relayUrl && !relayTreeDisabledForMint && !forceChainIndexing && utxo.index >= treeLength && !allowNearTipOnChainFallback) {
|
|
8101
|
-
|
|
8102
|
-
`Relay tree missing
|
|
8286
|
+
onProgress?.(
|
|
8287
|
+
`Relay tree missing index ${utxo.index} (tree length: ${treeLength}) \u2014 falling through to on-chain proof.`
|
|
8103
8288
|
);
|
|
8289
|
+
allowNearTipOnChainFallback = true;
|
|
8104
8290
|
}
|
|
8105
8291
|
if (allowNearTipOnChainFallback && relayTreeDisabledForMint) {
|
|
8106
8292
|
onProgress?.(
|
|
@@ -8304,10 +8490,18 @@ async function swapUtxo(params, options) {
|
|
|
8304
8490
|
onProgress?.(`Merkle proof error (stale sibling data), will regenerate with fresh tree...`);
|
|
8305
8491
|
lastError = new Error(`Circuit assertion failed: ${errorMsg}`);
|
|
8306
8492
|
if (forceChainIndexing) {
|
|
8307
|
-
onProgress?.("On-chain
|
|
8308
|
-
|
|
8493
|
+
onProgress?.("On-chain frontier proof failed; escalating to full chain tree rebuild...");
|
|
8494
|
+
try {
|
|
8495
|
+
merkleTree = await buildMerkleTreeFromChain(connection, programId, pdas.merkleTree, onProgress);
|
|
8496
|
+
onProgress?.(`Chain tree rebuilt with ${merkleTree.length} leaves.`);
|
|
8497
|
+
} catch (chainBuildErr) {
|
|
8498
|
+
onProgress?.(`Chain tree rebuild failed (${chainBuildErr?.message?.slice(0, 80)}); returning to relay-sync mode.`);
|
|
8499
|
+
forceChainIndexing = false;
|
|
8500
|
+
merkleTree = null;
|
|
8501
|
+
}
|
|
8502
|
+
} else {
|
|
8503
|
+
merkleTree = null;
|
|
8309
8504
|
}
|
|
8310
|
-
merkleTree = null;
|
|
8311
8505
|
merkleState = null;
|
|
8312
8506
|
useSiblingInfo = false;
|
|
8313
8507
|
const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(attempt, 4)), 5e3);
|
|
@@ -8502,19 +8696,26 @@ async function swapUtxo(params, options) {
|
|
|
8502
8696
|
throw new Error(`Swap transaction failed: ${lastError.message}`);
|
|
8503
8697
|
}
|
|
8504
8698
|
if (relayUrl && outputCommitments.length >= 2) {
|
|
8505
|
-
const
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8699
|
+
const hasOnChainIndices = commitmentIndices[0] >= 0 && commitmentIndices[1] >= 0;
|
|
8700
|
+
if (!hasOnChainIndices) {
|
|
8701
|
+
const reconcileSeedIndices = lastObservedNextIndexForOutputs !== null ? [lastObservedNextIndexForOutputs, lastObservedNextIndexForOutputs + 1] : commitmentIndices;
|
|
8702
|
+
const reconciledIndices = await reconcileCommitmentIndicesWithRelay(
|
|
8703
|
+
relayUrl,
|
|
8704
|
+
swapPoolMint,
|
|
8705
|
+
reconcileSeedIndices,
|
|
8706
|
+
[outputCommitments[0], outputCommitments[1]],
|
|
8707
|
+
onProgress
|
|
8708
|
+
);
|
|
8709
|
+
if (reconciledIndices[0] !== commitmentIndices[0] || reconciledIndices[1] !== commitmentIndices[1]) {
|
|
8710
|
+
onProgress?.(
|
|
8711
|
+
`Adjusted swap commitment indices after relay reconciliation: [${commitmentIndices[0]}, ${commitmentIndices[1]}] -> [${reconciledIndices[0]}, ${reconciledIndices[1]}]`
|
|
8712
|
+
);
|
|
8713
|
+
commitmentIndices = reconciledIndices;
|
|
8714
|
+
}
|
|
8715
|
+
} else {
|
|
8514
8716
|
onProgress?.(
|
|
8515
|
-
`
|
|
8717
|
+
`Using on-chain swap commitment indices [${commitmentIndices[0]}, ${commitmentIndices[1]}] (skipping relay reconciliation).`
|
|
8516
8718
|
);
|
|
8517
|
-
commitmentIndices = reconciledIndices;
|
|
8518
8719
|
}
|
|
8519
8720
|
}
|
|
8520
8721
|
const siblingCommitments = [
|
|
@@ -8580,6 +8781,7 @@ async function swapWithChange(inputUtxos, swapAmount, outputMint, recipientAta,
|
|
|
8580
8781
|
var import_bs582 = __toESM(require("bs58"), 1);
|
|
8581
8782
|
var import_web38 = require("@solana/web3.js");
|
|
8582
8783
|
var import_spl_token2 = require("@solana/spl-token");
|
|
8784
|
+
var bs582 = import_bs582.default.default || import_bs582.default;
|
|
8583
8785
|
var TRANSACT_TAG2 = 0;
|
|
8584
8786
|
var TRANSACT_SWAP_TAG2 = 1;
|
|
8585
8787
|
var PROOF_LEN2 = 256;
|
|
@@ -8763,7 +8965,7 @@ function normalizeIxData(rawData) {
|
|
|
8763
8965
|
if (rawData instanceof Uint8Array) return rawData;
|
|
8764
8966
|
if (typeof rawData === "string") {
|
|
8765
8967
|
try {
|
|
8766
|
-
const decoded =
|
|
8968
|
+
const decoded = bs582.decode(rawData);
|
|
8767
8969
|
return new Uint8Array(decoded);
|
|
8768
8970
|
} catch {
|
|
8769
8971
|
if (typeof Buffer !== "undefined") {
|
|
@@ -9669,7 +9871,7 @@ var SimpleWallet = class {
|
|
|
9669
9871
|
};
|
|
9670
9872
|
|
|
9671
9873
|
// src/index.ts
|
|
9672
|
-
var VERSION = "1.
|
|
9874
|
+
var VERSION = "0.1.5";
|
|
9673
9875
|
var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
9674
9876
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9675
9877
|
0 && (module.exports = {
|
|
@@ -9687,12 +9889,15 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
|
9687
9889
|
MemoryStorageAdapter,
|
|
9688
9890
|
MerkleTree,
|
|
9689
9891
|
NATIVE_SOL_MINT,
|
|
9892
|
+
RelayInternalError,
|
|
9690
9893
|
RelayService,
|
|
9691
9894
|
RootNotFoundError,
|
|
9692
9895
|
SCANNER_SUPPORTS_TRANSACT_SWAP,
|
|
9693
9896
|
SIGN_IN_MESSAGE,
|
|
9897
|
+
SanctionsQuoteError,
|
|
9694
9898
|
ShieldPoolErrors,
|
|
9695
9899
|
SimpleWallet,
|
|
9900
|
+
UtxoAlreadySpentError,
|
|
9696
9901
|
UtxoWallet,
|
|
9697
9902
|
VARIABLE_FEE_DENOMINATOR,
|
|
9698
9903
|
VARIABLE_FEE_NUMERATOR,
|
|
@@ -9711,6 +9916,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
|
9711
9916
|
calculateRelayFee,
|
|
9712
9917
|
chainNoteFromBase64,
|
|
9713
9918
|
chainNoteToBase64,
|
|
9919
|
+
classifyRelayError,
|
|
9714
9920
|
cleanupStalePendingOperations,
|
|
9715
9921
|
clearPendingDeposits,
|
|
9716
9922
|
clearPendingWithdrawals,
|
|
@@ -9823,6 +10029,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
|
9823
10029
|
partialWithdraw,
|
|
9824
10030
|
poseidonHash,
|
|
9825
10031
|
preflightCheck,
|
|
10032
|
+
preflightNullifiers,
|
|
9826
10033
|
prepareEncryptedOutput,
|
|
9827
10034
|
prepareEncryptedOutputForRecipient,
|
|
9828
10035
|
proofToBytes,
|
|
@@ -9870,6 +10077,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
|
9870
10077
|
validateWithdrawableNote,
|
|
9871
10078
|
verifyAllCircuits,
|
|
9872
10079
|
verifyCircuitIntegrity,
|
|
10080
|
+
verifyUtxos,
|
|
9873
10081
|
waitForRoot,
|
|
9874
10082
|
withTiming
|
|
9875
10083
|
});
|