@cloak.dev/sdk 0.2.2 → 0.2.3-staging.16d1078

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,8 +542,10 @@ 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,
545
546
  BUILD_ALLOWS_LOCAL_ENDPOINTS: () => BUILD_ALLOWS_LOCAL_ENDPOINTS,
546
547
  CHAIN_NOTE_SALT_BITS: () => CHAIN_NOTE_SALT_BITS,
548
+ CLEANUP_FEE_BUDGET: () => CLEANUP_FEE_BUDGET,
547
549
  CLOAK_PRODUCTION_RELAY_URL: () => CLOAK_PRODUCTION_RELAY_URL,
548
550
  CLOAK_PROGRAM_ID: () => CLOAK_PROGRAM_ID,
549
551
  CloakError: () => CloakError,
@@ -551,25 +553,38 @@ __export(index_exports, {
551
553
  DEFAULT_TRANSACTION_CIRCUITS_URL: () => DEFAULT_TRANSACTION_CIRCUITS_URL,
552
554
  DELIVERY_MEMO_TAG: () => DELIVERY_MEMO_TAG,
553
555
  DELIVERY_REGISTRY_SEED: () => DELIVERY_REGISTRY_SEED,
556
+ DepositError: () => DepositError,
557
+ DoNotRetry: () => DoNotRetry,
558
+ ECONOMIC_MINIMUM: () => ECONOMIC_MINIMUM,
554
559
  EXPECTED_CIRCUIT_HASHES: () => EXPECTED_CIRCUIT_HASHES,
560
+ FEE_BUDGET: () => FEE_BUDGET,
555
561
  FIXED_FEE_LAMPORTS: () => FIXED_FEE_LAMPORTS,
556
562
  InsecureRandomnessError: () => InsecureRandomnessError,
557
563
  LAMPORTS_PER_SOL: () => LAMPORTS_PER_SOL,
558
564
  LocalStorageAdapter: () => LocalStorageAdapter,
565
+ MAINNET_RENT_0: () => MAINNET_RENT_0,
566
+ MAINNET_RENT_1: () => MAINNET_RENT_1,
567
+ MAX_RECEIVER_INDEX: () => MAX_RECEIVER_INDEX,
559
568
  MERKLE_TREE_HEIGHT: () => MERKLE_TREE_HEIGHT2,
560
569
  MIN_DEPOSIT_LAMPORTS: () => MIN_DEPOSIT_LAMPORTS,
570
+ MIN_DEPOSIT_SPL_BASE_UNITS: () => MIN_DEPOSIT_SPL_BASE_UNITS,
561
571
  MemoryStorageAdapter: () => MemoryStorageAdapter,
562
572
  MerkleTree: () => MerkleTree,
563
573
  NATIVE_SOL_MINT: () => NATIVE_SOL_MINT,
574
+ ONECLICK_PUBKEY_B58: () => ONECLICK_PUBKEY_B58,
564
575
  RECIPIENT_DELIVERY_CIPHERTEXT_LEN: () => RECIPIENT_DELIVERY_CIPHERTEXT_LEN,
565
576
  RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN: () => RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN,
566
577
  RECIPIENT_DELIVERY_NONCE_LEN: () => RECIPIENT_DELIVERY_NONCE_LEN,
567
578
  RECIPIENT_DELIVERY_NOTE_BYTES: () => RECIPIENT_DELIVERY_NOTE_BYTES,
568
579
  RECIPIENT_DELIVERY_PLAINTEXT_LEN: () => RECIPIENT_DELIVERY_PLAINTEXT_LEN,
569
580
  RECIPIENT_DELIVERY_TAG_LEN: () => RECIPIENT_DELIVERY_TAG_LEN,
581
+ RELAY_BATCH_AUTH_MAX_ITEMS: () => RELAY_BATCH_AUTH_MAX_ITEMS,
570
582
  RELAY_ORIGIN_ALLOWLIST: () => RELAY_ORIGIN_ALLOWLIST,
583
+ REQUEST_AUTH_BATCH_DOMAIN: () => REQUEST_AUTH_BATCH_DOMAIN,
584
+ REQUEST_AUTH_BATCH_MAX_AGE_SECONDS: () => REQUEST_AUTH_BATCH_MAX_AGE_SECONDS,
571
585
  REQUEST_AUTH_MAX_AGE_SECONDS: () => REQUEST_AUTH_MAX_AGE_SECONDS,
572
586
  REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS: () => REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS,
587
+ RelayBatchAuthCoordinator: () => RelayBatchAuthCoordinator,
573
588
  RelayInternalError: () => RelayInternalError,
574
589
  RelayService: () => RelayService,
575
590
  RootNotFoundError: () => RootNotFoundError,
@@ -579,6 +594,7 @@ __export(index_exports, {
579
594
  SettlementVerificationError: () => SettlementVerificationError,
580
595
  ShieldPoolErrors: () => ShieldPoolErrors,
581
596
  SimpleWallet: () => SimpleWallet,
597
+ TERMINAL_FAILURE: () => TERMINAL_FAILURE,
582
598
  TRANSACTION_CIRCUITS_VERSION: () => TRANSACTION_CIRCUITS_VERSION,
583
599
  TRANSACT_AUTH_FIELDS: () => TRANSACT_AUTH_FIELDS,
584
600
  TRANSACT_SWAP_AUTH_FIELDS: () => TRANSACT_SWAP_AUTH_FIELDS,
@@ -588,8 +604,12 @@ __export(index_exports, {
588
604
  VARIABLE_FEE_NUMERATOR: () => VARIABLE_FEE_NUMERATOR,
589
605
  VARIABLE_FEE_RATE: () => VARIABLE_FEE_RATE,
590
606
  VERSION: () => VERSION,
607
+ WITHDRAW_FEE_BPS: () => WITHDRAW_FEE_BPS,
608
+ WITHDRAW_FIXED_FEE: () => WITHDRAW_FIXED_FEE,
591
609
  assertDirectSubmissionLanded: () => assertDirectSubmissionLanded,
610
+ assertInputMints: () => assertInputMints,
592
611
  assertTransactionCircuitIntegrity: () => assertTransactionCircuitIntegrity,
612
+ assessBridgeQuote: () => assessBridgeQuote,
593
613
  bigintToBytes32: () => bigintToBytes32,
594
614
  bigintToHex: () => bigintToHex,
595
615
  buildMerkleTree: () => buildMerkleTree,
@@ -597,6 +617,7 @@ __export(index_exports, {
597
617
  buildMerkleTreeFromRelay: () => buildMerkleTreeFromRelay,
598
618
  buildRecipientDeliveryNotes: () => buildRecipientDeliveryNotes,
599
619
  buildRelayAuthPreimage: () => buildRelayAuthPreimage,
620
+ buildRelayBatchAuthMessage: () => buildRelayBatchAuthMessage,
600
621
  buildTransactRequestBody: () => buildTransactRequestBody,
601
622
  bytesToHex: () => bytesToHex,
602
623
  calculateFee: () => calculateFee,
@@ -604,12 +625,16 @@ __export(index_exports, {
604
625
  calculateRelayFee: () => calculateRelayFee,
605
626
  canRebuildMerkleTreeFromChain: () => canRebuildMerkleTreeFromChain,
606
627
  canonicalJson: () => canonicalJson,
628
+ canonicalPayloadString: () => canonicalPayloadString,
607
629
  chainNoteFromBase64: () => chainNoteFromBase64,
608
630
  chainNoteToBase64: () => chainNoteToBase64,
631
+ classifyPostFailure: () => classifyPostFailure,
609
632
  classifyRelayError: () => classifyRelayError,
633
+ cleanupReceivingAddress: () => cleanupReceivingAddress,
610
634
  cleanupStalePendingOperations: () => cleanupStalePendingOperations,
611
635
  clearPendingDeposits: () => clearPendingDeposits,
612
636
  clearPendingWithdrawals: () => clearPendingWithdrawals,
637
+ cloakBridgeRail: () => cloakBridgeRail,
613
638
  computeChainNoteHash: () => computeChainNoteHash,
614
639
  computeExtDataHash: () => computeExtDataHash,
615
640
  computeMerkleRoot: () => computeMerkleRoot,
@@ -626,15 +651,19 @@ __export(index_exports, {
626
651
  createLogger: () => createLogger,
627
652
  createRecoverableChangeUtxo: () => createRecoverableChangeUtxo,
628
653
  createRecoverableDepositUtxo: () => createRecoverableDepositUtxo,
654
+ createRelayBatchAuthCoordinator: () => createRelayBatchAuthCoordinator,
629
655
  createUtxo: () => createUtxo,
630
656
  createZeroUtxo: () => createZeroUtxo,
631
657
  decryptCompactChainNote: () => decryptCompactChainNote,
632
658
  decryptComplianceMetadataWithMasterKey: () => decryptComplianceMetadataWithMasterKey,
633
659
  decryptTransactionMetadata: () => decryptTransactionMetadata,
660
+ depositFromDerivedKey: () => depositFromDerivedKey,
661
+ deriveBridgeReceiver: () => deriveBridgeReceiver,
634
662
  deriveChangeNoteBlinding: () => deriveChangeNoteBlinding,
635
663
  deriveDepositNoteSecrets: () => deriveDepositNoteSecrets,
636
664
  deriveDiversifiedViewingKey: () => deriveDiversifiedViewingKey,
637
665
  deriveDiversifier: () => deriveDiversifier,
666
+ deriveFundingTargets: () => deriveFundingTargets,
638
667
  deriveInputNullifierPdas: () => deriveInputNullifierPdas,
639
668
  derivePublicKey: () => derivePublicKey,
640
669
  deriveSpendKey: () => deriveSpendKey,
@@ -673,6 +702,7 @@ __export(index_exports, {
673
702
  formatErrorForLogging: () => formatErrorForLogging,
674
703
  formatSol: () => formatSol,
675
704
  fullWithdraw: () => fullWithdraw,
705
+ fundReceiverViaPaymaster: () => fundReceiverViaPaymaster,
676
706
  generateCloakKeys: () => generateCloakKeys,
677
707
  generateCommitmentAsync: () => generateCommitmentAsync,
678
708
  generateMasterSeed: () => generateMasterSeed,
@@ -708,18 +738,21 @@ __export(index_exports, {
708
738
  isReactNative: () => isReactNative,
709
739
  isRootNotFoundError: () => isRootNotFoundError,
710
740
  isSubmissionOutcomeUnknownResponse: () => isSubmissionOutcomeUnknownResponse,
741
+ isTerminalFailure: () => isTerminalFailure,
711
742
  isValidHex: () => isValidHex,
712
743
  isValidRpcUrl: () => isValidRpcUrl,
713
744
  isValidSolanaAddress: () => isValidSolanaAddress,
714
745
  isWithdrawAmountSufficient: () => isWithdrawAmountSufficient,
715
746
  isWithdrawable: () => isWithdrawable,
716
747
  keypairToAdapter: () => keypairToAdapter,
748
+ listBridgeDeposits: () => listBridgeDeposits,
717
749
  loadPendingDeposits: () => loadPendingDeposits,
718
750
  loadPendingWithdrawals: () => loadPendingWithdrawals,
719
751
  loadVerifiedCircuitArtifacts: () => loadVerifiedCircuitArtifacts,
720
752
  matchChangeNote: () => matchChangeNote,
721
753
  matchDepositNote: () => matchDepositNote,
722
754
  matchSwapRefundLeaf: () => matchSwapRefundLeaf,
755
+ mayRetry: () => mayRetry,
723
756
  openRecipientDeliveryNote: () => openRecipientDeliveryNote,
724
757
  parseAmount: () => parseAmount,
725
758
  parseDeliveryCarrierMemo: () => parseDeliveryCarrierMemo,
@@ -742,11 +775,15 @@ __export(index_exports, {
742
775
  randomDepositNoteSalt: () => randomDepositNoteSalt,
743
776
  randomFieldElement: () => randomFieldElement,
744
777
  readMerkleTreeState: () => readMerkleTreeState,
778
+ readRent: () => readRent,
745
779
  recipientDeliveryNoteToBase64: () => recipientDeliveryNoteToBase64,
746
780
  registerViewingKey: () => registerViewingKey,
781
+ relayRequestDigestHex: () => relayRequestDigestHex,
747
782
  removePendingDeposit: () => removePendingDeposit,
748
783
  removePendingWithdrawal: () => removePendingWithdrawal,
784
+ renderAssessment: () => renderAssessment,
749
785
  resolveCircuitsBase: () => resolveCircuitsBase,
786
+ retryDelayMs: () => retryDelayMs,
750
787
  savePendingDeposit: () => savePendingDeposit,
751
788
  savePendingWithdrawal: () => savePendingWithdrawal,
752
789
  scanNotesForWallet: () => scanNotesForWallet,
@@ -767,6 +804,7 @@ __export(index_exports, {
767
804
  swapWithChange: () => swapWithChange,
768
805
  toComplianceReport: () => toComplianceReport,
769
806
  transact: () => transact,
807
+ transactBatch: () => transactBatch,
770
808
  transfer: () => transfer,
771
809
  truncate: () => truncate,
772
810
  tryDecryptNote: () => tryDecryptNote,
@@ -779,15 +817,19 @@ __export(index_exports, {
779
817
  validateDepositParams: () => validateDepositParams,
780
818
  validateNote: () => validateNote,
781
819
  validateOutputsSum: () => validateOutputsSum,
820
+ validatePaymasterTopUpTransaction: () => validatePaymasterTopUpTransaction,
782
821
  validateRoot: () => validateRoot,
783
822
  validateTransfers: () => validateTransfers,
784
823
  validateWalletConnected: () => validateWalletConnected,
785
824
  validateWithdrawableNote: () => validateWithdrawableNote,
786
825
  verifyAllCircuits: () => verifyAllCircuits,
787
826
  verifyCircuitIntegrity: () => verifyCircuitIntegrity,
827
+ verifyQuoteSignature: () => verifyQuoteSignature,
788
828
  verifyUtxos: () => verifyUtxos,
789
829
  waitForRoot: () => waitForRoot,
790
- withTiming: () => withTiming
830
+ withShieldRetries: () => withShieldRetries,
831
+ withTiming: () => withTiming,
832
+ withdrawFeeFor: () => withdrawFeeFor
791
833
  });
792
834
  module.exports = __toCommonJS(index_exports);
793
835
 
@@ -1391,7 +1433,7 @@ function parseStrictViewingKeyChallenge(response, userPubkey, viewingKeyHex) {
1391
1433
 
1392
1434
  // src/config/relay.ts
1393
1435
  var CLOAK_PRODUCTION_RELAY_URL = "https://api.cloak.ag";
1394
- var RELAY_ORIGIN_ALLOWLIST = [CLOAK_PRODUCTION_RELAY_URL];
1436
+ var RELAY_ORIGIN_ALLOWLIST = ["https://staging-api.cloak.ag"];
1395
1437
  var ABSOLUTE_URL = /^[a-z][a-z0-9+.-]*:\/\//i;
1396
1438
  var LOOPBACK_IPV4 = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
1397
1439
  var THIS_NETWORK_IPV4 = /^0\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
@@ -2929,8 +2971,8 @@ async function verifyUtxos(utxos, connection, programId, commitment = "confirmed
2929
2971
  const nullifierHex = nullifierBig.toString(16).padStart(64, "0");
2930
2972
  const nullifierBytes = Buffer.from(nullifierHex, "hex");
2931
2973
  const { pool } = getShieldPoolPDAs(programId, utxo.mintAddress);
2932
- const [pda] = getNullifierPDA(pool, nullifierBytes, programId);
2933
- checkable.push({ utxo, pda });
2974
+ const [pda2] = getNullifierPDA(pool, nullifierBytes, programId);
2975
+ checkable.push({ utxo, pda: pda2 });
2934
2976
  } catch {
2935
2977
  skipped.push(utxo);
2936
2978
  }
@@ -3000,8 +3042,8 @@ function deriveInputNullifierPdas(programId, mint, inputNullifiers) {
3000
3042
  const pdas = [];
3001
3043
  for (const nullifier of inputNullifiers) {
3002
3044
  if (nullifier === BigInt(0)) continue;
3003
- const [pda] = getNullifierPDA(pool, bigintToBytes324(nullifier), programId);
3004
- pdas.push(pda);
3045
+ const [pda2] = getNullifierPDA(pool, bigintToBytes324(nullifier), programId);
3046
+ pdas.push(pda2);
3005
3047
  }
3006
3048
  return pdas;
3007
3049
  }
@@ -4320,7 +4362,7 @@ async function fetchWithRetry(url, options = {}) {
4320
4362
  const {
4321
4363
  timeoutMs = DEFAULT_TIMEOUT_MS,
4322
4364
  maxRetries = DEFAULT_MAX_RETRIES,
4323
- retryDelayMs = 1e3
4365
+ retryDelayMs: retryDelayMs2 = 1e3
4324
4366
  } = options;
4325
4367
  assertAllowedRelayOrigin(url);
4326
4368
  let lastError = null;
@@ -4344,7 +4386,7 @@ async function fetchWithRetry(url, options = {}) {
4344
4386
  `Relay request failed after ${attempt + 1} attempts: ${lastError.message}`
4345
4387
  );
4346
4388
  }
4347
- const delay = retryDelayMs * Math.pow(2, attempt) + Math.random() * 500;
4389
+ const delay = retryDelayMs2 * Math.pow(2, attempt) + Math.random() * 500;
4348
4390
  await new Promise((resolve) => setTimeout(resolve, delay));
4349
4391
  }
4350
4392
  }
@@ -5546,12 +5588,12 @@ function signRelayRequest(endpoint, programId, body, signer, nowSeconds, fields
5546
5588
  auth_signature: Buffer.from(signature).toString("base64")
5547
5589
  };
5548
5590
  }
5549
- function assertApprovalWithinFreshnessWindow(elapsedMs) {
5591
+ function assertApprovalWithinFreshnessWindow(elapsedMs, maxAgeSeconds = REQUEST_AUTH_MAX_AGE_SECONDS) {
5550
5592
  const elapsedSeconds = elapsedMs / 1e3;
5551
- const budget = REQUEST_AUTH_MAX_AGE_SECONDS - RELAY_AUTH_APPROVAL_MARGIN_SECONDS;
5593
+ const budget = maxAgeSeconds - RELAY_AUTH_APPROVAL_MARGIN_SECONDS;
5552
5594
  if (elapsedSeconds <= budget) return;
5553
5595
  throw new Error(
5554
- `The wallet approval took ${Math.round(elapsedSeconds)} seconds, and Cloak requests stay valid for ${REQUEST_AUTH_MAX_AGE_SECONDS} seconds from the moment they are signed (${RELAY_AUTH_APPROVAL_MARGIN_SECONDS} of those are held back for the request to reach the network). The timestamp is inside the signature, so it cannot be refreshed without your approval again. NOTHING WAS SUBMITTED and no funds moved. Start the same operation again and approve the prompt when it appears.`
5596
+ `The wallet approval took ${Math.round(elapsedSeconds)} seconds, and Cloak requests stay valid for ${maxAgeSeconds} seconds from the moment they are signed (${RELAY_AUTH_APPROVAL_MARGIN_SECONDS} of those are held back for the request to reach the network). The timestamp is inside the signature, so it cannot be refreshed without your approval again. NOTHING WAS SUBMITTED and no funds moved. Start the same operation again and approve the prompt when it appears.`
5555
5597
  );
5556
5598
  }
5557
5599
  function explainRelayAuthRejection(responseText) {
@@ -5609,6 +5651,16 @@ async function buildRelayAuthFields(endpoint, programId, body, signers, fields =
5609
5651
  auth_signature: Buffer.from(signature).toString("base64")
5610
5652
  };
5611
5653
  }
5654
+ var REQUEST_AUTH_BATCH_DOMAIN = "CLOAK_RELAY_BATCH_AUTH_V1";
5655
+ var REQUEST_AUTH_BATCH_MAX_AGE_SECONDS = 600;
5656
+ var RELAY_BATCH_AUTH_MAX_ITEMS = 64;
5657
+ function relayRequestDigestHex(preimage) {
5658
+ return (0, import_utils.bytesToHex)((0, import_sha23.sha256)(preimage.message));
5659
+ }
5660
+ function buildRelayBatchAuthMessage(programId, issuedAt, digests) {
5661
+ const lines = [REQUEST_AUTH_BATCH_DOMAIN, programId.toBase58(), issuedAt, String(digests.length)];
5662
+ return new TextEncoder().encode([...lines, ...digests].join("\n"));
5663
+ }
5612
5664
 
5613
5665
  // src/flows/transact.ts
5614
5666
  init_inputs();
@@ -5888,6 +5940,7 @@ async function resolveTransactionCircuitFiles() {
5888
5940
  }
5889
5941
  var _transactPaddingSaltCounter = 0;
5890
5942
  var _registeredViewingKeys = /* @__PURE__ */ new Set();
5943
+ var _viewingKeyRegistrationsInFlight = /* @__PURE__ */ new Map();
5891
5944
  var _resolvedAltAccountsCache = /* @__PURE__ */ new Map();
5892
5945
  var _relayMerkleDisabledMints = /* @__PURE__ */ new Set();
5893
5946
  var _relayMerkleFallbackNotifiedMints = /* @__PURE__ */ new Set();
@@ -6220,6 +6273,23 @@ async function computeSwapExtDataHash(outputMint, recipientAta, minOutputAmount,
6220
6273
  ]);
6221
6274
  return poseidonHasher.F.toObject(hash);
6222
6275
  }
6276
+ function assertInputMints(inputUtxos, expectedMint) {
6277
+ const funded = inputUtxos.filter((u) => u.amount > BigInt(0));
6278
+ if (funded.length === 0) return;
6279
+ const first = funded[0].mintAddress;
6280
+ for (const utxo of funded) {
6281
+ if (!utxo.mintAddress.equals(first)) {
6282
+ throw new Error(
6283
+ `Input notes span more than one mint (${first.toBase58()} and ${utxo.mintAddress.toBase58()}). Every pool holds a single mint, so this cannot be a valid spend of either. Select notes of one mint.`
6284
+ );
6285
+ }
6286
+ }
6287
+ if (expectedMint && !first.equals(expectedMint)) {
6288
+ throw new Error(
6289
+ `Input notes are ${first.toBase58()} but this transaction expects ${expectedMint.toBase58()}. The notes decide which pool is spent, so proceeding would move the wrong asset \u2014 refusing. This usually means note selection ignored the mint.`
6290
+ );
6291
+ }
6292
+ }
6223
6293
  function parseNkInput(input) {
6224
6294
  if (typeof input !== "string") {
6225
6295
  if (input.length !== 32) {
@@ -6275,6 +6345,26 @@ async function ensureViewingKeyRegistered(options, onProgress, fallbackNk) {
6275
6345
  if (_registeredViewingKeys.has(cacheKey)) {
6276
6346
  return;
6277
6347
  }
6348
+ const inFlight = _viewingKeyRegistrationsInFlight.get(cacheKey);
6349
+ if (inFlight) {
6350
+ return inFlight;
6351
+ }
6352
+ const registration = registerViewingKeyOnce(
6353
+ relayUrl,
6354
+ userPubkey,
6355
+ viewingKeyHex,
6356
+ cacheKey,
6357
+ options,
6358
+ onProgress
6359
+ );
6360
+ _viewingKeyRegistrationsInFlight.set(cacheKey, registration);
6361
+ try {
6362
+ await registration;
6363
+ } finally {
6364
+ _viewingKeyRegistrationsInFlight.delete(cacheKey);
6365
+ }
6366
+ }
6367
+ async function registerViewingKeyOnce(relayUrl, userPubkey, viewingKeyHex, cacheKey, options, onProgress) {
6278
6368
  const challengeResponse = await relayFetch(`${relayUrl}/viewing-key/challenge`, {
6279
6369
  method: "POST",
6280
6370
  headers: { "Content-Type": "application/json" },
@@ -7630,12 +7720,12 @@ async function submitTransactToRelay(args) {
7630
7720
  const doFetch = args.fetchImpl ?? fetch;
7631
7721
  const maxNetworkRetries = args.maxNetworkRetries ?? relayNetworkRetries();
7632
7722
  const requestTimeoutMs = args.requestTimeoutMs ?? relayRequestTimeoutMs();
7633
- if (!depositorKeypair && args.relayAuthSigner) {
7723
+ if (!depositorKeypair && args.relayAuthSigner && !args.relayAuthBatch) {
7634
7724
  onProgress?.(
7635
7725
  "Approve the request in your wallet. This signs the request for the relay, not a transaction, and it must be approved within a few minutes to stay valid."
7636
7726
  );
7637
7727
  }
7638
- const authFields = await buildRelayAuthFields("/transact", programId, requestBody, {
7728
+ const authFields = args.relayAuthBatch ? await args.relayAuthBatch.authorize("/transact", programId, requestBody, TRANSACT_AUTH_FIELDS) : await buildRelayAuthFields("/transact", programId, requestBody, {
7639
7729
  depositorKeypair,
7640
7730
  relayAuthSigner: args.relayAuthSigner
7641
7731
  });
@@ -7831,7 +7921,7 @@ async function transact(params, options) {
7831
7921
  // names is refused.
7832
7922
  maxRootRetries = 40,
7833
7923
  // Increased to handle prolonged relay sync recovery under high concurrency
7834
- retryDelayMs = 500,
7924
+ retryDelayMs: retryDelayMs2 = 500,
7835
7925
  // Start with short delay, will exponentially back off
7836
7926
  riskOracleQueue,
7837
7927
  riskQuoteUrl: riskQuoteUrlOption,
@@ -7886,6 +7976,7 @@ async function transact(params, options) {
7886
7976
  }
7887
7977
  }
7888
7978
  assertAllowedRpcConnection(connection);
7979
+ assertInputMints(inputUtxos, options.expectedMint);
7889
7980
  await ensureViewingKeyRegistered(options, onProgress, fallbackNk);
7890
7981
  const resolvedChainNoteNk = explicitChainNoteNk ?? fallbackNk ?? null;
7891
7982
  if (inputUtxos.length > 2) {
@@ -8252,7 +8343,7 @@ async function transact(params, options) {
8252
8343
  while (submissionAttempts <= maxRootRetries) {
8253
8344
  const isRetry = submissionAttempts > 0;
8254
8345
  if (isRetry) {
8255
- const exponentialDelay = Math.min(retryDelayMs * Math.pow(1.5, submissionAttempts - 1), 5e3);
8346
+ const exponentialDelay = Math.min(retryDelayMs2 * Math.pow(1.5, submissionAttempts - 1), 5e3);
8256
8347
  const jitter = Math.random() * 500;
8257
8348
  const totalDelay = Math.floor(exponentialDelay + jitter);
8258
8349
  await sleep2(totalDelay);
@@ -8391,11 +8482,14 @@ async function transact(params, options) {
8391
8482
  }
8392
8483
  let proof;
8393
8484
  let publicSignals;
8485
+ const releaseProofSlot = options.relayAuthBatch ? await options.relayAuthBatch.proofSlot() : void 0;
8394
8486
  try {
8395
8487
  const result = await generateTransactionProof(circuitInputs, onProofProgress);
8396
8488
  proof = result.proof;
8397
8489
  publicSignals = result.publicSignals;
8490
+ releaseProofSlot?.();
8398
8491
  } catch (proofError) {
8492
+ releaseProofSlot?.();
8399
8493
  const errorMsg = proofError?.message || String(proofError);
8400
8494
  if ((errorMsg.includes("ForceEqual") || errorMsg.includes("Assert Failed")) && submissionAttempts < maxRootRetries) {
8401
8495
  onProgress?.(`Merkle proof error (stale sibling data), will regenerate with fresh tree...`);
@@ -8415,7 +8509,7 @@ async function transact(params, options) {
8415
8509
  }
8416
8510
  treeState = null;
8417
8511
  useSiblingInfo = false;
8418
- const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(submissionAttempts, 4)), 5e3);
8512
+ const waitMs = Math.min(retryDelayMs2 * Math.pow(2, Math.min(submissionAttempts, 4)), 5e3);
8419
8513
  if (waitMs > 0) {
8420
8514
  onProgress?.(`Waiting ${waitMs}ms for relay sync before retry...`);
8421
8515
  await new Promise((r) => setTimeout(r, waitMs));
@@ -8708,6 +8802,7 @@ async function transact(params, options) {
8708
8802
  // point where they reach the relay submission instead of stopping at viewing-key
8709
8803
  // registration. The keypair still wins when both are present.
8710
8804
  relayAuthSigner: relayAuthPlan.kind === "wallet" ? relayAuthPlan.signer : void 0,
8805
+ relayAuthBatch: options.relayAuthBatch,
8711
8806
  settlement: {
8712
8807
  connection,
8713
8808
  programId,
@@ -9109,7 +9204,7 @@ async function swapUtxo(params, options) {
9109
9204
  riskQuoteUrl: riskQuoteUrlOption,
9110
9205
  maxRootRetries = 40,
9111
9206
  // Increased to handle prolonged relay sync recovery under high concurrency
9112
- retryDelayMs = 500,
9207
+ retryDelayMs: retryDelayMs2 = 500,
9113
9208
  // Start with short delay, will exponentially back off
9114
9209
  useUniqueNullifiers,
9115
9210
  useChainRootForProof = true
@@ -9128,6 +9223,12 @@ async function swapUtxo(params, options) {
9128
9223
  if (inputUtxos.length > 2) {
9129
9224
  throw new Error("Maximum 2 input UTXOs allowed");
9130
9225
  }
9226
+ assertInputMints(inputUtxos, NATIVE_SOL_MINT);
9227
+ if (options.expectedMint && !options.expectedMint.equals(NATIVE_SOL_MINT)) {
9228
+ throw new Error(
9229
+ `swapUtxo expects ${NATIVE_SOL_MINT.toBase58()} input notes (a swap always spends from the wSOL pool), but expectedMint was ${options.expectedMint.toBase58()}. Drop expectedMint, or spend the other mint with transact/transfer instead.`
9230
+ );
9231
+ }
9131
9232
  await preflightNullifiers(inputUtxos, connection, programId);
9132
9233
  const outputMintAccount = await connection.getAccountInfo(outputMint, {
9133
9234
  commitment: "confirmed"
@@ -9514,7 +9615,7 @@ async function swapUtxo(params, options) {
9514
9615
  let walletApprovals = 0;
9515
9616
  for (let attempt = 0; attempt <= maxRootRetries; attempt++) {
9516
9617
  if (attempt > 0) {
9517
- const exponentialDelay = Math.min(retryDelayMs * Math.pow(1.5, attempt - 1), 5e3);
9618
+ const exponentialDelay = Math.min(retryDelayMs2 * Math.pow(1.5, attempt - 1), 5e3);
9518
9619
  const jitter = Math.random() * 500;
9519
9620
  const totalDelay = Math.floor(exponentialDelay + jitter);
9520
9621
  await sleep2(totalDelay);
@@ -9652,7 +9753,7 @@ async function swapUtxo(params, options) {
9652
9753
  }
9653
9754
  merkleState = null;
9654
9755
  useSiblingInfo = false;
9655
- const waitMs = Math.min(retryDelayMs * Math.pow(2, Math.min(attempt, 4)), 5e3);
9756
+ const waitMs = Math.min(retryDelayMs2 * Math.pow(2, Math.min(attempt, 4)), 5e3);
9656
9757
  if (waitMs > 0) {
9657
9758
  onProgress?.(`Waiting ${waitMs}ms for relay sync before retry...`);
9658
9759
  await new Promise((r) => setTimeout(r, waitMs));
@@ -10157,9 +10258,272 @@ function cleanupStalePendingOperations(maxAgeMs = 24 * 60 * 60 * 1e3) {
10157
10258
  // src/index.ts
10158
10259
  init_utxo();
10159
10260
 
10261
+ // src/relay/batch-auth.ts
10262
+ var import_web310 = require("@solana/web3.js");
10263
+ var import_tweetnacl7 = __toESM(require("tweetnacl"), 1);
10264
+ var RelayBatchAuthCoordinator = class {
10265
+ constructor(options) {
10266
+ this.proofSlotsInUse = 0;
10267
+ this.proofQueue = [];
10268
+ this.items = [];
10269
+ this.signing = false;
10270
+ this.slotsInUse = 0;
10271
+ this.ready = [];
10272
+ this.waves = 0;
10273
+ if (!Number.isInteger(options.items) || options.items < 1) {
10274
+ throw new Error(`A batch needs at least one item (got ${options.items}).`);
10275
+ }
10276
+ if (options.items > RELAY_BATCH_AUTH_MAX_ITEMS) {
10277
+ throw new Error(
10278
+ `A batch may cover at most ${RELAY_BATCH_AUTH_MAX_ITEMS} requests (got ${options.items}); the relay refuses longer digest lists. Chunk the payout. The practical bound is lower still: each spend appends two roots to the on-chain ring of 100, so a batch proved against one root evicts it by itself before 50 items.`
10279
+ );
10280
+ }
10281
+ const concurrency = options.submitConcurrency ?? 3;
10282
+ if (!Number.isInteger(concurrency) || concurrency < 1) {
10283
+ throw new Error(`submitConcurrency must be a positive integer (got ${concurrency}).`);
10284
+ }
10285
+ this.signer = options.signer;
10286
+ this.sender = options.signer instanceof import_web310.Keypair ? options.signer.publicKey : options.signer.walletPublicKey;
10287
+ this.expectedItems = options.items;
10288
+ this.submitConcurrency = concurrency;
10289
+ const proofConcurrency = options.proofConcurrency ?? 2;
10290
+ if (!Number.isInteger(proofConcurrency) || proofConcurrency < 1) {
10291
+ throw new Error(`proofConcurrency must be a positive integer (got ${proofConcurrency}).`);
10292
+ }
10293
+ this.proofConcurrency = proofConcurrency;
10294
+ this.onProgress = options.onProgress;
10295
+ }
10296
+ /** The wallet that signs and is every item's authenticated `sender`. */
10297
+ get walletPublicKey() {
10298
+ return this.sender;
10299
+ }
10300
+ /** How many times the signer has been asked so far: one per wave. */
10301
+ get approvals() {
10302
+ return this.waves;
10303
+ }
10304
+ /** Where every item is right now. For progress UIs and for diagnosing a batch that never signs. */
10305
+ snapshot() {
10306
+ const count = (state) => this.items.filter((i) => i.state === state).length;
10307
+ return {
10308
+ building: count("building"),
10309
+ waiting: count("waiting"),
10310
+ submitting: count("submitting"),
10311
+ done: count("done"),
10312
+ proving: this.proofSlotsInUse,
10313
+ proofQueue: this.proofQueue.length,
10314
+ registered: this.items.length,
10315
+ expected: this.expectedItems
10316
+ };
10317
+ }
10318
+ /** Register one item. Throws past `items`: the wave condition would never be reachable. */
10319
+ item() {
10320
+ if (this.items.length >= this.expectedItems) {
10321
+ throw new Error(
10322
+ `This batch was created for ${this.expectedItems} item(s) and all of them are registered.`
10323
+ );
10324
+ }
10325
+ const item = { state: "building", waiting: null, holdsSlot: false };
10326
+ this.items.push(item);
10327
+ return {
10328
+ proofSlot: () => this.acquireProofSlot(),
10329
+ authorize: (endpoint, programId, body, fields) => this.authorize(item, endpoint, programId, body, fields),
10330
+ finish: () => this.finish(item)
10331
+ };
10332
+ }
10333
+ acquireProofSlot() {
10334
+ return new Promise((resolve) => {
10335
+ const grant = () => {
10336
+ this.proofSlotsInUse += 1;
10337
+ let released = false;
10338
+ resolve(() => {
10339
+ if (released) return;
10340
+ released = true;
10341
+ this.proofSlotsInUse -= 1;
10342
+ const next = this.proofQueue.shift();
10343
+ if (next) next();
10344
+ });
10345
+ };
10346
+ if (this.proofSlotsInUse < this.proofConcurrency) grant();
10347
+ else this.proofQueue.push(grant);
10348
+ });
10349
+ }
10350
+ authorize(item, endpoint, programId, body, fields) {
10351
+ if (item.state === "done") {
10352
+ return Promise.reject(new Error("This batch item already finished; it cannot authorize."));
10353
+ }
10354
+ if (item.state === "waiting") {
10355
+ return Promise.reject(new Error("This batch item is already waiting for a signature."));
10356
+ }
10357
+ this.releaseSlot(item);
10358
+ return new Promise((resolve, reject) => {
10359
+ item.state = "waiting";
10360
+ item.waiting = { endpoint, programId, body, fields, resolve, reject };
10361
+ this.maybeSign();
10362
+ });
10363
+ }
10364
+ finish(item) {
10365
+ if (item.state === "done") return;
10366
+ if (item.state === "waiting" && item.waiting) {
10367
+ item.waiting.reject(new Error("Batch item finished before it was signed."));
10368
+ item.waiting = null;
10369
+ }
10370
+ this.releaseSlot(item);
10371
+ item.state = "done";
10372
+ this.maybeSign();
10373
+ this.pump();
10374
+ }
10375
+ releaseSlot(item) {
10376
+ if (!item.holdsSlot) return;
10377
+ item.holdsSlot = false;
10378
+ this.slotsInUse -= 1;
10379
+ }
10380
+ /** Sign when every registered item is either waiting here or finished, and nothing is building. */
10381
+ maybeSign() {
10382
+ if (this.signing) return;
10383
+ if (this.items.length < this.expectedItems) return;
10384
+ if (this.items.some((item) => item.state === "building" || item.state === "submitting")) return;
10385
+ const wave = this.items.filter((item) => item.state === "waiting");
10386
+ if (wave.length === 0) return;
10387
+ this.signing = true;
10388
+ void this.signWave(wave).finally(() => {
10389
+ this.signing = false;
10390
+ this.maybeSign();
10391
+ });
10392
+ }
10393
+ async signWave(wave) {
10394
+ const waiting = wave.map((item) => item.waiting);
10395
+ try {
10396
+ const programId = waiting[0].programId;
10397
+ for (const w of waiting) {
10398
+ if (!w.programId.equals(programId)) {
10399
+ throw new Error("Every item of a batch must target the same program id.");
10400
+ }
10401
+ }
10402
+ const nowSeconds = Math.floor(Date.now() / 1e3);
10403
+ const preimages = waiting.map(
10404
+ (w) => buildRelayAuthPreimage(w.endpoint, programId, w.body, this.sender, nowSeconds, w.fields)
10405
+ );
10406
+ const digests = preimages.map(relayRequestDigestHex);
10407
+ const issuedAt = preimages[0].auth_issued_at;
10408
+ const message = buildRelayBatchAuthMessage(programId, issuedAt, digests);
10409
+ this.waves += 1;
10410
+ let signature;
10411
+ if (this.signer instanceof import_web310.Keypair) {
10412
+ signature = import_tweetnacl7.default.sign.detached(message, this.signer.secretKey);
10413
+ } else {
10414
+ this.onProgress?.(
10415
+ `Approve ${waiting.length} request(s) in your wallet` + (this.waves > 1 ? ` (approval ${this.waves}, for the rows that had to re-prove)` : "") + `. This signs the requests for the relay, not a transaction, and must be approved within a few minutes to stay valid.`
10416
+ );
10417
+ const approvalStartedMs = Date.now();
10418
+ signature = await this.signer.signMessage(message);
10419
+ assertApprovalWithinFreshnessWindow(
10420
+ Date.now() - approvalStartedMs,
10421
+ REQUEST_AUTH_BATCH_MAX_AGE_SECONDS
10422
+ );
10423
+ if (!(signature instanceof Uint8Array) || signature.length !== 64) {
10424
+ throw new Error(
10425
+ `The wallet's signMessage did not return a 64-byte ed25519 detached signature (got ${signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature}).`
10426
+ );
10427
+ }
10428
+ }
10429
+ const signatureB64 = Buffer.from(signature).toString("base64");
10430
+ wave.forEach((item, i) => {
10431
+ const preimage = preimages[i];
10432
+ this.ready.push({
10433
+ item,
10434
+ fields: {
10435
+ sender: preimage.sender,
10436
+ auth_issued_at: preimage.auth_issued_at,
10437
+ auth_nonce: preimage.auth_nonce,
10438
+ auth_signature: signatureB64,
10439
+ // A fresh array per item: `Object.assign` puts this on the wire body, and the body is
10440
+ // serialized again on every network retry.
10441
+ auth_batch: { digests: [...digests] }
10442
+ }
10443
+ });
10444
+ });
10445
+ this.pump();
10446
+ } catch (error) {
10447
+ for (const item of wave) {
10448
+ const w = item.waiting;
10449
+ item.waiting = null;
10450
+ item.state = "done";
10451
+ w?.reject(error);
10452
+ }
10453
+ }
10454
+ }
10455
+ /** Release signed items to submit, `submitConcurrency` at a time, in signing order. */
10456
+ pump() {
10457
+ while (this.ready.length > 0 && this.slotsInUse < this.submitConcurrency) {
10458
+ const next = this.ready.shift();
10459
+ const w = next.item.waiting;
10460
+ next.item.waiting = null;
10461
+ if (next.item.state !== "waiting" || !w) continue;
10462
+ next.item.state = "submitting";
10463
+ next.item.holdsSlot = true;
10464
+ this.slotsInUse += 1;
10465
+ w.resolve(next.fields);
10466
+ }
10467
+ }
10468
+ };
10469
+ function createRelayBatchAuthCoordinator(options) {
10470
+ return new RelayBatchAuthCoordinator(options);
10471
+ }
10472
+
10473
+ // src/flows/transact-batch.ts
10474
+ async function transactBatch(items, options) {
10475
+ if (items.length === 0) {
10476
+ return { results: [], approvals: 0 };
10477
+ }
10478
+ if (items.length > RELAY_BATCH_AUTH_MAX_ITEMS) {
10479
+ throw new Error(
10480
+ `transactBatch accepts at most ${RELAY_BATCH_AUTH_MAX_ITEMS} items per call (got ${items.length}). Chunk the payout; see RELAY_BATCH_AUTH_MAX_ITEMS for why the practical bound is lower.`
10481
+ );
10482
+ }
10483
+ if (!options.relayUrl) {
10484
+ throw new Error("transactBatch requires relayUrl: batch approval is a relay authentication scheme.");
10485
+ }
10486
+ const { proofConcurrency, submitConcurrency, ...shared } = options;
10487
+ const signer = shared.depositorKeypair ? shared.depositorKeypair : shared.walletPublicKey && shared.signMessage ? { walletPublicKey: shared.walletPublicKey, signMessage: shared.signMessage } : shared.depositorPublicKey && shared.signMessage ? { walletPublicKey: shared.depositorPublicKey, signMessage: shared.signMessage } : null;
10488
+ if (!signer) {
10489
+ throw new Error(
10490
+ "transactBatch requires an authenticated sender: pass `depositorKeypair` (a local Keypair) or `signMessage` together with `walletPublicKey` (a browser wallet adapter). Checked before proof generation, so nothing has been computed or submitted yet."
10491
+ );
10492
+ }
10493
+ const coordinator = createRelayBatchAuthCoordinator({
10494
+ signer,
10495
+ items: items.length,
10496
+ proofConcurrency,
10497
+ submitConcurrency,
10498
+ onProgress: shared.onProgress
10499
+ });
10500
+ const handles = items.map(() => coordinator.item());
10501
+ const results = new Array(items.length);
10502
+ const runOne = async (index) => {
10503
+ const item = items[index];
10504
+ const handle = handles[index];
10505
+ const label = `[batch ${index + 1}/${items.length}]`;
10506
+ try {
10507
+ const value = await transact(item.params, {
10508
+ ...shared,
10509
+ ...item.options,
10510
+ relayAuthBatch: handle,
10511
+ onProgress: shared.onProgress ? (status) => shared.onProgress?.(`${label} ${status}`) : void 0
10512
+ });
10513
+ results[index] = { status: "fulfilled", value };
10514
+ } catch (reason) {
10515
+ results[index] = { status: "rejected", reason };
10516
+ } finally {
10517
+ handle.finish();
10518
+ }
10519
+ };
10520
+ await Promise.all(items.map((_, index) => runOne(index)));
10521
+ return { results, approvals: coordinator.approvals };
10522
+ }
10523
+
10160
10524
  // src/scanning/scan.ts
10161
10525
  var import_bs583 = __toESM(require("bs58"), 1);
10162
- var import_web310 = require("@solana/web3.js");
10526
+ var import_web311 = require("@solana/web3.js");
10163
10527
  var import_spl_token2 = require("@solana/spl-token");
10164
10528
  init_inputs();
10165
10529
  init_utxo();
@@ -10248,7 +10612,7 @@ function parseSwapOutputMint(data) {
10248
10612
  const mintBytes = data.slice(SWAP_OUTPUT_MINT_OFFSET, end);
10249
10613
  if (mintBytes.every((byte) => byte === 0)) return void 0;
10250
10614
  try {
10251
- return new import_web310.PublicKey(mintBytes).toBase58();
10615
+ return new import_web311.PublicKey(mintBytes).toBase58();
10252
10616
  } catch {
10253
10617
  return void 0;
10254
10618
  }
@@ -10338,7 +10702,7 @@ function parseSwapRecipientAta(data) {
10338
10702
  const recipientAtaBytes = data.slice(recipientAtaStart, recipientAtaEnd);
10339
10703
  if (recipientAtaBytes.every((byte) => byte === 0)) return void 0;
10340
10704
  try {
10341
- return new import_web310.PublicKey(recipientAtaBytes).toBase58();
10705
+ return new import_web311.PublicKey(recipientAtaBytes).toBase58();
10342
10706
  } catch {
10343
10707
  return void 0;
10344
10708
  }
@@ -10500,7 +10864,7 @@ async function scanSwapNoteCarriers(connection, programId, viewingKeyNk, swapCtx
10500
10864
  let rpcCalls = 0;
10501
10865
  const candidates = Array.from(swapCtxByCommitment.keys());
10502
10866
  if (candidates.length === 0) return { records, rpcCalls };
10503
- const [registry] = import_web310.PublicKey.findProgramAddressSync(
10867
+ const [registry] = import_web311.PublicKey.findProgramAddressSync(
10504
10868
  [Buffer.from("cloak_chain_note_registry")],
10505
10869
  programId
10506
10870
  );
@@ -10903,8 +11267,8 @@ async function scanTransactions(opts) {
10903
11267
  if (onChainAta) {
10904
11268
  try {
10905
11269
  const expectedAta = (0, import_spl_token2.getAssociatedTokenAddressSync)(
10906
- new import_web310.PublicKey(asset.mint),
10907
- new import_web310.PublicKey(walletPublicKey)
11270
+ new import_web311.PublicKey(asset.mint),
11271
+ new import_web311.PublicKey(walletPublicKey)
10908
11272
  ).toBase58();
10909
11273
  if (onChainAta === expectedAta) {
10910
11274
  isOurs = true;
@@ -11118,7 +11482,7 @@ async function scanTransactions(opts) {
11118
11482
  // deposit — that is the public deposit amount. A deposit that also merged inputs
11119
11483
  // carries a larger output 0 and is not recoverable from public data alone.
11120
11484
  amount: grossAmount,
11121
- mintAddress: new import_web310.PublicKey(asset.mint),
11485
+ mintAddress: new import_web311.PublicKey(asset.mint),
11122
11486
  outputCommitments: ixCtx.outputCommitments ?? []
11123
11487
  });
11124
11488
  if (recoveredDeposit) {
@@ -11144,7 +11508,7 @@ async function scanTransactions(opts) {
11144
11508
  noteSalt: compactNote.noteSalt,
11145
11509
  amount: compactNote.outAmount0,
11146
11510
  keypair: { privateKey: 0n, publicKey: compactNote.outPubkey0 },
11147
- mintAddress: new import_web310.PublicKey(asset.mint),
11511
+ mintAddress: new import_web311.PublicKey(asset.mint),
11148
11512
  outputIndex: 0,
11149
11513
  // v4 describes output 0, which is where change lands
11150
11514
  outputCommitments: ixCtx.outputCommitments ?? []
@@ -11337,7 +11701,7 @@ function formatComplianceCsv(report) {
11337
11701
  }
11338
11702
 
11339
11703
  // src/wallet/utxo-wallet.ts
11340
- var import_web311 = require("@solana/web3.js");
11704
+ var import_web312 = require("@solana/web3.js");
11341
11705
  init_utxo();
11342
11706
  var UtxoWallet = class _UtxoWallet {
11343
11707
  constructor(viewingKey) {
@@ -11550,7 +11914,7 @@ var UtxoWallet = class _UtxoWallet {
11550
11914
  data.viewingKey ? new Uint8Array(data.viewingKey) : void 0
11551
11915
  );
11552
11916
  for (const w of data.wallets) {
11553
- const mint = new import_web311.PublicKey(w.mint);
11917
+ const mint = new import_web312.PublicKey(w.mint);
11554
11918
  for (const u of w.utxos) {
11555
11919
  wallet.addUtxo({
11556
11920
  amount: BigInt(u.amount),
@@ -11632,13 +11996,781 @@ var SimpleWallet = class {
11632
11996
  }
11633
11997
  };
11634
11998
 
11999
+ // src/bridge/rail-verify.ts
12000
+ var import_tweetnacl8 = __toESM(require("tweetnacl"), 1);
12001
+ var import_sha256 = require("@noble/hashes/sha256");
12002
+ var ONECLICK_PUBKEY_B58 = "reYaWhvwu8Jzo3WUM3zhn6VrhuMEF4eADL17qtRVifc";
12003
+ var b58 = /* @__PURE__ */ (() => {
12004
+ const A = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
12005
+ return {
12006
+ decode(s) {
12007
+ let n = 0n;
12008
+ for (const c of s) {
12009
+ const i = A.indexOf(c);
12010
+ if (i < 0) throw new Error("bad base58");
12011
+ n = n * 58n + BigInt(i);
12012
+ }
12013
+ const bytes = [];
12014
+ while (n > 0n) {
12015
+ bytes.unshift(Number(n & 255n));
12016
+ n >>= 8n;
12017
+ }
12018
+ for (const c of s) {
12019
+ if (c === "1") bytes.unshift(0);
12020
+ else break;
12021
+ }
12022
+ return Uint8Array.from(bytes);
12023
+ },
12024
+ encode(b) {
12025
+ let n = 0n;
12026
+ for (const x of b) n = n * 256n + BigInt(x);
12027
+ let s = "";
12028
+ while (n > 0n) {
12029
+ s = A[Number(n % 58n)] + s;
12030
+ n /= 58n;
12031
+ }
12032
+ for (const x of b) {
12033
+ if (x === 0) s = "1" + s;
12034
+ else break;
12035
+ }
12036
+ return s;
12037
+ }
12038
+ };
12039
+ })();
12040
+ function stable(v) {
12041
+ if (v === null || typeof v !== "object") return JSON.stringify(v) ?? "null";
12042
+ if (Array.isArray(v)) return `[${v.map(stable).join(",")}]`;
12043
+ const o = v;
12044
+ const parts = Object.keys(o).sort().filter((k) => o[k] !== void 0).map((k) => `${JSON.stringify(k)}:${stable(o[k])}`);
12045
+ return `{${parts.join(",")}}`;
12046
+ }
12047
+ function signedRequest(r) {
12048
+ const q = r.quoteRequest ?? {};
12049
+ return {
12050
+ dry: q.dry,
12051
+ swapType: q.swapType,
12052
+ slippageTolerance: q.slippageTolerance,
12053
+ originAsset: q.originAsset,
12054
+ depositType: q.depositType,
12055
+ destinationAsset: q.destinationAsset,
12056
+ amount: q.amount,
12057
+ refundTo: q.refundTo,
12058
+ refundType: q.refundType,
12059
+ recipient: q.recipient,
12060
+ recipientType: q.recipientType,
12061
+ deadline: q.deadline,
12062
+ quoteWaitingTimeMs: q.quoteWaitingTimeMs || void 0,
12063
+ referral: q.referral || void 0,
12064
+ virtualChainRecipient: q.virtualChainRecipient || void 0,
12065
+ virtualChainRefundRecipient: q.virtualChainRefundRecipient || void 0,
12066
+ customRecipientMsg: q.customRecipientMsg || void 0
12067
+ // Deliberately unsigned by the rail: sessionId, connectedWallets, correlationId, appFees,
12068
+ // partnerId, userAccountId, depositMode. APP FEES ARE NOT AUTHENTICATED — never display a fee
12069
+ // caption as if the signature vouched for it.
12070
+ };
12071
+ }
12072
+ function signedQuote(r) {
12073
+ const q = r.quote ?? {};
12074
+ const base = {
12075
+ amountIn: q.amountIn,
12076
+ amountInFormatted: q.amountInFormatted,
12077
+ amountInUsd: q.amountInUsd,
12078
+ minAmountIn: q.minAmountIn,
12079
+ amountOut: q.amountOut,
12080
+ amountOutFormatted: q.amountOutFormatted,
12081
+ amountOutUsd: q.amountOutUsd,
12082
+ minAmountOut: q.minAmountOut
12083
+ };
12084
+ if (r.quoteRequest?.dry) return base;
12085
+ return {
12086
+ ...base,
12087
+ depositAddress: q.depositAddress || void 0,
12088
+ // <- the field that makes substitution detectable
12089
+ depositMemo: q.depositMemo || void 0,
12090
+ deadline: q.deadline || void 0,
12091
+ // <- a real, SIGNED expiry
12092
+ timeWhenInactive: q.timeWhenInactive || void 0,
12093
+ timeEstimate: q.timeEstimate || void 0,
12094
+ virtualChainRecipient: q.virtualChainRecipient || void 0,
12095
+ virtualChainRefundRecipient: q.virtualChainRefundRecipient || void 0,
12096
+ customRecipientMsg: q.customRecipientMsg || void 0,
12097
+ refundFee: q.refundFee || void 0,
12098
+ withdrawFee: q.withdrawFee || void 0
12099
+ };
12100
+ }
12101
+ function canonicalPayloadString(resp) {
12102
+ return stable({ ...signedRequest(resp), ...signedQuote(resp), timestamp: resp.timestamp });
12103
+ }
12104
+ function verifyQuoteSignature(resp) {
12105
+ if (!resp?.signature) return { valid: false, reason: "no signature on the response" };
12106
+ const payload = { ...signedRequest(resp), ...signedQuote(resp), timestamp: resp.timestamp };
12107
+ const digest = (0, import_sha256.sha256)(new TextEncoder().encode(stable(payload)));
12108
+ const message = new TextEncoder().encode(b58.encode(new Uint8Array(digest)));
12109
+ const sig = resp.signature.replace(/^ed25519:/, "");
12110
+ try {
12111
+ return { valid: import_tweetnacl8.default.sign.detached.verify(message, b58.decode(sig), b58.decode(ONECLICK_PUBKEY_B58)) };
12112
+ } catch (e) {
12113
+ return { valid: false, reason: e instanceof Error ? e.message : String(e) };
12114
+ }
12115
+ }
12116
+
12117
+ // src/bridge/rails.ts
12118
+ async function parseBridgeResponse(res, what) {
12119
+ let body;
12120
+ try {
12121
+ body = await res.json();
12122
+ } catch {
12123
+ throw new Error(`${what} failed: ${res.status} ${res.statusText} (response body was not JSON)`);
12124
+ }
12125
+ if (!res.ok) {
12126
+ const b = body ?? {};
12127
+ throw new Error(
12128
+ `${what} failed: ${b.message ?? res.statusText} (${b.code ?? res.status}${b.retryable ? ", retryable" : ""})`
12129
+ );
12130
+ }
12131
+ return body;
12132
+ }
12133
+ function toAttestation(raw) {
12134
+ if (raw.kind === "ed25519") {
12135
+ return { kind: "ed25519", verified: raw.verified ?? false, signer: raw.signer ?? "" };
12136
+ }
12137
+ return { kind: "none", checks: raw.checks ?? [], note: raw.note ?? "" };
12138
+ }
12139
+ async function fetchBridgeQuote(relayUrl, req) {
12140
+ const body = {
12141
+ recipient: req.recipient,
12142
+ origin_chain: req.originChain,
12143
+ amount_base_units: req.amountBaseUnits.toString(),
12144
+ allocate: req.allocate ?? false
12145
+ };
12146
+ if (req.refundTo !== void 0) body.refund_to = req.refundTo;
12147
+ if (req.rails !== void 0) body.rails = req.rails;
12148
+ const res = await relayFetch(`${relayUrl}/bridge/quote`, {
12149
+ method: "POST",
12150
+ headers: { "Content-Type": "application/json" },
12151
+ body: JSON.stringify(body)
12152
+ });
12153
+ const raw = await parseBridgeResponse(res, "bridge quote");
12154
+ const options = [];
12155
+ const unavailable = (raw.unavailable ?? []).map((p) => ({
12156
+ rail: p.rail,
12157
+ reason: p.reason
12158
+ }));
12159
+ for (const opt of raw.options) {
12160
+ const attestation = toAttestation(opt.attestation);
12161
+ if (attestation.kind === "ed25519") {
12162
+ const verdict = opt.rail_response ? verifyQuoteSignature(opt.rail_response) : { valid: false, reason: "no rail_response to verify against" };
12163
+ if (!verdict.valid) {
12164
+ unavailable.push({
12165
+ rail: opt.rail,
12166
+ reason: `deposit address failed independent signature verification, refusing to display it (${verdict.reason ?? "signature did not verify"})`
12167
+ });
12168
+ continue;
12169
+ }
12170
+ }
12171
+ options.push({
12172
+ rail: opt.rail,
12173
+ refunds: opt.refunds,
12174
+ addressLifetime: opt.address_lifetime,
12175
+ amountOut: BigInt(opt.amount_out),
12176
+ minAmountOut: BigInt(opt.min_amount_out),
12177
+ timeEstimateSeconds: opt.time_estimate_s,
12178
+ expiresAt: opt.expires_at,
12179
+ depositAddress: opt.deposit_address,
12180
+ attestation
12181
+ });
12182
+ }
12183
+ return { options, unavailable };
12184
+ }
12185
+ var STATUS_STATES = [
12186
+ "pending",
12187
+ "delivered",
12188
+ "refunded",
12189
+ "expired",
12190
+ "unknown"
12191
+ ];
12192
+ async function fetchBridgeStatus(relayUrl, depositAddress, rail) {
12193
+ const qs = new URLSearchParams({ deposit_address: depositAddress, rail });
12194
+ const res = await relayFetch(`${relayUrl}/bridge/status?${qs.toString()}`);
12195
+ const raw = await parseBridgeResponse(res, "bridge status");
12196
+ const state = STATUS_STATES.includes(raw.state ?? "") ? raw.state : "unknown";
12197
+ return { rail: raw.rail ?? rail, state, detail: raw.detail ?? "" };
12198
+ }
12199
+ function cloakBridgeRail(relayUrl) {
12200
+ assertAllowedRelayOrigin(relayUrl);
12201
+ return {
12202
+ id: "cloak-bridge",
12203
+ quote: (req) => fetchBridgeQuote(relayUrl, req),
12204
+ status: (depositAddress, rail) => fetchBridgeStatus(relayUrl, depositAddress, rail)
12205
+ };
12206
+ }
12207
+
12208
+ // src/bridge/paymaster-client.ts
12209
+ var import_web313 = require("@solana/web3.js");
12210
+ var import_spl_token3 = require("@solana/spl-token");
12211
+ function validatePaymasterTopUpTransaction(tx, expect) {
12212
+ const ixs = tx.instructions;
12213
+ if (ixs.length !== 1 && ixs.length !== 2) {
12214
+ throw new Error(
12215
+ `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`
12216
+ );
12217
+ }
12218
+ const ix0 = ixs[0];
12219
+ if (!ix0.programId.equals(import_web313.SystemProgram.programId)) {
12220
+ throw new Error(
12221
+ `paymaster top-up instruction 0 is owned by ${ix0.programId.toBase58()}, not the System Program \u2014 refusing to sign an unrecognised first instruction`
12222
+ );
12223
+ }
12224
+ const transfer2 = import_web313.SystemInstruction.decodeTransfer(ix0);
12225
+ if (!transfer2.toPubkey.equals(expect.recipient)) {
12226
+ throw new Error(
12227
+ `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`
12228
+ );
12229
+ }
12230
+ if (BigInt(transfer2.lamports) > expect.maxGrantLamports) {
12231
+ throw new Error(
12232
+ `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`
12233
+ );
12234
+ }
12235
+ if (ixs.length === 1) return;
12236
+ const ix1 = ixs[1];
12237
+ if (!ix1.programId.equals(import_spl_token3.TOKEN_PROGRAM_ID)) {
12238
+ throw new Error(
12239
+ `paymaster top-up instruction 1 is owned by ${ix1.programId.toBase58()}, not the SPL Token program \u2014 refusing to sign an unrecognised second instruction`
12240
+ );
12241
+ }
12242
+ const spl = (0, import_spl_token3.decodeTransferInstruction)(ix1, import_spl_token3.TOKEN_PROGRAM_ID);
12243
+ const authority = spl.keys.owner.pubkey;
12244
+ if (!authority.equals(expect.recipient)) {
12245
+ throw new Error(
12246
+ `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`
12247
+ );
12248
+ }
12249
+ const expectedDestination = (0, import_spl_token3.getAssociatedTokenAddressSync)(
12250
+ expect.feeMint,
12251
+ expect.paymentAddress,
12252
+ false
12253
+ );
12254
+ const destination = spl.keys.destination.pubkey;
12255
+ if (!destination.equals(expectedDestination)) {
12256
+ throw new Error(
12257
+ `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`
12258
+ );
12259
+ }
12260
+ const paidAmount = BigInt(spl.data.amount);
12261
+ if (paidAmount !== expect.feeTokenAmount) {
12262
+ throw new Error(
12263
+ `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`
12264
+ );
12265
+ }
12266
+ }
12267
+ async function parseBridgeResponse2(res, what) {
12268
+ let body;
12269
+ try {
12270
+ body = await res.json();
12271
+ } catch {
12272
+ throw new Error(`${what} failed: ${res.status} ${res.statusText} (response body was not JSON)`);
12273
+ }
12274
+ if (!res.ok) {
12275
+ const b = body ?? {};
12276
+ throw new Error(
12277
+ `${what} failed: ${b.message ?? res.statusText} (${b.code ?? res.status}${b.retryable ? ", retryable" : ""})`
12278
+ );
12279
+ }
12280
+ return body;
12281
+ }
12282
+ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
12283
+ assertAllowedRelayOrigin(relayUrl);
12284
+ if (grantLamports <= 0n || grantLamports > BigInt(Number.MAX_SAFE_INTEGER)) {
12285
+ throw new Error(
12286
+ `grantLamports must be a positive value representable as a JS number, got ${grantLamports}`
12287
+ );
12288
+ }
12289
+ const prepareRes = await relayFetch(`${relayUrl}/bridge/paymaster/prepare`, {
12290
+ method: "POST",
12291
+ headers: { "Content-Type": "application/json" },
12292
+ body: JSON.stringify({
12293
+ recipient: receiver.publicKey.toBase58(),
12294
+ grant_lamports: Number(grantLamports)
12295
+ })
12296
+ });
12297
+ const prepared = await parseBridgeResponse2(prepareRes, "paymaster prepare");
12298
+ if (Math.floor(Date.now() / 1e3) >= prepared.expires_at_unix) {
12299
+ throw new Error(
12300
+ "paymaster prepare returned a voucher that is already expired \u2014 refusing to sign a stale top-up rather than fail confusingly at cosign"
12301
+ );
12302
+ }
12303
+ const feeMint = new import_web313.PublicKey(prepared.fee_mint);
12304
+ const paymentAddress = new import_web313.PublicKey(prepared.payment_address);
12305
+ const feeTokenAmount = BigInt(prepared.fee_token_amount);
12306
+ const tx = import_web313.Transaction.from(Buffer.from(prepared.transaction, "base64"));
12307
+ validatePaymasterTopUpTransaction(tx, {
12308
+ recipient: receiver.publicKey,
12309
+ maxGrantLamports: grantLamports,
12310
+ feeMint,
12311
+ feeTokenAmount,
12312
+ paymentAddress
12313
+ });
12314
+ tx.partialSign(receiver);
12315
+ const cosignRes = await relayFetch(`${relayUrl}/bridge/paymaster/cosign`, {
12316
+ method: "POST",
12317
+ headers: { "Content-Type": "application/json" },
12318
+ body: JSON.stringify({
12319
+ transaction: tx.serialize({ requireAllSignatures: false, verifySignatures: false }).toString("base64"),
12320
+ voucher: prepared.voucher
12321
+ })
12322
+ });
12323
+ const cosigned = await parseBridgeResponse2(cosignRes, "paymaster cosign");
12324
+ return {
12325
+ transaction: import_web313.Transaction.from(Buffer.from(cosigned.transaction, "base64")),
12326
+ feeTokenAmount,
12327
+ feeMint: prepared.fee_mint,
12328
+ paymentAddress: prepared.payment_address
12329
+ };
12330
+ }
12331
+
12332
+ // src/bridge/derive.ts
12333
+ var import_web314 = require("@solana/web3.js");
12334
+ var import_hmac = require("@noble/hashes/hmac");
12335
+ var import_sha512 = require("@noble/hashes/sha512");
12336
+ var BRIDGE_ESCROW_LABEL = "cloak_bridge_escrow";
12337
+ var MAX_RECEIVER_INDEX = 1e4;
12338
+ function deriveBridgeReceiver(nk, index) {
12339
+ if (!Number.isInteger(index) || index < 0) {
12340
+ throw new Error(`index must be a non-negative integer, got ${index}`);
12341
+ }
12342
+ if (index > MAX_RECEIVER_INDEX) {
12343
+ throw new Error(
12344
+ `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.`
12345
+ );
12346
+ }
12347
+ const h = (0, import_hmac.hmac)(import_sha512.sha512, new Uint8Array(nk), new TextEncoder().encode(`${BRIDGE_ESCROW_LABEL}:${index}`));
12348
+ return import_web314.Keypair.fromSeed(h.slice(0, 32));
12349
+ }
12350
+
12351
+ // src/bridge/discover.ts
12352
+ var import_web315 = require("@solana/web3.js");
12353
+ var import_spl_token4 = require("@solana/spl-token");
12354
+ function describeError(err) {
12355
+ return err instanceof Error ? err.message : String(err);
12356
+ }
12357
+ async function listBridgeDeposits(conn, nk, opts) {
12358
+ const scanDepth = Math.min(opts.scanDepth ?? 20, MAX_RECEIVER_INDEX + 1);
12359
+ const stopAfterUnused = opts.stopAfterUnused ?? 5;
12360
+ const out = [];
12361
+ let consecutiveUnused = 0;
12362
+ for (let index = 0; index < scanDepth; index++) {
12363
+ const kp = deriveBridgeReceiver(nk, index);
12364
+ const receiver = kp.publicKey;
12365
+ const tokenAccount = (0, import_spl_token4.getAssociatedTokenAddressSync)(opts.mint, receiver, false);
12366
+ try {
12367
+ const [recvInfo, ataInfo] = await conn.getMultipleAccountsInfo([receiver, tokenAccount]);
12368
+ const lamports = recvInfo?.lamports ?? 0;
12369
+ let tokenBalance = 0n;
12370
+ if (ataInfo) {
12371
+ try {
12372
+ tokenBalance = BigInt((await conn.getTokenAccountBalance(tokenAccount)).value.amount);
12373
+ } catch (err) {
12374
+ if (!(err instanceof import_web315.SolanaJSONRPCError && /could not find account/i.test(err.message))) {
12375
+ throw err;
12376
+ }
12377
+ }
12378
+ }
12379
+ if (lamports === 0 && !ataInfo) {
12380
+ consecutiveUnused++;
12381
+ if (consecutiveUnused >= stopAfterUnused) break;
12382
+ continue;
12383
+ }
12384
+ consecutiveUnused = 0;
12385
+ const shieldSignatures = [];
12386
+ const sigs = await conn.getSignaturesForAddress(receiver, { limit: 20 });
12387
+ for (const s of sigs) {
12388
+ if (s.err) continue;
12389
+ const tx = await conn.getTransaction(s.signature, { maxSupportedTransactionVersion: 0 });
12390
+ const keys = tx?.transaction.message.getAccountKeys({
12391
+ accountKeysFromLookups: tx.meta?.loadedAddresses
12392
+ });
12393
+ if (keys && [...Array(keys.length).keys()].some((i) => keys.get(i)?.equals(opts.programId))) {
12394
+ shieldSignatures.push(s.signature);
12395
+ }
12396
+ }
12397
+ const shieldSignature = shieldSignatures[0];
12398
+ const indexReused = shieldSignatures.length > 1;
12399
+ let state;
12400
+ if (tokenBalance > 0n) state = shieldSignature ? "needs-cleanup" : "arrived";
12401
+ else if (shieldSignature) state = ataInfo ? "needs-cleanup" : "complete";
12402
+ else state = "awaiting";
12403
+ out.push({
12404
+ index,
12405
+ receiver,
12406
+ tokenAccount,
12407
+ state,
12408
+ tokenBalance,
12409
+ lamports,
12410
+ shieldSignature,
12411
+ ...indexReused ? { indexReused, shieldSignatures } : {}
12412
+ });
12413
+ } catch (err) {
12414
+ out.push({
12415
+ index,
12416
+ receiver,
12417
+ tokenAccount,
12418
+ state: "unknown",
12419
+ tokenBalance: 0n,
12420
+ lamports: 0,
12421
+ error: describeError(err)
12422
+ });
12423
+ }
12424
+ }
12425
+ return out;
12426
+ }
12427
+
12428
+ // src/bridge/deposit-core.ts
12429
+ var import_web317 = require("@solana/web3.js");
12430
+ var import_tweetnacl9 = __toESM(require("tweetnacl"), 1);
12431
+ init_utxo();
12432
+
12433
+ // src/bridge/funder.ts
12434
+ var import_web316 = require("@solana/web3.js");
12435
+ var import_spl_token5 = require("@solana/spl-token");
12436
+ var MAINNET_RENT_0 = 890880;
12437
+ var MAINNET_RENT_1 = 897840;
12438
+ var FEE_BUDGET = 13e4;
12439
+ var CLEANUP_FEE_BUDGET = 5e3;
12440
+ var pda = (seeds, programId) => import_web316.PublicKey.findProgramAddressSync(seeds.map((s) => Buffer.from(s)), programId)[0];
12441
+ function deriveFundingTargets(d) {
12442
+ const pool = pda([Buffer.from("pool"), d.mint.toBuffer()], d.programId);
12443
+ return {
12444
+ pool,
12445
+ // program: NullifierAccount::derive_pda_with_pool -> [b"nullifier", pool, nullifier]
12446
+ nullifier0: pda([Buffer.from("nullifier"), pool.toBuffer(), d.nullifiers[0]], d.programId),
12447
+ nullifier1: pda([Buffer.from("nullifier"), pool.toBuffer(), d.nullifiers[1]], d.programId),
12448
+ // relay: derive_risk_nonce_pda -> [b"risk_nonce", bind0]
12449
+ riskNonce: pda([Buffer.from("risk_nonce"), d.bind0], d.programId),
12450
+ depositorAta: (0, import_spl_token5.getAssociatedTokenAddressSync)(d.mint, d.depositor, false)
12451
+ };
12452
+ }
12453
+ async function readRent(conn) {
12454
+ const [zero, one] = await Promise.all([
12455
+ conn.getMinimumBalanceForRentExemption(0),
12456
+ conn.getMinimumBalanceForRentExemption(1)
12457
+ ]);
12458
+ return { zero, one };
12459
+ }
12460
+
12461
+ // src/bridge/deposit-core.ts
12462
+ var DepositError = class extends Error {
12463
+ constructor(message, fundedAccounts, measuredTxSize) {
12464
+ super(message);
12465
+ this.fundedAccounts = fundedAccounts;
12466
+ this.measuredTxSize = measuredTxSize;
12467
+ this.name = "DepositError";
12468
+ }
12469
+ };
12470
+ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log, grantOverride, opts) {
12471
+ if (!opts.noteSpendKey || opts.noteSpendKey.length !== 32) {
12472
+ throw new Error(
12473
+ "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."
12474
+ );
12475
+ }
12476
+ if (!opts.relayUrl) {
12477
+ throw new Error(
12478
+ "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."
12479
+ );
12480
+ }
12481
+ if (!opts.programId) {
12482
+ throw new Error(
12483
+ "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."
12484
+ );
12485
+ }
12486
+ if (!opts.mint) {
12487
+ throw new Error(
12488
+ "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."
12489
+ );
12490
+ }
12491
+ assertAllowedRpcConnection(conn);
12492
+ const relayUrl = opts.relayUrl;
12493
+ const programId = opts.programId;
12494
+ const mint = opts.mint;
12495
+ setCircuitsPath(resolveCircuitsBase());
12496
+ const grantR = grantOverride ?? MAINNET_RENT_0 + FEE_BUDGET + CLEANUP_FEE_BUDGET;
12497
+ const heldByR = await conn.getBalance(R.publicKey);
12498
+ if (heldByR >= grantR) {
12499
+ log(` R already holds ${heldByR} (>= ${grantR}) \u2014 no top-up needed`);
12500
+ } else {
12501
+ await (0, import_web317.sendAndConfirmTransaction)(conn, new import_web317.Transaction().add(
12502
+ import_web317.SystemProgram.transfer({ fromPubkey: funder.publicKey, toPubkey: R.publicKey, lamports: grantR - heldByR })
12503
+ ), [funder]);
12504
+ 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"}`);
12505
+ }
12506
+ let measuredSize = -1;
12507
+ let fundedAccounts = [];
12508
+ const signTransaction2 = async (tx) => {
12509
+ if (tx instanceof import_web317.VersionedTransaction) {
12510
+ measuredSize = tx.serialize().length;
12511
+ const alts = await Promise.all(
12512
+ tx.message.addressTableLookups.map(async (l) => (await conn.getAddressLookupTable(l.accountKey)).value)
12513
+ );
12514
+ const keys = tx.message.getAccountKeys({ addressLookupTableAccounts: alts });
12515
+ const ix = tx.message.compiledInstructions.find((i) => keys.get(i.programIdIndex).equals(programId));
12516
+ const at = (n) => keys.get(ix.accountKeyIndexes[n]);
12517
+ const targets = [
12518
+ { a: at(12), need: MAINNET_RENT_0, name: "risk_nonce" },
12519
+ { a: at(4), need: MAINNET_RENT_1, name: "nullifier_0" },
12520
+ { a: at(5), need: MAINNET_RENT_1, name: "nullifier_1" }
12521
+ ];
12522
+ const infos = await conn.getMultipleAccountsInfo(targets.map((t) => t.a));
12523
+ fundedAccounts = targets.map((t, i) => ({
12524
+ name: t.name,
12525
+ address: t.a.toBase58(),
12526
+ lamportsSent: Math.max(0, t.need - (infos[i]?.lamports ?? 0))
12527
+ }));
12528
+ const ixs = targets.flatMap((t, i) => (infos[i]?.lamports ?? 0) >= t.need ? [] : [import_web317.SystemProgram.transfer({
12529
+ fromPubkey: funder.publicKey,
12530
+ toPubkey: t.a,
12531
+ lamports: t.need - (infos[i]?.lamports ?? 0)
12532
+ })]);
12533
+ if (ixs.length) {
12534
+ const sig = await (0, import_web317.sendAndConfirmTransaction)(conn, new import_web317.Transaction().add(...ixs), [funder]);
12535
+ log(` seam: funded ${ixs.length} program accounts read off the built tx \u2014 ${sig.slice(0, 16)}\u2026`);
12536
+ }
12537
+ tx.sign([R]);
12538
+ return tx;
12539
+ }
12540
+ tx.partialSign(R);
12541
+ return tx;
12542
+ };
12543
+ const signMessage = async (m) => import_tweetnacl9.default.sign.detached(m, R.secretKey);
12544
+ const utxoKeypair = await deriveUtxoKeypairFromSpendKey(opts.noteSpendKey);
12545
+ const nk = getNkFromUtxoPrivateKey(utxoKeypair.privateKey);
12546
+ const { utxo, noteSalt } = await createRecoverableDepositUtxo(amount, nk, mint);
12547
+ const zeroInput = await createZeroUtxo(mint);
12548
+ const rBefore = await conn.getBalance(R.publicKey);
12549
+ let result;
12550
+ try {
12551
+ result = await transact(
12552
+ { inputUtxos: [zeroInput], outputUtxos: [utxo], externalAmount: amount, depositor: R.publicKey },
12553
+ {
12554
+ connection: conn,
12555
+ programId,
12556
+ relayUrl,
12557
+ // NO depositorKeypair: the SDK branches `if (keypair) … else if (signTransaction)`
12558
+ // (transact.ts:2786, :2936), so passing one silently skips the funding seam.
12559
+ depositorPublicKey: R.publicKey,
12560
+ walletPublicKey: R.publicKey,
12561
+ signTransaction: signTransaction2,
12562
+ signMessage,
12563
+ chainNoteViewingKeyNk: nk,
12564
+ chainNoteSalt: noteSalt,
12565
+ relaySupplementalAlt: true,
12566
+ onProgress: (s) => log(` \xB7 ${s}`)
12567
+ }
12568
+ );
12569
+ } catch (e) {
12570
+ const msg = e instanceof Error ? e.message : String(e);
12571
+ throw new DepositError(msg, fundedAccounts, measuredSize);
12572
+ }
12573
+ const rAfter = await conn.getBalance(R.publicKey);
12574
+ const noteIndex = result.outputUtxos[0].index;
12575
+ if (noteIndex === void 0) throw new Error("deposit landed but the note has no index \u2014 it cannot be discovered later");
12576
+ return {
12577
+ signature: result.signature,
12578
+ noteIndex,
12579
+ amount: result.outputUtxos[0].amount,
12580
+ txSize: measuredSize,
12581
+ rBefore,
12582
+ rAfter,
12583
+ rentExempt: rAfter >= MAINNET_RENT_0,
12584
+ inputNullifiers: result.inputNullifiers,
12585
+ fundedAccounts
12586
+ };
12587
+ }
12588
+
12589
+ // src/bridge/cleanup.ts
12590
+ var import_web318 = require("@solana/web3.js");
12591
+ var import_spl_token6 = require("@solana/spl-token");
12592
+ var DEFAULT_MINT = new import_web318.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
12593
+ async function cleanupReceivingAddress(conn, R, dustDestination, mint = DEFAULT_MINT) {
12594
+ assertAllowedRpcConnection(conn);
12595
+ const rAta = (0, import_spl_token6.getAssociatedTokenAddressSync)(mint, R.publicKey);
12596
+ const info = await conn.getAccountInfo(rAta);
12597
+ if (!info) {
12598
+ return {
12599
+ closed: false,
12600
+ dustSwept: 0n,
12601
+ rentReturned: 0,
12602
+ destination: null,
12603
+ signature: null,
12604
+ note: "no token account \u2014 nothing to recover"
12605
+ };
12606
+ }
12607
+ const bal = BigInt((await conn.getTokenAccountBalance(rAta)).value.amount);
12608
+ const rentHeld = info.lamports;
12609
+ const before = await conn.getBalance(R.publicKey);
12610
+ const ixs = [];
12611
+ let destination = null;
12612
+ if (bal > 0n && !dustDestination) {
12613
+ return {
12614
+ closed: false,
12615
+ dustSwept: 0n,
12616
+ rentReturned: 0,
12617
+ destination: null,
12618
+ signature: null,
12619
+ 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`
12620
+ };
12621
+ }
12622
+ if (bal > 0n && dustDestination) {
12623
+ const destAta = (0, import_spl_token6.getAssociatedTokenAddressSync)(mint, dustDestination);
12624
+ const destInfo = await conn.getAccountInfo(destAta);
12625
+ if (!destInfo) {
12626
+ const ataRent = await (0, import_spl_token6.getMinimumBalanceForRentExemptAccount)(conn);
12627
+ if (before < ataRent + CLEANUP_FEE_BUDGET) {
12628
+ throw new Error(
12629
+ `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.`
12630
+ );
12631
+ }
12632
+ ixs.push((0, import_spl_token6.createAssociatedTokenAccountIdempotentInstruction)(R.publicKey, destAta, dustDestination, mint));
12633
+ }
12634
+ ixs.push((0, import_spl_token6.createTransferInstruction)(rAta, destAta, R.publicKey, bal));
12635
+ destination = destAta.toBase58();
12636
+ }
12637
+ ixs.push((0, import_spl_token6.createCloseAccountInstruction)(rAta, R.publicKey, R.publicKey));
12638
+ const signature = await (0, import_web318.sendAndConfirmTransaction)(conn, new import_web318.Transaction().add(...ixs), [R], {
12639
+ commitment: "confirmed"
12640
+ });
12641
+ const after = await conn.getBalance(R.publicKey);
12642
+ const gone = await conn.getAccountInfo(rAta) === null;
12643
+ return {
12644
+ closed: gone,
12645
+ dustSwept: bal,
12646
+ rentReturned: after - before,
12647
+ destination,
12648
+ signature,
12649
+ 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`
12650
+ };
12651
+ }
12652
+
12653
+ // src/bridge/quote.ts
12654
+ var MIN_DEPOSIT_SPL_BASE_UNITS = 1000000n;
12655
+ var WITHDRAW_FIXED_FEE = 450000n;
12656
+ var WITHDRAW_FEE_BPS = 30n;
12657
+ function withdrawFeeAt(amount, fixedFee, feeBps) {
12658
+ return fixedFee + amount * feeBps / 10000n;
12659
+ }
12660
+ var MAX_FEE_FRACTION = 0.063;
12661
+ var FIXED_ROUND_TRIP = 903000n;
12662
+ var ECONOMIC_MINIMUM = FIXED_ROUND_TRIP * 1000000n / BigInt(Math.round((MAX_FEE_FRACTION - 3e-3) * 1e6));
12663
+ function withdrawFeeFor(amount) {
12664
+ return withdrawFeeAt(amount, WITHDRAW_FIXED_FEE, WITHDRAW_FEE_BPS);
12665
+ }
12666
+ function assessBridgeQuote(q) {
12667
+ if (q.sent < 0n) {
12668
+ throw new Error(`assessBridgeQuote: sent must not be negative (got ${q.sent}).`);
12669
+ }
12670
+ if (q.arrivesMin > q.sent) {
12671
+ throw new Error(
12672
+ `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.`
12673
+ );
12674
+ }
12675
+ const shieldedMinRaw = q.arrivesMin - q.paymasterFee;
12676
+ const shieldedTargetRaw = q.arrivesTarget - q.paymasterFee;
12677
+ const shieldedMin = shieldedMinRaw > 0n ? shieldedMinRaw : 0n;
12678
+ const shieldedTarget = shieldedTargetRaw > 0n ? shieldedTargetRaw : 0n;
12679
+ const viable = shieldedMinRaw >= MIN_DEPOSIT_SPL_BASE_UNITS;
12680
+ const economic = q.sent >= ECONOMIC_MINIMUM;
12681
+ const withdrawFee = shieldedMin > 0n ? withdrawFeeAt(shieldedMin, q.liveWithdrawFixedFee ?? WITHDRAW_FIXED_FEE, q.liveWithdrawFeeBps ?? WITHDRAW_FEE_BPS) : 0n;
12682
+ const roundTripCost = q.sent - (shieldedMin > withdrawFee ? shieldedMin - withdrawFee : 0n);
12683
+ const roundTripFraction = q.sent > 0n ? Number(roundTripCost) / Number(q.sent) : 0;
12684
+ const reasons = [];
12685
+ if (!viable) {
12686
+ const short = MIN_DEPOSIT_SPL_BASE_UNITS - shieldedMinRaw;
12687
+ reasons.push(
12688
+ (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.`
12689
+ );
12690
+ }
12691
+ if (viable && !economic) {
12692
+ reasons.push(
12693
+ `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.`
12694
+ );
12695
+ }
12696
+ return {
12697
+ ...q,
12698
+ shieldedMin,
12699
+ shieldedTarget,
12700
+ viable,
12701
+ economic,
12702
+ withdrawFee,
12703
+ roundTripCost,
12704
+ roundTripFraction,
12705
+ reasons
12706
+ };
12707
+ }
12708
+ var fmt = (v) => `${(Number(v) / 1e6).toFixed(6)} USDC`;
12709
+ function renderAssessment(a) {
12710
+ const L = [];
12711
+ L.push(` you send ${fmt(a.sent)}`);
12712
+ L.push(` arrives at least ${fmt(a.arrivesMin)} (target ${fmt(a.arrivesTarget)}, not a promise)`);
12713
+ L.push(` paymaster fee ${fmt(a.paymasterFee)} buys the receiver its SOL, so your wallet stays off chain`);
12714
+ L.push(` SHIELDED ${fmt(a.shieldedMin)} at least \u2014 this is what you end up with`);
12715
+ L.push(` to withdraw later ${fmt(a.withdrawFee)} the program's fee, whenever you take it out`);
12716
+ for (const r of a.reasons) L.push(`
12717
+ ${a.viable ? "NOTE" : "REFUSED"}: ${r}`);
12718
+ return L.join("\n");
12719
+ }
12720
+
12721
+ // src/bridge/retry.ts
12722
+ var TERMINAL_FAILURE = /DepositTooSmall|minimum is 1\.000000|insufficient|holds only|below the program|kora wants|over the .* ceiling/i;
12723
+ function isTerminalFailure(message) {
12724
+ return TERMINAL_FAILURE.test(message);
12725
+ }
12726
+ function classifyPostFailure(attempted, after) {
12727
+ if (after === null) return "unknown";
12728
+ if (after === 0n) return "landed";
12729
+ if (after >= attempted) return "did-not-land";
12730
+ return "unknown";
12731
+ }
12732
+ function mayRetry(verdict, message) {
12733
+ return verdict === "did-not-land" && !isTerminalFailure(message);
12734
+ }
12735
+ function retryDelayMs(attempt) {
12736
+ return 15e3 * Math.max(0, attempt - 1);
12737
+ }
12738
+ var DoNotRetry = class extends Error {
12739
+ constructor(message) {
12740
+ super(message);
12741
+ this.name = "DoNotRetry";
12742
+ }
12743
+ };
12744
+ async function withShieldRetries(attempt, hooks = {}) {
12745
+ const attempts = hooks.attempts ?? 3;
12746
+ const sleep4 = hooks.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
12747
+ let last = "";
12748
+ for (let n = 1; n <= attempts; n++) {
12749
+ if (n > 1) {
12750
+ const delay = retryDelayMs(n);
12751
+ hooks.onRetry?.(n, delay, last);
12752
+ await sleep4(delay);
12753
+ }
12754
+ try {
12755
+ return await attempt(n);
12756
+ } catch (e) {
12757
+ if (e instanceof DoNotRetry) throw e;
12758
+ last = e instanceof Error ? e.message : String(e);
12759
+ if (isTerminalFailure(last) || n === attempts) throw e;
12760
+ }
12761
+ }
12762
+ throw new Error("unreachable");
12763
+ }
12764
+
11635
12765
  // src/index.ts
11636
- var VERSION = "0.2.1";
12766
+ var VERSION = "0.2.3";
11637
12767
  var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11638
12768
  // Annotate the CommonJS export names for ESM import in node:
11639
12769
  0 && (module.exports = {
12770
+ BRIDGE_ESCROW_LABEL,
11640
12771
  BUILD_ALLOWS_LOCAL_ENDPOINTS,
11641
12772
  CHAIN_NOTE_SALT_BITS,
12773
+ CLEANUP_FEE_BUDGET,
11642
12774
  CLOAK_PRODUCTION_RELAY_URL,
11643
12775
  CLOAK_PROGRAM_ID,
11644
12776
  CloakError,
@@ -11646,25 +12778,38 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11646
12778
  DEFAULT_TRANSACTION_CIRCUITS_URL,
11647
12779
  DELIVERY_MEMO_TAG,
11648
12780
  DELIVERY_REGISTRY_SEED,
12781
+ DepositError,
12782
+ DoNotRetry,
12783
+ ECONOMIC_MINIMUM,
11649
12784
  EXPECTED_CIRCUIT_HASHES,
12785
+ FEE_BUDGET,
11650
12786
  FIXED_FEE_LAMPORTS,
11651
12787
  InsecureRandomnessError,
11652
12788
  LAMPORTS_PER_SOL,
11653
12789
  LocalStorageAdapter,
12790
+ MAINNET_RENT_0,
12791
+ MAINNET_RENT_1,
12792
+ MAX_RECEIVER_INDEX,
11654
12793
  MERKLE_TREE_HEIGHT,
11655
12794
  MIN_DEPOSIT_LAMPORTS,
12795
+ MIN_DEPOSIT_SPL_BASE_UNITS,
11656
12796
  MemoryStorageAdapter,
11657
12797
  MerkleTree,
11658
12798
  NATIVE_SOL_MINT,
12799
+ ONECLICK_PUBKEY_B58,
11659
12800
  RECIPIENT_DELIVERY_CIPHERTEXT_LEN,
11660
12801
  RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN,
11661
12802
  RECIPIENT_DELIVERY_NONCE_LEN,
11662
12803
  RECIPIENT_DELIVERY_NOTE_BYTES,
11663
12804
  RECIPIENT_DELIVERY_PLAINTEXT_LEN,
11664
12805
  RECIPIENT_DELIVERY_TAG_LEN,
12806
+ RELAY_BATCH_AUTH_MAX_ITEMS,
11665
12807
  RELAY_ORIGIN_ALLOWLIST,
12808
+ REQUEST_AUTH_BATCH_DOMAIN,
12809
+ REQUEST_AUTH_BATCH_MAX_AGE_SECONDS,
11666
12810
  REQUEST_AUTH_MAX_AGE_SECONDS,
11667
12811
  REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS,
12812
+ RelayBatchAuthCoordinator,
11668
12813
  RelayInternalError,
11669
12814
  RelayService,
11670
12815
  RootNotFoundError,
@@ -11674,6 +12819,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11674
12819
  SettlementVerificationError,
11675
12820
  ShieldPoolErrors,
11676
12821
  SimpleWallet,
12822
+ TERMINAL_FAILURE,
11677
12823
  TRANSACTION_CIRCUITS_VERSION,
11678
12824
  TRANSACT_AUTH_FIELDS,
11679
12825
  TRANSACT_SWAP_AUTH_FIELDS,
@@ -11683,8 +12829,12 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11683
12829
  VARIABLE_FEE_NUMERATOR,
11684
12830
  VARIABLE_FEE_RATE,
11685
12831
  VERSION,
12832
+ WITHDRAW_FEE_BPS,
12833
+ WITHDRAW_FIXED_FEE,
11686
12834
  assertDirectSubmissionLanded,
12835
+ assertInputMints,
11687
12836
  assertTransactionCircuitIntegrity,
12837
+ assessBridgeQuote,
11688
12838
  bigintToBytes32,
11689
12839
  bigintToHex,
11690
12840
  buildMerkleTree,
@@ -11692,6 +12842,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11692
12842
  buildMerkleTreeFromRelay,
11693
12843
  buildRecipientDeliveryNotes,
11694
12844
  buildRelayAuthPreimage,
12845
+ buildRelayBatchAuthMessage,
11695
12846
  buildTransactRequestBody,
11696
12847
  bytesToHex,
11697
12848
  calculateFee,
@@ -11699,12 +12850,16 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11699
12850
  calculateRelayFee,
11700
12851
  canRebuildMerkleTreeFromChain,
11701
12852
  canonicalJson,
12853
+ canonicalPayloadString,
11702
12854
  chainNoteFromBase64,
11703
12855
  chainNoteToBase64,
12856
+ classifyPostFailure,
11704
12857
  classifyRelayError,
12858
+ cleanupReceivingAddress,
11705
12859
  cleanupStalePendingOperations,
11706
12860
  clearPendingDeposits,
11707
12861
  clearPendingWithdrawals,
12862
+ cloakBridgeRail,
11708
12863
  computeChainNoteHash,
11709
12864
  computeExtDataHash,
11710
12865
  computeMerkleRoot,
@@ -11721,15 +12876,19 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11721
12876
  createLogger,
11722
12877
  createRecoverableChangeUtxo,
11723
12878
  createRecoverableDepositUtxo,
12879
+ createRelayBatchAuthCoordinator,
11724
12880
  createUtxo,
11725
12881
  createZeroUtxo,
11726
12882
  decryptCompactChainNote,
11727
12883
  decryptComplianceMetadataWithMasterKey,
11728
12884
  decryptTransactionMetadata,
12885
+ depositFromDerivedKey,
12886
+ deriveBridgeReceiver,
11729
12887
  deriveChangeNoteBlinding,
11730
12888
  deriveDepositNoteSecrets,
11731
12889
  deriveDiversifiedViewingKey,
11732
12890
  deriveDiversifier,
12891
+ deriveFundingTargets,
11733
12892
  deriveInputNullifierPdas,
11734
12893
  derivePublicKey,
11735
12894
  deriveSpendKey,
@@ -11768,6 +12927,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11768
12927
  formatErrorForLogging,
11769
12928
  formatSol,
11770
12929
  fullWithdraw,
12930
+ fundReceiverViaPaymaster,
11771
12931
  generateCloakKeys,
11772
12932
  generateCommitmentAsync,
11773
12933
  generateMasterSeed,
@@ -11803,18 +12963,21 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11803
12963
  isReactNative,
11804
12964
  isRootNotFoundError,
11805
12965
  isSubmissionOutcomeUnknownResponse,
12966
+ isTerminalFailure,
11806
12967
  isValidHex,
11807
12968
  isValidRpcUrl,
11808
12969
  isValidSolanaAddress,
11809
12970
  isWithdrawAmountSufficient,
11810
12971
  isWithdrawable,
11811
12972
  keypairToAdapter,
12973
+ listBridgeDeposits,
11812
12974
  loadPendingDeposits,
11813
12975
  loadPendingWithdrawals,
11814
12976
  loadVerifiedCircuitArtifacts,
11815
12977
  matchChangeNote,
11816
12978
  matchDepositNote,
11817
12979
  matchSwapRefundLeaf,
12980
+ mayRetry,
11818
12981
  openRecipientDeliveryNote,
11819
12982
  parseAmount,
11820
12983
  parseDeliveryCarrierMemo,
@@ -11837,11 +13000,15 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11837
13000
  randomDepositNoteSalt,
11838
13001
  randomFieldElement,
11839
13002
  readMerkleTreeState,
13003
+ readRent,
11840
13004
  recipientDeliveryNoteToBase64,
11841
13005
  registerViewingKey,
13006
+ relayRequestDigestHex,
11842
13007
  removePendingDeposit,
11843
13008
  removePendingWithdrawal,
13009
+ renderAssessment,
11844
13010
  resolveCircuitsBase,
13011
+ retryDelayMs,
11845
13012
  savePendingDeposit,
11846
13013
  savePendingWithdrawal,
11847
13014
  scanNotesForWallet,
@@ -11862,6 +13029,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11862
13029
  swapWithChange,
11863
13030
  toComplianceReport,
11864
13031
  transact,
13032
+ transactBatch,
11865
13033
  transfer,
11866
13034
  truncate,
11867
13035
  tryDecryptNote,
@@ -11874,13 +13042,17 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
11874
13042
  validateDepositParams,
11875
13043
  validateNote,
11876
13044
  validateOutputsSum,
13045
+ validatePaymasterTopUpTransaction,
11877
13046
  validateRoot,
11878
13047
  validateTransfers,
11879
13048
  validateWalletConnected,
11880
13049
  validateWithdrawableNote,
11881
13050
  verifyAllCircuits,
11882
13051
  verifyCircuitIntegrity,
13052
+ verifyQuoteSignature,
11883
13053
  verifyUtxos,
11884
13054
  waitForRoot,
11885
- withTiming
13055
+ withShieldRetries,
13056
+ withTiming,
13057
+ withdrawFeeFor
11886
13058
  });