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

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.js CHANGED
@@ -577,9 +577,9 @@ var LocalStorageAdapter = class {
577
577
  };
578
578
 
579
579
  // src/scanning/compliance-keys.ts
580
- import nacl2 from "tweetnacl";
580
+ import nacl3 from "tweetnacl";
581
581
  import { blake3 as blake32 } from "@noble/hashes/blake3";
582
- import { sha256 } from "@noble/hashes/sha2";
582
+ import { sha256 as sha2562 } from "@noble/hashes/sha2";
583
583
 
584
584
  // src/relay/viewing-key.ts
585
585
  var VIEWING_KEY_CHALLENGE_PREFIX = "CLOAK_VIEWING_KEY_REGISTER";
@@ -766,6 +766,275 @@ function connectionRpcEndpoint(connection) {
766
766
  return connection?._rpcEndpoint ?? connection?.rpcEndpoint;
767
767
  }
768
768
 
769
+ // src/relay/payload.ts
770
+ import { sha256 } from "@noble/hashes/sha2";
771
+ import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
772
+ import nacl2 from "tweetnacl";
773
+ import { Keypair, PublicKey as PublicKey3, SystemProgram, Transaction } from "@solana/web3.js";
774
+ var REQUEST_AUTH_DOMAIN = "CLOAK_RELAY_REQUEST_AUTH_V1";
775
+ var REQUEST_AUTH_MAX_AGE_SECONDS = 300;
776
+ var REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS = 30;
777
+ var RELAY_AUTH_APPROVAL_MARGIN_SECONDS = 15;
778
+ function sha256Hex(text) {
779
+ return bytesToHex2(sha256(new TextEncoder().encode(text)));
780
+ }
781
+ function randomNonceUuid() {
782
+ const webCrypto = globalThis?.crypto;
783
+ if (typeof webCrypto?.randomUUID === "function") return webCrypto.randomUUID();
784
+ const proc = globalThis?.process;
785
+ const nodeCrypto = typeof proc?.getBuiltinModule === "function" ? proc.getBuiltinModule("node:crypto") : void 0;
786
+ if (typeof nodeCrypto?.randomUUID === "function") return nodeCrypto.randomUUID();
787
+ const bytes = randomBytes(16);
788
+ bytes[6] = bytes[6] & 15 | 64;
789
+ bytes[8] = bytes[8] & 63 | 128;
790
+ const hex = bytesToHex2(bytes);
791
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
792
+ }
793
+ var TRANSACT_AUTH_FIELDS = [
794
+ "encrypted_notes",
795
+ "max_fee",
796
+ "mint",
797
+ "proof_bytes",
798
+ "public_inputs",
799
+ "recipient",
800
+ "recipient_delivery_notes",
801
+ "risk_quote",
802
+ "sender"
803
+ ];
804
+ var TRANSACT_SWAP_AUTH_FIELDS = [
805
+ "close_timed_out",
806
+ "dexes",
807
+ "encrypted_notes",
808
+ "exclude_dexes",
809
+ "max_fee",
810
+ "min_output_amount",
811
+ "output_mint",
812
+ "proof_bytes",
813
+ "public_inputs",
814
+ "recipient",
815
+ "recipient_ata",
816
+ "refund_blinding",
817
+ "refund_pubkey",
818
+ "retry_request_id",
819
+ "risk_quote",
820
+ "route_retry_attempts",
821
+ "sender",
822
+ "slippage_bps",
823
+ "swap_max_retries"
824
+ ];
825
+ var UTF8 = new TextEncoder();
826
+ function compareKeysBytewise(a, b) {
827
+ if (a === b) return 0;
828
+ const ab = UTF8.encode(a);
829
+ const bb = UTF8.encode(b);
830
+ const shared = Math.min(ab.length, bb.length);
831
+ for (let i = 0; i < shared; i++) {
832
+ if (ab[i] !== bb[i]) return ab[i] - bb[i];
833
+ }
834
+ return ab.length - bb.length;
835
+ }
836
+ function canonicalJson(value) {
837
+ if (value === null || value === void 0) return "null";
838
+ if (typeof value === "boolean") return value ? "true" : "false";
839
+ if (typeof value === "number") {
840
+ if (!Number.isFinite(value) || !Number.isInteger(value) || !Number.isSafeInteger(value)) {
841
+ throw new Error(
842
+ `canonicalJson: refusing to sign the number ${String(value)}. The relay renders numbers with serde_json, which spells non-integer, non-finite and very large values differently from JavaScript, so the two digests would differ and the request would be rejected with an unexplained 401. Send it as a decimal string instead, which is how every amount in this schema travels.`
843
+ );
844
+ }
845
+ return String(value);
846
+ }
847
+ if (typeof value === "bigint") return value.toString();
848
+ if (typeof value === "string") return JSON.stringify(value);
849
+ if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
850
+ if (typeof value === "object") {
851
+ const obj = value;
852
+ const keys = Object.keys(obj).sort(compareKeysBytewise);
853
+ return "{" + keys.map((k) => {
854
+ const v = obj[k];
855
+ if (typeof v === "function" || typeof v === "symbol") {
856
+ throw new Error(
857
+ `canonicalJson: the key "${k}" holds a ${typeof v}, which has no JSON representation. JSON.stringify would drop it from the wire body while it stayed in the signed view, so the relay's digest could never match this one.`
858
+ );
859
+ }
860
+ return `${JSON.stringify(k)}:${canonicalJson(v)}`;
861
+ }).join(",") + "}";
862
+ }
863
+ throw new Error(`canonicalJson: unsupported value of type ${typeof value}`);
864
+ }
865
+ var FIELDS_WITHOUT_NULL_ENCODING = {
866
+ slippage_bps: "500 (`default_slippage_bps` in api/transact_swap.rs)"
867
+ };
868
+ function buildAuthRequest(body, sender, fields) {
869
+ const out = {};
870
+ for (const k of fields) {
871
+ if (k === "sender") {
872
+ out[k] = sender;
873
+ continue;
874
+ }
875
+ const value = body[k];
876
+ if (value === void 0 || value === null) {
877
+ const relayDefault = FIELDS_WITHOUT_NULL_ENCODING[k];
878
+ if (relayDefault) {
879
+ throw new Error(
880
+ `Relay request auth: \`${k}\` must be present in the body. It is the one field in this schema that is not optional on the relay side: when it is missing the relay signs its default, ${relayDefault}, while this request would sign null. The two digests differ and the relay answers 401 "Relay request signature does not match the exact request", which points at nothing. Set \`${k}\` explicitly, to the same value the body will carry.`
881
+ );
882
+ }
883
+ out[k] = null;
884
+ continue;
885
+ }
886
+ out[k] = value;
887
+ }
888
+ return out;
889
+ }
890
+ function buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request) {
891
+ const digest = sha256Hex(canonicalJson(request));
892
+ return new TextEncoder().encode(
893
+ `${REQUEST_AUTH_DOMAIN}
894
+ ${endpoint}
895
+ ${programId.toBase58()}
896
+ ${nonce}
897
+ ${issuedAt}
898
+ ${digest}`
899
+ );
900
+ }
901
+ function buildRelayAuthPreimage(endpoint, programId, body, sender, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
902
+ const senderB58 = sender.toBase58();
903
+ const issuedAt = String(nowSeconds ?? Math.floor(Date.now() / 1e3));
904
+ const nonce = randomNonceUuid();
905
+ const request = buildAuthRequest({ ...body, sender: senderB58 }, senderB58, fields);
906
+ const message = buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request);
907
+ return { sender: senderB58, auth_issued_at: issuedAt, auth_nonce: nonce, message };
908
+ }
909
+ function signRelayRequest(endpoint, programId, body, signer, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
910
+ const preimage = buildRelayAuthPreimage(
911
+ endpoint,
912
+ programId,
913
+ body,
914
+ signer.publicKey,
915
+ nowSeconds,
916
+ fields
917
+ );
918
+ const signature = nacl2.sign.detached(preimage.message, signer.secretKey);
919
+ return {
920
+ sender: preimage.sender,
921
+ auth_issued_at: preimage.auth_issued_at,
922
+ auth_nonce: preimage.auth_nonce,
923
+ auth_signature: Buffer.from(signature).toString("base64")
924
+ };
925
+ }
926
+ function buildAuthTransactionMessage(sender, digest) {
927
+ if (digest.length !== 32) throw new Error(`auth transaction digest must be 32 bytes (got ${digest.length})`);
928
+ const tx = new Transaction();
929
+ tx.add(SystemProgram.transfer({ fromPubkey: sender, toPubkey: sender, lamports: 0 }));
930
+ tx.feePayer = sender;
931
+ tx.recentBlockhash = new PublicKey3(digest).toBase58();
932
+ return tx;
933
+ }
934
+ function serializeAuthTransactionMessage(sender, digest) {
935
+ return Uint8Array.from(buildAuthTransactionMessage(sender, digest).compileMessage().serialize());
936
+ }
937
+ async function signRelayAuthPayload(signer, payload) {
938
+ if (signer instanceof Keypair) {
939
+ return { signature: nacl2.sign.detached(payload, signer.secretKey), mode: "message" };
940
+ }
941
+ if (signer.signMessage) {
942
+ const signature = await signer.signMessage(payload);
943
+ assertDetachedSignature(signature, "signMessage");
944
+ return { signature, mode: "message" };
945
+ }
946
+ if (signer.signAuthTransaction) {
947
+ const digest = sha256(payload);
948
+ const signed = await signer.signAuthTransaction(buildAuthTransactionMessage(signer.walletPublicKey, digest));
949
+ const own = signed.signatures.find((s) => s.publicKey.equals(signer.walletPublicKey))?.signature;
950
+ if (!own) {
951
+ throw new Error(
952
+ "The wallet returned no signature for the Cloak auth transaction. Nothing was submitted."
953
+ );
954
+ }
955
+ const signature = Uint8Array.from(own);
956
+ assertDetachedSignature(signature, "signTransaction");
957
+ return { signature, mode: "transaction" };
958
+ }
959
+ throw new Error("Relay auth signer has neither signMessage nor signAuthTransaction.");
960
+ }
961
+ function assertDetachedSignature(signature, method) {
962
+ if (!(signature instanceof Uint8Array) || signature.length !== 64) {
963
+ throw new Error(
964
+ `The wallet's ${method} did not return a 64-byte ed25519 detached signature (got ${signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature}). Cloak signs with a raw detached signature over the bytes it hands the wallet; adapters that wrap or re-encode the result cannot be used here.`
965
+ );
966
+ }
967
+ }
968
+ function assertApprovalWithinFreshnessWindow(elapsedMs, maxAgeSeconds = REQUEST_AUTH_MAX_AGE_SECONDS) {
969
+ const elapsedSeconds = elapsedMs / 1e3;
970
+ const budget = maxAgeSeconds - RELAY_AUTH_APPROVAL_MARGIN_SECONDS;
971
+ if (elapsedSeconds <= budget) return;
972
+ throw new Error(
973
+ `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.`
974
+ );
975
+ }
976
+ function explainRelayAuthRejection(responseText) {
977
+ const text = String(responseText);
978
+ const has = (needle) => text.includes(needle);
979
+ if (has("issued too far in the future")) {
980
+ return `This computer's clock is more than ${REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS} seconds ahead of the network's, so the request looks like it was signed in the future and is refused before anything else happens. Turn on automatic date and time (or resynchronise the clock) and try again. Nothing was submitted.`;
981
+ }
982
+ if (has("signature expired")) {
983
+ return `The request was signed more than ${REQUEST_AUTH_MAX_AGE_SECONDS} seconds before it arrived, usually because a wallet approval was left waiting, or because this computer's clock is running behind. The signed timestamp cannot be refreshed on its own. Start the operation again. Nothing was submitted.`;
984
+ }
985
+ if (has("does not match the exact request")) {
986
+ return `The request body changed after it was signed, so the relay's digest and this one disagree. Sign the exact body that is POSTed, and re-POST a retry byte for byte rather than rebuilding it. If this is a hand-built swap call, check that every field in TRANSACT_SWAP_AUTH_FIELDS is present, including \`slippage_bps\`.`;
987
+ }
988
+ if (has("has no registered viewing key")) {
989
+ return `The signature was accepted, so this is not a signing problem: the wallet that signed has no viewing key registered with Cloak yet. Register one first, or let the SDK do it by leaving \`enforceViewingKeyRegistration\` on and supplying the viewing key.`;
990
+ }
991
+ if (has("Authenticated sender is required") || has("auth_issued_at is required") || has("auth_nonce is required") || has("auth_signature is required")) {
992
+ return `The request reached the relay without its authentication fields. Pass \`depositorKeypair\`, or \`signMessage\` together with \`walletPublicKey\`, so the request can be signed.`;
993
+ }
994
+ if (has("auth_nonce must be a canonical UUID")) {
995
+ return `\`auth_nonce\` must be a canonical lowercase UUID. Reuse the one from the preimage.`;
996
+ }
997
+ if (has("Relay request signature must be exactly 64 bytes") || has("Invalid relay request signature encoding")) {
998
+ return `\`auth_signature\` must be the raw 64-byte ed25519 detached signature, base64 encoded. Wallet adapters that wrap or re-encode what \`signMessage\` returns cannot be used here.`;
999
+ }
1000
+ return null;
1001
+ }
1002
+ async function buildRelayAuthFields(endpoint, programId, body, signers, fields = TRANSACT_AUTH_FIELDS) {
1003
+ if (signers.depositorKeypair) {
1004
+ return signRelayRequest(endpoint, programId, body, signers.depositorKeypair, void 0, fields);
1005
+ }
1006
+ const wallet = signers.relayAuthSigner;
1007
+ if (!wallet) return null;
1008
+ const preimage = buildRelayAuthPreimage(
1009
+ endpoint,
1010
+ programId,
1011
+ body,
1012
+ wallet.walletPublicKey,
1013
+ void 0,
1014
+ fields
1015
+ );
1016
+ const approvalStartedMs = Date.now();
1017
+ const { signature, mode } = await signRelayAuthPayload(wallet, preimage.message);
1018
+ assertApprovalWithinFreshnessWindow(Date.now() - approvalStartedMs);
1019
+ return {
1020
+ sender: preimage.sender,
1021
+ auth_issued_at: preimage.auth_issued_at,
1022
+ auth_nonce: preimage.auth_nonce,
1023
+ auth_signature: Buffer.from(signature).toString("base64"),
1024
+ ...mode === "transaction" ? { auth_mode: mode } : {}
1025
+ };
1026
+ }
1027
+ var REQUEST_AUTH_BATCH_DOMAIN = "CLOAK_RELAY_BATCH_AUTH_V1";
1028
+ var REQUEST_AUTH_BATCH_MAX_AGE_SECONDS = 600;
1029
+ var RELAY_BATCH_AUTH_MAX_ITEMS = 64;
1030
+ function relayRequestDigestHex(preimage) {
1031
+ return bytesToHex2(sha256(preimage.message));
1032
+ }
1033
+ function buildRelayBatchAuthMessage(programId, issuedAt, digests) {
1034
+ const lines = [REQUEST_AUTH_BATCH_DOMAIN, programId.toBase58(), issuedAt, String(digests.length)];
1035
+ return new TextEncoder().encode([...lines, ...digests].join("\n"));
1036
+ }
1037
+
769
1038
  // src/scanning/compliance-keys.ts
