@cloak.dev/sdk 0.2.3-staging.f2d7f2a → 0.2.3

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
@@ -542,10 +542,8 @@ var init_utxo = __esm({
542
542
  // src/index.ts
543
543
  var index_exports = {};
544
544
  __export(index_exports, {
545
- BRIDGE_ESCROW_LABEL: () => BRIDGE_ESCROW_LABEL,
546
545
  BUILD_ALLOWS_LOCAL_ENDPOINTS: () => BUILD_ALLOWS_LOCAL_ENDPOINTS,
547
546
  CHAIN_NOTE_SALT_BITS: () => CHAIN_NOTE_SALT_BITS,
548
- CLEANUP_FEE_BUDGET: () => CLEANUP_FEE_BUDGET,
549
547
  CLOAK_PRODUCTION_RELAY_URL: () => CLOAK_PRODUCTION_RELAY_URL,
550
548
  CLOAK_PROGRAM_ID: () => CLOAK_PROGRAM_ID,
551
549
  CloakError: () => CloakError,
@@ -553,25 +551,16 @@ __export(index_exports, {
553
551
  DEFAULT_TRANSACTION_CIRCUITS_URL: () => DEFAULT_TRANSACTION_CIRCUITS_URL,
554
552
  DELIVERY_MEMO_TAG: () => DELIVERY_MEMO_TAG,
555
553
  DELIVERY_REGISTRY_SEED: () => DELIVERY_REGISTRY_SEED,
556
- DepositError: () => DepositError,
557
- DoNotRetry: () => DoNotRetry,
558
- ECONOMIC_MINIMUM: () => ECONOMIC_MINIMUM,
559
554
  EXPECTED_CIRCUIT_HASHES: () => EXPECTED_CIRCUIT_HASHES,
560
- FEE_BUDGET: () => FEE_BUDGET,
561
555
  FIXED_FEE_LAMPORTS: () => FIXED_FEE_LAMPORTS,
562
556
  InsecureRandomnessError: () => InsecureRandomnessError,
563
557
  LAMPORTS_PER_SOL: () => LAMPORTS_PER_SOL,
564
558
  LocalStorageAdapter: () => LocalStorageAdapter,
565
- MAINNET_RENT_0: () => MAINNET_RENT_0,
566
- MAINNET_RENT_1: () => MAINNET_RENT_1,
567
- MAX_RECEIVER_INDEX: () => MAX_RECEIVER_INDEX,
568
559
  MERKLE_TREE_HEIGHT: () => MERKLE_TREE_HEIGHT2,
569
560
  MIN_DEPOSIT_LAMPORTS: () => MIN_DEPOSIT_LAMPORTS,
570
- MIN_DEPOSIT_SPL_BASE_UNITS: () => MIN_DEPOSIT_SPL_BASE_UNITS,
571
561
  MemoryStorageAdapter: () => MemoryStorageAdapter,
572
562
  MerkleTree: () => MerkleTree,
573
563
  NATIVE_SOL_MINT: () => NATIVE_SOL_MINT,
574
- ONECLICK_PUBKEY_B58: () => ONECLICK_PUBKEY_B58,
575
564
  RECIPIENT_DELIVERY_CIPHERTEXT_LEN: () => RECIPIENT_DELIVERY_CIPHERTEXT_LEN,
576
565
  RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN: () => RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN,
577
566
  RECIPIENT_DELIVERY_NONCE_LEN: () => RECIPIENT_DELIVERY_NONCE_LEN,
@@ -590,7 +579,6 @@ __export(index_exports, {
590
579
  SettlementVerificationError: () => SettlementVerificationError,
591
580
  ShieldPoolErrors: () => ShieldPoolErrors,
592
581
  SimpleWallet: () => SimpleWallet,
593
- TERMINAL_FAILURE: () => TERMINAL_FAILURE,
594
582
  TRANSACTION_CIRCUITS_VERSION: () => TRANSACTION_CIRCUITS_VERSION,
595
583
  TRANSACT_AUTH_FIELDS: () => TRANSACT_AUTH_FIELDS,
596
584
  TRANSACT_SWAP_AUTH_FIELDS: () => TRANSACT_SWAP_AUTH_FIELDS,
@@ -600,12 +588,9 @@ __export(index_exports, {
600
588
  VARIABLE_FEE_NUMERATOR: () => VARIABLE_FEE_NUMERATOR,
601
589
  VARIABLE_FEE_RATE: () => VARIABLE_FEE_RATE,
602
590
  VERSION: () => VERSION,
603
- WITHDRAW_FEE_BPS: () => WITHDRAW_FEE_BPS,
604
- WITHDRAW_FIXED_FEE: () => WITHDRAW_FIXED_FEE,
605
591
  assertDirectSubmissionLanded: () => assertDirectSubmissionLanded,
606
592
  assertInputMints: () => assertInputMints,
607
593
  assertTransactionCircuitIntegrity: () => assertTransactionCircuitIntegrity,
608
- assessBridgeQuote: () => assessBridgeQuote,
609
594
  bigintToBytes32: () => bigintToBytes32,
610
595
  bigintToHex: () => bigintToHex,
611
596
  buildMerkleTree: () => buildMerkleTree,
@@ -620,16 +605,12 @@ __export(index_exports, {
620
605
  calculateRelayFee: () => calculateRelayFee,
621
606
  canRebuildMerkleTreeFromChain: () => canRebuildMerkleTreeFromChain,
622
607
  canonicalJson: () => canonicalJson,
623
- canonicalPayloadString: () => canonicalPayloadString,
624
608
  chainNoteFromBase64: () => chainNoteFromBase64,
625
609
  chainNoteToBase64: () => chainNoteToBase64,
626
- classifyPostFailure: () => classifyPostFailure,
627
610
  classifyRelayError: () => classifyRelayError,
628
- cleanupReceivingAddress: () => cleanupReceivingAddress,
629
611
  cleanupStalePendingOperations: () => cleanupStalePendingOperations,
630
612
  clearPendingDeposits: () => clearPendingDeposits,
631
613
  clearPendingWithdrawals: () => clearPendingWithdrawals,
632
- cloakBridgeRail: () => cloakBridgeRail,
633
614
  computeChainNoteHash: () => computeChainNoteHash,
634
615
  computeExtDataHash: () => computeExtDataHash,
635
616
  computeMerkleRoot: () => computeMerkleRoot,
@@ -651,13 +632,10 @@ __export(index_exports, {
651
632
  decryptCompactChainNote: () => decryptCompactChainNote,
652
633
  decryptComplianceMetadataWithMasterKey: () => decryptComplianceMetadataWithMasterKey,
653
634
  decryptTransactionMetadata: () => decryptTransactionMetadata,
654
- depositFromDerivedKey: () => depositFromDerivedKey,
655
- deriveBridgeReceiver: () => deriveBridgeReceiver,
656
635
  deriveChangeNoteBlinding: () => deriveChangeNoteBlinding,
657
636
  deriveDepositNoteSecrets: () => deriveDepositNoteSecrets,
658
637
  deriveDiversifiedViewingKey: () => deriveDiversifiedViewingKey,
659
638
  deriveDiversifier: () => deriveDiversifier,
660
- deriveFundingTargets: () => deriveFundingTargets,
661
639
  deriveInputNullifierPdas: () => deriveInputNullifierPdas,
662
640
  derivePublicKey: () => derivePublicKey,
663
641
  deriveSpendKey: () => deriveSpendKey,
@@ -696,7 +674,6 @@ __export(index_exports, {
696
674
  formatErrorForLogging: () => formatErrorForLogging,
697
675
  formatSol: () => formatSol,
698
676
  fullWithdraw: () => fullWithdraw,
699
- fundReceiverViaPaymaster: () => fundReceiverViaPaymaster,
700
677
  generateCloakKeys: () => generateCloakKeys,
701
678
  generateCommitmentAsync: () => generateCommitmentAsync,
702
679
  generateMasterSeed: () => generateMasterSeed,
@@ -732,21 +709,18 @@ __export(index_exports, {
732
709
  isReactNative: () => isReactNative,
733
710
  isRootNotFoundError: () => isRootNotFoundError,
734
711
  isSubmissionOutcomeUnknownResponse: () => isSubmissionOutcomeUnknownResponse,
735
- isTerminalFailure: () => isTerminalFailure,
736
712
  isValidHex: () => isValidHex,
737
713
  isValidRpcUrl: () => isValidRpcUrl,
738
714
  isValidSolanaAddress: () => isValidSolanaAddress,
739
715
  isWithdrawAmountSufficient: () => isWithdrawAmountSufficient,
740
716
  isWithdrawable: () => isWithdrawable,
741
717
  keypairToAdapter: () => keypairToAdapter,
742
- listBridgeDeposits: () => listBridgeDeposits,
743
718
  loadPendingDeposits: () => loadPendingDeposits,
744
719
  loadPendingWithdrawals: () => loadPendingWithdrawals,
745
720
  loadVerifiedCircuitArtifacts: () => loadVerifiedCircuitArtifacts,
746
721
  matchChangeNote: () => matchChangeNote,
747
722
  matchDepositNote: () => matchDepositNote,
748
723
  matchSwapRefundLeaf: () => matchSwapRefundLeaf,
749
- mayRetry: () => mayRetry,
750
724
  openRecipientDeliveryNote: () => openRecipientDeliveryNote,
751
725
  parseAmount: () => parseAmount,
752
726
  parseDeliveryCarrierMemo: () => parseDeliveryCarrierMemo,
@@ -769,14 +743,11 @@ __export(index_exports, {
769
743
  randomDepositNoteSalt: () => randomDepositNoteSalt,
770
744
  randomFieldElement: () => randomFieldElement,
771
745
  readMerkleTreeState: () => readMerkleTreeState,
772
- readRent: () => readRent,
773
746
  recipientDeliveryNoteToBase64: () => recipientDeliveryNoteToBase64,
774
747
  registerViewingKey: () => registerViewingKey,
775
748
  removePendingDeposit: () => removePendingDeposit,
776
749
  removePendingWithdrawal: () => removePendingWithdrawal,
777
- renderAssessment: () => renderAssessment,
778
750
  resolveCircuitsBase: () => resolveCircuitsBase,
779
- retryDelayMs: () => retryDelayMs,
780
751
  savePendingDeposit: () => savePendingDeposit,
781
752
  savePendingWithdrawal: () => savePendingWithdrawal,
782
753
  scanNotesForWallet: () => scanNotesForWallet,
@@ -809,19 +780,15 @@ __export(index_exports, {
809
780
  validateDepositParams: () => validateDepositParams,
810
781
  validateNote: () => validateNote,
811
782
  validateOutputsSum: () => validateOutputsSum,
812
- validatePaymasterTopUpTransaction: () => validatePaymasterTopUpTransaction,
813
783
  validateRoot: () => validateRoot,
814
784
  validateTransfers: () => validateTransfers,
815
785
  validateWalletConnected: () => validateWalletConnected,
816
786
  validateWithdrawableNote: () => validateWithdrawableNote,
817
787
  verifyAllCircuits: () => verifyAllCircuits,
818
788
  verifyCircuitIntegrity: () => verifyCircuitIntegrity,
819
- verifyQuoteSignature: () => verifyQuoteSignature,
820
789
  verifyUtxos: () => verifyUtxos,
821
790
  waitForRoot: () => waitForRoot,
822
- withShieldRetries: () => withShieldRetries,
823
- withTiming: () => withTiming,
824
- withdrawFeeFor: () => withdrawFeeFor
791
+ withTiming: () => withTiming
825
792
  });
826
793
  module.exports = __toCommonJS(index_exports);
827
794
 
@@ -1425,7 +1392,7 @@ function parseStrictViewingKeyChallenge(response, userPubkey, viewingKeyHex) {
1425
1392
 
1426
1393
  // src/config/relay.ts
1427
1394
  var CLOAK_PRODUCTION_RELAY_URL = "https://api.cloak.ag";
1428
- var RELAY_ORIGIN_ALLOWLIST = ["https://staging-api.cloak.ag"];
1395
+ var RELAY_ORIGIN_ALLOWLIST = [CLOAK_PRODUCTION_RELAY_URL];
1429
1396
  var ABSOLUTE_URL = /^[a-z][a-z0-9+.-]*:\/\//i;
1430
1397
  var LOOPBACK_IPV4 = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
1431
1398
  var THIS_NETWORK_IPV4 = /^0\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
@@ -2963,8 +2930,8 @@ async function verifyUtxos(utxos, connection, programId, commitment = "confirmed
2963
2930
  const nullifierHex = nullifierBig.toString(16).padStart(64, "0");
2964
2931
  const nullifierBytes = Buffer.from(nullifierHex, "hex");
2965
2932
  const { pool } = getShieldPoolPDAs(programId, utxo.mintAddress);
2966
- const [pda2] = getNullifierPDA(pool, nullifierBytes, programId);
2967
- checkable.push({ utxo, pda: pda2 });
2933
+ const [pda] = getNullifierPDA(pool, nullifierBytes, programId);
2934
+ checkable.push({ utxo, pda });
2968
2935
  } catch {
2969
2936
  skipped.push(utxo);
2970
2937
  }
@@ -3034,8 +3001,8 @@ function deriveInputNullifierPdas(programId, mint, inputNullifiers) {
3034
3001
  const pdas = [];
3035
3002
  for (const nullifier of inputNullifiers) {
3036
3003
  if (nullifier === BigInt(0)) continue;
3037
- const [pda2] = getNullifierPDA(pool, bigintToBytes324(nullifier), programId);
3038
- pdas.push(pda2);
3004
+ const [pda] = getNullifierPDA(pool, bigintToBytes324(nullifier), programId);
3005
+ pdas.push(pda);
3039
3006
  }
3040
3007
  return pdas;
3041
3008
  }
@@ -4354,7 +4321,7 @@ async function fetchWithRetry(url, options = {}) {
4354
4321
  const {
4355
4322
  timeoutMs = DEFAULT_TIMEOUT_MS,
4356
4323
  maxRetries = DEFAULT_MAX_RETRIES,
4357
- retryDelayMs: retryDelayMs2 = 1e3
4324
+ retryDelayMs = 1e3
4358
4325
  } = options;
4359
4326
  assertAllowedRelayOrigin(url);
4360
4327
  let lastError = null;
@@ -4378,7 +4345,7 @@ async function fetchWithRetry(url, options = {}) {
4378
4345
  `Relay request failed after ${attempt + 1} attempts: ${lastError.message}`
4379
4346
  );
4380
4347
  }
4381
- const delay = retryDelayMs2 * Math.pow(2, attempt) + Math.random() * 500;
4348
+ const delay = retryDelayMs * Math.pow(2, attempt) + Math.random() * 500;
4382
4349
  await new Promise((resolve) => setTimeout(resolve, delay));
4383
4350
  }
4384
4351
  }
@@ -7882,7 +7849,7 @@ async function transact(params, options) {
7882
7849
  // names is refused.
7883
7850
  maxRootRetries = 40,
7884
7851
  // Increased to handle prolonged relay sync recovery under high concurrency
7885
- retryDelayMs: retryDelayMs2 = 500,
7852
+ retryDelayMs = 500,
7886
7853
  // Start with short delay, will exponentially back off
7887
7854
  riskOracleQueue,
7888
7855
  riskQuoteUrl: riskQuoteUrlOption,
@@ -8304,7 +8271,7 @@ async function transact(params, options) {
8304
8271
  while (submissionAttempts <= maxRootRetries) {
8305
8272
  const isRetry = submissionAttempts > 0;
8306
8273
  if (isRetry) {
8307
- const exponentialDelay = Math.min(retryDelayMs2 * Math.pow(1.5, submissionAttempts - 1), 5e3);
8274
+ const exponentialDelay = Math.min(retryDelayMs * Math.pow(1.5, submissionAttempts - 1), 5e3);
8308
8275
  const jitter = Math.random() * 500;
8309
8276
  const totalDelay = Math.floor(exponentialDelay + jitter);
8310
8277
  await sleep2(totalDelay);
@@ -8467,7 +8434,7 @@ async function transact(params, options) {
8467
8434
  }
8468
8435
  treeState = null;
8469
8436
  useSiblingInfo = false;
8470
- const waitMs = Math.min(retryDelayMs2 * Math.pow(2, Math.min(submissionAttempts, 4)), 5e3);
8437
+ const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(submissionAttempts, 4)), 5e3);
8471
8438
  if (waitMs > 0) {
8472
8439
  onProgress?.(`Waiting ${waitMs}ms for relay sync before retry...`);
8473
8440
  await new Promise((r) => setTimeout(r, waitMs));
@@ -9161,7 +9128,7 @@ async function swapUtxo(params, options) {
9161
9128
  riskQuoteUrl: riskQuoteUrlOption,
9162
9129
  maxRootRetries = 40,
9163
9130
  // Increased to handle prolonged relay sync recovery under high concurrency
9164
- retryDelayMs: retryDelayMs2 = 500,
9131
+ retryDelayMs = 500,
9165
9132
  // Start with short delay, will exponentially back off
9166
9133
  useUniqueNullifiers,
9167
9134
  useChainRootForProof = true
@@ -9572,7 +9539,7 @@ async function swapUtxo(params, options) {
9572
9539
  let walletApprovals = 0;
9573
9540
  for (let attempt = 0; attempt <= maxRootRetries; attempt++) {
9574
9541
  if (attempt > 0) {
9575
- const exponentialDelay = Math.min(retryDelayMs2 * Math.pow(1.5, attempt - 1), 5e3);
9542
+ const exponentialDelay = Math.min(retryDelayMs * Math.pow(1.5, attempt - 1), 5e3);
9576
9543
  const jitter = Math.random() * 500;
9577
9544
  const totalDelay = Math.floor(exponentialDelay + jitter);
9578
9545
  await sleep2(totalDelay);
@@ -9710,7 +9677,7 @@ async function swapUtxo(params, options) {
9710
9677
  }
9711
9678
  merkleState = null;
9712
9679
  useSiblingInfo = false;
9713
- const waitMs = Math.min(retryDelayMs2 * Math.pow(2, Math.min(attempt, 4)), 5e3);
9680
+ const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(attempt, 4)), 5e3);
9714
9681
  if (waitMs > 0) {
9715
9682
  onProgress?.(`Waiting ${waitMs}ms for relay sync before retry...`);
9716
9683
  await new Promise((r) => setTimeout(r, waitMs));
@@ -11690,781 +11657,13 @@ var SimpleWallet = class {
11690
11657
  }
11691
11658
  };
11692
11659
 
11693
- // src/bridge/rail-verify.ts
11694
- var import_tweetnacl7 = __toESM(require("tweetnacl"), 1);
11695
- var import_sha256 = require("@noble/hashes/sha256");
11696
- var ONECLICK_PUBKEY_B58 = "reYaWhvwu8Jzo3WUM3zhn6VrhuMEF4eADL17qtRVifc";
11697
- var b58 = /* @__PURE__ */ (() => {
11698
- const A = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
11699
- return {
11700
- decode(s) {
11701
- let n = 0n;
11702
- for (const c of s) {
11703
- const i = A.indexOf(c);
11704
- if (i < 0) throw new Error("bad base58");
11705
- n = n * 58n + BigInt(i);
11706
- }
11707
- const bytes = [];
11708
- while (n > 0n) {
11709
- bytes.unshift(Number(n & 255n));
11710
- n >>= 8n;
11711
- }
11712
- for (const c of s) {
11713
- if (c === "1") bytes.unshift(0);
11714
- else break;
11715
- }
11716
- return Uint8Array.from(bytes);
11717
- },
11718
- encode(b) {
11719
- let n = 0n;
11720
- for (const x of b) n = n * 256n + BigInt(x);
11721
- let s = "";
11722
- while (n > 0n) {
11723
- s = A[Number(n % 58n)] + s;
11724
- n /= 58n;
11725
- }
11726
- for (const x of b) {
11727
- if (x === 0) s = "1" + s;
11728
- else break;
11729
- }
11730
- return s;
11731
- }
11732
- };
11733
- })();
11734
- function stable(v) {
11735
- if (v === null || typeof v !== "object") return JSON.stringify(v) ?? "null";
11736
- if (Array.isArray(v)) return `[${v.map(stable).join(",")}]`;
11737
- const o = v;
11738
- const parts = Object.keys(o).sort().filter((k) => o[k] !== void 0).map((k) => `${JSON.stringify(k)}:${stable(o[k])}`);
11739
- return `{${parts.join(",")}}`;
11740
- }
11741
- function signedRequest(r) {
11742
- const q = r.quoteRequest ?? {};
11743
- return {
11744
- dry: q.dry,
11745
- swapType: q.swapType,
11746
- slippageTolerance: q.slippageTolerance,
11747
- originAsset: q.originAsset,
11748
- depositType: q.depositType,
11749
- destinationAsset: q.destinationAsset,
11750
- amount: q.amount,
11751
- refundTo: q.refundTo,
11752
- refundType: q.refundType,
11753
- recipient: q.recipient,
11754
- recipientType: q.recipientType,
11755
- deadline: q.deadline,
11756
- quoteWaitingTimeMs: q.quoteWaitingTimeMs || void 0,
11757
- referral: q.referral || void 0,
11758
- virtualChainRecipient: q.virtualChainRecipient || void 0,
11759
- virtualChainRefundRecipient: q.virtualChainRefundRecipient || void 0,
11760
- customRecipientMsg: q.customRecipientMsg || void 0
11761
- // Deliberately unsigned by the rail: sessionId, connectedWallets, correlationId, appFees,
11762
- // partnerId, userAccountId, depositMode. APP FEES ARE NOT AUTHENTICATED — never display a fee
11763
- // caption as if the signature vouched for it.
11764
- };
11765
- }
11766
- function signedQuote(r) {
11767
- const q = r.quote ?? {};
11768
- const base = {
11769
- amountIn: q.amountIn,
11770
- amountInFormatted: q.amountInFormatted,
11771
- amountInUsd: q.amountInUsd,
11772
- minAmountIn: q.minAmountIn,
11773
- amountOut: q.amountOut,
11774
- amountOutFormatted: q.amountOutFormatted,
11775
- amountOutUsd: q.amountOutUsd,
11776
- minAmountOut: q.minAmountOut
11777
- };
11778
- if (r.quoteRequest?.dry) return base;
11779
- return {
11780
- ...base,
11781
- depositAddress: q.depositAddress || void 0,
11782
- // <- the field that makes substitution detectable
11783
- depositMemo: q.depositMemo || void 0,
11784
- deadline: q.deadline || void 0,
11785
- // <- a real, SIGNED expiry
11786
- timeWhenInactive: q.timeWhenInactive || void 0,
11787
- timeEstimate: q.timeEstimate || void 0,
11788
- virtualChainRecipient: q.virtualChainRecipient || void 0,
11789
- virtualChainRefundRecipient: q.virtualChainRefundRecipient || void 0,
11790
- customRecipientMsg: q.customRecipientMsg || void 0,
11791
- refundFee: q.refundFee || void 0,
11792
- withdrawFee: q.withdrawFee || void 0
11793
- };
11794
- }
11795
- function canonicalPayloadString(resp) {
11796
- return stable({ ...signedRequest(resp), ...signedQuote(resp), timestamp: resp.timestamp });
11797
- }
11798
- function verifyQuoteSignature(resp) {
11799
- if (!resp?.signature) return { valid: false, reason: "no signature on the response" };
11800
- const payload = { ...signedRequest(resp), ...signedQuote(resp), timestamp: resp.timestamp };
11801
- const digest = (0, import_sha256.sha256)(new TextEncoder().encode(stable(payload)));
11802
- const message = new TextEncoder().encode(b58.encode(new Uint8Array(digest)));
11803
- const sig = resp.signature.replace(/^ed25519:/, "");
11804
- try {
11805
- return { valid: import_tweetnacl7.default.sign.detached.verify(message, b58.decode(sig), b58.decode(ONECLICK_PUBKEY_B58)) };
11806
- } catch (e) {
11807
- return { valid: false, reason: e instanceof Error ? e.message : String(e) };
11808
- }
11809
- }
11810
-
11811
- // src/bridge/rails.ts
11812
- async function parseBridgeResponse(res, what) {
11813
- let body;
11814
- try {
11815
- body = await res.json();
11816
- } catch {
11817
- throw new Error(`${what} failed: ${res.status} ${res.statusText} (response body was not JSON)`);
11818
- }
11819
- if (!res.ok) {
11820
- const b = body ?? {};
11821
- throw new Error(
11822
- `${what} failed: ${b.message ?? res.statusText} (${b.code ?? res.status}${b.retryable ? ", retryable" : ""})`
11823
- );
11824
- }
11825
- return body;
11826
- }
11827
- function toAttestation(raw) {
11828
- if (raw.kind === "ed25519") {
11829
- return { kind: "ed25519", verified: raw.verified ?? false, signer: raw.signer ?? "" };
11830
- }
11831
- return { kind: "none", checks: raw.checks ?? [], note: raw.note ?? "" };
11832
- }
11833
- async function fetchBridgeQuote(relayUrl, req) {
11834
- const body = {
11835
- recipient: req.recipient,
11836
- origin_chain: req.originChain,
11837
- amount_base_units: req.amountBaseUnits.toString(),
11838
- allocate: req.allocate ?? false
11839
- };
11840
- if (req.refundTo !== void 0) body.refund_to = req.refundTo;
11841
- if (req.rails !== void 0) body.rails = req.rails;
11842
- const res = await relayFetch(`${relayUrl}/bridge/quote`, {
11843
- method: "POST",
11844
- headers: { "Content-Type": "application/json" },
11845
- body: JSON.stringify(body)
11846
- });
11847
- const raw = await parseBridgeResponse(res, "bridge quote");
11848
- const options = [];
11849
- const unavailable = (raw.unavailable ?? []).map((p) => ({
11850
- rail: p.rail,
11851
- reason: p.reason
11852
- }));
11853
- for (const opt of raw.options) {
11854
- const attestation = toAttestation(opt.attestation);
11855
- if (attestation.kind === "ed25519") {
11856
- const verdict = opt.rail_response ? verifyQuoteSignature(opt.rail_response) : { valid: false, reason: "no rail_response to verify against" };
11857
- if (!verdict.valid) {
11858
- unavailable.push({
11859
- rail: opt.rail,
11860
- reason: `deposit address failed independent signature verification, refusing to display it (${verdict.reason ?? "signature did not verify"})`
11861
- });
11862
- continue;
11863
- }
11864
- }
11865
- options.push({
11866
- rail: opt.rail,
11867
- refunds: opt.refunds,
11868
- addressLifetime: opt.address_lifetime,
11869
- amountOut: BigInt(opt.amount_out),
11870
- minAmountOut: BigInt(opt.min_amount_out),
11871
- timeEstimateSeconds: opt.time_estimate_s,
11872
- expiresAt: opt.expires_at,
11873
- depositAddress: opt.deposit_address,
11874
- attestation
11875
- });
11876
- }
11877
- return { options, unavailable };
11878
- }
11879
- var STATUS_STATES = [
11880
- "pending",
11881
- "delivered",
11882
- "refunded",
11883
- "expired",
11884
- "unknown"
11885
- ];
11886
- async function fetchBridgeStatus(relayUrl, depositAddress, rail) {
11887
- const qs = new URLSearchParams({ deposit_address: depositAddress, rail });
11888
- const res = await relayFetch(`${relayUrl}/bridge/status?${qs.toString()}`);
11889
- const raw = await parseBridgeResponse(res, "bridge status");
11890
- const state = STATUS_STATES.includes(raw.state ?? "") ? raw.state : "unknown";
11891
- return { rail: raw.rail ?? rail, state, detail: raw.detail ?? "" };
11892
- }
11893
- function cloakBridgeRail(relayUrl) {
11894
- assertAllowedRelayOrigin(relayUrl);
11895
- return {
11896
- id: "cloak-bridge",
11897
- quote: (req) => fetchBridgeQuote(relayUrl, req),
11898
- status: (depositAddress, rail) => fetchBridgeStatus(relayUrl, depositAddress, rail)
11899
- };
11900
- }
11901
-
11902
- // src/bridge/paymaster-client.ts
11903
- var import_web312 = require("@solana/web3.js");
11904
- var import_spl_token3 = require("@solana/spl-token");
11905
- function validatePaymasterTopUpTransaction(tx, expect) {
11906
- const ixs = tx.instructions;
11907
- if (ixs.length !== 1 && ixs.length !== 2) {
11908
- throw new Error(
11909
- `paymaster top-up must be exactly 1 or 2 instructions, got ${ixs.length} \u2014 refusing to sign a transaction whose shape does not match the documented top-up contract`
11910
- );
11911
- }
11912
- const ix0 = ixs[0];
11913
- if (!ix0.programId.equals(import_web312.SystemProgram.programId)) {
11914
- throw new Error(
11915
- `paymaster top-up instruction 0 is owned by ${ix0.programId.toBase58()}, not the System Program \u2014 refusing to sign an unrecognised first instruction`
11916
- );
11917
- }
11918
- const transfer2 = import_web312.SystemInstruction.decodeTransfer(ix0);
11919
- if (!transfer2.toPubkey.equals(expect.recipient)) {
11920
- throw new Error(
11921
- `paymaster top-up sends SOL to ${transfer2.toPubkey.toBase58()}, which is not our recipient ${expect.recipient.toBase58()} \u2014 refusing to sign a transaction that funds a key we do not control`
11922
- );
11923
- }
11924
- if (BigInt(transfer2.lamports) > expect.maxGrantLamports) {
11925
- throw new Error(
11926
- `paymaster top-up grants ${transfer2.lamports} lamports, more than the ${expect.maxGrantLamports} we asked for \u2014 refusing a transaction that funds beyond our own request`
11927
- );
11928
- }
11929
- if (ixs.length === 1) return;
11930
- const ix1 = ixs[1];
11931
- if (!ix1.programId.equals(import_spl_token3.TOKEN_PROGRAM_ID)) {
11932
- throw new Error(
11933
- `paymaster top-up instruction 1 is owned by ${ix1.programId.toBase58()}, not the SPL Token program \u2014 refusing to sign an unrecognised second instruction`
11934
- );
11935
- }
11936
- const spl = (0, import_spl_token3.decodeTransferInstruction)(ix1, import_spl_token3.TOKEN_PROGRAM_ID);
11937
- const authority = spl.keys.owner.pubkey;
11938
- if (!authority.equals(expect.recipient)) {
11939
- throw new Error(
11940
- `paymaster top-up's fee transfer is authorised by ${authority.toBase58()}, not our recipient ${expect.recipient.toBase58()} \u2014 refusing to sign away tokens from an account we do not control`
11941
- );
11942
- }
11943
- const expectedDestination = (0, import_spl_token3.getAssociatedTokenAddressSync)(
11944
- expect.feeMint,
11945
- expect.paymentAddress,
11946
- false
11947
- );
11948
- const destination = spl.keys.destination.pubkey;
11949
- if (!destination.equals(expectedDestination)) {
11950
- throw new Error(
11951
- `paymaster top-up's fee transfer is addressed to ${destination.toBase58()}, not the paymaster's own payment ATA ${expectedDestination.toBase58()} \u2014 refusing to sign a payment to an unverified destination`
11952
- );
11953
- }
11954
- const paidAmount = BigInt(spl.data.amount);
11955
- if (paidAmount !== expect.feeTokenAmount) {
11956
- throw new Error(
11957
- `paymaster top-up's fee amount is ${paidAmount}, not the ${expect.feeTokenAmount} Kora quoted at prepare time \u2014 refusing to sign a payment that does not match the quote`
11958
- );
11959
- }
11960
- }
11961
- async function parseBridgeResponse2(res, what) {
11962
- let body;
11963
- try {
11964
- body = await res.json();
11965
- } catch {
11966
- throw new Error(`${what} failed: ${res.status} ${res.statusText} (response body was not JSON)`);
11967
- }
11968
- if (!res.ok) {
11969
- const b = body ?? {};
11970
- throw new Error(
11971
- `${what} failed: ${b.message ?? res.statusText} (${b.code ?? res.status}${b.retryable ? ", retryable" : ""})`
11972
- );
11973
- }
11974
- return body;
11975
- }
11976
- async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
11977
- assertAllowedRelayOrigin(relayUrl);
11978
- if (grantLamports <= 0n || grantLamports > BigInt(Number.MAX_SAFE_INTEGER)) {
11979
- throw new Error(
11980
- `grantLamports must be a positive value representable as a JS number, got ${grantLamports}`
11981
- );
11982
- }
11983
- const prepareRes = await relayFetch(`${relayUrl}/bridge/paymaster/prepare`, {
11984
- method: "POST",
11985
- headers: { "Content-Type": "application/json" },
11986
- body: JSON.stringify({
11987
- recipient: receiver.publicKey.toBase58(),
11988
- grant_lamports: Number(grantLamports)
11989
- })
11990
- });
11991
- const prepared = await parseBridgeResponse2(prepareRes, "paymaster prepare");
11992
- if (Math.floor(Date.now() / 1e3) >= prepared.expires_at_unix) {
11993
- throw new Error(
11994
- "paymaster prepare returned a voucher that is already expired \u2014 refusing to sign a stale top-up rather than fail confusingly at cosign"
11995
- );
11996
- }
11997
- const feeMint = new import_web312.PublicKey(prepared.fee_mint);
11998
- const paymentAddress = new import_web312.PublicKey(prepared.payment_address);
11999
- const feeTokenAmount = BigInt(prepared.fee_token_amount);
12000
- const tx = import_web312.Transaction.from(Buffer.from(prepared.transaction, "base64"));
12001
- validatePaymasterTopUpTransaction(tx, {
12002
- recipient: receiver.publicKey,
12003
- maxGrantLamports: grantLamports,
12004
- feeMint,
12005
- feeTokenAmount,
12006
- paymentAddress
12007
- });
12008
- tx.partialSign(receiver);
12009
- const cosignRes = await relayFetch(`${relayUrl}/bridge/paymaster/cosign`, {
12010
- method: "POST",
12011
- headers: { "Content-Type": "application/json" },
12012
- body: JSON.stringify({
12013
- transaction: tx.serialize({ requireAllSignatures: false, verifySignatures: false }).toString("base64"),
12014
- voucher: prepared.voucher
12015
- })
12016
- });
12017
- const cosigned = await parseBridgeResponse2(cosignRes, "paymaster cosign");
12018
- return {
12019
- transaction: import_web312.Transaction.from(Buffer.from(cosigned.transaction, "base64")),
12020
- feeTokenAmount,
12021
- feeMint: prepared.fee_mint,
12022
- paymentAddress: prepared.payment_address
12023
- };
12024
- }
12025
-
12026
- // src/bridge/derive.ts
12027
- var import_web313 = require("@solana/web3.js");
12028
- var import_hmac = require("@noble/hashes/hmac");
12029
- var import_sha512 = require("@noble/hashes/sha512");
12030
- var BRIDGE_ESCROW_LABEL = "cloak_bridge_escrow";
12031
- var MAX_RECEIVER_INDEX = 1e4;
12032
- function deriveBridgeReceiver(nk, index) {
12033
- if (!Number.isInteger(index) || index < 0) {
12034
- throw new Error(`index must be a non-negative integer, got ${index}`);
12035
- }
12036
- if (index > MAX_RECEIVER_INDEX) {
12037
- throw new Error(
12038
- `index ${index} exceeds MAX_RECEIVER_INDEX (${MAX_RECEIVER_INDEX}). Indices must be a small sequential counter \u2014 discovery derives 0\u2026N and reads each on chain, so a timestamp index is unreachable by any scan and the deposit would be invisible to every device but this one.`
12039
- );
12040
- }
12041
- const h = (0, import_hmac.hmac)(import_sha512.sha512, new Uint8Array(nk), new TextEncoder().encode(`${BRIDGE_ESCROW_LABEL}:${index}`));
12042
- return import_web313.Keypair.fromSeed(h.slice(0, 32));
12043
- }
12044
-
12045
- // src/bridge/discover.ts
12046
- var import_web314 = require("@solana/web3.js");
12047
- var import_spl_token4 = require("@solana/spl-token");
12048
- function describeError(err) {
12049
- return err instanceof Error ? err.message : String(err);
12050
- }
12051
- async function listBridgeDeposits(conn, nk, opts) {
12052
- const scanDepth = Math.min(opts.scanDepth ?? 20, MAX_RECEIVER_INDEX + 1);
12053
- const stopAfterUnused = opts.stopAfterUnused ?? 5;
12054
- const out = [];
12055
- let consecutiveUnused = 0;
12056
- for (let index = 0; index < scanDepth; index++) {
12057
- const kp = deriveBridgeReceiver(nk, index);
12058
- const receiver = kp.publicKey;
12059
- const tokenAccount = (0, import_spl_token4.getAssociatedTokenAddressSync)(opts.mint, receiver, false);
12060
- try {
12061
- const [recvInfo, ataInfo] = await conn.getMultipleAccountsInfo([receiver, tokenAccount]);
12062
- const lamports = recvInfo?.lamports ?? 0;
12063
- let tokenBalance = 0n;
12064
- if (ataInfo) {
12065
- try {
12066
- tokenBalance = BigInt((await conn.getTokenAccountBalance(tokenAccount)).value.amount);
12067
- } catch (err) {
12068
- if (!(err instanceof import_web314.SolanaJSONRPCError && /could not find account/i.test(err.message))) {
12069
- throw err;
12070
- }
12071
- }
12072
- }
12073
- if (lamports === 0 && !ataInfo) {
12074
- consecutiveUnused++;
12075
- if (consecutiveUnused >= stopAfterUnused) break;
12076
- continue;
12077
- }
12078
- consecutiveUnused = 0;
12079
- const shieldSignatures = [];
12080
- const sigs = await conn.getSignaturesForAddress(receiver, { limit: 20 });
12081
- for (const s of sigs) {
12082
- if (s.err) continue;
12083
- const tx = await conn.getTransaction(s.signature, { maxSupportedTransactionVersion: 0 });
12084
- const keys = tx?.transaction.message.getAccountKeys({
12085
- accountKeysFromLookups: tx.meta?.loadedAddresses
12086
- });
12087
- if (keys && [...Array(keys.length).keys()].some((i) => keys.get(i)?.equals(opts.programId))) {
12088
- shieldSignatures.push(s.signature);
12089
- }
12090
- }
12091
- const shieldSignature = shieldSignatures[0];
12092
- const indexReused = shieldSignatures.length > 1;
12093
- let state;
12094
- if (tokenBalance > 0n) state = shieldSignature ? "needs-cleanup" : "arrived";
12095
- else if (shieldSignature) state = ataInfo ? "needs-cleanup" : "complete";
12096
- else state = "awaiting";
12097
- out.push({
12098
- index,
12099
- receiver,
12100
- tokenAccount,
12101
- state,
12102
- tokenBalance,
12103
- lamports,
12104
- shieldSignature,
12105
- ...indexReused ? { indexReused, shieldSignatures } : {}
12106
- });
12107
- } catch (err) {
12108
- out.push({
12109
- index,
12110
- receiver,
12111
- tokenAccount,
12112
- state: "unknown",
12113
- tokenBalance: 0n,
12114
- lamports: 0,
12115
- error: describeError(err)
12116
- });
12117
- }
12118
- }
12119
- return out;
12120
- }
12121
-
12122
- // src/bridge/deposit-core.ts
12123
- var import_web316 = require("@solana/web3.js");
12124
- var import_tweetnacl8 = __toESM(require("tweetnacl"), 1);
12125
- init_utxo();
12126
-
12127
- // src/bridge/funder.ts
12128
- var import_web315 = require("@solana/web3.js");
12129
- var import_spl_token5 = require("@solana/spl-token");
12130
- var MAINNET_RENT_0 = 890880;
12131
- var MAINNET_RENT_1 = 897840;
12132
- var FEE_BUDGET = 13e4;
12133
- var CLEANUP_FEE_BUDGET = 5e3;
12134
- var pda = (seeds, programId) => import_web315.PublicKey.findProgramAddressSync(seeds.map((s) => Buffer.from(s)), programId)[0];
12135
- function deriveFundingTargets(d) {
12136
- const pool = pda([Buffer.from("pool"), d.mint.toBuffer()], d.programId);
12137
- return {
12138
- pool,
12139
- // program: NullifierAccount::derive_pda_with_pool -> [b"nullifier", pool, nullifier]
12140
- nullifier0: pda([Buffer.from("nullifier"), pool.toBuffer(), d.nullifiers[0]], d.programId),
12141
- nullifier1: pda([Buffer.from("nullifier"), pool.toBuffer(), d.nullifiers[1]], d.programId),
12142
- // relay: derive_risk_nonce_pda -> [b"risk_nonce", bind0]
12143
- riskNonce: pda([Buffer.from("risk_nonce"), d.bind0], d.programId),
12144
- depositorAta: (0, import_spl_token5.getAssociatedTokenAddressSync)(d.mint, d.depositor, false)
12145
- };
12146
- }
12147
- async function readRent(conn) {
12148
- const [zero, one] = await Promise.all([
12149
- conn.getMinimumBalanceForRentExemption(0),
12150
- conn.getMinimumBalanceForRentExemption(1)
12151
- ]);
12152
- return { zero, one };
12153
- }
12154
-
12155
- // src/bridge/deposit-core.ts
12156
- var DepositError = class extends Error {
12157
- constructor(message, fundedAccounts, measuredTxSize) {
12158
- super(message);
12159
- this.fundedAccounts = fundedAccounts;
12160
- this.measuredTxSize = measuredTxSize;
12161
- this.name = "DepositError";
12162
- }
12163
- };
12164
- async function depositFromDerivedKey(conn, R, funder, amount, log = console.log, grantOverride, opts) {
12165
- if (!opts.noteSpendKey || opts.noteSpendKey.length !== 32) {
12166
- throw new Error(
12167
- "opts.noteSpendKey (32 bytes) is required. It derives the note's spending key, and a note whose key is not derived from something you can reproduce is unspendable forever. Pass the same Cloak seed you derived the receiving address from."
12168
- );
12169
- }
12170
- if (!opts.relayUrl) {
12171
- throw new Error(
12172
- "opts.relayUrl is required. There is no default: a missing relay used to resolve silently to the local stack, which is how a live run built a deposit against infrastructure that only existed on someone's laptop. Say which relay, every call."
12173
- );
12174
- }
12175
- if (!opts.programId) {
12176
- throw new Error(
12177
- "opts.programId is required. There is no default: this is the exact field a live mainnet run once inherited from this module's local-stack constant, built a deposit against a program that does not exist on mainnet, and failed hunting a merkle tree that was never there."
12178
- );
12179
- }
12180
- if (!opts.mint) {
12181
- throw new Error(
12182
- "opts.mint is required. There is no default: a deposit built for the wrong mint produces a note for an asset that never arrived at R, and there is nothing to silently fall back to."
12183
- );
12184
- }
12185
- assertAllowedRpcConnection(conn);
12186
- const relayUrl = opts.relayUrl;
12187
- const programId = opts.programId;
12188
- const mint = opts.mint;
12189
- setCircuitsPath(resolveCircuitsBase());
12190
- const grantR = grantOverride ?? MAINNET_RENT_0 + FEE_BUDGET + CLEANUP_FEE_BUDGET;
12191
- const heldByR = await conn.getBalance(R.publicKey);
12192
- if (heldByR >= grantR) {
12193
- log(` R already holds ${heldByR} (>= ${grantR}) \u2014 no top-up needed`);
12194
- } else {
12195
- await (0, import_web316.sendAndConfirmTransaction)(conn, new import_web316.Transaction().add(
12196
- import_web316.SystemProgram.transfer({ fromPubkey: funder.publicKey, toPubkey: R.publicKey, lamports: grantR - heldByR })
12197
- ), [funder]);
12198
- log(` funder topped R up by ${grantR - heldByR} to ${grantR}${grantOverride !== void 0 ? " (OVERRIDDEN for a deliberate test)" : " \u2014 floor + deposit fee + cleanup fee, no rent"}`);
12199
- }
12200
- let measuredSize = -1;
12201
- let fundedAccounts = [];
12202
- const signTransaction2 = async (tx) => {
12203
- if (tx instanceof import_web316.VersionedTransaction) {
12204
- measuredSize = tx.serialize().length;
12205
- const alts = await Promise.all(
12206
- tx.message.addressTableLookups.map(async (l) => (await conn.getAddressLookupTable(l.accountKey)).value)
12207
- );
12208
- const keys = tx.message.getAccountKeys({ addressLookupTableAccounts: alts });
12209
- const ix = tx.message.compiledInstructions.find((i) => keys.get(i.programIdIndex).equals(programId));
12210
- const at = (n) => keys.get(ix.accountKeyIndexes[n]);
12211
- const targets = [
12212
- { a: at(12), need: MAINNET_RENT_0, name: "risk_nonce" },
12213
- { a: at(4), need: MAINNET_RENT_1, name: "nullifier_0" },
12214
- { a: at(5), need: MAINNET_RENT_1, name: "nullifier_1" }
12215
- ];
12216
- const infos = await conn.getMultipleAccountsInfo(targets.map((t) => t.a));
12217
- fundedAccounts = targets.map((t, i) => ({
12218
- name: t.name,
12219
- address: t.a.toBase58(),
12220
- lamportsSent: Math.max(0, t.need - (infos[i]?.lamports ?? 0))
12221
- }));
12222
- const ixs = targets.flatMap((t, i) => (infos[i]?.lamports ?? 0) >= t.need ? [] : [import_web316.SystemProgram.transfer({
12223
- fromPubkey: funder.publicKey,
12224
- toPubkey: t.a,
12225
- lamports: t.need - (infos[i]?.lamports ?? 0)
12226
- })]);
12227
- if (ixs.length) {
12228
- const sig = await (0, import_web316.sendAndConfirmTransaction)(conn, new import_web316.Transaction().add(...ixs), [funder]);
12229
- log(` seam: funded ${ixs.length} program accounts read off the built tx \u2014 ${sig.slice(0, 16)}\u2026`);
12230
- }
12231
- tx.sign([R]);
12232
- return tx;
12233
- }
12234
- tx.partialSign(R);
12235
- return tx;
12236
- };
12237
- const signMessage = async (m) => import_tweetnacl8.default.sign.detached(m, R.secretKey);
12238
- const utxoKeypair = await deriveUtxoKeypairFromSpendKey(opts.noteSpendKey);
12239
- const nk = getNkFromUtxoPrivateKey(utxoKeypair.privateKey);
12240
- const { utxo, noteSalt } = await createRecoverableDepositUtxo(amount, nk, mint);
12241
- const zeroInput = await createZeroUtxo(mint);
12242
- const rBefore = await conn.getBalance(R.publicKey);
12243
- let result;
12244
- try {
12245
- result = await transact(
12246
- { inputUtxos: [zeroInput], outputUtxos: [utxo], externalAmount: amount, depositor: R.publicKey },
12247
- {
12248
- connection: conn,
12249
- programId,
12250
- relayUrl,
12251
- // NO depositorKeypair: the SDK branches `if (keypair) … else if (signTransaction)`
12252
- // (transact.ts:2786, :2936), so passing one silently skips the funding seam.
12253
- depositorPublicKey: R.publicKey,
12254
- walletPublicKey: R.publicKey,
12255
- signTransaction: signTransaction2,
12256
- signMessage,
12257
- chainNoteViewingKeyNk: nk,
12258
- chainNoteSalt: noteSalt,
12259
- relaySupplementalAlt: true,
12260
- onProgress: (s) => log(` \xB7 ${s}`)
12261
- }
12262
- );
12263
- } catch (e) {
12264
- const msg = e instanceof Error ? e.message : String(e);
12265
- throw new DepositError(msg, fundedAccounts, measuredSize);
12266
- }
12267
- const rAfter = await conn.getBalance(R.publicKey);
12268
- const noteIndex = result.outputUtxos[0].index;
12269
- if (noteIndex === void 0) throw new Error("deposit landed but the note has no index \u2014 it cannot be discovered later");
12270
- return {
12271
- signature: result.signature,
12272
- noteIndex,
12273
- amount: result.outputUtxos[0].amount,
12274
- txSize: measuredSize,
12275
- rBefore,
12276
- rAfter,
12277
- rentExempt: rAfter >= MAINNET_RENT_0,
12278
- inputNullifiers: result.inputNullifiers,
12279
- fundedAccounts
12280
- };
12281
- }
12282
-
12283
- // src/bridge/cleanup.ts
12284
- var import_web317 = require("@solana/web3.js");
12285
- var import_spl_token6 = require("@solana/spl-token");
12286
- var DEFAULT_MINT = new import_web317.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
12287
- async function cleanupReceivingAddress(conn, R, dustDestination, mint = DEFAULT_MINT) {
12288
- assertAllowedRpcConnection(conn);
12289
- const rAta = (0, import_spl_token6.getAssociatedTokenAddressSync)(mint, R.publicKey);
12290
- const info = await conn.getAccountInfo(rAta);
12291
- if (!info) {
12292
- return {
12293
- closed: false,
12294
- dustSwept: 0n,
12295
- rentReturned: 0,
12296
- destination: null,
12297
- signature: null,
12298
- note: "no token account \u2014 nothing to recover"
12299
- };
12300
- }
12301
- const bal = BigInt((await conn.getTokenAccountBalance(rAta)).value.amount);
12302
- const rentHeld = info.lamports;
12303
- const before = await conn.getBalance(R.publicKey);
12304
- const ixs = [];
12305
- let destination = null;
12306
- if (bal > 0n && !dustDestination) {
12307
- return {
12308
- closed: false,
12309
- dustSwept: 0n,
12310
- rentReturned: 0,
12311
- destination: null,
12312
- signature: null,
12313
- note: `dusted with ${bal} base units after the deposit; leaving the account open and ${rentHeld.toLocaleString()} lamports of rent unrecovered, because sweeping it would publish a link from this deposit to whoever receives it`
12314
- };
12315
- }
12316
- if (bal > 0n && dustDestination) {
12317
- const destAta = (0, import_spl_token6.getAssociatedTokenAddressSync)(mint, dustDestination);
12318
- const destInfo = await conn.getAccountInfo(destAta);
12319
- if (!destInfo) {
12320
- const ataRent = await (0, import_spl_token6.getMinimumBalanceForRentExemptAccount)(conn);
12321
- if (before < ataRent + CLEANUP_FEE_BUDGET) {
12322
- throw new Error(
12323
- `dustDestination ${dustDestination.toBase58()} has no token account for mint ${mint.toBase58()}, and creating one costs ${ataRent} lamports of rent that R does not have: R holds ${before}, which deposit-core.ts reserved only for this transaction's own fee (CLEANUP_FEE_BUDGET = ${CLEANUP_FEE_BUDGET} in funder.ts), not for a fresh account's rent. Fund R with at least ${ataRent + CLEANUP_FEE_BUDGET - before} more lamports first, or choose a destination that already has a token account for this mint.`
12324
- );
12325
- }
12326
- ixs.push((0, import_spl_token6.createAssociatedTokenAccountIdempotentInstruction)(R.publicKey, destAta, dustDestination, mint));
12327
- }
12328
- ixs.push((0, import_spl_token6.createTransferInstruction)(rAta, destAta, R.publicKey, bal));
12329
- destination = destAta.toBase58();
12330
- }
12331
- ixs.push((0, import_spl_token6.createCloseAccountInstruction)(rAta, R.publicKey, R.publicKey));
12332
- const signature = await (0, import_web317.sendAndConfirmTransaction)(conn, new import_web317.Transaction().add(...ixs), [R], {
12333
- commitment: "confirmed"
12334
- });
12335
- const after = await conn.getBalance(R.publicKey);
12336
- const gone = await conn.getAccountInfo(rAta) === null;
12337
- return {
12338
- closed: gone,
12339
- dustSwept: bal,
12340
- rentReturned: after - before,
12341
- destination,
12342
- signature,
12343
- note: bal > 0n ? `swept ${bal} base units of dust to the caller-chosen destination and closed, in one transaction \u2014 note this publishes a link from the deposit to that destination` : `closed cleanly, nothing to sweep`
12344
- };
12345
- }
12346
-
12347
- // src/bridge/quote.ts
12348
- var MIN_DEPOSIT_SPL_BASE_UNITS = 1000000n;
12349
- var WITHDRAW_FIXED_FEE = 450000n;
12350
- var WITHDRAW_FEE_BPS = 30n;
12351
- function withdrawFeeAt(amount, fixedFee, feeBps) {
12352
- return fixedFee + amount * feeBps / 10000n;
12353
- }
12354
- var MAX_FEE_FRACTION = 0.063;
12355
- var FIXED_ROUND_TRIP = 903000n;
12356
- var ECONOMIC_MINIMUM = FIXED_ROUND_TRIP * 1000000n / BigInt(Math.round((MAX_FEE_FRACTION - 3e-3) * 1e6));
12357
- function withdrawFeeFor(amount) {
12358
- return withdrawFeeAt(amount, WITHDRAW_FIXED_FEE, WITHDRAW_FEE_BPS);
12359
- }
12360
- function assessBridgeQuote(q) {
12361
- if (q.sent < 0n) {
12362
- throw new Error(`assessBridgeQuote: sent must not be negative (got ${q.sent}).`);
12363
- }
12364
- if (q.arrivesMin > q.sent) {
12365
- throw new Error(
12366
- `assessBridgeQuote: arrivesMin (${q.arrivesMin}) exceeds sent (${q.sent}) \u2014 no rail returns more than it was given, so this input did not come from a real quote.`
12367
- );
12368
- }
12369
- const shieldedMinRaw = q.arrivesMin - q.paymasterFee;
12370
- const shieldedTargetRaw = q.arrivesTarget - q.paymasterFee;
12371
- const shieldedMin = shieldedMinRaw > 0n ? shieldedMinRaw : 0n;
12372
- const shieldedTarget = shieldedTargetRaw > 0n ? shieldedTargetRaw : 0n;
12373
- const viable = shieldedMinRaw >= MIN_DEPOSIT_SPL_BASE_UNITS;
12374
- const economic = q.sent >= ECONOMIC_MINIMUM;
12375
- const withdrawFee = shieldedMin > 0n ? withdrawFeeAt(shieldedMin, q.liveWithdrawFixedFee ?? WITHDRAW_FIXED_FEE, q.liveWithdrawFeeBps ?? WITHDRAW_FEE_BPS) : 0n;
12376
- const roundTripCost = q.sent - (shieldedMin > withdrawFee ? shieldedMin - withdrawFee : 0n);
12377
- const roundTripFraction = q.sent > 0n ? Number(roundTripCost) / Number(q.sent) : 0;
12378
- const reasons = [];
12379
- if (!viable) {
12380
- const short = MIN_DEPOSIT_SPL_BASE_UNITS - shieldedMinRaw;
12381
- reasons.push(
12382
- (shieldedMinRaw <= 0n ? `The ${fmt(q.paymasterFee)} paymaster fee alone is ${shieldedMinRaw < 0n ? `${fmt(-shieldedMinRaw)} more than` : "all of"} the ${fmt(q.arrivesMin)} the rail guarantees, so nothing would be left to shield.` : `Only ${fmt(shieldedMinRaw)} would be left to shield after the ${fmt(q.paymasterFee)} paymaster fee.`) + ` The program's minimum deposit is ${fmt(MIN_DEPOSIT_SPL_BASE_UNITS)}. Send at least ${fmt(q.sent + short)} to clear it.`
12383
- );
12384
- }
12385
- if (viable && !economic) {
12386
- reasons.push(
12387
- `This works, but ${fmt(roundTripCost)} of ${fmt(q.sent)} goes to fees (${(roundTripFraction * 100).toFixed(0)}%). The costs are almost all fixed, so bridging ${fmt(ECONOMIC_MINIMUM)} or more spreads them much further.`
12388
- );
12389
- }
12390
- return {
12391
- ...q,
12392
- shieldedMin,
12393
- shieldedTarget,
12394
- viable,
12395
- economic,
12396
- withdrawFee,
12397
- roundTripCost,
12398
- roundTripFraction,
12399
- reasons
12400
- };
12401
- }
12402
- var fmt = (v) => `${(Number(v) / 1e6).toFixed(6)} USDC`;
12403
- function renderAssessment(a) {
12404
- const L = [];
12405
- L.push(` you send ${fmt(a.sent)}`);
12406
- L.push(` arrives at least ${fmt(a.arrivesMin)} (target ${fmt(a.arrivesTarget)}, not a promise)`);
12407
- L.push(` paymaster fee ${fmt(a.paymasterFee)} buys the receiver its SOL, so your wallet stays off chain`);
12408
- L.push(` SHIELDED ${fmt(a.shieldedMin)} at least \u2014 this is what you end up with`);
12409
- L.push(` to withdraw later ${fmt(a.withdrawFee)} the program's fee, whenever you take it out`);
12410
- for (const r of a.reasons) L.push(`
12411
- ${a.viable ? "NOTE" : "REFUSED"}: ${r}`);
12412
- return L.join("\n");
12413
- }
12414
-
12415
- // src/bridge/retry.ts
12416
- var TERMINAL_FAILURE = /DepositTooSmall|minimum is 1\.000000|insufficient|holds only|below the program|kora wants|over the .* ceiling/i;
12417
- function isTerminalFailure(message) {
12418
- return TERMINAL_FAILURE.test(message);
12419
- }
12420
- function classifyPostFailure(attempted, after) {
12421
- if (after === null) return "unknown";
12422
- if (after === 0n) return "landed";
12423
- if (after >= attempted) return "did-not-land";
12424
- return "unknown";
12425
- }
12426
- function mayRetry(verdict, message) {
12427
- return verdict === "did-not-land" && !isTerminalFailure(message);
12428
- }
12429
- function retryDelayMs(attempt) {
12430
- return 15e3 * Math.max(0, attempt - 1);
12431
- }
12432
- var DoNotRetry = class extends Error {
12433
- constructor(message) {
12434
- super(message);
12435
- this.name = "DoNotRetry";
12436
- }
12437
- };
12438
- async function withShieldRetries(attempt, hooks = {}) {
12439
- const attempts = hooks.attempts ?? 3;
12440
- const sleep4 = hooks.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
12441
- let last = "";
12442
- for (let n = 1; n <= attempts; n++) {
12443
- if (n > 1) {
12444
- const delay = retryDelayMs(n);
12445
- hooks.onRetry?.(n, delay, last);
12446
- await sleep4(delay);
12447
- }
12448
- try {
12449
- return await attempt(n);
12450
- } catch (e) {
12451
- if (e instanceof DoNotRetry) throw e;
12452
- last = e instanceof Error ? e.message : String(e);
12453
- if (isTerminalFailure(last) || n === attempts) throw e;
12454
- }
12455
- }
12456
- throw new Error("unreachable");
12457
- }
12458
-
12459
11660
  // src/index.ts
12460
11661
  var VERSION = "0.2.3";
12461
11662
  var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12462
11663
  // Annotate the CommonJS export names for ESM import in node:
12463
11664
  0 && (module.exports = {
12464
- BRIDGE_ESCROW_LABEL,
12465
11665
  BUILD_ALLOWS_LOCAL_ENDPOINTS,
12466
11666
  CHAIN_NOTE_SALT_BITS,
12467
- CLEANUP_FEE_BUDGET,
12468
11667
  CLOAK_PRODUCTION_RELAY_URL,
12469
11668
  CLOAK_PROGRAM_ID,
12470
11669
  CloakError,
@@ -12472,25 +11671,16 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12472
11671
  DEFAULT_TRANSACTION_CIRCUITS_URL,
12473
11672
  DELIVERY_MEMO_TAG,
12474
11673
  DELIVERY_REGISTRY_SEED,
12475
- DepositError,
12476
- DoNotRetry,
12477
- ECONOMIC_MINIMUM,
12478
11674
  EXPECTED_CIRCUIT_HASHES,
12479
- FEE_BUDGET,
12480
11675
  FIXED_FEE_LAMPORTS,
12481
11676
  InsecureRandomnessError,
12482
11677
  LAMPORTS_PER_SOL,
12483
11678
  LocalStorageAdapter,
12484
- MAINNET_RENT_0,
12485
- MAINNET_RENT_1,
12486
- MAX_RECEIVER_INDEX,
12487
11679
  MERKLE_TREE_HEIGHT,
12488
11680
  MIN_DEPOSIT_LAMPORTS,
12489
- MIN_DEPOSIT_SPL_BASE_UNITS,
12490
11681
  MemoryStorageAdapter,
12491
11682
  MerkleTree,
12492
11683
  NATIVE_SOL_MINT,
12493
- ONECLICK_PUBKEY_B58,
12494
11684
  RECIPIENT_DELIVERY_CIPHERTEXT_LEN,
12495
11685
  RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN,
12496
11686
  RECIPIENT_DELIVERY_NONCE_LEN,
@@ -12509,7 +11699,6 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12509
11699
  SettlementVerificationError,
12510
11700
  ShieldPoolErrors,
12511
11701
  SimpleWallet,
12512
- TERMINAL_FAILURE,
12513
11702
  TRANSACTION_CIRCUITS_VERSION,
12514
11703
  TRANSACT_AUTH_FIELDS,
12515
11704
  TRANSACT_SWAP_AUTH_FIELDS,
@@ -12519,12 +11708,9 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12519
11708
  VARIABLE_FEE_NUMERATOR,
12520
11709
  VARIABLE_FEE_RATE,
12521
11710
  VERSION,
12522
- WITHDRAW_FEE_BPS,
12523
- WITHDRAW_FIXED_FEE,
12524
11711
  assertDirectSubmissionLanded,
12525
11712
  assertInputMints,
12526
11713
  assertTransactionCircuitIntegrity,
12527
- assessBridgeQuote,
12528
11714
  bigintToBytes32,
12529
11715
  bigintToHex,
12530
11716
  buildMerkleTree,
@@ -12539,16 +11725,12 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12539
11725
  calculateRelayFee,
12540
11726
  canRebuildMerkleTreeFromChain,
12541
11727
  canonicalJson,
12542
- canonicalPayloadString,
12543
11728
  chainNoteFromBase64,
12544
11729
  chainNoteToBase64,
12545
- classifyPostFailure,
12546
11730
  classifyRelayError,
12547
- cleanupReceivingAddress,
12548
11731
  cleanupStalePendingOperations,
12549
11732
  clearPendingDeposits,
12550
11733
  clearPendingWithdrawals,
12551
- cloakBridgeRail,
12552
11734
  computeChainNoteHash,
12553
11735
  computeExtDataHash,
12554
11736
  computeMerkleRoot,
@@ -12570,13 +11752,10 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12570
11752
  decryptCompactChainNote,
12571
11753
  decryptComplianceMetadataWithMasterKey,
12572
11754
  decryptTransactionMetadata,
12573
- depositFromDerivedKey,
12574
- deriveBridgeReceiver,
12575
11755
  deriveChangeNoteBlinding,
12576
11756
  deriveDepositNoteSecrets,
12577
11757
  deriveDiversifiedViewingKey,
12578
11758
  deriveDiversifier,
12579
- deriveFundingTargets,
12580
11759
  deriveInputNullifierPdas,
12581
11760
  derivePublicKey,
12582
11761
  deriveSpendKey,
@@ -12615,7 +11794,6 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12615
11794
  formatErrorForLogging,
12616
11795
  formatSol,
12617
11796
  fullWithdraw,
12618
- fundReceiverViaPaymaster,
12619
11797
  generateCloakKeys,
12620
11798
  generateCommitmentAsync,
12621
11799
  generateMasterSeed,
@@ -12651,21 +11829,18 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12651
11829
  isReactNative,
12652
11830
  isRootNotFoundError,
12653
11831
  isSubmissionOutcomeUnknownResponse,
12654
- isTerminalFailure,
12655
11832
  isValidHex,
12656
11833
  isValidRpcUrl,
12657
11834
  isValidSolanaAddress,
12658
11835
  isWithdrawAmountSufficient,
12659
11836
  isWithdrawable,
12660
11837
  keypairToAdapter,
12661
- listBridgeDeposits,
12662
11838
  loadPendingDeposits,
12663
11839
  loadPendingWithdrawals,
12664
11840
  loadVerifiedCircuitArtifacts,
12665
11841
  matchChangeNote,
12666
11842
  matchDepositNote,
12667
11843
  matchSwapRefundLeaf,
12668
- mayRetry,
12669
11844
  openRecipientDeliveryNote,
12670
11845
  parseAmount,
12671
11846
  parseDeliveryCarrierMemo,
@@ -12688,14 +11863,11 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12688
11863
  randomDepositNoteSalt,
12689
11864
  randomFieldElement,
12690
11865
  readMerkleTreeState,
12691
- readRent,
12692
11866
  recipientDeliveryNoteToBase64,
12693
11867
  registerViewingKey,
12694
11868
  removePendingDeposit,
12695
11869
  removePendingWithdrawal,
12696
- renderAssessment,
12697
11870
  resolveCircuitsBase,
12698
- retryDelayMs,
12699
11871
  savePendingDeposit,
12700
11872
  savePendingWithdrawal,
12701
11873
  scanNotesForWallet,
@@ -12728,17 +11900,13 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12728
11900
  validateDepositParams,
12729
11901
  validateNote,
12730
11902
  validateOutputsSum,
12731
- validatePaymasterTopUpTransaction,
12732
11903
  validateRoot,
12733
11904
  validateTransfers,
12734
11905
  validateWalletConnected,
12735
11906
  validateWithdrawableNote,
12736
11907
  verifyAllCircuits,
12737
11908
  verifyCircuitIntegrity,
12738
- verifyQuoteSignature,
12739
11909
  verifyUtxos,
12740
11910
  waitForRoot,
12741
- withShieldRetries,
12742
- withTiming,
12743
- withdrawFeeFor
11911
+ withTiming
12744
11912
  });