770
1039
  var X25519_KEY_LENGTH = 32;
771
1040
  var DIVERSIFIER_LENGTH = 11;
@@ -803,7 +1072,7 @@ function deriveViewingKeyFromNk(nk) {
803
1072
  preimage.set(nk, CHAIN_NOTE_VK_DOMAIN.length);
804
1073
  const derived = blake32(preimage);
805
1074
  const privateKey = clampX25519Secret(derived);
806
- const publicKey = nacl2.scalarMult.base(privateKey);
1075
+ const publicKey = nacl3.scalarMult.base(privateKey);
807
1076
  return { privateKey, publicKey };
808
1077
  }
809
1078
  function deriveDiversifier(nk, commitmentHex, outputIndex) {
@@ -838,7 +1107,7 @@ function deriveDiversifiedViewingKey(nk, diversifier) {
838
1107
  preimage.set(diversifier, SK_D_DOMAIN.length + nk.length);
839
1108
  const derived = blake32(preimage);
840
1109
  const privateKey = clampX25519Secret(derived);
841
- const publicKey = nacl2.scalarMult.base(privateKey);
1110
+ const publicKey = nacl3.scalarMult.base(privateKey);
842
1111
  return { privateKey, publicKey };
843
1112
  }
844
1113
  function deriveViewingKeyFromSpendKey(skSpend) {
@@ -901,19 +1170,19 @@ async function deriveUserCompliancePublicKey(masterCompliancePublicKey, userPubl
901
1170
  masterCompliancePublicKey,
902
1171
  userPublicKey
903
1172
  );
904
- return nacl2.scalarMult(factor, masterCompliancePublicKey);
1173
+ return nacl3.scalarMult(factor, masterCompliancePublicKey);
905
1174
  }
906
- function bytesToHex2(bytes) {
1175
+ function bytesToHex3(bytes) {
907
1176
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
908
1177
  }
909
1178
  function computeViewingKeyIdentifier(userPubkey, nkHex) {
910
1179
  const preimage = new TextEncoder().encode(`${userPubkey.toBase58()}${nkHex}`);
911
- return bytesToHex2(sha256(preimage));
1180
+ return bytesToHex3(sha2562(preimage));
912
1181
  }
913
1182
  var SIGN_IN_MESSAGE = "Cloak: Sign in\n\nSign this message to securely access your Cloak account.\nThis does NOT authorize any transaction or spend any funds.";
914
1183
  async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
915
1184
  assert32Bytes(nk, "nk");
916
- const nkHex = bytesToHex2(nk);
1185
+ const nkHex = bytesToHex3(nk);
917
1186
  const keyId = computeViewingKeyIdentifier(userPubkey, nkHex);
918
1187
  const challengeResponse = await relayFetch(`${relayUrl}/viewing-key/challenge`, {
919
1188
  method: "POST",
@@ -934,8 +1203,11 @@ async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
934
1203
  nkHex
935
1204
  );
936
1205
  const messageBytes = new TextEncoder().encode(challenge.message);
937
- const signatureBytes = await signMessage(messageBytes);
938
- const signature = Buffer.from(signatureBytes).toString("base64");
1206
+ const signed = await signRelayAuthPayload(
1207
+ typeof signMessage === "function" ? { walletPublicKey: userPubkey, signMessage } : signMessage,
1208
+ messageBytes
1209
+ );
1210
+ const signature = Buffer.from(signed.signature).toString("base64");
939
1211
  const response = await relayFetch(`${relayUrl}/viewing-key/register`, {
940
1212
  method: "POST",
941
1213
  headers: { "Content-Type": "application/json" },
@@ -944,7 +1216,8 @@ async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
944
1216
  viewing_key: nkHex,
945
1217
  nonce: challenge.nonce,
946
1218
  identifier: keyId,
947
- signature
1219
+ signature,
1220
+ ...signed.mode === "transaction" ? { auth_mode: signed.mode } : {}
948
1221
  })
949
1222
  });
950
1223
  if (!response.ok) {
@@ -953,7 +1226,7 @@ async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
953
1226
  }
954
1227
 
955
1228
  // src/scanning/metadata-encryption.ts
956
- import nacl3 from "tweetnacl";
1229
+ import nacl4 from "tweetnacl";
957
1230
  var AES_GCM_NONCE_LENGTH = 12;
958
1231
  var AES_GCM_TAG_LENGTH = 16;
959
1232
  var X25519_KEY_LENGTH2 = 32;
@@ -1050,8 +1323,8 @@ async function aesGcmDecrypt(ciphertext, keyBytes, nonce) {
1050
1323
  }
1051
1324
  async function encryptForRecipient(plaintext, recipientPublicKey) {
1052
1325
  assert32Bytes2(recipientPublicKey, "recipientPublicKey");
1053
- const ephemeral = nacl3.box.keyPair();
1054
- const sharedSecret = nacl3.scalarMult(ephemeral.secretKey, recipientPublicKey);
1326
+ const ephemeral = nacl4.box.keyPair();
1327
+ const sharedSecret = nacl4.scalarMult(ephemeral.secretKey, recipientPublicKey);
1055
1328
  const nonce = randomBytes(AES_GCM_NONCE_LENGTH);
1056
1329
  const ciphertext = await aesGcmEncrypt(plaintext, sharedSecret, nonce);
1057
1330
  return {
@@ -1110,7 +1383,7 @@ async function encryptTransactionMetadataBundle(metadata, viewingKeyPrivate, use
1110
1383
  const plaintext = new TextEncoder().encode(JSON.stringify(metadata));
1111
1384
  const basePoint = new Uint8Array(32);
1112
1385
  basePoint[0] = 9;
1113
- const viewingKeyPublic = nacl3.scalarMult(viewingKeyPrivate, basePoint);
1386
+ const viewingKeyPublic = nacl4.scalarMult(viewingKeyPrivate, basePoint);
1114
1387
  const [userPayload, compliancePayload] = await Promise.all([
1115
1388
  encryptForRecipient(plaintext, viewingKeyPublic),
1116
1389
  encryptForRecipient(plaintext, viewingKeyPublic)
@@ -1129,7 +1402,7 @@ async function decryptTransactionMetadata(encrypted, viewKeySecret) {
1129
1402
  const payload = decodePayload(encrypted);
1130
1403
  const ephemeralPk = hexToBytes(payload.ephemeral_pk);
1131
1404
  assert32Bytes2(ephemeralPk, "ephemeral public key");
1132
- const sharedSecret = nacl3.scalarMult(viewKeySecret, ephemeralPk);
1405
+ const sharedSecret = nacl4.scalarMult(viewKeySecret, ephemeralPk);
1133
1406
  return decryptWithSharedSecret(payload, sharedSecret);
1134
1407
  }
1135
1408
  async function decryptComplianceMetadataWithMasterKey(encrypted, masterCompliancePrivateKey, masterCompliancePublicKey, userPublicKey) {
@@ -1142,8 +1415,8 @@ async function decryptComplianceMetadataWithMasterKey(encrypted, masterComplianc
1142
1415
  masterCompliancePublicKey,
1143
1416
  userPublicKey
1144
1417
  );
1145
- const scaledEphemeral = nacl3.scalarMult(userFactor, ephemeralPk);
1146
- const sharedSecret = nacl3.scalarMult(masterCompliancePrivateKey, scaledEphemeral);
1418
+ const scaledEphemeral = nacl4.scalarMult(userFactor, ephemeralPk);
1419
+ const sharedSecret = nacl4.scalarMult(masterCompliancePrivateKey, scaledEphemeral);
1147
1420
  return decryptWithSharedSecret(payload, sharedSecret);
1148
1421
  }
1149
1422
 
@@ -2073,22 +2346,22 @@ function formatErrorForLogging(error) {
2073
2346
  }
2074
2347
 
2075
2348
  // src/program/pda.ts
2076
- import { PublicKey as PublicKey3 } from "@solana/web3.js";
2349
+ import { PublicKey as PublicKey4 } from "@solana/web3.js";
2077
2350
  function getShieldPoolPDAs(programId, mint = NATIVE_SOL_MINT) {
2078
2351
  const pid = programId || CLOAK_PROGRAM_ID;
2079
- const [pool] = PublicKey3.findProgramAddressSync(
2352
+ const [pool] = PublicKey4.findProgramAddressSync(
2080
2353
  [Buffer.from("pool"), mint.toBuffer()],
2081
2354
  pid
2082
2355
  );
2083
- const [merkleTree] = PublicKey3.findProgramAddressSync(
2356
+ const [merkleTree] = PublicKey4.findProgramAddressSync(
2084
2357
  [Buffer.from("merkle_tree"), mint.toBuffer()],
2085
2358
  pid
2086
2359
  );
2087
- const [treasury] = PublicKey3.findProgramAddressSync(
2360
+ const [treasury] = PublicKey4.findProgramAddressSync(
2088
2361
  [Buffer.from("treasury"), mint.toBuffer()],
2089
2362
  pid
2090
2363
  );
2091
- const [vaultAuthority] = PublicKey3.findProgramAddressSync(
2364
+ const [vaultAuthority] = PublicKey4.findProgramAddressSync(
2092
2365
  [Buffer.from("vault_authority"), mint.toBuffer()],
2093
2366
  pid
2094
2367
  );
@@ -2104,7 +2377,7 @@ function getNullifierPDA(poolPubkey, nullifier, programId) {
2104
2377
  if (nullifier.length !== 32) {
2105
2378
  throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2106
2379
  }
2107
- return PublicKey3.findProgramAddressSync(
2380
+ return PublicKey4.findProgramAddressSync(
2108
2381
  [Buffer.from("nullifier"), poolPubkey.toBuffer(), Buffer.from(nullifier)],
2109
2382
  pid
2110
2383
  );
@@ -2114,25 +2387,25 @@ function getSwapStatePDA(poolPubkey, nullifier, programId) {
2114
2387
  if (nullifier.length !== 32) {
2115
2388
  throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2116
2389
  }
2117
- return PublicKey3.findProgramAddressSync(
2390
+ return PublicKey4.findProgramAddressSync(
2118
2391
  [Buffer.from("swap_state"), poolPubkey.toBuffer(), Buffer.from(nullifier)],
2119
2392
  pid
2120
2393
  );
2121
2394
  }
2122
2395
  function getPoolAuthorityConfigPDA(mint = NATIVE_SOL_MINT, programId) {
2123
2396
  const pid = programId || CLOAK_PROGRAM_ID;
2124
- return PublicKey3.findProgramAddressSync(
2397
+ return PublicKey4.findProgramAddressSync(
2125
2398
  [Buffer.from("pool_authority"), mint.toBuffer()],
2126
2399
  pid
2127
2400
  );
2128
2401
  }
2129
2402
  function getDeliveryRegistryPDA(programId) {
2130
2403
  const pid = programId || CLOAK_PROGRAM_ID;
2131
- return PublicKey3.findProgramAddressSync([Buffer.from("cloak_delivery_registry")], pid)[0];
2404
+ return PublicKey4.findProgramAddressSync([Buffer.from("cloak_delivery_registry")], pid)[0];
2132
2405
  }
2133
2406
  function getChainNoteRegistryPDA(programId) {
2134
2407
  const pid = programId || CLOAK_PROGRAM_ID;
2135
- return PublicKey3.findProgramAddressSync([Buffer.from("cloak_chain_note_registry")], pid)[0];
2408
+ return PublicKey4.findProgramAddressSync([Buffer.from("cloak_chain_note_registry")], pid)[0];
2136
2409
  }
2137
2410
 
2138
2411
  // src/flows/verify-utxos.ts
@@ -2463,7 +2736,8 @@ function truncate(str, len = 20) {
2463
2736
  var sdkLogger = createLogger("cloak::sdk");
2464
2737
 
2465
2738
  // src/relay/relay-service.ts
2466
- import { sha256 as sha2562 } from "@noble/hashes/sha2";
2739
+ import { sha256 as sha2563 } from "@noble/hashes/sha2";
2740
+ import { PublicKey as PublicKey5 } from "@solana/web3.js";
2467
2741
  var RelayService = class {
2468
2742
  /**
2469
2743
  * Create a new Relay Service client
@@ -2779,8 +3053,11 @@ var RelayService = class {
2779
3053
  userPubkey,
2780
3054
  viewingKey
2781
3055
  );
2782
- const signatureBytes = await signMessage(new TextEncoder().encode(challenge.message));
2783
- const signature = this.bytesToBase64(signatureBytes);
3056
+ const signed = await signRelayAuthPayload(
3057
+ typeof signMessage === "function" ? { walletPublicKey: new PublicKey5(userPubkey), signMessage } : signMessage,
3058
+ new TextEncoder().encode(challenge.message)
3059
+ );
3060
+ const signature = this.bytesToBase64(signed.signature);
2784
3061
  const response = await relayFetch(`${this.baseUrl}/viewing-key/register`, {
2785
3062
  method: "POST",
2786
3063
  headers: { "Content-Type": "application/json" },
@@ -2789,7 +3066,8 @@ var RelayService = class {
2789
3066
  viewing_key: viewingKey,
2790
3067
  nonce: challenge.nonce,
2791
3068
  identifier,
2792
- signature
3069
+ signature,
3070
+ ...signed.mode === "transaction" ? { auth_mode: signed.mode } : {}
2793
3071
  })
2794
3072
  });
2795
3073
  if (!response.ok) {
@@ -2827,7 +3105,7 @@ var RelayService = class {
2827
3105
  }
2828
3106
  computeViewingKeyIdentifier(userPubkey, viewingKeyHex) {
2829
3107
  const preimage = new TextEncoder().encode(`${userPubkey}${viewingKeyHex}`);
2830
- const hash = sha2562(preimage);
3108
+ const hash = sha2563(preimage);
2831
3109
  return Array.from(hash).map((b) => b.toString(16).padStart(2, "0")).join("");
2832
3110
  }
2833
3111
  };
@@ -2945,10 +3223,10 @@ function encodeNoteSimple(note) {
2945
3223
 
2946
3224
  // src/wallet/adapter.ts
2947
3225
  import {
2948
- Keypair
3226
+ Keypair as Keypair2
2949
3227
  } from "@solana/web3.js";
2950
3228
  function validateWalletConnected(wallet) {
2951
- if (wallet instanceof Keypair) {
3229
+ if (wallet instanceof Keypair2) {
2952
3230
  return;
2953
3231
  }
2954
3232
  if (!wallet.publicKey) {
@@ -2960,7 +3238,7 @@ function validateWalletConnected(wallet) {
2960
3238
  }
2961
3239
  }
2962
3240
  function getPublicKey(wallet) {
2963
- if (wallet instanceof Keypair) {
3241
+ if (wallet instanceof Keypair2) {
2964
3242
  return wallet.publicKey;
2965
3243
  }
2966
3244
  if (!wallet.publicKey) {
@@ -2974,7 +3252,7 @@ function getPublicKey(wallet) {
2974
3252
  }
2975
3253
  async function sendTransaction(transaction, wallet, connection, options) {
2976
3254
  assertAllowedRpcConnection(connection);
2977
- if (wallet instanceof Keypair) {
3255
+ if (wallet instanceof Keypair2) {
2978
3256
  return await connection.sendTransaction(transaction, [wallet], options);
2979
3257
  }
2980
3258
  if (wallet.sendTransaction) {
@@ -2991,7 +3269,7 @@ async function sendTransaction(transaction, wallet, connection, options) {
2991
3269
  }
2992
3270
  }
2993
3271
  async function signTransaction(transaction, wallet) {
2994
- if (wallet instanceof Keypair) {
3272
+ if (wallet instanceof Keypair2) {
2995
3273
  transaction.sign(wallet);
2996
3274
  return transaction;
2997
3275
  }
@@ -3020,8 +3298,8 @@ function keypairToAdapter(keypair) {
3020
3298
 
3021
3299
  // src/program/instructions.ts
3022
3300
  import {
3023
- PublicKey as PublicKey5,
3024
- SystemProgram,
3301
+ PublicKey as PublicKey7,
3302
+ SystemProgram as SystemProgram2,
3025
3303
  TransactionInstruction
3026
3304
  } from "@solana/web3.js";
3027
3305
  function createDepositInstruction(params) {
@@ -3053,7 +3331,7 @@ function createDepositInstruction(params) {
3053
3331
  // Account 1: Pool (writable) - receives SOL
3054
3332
  { pubkey: params.pool, isSigner: false, isWritable: true },
3055
3333
  // Account 2: System Program (readonly) - for transfers
3056
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
3334
+ { pubkey: SystemProgram2.programId, isSigner: false, isWritable: false },
3057
3335
  // Account 3: Merkle Tree (writable) - stores on-chain Merkle tree
3058
3336
  { pubkey: params.merkleTree, isSigner: false, isWritable: true }
3059
3337
  ],
@@ -3061,16 +3339,16 @@ function createDepositInstruction(params) {
3061
3339
  });
3062
3340
  }
3063
3341
  function validateDepositParams(params) {
3064
- if (!(params.programId instanceof PublicKey5)) {
3342
+ if (!(params.programId instanceof PublicKey7)) {
3065
3343
  throw new Error("programId must be a PublicKey");
3066
3344
  }
3067
- if (!(params.payer instanceof PublicKey5)) {
3345
+ if (!(params.payer instanceof PublicKey7)) {
3068
3346
  throw new Error("payer must be a PublicKey");
3069
3347
  }
3070
- if (!(params.pool instanceof PublicKey5)) {
3348
+ if (!(params.pool instanceof PublicKey7)) {
3071
3349
  throw new Error("pool must be a PublicKey");
3072
3350
  }
3073
- if (!(params.merkleTree instanceof PublicKey5)) {
3351
+ if (!(params.merkleTree instanceof PublicKey7)) {
3074
3352
  throw new Error("merkleTree must be a PublicKey");
3075
3353
  }
3076
3354
  if (typeof params.amount !== "number" || params.amount <= 0) {
@@ -3410,7 +3688,7 @@ async function buildMerkleTree(commitments, height = MERKLE_TREE_HEIGHT2) {
3410
3688
  }
3411
3689
 
3412
3690
  // src/relay/client.ts
3413
- import { PublicKey as PublicKey6 } from "@solana/web3.js";
3691
+ import { PublicKey as PublicKey8 } from "@solana/web3.js";
3414
3692
  import _bs58 from "bs58";
3415
3693
 
3416
3694
  // src/notes/refund-leaf.ts
@@ -3527,7 +3805,7 @@ var CLOSE_SWAP_STATE_TAG = 13;
3527
3805
  var CLOSE_SWAP_STATE_PHASE1_PAYLOAD_LEN = 40;
3528
3806
  var CLOSE_SWAP_STATE_PHASE1_WIRE_LEN = 1 + CLOSE_SWAP_STATE_PHASE1_PAYLOAD_LEN;
3529
3807
  var CLOSE_SWAP_STATE_COMMITMENT_END = 1 + 32;
3530
- var NATIVE_SOL_MINT2 = new PublicKey6("So11111111111111111111111111111111111111112");
3808
+ var NATIVE_SOL_MINT2 = new PublicKey8("So11111111111111111111111111111111111111112");
3531
3809
  var PROOF_LEN = 256;
3532
3810
  var PUBLIC_INPUTS_LEN = 264;
3533
3811
  var COMMITMENTS_OFFSET = 168;
@@ -3817,11 +4095,11 @@ async function preflightCheck(relayUrl, rootHex) {
3817
4095
 
3818
4096
  // src/flows/transact.ts
3819
4097
  import {
3820
- PublicKey as PublicKey8,
3821
- Transaction as Transaction2,
4098
+ PublicKey as PublicKey10,
4099
+ Transaction as Transaction3,
3822
4100
  TransactionInstruction as TransactionInstruction2,
3823
4101
  sendAndConfirmTransaction,
3824
- SystemProgram as SystemProgram2,
4102
+ SystemProgram as SystemProgram3,
3825
4103
  ComputeBudgetProgram,
3826
4104
  SYSVAR_INSTRUCTIONS_PUBKEY,
3827
4105
  SYSVAR_SLOT_HASHES_PUBKEY,
@@ -4060,7 +4338,7 @@ function chainNoteFromBase64(base64) {
4060
4338
  }
4061
4339
 
4062
4340
  // src/notes/delivery-note.ts
4063
- import nacl4 from "tweetnacl";
4341
+ import nacl5 from "tweetnacl";
4064
4342
  var RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN = 32;
4065
4343
  var RECIPIENT_DELIVERY_NONCE_LEN = 24;
4066
4344
  var RECIPIENT_DELIVERY_PLAINTEXT_LEN = 40;
@@ -4111,10 +4389,10 @@ function encodeRecipientDeliveryNote(note, recipientViewingPublicKey) {
4111
4389
  const plaintext = new Uint8Array(RECIPIENT_DELIVERY_PLAINTEXT_LEN);
4112
4390
  writeU64LE2(plaintext, 0, note.amount);
4113
4391
  writeU256BE2(plaintext, 8, note.blinding);
4114
- const ephemeral = nacl4.box.keyPair();
4115
- const shared = nacl4.box.before(recipientViewingPublicKey, ephemeral.secretKey);
4116
- const nonce = nacl4.randomBytes(nacl4.secretbox.nonceLength);
4117
- const ciphertext = nacl4.secretbox(plaintext, nonce, shared);
4392
+ const ephemeral = nacl5.box.keyPair();
4393
+ const shared = nacl5.box.before(recipientViewingPublicKey, ephemeral.secretKey);
4394
+ const nonce = nacl5.randomBytes(nacl5.secretbox.nonceLength);
4395
+ const ciphertext = nacl5.secretbox(plaintext, nonce, shared);
4118
4396
  if (ciphertext.length !== RECIPIENT_DELIVERY_CIPHERTEXT_LEN) {
4119
4397
  throw new Error(
4120
4398
  `delivery ciphertext must be ${RECIPIENT_DELIVERY_CIPHERTEXT_LEN} bytes, got ${ciphertext.length}`
@@ -4140,8 +4418,8 @@ function openRecipientDeliveryNote(envelope, viewingSecretKey) {
4140
4418
  const ciphertext = envelope.slice(
4141
4419
  RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN + RECIPIENT_DELIVERY_NONCE_LEN
4142
4420
  );
4143
- const shared = nacl4.box.before(ephemeralPk, viewingSecretKey);
4144
- const plaintext = nacl4.secretbox.open(ciphertext, nonce, shared);
4421
+ const shared = nacl5.box.before(ephemeralPk, viewingSecretKey);
4422
+ const plaintext = nacl5.secretbox.open(ciphertext, nonce, shared);
4145
4423
  if (!plaintext || plaintext.length !== RECIPIENT_DELIVERY_PLAINTEXT_LEN) return null;
4146
4424
  return { amount: readU64LE2(plaintext, 0), blinding: readU256BE2(plaintext, 8) };
4147
4425
  } catch {
@@ -4199,7 +4477,7 @@ function parseDeliveryCarrierMemo(data) {
4199
4477
 
4200
4478
  // src/notes/swap-refund.ts
4201
4479
  import { blake3 as blake33 } from "@noble/hashes/blake3";
4202
- import { PublicKey as PublicKey7 } from "@solana/web3.js";
4480
+ import { PublicKey as PublicKey9 } from "@solana/web3.js";
4203
4481
  import _bs582 from "bs58";
4204
4482
  var bs582 = _bs582.default || _bs582;
4205
4483
  var REFUND_SEED_DOMAIN = new TextEncoder().encode("cloak_swap_refund_v1");
@@ -4344,7 +4622,7 @@ async function discoverSwapRefunds(connection, programId, viewingKeyNk, options
4344
4622
  const { limit = 0, untilSignature, batchSize = 50, onStatus } = options;
4345
4623
  const poolMint = options.poolMint ?? NATIVE_SOL_MINT;
4346
4624
  const programIdBase58 = programId.toBase58();
4347
- const [pool] = PublicKey7.findProgramAddressSync(
4625
+ const [pool] = PublicKey9.findProgramAddressSync(
4348
4626
  [Buffer.from("pool"), poolMint.toBuffer()],
4349
4627
  programId
4350
4628
  );
@@ -4395,7 +4673,7 @@ async function discoverSwapRefunds(connection, programId, viewingKeyNk, options
4395
4673
  if (data[0] !== TRANSACT_SWAP_TAG2 || data.length < MIN_TRANSACT_SWAP_LEN) continue;
4396
4674
  const nullifier = data.slice(NULLIFIER_0_OFFSET, NULLIFIER_0_OFFSET + 32);
4397
4675
  if (nullifier.length !== 32) continue;
4398
- const [swapState] = PublicKey7.findProgramAddressSync(
4676
+ const [swapState] = PublicKey9.findProgramAddressSync(
4399
4677
  [Buffer.from("swap_state"), pool.toBuffer(), Buffer.from(nullifier)],
4400
4678
  programId
4401
4679
  );
@@ -4622,236 +4900,6 @@ async function matchChangeNote(params) {
4622
4900
  import { buildPoseidon as buildPoseidon2 } from "circomlibjs";
4623
4901
  import nacl6 from "tweetnacl";
4624
4902
 
4625
- // src/relay/payload.ts
4626
- import { sha256 as sha2563 } from "@noble/hashes/sha2";
4627
- import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils";
4628
- import nacl5 from "tweetnacl";
4629
- var REQUEST_AUTH_DOMAIN = "CLOAK_RELAY_REQUEST_AUTH_V1";
4630
- var REQUEST_AUTH_MAX_AGE_SECONDS = 300;
4631
- var REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS = 30;
4632
- var RELAY_AUTH_APPROVAL_MARGIN_SECONDS = 15;
4633
- function sha256Hex(text) {
4634
- return bytesToHex3(sha2563(new TextEncoder().encode(text)));
4635
- }
4636
- function randomNonceUuid() {
4637
- const webCrypto = globalThis?.crypto;
4638
- if (typeof webCrypto?.randomUUID === "function") return webCrypto.randomUUID();
4639
- const proc = globalThis?.process;
4640
- const nodeCrypto = typeof proc?.getBuiltinModule === "function" ? proc.getBuiltinModule("node:crypto") : void 0;
4641
- if (typeof nodeCrypto?.randomUUID === "function") return nodeCrypto.randomUUID();
4642
- const bytes = randomBytes(16);
4643
- bytes[6] = bytes[6] & 15 | 64;
4644
- bytes[8] = bytes[8] & 63 | 128;
4645
- const hex = bytesToHex3(bytes);
4646
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
4647
- }
4648
- var TRANSACT_AUTH_FIELDS = [
4649
- "encrypted_notes",
4650
- "max_fee",
4651
- "mint",
4652
- "proof_bytes",
4653
- "public_inputs",
4654
- "recipient",
4655
- "recipient_delivery_notes",
4656
- "risk_quote",
4657
- "sender"
4658
- ];
4659
- var TRANSACT_SWAP_AUTH_FIELDS = [
4660
- "close_timed_out",
4661
- "dexes",
4662
- "encrypted_notes",
4663
- "exclude_dexes",
4664
- "max_fee",
4665
- "min_output_amount",
4666
- "output_mint",
4667
- "proof_bytes",
4668
- "public_inputs",
4669
- "recipient",
4670
- "recipient_ata",
4671
- "refund_blinding",
4672
- "refund_pubkey",
4673
- "retry_request_id",
4674
- "risk_quote",
4675
- "route_retry_attempts",
4676
- "sender",
4677
- "slippage_bps",
4678
- "swap_max_retries"
4679
- ];
4680
- var UTF8 = new TextEncoder();
4681
- function compareKeysBytewise(a, b) {
4682
- if (a === b) return 0;
4683
- const ab = UTF8.encode(a);
4684
- const bb = UTF8.encode(b);
4685
- const shared = Math.min(ab.length, bb.length);
4686
- for (let i = 0; i < shared; i++) {
4687
- if (ab[i] !== bb[i]) return ab[i] - bb[i];
4688
- }
4689
- return ab.length - bb.length;
4690
- }
4691
- function canonicalJson(value) {
4692
- if (value === null || value === void 0) return "null";
4693
- if (typeof value === "boolean") return value ? "true" : "false";
4694
- if (typeof value === "number") {
4695
- if (!Number.isFinite(value) || !Number.isInteger(value) || !Number.isSafeInteger(value)) {
4696
- throw new Error(
4697
- `canonicalJson: refusing to sign the number ${String(value)}. The relay renders numbers with serde_json, which spells non-integer, non-finite and very large values differently from JavaScript, so the two digests would differ and the request would be rejected with an unexplained 401. Send it as a decimal string instead, which is how every amount in this schema travels.`
4698
- );
4699
- }
4700
- return String(value);
4701
- }
4702
- if (typeof value === "bigint") return value.toString();
4703
- if (typeof value === "string") return JSON.stringify(value);
4704
- if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
4705
- if (typeof value === "object") {
4706
- const obj = value;
4707
- const keys = Object.keys(obj).sort(compareKeysBytewise);
4708
- return "{" + keys.map((k) => {
4709
- const v = obj[k];
4710
- if (typeof v === "function" || typeof v === "symbol") {
4711
- throw new Error(
4712
- `canonicalJson: the key "${k}" holds a ${typeof v}, which has no JSON representation. JSON.stringify would drop it from the wire body while it stayed in the signed view, so the relay's digest could never match this one.`
4713
- );
4714
- }
4715
- return `${JSON.stringify(k)}:${canonicalJson(v)}`;
4716
- }).join(",") + "}";
4717
- }
4718
- throw new Error(`canonicalJson: unsupported value of type ${typeof value}`);
4719
- }
4720
- var FIELDS_WITHOUT_NULL_ENCODING = {
4721
- slippage_bps: "500 (`default_slippage_bps` in api/transact_swap.rs)"
4722
- };
4723
- function buildAuthRequest(body, sender, fields) {
4724
- const out = {};
4725
- for (const k of fields) {
4726
- if (k === "sender") {
4727
- out[k] = sender;
4728
- continue;
4729
- }
4730
- const value = body[k];
4731
- if (value === void 0 || value === null) {
4732
- const relayDefault = FIELDS_WITHOUT_NULL_ENCODING[k];
4733
- if (relayDefault) {
4734
- throw new Error(
4735
- `Relay request auth: \`${k}\` must be present in the body. It is the one field in this schema that is not optional on the relay side: when it is missing the relay signs its default, ${relayDefault}, while this request would sign null. The two digests differ and the relay answers 401 "Relay request signature does not match the exact request", which points at nothing. Set \`${k}\` explicitly, to the same value the body will carry.`
4736
- );
4737
- }
4738
- out[k] = null;
4739
- continue;
4740
- }
4741
- out[k] = value;
4742
- }
4743
- return out;
4744
- }
4745
- function buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request) {
4746
- const digest = sha256Hex(canonicalJson(request));
4747
- return new TextEncoder().encode(
4748
- `${REQUEST_AUTH_DOMAIN}
4749
- ${endpoint}
4750
- ${programId.toBase58()}
4751
- ${nonce}
4752
- ${issuedAt}
4753
- ${digest}`
4754
- );
4755
- }
4756
- function buildRelayAuthPreimage(endpoint, programId, body, sender, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
4757
- const senderB58 = sender.toBase58();
4758
- const issuedAt = String(nowSeconds ?? Math.floor(Date.now() / 1e3));
4759
- const nonce = randomNonceUuid();
4760
- const request = buildAuthRequest({ ...body, sender: senderB58 }, senderB58, fields);
4761
- const message = buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request);
4762
- return { sender: senderB58, auth_issued_at: issuedAt, auth_nonce: nonce, message };
4763
- }
4764
- function signRelayRequest(endpoint, programId, body, signer, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
4765
- const preimage = buildRelayAuthPreimage(
4766
- endpoint,
4767
- programId,
4768
- body,
4769
- signer.publicKey,
4770
- nowSeconds,
4771
- fields
4772
- );
4773
- const signature = nacl5.sign.detached(preimage.message, signer.secretKey);
4774
- return {
4775
- sender: preimage.sender,
4776
- auth_issued_at: preimage.auth_issued_at,
4777
- auth_nonce: preimage.auth_nonce,
4778
- auth_signature: Buffer.from(signature).toString("base64")
4779
- };
4780
- }
4781
- function assertApprovalWithinFreshnessWindow(elapsedMs, maxAgeSeconds = REQUEST_AUTH_MAX_AGE_SECONDS) {
4782
- const elapsedSeconds = elapsedMs / 1e3;
4783
- const budget = maxAgeSeconds - RELAY_AUTH_APPROVAL_MARGIN_SECONDS;
4784
- if (elapsedSeconds <= budget) return;
4785
- throw new Error(
4786
- `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.`
4787
- );
4788
- }
4789
- function explainRelayAuthRejection(responseText) {
4790
- const text = String(responseText);
4791
- const has = (needle) => text.includes(needle);
4792
- if (has("issued too far in the future")) {
4793
- return `This computer's clock is more than ${REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS} seconds ahead of the network's, so the request looks like it was signed in the future and is refused before anything else happens. Turn on automatic date and time (or resynchronise the clock) and try again. Nothing was submitted.`;
4794
- }
4795
- if (has("signature expired")) {
4796
- return `The request was signed more than ${REQUEST_AUTH_MAX_AGE_SECONDS} seconds before it arrived, usually because a wallet approval was left waiting, or because this computer's clock is running behind. The signed timestamp cannot be refreshed on its own. Start the operation again. Nothing was submitted.`;
4797
- }
4798
- if (has("does not match the exact request")) {
4799
- return `The request body changed after it was signed, so the relay's digest and this one disagree. Sign the exact body that is POSTed, and re-POST a retry byte for byte rather than rebuilding it. If this is a hand-built swap call, check that every field in TRANSACT_SWAP_AUTH_FIELDS is present, including \`slippage_bps\`.`;
4800
- }
4801
- if (has("has no registered viewing key")) {
4802
- return `The signature was accepted, so this is not a signing problem: the wallet that signed has no viewing key registered with Cloak yet. Register one first, or let the SDK do it by leaving \`enforceViewingKeyRegistration\` on and supplying the viewing key.`;
4803
- }
4804
- if (has("Authenticated sender is required") || has("auth_issued_at is required") || has("auth_nonce is required") || has("auth_signature is required")) {
4805
- return `The request reached the relay without its authentication fields. Pass \`depositorKeypair\`, or \`signMessage\` together with \`walletPublicKey\`, so the request can be signed.`;
4806
- }
4807
- if (has("auth_nonce must be a canonical UUID")) {
4808
- return `\`auth_nonce\` must be a canonical lowercase UUID. Reuse the one from the preimage.`;
4809
- }
4810
- if (has("Relay request signature must be exactly 64 bytes") || has("Invalid relay request signature encoding")) {
4811
- return `\`auth_signature\` must be the raw 64-byte ed25519 detached signature, base64 encoded. Wallet adapters that wrap or re-encode what \`signMessage\` returns cannot be used here.`;
4812
- }
4813
- return null;
4814
- }
4815
- async function buildRelayAuthFields(endpoint, programId, body, signers, fields = TRANSACT_AUTH_FIELDS) {
4816
- if (signers.depositorKeypair) {
4817
- return signRelayRequest(endpoint, programId, body, signers.depositorKeypair, void 0, fields);
4818
- }
4819
- const wallet = signers.relayAuthSigner;
4820
- if (!wallet) return null;
4821
- const preimage = buildRelayAuthPreimage(
4822
- endpoint,
4823
- programId,
4824
- body,
4825
- wallet.walletPublicKey,
4826
- void 0,
4827
- fields
4828
- );
4829
- const approvalStartedMs = Date.now();
4830
- const signature = await wallet.signMessage(preimage.message);
4831
- assertApprovalWithinFreshnessWindow(Date.now() - approvalStartedMs);
4832
- if (!(signature instanceof Uint8Array) || signature.length !== 64) {
4833
- throw new Error(
4834
- `The wallet's signMessage did not return a 64-byte ed25519 detached signature (got ${signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature}). Cloak signs with a raw detached signature over the bytes it hands the wallet; adapters that wrap or re-encode the result cannot be used here. Pass depositorKeypair instead, or use an adapter whose signMessage returns the raw signature.`
4835
- );
4836
- }
4837
- return {
4838
- sender: preimage.sender,
4839
- auth_issued_at: preimage.auth_issued_at,
4840
- auth_nonce: preimage.auth_nonce,
4841
- auth_signature: Buffer.from(signature).toString("base64")
4842
- };
4843
- }
4844
- var REQUEST_AUTH_BATCH_DOMAIN = "CLOAK_RELAY_BATCH_AUTH_V1";
4845
- var REQUEST_AUTH_BATCH_MAX_AGE_SECONDS = 600;
4846
- var RELAY_BATCH_AUTH_MAX_ITEMS = 64;
4847
- function relayRequestDigestHex(preimage) {
4848
- return bytesToHex3(sha2563(preimage.message));
4849
- }
4850
- function buildRelayBatchAuthMessage(programId, issuedAt, digests) {
4851
- const lines = [REQUEST_AUTH_BATCH_DOMAIN, programId.toBase58(), issuedAt, String(digests.length)];
4852
- return new TextEncoder().encode([...lines, ...digests].join("\n"));
4853
- }
4854
-
4855
4903
  // src/proving/artifacts.ts
4856
4904
  import { sha256 as sha2564 } from "@noble/hashes/sha2";
4857
4905
 
@@ -5252,7 +5300,7 @@ async function fetchSupplementalAltFromRelay(relayUrl, params) {
5252
5300
  throw new Error("Supplemental ALT response is missing a 'table' address");
5253
5301
  }
5254
5302
  try {
5255
- return new PublicKey8(table);
5303
+ return new PublicKey10(table);
5256
5304
  } catch {
5257
5305
  throw new Error(`Supplemental ALT response 'table' is not a valid public key: ${table}`);
5258
5306
  }
@@ -5320,7 +5368,7 @@ async function resolveAddressLookupTableAccounts(connection, relayUrl, altAddres
5320
5368
  const fetched = await Promise.all(
5321
5369
  altAddresses.map(async (addr) => {
5322
5370
  try {
5323
- const pubkey = new PublicKey8(addr);
5371
+ const pubkey = new PublicKey10(addr);
5324
5372
  const result = await connection.getAddressLookupTable(pubkey);
5325
5373
  return result.value ?? null;
5326
5374
  } catch {
@@ -5410,7 +5458,7 @@ function calculateConfiguredProtocolFee(amount, config) {
5410
5458
  return total;
5411
5459
  }
5412
5460
  async function readLiveProtocolFee(connection, programId, mint, amount, requireSwapOpen = false) {
5413
- const [poolConfigPda] = PublicKey8.findProgramAddressSync(
5461
+ const [poolConfigPda] = PublicKey10.findProgramAddressSync(
5414
5462
  [Buffer.from("pool_config"), mint.toBuffer()],
5415
5463
  programId
5416
5464
  );
@@ -5572,17 +5620,27 @@ async function registerViewingKeyOnce(relayUrl, userPubkey, viewingKeyHex, cache
5572
5620
  viewingKeyHex
5573
5621
  );
5574
5622
  let signatureBase64;
5623
+ let authMode = "message";
5624
+ const messageBytes = new TextEncoder().encode(challenge.message);
5575
5625
  if (options.signMessage) {
5576
- const messageBytes = new TextEncoder().encode(challenge.message);
5577
5626
  const sig = await options.signMessage(messageBytes);
5578
5627
  signatureBase64 = Buffer.from(sig).toString("base64");
5579
5628
  } else if (options.depositorKeypair) {
5580
- const messageBytes = new TextEncoder().encode(challenge.message);
5581
5629
  const sig = nacl6.sign.detached(messageBytes, options.depositorKeypair.secretKey);
5582
5630
  signatureBase64 = Buffer.from(sig).toString("base64");
5631
+ } else if (options.signAuthTransaction) {
5632
+ onProgress?.(
5633
+ "Approve the viewing-key registration in your wallet. It shows as a 0 SOL transfer to yourself and is never sent to the network."
5634
+ );
5635
+ const signed = await signRelayAuthPayload(
5636
+ { walletPublicKey: userPubkey, signAuthTransaction: options.signAuthTransaction },
5637
+ messageBytes
5638
+ );
5639
+ signatureBase64 = Buffer.from(signed.signature).toString("base64");
5640
+ authMode = signed.mode;
5583
5641
  } else {
5584
5642
  throw new Error(
5585
- "Viewing key registration is mandatory: signMessage (wallet) or depositorKeypair is required."
5643
+ "Viewing key registration is mandatory: signMessage or signAuthTransaction (wallet) or depositorKeypair is required."
5586
5644
  );
5587
5645
  }
5588
5646
  onProgress?.("Registering viewing key...");
@@ -5593,7 +5651,8 @@ async function registerViewingKeyOnce(relayUrl, userPubkey, viewingKeyHex, cache
5593
5651
  user_pubkey: userPubkey.toBase58(),
5594
5652
  viewing_key: viewingKeyHex,
5595
5653
  nonce: challenge.nonce,
5596
- signature: signatureBase64
5654
+ signature: signatureBase64,
5655
+ ...authMode === "transaction" ? { auth_mode: authMode } : {}
5597
5656
  })
5598
5657
  });
5599
5658
  if (!response.ok) {
@@ -5687,7 +5746,7 @@ function buildPublicInputsBytesFromSignals(publicSignals) {
5687
5746
  var TRANSACT_DISCRIMINATOR = 0;
5688
5747
  var RANGE_QUOTE_TAG_DEPOSIT = 1;
5689
5748
  function deriveRiskNoncePDA(programId, nonce) {
5690
- return PublicKey8.findProgramAddressSync(
5749
+ return PublicKey10.findProgramAddressSync(
5691
5750
  [Buffer.from("risk_nonce"), Buffer.from(nonce)],
5692
5751
  programId
5693
5752
  );
@@ -5706,7 +5765,7 @@ function extractDepositNonceFromEd25519Ix(ix) {
5706
5765
  }
5707
5766
  }
5708
5767
  function deriveNullifierPDA(programId, poolPDA, nullifier) {
5709
- return PublicKey8.findProgramAddressSync(
5768
+ return PublicKey10.findProgramAddressSync(
5710
5769
  [Buffer.from("nullifier"), poolPDA.toBuffer(), Buffer.from(nullifier)],
5711
5770
  programId
5712
5771
  );
@@ -5739,7 +5798,7 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
5739
5798
  }
5740
5799
  if (!isDepositData) {
5741
5800
  data[offset++] = 3;
5742
- data.set((relayer ?? PublicKey8.default).toBytes(), offset);
5801
+ data.set((relayer ?? PublicKey10.default).toBytes(), offset);
5743
5802
  offset += 32;
5744
5803
  writeBigUInt64LE(data, relayerFee ?? BigInt(0), offset);
5745
5804
  offset += 8;
@@ -5769,7 +5828,7 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
5769
5828
  // 4. nullifier PDA 0 (writable)
5770
5829
  { pubkey: nullifierPDA1, isSigner: false, isWritable: true },
5771
5830
  // 5. nullifier PDA 1 (writable)
5772
- { pubkey: SystemProgram2.programId, isSigner: false, isWritable: false }
5831
+ { pubkey: SystemProgram3.programId, isSigner: false, isWritable: false }
5773
5832
  // 6. system_program
5774
5833
  ];
5775
5834
  if (splAccounts) {
@@ -5814,7 +5873,7 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
5814
5873
  var PACKET_LIMIT_BYTES = 1232;
5815
5874
  function getCommonALTAddresses() {
5816
5875
  return [
5817
- SystemProgram2.programId,
5876
+ SystemProgram3.programId,
5818
5877
  SYSVAR_SLOT_HASHES_PUBKEY,
5819
5878
  SYSVAR_INSTRUCTIONS_PUBKEY,
5820
5879
  ComputeBudgetProgram.programId
@@ -5892,7 +5951,7 @@ async function createEphemeralALT(connection, depositor, onProgress, additionalA
5892
5951
  allowSupplementalAlt
5893
5952
  );
5894
5953
  } else {
5895
- const tx = new Transaction2().add(createIx).add(extendIx);
5954
+ const tx = new Transaction3().add(createIx).add(extendIx);
5896
5955
  const { blockhash } = await connection.getLatestBlockhash();
5897
5956
  tx.recentBlockhash = blockhash;
5898
5957
  tx.feePayer = depositor.publicKey;
@@ -6553,7 +6612,7 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
6553
6612
  let legacyTransportAttempt = 0;
6554
6613
  while (true) {
6555
6614
  try {
6556
- const tx = new Transaction2();
6615
+ const tx = new Transaction3();
6557
6616
  for (const ix of instructions) {
6558
6617
  tx.add(ix);
6559
6618
  }
@@ -6777,7 +6836,7 @@ async function fetchRiskQuote(riskQuoteUrl, wallet, options) {
6777
6836
  const messageArr = hexToBytes2(messageHex);
6778
6837
  let signerPubkey;
6779
6838
  try {
6780
- signerPubkey = new PublicKey8(signerB58);
6839
+ signerPubkey = new PublicKey10(signerB58);
6781
6840
  } catch {
6782
6841
  throw new Error("Invalid risk quote response: signer_pubkey is not a public key");
6783
6842
  }
@@ -6878,18 +6937,22 @@ function planRelayAuth(options) {
6878
6937
  const walletPublicKey = resolveUserWallet(options);
6879
6938
  if (options.depositorKeypair) return { kind: "keypair" };
6880
6939
  const signMessage = options.signMessage;
6940
+ const signAuthTransaction = options.signAuthTransaction;
6881
6941
  if (walletPublicKey && signMessage) return { kind: "wallet", signer: { walletPublicKey, signMessage } };
6882
- if (!walletPublicKey && !signMessage) return { kind: "none" };
6942
+ if (walletPublicKey && signAuthTransaction) {
6943
+ return { kind: "wallet", signer: { walletPublicKey, signAuthTransaction } };
6944
+ }
6945
+ if (!walletPublicKey && !signMessage && !signAuthTransaction) return { kind: "none" };
6883
6946
  return {
6884
6947
  kind: "incomplete",
6885
- detail: signMessage ? "`signMessage` was provided but no wallet public key, so the request has no sender to authenticate as. Add `walletPublicKey` (or `depositorPublicKey`)." : "a wallet public key was provided but no `signMessage`, so nothing can sign. Add `signMessage` from the same wallet adapter."
6948
+ detail: signMessage || signAuthTransaction ? "a signer was provided but no wallet public key, so the request has no sender to authenticate as. Add `walletPublicKey` (or `depositorPublicKey`)." : "a wallet public key was provided but no `signMessage` and no `signAuthTransaction`, so nothing can sign. Add `signMessage` from the wallet adapter, or `signAuthTransaction` (its `signTransaction`) for a wallet that cannot sign messages."
6886
6949
  };
6887
6950
  }
6888
6951
  function assertRelayAuthAvailable(plan, flow) {
6889
6952
  if (plan.kind === "keypair" || plan.kind === "wallet") return;
6890
6953
  const cause = plan.kind === "none" ? "no signer was provided." : `the signer provided cannot produce one: ${plan.detail}`;
6891
6954
  throw new Error(
6892
- `Cloak ${flow} requires an authenticated sender, and ${cause} Pass either \`depositorKeypair\` (a local Keypair) or \`signMessage\` together with \`walletPublicKey\` (a browser wallet adapter). The sender must be the end user's own wallet. Checked before proof generation, so nothing has been computed or submitted yet.`
6955
+ `Cloak ${flow} requires an authenticated sender, and ${cause} Pass either \`depositorKeypair\` (a local Keypair), or \`signMessage\` (a browser wallet adapter) or \`signAuthTransaction\` (a hardware wallet that cannot sign messages) together with \`walletPublicKey\`. The sender must be the end user's own wallet. Checked up front, so nothing has been computed or submitted yet.`
6893
6956
  );
6894
6957
  }
6895
6958
  async function submitTransactToRelay(args) {
@@ -8035,7 +8098,7 @@ async function transact(params, options) {
8035
8098
  "All relay-tree attempts failed. Rebuilding merkle tree from chain as last resort..."
8036
8099
  );
8037
8100
  try {
8038
- const [merkleTreePda] = PublicKey8.findProgramAddressSync(
8101
+ const [merkleTreePda] = PublicKey10.findProgramAddressSync(
8039
8102
  [Buffer.from("merkle_tree"), mint.toBuffer()],
8040
8103
  programId
8041
8104
  );
@@ -9023,7 +9086,7 @@ async function swapUtxo(params, options) {
9023
9086
  }
9024
9087
  if (options.onSwapStatePredicted && inputNullifiers.length > 0) {
9025
9088
  const nBytes = bigintToBytes322(inputNullifiers[0]);
9026
- const [ssp] = PublicKey8.findProgramAddressSync(
9089
+ const [ssp] = PublicKey10.findProgramAddressSync(
9027
9090
  [Buffer.from("swap_state"), pdas.pool.toBuffer(), Buffer.from(nBytes)],
9028
9091
  programId
9029
9092
  );
@@ -9443,8 +9506,7 @@ function cleanupStalePendingOperations(maxAgeMs = 24 * 60 * 60 * 1e3) {
9443
9506
  }
9444
9507
 
9445
9508
  // src/relay/batch-auth.ts
9446
- import { Keypair as Keypair3 } from "@solana/web3.js";
9447
- import nacl7 from "tweetnacl";
9509
+ import { Keypair as Keypair4 } from "@solana/web3.js";
9448
9510
  var RelayBatchAuthCoordinator = class {
9449
9511
  constructor(options) {
9450
9512
  this.proofSlotsInUse = 0;
@@ -9467,7 +9529,7 @@ var RelayBatchAuthCoordinator = class {
9467
9529
  throw new Error(`submitConcurrency must be a positive integer (got ${concurrency}).`);
9468
9530
  }
9469
9531
  this.signer = options.signer;
9470
- this.sender = options.signer instanceof Keypair3 ? options.signer.publicKey : options.signer.walletPublicKey;
9532
+ this.sender = options.signer instanceof Keypair4 ? options.signer.publicKey : options.signer.walletPublicKey;
9471
9533
  this.expectedItems = options.items;
9472
9534
  this.submitConcurrency = concurrency;
9473
9535
  const proofConcurrency = options.proofConcurrency ?? 2;
@@ -9591,24 +9653,19 @@ var RelayBatchAuthCoordinator = class {
9591
9653
  const issuedAt = preimages[0].auth_issued_at;
9592
9654
  const message = buildRelayBatchAuthMessage(programId, issuedAt, digests);
9593
9655
  this.waves += 1;
9594
- let signature;
9595
- if (this.signer instanceof Keypair3) {
9596
- signature = nacl7.sign.detached(message, this.signer.secretKey);
9597
- } else {
9656
+ if (!(this.signer instanceof Keypair4)) {
9657
+ const asTransaction = !this.signer.signMessage;
9598
9658
  this.onProgress?.(
9599
- `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.`
9659
+ `Approve ${waiting.length} request(s) in your wallet` + (this.waves > 1 ? ` (approval ${this.waves}, for the rows that had to re-prove)` : "") + (asTransaction ? `. Your wallet shows this as a 0 SOL transfer to yourself: it is how a wallet that cannot sign messages authorizes the requests for the relay, and it is never sent to the network. Approve it on the device within a few minutes.` : `. This signs the requests for the relay, not a transaction, and must be approved within a few minutes to stay valid.`)
9600
9660
  );
9601
- const approvalStartedMs = Date.now();
9602
- signature = await this.signer.signMessage(message);
9661
+ }
9662
+ const approvalStartedMs = Date.now();
9663
+ const { signature, mode } = await signRelayAuthPayload(this.signer, message);
9664
+ if (!(this.signer instanceof Keypair4)) {
9603
9665
  assertApprovalWithinFreshnessWindow(
9604
9666
  Date.now() - approvalStartedMs,
9605
9667
  REQUEST_AUTH_BATCH_MAX_AGE_SECONDS
9606
9668
  );
9607
- if (!(signature instanceof Uint8Array) || signature.length !== 64) {
9608
- throw new Error(
9609
- `The wallet's signMessage did not return a 64-byte ed25519 detached signature (got ${signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature}).`
9610
- );
9611
- }
9612
9669
  }
9613
9670
  const signatureB64 = Buffer.from(signature).toString("base64");
9614
9671
  wave.forEach((item, i) => {
@@ -9620,6 +9677,7 @@ var RelayBatchAuthCoordinator = class {
9620
9677
  auth_issued_at: preimage.auth_issued_at,
9621
9678
  auth_nonce: preimage.auth_nonce,
9622
9679
  auth_signature: signatureB64,
9680
+ ...mode === "transaction" ? { auth_mode: mode } : {},
9623
9681
  // A fresh array per item: `Object.assign` puts this on the wire body, and the body is
9624
9682
  // serialized again on every network retry.
9625
9683
  auth_batch: { digests: [...digests] }
@@ -9668,10 +9726,18 @@ async function transactBatch(items, options) {
9668
9726
  throw new Error("transactBatch requires relayUrl: batch approval is a relay authentication scheme.");
9669
9727
  }
9670
9728
  const { proofConcurrency, submitConcurrency, ...shared } = options;
9671
- 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;
9729
+ const signer = shared.depositorKeypair ? shared.depositorKeypair : (() => {
9730
+ const wallet = shared.walletPublicKey ?? shared.depositorPublicKey;
9731
+ if (!wallet) return null;
9732
+ if (shared.signMessage) return { walletPublicKey: wallet, signMessage: shared.signMessage };
9733
+ if (shared.signAuthTransaction) {
9734
+ return { walletPublicKey: wallet, signAuthTransaction: shared.signAuthTransaction };
9735
+ }
9736
+ return null;
9737
+ })();
9672
9738
  if (!signer) {
9673
9739
  throw new Error(
9674
- "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."
9740
+ "transactBatch requires an authenticated sender: pass `depositorKeypair` (a local Keypair), or `walletPublicKey` with `signMessage` (a browser wallet adapter) or `signAuthTransaction` (a hardware wallet). Checked up front, so nothing has been computed or submitted yet."
9675
9741
  );
9676
9742
  }
9677
9743
  const coordinator = createRelayBatchAuthCoordinator({
@@ -9708,7 +9774,7 @@ async function transactBatch(items, options) {
9708
9774
  // src/scanning/scan.ts
9709
9775
  import _bs583 from "bs58";
9710
9776
  import {
9711
- PublicKey as PublicKey10
9777
+ PublicKey as PublicKey12
9712
9778
  } from "@solana/web3.js";
9713
9779
  import { getAssociatedTokenAddressSync as getAssociatedTokenAddressSync2 } from "@solana/spl-token";
9714
9780
  var bs583 = _bs583.default || _bs583;
@@ -9796,7 +9862,7 @@ function parseSwapOutputMint(data) {
9796
9862
  const mintBytes = data.slice(SWAP_OUTPUT_MINT_OFFSET, end);
9797
9863
  if (mintBytes.every((byte) => byte === 0)) return void 0;
9798
9864
  try {
9799
- return new PublicKey10(mintBytes).toBase58();
9865
+ return new PublicKey12(mintBytes).toBase58();
9800
9866
  } catch {
9801
9867
  return void 0;
9802
9868
  }
@@ -9886,7 +9952,7 @@ function parseSwapRecipientAta(data) {
9886
9952
  const recipientAtaBytes = data.slice(recipientAtaStart, recipientAtaEnd);
9887
9953
  if (recipientAtaBytes.every((byte) => byte === 0)) return void 0;
9888
9954
  try {
9889
- return new PublicKey10(recipientAtaBytes).toBase58();
9955
+ return new PublicKey12(recipientAtaBytes).toBase58();
9890
9956
  } catch {
9891
9957
  return void 0;
9892
9958
  }
@@ -10048,7 +10114,7 @@ async function scanSwapNoteCarriers(connection, programId, viewingKeyNk, swapCtx
10048
10114
  let rpcCalls = 0;
10049
10115
  const candidates = Array.from(swapCtxByCommitment.keys());
10050
10116
  if (candidates.length === 0) return { records, rpcCalls };
10051
- const [registry] = PublicKey10.findProgramAddressSync(
10117
+ const [registry] = PublicKey12.findProgramAddressSync(
10052
10118
  [Buffer.from("cloak_chain_note_registry")],
10053
10119
  programId
10054
10120
  );
@@ -10451,8 +10517,8 @@ async function scanTransactions(opts) {
10451
10517
  if (onChainAta) {
10452
10518
  try {
10453
10519
  const expectedAta = getAssociatedTokenAddressSync2(
10454
- new PublicKey10(asset.mint),
10455
- new PublicKey10(walletPublicKey)
10520
+ new PublicKey12(asset.mint),
10521
+ new PublicKey12(walletPublicKey)
10456
10522
  ).toBase58();
10457
10523
  if (onChainAta === expectedAta) {
10458
10524
  isOurs = true;
@@ -10666,7 +10732,7 @@ async function scanTransactions(opts) {
10666
10732
  // deposit — that is the public deposit amount. A deposit that also merged inputs
10667
10733
  // carries a larger output 0 and is not recoverable from public data alone.
10668
10734
  amount: grossAmount,
10669
- mintAddress: new PublicKey10(asset.mint),
10735
+ mintAddress: new PublicKey12(asset.mint),
10670
10736
  outputCommitments: ixCtx.outputCommitments ?? []
10671
10737
  });
10672
10738
  if (recoveredDeposit) {
@@ -10692,7 +10758,7 @@ async function scanTransactions(opts) {
10692
10758
  noteSalt: compactNote.noteSalt,
10693
10759
  amount: compactNote.outAmount0,
10694
10760
  keypair: { privateKey: 0n, publicKey: compactNote.outPubkey0 },
10695
- mintAddress: new PublicKey10(asset.mint),
10761
+ mintAddress: new PublicKey12(asset.mint),
10696
10762
  outputIndex: 0,
10697
10763
  // v4 describes output 0, which is where change lands
10698
10764
  outputCommitments: ixCtx.outputCommitments ?? []
@@ -10885,7 +10951,7 @@ function formatComplianceCsv(report) {
10885
10951
  }
10886
10952
 
10887
10953
  // src/wallet/utxo-wallet.ts
10888
- import { PublicKey as PublicKey11 } from "@solana/web3.js";
10954
+ import { PublicKey as PublicKey13 } from "@solana/web3.js";
10889
10955
  var UtxoWallet = class _UtxoWallet {
10890
10956
  constructor(viewingKey) {
10891
10957
  this.wallets = /* @__PURE__ */ new Map();
@@ -11097,7 +11163,7 @@ var UtxoWallet = class _UtxoWallet {
11097
11163
  data.viewingKey ? new Uint8Array(data.viewingKey) : void 0
11098
11164
  );
11099
11165
  for (const w of data.wallets) {
11100
- const mint = new PublicKey11(w.mint);
11166
+ const mint = new PublicKey13(w.mint);
11101
11167
  for (const u of w.utxos) {
11102
11168
  wallet.addUtxo({
11103
11169
  amount: BigInt(u.amount),
@@ -11180,7 +11246,7 @@ var SimpleWallet = class {
11180
11246
  };
11181
11247
 
11182
11248
  // src/bridge/rail-verify.ts
11183
- import nacl8 from "tweetnacl";
11249
+ import nacl7 from "tweetnacl";
11184
11250
  import { sha256 as sha2565 } from "@noble/hashes/sha256";
11185
11251
  var ONECLICK_PUBKEY_B58 = "reYaWhvwu8Jzo3WUM3zhn6VrhuMEF4eADL17qtRVifc";
11186
11252
  var b58 = /* @__PURE__ */ (() => {
@@ -11291,7 +11357,7 @@ function verifyQuoteSignature(resp) {
11291
11357
  const message = new TextEncoder().encode(b58.encode(new Uint8Array(digest)));
11292
11358
  const sig = resp.signature.replace(/^ed25519:/, "");
11293
11359
  try {
11294
- return { valid: nacl8.sign.detached.verify(message, b58.decode(sig), b58.decode(ONECLICK_PUBKEY_B58)) };
11360
+ return { valid: nacl7.sign.detached.verify(message, b58.decode(sig), b58.decode(ONECLICK_PUBKEY_B58)) };
11295
11361
  } catch (e) {
11296
11362
  return { valid: false, reason: e instanceof Error ? e.message : String(e) };
11297
11363
  }
@@ -11390,10 +11456,10 @@ function cloakBridgeRail(relayUrl) {
11390
11456
 
11391
11457
  // src/bridge/paymaster-client.ts
11392
11458
  import {
11393
- PublicKey as PublicKey12,
11459
+ PublicKey as PublicKey14,
11394
11460
  SystemInstruction,
11395
- SystemProgram as SystemProgram3,
11396
- Transaction as Transaction3
11461
+ SystemProgram as SystemProgram4,
11462
+ Transaction as Transaction4
11397
11463
  } from "@solana/web3.js";
11398
11464
  import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID3, decodeTransferInstruction, getAssociatedTokenAddressSync as getAssociatedTokenAddressSync3 } from "@solana/spl-token";
11399
11465
  function validatePaymasterTopUpTransaction(tx, expect) {
@@ -11404,7 +11470,7 @@ function validatePaymasterTopUpTransaction(tx, expect) {
11404
11470
  );
11405
11471
  }
11406
11472
  const ix0 = ixs[0];
11407
- if (!ix0.programId.equals(SystemProgram3.programId)) {
11473
+ if (!ix0.programId.equals(SystemProgram4.programId)) {
11408
11474
  throw new Error(
11409
11475
  `paymaster top-up instruction 0 is owned by ${ix0.programId.toBase58()}, not the System Program \u2014 refusing to sign an unrecognised first instruction`
11410
11476
  );
@@ -11488,10 +11554,10 @@ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
11488
11554
  "paymaster prepare returned a voucher that is already expired \u2014 refusing to sign a stale top-up rather than fail confusingly at cosign"
11489
11555
  );
11490
11556
  }
11491
- const feeMint = new PublicKey12(prepared.fee_mint);
11492
- const paymentAddress = new PublicKey12(prepared.payment_address);
11557
+ const feeMint = new PublicKey14(prepared.fee_mint);
11558
+ const paymentAddress = new PublicKey14(prepared.payment_address);
11493
11559
  const feeTokenAmount = BigInt(prepared.fee_token_amount);
11494
- const tx = Transaction3.from(Buffer.from(prepared.transaction, "base64"));
11560
+ const tx = Transaction4.from(Buffer.from(prepared.transaction, "base64"));
11495
11561
  validatePaymasterTopUpTransaction(tx, {
11496
11562
  recipient: receiver.publicKey,
11497
11563
  maxGrantLamports: grantLamports,
@@ -11510,7 +11576,7 @@ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
11510
11576
  });
11511
11577
  const cosigned = await parseBridgeResponse2(cosignRes, "paymaster cosign");
11512
11578
  return {
11513
- transaction: Transaction3.from(Buffer.from(cosigned.transaction, "base64")),
11579
+ transaction: Transaction4.from(Buffer.from(cosigned.transaction, "base64")),
11514
11580
  feeTokenAmount,
11515
11581
  feeMint: prepared.fee_mint,
11516
11582
  paymentAddress: prepared.payment_address
@@ -11518,7 +11584,7 @@ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
11518
11584
  }
11519
11585
 
11520
11586
  // src/bridge/derive.ts
11521
- import { Keypair as Keypair5 } from "@solana/web3.js";
11587
+ import { Keypair as Keypair6 } from "@solana/web3.js";
11522
11588
  import { hmac } from "@noble/hashes/hmac";
11523
11589
  import { sha512 } from "@noble/hashes/sha512";
11524
11590
  var BRIDGE_ESCROW_LABEL = "cloak_bridge_escrow";
@@ -11533,7 +11599,7 @@ function deriveBridgeReceiver(nk, index) {
11533
11599
  );
11534
11600
  }
11535
11601
  const h = hmac(sha512, new Uint8Array(nk), new TextEncoder().encode(`${BRIDGE_ESCROW_LABEL}:${index}`));
11536
- return Keypair5.fromSeed(h.slice(0, 32));
11602
+ return Keypair6.fromSeed(h.slice(0, 32));
11537
11603
  }
11538
11604
 
11539
11605
  // src/bridge/discover.ts
@@ -11615,21 +11681,21 @@ async function listBridgeDeposits(conn, nk, opts) {
11615
11681
 
11616
11682
  // src/bridge/deposit-core.ts
11617
11683
  import {
11618
- SystemProgram as SystemProgram4,
11619
- Transaction as Transaction4,
11684
+ SystemProgram as SystemProgram5,
11685
+ Transaction as Transaction5,
11620
11686
  VersionedTransaction as VersionedTransaction2,
11621
11687
  sendAndConfirmTransaction as sendAndConfirmTransaction2
11622
11688
  } from "@solana/web3.js";
11623
- import nacl9 from "tweetnacl";
11689
+ import nacl8 from "tweetnacl";
11624
11690
 
11625
11691
  // src/bridge/funder.ts
11626
- import { PublicKey as PublicKey14 } from "@solana/web3.js";
11692
+ import { PublicKey as PublicKey16 } from "@solana/web3.js";
11627
11693
  import { getAssociatedTokenAddressSync as getAssociatedTokenAddressSync5 } from "@solana/spl-token";
11628
11694
  var MAINNET_RENT_0 = 890880;
11629
11695
  var MAINNET_RENT_1 = 897840;
11630
11696
  var FEE_BUDGET = 13e4;
11631
11697
  var CLEANUP_FEE_BUDGET = 5e3;
11632
- var pda = (seeds, programId) => PublicKey14.findProgramAddressSync(seeds.map((s) => Buffer.from(s)), programId)[0];
11698
+ var pda = (seeds, programId) => PublicKey16.findProgramAddressSync(seeds.map((s) => Buffer.from(s)), programId)[0];
11633
11699
  function deriveFundingTargets(d) {
11634
11700
  const pool = pda([Buffer.from("pool"), d.mint.toBuffer()], d.programId);
11635
11701
  return {
@@ -11690,8 +11756,8 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
11690
11756
  if (heldByR >= grantR) {
11691
11757
  log(` R already holds ${heldByR} (>= ${grantR}) \u2014 no top-up needed`);
11692
11758
  } else {
11693
- await sendAndConfirmTransaction2(conn, new Transaction4().add(
11694
- SystemProgram4.transfer({ fromPubkey: funder.publicKey, toPubkey: R.publicKey, lamports: grantR - heldByR })
11759
+ await sendAndConfirmTransaction2(conn, new Transaction5().add(
11760
+ SystemProgram5.transfer({ fromPubkey: funder.publicKey, toPubkey: R.publicKey, lamports: grantR - heldByR })
11695
11761
  ), [funder]);
11696
11762
  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"}`);
11697
11763
  }
@@ -11717,13 +11783,13 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
11717
11783
  address: t.a.toBase58(),
11718
11784
  lamportsSent: Math.max(0, t.need - (infos[i]?.lamports ?? 0))
11719
11785
  }));
11720
- const ixs = targets.flatMap((t, i) => (infos[i]?.lamports ?? 0) >= t.need ? [] : [SystemProgram4.transfer({
11786
+ const ixs = targets.flatMap((t, i) => (infos[i]?.lamports ?? 0) >= t.need ? [] : [SystemProgram5.transfer({
11721
11787
  fromPubkey: funder.publicKey,
11722
11788
  toPubkey: t.a,
11723
11789
  lamports: t.need - (infos[i]?.lamports ?? 0)
11724
11790
  })]);
11725
11791
  if (ixs.length) {
11726
- const sig = await sendAndConfirmTransaction2(conn, new Transaction4().add(...ixs), [funder]);
11792
+ const sig = await sendAndConfirmTransaction2(conn, new Transaction5().add(...ixs), [funder]);
11727
11793
  log(` seam: funded ${ixs.length} program accounts read off the built tx \u2014 ${sig.slice(0, 16)}\u2026`);
11728
11794
  }
11729
11795
  tx.sign([R]);
@@ -11732,7 +11798,7 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
11732
11798
  tx.partialSign(R);
11733
11799
  return tx;
11734
11800
  };
11735
- const signMessage = async (m) => nacl9.sign.detached(m, R.secretKey);
11801
+ const signMessage = async (m) => nacl8.sign.detached(m, R.secretKey);
11736
11802
  const utxoKeypair = await deriveUtxoKeypairFromSpendKey(opts.noteSpendKey);
11737
11803
  const nk = getNkFromUtxoPrivateKey(utxoKeypair.privateKey);
11738
11804
  const { utxo, noteSalt } = await createRecoverableDepositUtxo(amount, nk, mint);
@@ -11780,8 +11846,8 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
11780
11846
 
11781
11847
  // src/bridge/cleanup.ts
11782
11848
  import {
11783
- PublicKey as PublicKey16,
11784
- Transaction as Transaction5,
11849
+ PublicKey as PublicKey18,
11850
+ Transaction as Transaction6,
11785
11851
  sendAndConfirmTransaction as sendAndConfirmTransaction3
11786
11852
  } from "@solana/web3.js";
11787
11853
  import {
@@ -11791,7 +11857,7 @@ import {
11791
11857
  createAssociatedTokenAccountIdempotentInstruction,
11792
11858
  getMinimumBalanceForRentExemptAccount
11793
11859
  } from "@solana/spl-token";
11794
- var DEFAULT_MINT = new PublicKey16("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
11860
+ var DEFAULT_MINT = new PublicKey18("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
11795
11861
  async function cleanupReceivingAddress(conn, R, dustDestination, mint = DEFAULT_MINT) {
11796
11862
  assertAllowedRpcConnection(conn);
11797
11863
  const rAta = getAssociatedTokenAddressSync6(mint, R.publicKey);
@@ -11837,7 +11903,7 @@ async function cleanupReceivingAddress(conn, R, dustDestination, mint = DEFAULT_
11837
11903
  destination = destAta.toBase58();
11838
11904
  }
11839
11905
  ixs.push(createCloseAccountInstruction(rAta, R.publicKey, R.publicKey));
11840
- const signature = await sendAndConfirmTransaction3(conn, new Transaction5().add(...ixs), [R], {
11906
+ const signature = await sendAndConfirmTransaction3(conn, new Transaction6().add(...ixs), [R], {
11841
11907
  commitment: "confirmed"
11842
11908
  });
11843
11909
  const after = await conn.getBalance(R.publicKey);
@@ -12038,6 +12104,7 @@ export {
12038
12104
  assessBridgeQuote,
12039
12105
  bigintToBytes32,
12040
12106
  bigintToHex,
12107
+ buildAuthTransactionMessage,
12041
12108
  buildMerkleTree,
12042
12109
  buildMerkleTreeFromChain,
12043
12110
  buildMerkleTreeFromRelay,
@@ -12218,10 +12285,12 @@ export {
12218
12285
  sdkLogger,
12219
12286
  selectUtxos,
12220
12287
  sendTransaction,
12288
+ serializeAuthTransactionMessage,
12221
12289
  serializeNote,
12222
12290
  serializeUtxo,
12223
12291
  setCircuitsPath,
12224
12292
  setDebugMode,
12293
+ signRelayAuthPayload,
12225
12294
  signTransaction,
12226
12295
  splitTo2Limbs,
12227
12296
  submitTransactToRelay,