@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.cjs CHANGED
@@ -455,7 +455,7 @@ async function deserializeUtxo(bytes) {
455
455
  const blindingBytes = bytes.slice(40, 72);
456
456
  const blinding = bytesToBigint2(blindingBytes);
457
457
  const mintBytes = bytes.slice(72, 104);
458
- const mintAddress = new import_web33.PublicKey(mintBytes);
458
+ const mintAddress = new import_web34.PublicKey(mintBytes);
459
459
  const index = view.getUint32(104, true);
460
460
  const utxo = {
461
461
  amount,
@@ -523,18 +523,18 @@ function selectUtxos(available, targetAmount) {
523
523
  }
524
524
  return selected;
525
525
  }
526
- var import_web33, import_circomlibjs2, import_blake33, FIELD_MODULUS, KEYPAIR_DOMAIN_TAG, UTXO_KEY_DOMAIN, NATIVE_SOL_MINT, poseidonInstance;
526
+ var import_web34, import_circomlibjs2, import_blake33, FIELD_MODULUS, KEYPAIR_DOMAIN_TAG, UTXO_KEY_DOMAIN, NATIVE_SOL_MINT, poseidonInstance;
527
527
  var init_utxo = __esm({
528
528
  "src/notes/utxo.ts"() {
529
529
  "use strict";
530
- import_web33 = require("@solana/web3.js");
530
+ import_web34 = require("@solana/web3.js");
531
531
  import_circomlibjs2 = require("circomlibjs");
532
532
  import_blake33 = require("@noble/hashes/blake3");
533
533
  init_inputs();
534
534
  FIELD_MODULUS = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
535
535
  KEYPAIR_DOMAIN_TAG = BigInt("5423839527465210463");
536
536
  UTXO_KEY_DOMAIN = new TextEncoder().encode("cloak_utxo_priv_v1");
537
- NATIVE_SOL_MINT = new import_web33.PublicKey("So11111111111111111111111111111111111111112");
537
+ NATIVE_SOL_MINT = new import_web34.PublicKey("So11111111111111111111111111111111111111112");
538
538
  poseidonInstance = null;
539
539
  }
540
540
  });
@@ -612,6 +612,7 @@ __export(index_exports, {
612
612
  assessBridgeQuote: () => assessBridgeQuote,
613
613
  bigintToBytes32: () => bigintToBytes32,
614
614
  bigintToHex: () => bigintToHex,
615
+ buildAuthTransactionMessage: () => buildAuthTransactionMessage,
615
616
  buildMerkleTree: () => buildMerkleTree,
616
617
  buildMerkleTreeFromChain: () => buildMerkleTreeFromChain,
617
618
  buildMerkleTreeFromRelay: () => buildMerkleTreeFromRelay,
@@ -792,10 +793,12 @@ __export(index_exports, {
792
793
  sdkLogger: () => sdkLogger,
793
794
  selectUtxos: () => selectUtxos,
794
795
  sendTransaction: () => sendTransaction,
796
+ serializeAuthTransactionMessage: () => serializeAuthTransactionMessage,
795
797
  serializeNote: () => serializeNote,
796
798
  serializeUtxo: () => serializeUtxo,
797
799
  setCircuitsPath: () => setCircuitsPath,
798
800
  setDebugMode: () => setDebugMode,
801
+ signRelayAuthPayload: () => signRelayAuthPayload,
799
802
  signTransaction: () => signTransaction,
800
803
  splitTo2Limbs: () => splitTo2Limbs,
801
804
  submitTransactToRelay: () => submitTransactToRelay,
@@ -1388,9 +1391,9 @@ var LocalStorageAdapter = class {
1388
1391
  };
1389
1392
 
1390
1393
  // src/scanning/compliance-keys.ts
1391
- var import_tweetnacl2 = __toESM(require("tweetnacl"), 1);
1394
+ var import_tweetnacl3 = __toESM(require("tweetnacl"), 1);
1392
1395
  var import_blake32 = require("@noble/hashes/blake3");
1393
- var import_sha2 = require("@noble/hashes/sha2");
1396
+ var import_sha22 = require("@noble/hashes/sha2");
1394
1397
  init_inputs();
1395
1398
 
1396
1399
  // src/relay/viewing-key.ts
@@ -1578,6 +1581,276 @@ function connectionRpcEndpoint(connection) {
1578
1581
  return connection?._rpcEndpoint ?? connection?.rpcEndpoint;
1579
1582
  }
1580
1583
 
1584
+ // src/relay/payload.ts
1585
+ var import_sha2 = require("@noble/hashes/sha2");
1586
+ var import_utils = require("@noble/hashes/utils");
1587
+ var import_tweetnacl2 = __toESM(require("tweetnacl"), 1);
1588
+ var import_web33 = require("@solana/web3.js");
1589
+ init_inputs();
1590
+ var REQUEST_AUTH_DOMAIN = "CLOAK_RELAY_REQUEST_AUTH_V1";
1591
+ var REQUEST_AUTH_MAX_AGE_SECONDS = 300;
1592
+ var REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS = 30;
1593
+ var RELAY_AUTH_APPROVAL_MARGIN_SECONDS = 15;
1594
+ function sha256Hex(text) {
1595
+ return (0, import_utils.bytesToHex)((0, import_sha2.sha256)(new TextEncoder().encode(text)));
1596
+ }
1597
+ function randomNonceUuid() {
1598
+ const webCrypto = globalThis?.crypto;
1599
+ if (typeof webCrypto?.randomUUID === "function") return webCrypto.randomUUID();
1600
+ const proc = globalThis?.process;
1601
+ const nodeCrypto = typeof proc?.getBuiltinModule === "function" ? proc.getBuiltinModule("node:crypto") : void 0;
1602
+ if (typeof nodeCrypto?.randomUUID === "function") return nodeCrypto.randomUUID();
1603
+ const bytes = randomBytes(16);
1604
+ bytes[6] = bytes[6] & 15 | 64;
1605
+ bytes[8] = bytes[8] & 63 | 128;
1606
+ const hex = (0, import_utils.bytesToHex)(bytes);
1607
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
1608
+ }
1609
+ var TRANSACT_AUTH_FIELDS = [
1610
+ "encrypted_notes",
1611
+ "max_fee",
1612
+ "mint",
1613
+ "proof_bytes",
1614
+ "public_inputs",
1615
+ "recipient",
1616
+ "recipient_delivery_notes",
1617
+ "risk_quote",
1618
+ "sender"
1619
+ ];
1620
+ var TRANSACT_SWAP_AUTH_FIELDS = [
1621
+ "close_timed_out",
1622
+ "dexes",
1623
+ "encrypted_notes",
1624
+ "exclude_dexes",
1625
+ "max_fee",
1626
+ "min_output_amount",
1627
+ "output_mint",
1628
+ "proof_bytes",
1629
+ "public_inputs",
1630
+ "recipient",
1631
+ "recipient_ata",
1632
+ "refund_blinding",
1633
+ "refund_pubkey",
1634
+ "retry_request_id",
1635
+ "risk_quote",
1636
+ "route_retry_attempts",
1637
+ "sender",
1638
+ "slippage_bps",
1639
+ "swap_max_retries"
1640
+ ];
1641
+ var UTF8 = new TextEncoder();
1642
+ function compareKeysBytewise(a, b) {
1643
+ if (a === b) return 0;
1644
+ const ab = UTF8.encode(a);
1645
+ const bb = UTF8.encode(b);
1646
+ const shared = Math.min(ab.length, bb.length);
1647
+ for (let i = 0; i < shared; i++) {
1648
+ if (ab[i] !== bb[i]) return ab[i] - bb[i];
1649
+ }
1650
+ return ab.length - bb.length;
1651
+ }
1652
+ function canonicalJson(value) {
1653
+ if (value === null || value === void 0) return "null";
1654
+ if (typeof value === "boolean") return value ? "true" : "false";
1655
+ if (typeof value === "number") {
1656
+ if (!Number.isFinite(value) || !Number.isInteger(value) || !Number.isSafeInteger(value)) {
1657
+ throw new Error(
1658
+ `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.`
1659
+ );
1660
+ }
1661
+ return String(value);
1662
+ }
1663
+ if (typeof value === "bigint") return value.toString();
1664
+ if (typeof value === "string") return JSON.stringify(value);
1665
+ if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
1666
+ if (typeof value === "object") {
1667
+ const obj = value;
1668
+ const keys = Object.keys(obj).sort(compareKeysBytewise);
1669
+ return "{" + keys.map((k) => {
1670
+ const v = obj[k];
1671
+ if (typeof v === "function" || typeof v === "symbol") {
1672
+ throw new Error(
1673
+ `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.`
1674
+ );
1675
+ }
1676
+ return `${JSON.stringify(k)}:${canonicalJson(v)}`;
1677
+ }).join(",") + "}";
1678
+ }
1679
+ throw new Error(`canonicalJson: unsupported value of type ${typeof value}`);
1680
+ }
1681
+ var FIELDS_WITHOUT_NULL_ENCODING = {
1682
+ slippage_bps: "500 (`default_slippage_bps` in api/transact_swap.rs)"
1683
+ };
1684
+ function buildAuthRequest(body, sender, fields) {
1685
+ const out = {};
1686
+ for (const k of fields) {
1687
+ if (k === "sender") {
1688
+ out[k] = sender;
1689
+ continue;
1690
+ }
1691
+ const value = body[k];
1692
+ if (value === void 0 || value === null) {
1693
+ const relayDefault = FIELDS_WITHOUT_NULL_ENCODING[k];
1694
+ if (relayDefault) {
1695
+ throw new Error(
1696
+ `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.`
1697
+ );
1698
+ }
1699
+ out[k] = null;
1700
+ continue;
1701
+ }
1702
+ out[k] = value;
1703
+ }
1704
+ return out;
1705
+ }
1706
+ function buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request) {
1707
+ const digest = sha256Hex(canonicalJson(request));
1708
+ return new TextEncoder().encode(
1709
+ `${REQUEST_AUTH_DOMAIN}
1710
+ ${endpoint}
1711
+ ${programId.toBase58()}
1712
+ ${nonce}
1713
+ ${issuedAt}
1714
+ ${digest}`
1715
+ );
1716
+ }
1717
+ function buildRelayAuthPreimage(endpoint, programId, body, sender, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
1718
+ const senderB58 = sender.toBase58();
1719
+ const issuedAt = String(nowSeconds ?? Math.floor(Date.now() / 1e3));
1720
+ const nonce = randomNonceUuid();
1721
+ const request = buildAuthRequest({ ...body, sender: senderB58 }, senderB58, fields);
1722
+ const message = buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request);
1723
+ return { sender: senderB58, auth_issued_at: issuedAt, auth_nonce: nonce, message };
1724
+ }
1725
+ function signRelayRequest(endpoint, programId, body, signer, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
1726
+ const preimage = buildRelayAuthPreimage(
1727
+ endpoint,
1728
+ programId,
1729
+ body,
1730
+ signer.publicKey,
1731
+ nowSeconds,
1732
+ fields
1733
+ );
1734
+ const signature = import_tweetnacl2.default.sign.detached(preimage.message, signer.secretKey);
1735
+ return {
1736
+ sender: preimage.sender,
1737
+ auth_issued_at: preimage.auth_issued_at,
1738
+ auth_nonce: preimage.auth_nonce,
1739
+ auth_signature: Buffer.from(signature).toString("base64")
1740
+ };
1741
+ }
1742
+ function buildAuthTransactionMessage(sender, digest) {
1743
+ if (digest.length !== 32) throw new Error(`auth transaction digest must be 32 bytes (got ${digest.length})`);
1744
+ const tx = new import_web33.Transaction();
1745
+ tx.add(import_web33.SystemProgram.transfer({ fromPubkey: sender, toPubkey: sender, lamports: 0 }));
1746
+ tx.feePayer = sender;
1747
+ tx.recentBlockhash = new import_web33.PublicKey(digest).toBase58();
1748
+ return tx;
1749
+ }
1750
+ function serializeAuthTransactionMessage(sender, digest) {
1751
+ return Uint8Array.from(buildAuthTransactionMessage(sender, digest).compileMessage().serialize());
1752
+ }
1753
+ async function signRelayAuthPayload(signer, payload) {
1754
+ if (signer instanceof import_web33.Keypair) {
1755
+ return { signature: import_tweetnacl2.default.sign.detached(payload, signer.secretKey), mode: "message" };
1756
+ }
1757
+ if (signer.signMessage) {
1758
+ const signature = await signer.signMessage(payload);
1759
+ assertDetachedSignature(signature, "signMessage");
1760
+ return { signature, mode: "message" };
1761
+ }
1762
+ if (signer.signAuthTransaction) {
1763
+ const digest = (0, import_sha2.sha256)(payload);
1764
+ const signed = await signer.signAuthTransaction(buildAuthTransactionMessage(signer.walletPublicKey, digest));
1765
+ const own = signed.signatures.find((s) => s.publicKey.equals(signer.walletPublicKey))?.signature;
1766
+ if (!own) {
1767
+ throw new Error(
1768
+ "The wallet returned no signature for the Cloak auth transaction. Nothing was submitted."
1769
+ );
1770
+ }
1771
+ const signature = Uint8Array.from(own);
1772
+ assertDetachedSignature(signature, "signTransaction");
1773
+ return { signature, mode: "transaction" };
1774
+ }
1775
+ throw new Error("Relay auth signer has neither signMessage nor signAuthTransaction.");
1776
+ }
1777
+ function assertDetachedSignature(signature, method) {
1778
+ if (!(signature instanceof Uint8Array) || signature.length !== 64) {
1779
+ throw new Error(
1780
+ `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.`
1781
+ );
1782
+ }
1783
+ }
1784
+ function assertApprovalWithinFreshnessWindow(elapsedMs, maxAgeSeconds = REQUEST_AUTH_MAX_AGE_SECONDS) {
1785
+ const elapsedSeconds = elapsedMs / 1e3;
1786
+ const budget = maxAgeSeconds - RELAY_AUTH_APPROVAL_MARGIN_SECONDS;
1787
+ if (elapsedSeconds <= budget) return;
1788
+ throw new Error(
1789
+ `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.`
1790
+ );
1791
+ }
1792
+ function explainRelayAuthRejection(responseText) {
1793
+ const text = String(responseText);
1794
+ const has = (needle) => text.includes(needle);
1795
+ if (has("issued too far in the future")) {
1796
+ 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.`;
1797
+ }
1798
+ if (has("signature expired")) {
1799
+ 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.`;
1800
+ }
1801
+ if (has("does not match the exact request")) {
1802
+ 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\`.`;
1803
+ }
1804
+ if (has("has no registered viewing key")) {
1805
+ 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.`;
1806
+ }
1807
+ if (has("Authenticated sender is required") || has("auth_issued_at is required") || has("auth_nonce is required") || has("auth_signature is required")) {
1808
+ return `The request reached the relay without its authentication fields. Pass \`depositorKeypair\`, or \`signMessage\` together with \`walletPublicKey\`, so the request can be signed.`;
1809
+ }
1810
+ if (has("auth_nonce must be a canonical UUID")) {
1811
+ return `\`auth_nonce\` must be a canonical lowercase UUID. Reuse the one from the preimage.`;
1812
+ }
1813
+ if (has("Relay request signature must be exactly 64 bytes") || has("Invalid relay request signature encoding")) {
1814
+ 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.`;
1815
+ }
1816
+ return null;
1817
+ }
1818
+ async function buildRelayAuthFields(endpoint, programId, body, signers, fields = TRANSACT_AUTH_FIELDS) {
1819
+ if (signers.depositorKeypair) {
1820
+ return signRelayRequest(endpoint, programId, body, signers.depositorKeypair, void 0, fields);
1821
+ }
1822
+ const wallet = signers.relayAuthSigner;
1823
+ if (!wallet) return null;
1824
+ const preimage = buildRelayAuthPreimage(
1825
+ endpoint,
1826
+ programId,
1827
+ body,
1828
+ wallet.walletPublicKey,
1829
+ void 0,
1830
+ fields
1831
+ );
1832
+ const approvalStartedMs = Date.now();
1833
+ const { signature, mode } = await signRelayAuthPayload(wallet, preimage.message);
1834
+ assertApprovalWithinFreshnessWindow(Date.now() - approvalStartedMs);
1835
+ return {
1836
+ sender: preimage.sender,
1837
+ auth_issued_at: preimage.auth_issued_at,
1838
+ auth_nonce: preimage.auth_nonce,
1839
+ auth_signature: Buffer.from(signature).toString("base64"),
1840
+ ...mode === "transaction" ? { auth_mode: mode } : {}
1841
+ };
1842
+ }
1843
+ var REQUEST_AUTH_BATCH_DOMAIN = "CLOAK_RELAY_BATCH_AUTH_V1";
1844
+ var REQUEST_AUTH_BATCH_MAX_AGE_SECONDS = 600;
1845
+ var RELAY_BATCH_AUTH_MAX_ITEMS = 64;
1846
+ function relayRequestDigestHex(preimage) {
1847
+ return (0, import_utils.bytesToHex)((0, import_sha2.sha256)(preimage.message));
1848
+ }
1849
+ function buildRelayBatchAuthMessage(programId, issuedAt, digests) {
1850
+ const lines = [REQUEST_AUTH_BATCH_DOMAIN, programId.toBase58(), issuedAt, String(digests.length)];
1851
+ return new TextEncoder().encode([...lines, ...digests].join("\n"));
1852
+ }
1853
+
1581
1854
  // src/scanning/compliance-keys.ts
1582
1855
  var X25519_KEY_LENGTH = 32;
1583
1856
  var DIVERSIFIER_LENGTH = 11;
@@ -1615,7 +1888,7 @@ function deriveViewingKeyFromNk(nk) {
1615
1888
  preimage.set(nk, CHAIN_NOTE_VK_DOMAIN.length);
1616
1889
  const derived = (0, import_blake32.blake3)(preimage);
1617
1890
  const privateKey = clampX25519Secret(derived);
1618
- const publicKey = import_tweetnacl2.default.scalarMult.base(privateKey);
1891
+ const publicKey = import_tweetnacl3.default.scalarMult.base(privateKey);
1619
1892
  return { privateKey, publicKey };
1620
1893
  }
1621
1894
  function deriveDiversifier(nk, commitmentHex, outputIndex) {
@@ -1650,7 +1923,7 @@ function deriveDiversifiedViewingKey(nk, diversifier) {
1650
1923
  preimage.set(diversifier, SK_D_DOMAIN.length + nk.length);
1651
1924
  const derived = (0, import_blake32.blake3)(preimage);
1652
1925
  const privateKey = clampX25519Secret(derived);
1653
- const publicKey = import_tweetnacl2.default.scalarMult.base(privateKey);
1926
+ const publicKey = import_tweetnacl3.default.scalarMult.base(privateKey);
1654
1927
  return { privateKey, publicKey };
1655
1928
  }
1656
1929
  function deriveViewingKeyFromSpendKey(skSpend) {
@@ -1713,19 +1986,19 @@ async function deriveUserCompliancePublicKey(masterCompliancePublicKey, userPubl
1713
1986
  masterCompliancePublicKey,
1714
1987
  userPublicKey
1715
1988
  );
1716
- return import_tweetnacl2.default.scalarMult(factor, masterCompliancePublicKey);
1989
+ return import_tweetnacl3.default.scalarMult(factor, masterCompliancePublicKey);
1717
1990
  }
1718
- function bytesToHex2(bytes) {
1991
+ function bytesToHex3(bytes) {
1719
1992
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
1720
1993
  }
1721
1994
  function computeViewingKeyIdentifier(userPubkey, nkHex) {
1722
1995
  const preimage = new TextEncoder().encode(`${userPubkey.toBase58()}${nkHex}`);
1723
- return bytesToHex2((0, import_sha2.sha256)(preimage));
1996
+ return bytesToHex3((0, import_sha22.sha256)(preimage));
1724
1997
  }
1725
1998
  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.";
1726
1999
  async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
1727
2000
  assert32Bytes(nk, "nk");
1728
- const nkHex = bytesToHex2(nk);
2001
+ const nkHex = bytesToHex3(nk);
1729
2002
  const keyId = computeViewingKeyIdentifier(userPubkey, nkHex);
1730
2003
  const challengeResponse = await relayFetch(`${relayUrl}/viewing-key/challenge`, {
1731
2004
  method: "POST",
@@ -1746,8 +2019,11 @@ async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
1746
2019
  nkHex
1747
2020
  );
1748
2021
  const messageBytes = new TextEncoder().encode(challenge.message);
1749
- const signatureBytes = await signMessage(messageBytes);
1750
- const signature = Buffer.from(signatureBytes).toString("base64");
2022
+ const signed = await signRelayAuthPayload(
2023
+ typeof signMessage === "function" ? { walletPublicKey: userPubkey, signMessage } : signMessage,
2024
+ messageBytes
2025
+ );
2026
+ const signature = Buffer.from(signed.signature).toString("base64");
1751
2027
  const response = await relayFetch(`${relayUrl}/viewing-key/register`, {
1752
2028
  method: "POST",
1753
2029
  headers: { "Content-Type": "application/json" },
@@ -1756,7 +2032,8 @@ async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
1756
2032
  viewing_key: nkHex,
1757
2033
  nonce: challenge.nonce,
1758
2034
  identifier: keyId,
1759
- signature
2035
+ signature,
2036
+ ...signed.mode === "transaction" ? { auth_mode: signed.mode } : {}
1760
2037
  })
1761
2038
  });
1762
2039
  if (!response.ok) {
@@ -1765,7 +2042,7 @@ async function registerViewingKey(relayUrl, userPubkey, nk, signMessage) {
1765
2042
  }
1766
2043
 
1767
2044
  // src/scanning/metadata-encryption.ts
1768
- var import_tweetnacl3 = __toESM(require("tweetnacl"), 1);
2045
+ var import_tweetnacl4 = __toESM(require("tweetnacl"), 1);
1769
2046
  init_inputs();
1770
2047
  var AES_GCM_NONCE_LENGTH = 12;
1771
2048
  var AES_GCM_TAG_LENGTH = 16;
@@ -1863,8 +2140,8 @@ async function aesGcmDecrypt(ciphertext, keyBytes, nonce) {
1863
2140
  }
1864
2141
  async function encryptForRecipient(plaintext, recipientPublicKey) {
1865
2142
  assert32Bytes2(recipientPublicKey, "recipientPublicKey");
1866
- const ephemeral = import_tweetnacl3.default.box.keyPair();
1867
- const sharedSecret = import_tweetnacl3.default.scalarMult(ephemeral.secretKey, recipientPublicKey);
2143
+ const ephemeral = import_tweetnacl4.default.box.keyPair();
2144
+ const sharedSecret = import_tweetnacl4.default.scalarMult(ephemeral.secretKey, recipientPublicKey);
1868
2145
  const nonce = randomBytes(AES_GCM_NONCE_LENGTH);
1869
2146
  const ciphertext = await aesGcmEncrypt(plaintext, sharedSecret, nonce);
1870
2147
  return {
@@ -1923,7 +2200,7 @@ async function encryptTransactionMetadataBundle(metadata, viewingKeyPrivate, use
1923
2200
  const plaintext = new TextEncoder().encode(JSON.stringify(metadata));
1924
2201
  const basePoint = new Uint8Array(32);
1925
2202
  basePoint[0] = 9;
1926
- const viewingKeyPublic = import_tweetnacl3.default.scalarMult(viewingKeyPrivate, basePoint);
2203
+ const viewingKeyPublic = import_tweetnacl4.default.scalarMult(viewingKeyPrivate, basePoint);
1927
2204
  const [userPayload, compliancePayload] = await Promise.all([
1928
2205
  encryptForRecipient(plaintext, viewingKeyPublic),
1929
2206
  encryptForRecipient(plaintext, viewingKeyPublic)
@@ -1942,7 +2219,7 @@ async function decryptTransactionMetadata(encrypted, viewKeySecret) {
1942
2219
  const payload = decodePayload(encrypted);
1943
2220
  const ephemeralPk = hexToBytes(payload.ephemeral_pk);
1944
2221
  assert32Bytes2(ephemeralPk, "ephemeral public key");
1945
- const sharedSecret = import_tweetnacl3.default.scalarMult(viewKeySecret, ephemeralPk);
2222
+ const sharedSecret = import_tweetnacl4.default.scalarMult(viewKeySecret, ephemeralPk);
1946
2223
  return decryptWithSharedSecret(payload, sharedSecret);
1947
2224
  }
1948
2225
  async function decryptComplianceMetadataWithMasterKey(encrypted, masterCompliancePrivateKey, masterCompliancePublicKey, userPublicKey) {
@@ -1955,8 +2232,8 @@ async function decryptComplianceMetadataWithMasterKey(encrypted, masterComplianc
1955
2232
  masterCompliancePublicKey,
1956
2233
  userPublicKey
1957
2234
  );
1958
- const scaledEphemeral = import_tweetnacl3.default.scalarMult(userFactor, ephemeralPk);
1959
- const sharedSecret = import_tweetnacl3.default.scalarMult(masterCompliancePrivateKey, scaledEphemeral);
2235
+ const scaledEphemeral = import_tweetnacl4.default.scalarMult(userFactor, ephemeralPk);
2236
+ const sharedSecret = import_tweetnacl4.default.scalarMult(masterCompliancePrivateKey, scaledEphemeral);
1960
2237
  return decryptWithSharedSecret(payload, sharedSecret);
1961
2238
  }
1962
2239
 
@@ -2893,23 +3170,23 @@ function formatErrorForLogging(error) {
2893
3170
  init_utxo();
2894
3171
 
2895
3172
  // src/program/pda.ts
2896
- var import_web34 = require("@solana/web3.js");
3173
+ var import_web35 = require("@solana/web3.js");
2897
3174
  init_utxo();
2898
3175
  function getShieldPoolPDAs(programId, mint = NATIVE_SOL_MINT) {
2899
3176
  const pid = programId || CLOAK_PROGRAM_ID;
2900
- const [pool] = import_web34.PublicKey.findProgramAddressSync(
3177
+ const [pool] = import_web35.PublicKey.findProgramAddressSync(
2901
3178
  [Buffer.from("pool"), mint.toBuffer()],
2902
3179
  pid
2903
3180
  );
2904
- const [merkleTree] = import_web34.PublicKey.findProgramAddressSync(
3181
+ const [merkleTree] = import_web35.PublicKey.findProgramAddressSync(
2905
3182
  [Buffer.from("merkle_tree"), mint.toBuffer()],
2906
3183
  pid
2907
3184
  );
2908
- const [treasury] = import_web34.PublicKey.findProgramAddressSync(
3185
+ const [treasury] = import_web35.PublicKey.findProgramAddressSync(
2909
3186
  [Buffer.from("treasury"), mint.toBuffer()],
2910
3187
  pid
2911
3188
  );
2912
- const [vaultAuthority] = import_web34.PublicKey.findProgramAddressSync(
3189
+ const [vaultAuthority] = import_web35.PublicKey.findProgramAddressSync(
2913
3190
  [Buffer.from("vault_authority"), mint.toBuffer()],
2914
3191
  pid
2915
3192
  );
@@ -2925,7 +3202,7 @@ function getNullifierPDA(poolPubkey, nullifier, programId) {
2925
3202
  if (nullifier.length !== 32) {
2926
3203
  throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2927
3204
  }
2928
- return import_web34.PublicKey.findProgramAddressSync(
3205
+ return import_web35.PublicKey.findProgramAddressSync(
2929
3206
  [Buffer.from("nullifier"), poolPubkey.toBuffer(), Buffer.from(nullifier)],
2930
3207
  pid
2931
3208
  );
@@ -2935,25 +3212,25 @@ function getSwapStatePDA(poolPubkey, nullifier, programId) {
2935
3212
  if (nullifier.length !== 32) {
2936
3213
  throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2937
3214
  }
2938
- return import_web34.PublicKey.findProgramAddressSync(
3215
+ return import_web35.PublicKey.findProgramAddressSync(
2939
3216
  [Buffer.from("swap_state"), poolPubkey.toBuffer(), Buffer.from(nullifier)],
2940
3217
  pid
2941
3218
  );
2942
3219
  }
2943
3220
  function getPoolAuthorityConfigPDA(mint = NATIVE_SOL_MINT, programId) {
2944
3221
  const pid = programId || CLOAK_PROGRAM_ID;
2945
- return import_web34.PublicKey.findProgramAddressSync(
3222
+ return import_web35.PublicKey.findProgramAddressSync(
2946
3223
  [Buffer.from("pool_authority"), mint.toBuffer()],
2947
3224
  pid
2948
3225
  );
2949
3226
  }
2950
3227
  function getDeliveryRegistryPDA(programId) {
2951
3228
  const pid = programId || CLOAK_PROGRAM_ID;
2952
- return import_web34.PublicKey.findProgramAddressSync([Buffer.from("cloak_delivery_registry")], pid)[0];
3229
+ return import_web35.PublicKey.findProgramAddressSync([Buffer.from("cloak_delivery_registry")], pid)[0];
2953
3230
  }
2954
3231
  function getChainNoteRegistryPDA(programId) {
2955
3232
  const pid = programId || CLOAK_PROGRAM_ID;
2956
- return import_web34.PublicKey.findProgramAddressSync([Buffer.from("cloak_chain_note_registry")], pid)[0];
3233
+ return import_web35.PublicKey.findProgramAddressSync([Buffer.from("cloak_chain_note_registry")], pid)[0];
2957
3234
  }
2958
3235
 
2959
3236
  // src/flows/verify-utxos.ts
@@ -3284,8 +3561,9 @@ function truncate(str, len = 20) {
3284
3561
  var sdkLogger = createLogger("cloak::sdk");
3285
3562
 
3286
3563
  // src/relay/relay-service.ts
3287
- var import_sha22 = require("@noble/hashes/sha2");
3564
+ var import_sha23 = require("@noble/hashes/sha2");
3288
3565
  init_inputs();
3566
+ var import_web36 = require("@solana/web3.js");
3289
3567
  var RelayService = class {
3290
3568
  /**
3291
3569
  * Create a new Relay Service client
@@ -3601,8 +3879,11 @@ var RelayService = class {
3601
3879
  userPubkey,
3602
3880
  viewingKey
3603
3881
  );
3604
- const signatureBytes = await signMessage(new TextEncoder().encode(challenge.message));
3605
- const signature = this.bytesToBase64(signatureBytes);
3882
+ const signed = await signRelayAuthPayload(
3883
+ typeof signMessage === "function" ? { walletPublicKey: new import_web36.PublicKey(userPubkey), signMessage } : signMessage,
3884
+ new TextEncoder().encode(challenge.message)
3885
+ );
3886
+ const signature = this.bytesToBase64(signed.signature);
3606
3887
  const response = await relayFetch(`${this.baseUrl}/viewing-key/register`, {
3607
3888
  method: "POST",
3608
3889
  headers: { "Content-Type": "application/json" },
@@ -3611,7 +3892,8 @@ var RelayService = class {
3611
3892
  viewing_key: viewingKey,
3612
3893
  nonce: challenge.nonce,
3613
3894
  identifier,
3614
- signature
3895
+ signature,
3896
+ ...signed.mode === "transaction" ? { auth_mode: signed.mode } : {}
3615
3897
  })
3616
3898
  });
3617
3899
  if (!response.ok) {
@@ -3649,7 +3931,7 @@ var RelayService = class {
3649
3931
  }
3650
3932
  computeViewingKeyIdentifier(userPubkey, viewingKeyHex) {
3651
3933
  const preimage = new TextEncoder().encode(`${userPubkey}${viewingKeyHex}`);
3652
- const hash = (0, import_sha22.sha256)(preimage);
3934
+ const hash = (0, import_sha23.sha256)(preimage);
3653
3935
  return Array.from(hash).map((b) => b.toString(16).padStart(2, "0")).join("");
3654
3936
  }
3655
3937
  };
@@ -3767,10 +4049,10 @@ function encodeNoteSimple(note) {
3767
4049
  }
3768
4050
 
3769
4051
  // src/wallet/adapter.ts
3770
- var import_web35 = require("@solana/web3.js");
4052
+ var import_web37 = require("@solana/web3.js");
3771
4053
  init_types();
3772
4054
  function validateWalletConnected(wallet) {
3773
- if (wallet instanceof import_web35.Keypair) {
4055
+ if (wallet instanceof import_web37.Keypair) {
3774
4056
  return;
3775
4057
  }
3776
4058
  if (!wallet.publicKey) {
@@ -3782,7 +4064,7 @@ function validateWalletConnected(wallet) {
3782
4064
  }
3783
4065
  }
3784
4066
  function getPublicKey(wallet) {
3785
- if (wallet instanceof import_web35.Keypair) {
4067
+ if (wallet instanceof import_web37.Keypair) {
3786
4068
  return wallet.publicKey;
3787
4069
  }
3788
4070
  if (!wallet.publicKey) {
@@ -3796,7 +4078,7 @@ function getPublicKey(wallet) {
3796
4078
  }
3797
4079
  async function sendTransaction(transaction, wallet, connection, options) {
3798
4080
  assertAllowedRpcConnection(connection);
3799
- if (wallet instanceof import_web35.Keypair) {
4081
+ if (wallet instanceof import_web37.Keypair) {
3800
4082
  return await connection.sendTransaction(transaction, [wallet], options);
3801
4083
  }
3802
4084
  if (wallet.sendTransaction) {
@@ -3813,7 +4095,7 @@ async function sendTransaction(transaction, wallet, connection, options) {
3813
4095
  }
3814
4096
  }
3815
4097
  async function signTransaction(transaction, wallet) {
3816
- if (wallet instanceof import_web35.Keypair) {
4098
+ if (wallet instanceof import_web37.Keypair) {
3817
4099
  transaction.sign(wallet);
3818
4100
  return transaction;
3819
4101
  }
@@ -3841,7 +4123,7 @@ function keypairToAdapter(keypair) {
3841
4123
  }
3842
4124
 
3843
4125
  // src/program/instructions.ts
3844
- var import_web36 = require("@solana/web3.js");
4126
+ var import_web38 = require("@solana/web3.js");
3845
4127
  function createDepositInstruction(params) {
3846
4128
  if (params.commitment.length !== 32) {
3847
4129
  throw new Error(
@@ -3863,7 +4145,7 @@ function createDepositInstruction(params) {
3863
4145
  data.set(discriminant, 0);
3864
4146
  data.set(amountBytes, 1);
3865
4147
  data.set(params.commitment, 9);
3866
- return new import_web36.TransactionInstruction({
4148
+ return new import_web38.TransactionInstruction({
3867
4149
  programId: params.programId,
3868
4150
  keys: [
3869
4151
  // Account 0: Payer (signer, writable) - pays for transaction
@@ -3871,7 +4153,7 @@ function createDepositInstruction(params) {
3871
4153
  // Account 1: Pool (writable) - receives SOL
3872
4154
  { pubkey: params.pool, isSigner: false, isWritable: true },
3873
4155
  // Account 2: System Program (readonly) - for transfers
3874
- { pubkey: import_web36.SystemProgram.programId, isSigner: false, isWritable: false },
4156
+ { pubkey: import_web38.SystemProgram.programId, isSigner: false, isWritable: false },
3875
4157
  // Account 3: Merkle Tree (writable) - stores on-chain Merkle tree
3876
4158
  { pubkey: params.merkleTree, isSigner: false, isWritable: true }
3877
4159
  ],
@@ -3879,16 +4161,16 @@ function createDepositInstruction(params) {
3879
4161
  });
3880
4162
  }
3881
4163
  function validateDepositParams(params) {
3882
- if (!(params.programId instanceof import_web36.PublicKey)) {
4164
+ if (!(params.programId instanceof import_web38.PublicKey)) {
3883
4165
  throw new Error("programId must be a PublicKey");
3884
4166
  }
3885
- if (!(params.payer instanceof import_web36.PublicKey)) {
4167
+ if (!(params.payer instanceof import_web38.PublicKey)) {
3886
4168
  throw new Error("payer must be a PublicKey");
3887
4169
  }
3888
- if (!(params.pool instanceof import_web36.PublicKey)) {
4170
+ if (!(params.pool instanceof import_web38.PublicKey)) {
3889
4171
  throw new Error("pool must be a PublicKey");
3890
4172
  }
3891
- if (!(params.merkleTree instanceof import_web36.PublicKey)) {
4173
+ if (!(params.merkleTree instanceof import_web38.PublicKey)) {
3892
4174
  throw new Error("merkleTree must be a PublicKey");
3893
4175
  }
3894
4176
  if (typeof params.amount !== "number" || params.amount <= 0) {
@@ -4229,7 +4511,7 @@ async function buildMerkleTree(commitments, height = MERKLE_TREE_HEIGHT2) {
4229
4511
  }
4230
4512
 
4231
4513
  // src/relay/client.ts
4232
- var import_web37 = require("@solana/web3.js");
4514
+ var import_web39 = require("@solana/web3.js");
4233
4515
  var import_bs58 = __toESM(require("bs58"), 1);
4234
4516
 
4235
4517
  // src/notes/refund-leaf.ts
@@ -4346,7 +4628,7 @@ var CLOSE_SWAP_STATE_TAG = 13;
4346
4628
  var CLOSE_SWAP_STATE_PHASE1_PAYLOAD_LEN = 40;
4347
4629
  var CLOSE_SWAP_STATE_PHASE1_WIRE_LEN = 1 + CLOSE_SWAP_STATE_PHASE1_PAYLOAD_LEN;
4348
4630
  var CLOSE_SWAP_STATE_COMMITMENT_END = 1 + 32;
4349
- var NATIVE_SOL_MINT2 = new import_web37.PublicKey("So11111111111111111111111111111111111111112");
4631
+ var NATIVE_SOL_MINT2 = new import_web39.PublicKey("So11111111111111111111111111111111111111112");
4350
4632
  var PROOF_LEN = 256;
4351
4633
  var PUBLIC_INPUTS_LEN = 264;
4352
4634
  var COMMITMENTS_OFFSET = 168;
@@ -4635,7 +4917,7 @@ async function preflightCheck(relayUrl, rootHex) {
4635
4917
  }
4636
4918
 
4637
4919
  // src/flows/transact.ts
4638
- var import_web39 = require("@solana/web3.js");
4920
+ var import_web311 = require("@solana/web3.js");
4639
4921
  var import_spl_token = require("@solana/spl-token");
4640
4922
  var snarkjs = __toESM(require("snarkjs"), 1);
4641
4923
  init_utxo();
@@ -4863,7 +5145,7 @@ function chainNoteFromBase64(base64) {
4863
5145
  }
4864
5146
 
4865
5147
  // src/notes/delivery-note.ts
4866
- var import_tweetnacl4 = __toESM(require("tweetnacl"), 1);
5148
+ var import_tweetnacl5 = __toESM(require("tweetnacl"), 1);
4867
5149
  var RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN = 32;
4868
5150
  var RECIPIENT_DELIVERY_NONCE_LEN = 24;
4869
5151
  var RECIPIENT_DELIVERY_PLAINTEXT_LEN = 40;
@@ -4914,10 +5196,10 @@ function encodeRecipientDeliveryNote(note, recipientViewingPublicKey) {
4914
5196
  const plaintext = new Uint8Array(RECIPIENT_DELIVERY_PLAINTEXT_LEN);
4915
5197
  writeU64LE2(plaintext, 0, note.amount);
4916
5198
  writeU256BE2(plaintext, 8, note.blinding);
4917
- const ephemeral = import_tweetnacl4.default.box.keyPair();
4918
- const shared = import_tweetnacl4.default.box.before(recipientViewingPublicKey, ephemeral.secretKey);
4919
- const nonce = import_tweetnacl4.default.randomBytes(import_tweetnacl4.default.secretbox.nonceLength);
4920
- const ciphertext = import_tweetnacl4.default.secretbox(plaintext, nonce, shared);
5199
+ const ephemeral = import_tweetnacl5.default.box.keyPair();
5200
+ const shared = import_tweetnacl5.default.box.before(recipientViewingPublicKey, ephemeral.secretKey);
5201
+ const nonce = import_tweetnacl5.default.randomBytes(import_tweetnacl5.default.secretbox.nonceLength);
5202
+ const ciphertext = import_tweetnacl5.default.secretbox(plaintext, nonce, shared);
4921
5203
  if (ciphertext.length !== RECIPIENT_DELIVERY_CIPHERTEXT_LEN) {
4922
5204
  throw new Error(
4923
5205
  `delivery ciphertext must be ${RECIPIENT_DELIVERY_CIPHERTEXT_LEN} bytes, got ${ciphertext.length}`
@@ -4943,8 +5225,8 @@ function openRecipientDeliveryNote(envelope, viewingSecretKey) {
4943
5225
  const ciphertext = envelope.slice(
4944
5226
  RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN + RECIPIENT_DELIVERY_NONCE_LEN
4945
5227
  );
4946
- const shared = import_tweetnacl4.default.box.before(ephemeralPk, viewingSecretKey);
4947
- const plaintext = import_tweetnacl4.default.secretbox.open(ciphertext, nonce, shared);
5228
+ const shared = import_tweetnacl5.default.box.before(ephemeralPk, viewingSecretKey);
5229
+ const plaintext = import_tweetnacl5.default.secretbox.open(ciphertext, nonce, shared);
4948
5230
  if (!plaintext || plaintext.length !== RECIPIENT_DELIVERY_PLAINTEXT_LEN) return null;
4949
5231
  return { amount: readU64LE2(plaintext, 0), blinding: readU256BE2(plaintext, 8) };
4950
5232
  } catch {
@@ -5002,7 +5284,7 @@ function parseDeliveryCarrierMemo(data) {
5002
5284
 
5003
5285
  // src/notes/swap-refund.ts
5004
5286
  var import_blake34 = require("@noble/hashes/blake3");
5005
- var import_web38 = require("@solana/web3.js");
5287
+ var import_web310 = require("@solana/web3.js");
5006
5288
  var import_bs582 = __toESM(require("bs58"), 1);
5007
5289
  init_utxo();
5008
5290
  init_inputs();
@@ -5149,7 +5431,7 @@ async function discoverSwapRefunds(connection, programId, viewingKeyNk, options
5149
5431
  const { limit = 0, untilSignature, batchSize = 50, onStatus } = options;
5150
5432
  const poolMint = options.poolMint ?? NATIVE_SOL_MINT;
5151
5433
  const programIdBase58 = programId.toBase58();
5152
- const [pool] = import_web38.PublicKey.findProgramAddressSync(
5434
+ const [pool] = import_web310.PublicKey.findProgramAddressSync(
5153
5435
  [Buffer.from("pool"), poolMint.toBuffer()],
5154
5436
  programId
5155
5437
  );
@@ -5200,7 +5482,7 @@ async function discoverSwapRefunds(connection, programId, viewingKeyNk, options
5200
5482
  if (data[0] !== TRANSACT_SWAP_TAG2 || data.length < MIN_TRANSACT_SWAP_LEN) continue;
5201
5483
  const nullifier = data.slice(NULLIFIER_0_OFFSET, NULLIFIER_0_OFFSET + 32);
5202
5484
  if (nullifier.length !== 32) continue;
5203
- const [swapState] = import_web38.PublicKey.findProgramAddressSync(
5485
+ const [swapState] = import_web310.PublicKey.findProgramAddressSync(
5204
5486
  [Buffer.from("swap_state"), pool.toBuffer(), Buffer.from(nullifier)],
5205
5487
  programId
5206
5488
  );
@@ -5263,406 +5545,173 @@ function saltToBytes(noteSalt) {
5263
5545
  out[i] = Number(v & 0xffn);
5264
5546
  v >>= 8n;
5265
5547
  }
5266
- return out;
5267
- }
5268
- function toFieldSecret2(bytes) {
5269
- let value = 0n;
5270
- for (let i = 0; i < 32; i++) value = value << 8n | BigInt(bytes[i]);
5271
- const reduced = value % (BN254_MODULUS >> 4n);
5272
- return reduced === 0n ? 1n : reduced;
5273
- }
5274
- function derive2(nk, salt, info) {
5275
- const preimage = new Uint8Array(
5276
- DEPOSIT_NOTE_DOMAIN.length + nk.length + salt.length + info.length
5277
- );
5278
- let off = 0;
5279
- preimage.set(DEPOSIT_NOTE_DOMAIN, off);
5280
- off += DEPOSIT_NOTE_DOMAIN.length;
5281
- preimage.set(nk, off);
5282
- off += nk.length;
5283
- preimage.set(salt, off);
5284
- off += salt.length;
5285
- preimage.set(info, off);
5286
- return (0, import_blake35.blake3)(preimage);
5287
- }
5288
- function randomDepositNoteSalt() {
5289
- const bytes = randomBytes(12);
5290
- let v = 0n;
5291
- for (const b of bytes) v = v << 8n | BigInt(b);
5292
- return v === 0n ? 1n : v;
5293
- }
5294
- async function deriveDepositNoteSecrets(viewingKeyNk, noteSalt) {
5295
- if (!viewingKeyNk || !(viewingKeyNk instanceof Uint8Array) || viewingKeyNk.length !== 32) {
5296
- throw new Error("viewingKeyNk must be 32 bytes");
5297
- }
5298
- const salt = saltToBytes(noteSalt);
5299
- const privateKey = toFieldSecret2(derive2(viewingKeyNk, salt, DEPOSIT_PRIVATE_KEY_INFO));
5300
- const blinding = toFieldSecret2(derive2(viewingKeyNk, salt, DEPOSIT_BLINDING_INFO));
5301
- const publicKey = await derivePublicKey(privateKey);
5302
- if (publicKey === 0n || blinding === 0n) {
5303
- throw new Error("derived deposit note secrets are degenerate");
5304
- }
5305
- return { keypair: { privateKey, publicKey }, blinding };
5306
- }
5307
- async function createRecoverableDepositUtxo(amount, viewingKeyNk, mintAddress = NATIVE_SOL_MINT, noteSalt = randomDepositNoteSalt()) {
5308
- if (typeof amount !== "bigint" || amount <= 0n) {
5309
- throw new Error("amount must be a positive bigint");
5310
- }
5311
- const { keypair, blinding } = await deriveDepositNoteSecrets(viewingKeyNk, noteSalt);
5312
- const utxo = { amount, keypair, blinding, mintAddress };
5313
- utxo.commitment = await computeCommitment2(utxo);
5314
- return { utxo, noteSalt };
5315
- }
5316
- function normalizeCommitment(value) {
5317
- if (typeof value === "bigint") return value;
5318
- if (typeof value !== "string") return null;
5319
- const clean = value.startsWith("0x") ? value.slice(2) : value;
5320
- if (!/^[0-9a-fA-F]{1,64}$/.test(clean)) return null;
5321
- return BigInt("0x" + clean);
5322
- }
5323
- async function matchDepositNote(params) {
5324
- const { viewingKeyNk, noteSalt, amount, mintAddress, outputCommitments } = params;
5325
- if (typeof amount !== "bigint" || amount <= 0n) return null;
5326
- let secrets;
5327
- try {
5328
- secrets = await deriveDepositNoteSecrets(viewingKeyNk, noteSalt);
5329
- } catch {
5330
- return null;
5331
- }
5332
- const candidate = await computeCommitment2({
5333
- amount,
5334
- keypair: secrets.keypair,
5335
- blinding: secrets.blinding,
5336
- mintAddress
5337
- });
5338
- const published = (outputCommitments ?? []).map(normalizeCommitment).filter((value) => value !== null);
5339
- if (!published.some((value) => value === candidate)) return null;
5340
- return { ...secrets, amount, mintAddress, commitment: candidate, noteSalt };
5341
- }
5342
-
5343
- // src/notes/change-note.ts
5344
- var import_blake36 = require("@noble/hashes/blake3");
5345
- init_utxo();
5346
- init_inputs();
5347
- var CHANGE_NOTE_DOMAIN = new TextEncoder().encode("cloak_change_note_v1");
5348
- var CHANGE_BLINDING_INFO = new TextEncoder().encode("blinding");
5349
- var MAX_OUTPUT_INDEX = 1;
5350
- var MAX_CHAIN_NOTE_SALT2 = (1n << BigInt(CHAIN_NOTE_SALT_BITS)) - 1n;
5351
- function saltToBytes2(noteSalt) {
5352
- if (typeof noteSalt !== "bigint" || noteSalt <= 0n || noteSalt > MAX_CHAIN_NOTE_SALT2) {
5353
- throw new Error(`noteSalt must be a positive ${CHAIN_NOTE_SALT_BITS}-bit value`);
5354
- }
5355
- const out = new Uint8Array(32);
5356
- let v = noteSalt;
5357
- for (let i = 31; i >= 0; i--) {
5358
- out[i] = Number(v & 0xffn);
5359
- v >>= 8n;
5360
- }
5361
- return out;
5362
- }
5363
- function toFieldSecret3(bytes) {
5364
- let value = 0n;
5365
- for (let i = 0; i < 32; i++) value = value << 8n | BigInt(bytes[i]);
5366
- const reduced = value % (BN254_MODULUS >> 4n);
5367
- return reduced === 0n ? 1n : reduced;
5368
- }
5369
- function randomChangeNoteSalt() {
5370
- const bytes = randomBytes(12);
5371
- let v = 0n;
5372
- for (const b of bytes) v = v << 8n | BigInt(b);
5373
- return v === 0n ? 1n : v;
5374
- }
5375
- function deriveChangeNoteBlinding(viewingKeyNk, noteSalt, outputIndex) {
5376
- if (!viewingKeyNk || !(viewingKeyNk instanceof Uint8Array) || viewingKeyNk.length !== 32) {
5377
- throw new Error("viewingKeyNk must be 32 bytes");
5378
- }
5379
- if (!Number.isInteger(outputIndex) || outputIndex < 0 || outputIndex > MAX_OUTPUT_INDEX) {
5380
- throw new Error(`outputIndex must be 0..${MAX_OUTPUT_INDEX}`);
5381
- }
5382
- const salt = saltToBytes2(noteSalt);
5383
- const preimage = new Uint8Array(
5384
- CHANGE_NOTE_DOMAIN.length + viewingKeyNk.length + salt.length + 1 + CHANGE_BLINDING_INFO.length
5385
- );
5386
- let off = 0;
5387
- preimage.set(CHANGE_NOTE_DOMAIN, off);
5388
- off += CHANGE_NOTE_DOMAIN.length;
5389
- preimage.set(viewingKeyNk, off);
5390
- off += viewingKeyNk.length;
5391
- preimage.set(salt, off);
5392
- off += salt.length;
5393
- preimage[off] = outputIndex;
5394
- off += 1;
5395
- preimage.set(CHANGE_BLINDING_INFO, off);
5396
- return toFieldSecret3((0, import_blake36.blake3)(preimage));
5397
- }
5398
- async function createRecoverableChangeUtxo(amount, keypair, viewingKeyNk, mintAddress = NATIVE_SOL_MINT, noteSalt = randomChangeNoteSalt(), outputIndex = 0) {
5399
- if (typeof amount !== "bigint" || amount <= 0n) {
5400
- throw new Error("amount must be a positive bigint");
5401
- }
5402
- const blinding = deriveChangeNoteBlinding(viewingKeyNk, noteSalt, outputIndex);
5403
- const utxo = { amount, keypair, blinding, mintAddress };
5404
- utxo.commitment = await computeCommitment2(utxo);
5405
- return { utxo, noteSalt };
5406
- }
5407
- function normalizeCommitment2(value) {
5408
- if (typeof value === "bigint") return value;
5409
- if (typeof value !== "string") return null;
5410
- const clean = value.startsWith("0x") ? value.slice(2) : value;
5411
- if (!/^[0-9a-fA-F]{1,64}$/.test(clean)) return null;
5412
- return BigInt("0x" + clean);
5413
- }
5414
- async function matchChangeNote(params) {
5415
- const { viewingKeyNk, noteSalt, amount, keypair, mintAddress, outputIndex, outputCommitments } = params;
5416
- if (typeof amount !== "bigint" || amount <= 0n) return null;
5417
- if (!keypair || typeof keypair.publicKey !== "bigint" || keypair.publicKey === 0n) return null;
5418
- let blinding;
5419
- try {
5420
- blinding = deriveChangeNoteBlinding(viewingKeyNk, noteSalt, outputIndex);
5421
- } catch {
5422
- return null;
5423
- }
5424
- const candidate = await computeCommitment2({ amount, keypair, blinding, mintAddress });
5425
- const published = (outputCommitments ?? []).map(normalizeCommitment2).filter((value) => value !== null);
5426
- if (!published.some((value) => value === candidate)) return null;
5427
- return { keypair, blinding, amount, mintAddress, commitment: candidate, noteSalt };
5428
- }
5429
-
5430
- // src/flows/transact.ts
5431
- var import_circomlibjs4 = require("circomlibjs");
5432
- var import_tweetnacl6 = __toESM(require("tweetnacl"), 1);
5433
-
5434
- // src/relay/payload.ts
5435
- var import_sha23 = require("@noble/hashes/sha2");
5436
- var import_utils = require("@noble/hashes/utils");
5437
- var import_tweetnacl5 = __toESM(require("tweetnacl"), 1);
5438
- init_inputs();
5439
- var REQUEST_AUTH_DOMAIN = "CLOAK_RELAY_REQUEST_AUTH_V1";
5440
- var REQUEST_AUTH_MAX_AGE_SECONDS = 300;
5441
- var REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS = 30;
5442
- var RELAY_AUTH_APPROVAL_MARGIN_SECONDS = 15;
5443
- function sha256Hex(text) {
5444
- return (0, import_utils.bytesToHex)((0, import_sha23.sha256)(new TextEncoder().encode(text)));
5445
- }
5446
- function randomNonceUuid() {
5447
- const webCrypto = globalThis?.crypto;
5448
- if (typeof webCrypto?.randomUUID === "function") return webCrypto.randomUUID();
5449
- const proc = globalThis?.process;
5450
- const nodeCrypto = typeof proc?.getBuiltinModule === "function" ? proc.getBuiltinModule("node:crypto") : void 0;
5451
- if (typeof nodeCrypto?.randomUUID === "function") return nodeCrypto.randomUUID();
5452
- const bytes = randomBytes(16);
5453
- bytes[6] = bytes[6] & 15 | 64;
5454
- bytes[8] = bytes[8] & 63 | 128;
5455
- const hex = (0, import_utils.bytesToHex)(bytes);
5456
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
5457
- }
5458
- var TRANSACT_AUTH_FIELDS = [
5459
- "encrypted_notes",
5460
- "max_fee",
5461
- "mint",
5462
- "proof_bytes",
5463
- "public_inputs",
5464
- "recipient",
5465
- "recipient_delivery_notes",
5466
- "risk_quote",
5467
- "sender"
5468
- ];
5469
- var TRANSACT_SWAP_AUTH_FIELDS = [
5470
- "close_timed_out",
5471
- "dexes",
5472
- "encrypted_notes",
5473
- "exclude_dexes",
5474
- "max_fee",
5475
- "min_output_amount",
5476
- "output_mint",
5477
- "proof_bytes",
5478
- "public_inputs",
5479
- "recipient",
5480
- "recipient_ata",
5481
- "refund_blinding",
5482
- "refund_pubkey",
5483
- "retry_request_id",
5484
- "risk_quote",
5485
- "route_retry_attempts",
5486
- "sender",
5487
- "slippage_bps",
5488
- "swap_max_retries"
5489
- ];
5490
- var UTF8 = new TextEncoder();
5491
- function compareKeysBytewise(a, b) {
5492
- if (a === b) return 0;
5493
- const ab = UTF8.encode(a);
5494
- const bb = UTF8.encode(b);
5495
- const shared = Math.min(ab.length, bb.length);
5496
- for (let i = 0; i < shared; i++) {
5497
- if (ab[i] !== bb[i]) return ab[i] - bb[i];
5498
- }
5499
- return ab.length - bb.length;
5500
- }
5501
- function canonicalJson(value) {
5502
- if (value === null || value === void 0) return "null";
5503
- if (typeof value === "boolean") return value ? "true" : "false";
5504
- if (typeof value === "number") {
5505
- if (!Number.isFinite(value) || !Number.isInteger(value) || !Number.isSafeInteger(value)) {
5506
- throw new Error(
5507
- `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.`
5508
- );
5509
- }
5510
- return String(value);
5511
- }
5512
- if (typeof value === "bigint") return value.toString();
5513
- if (typeof value === "string") return JSON.stringify(value);
5514
- if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
5515
- if (typeof value === "object") {
5516
- const obj = value;
5517
- const keys = Object.keys(obj).sort(compareKeysBytewise);
5518
- return "{" + keys.map((k) => {
5519
- const v = obj[k];
5520
- if (typeof v === "function" || typeof v === "symbol") {
5521
- throw new Error(
5522
- `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.`
5523
- );
5524
- }
5525
- return `${JSON.stringify(k)}:${canonicalJson(v)}`;
5526
- }).join(",") + "}";
5527
- }
5528
- throw new Error(`canonicalJson: unsupported value of type ${typeof value}`);
5529
- }
5530
- var FIELDS_WITHOUT_NULL_ENCODING = {
5531
- slippage_bps: "500 (`default_slippage_bps` in api/transact_swap.rs)"
5532
- };
5533
- function buildAuthRequest(body, sender, fields) {
5534
- const out = {};
5535
- for (const k of fields) {
5536
- if (k === "sender") {
5537
- out[k] = sender;
5538
- continue;
5539
- }
5540
- const value = body[k];
5541
- if (value === void 0 || value === null) {
5542
- const relayDefault = FIELDS_WITHOUT_NULL_ENCODING[k];
5543
- if (relayDefault) {
5544
- throw new Error(
5545
- `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.`
5546
- );
5547
- }
5548
- out[k] = null;
5549
- continue;
5550
- }
5551
- out[k] = value;
5552
- }
5553
- return out;
5554
- }
5555
- function buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request) {
5556
- const digest = sha256Hex(canonicalJson(request));
5557
- return new TextEncoder().encode(
5558
- `${REQUEST_AUTH_DOMAIN}
5559
- ${endpoint}
5560
- ${programId.toBase58()}
5561
- ${nonce}
5562
- ${issuedAt}
5563
- ${digest}`
5564
- );
5548
+ return out;
5565
5549
  }
5566
- function buildRelayAuthPreimage(endpoint, programId, body, sender, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
5567
- const senderB58 = sender.toBase58();
5568
- const issuedAt = String(nowSeconds ?? Math.floor(Date.now() / 1e3));
5569
- const nonce = randomNonceUuid();
5570
- const request = buildAuthRequest({ ...body, sender: senderB58 }, senderB58, fields);
5571
- const message = buildRequestAuthMessage(endpoint, programId, issuedAt, nonce, request);
5572
- return { sender: senderB58, auth_issued_at: issuedAt, auth_nonce: nonce, message };
5550
+ function toFieldSecret2(bytes) {
5551
+ let value = 0n;
5552
+ for (let i = 0; i < 32; i++) value = value << 8n | BigInt(bytes[i]);
5553
+ const reduced = value % (BN254_MODULUS >> 4n);
5554
+ return reduced === 0n ? 1n : reduced;
5573
5555
  }
5574
- function signRelayRequest(endpoint, programId, body, signer, nowSeconds, fields = TRANSACT_AUTH_FIELDS) {
5575
- const preimage = buildRelayAuthPreimage(
5576
- endpoint,
5577
- programId,
5578
- body,
5579
- signer.publicKey,
5580
- nowSeconds,
5581
- fields
5556
+ function derive2(nk, salt, info) {
5557
+ const preimage = new Uint8Array(
5558
+ DEPOSIT_NOTE_DOMAIN.length + nk.length + salt.length + info.length
5582
5559
  );
5583
- const signature = import_tweetnacl5.default.sign.detached(preimage.message, signer.secretKey);
5584
- return {
5585
- sender: preimage.sender,
5586
- auth_issued_at: preimage.auth_issued_at,
5587
- auth_nonce: preimage.auth_nonce,
5588
- auth_signature: Buffer.from(signature).toString("base64")
5589
- };
5560
+ let off = 0;
5561
+ preimage.set(DEPOSIT_NOTE_DOMAIN, off);
5562
+ off += DEPOSIT_NOTE_DOMAIN.length;
5563
+ preimage.set(nk, off);
5564
+ off += nk.length;
5565
+ preimage.set(salt, off);
5566
+ off += salt.length;
5567
+ preimage.set(info, off);
5568
+ return (0, import_blake35.blake3)(preimage);
5590
5569
  }
5591
- function assertApprovalWithinFreshnessWindow(elapsedMs, maxAgeSeconds = REQUEST_AUTH_MAX_AGE_SECONDS) {
5592
- const elapsedSeconds = elapsedMs / 1e3;
5593
- const budget = maxAgeSeconds - RELAY_AUTH_APPROVAL_MARGIN_SECONDS;
5594
- if (elapsedSeconds <= budget) return;
5595
- throw new Error(
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.`
5597
- );
5570
+ function randomDepositNoteSalt() {
5571
+ const bytes = randomBytes(12);
5572
+ let v = 0n;
5573
+ for (const b of bytes) v = v << 8n | BigInt(b);
5574
+ return v === 0n ? 1n : v;
5598
5575
  }
5599
- function explainRelayAuthRejection(responseText) {
5600
- const text = String(responseText);
5601
- const has = (needle) => text.includes(needle);
5602
- if (has("issued too far in the future")) {
5603
- 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.`;
5604
- }
5605
- if (has("signature expired")) {
5606
- 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.`;
5576
+ async function deriveDepositNoteSecrets(viewingKeyNk, noteSalt) {
5577
+ if (!viewingKeyNk || !(viewingKeyNk instanceof Uint8Array) || viewingKeyNk.length !== 32) {
5578
+ throw new Error("viewingKeyNk must be 32 bytes");
5607
5579
  }
5608
- if (has("does not match the exact request")) {
5609
- 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\`.`;
5580
+ const salt = saltToBytes(noteSalt);
5581
+ const privateKey = toFieldSecret2(derive2(viewingKeyNk, salt, DEPOSIT_PRIVATE_KEY_INFO));
5582
+ const blinding = toFieldSecret2(derive2(viewingKeyNk, salt, DEPOSIT_BLINDING_INFO));
5583
+ const publicKey = await derivePublicKey(privateKey);
5584
+ if (publicKey === 0n || blinding === 0n) {
5585
+ throw new Error("derived deposit note secrets are degenerate");
5610
5586
  }
5611
- if (has("has no registered viewing key")) {
5612
- 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.`;
5587
+ return { keypair: { privateKey, publicKey }, blinding };
5588
+ }
5589
+ async function createRecoverableDepositUtxo(amount, viewingKeyNk, mintAddress = NATIVE_SOL_MINT, noteSalt = randomDepositNoteSalt()) {
5590
+ if (typeof amount !== "bigint" || amount <= 0n) {
5591
+ throw new Error("amount must be a positive bigint");
5613
5592
  }
5614
- if (has("Authenticated sender is required") || has("auth_issued_at is required") || has("auth_nonce is required") || has("auth_signature is required")) {
5615
- return `The request reached the relay without its authentication fields. Pass \`depositorKeypair\`, or \`signMessage\` together with \`walletPublicKey\`, so the request can be signed.`;
5593
+ const { keypair, blinding } = await deriveDepositNoteSecrets(viewingKeyNk, noteSalt);
5594
+ const utxo = { amount, keypair, blinding, mintAddress };
5595
+ utxo.commitment = await computeCommitment2(utxo);
5596
+ return { utxo, noteSalt };
5597
+ }
5598
+ function normalizeCommitment(value) {
5599
+ if (typeof value === "bigint") return value;
5600
+ if (typeof value !== "string") return null;
5601
+ const clean = value.startsWith("0x") ? value.slice(2) : value;
5602
+ if (!/^[0-9a-fA-F]{1,64}$/.test(clean)) return null;
5603
+ return BigInt("0x" + clean);
5604
+ }
5605
+ async function matchDepositNote(params) {
5606
+ const { viewingKeyNk, noteSalt, amount, mintAddress, outputCommitments } = params;
5607
+ if (typeof amount !== "bigint" || amount <= 0n) return null;
5608
+ let secrets;
5609
+ try {
5610
+ secrets = await deriveDepositNoteSecrets(viewingKeyNk, noteSalt);
5611
+ } catch {
5612
+ return null;
5616
5613
  }
5617
- if (has("auth_nonce must be a canonical UUID")) {
5618
- return `\`auth_nonce\` must be a canonical lowercase UUID. Reuse the one from the preimage.`;
5614
+ const candidate = await computeCommitment2({
5615
+ amount,
5616
+ keypair: secrets.keypair,
5617
+ blinding: secrets.blinding,
5618
+ mintAddress
5619
+ });
5620
+ const published = (outputCommitments ?? []).map(normalizeCommitment).filter((value) => value !== null);
5621
+ if (!published.some((value) => value === candidate)) return null;
5622
+ return { ...secrets, amount, mintAddress, commitment: candidate, noteSalt };
5623
+ }
5624
+
5625
+ // src/notes/change-note.ts
5626
+ var import_blake36 = require("@noble/hashes/blake3");
5627
+ init_utxo();
5628
+ init_inputs();
5629
+ var CHANGE_NOTE_DOMAIN = new TextEncoder().encode("cloak_change_note_v1");
5630
+ var CHANGE_BLINDING_INFO = new TextEncoder().encode("blinding");
5631
+ var MAX_OUTPUT_INDEX = 1;
5632
+ var MAX_CHAIN_NOTE_SALT2 = (1n << BigInt(CHAIN_NOTE_SALT_BITS)) - 1n;
5633
+ function saltToBytes2(noteSalt) {
5634
+ if (typeof noteSalt !== "bigint" || noteSalt <= 0n || noteSalt > MAX_CHAIN_NOTE_SALT2) {
5635
+ throw new Error(`noteSalt must be a positive ${CHAIN_NOTE_SALT_BITS}-bit value`);
5619
5636
  }
5620
- if (has("Relay request signature must be exactly 64 bytes") || has("Invalid relay request signature encoding")) {
5621
- 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.`;
5637
+ const out = new Uint8Array(32);
5638
+ let v = noteSalt;
5639
+ for (let i = 31; i >= 0; i--) {
5640
+ out[i] = Number(v & 0xffn);
5641
+ v >>= 8n;
5622
5642
  }
5623
- return null;
5643
+ return out;
5624
5644
  }
5625
- async function buildRelayAuthFields(endpoint, programId, body, signers, fields = TRANSACT_AUTH_FIELDS) {
5626
- if (signers.depositorKeypair) {
5627
- return signRelayRequest(endpoint, programId, body, signers.depositorKeypair, void 0, fields);
5645
+ function toFieldSecret3(bytes) {
5646
+ let value = 0n;
5647
+ for (let i = 0; i < 32; i++) value = value << 8n | BigInt(bytes[i]);
5648
+ const reduced = value % (BN254_MODULUS >> 4n);
5649
+ return reduced === 0n ? 1n : reduced;
5650
+ }
5651
+ function randomChangeNoteSalt() {
5652
+ const bytes = randomBytes(12);
5653
+ let v = 0n;
5654
+ for (const b of bytes) v = v << 8n | BigInt(b);
5655
+ return v === 0n ? 1n : v;
5656
+ }
5657
+ function deriveChangeNoteBlinding(viewingKeyNk, noteSalt, outputIndex) {
5658
+ if (!viewingKeyNk || !(viewingKeyNk instanceof Uint8Array) || viewingKeyNk.length !== 32) {
5659
+ throw new Error("viewingKeyNk must be 32 bytes");
5628
5660
  }
5629
- const wallet = signers.relayAuthSigner;
5630
- if (!wallet) return null;
5631
- const preimage = buildRelayAuthPreimage(
5632
- endpoint,
5633
- programId,
5634
- body,
5635
- wallet.walletPublicKey,
5636
- void 0,
5637
- fields
5661
+ if (!Number.isInteger(outputIndex) || outputIndex < 0 || outputIndex > MAX_OUTPUT_INDEX) {
5662
+ throw new Error(`outputIndex must be 0..${MAX_OUTPUT_INDEX}`);
5663
+ }
5664
+ const salt = saltToBytes2(noteSalt);
5665
+ const preimage = new Uint8Array(
5666
+ CHANGE_NOTE_DOMAIN.length + viewingKeyNk.length + salt.length + 1 + CHANGE_BLINDING_INFO.length
5638
5667
  );
5639
- const approvalStartedMs = Date.now();
5640
- const signature = await wallet.signMessage(preimage.message);
5641
- assertApprovalWithinFreshnessWindow(Date.now() - approvalStartedMs);
5642
- if (!(signature instanceof Uint8Array) || signature.length !== 64) {
5643
- throw new Error(
5644
- `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.`
5645
- );
5668
+ let off = 0;
5669
+ preimage.set(CHANGE_NOTE_DOMAIN, off);
5670
+ off += CHANGE_NOTE_DOMAIN.length;
5671
+ preimage.set(viewingKeyNk, off);
5672
+ off += viewingKeyNk.length;
5673
+ preimage.set(salt, off);
5674
+ off += salt.length;
5675
+ preimage[off] = outputIndex;
5676
+ off += 1;
5677
+ preimage.set(CHANGE_BLINDING_INFO, off);
5678
+ return toFieldSecret3((0, import_blake36.blake3)(preimage));
5679
+ }
5680
+ async function createRecoverableChangeUtxo(amount, keypair, viewingKeyNk, mintAddress = NATIVE_SOL_MINT, noteSalt = randomChangeNoteSalt(), outputIndex = 0) {
5681
+ if (typeof amount !== "bigint" || amount <= 0n) {
5682
+ throw new Error("amount must be a positive bigint");
5646
5683
  }
5647
- return {
5648
- sender: preimage.sender,
5649
- auth_issued_at: preimage.auth_issued_at,
5650
- auth_nonce: preimage.auth_nonce,
5651
- auth_signature: Buffer.from(signature).toString("base64")
5652
- };
5684
+ const blinding = deriveChangeNoteBlinding(viewingKeyNk, noteSalt, outputIndex);
5685
+ const utxo = { amount, keypair, blinding, mintAddress };
5686
+ utxo.commitment = await computeCommitment2(utxo);
5687
+ return { utxo, noteSalt };
5653
5688
  }
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));
5689
+ function normalizeCommitment2(value) {
5690
+ if (typeof value === "bigint") return value;
5691
+ if (typeof value !== "string") return null;
5692
+ const clean = value.startsWith("0x") ? value.slice(2) : value;
5693
+ if (!/^[0-9a-fA-F]{1,64}$/.test(clean)) return null;
5694
+ return BigInt("0x" + clean);
5659
5695
  }
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"));
5696
+ async function matchChangeNote(params) {
5697
+ const { viewingKeyNk, noteSalt, amount, keypair, mintAddress, outputIndex, outputCommitments } = params;
5698
+ if (typeof amount !== "bigint" || amount <= 0n) return null;
5699
+ if (!keypair || typeof keypair.publicKey !== "bigint" || keypair.publicKey === 0n) return null;
5700
+ let blinding;
5701
+ try {
5702
+ blinding = deriveChangeNoteBlinding(viewingKeyNk, noteSalt, outputIndex);
5703
+ } catch {
5704
+ return null;
5705
+ }
5706
+ const candidate = await computeCommitment2({ amount, keypair, blinding, mintAddress });
5707
+ const published = (outputCommitments ?? []).map(normalizeCommitment2).filter((value) => value !== null);
5708
+ if (!published.some((value) => value === candidate)) return null;
5709
+ return { keypair, blinding, amount, mintAddress, commitment: candidate, noteSalt };
5663
5710
  }
5664
5711
 
5665
5712
  // src/flows/transact.ts
5713
+ var import_circomlibjs4 = require("circomlibjs");
5714
+ var import_tweetnacl6 = __toESM(require("tweetnacl"), 1);
5666
5715
  init_inputs();
5667
5716
 
5668
5717
  // src/proving/artifacts.ts
@@ -6065,7 +6114,7 @@ async function fetchSupplementalAltFromRelay(relayUrl, params) {
6065
6114
  throw new Error("Supplemental ALT response is missing a 'table' address");
6066
6115
  }
6067
6116
  try {
6068
- return new import_web39.PublicKey(table);
6117
+ return new import_web311.PublicKey(table);
6069
6118
  } catch {
6070
6119
  throw new Error(`Supplemental ALT response 'table' is not a valid public key: ${table}`);
6071
6120
  }
@@ -6133,7 +6182,7 @@ async function resolveAddressLookupTableAccounts(connection, relayUrl, altAddres
6133
6182
  const fetched = await Promise.all(
6134
6183
  altAddresses.map(async (addr) => {
6135
6184
  try {
6136
- const pubkey = new import_web39.PublicKey(addr);
6185
+ const pubkey = new import_web311.PublicKey(addr);
6137
6186
  const result = await connection.getAddressLookupTable(pubkey);
6138
6187
  return result.value ?? null;
6139
6188
  } catch {
@@ -6223,7 +6272,7 @@ function calculateConfiguredProtocolFee(amount, config) {
6223
6272
  return total;
6224
6273
  }
6225
6274
  async function readLiveProtocolFee(connection, programId, mint, amount, requireSwapOpen = false) {
6226
- const [poolConfigPda] = import_web39.PublicKey.findProgramAddressSync(
6275
+ const [poolConfigPda] = import_web311.PublicKey.findProgramAddressSync(
6227
6276
  [Buffer.from("pool_config"), mint.toBuffer()],
6228
6277
  programId
6229
6278
  );
@@ -6385,17 +6434,27 @@ async function registerViewingKeyOnce(relayUrl, userPubkey, viewingKeyHex, cache
6385
6434
  viewingKeyHex
6386
6435
  );
6387
6436
  let signatureBase64;
6437
+ let authMode = "message";
6438
+ const messageBytes = new TextEncoder().encode(challenge.message);
6388
6439
  if (options.signMessage) {
6389
- const messageBytes = new TextEncoder().encode(challenge.message);
6390
6440
  const sig = await options.signMessage(messageBytes);
6391
6441
  signatureBase64 = Buffer.from(sig).toString("base64");
6392
6442
  } else if (options.depositorKeypair) {
6393
- const messageBytes = new TextEncoder().encode(challenge.message);
6394
6443
  const sig = import_tweetnacl6.default.sign.detached(messageBytes, options.depositorKeypair.secretKey);
6395
6444
  signatureBase64 = Buffer.from(sig).toString("base64");
6445
+ } else if (options.signAuthTransaction) {
6446
+ onProgress?.(
6447
+ "Approve the viewing-key registration in your wallet. It shows as a 0 SOL transfer to yourself and is never sent to the network."
6448
+ );
6449
+ const signed = await signRelayAuthPayload(
6450
+ { walletPublicKey: userPubkey, signAuthTransaction: options.signAuthTransaction },
6451
+ messageBytes
6452
+ );
6453
+ signatureBase64 = Buffer.from(signed.signature).toString("base64");
6454
+ authMode = signed.mode;
6396
6455
  } else {
6397
6456
  throw new Error(
6398
- "Viewing key registration is mandatory: signMessage (wallet) or depositorKeypair is required."
6457
+ "Viewing key registration is mandatory: signMessage or signAuthTransaction (wallet) or depositorKeypair is required."
6399
6458
  );
6400
6459
  }
6401
6460
  onProgress?.("Registering viewing key...");
@@ -6406,7 +6465,8 @@ async function registerViewingKeyOnce(relayUrl, userPubkey, viewingKeyHex, cache
6406
6465
  user_pubkey: userPubkey.toBase58(),
6407
6466
  viewing_key: viewingKeyHex,
6408
6467
  nonce: challenge.nonce,
6409
- signature: signatureBase64
6468
+ signature: signatureBase64,
6469
+ ...authMode === "transaction" ? { auth_mode: authMode } : {}
6410
6470
  })
6411
6471
  });
6412
6472
  if (!response.ok) {
@@ -6500,7 +6560,7 @@ function buildPublicInputsBytesFromSignals(publicSignals) {
6500
6560
  var TRANSACT_DISCRIMINATOR = 0;
6501
6561
  var RANGE_QUOTE_TAG_DEPOSIT = 1;
6502
6562
  function deriveRiskNoncePDA(programId, nonce) {
6503
- return import_web39.PublicKey.findProgramAddressSync(
6563
+ return import_web311.PublicKey.findProgramAddressSync(
6504
6564
  [Buffer.from("risk_nonce"), Buffer.from(nonce)],
6505
6565
  programId
6506
6566
  );
@@ -6519,7 +6579,7 @@ function extractDepositNonceFromEd25519Ix(ix) {
6519
6579
  }
6520
6580
  }
6521
6581
  function deriveNullifierPDA(programId, poolPDA, nullifier) {
6522
- return import_web39.PublicKey.findProgramAddressSync(
6582
+ return import_web311.PublicKey.findProgramAddressSync(
6523
6583
  [Buffer.from("nullifier"), poolPDA.toBuffer(), Buffer.from(nullifier)],
6524
6584
  programId
6525
6585
  );
@@ -6552,7 +6612,7 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6552
6612
  }
6553
6613
  if (!isDepositData) {
6554
6614
  data[offset++] = 3;
6555
- data.set((relayer ?? import_web39.PublicKey.default).toBytes(), offset);
6615
+ data.set((relayer ?? import_web311.PublicKey.default).toBytes(), offset);
6556
6616
  offset += 32;
6557
6617
  writeBigUInt64LE(data, relayerFee ?? BigInt(0), offset);
6558
6618
  offset += 8;
@@ -6582,7 +6642,7 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6582
6642
  // 4. nullifier PDA 0 (writable)
6583
6643
  { pubkey: nullifierPDA1, isSigner: false, isWritable: true },
6584
6644
  // 5. nullifier PDA 1 (writable)
6585
- { pubkey: import_web39.SystemProgram.programId, isSigner: false, isWritable: false }
6645
+ { pubkey: import_web311.SystemProgram.programId, isSigner: false, isWritable: false }
6586
6646
  // 6. system_program
6587
6647
  ];
6588
6648
  if (splAccounts) {
@@ -6591,34 +6651,34 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6591
6651
  accounts.push({ pubkey: splAccounts.tokenProgram, isSigner: false, isWritable: false });
6592
6652
  if (splAccounts.payerAta) {
6593
6653
  if (enableRiskCheck) {
6594
- accounts.push({ pubkey: import_web39.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6654
+ accounts.push({ pubkey: import_web311.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6595
6655
  }
6596
6656
  accounts.push({ pubkey: splAccounts.payerAta, isSigner: false, isWritable: true });
6597
6657
  if (riskNonce) {
6598
6658
  accounts.push({ pubkey: riskNonce, isSigner: false, isWritable: true });
6599
6659
  }
6600
6660
  } else if (enableRiskCheck && !recipient) {
6601
- accounts.push({ pubkey: import_web39.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6661
+ accounts.push({ pubkey: import_web311.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6602
6662
  }
6603
6663
  } else {
6604
6664
  if (recipient) {
6605
6665
  accounts.push({ pubkey: recipient, isSigner: false, isWritable: true });
6606
6666
  if (enableRiskCheck) {
6607
- accounts.push({ pubkey: import_web39.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6667
+ accounts.push({ pubkey: import_web311.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6608
6668
  }
6609
6669
  } else if (enableRiskCheck) {
6610
6670
  if (publicAmountForAccounts === BigInt(0)) {
6611
6671
  accounts.push({ pubkey: payer, isSigner: true, isWritable: false });
6612
- accounts.push({ pubkey: import_web39.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6672
+ accounts.push({ pubkey: import_web311.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6613
6673
  } else {
6614
- accounts.push({ pubkey: import_web39.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6674
+ accounts.push({ pubkey: import_web311.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6615
6675
  if (riskNonce) {
6616
6676
  accounts.push({ pubkey: riskNonce, isSigner: false, isWritable: true });
6617
6677
  }
6618
6678
  }
6619
6679
  }
6620
6680
  }
6621
- return new import_web39.TransactionInstruction({
6681
+ return new import_web311.TransactionInstruction({
6622
6682
  programId,
6623
6683
  keys: accounts,
6624
6684
  data
@@ -6627,10 +6687,10 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6627
6687
  var PACKET_LIMIT_BYTES = 1232;
6628
6688
  function getCommonALTAddresses() {
6629
6689
  return [
6630
- import_web39.SystemProgram.programId,
6631
- import_web39.SYSVAR_SLOT_HASHES_PUBKEY,
6632
- import_web39.SYSVAR_INSTRUCTIONS_PUBKEY,
6633
- import_web39.ComputeBudgetProgram.programId
6690
+ import_web311.SystemProgram.programId,
6691
+ import_web311.SYSVAR_SLOT_HASHES_PUBKEY,
6692
+ import_web311.SYSVAR_INSTRUCTIONS_PUBKEY,
6693
+ import_web311.ComputeBudgetProgram.programId
6634
6694
  ];
6635
6695
  }
6636
6696
  function dedupePubkeys(addresses) {
@@ -6681,12 +6741,12 @@ async function createEphemeralALT(connection, depositor, onProgress, additionalA
6681
6741
  try {
6682
6742
  const slot = await connection.getSlot("finalized");
6683
6743
  const altPayerPubkey = externalFeePayer ? await externalFeePayer.getPayerPubkey() : depositor.publicKey;
6684
- const [createIx, altAddress] = import_web39.AddressLookupTableProgram.createLookupTable({
6744
+ const [createIx, altAddress] = import_web311.AddressLookupTableProgram.createLookupTable({
6685
6745
  authority: depositor.publicKey,
6686
6746
  payer: altPayerPubkey,
6687
6747
  recentSlot: slot
6688
6748
  });
6689
- const extendIx = import_web39.AddressLookupTableProgram.extendLookupTable({
6749
+ const extendIx = import_web311.AddressLookupTableProgram.extendLookupTable({
6690
6750
  payer: altPayerPubkey,
6691
6751
  authority: depositor.publicKey,
6692
6752
  lookupTable: altAddress,
@@ -6705,12 +6765,12 @@ async function createEphemeralALT(connection, depositor, onProgress, additionalA
6705
6765
  allowSupplementalAlt
6706
6766
  );
6707
6767
  } else {
6708
- const tx = new import_web39.Transaction().add(createIx).add(extendIx);
6768
+ const tx = new import_web311.Transaction().add(createIx).add(extendIx);
6709
6769
  const { blockhash } = await connection.getLatestBlockhash();
6710
6770
  tx.recentBlockhash = blockhash;
6711
6771
  tx.feePayer = depositor.publicKey;
6712
6772
  if (depositor.keypair) {
6713
- await (0, import_web39.sendAndConfirmTransaction)(connection, tx, [depositor.keypair], { commitment: "confirmed" });
6773
+ await (0, import_web311.sendAndConfirmTransaction)(connection, tx, [depositor.keypair], { commitment: "confirmed" });
6714
6774
  } else if (depositor.signTransaction) {
6715
6775
  const signedTx = await depositor.signTransaction(tx);
6716
6776
  const sig = await connection.sendRawTransaction(signedTx.serialize());
@@ -6749,7 +6809,7 @@ async function createEphemeralALT(connection, depositor, onProgress, additionalA
6749
6809
  var SOLANA_PACKET_DATA_SIZE = 1232;
6750
6810
  function estimateV0TransactionSize(payerKey, recentBlockhash, instructions, addressLookupTableAccounts) {
6751
6811
  try {
6752
- const messageV0 = new import_web39.TransactionMessage({
6812
+ const messageV0 = new import_web311.TransactionMessage({
6753
6813
  payerKey,
6754
6814
  recentBlockhash,
6755
6815
  instructions
@@ -6818,7 +6878,7 @@ async function submitViaExternalFeePayer(connection, depositor, externalFeePayer
6818
6878
  const { blockhash: quoteBlockhash } = await connection.getLatestBlockhash();
6819
6879
  const measure = (instrs, alts) => {
6820
6880
  try {
6821
- const message = new import_web39.TransactionMessage({
6881
+ const message = new import_web311.TransactionMessage({
6822
6882
  payerKey: externalFeePayerPubkey,
6823
6883
  recentBlockhash: quoteBlockhash,
6824
6884
  instructions: instrs
@@ -6876,12 +6936,12 @@ async function submitViaExternalFeePayer(connection, depositor, externalFeePayer
6876
6936
  pre = measure(instructions, addressLookupTableAccounts);
6877
6937
  }
6878
6938
  failIfOverLimit(pre.size, pre.error);
6879
- const quoteMessage = new import_web39.TransactionMessage({
6939
+ const quoteMessage = new import_web311.TransactionMessage({
6880
6940
  payerKey: externalFeePayerPubkey,
6881
6941
  recentBlockhash: quoteBlockhash,
6882
6942
  instructions
6883
6943
  }).compileToV0Message(addressLookupTableAccounts ?? []);
6884
- const quoteTxBase64 = Buffer.from(new import_web39.VersionedTransaction(quoteMessage).serialize()).toString("base64");
6944
+ const quoteTxBase64 = Buffer.from(new import_web311.VersionedTransaction(quoteMessage).serialize()).toString("base64");
6885
6945
  const paymentInstruction = await externalFeePayer.getPaymentInstruction(quoteTxBase64);
6886
6946
  const finalInstructions = [...instructions, paymentInstruction];
6887
6947
  let post = measure(finalInstructions, addressLookupTableAccounts);
@@ -6892,12 +6952,12 @@ async function submitViaExternalFeePayer(connection, depositor, externalFeePayer
6892
6952
  failIfOverLimit(post.size, post.error);
6893
6953
  onProgress?.("Building final transaction...");
6894
6954
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
6895
- const finalMessage = new import_web39.TransactionMessage({
6955
+ const finalMessage = new import_web311.TransactionMessage({
6896
6956
  payerKey: externalFeePayerPubkey,
6897
6957
  recentBlockhash: blockhash,
6898
6958
  instructions: finalInstructions
6899
6959
  }).compileToV0Message(addressLookupTableAccounts ?? []);
6900
- const finalTx = new import_web39.VersionedTransaction(finalMessage);
6960
+ const finalTx = new import_web311.VersionedTransaction(finalMessage);
6901
6961
  onProgress?.("Waiting for wallet signature...");
6902
6962
  const partiallySignedTx = await depositor.signTransaction(finalTx);
6903
6963
  const partiallySignedBase64 = Buffer.from(partiallySignedTx.serialize()).toString("base64");
@@ -7118,8 +7178,8 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
7118
7178
  baseInstructions.splice(riskQuoteIx ? 1 : 0, 0, ...topUpInstructions);
7119
7179
  }
7120
7180
  }
7121
- const cuLimitIx = import_web39.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 });
7122
- const cuPriceIx = import_web39.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1e5 });
7181
+ const cuLimitIx = import_web311.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 });
7182
+ const cuPriceIx = import_web311.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1e5 });
7123
7183
  const fullInstructions = [...baseInstructions, cuLimitIx, cuPriceIx, transactIx];
7124
7184
  const compactInstructions = [...baseInstructions, cuLimitIx, transactIx];
7125
7185
  const minimalInstructions = [...baseInstructions, cuLimitIx, transactIx];
@@ -7231,12 +7291,12 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
7231
7291
  }
7232
7292
  let transportAttempt = 0;
7233
7293
  while (true) {
7234
- const messageV0 = new import_web39.TransactionMessage({
7294
+ const messageV0 = new import_web311.TransactionMessage({
7235
7295
  payerKey: depositor.publicKey,
7236
7296
  recentBlockhash: blockhash,
7237
7297
  instructions: ixs
7238
7298
  }).compileToV0Message(addressLookupTableAccounts);
7239
- const versionedTx = new import_web39.VersionedTransaction(messageV0);
7299
+ const versionedTx = new import_web311.VersionedTransaction(messageV0);
7240
7300
  if (onTransactProofBuilt) {
7241
7301
  await onTransactProofBuilt();
7242
7302
  }
@@ -7366,7 +7426,7 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
7366
7426
  let legacyTransportAttempt = 0;
7367
7427
  while (true) {
7368
7428
  try {
7369
- const tx = new import_web39.Transaction();
7429
+ const tx = new import_web311.Transaction();
7370
7430
  for (const ix of instructions) {
7371
7431
  tx.add(ix);
7372
7432
  }
@@ -7374,7 +7434,7 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
7374
7434
  tx.feePayer = depositor.publicKey;
7375
7435
  if (depositor.keypair) {
7376
7436
  onProgress?.("Signing and sending transaction...");
7377
- signature = await (0, import_web39.sendAndConfirmTransaction)(
7437
+ signature = await (0, import_web311.sendAndConfirmTransaction)(
7378
7438
  connection,
7379
7439
  tx,
7380
7440
  [depositor.keypair],
@@ -7590,7 +7650,7 @@ async function fetchRiskQuote(riskQuoteUrl, wallet, options) {
7590
7650
  const messageArr = hexToBytes2(messageHex);
7591
7651
  let signerPubkey;
7592
7652
  try {
7593
- signerPubkey = new import_web39.PublicKey(signerB58);
7653
+ signerPubkey = new import_web311.PublicKey(signerB58);
7594
7654
  } catch {
7595
7655
  throw new Error("Invalid risk quote response: signer_pubkey is not a public key");
7596
7656
  }
@@ -7614,7 +7674,7 @@ async function fetchRiskQuote(riskQuoteUrl, wallet, options) {
7614
7674
  const signature = new Uint8Array(signatureBuf);
7615
7675
  const message = new Uint8Array(messageArr);
7616
7676
  const publicKey = new Uint8Array(publicKeyBytes);
7617
- const instruction = import_web39.Ed25519Program.createInstructionWithPublicKey({
7677
+ const instruction = import_web311.Ed25519Program.createInstructionWithPublicKey({
7618
7678
  publicKey,
7619
7679
  message,
7620
7680
  signature
@@ -7691,18 +7751,22 @@ function planRelayAuth(options) {
7691
7751
  const walletPublicKey = resolveUserWallet(options);
7692
7752
  if (options.depositorKeypair) return { kind: "keypair" };
7693
7753
  const signMessage = options.signMessage;
7754
+ const signAuthTransaction = options.signAuthTransaction;
7694
7755
  if (walletPublicKey && signMessage) return { kind: "wallet", signer: { walletPublicKey, signMessage } };
7695
- if (!walletPublicKey && !signMessage) return { kind: "none" };
7756
+ if (walletPublicKey && signAuthTransaction) {
7757
+ return { kind: "wallet", signer: { walletPublicKey, signAuthTransaction } };
7758
+ }
7759
+ if (!walletPublicKey && !signMessage && !signAuthTransaction) return { kind: "none" };
7696
7760
  return {
7697
7761
  kind: "incomplete",
7698
- 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."
7762
+ 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."
7699
7763
  };
7700
7764
  }
7701
7765
  function assertRelayAuthAvailable(plan, flow) {
7702
7766
  if (plan.kind === "keypair" || plan.kind === "wallet") return;
7703
7767
  const cause = plan.kind === "none" ? "no signer was provided." : `the signer provided cannot produce one: ${plan.detail}`;
7704
7768
  throw new Error(
7705
- `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.`
7769
+ `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.`
7706
7770
  );
7707
7771
  }
7708
7772
  async function submitTransactToRelay(args) {
@@ -8848,7 +8912,7 @@ async function transact(params, options) {
8848
8912
  "All relay-tree attempts failed. Rebuilding merkle tree from chain as last resort..."
8849
8913
  );
8850
8914
  try {
8851
- const [merkleTreePda] = import_web39.PublicKey.findProgramAddressSync(
8915
+ const [merkleTreePda] = import_web311.PublicKey.findProgramAddressSync(
8852
8916
  [Buffer.from("merkle_tree"), mint.toBuffer()],
8853
8917
  programId
8854
8918
  );
@@ -9836,7 +9900,7 @@ async function swapUtxo(params, options) {
9836
9900
  }
9837
9901
  if (options.onSwapStatePredicted && inputNullifiers.length > 0) {
9838
9902
  const nBytes = bigintToBytes323(inputNullifiers[0]);
9839
- const [ssp] = import_web39.PublicKey.findProgramAddressSync(
9903
+ const [ssp] = import_web311.PublicKey.findProgramAddressSync(
9840
9904
  [Buffer.from("swap_state"), pdas.pool.toBuffer(), Buffer.from(nBytes)],
9841
9905
  programId
9842
9906
  );
@@ -10259,8 +10323,7 @@ function cleanupStalePendingOperations(maxAgeMs = 24 * 60 * 60 * 1e3) {
10259
10323
  init_utxo();
10260
10324
 
10261
10325
  // src/relay/batch-auth.ts
10262
- var import_web310 = require("@solana/web3.js");
10263
- var import_tweetnacl7 = __toESM(require("tweetnacl"), 1);
10326
+ var import_web312 = require("@solana/web3.js");
10264
10327
  var RelayBatchAuthCoordinator = class {
10265
10328
  constructor(options) {
10266
10329
  this.proofSlotsInUse = 0;
@@ -10283,7 +10346,7 @@ var RelayBatchAuthCoordinator = class {
10283
10346
  throw new Error(`submitConcurrency must be a positive integer (got ${concurrency}).`);
10284
10347
  }
10285
10348
  this.signer = options.signer;
10286
- this.sender = options.signer instanceof import_web310.Keypair ? options.signer.publicKey : options.signer.walletPublicKey;
10349
+ this.sender = options.signer instanceof import_web312.Keypair ? options.signer.publicKey : options.signer.walletPublicKey;
10287
10350
  this.expectedItems = options.items;
10288
10351
  this.submitConcurrency = concurrency;
10289
10352
  const proofConcurrency = options.proofConcurrency ?? 2;
@@ -10407,24 +10470,19 @@ var RelayBatchAuthCoordinator = class {
10407
10470
  const issuedAt = preimages[0].auth_issued_at;
10408
10471
  const message = buildRelayBatchAuthMessage(programId, issuedAt, digests);
10409
10472
  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 {
10473
+ if (!(this.signer instanceof import_web312.Keypair)) {
10474
+ const asTransaction = !this.signer.signMessage;
10414
10475
  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.`
10476
+ `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.`)
10416
10477
  );
10417
- const approvalStartedMs = Date.now();
10418
- signature = await this.signer.signMessage(message);
10478
+ }
10479
+ const approvalStartedMs = Date.now();
10480
+ const { signature, mode } = await signRelayAuthPayload(this.signer, message);
10481
+ if (!(this.signer instanceof import_web312.Keypair)) {
10419
10482
  assertApprovalWithinFreshnessWindow(
10420
10483
  Date.now() - approvalStartedMs,
10421
10484
  REQUEST_AUTH_BATCH_MAX_AGE_SECONDS
10422
10485
  );
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
10486
  }
10429
10487
  const signatureB64 = Buffer.from(signature).toString("base64");
10430
10488
  wave.forEach((item, i) => {
@@ -10436,6 +10494,7 @@ var RelayBatchAuthCoordinator = class {
10436
10494
  auth_issued_at: preimage.auth_issued_at,
10437
10495
  auth_nonce: preimage.auth_nonce,
10438
10496
  auth_signature: signatureB64,
10497
+ ...mode === "transaction" ? { auth_mode: mode } : {},
10439
10498
  // A fresh array per item: `Object.assign` puts this on the wire body, and the body is
10440
10499
  // serialized again on every network retry.
10441
10500
  auth_batch: { digests: [...digests] }
@@ -10484,10 +10543,18 @@ async function transactBatch(items, options) {
10484
10543
  throw new Error("transactBatch requires relayUrl: batch approval is a relay authentication scheme.");
10485
10544
  }
10486
10545
  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;
10546
+ const signer = shared.depositorKeypair ? shared.depositorKeypair : (() => {
10547
+ const wallet = shared.walletPublicKey ?? shared.depositorPublicKey;
10548
+ if (!wallet) return null;
10549
+ if (shared.signMessage) return { walletPublicKey: wallet, signMessage: shared.signMessage };
10550
+ if (shared.signAuthTransaction) {
10551
+ return { walletPublicKey: wallet, signAuthTransaction: shared.signAuthTransaction };
10552
+ }
10553
+ return null;
10554
+ })();
10488
10555
  if (!signer) {
10489
10556
  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."
10557
+ "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."
10491
10558
  );
10492
10559
  }
10493
10560
  const coordinator = createRelayBatchAuthCoordinator({
@@ -10523,7 +10590,7 @@ async function transactBatch(items, options) {
10523
10590
 
10524
10591
  // src/scanning/scan.ts
10525
10592
  var import_bs583 = __toESM(require("bs58"), 1);
10526
- var import_web311 = require("@solana/web3.js");
10593
+ var import_web313 = require("@solana/web3.js");
10527
10594
  var import_spl_token2 = require("@solana/spl-token");
10528
10595
  init_inputs();
10529
10596
  init_utxo();
@@ -10612,7 +10679,7 @@ function parseSwapOutputMint(data) {
10612
10679
  const mintBytes = data.slice(SWAP_OUTPUT_MINT_OFFSET, end);
10613
10680
  if (mintBytes.every((byte) => byte === 0)) return void 0;
10614
10681
  try {
10615
- return new import_web311.PublicKey(mintBytes).toBase58();
10682
+ return new import_web313.PublicKey(mintBytes).toBase58();
10616
10683
  } catch {
10617
10684
  return void 0;
10618
10685
  }
@@ -10702,7 +10769,7 @@ function parseSwapRecipientAta(data) {
10702
10769
  const recipientAtaBytes = data.slice(recipientAtaStart, recipientAtaEnd);
10703
10770
  if (recipientAtaBytes.every((byte) => byte === 0)) return void 0;
10704
10771
  try {
10705
- return new import_web311.PublicKey(recipientAtaBytes).toBase58();
10772
+ return new import_web313.PublicKey(recipientAtaBytes).toBase58();
10706
10773
  } catch {
10707
10774
  return void 0;
10708
10775
  }
@@ -10864,7 +10931,7 @@ async function scanSwapNoteCarriers(connection, programId, viewingKeyNk, swapCtx
10864
10931
  let rpcCalls = 0;
10865
10932
  const candidates = Array.from(swapCtxByCommitment.keys());
10866
10933
  if (candidates.length === 0) return { records, rpcCalls };
10867
- const [registry] = import_web311.PublicKey.findProgramAddressSync(
10934
+ const [registry] = import_web313.PublicKey.findProgramAddressSync(
10868
10935
  [Buffer.from("cloak_chain_note_registry")],
10869
10936
  programId
10870
10937
  );
@@ -11267,8 +11334,8 @@ async function scanTransactions(opts) {
11267
11334
  if (onChainAta) {
11268
11335
  try {
11269
11336
  const expectedAta = (0, import_spl_token2.getAssociatedTokenAddressSync)(
11270
- new import_web311.PublicKey(asset.mint),
11271
- new import_web311.PublicKey(walletPublicKey)
11337
+ new import_web313.PublicKey(asset.mint),
11338
+ new import_web313.PublicKey(walletPublicKey)
11272
11339
  ).toBase58();
11273
11340
  if (onChainAta === expectedAta) {
11274
11341
  isOurs = true;
@@ -11482,7 +11549,7 @@ async function scanTransactions(opts) {
11482
11549
  // deposit — that is the public deposit amount. A deposit that also merged inputs
11483
11550
  // carries a larger output 0 and is not recoverable from public data alone.
11484
11551
  amount: grossAmount,
11485
- mintAddress: new import_web311.PublicKey(asset.mint),
11552
+ mintAddress: new import_web313.PublicKey(asset.mint),
11486
11553
  outputCommitments: ixCtx.outputCommitments ?? []
11487
11554
  });
11488
11555
  if (recoveredDeposit) {
@@ -11508,7 +11575,7 @@ async function scanTransactions(opts) {
11508
11575
  noteSalt: compactNote.noteSalt,
11509
11576
  amount: compactNote.outAmount0,
11510
11577
  keypair: { privateKey: 0n, publicKey: compactNote.outPubkey0 },
11511
- mintAddress: new import_web311.PublicKey(asset.mint),
11578
+ mintAddress: new import_web313.PublicKey(asset.mint),
11512
11579
  outputIndex: 0,
11513
11580
  // v4 describes output 0, which is where change lands
11514
11581
  outputCommitments: ixCtx.outputCommitments ?? []
@@ -11701,7 +11768,7 @@ function formatComplianceCsv(report) {
11701
11768
  }
11702
11769
 
11703
11770
  // src/wallet/utxo-wallet.ts
11704
- var import_web312 = require("@solana/web3.js");
11771
+ var import_web314 = require("@solana/web3.js");
11705
11772
  init_utxo();
11706
11773
  var UtxoWallet = class _UtxoWallet {
11707
11774
  constructor(viewingKey) {
@@ -11914,7 +11981,7 @@ var UtxoWallet = class _UtxoWallet {
11914
11981
  data.viewingKey ? new Uint8Array(data.viewingKey) : void 0
11915
11982
  );
11916
11983
  for (const w of data.wallets) {
11917
- const mint = new import_web312.PublicKey(w.mint);
11984
+ const mint = new import_web314.PublicKey(w.mint);
11918
11985
  for (const u of w.utxos) {
11919
11986
  wallet.addUtxo({
11920
11987
  amount: BigInt(u.amount),
@@ -11997,7 +12064,7 @@ var SimpleWallet = class {
11997
12064
  };
11998
12065
 
11999
12066
  // src/bridge/rail-verify.ts
12000
- var import_tweetnacl8 = __toESM(require("tweetnacl"), 1);
12067
+ var import_tweetnacl7 = __toESM(require("tweetnacl"), 1);
12001
12068
  var import_sha256 = require("@noble/hashes/sha256");
12002
12069
  var ONECLICK_PUBKEY_B58 = "reYaWhvwu8Jzo3WUM3zhn6VrhuMEF4eADL17qtRVifc";
12003
12070
  var b58 = /* @__PURE__ */ (() => {
@@ -12108,7 +12175,7 @@ function verifyQuoteSignature(resp) {
12108
12175
  const message = new TextEncoder().encode(b58.encode(new Uint8Array(digest)));
12109
12176
  const sig = resp.signature.replace(/^ed25519:/, "");
12110
12177
  try {
12111
- return { valid: import_tweetnacl8.default.sign.detached.verify(message, b58.decode(sig), b58.decode(ONECLICK_PUBKEY_B58)) };
12178
+ return { valid: import_tweetnacl7.default.sign.detached.verify(message, b58.decode(sig), b58.decode(ONECLICK_PUBKEY_B58)) };
12112
12179
  } catch (e) {
12113
12180
  return { valid: false, reason: e instanceof Error ? e.message : String(e) };
12114
12181
  }
@@ -12206,7 +12273,7 @@ function cloakBridgeRail(relayUrl) {
12206
12273
  }
12207
12274
 
12208
12275
  // src/bridge/paymaster-client.ts
12209
- var import_web313 = require("@solana/web3.js");
12276
+ var import_web315 = require("@solana/web3.js");
12210
12277
  var import_spl_token3 = require("@solana/spl-token");
12211
12278
  function validatePaymasterTopUpTransaction(tx, expect) {
12212
12279
  const ixs = tx.instructions;
@@ -12216,12 +12283,12 @@ function validatePaymasterTopUpTransaction(tx, expect) {
12216
12283
  );
12217
12284
  }
12218
12285
  const ix0 = ixs[0];
12219
- if (!ix0.programId.equals(import_web313.SystemProgram.programId)) {
12286
+ if (!ix0.programId.equals(import_web315.SystemProgram.programId)) {
12220
12287
  throw new Error(
12221
12288
  `paymaster top-up instruction 0 is owned by ${ix0.programId.toBase58()}, not the System Program \u2014 refusing to sign an unrecognised first instruction`
12222
12289
  );
12223
12290
  }
12224
- const transfer2 = import_web313.SystemInstruction.decodeTransfer(ix0);
12291
+ const transfer2 = import_web315.SystemInstruction.decodeTransfer(ix0);
12225
12292
  if (!transfer2.toPubkey.equals(expect.recipient)) {
12226
12293
  throw new Error(
12227
12294
  `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`
@@ -12300,10 +12367,10 @@ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
12300
12367
  "paymaster prepare returned a voucher that is already expired \u2014 refusing to sign a stale top-up rather than fail confusingly at cosign"
12301
12368
  );
12302
12369
  }
12303
- const feeMint = new import_web313.PublicKey(prepared.fee_mint);
12304
- const paymentAddress = new import_web313.PublicKey(prepared.payment_address);
12370
+ const feeMint = new import_web315.PublicKey(prepared.fee_mint);
12371
+ const paymentAddress = new import_web315.PublicKey(prepared.payment_address);
12305
12372
  const feeTokenAmount = BigInt(prepared.fee_token_amount);
12306
- const tx = import_web313.Transaction.from(Buffer.from(prepared.transaction, "base64"));
12373
+ const tx = import_web315.Transaction.from(Buffer.from(prepared.transaction, "base64"));
12307
12374
  validatePaymasterTopUpTransaction(tx, {
12308
12375
  recipient: receiver.publicKey,
12309
12376
  maxGrantLamports: grantLamports,
@@ -12322,7 +12389,7 @@ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
12322
12389
  });
12323
12390
  const cosigned = await parseBridgeResponse2(cosignRes, "paymaster cosign");
12324
12391
  return {
12325
- transaction: import_web313.Transaction.from(Buffer.from(cosigned.transaction, "base64")),
12392
+ transaction: import_web315.Transaction.from(Buffer.from(cosigned.transaction, "base64")),
12326
12393
  feeTokenAmount,
12327
12394
  feeMint: prepared.fee_mint,
12328
12395
  paymentAddress: prepared.payment_address
@@ -12330,7 +12397,7 @@ async function fundReceiverViaPaymaster(relayUrl, receiver, grantLamports) {
12330
12397
  }
12331
12398
 
12332
12399
  // src/bridge/derive.ts
12333
- var import_web314 = require("@solana/web3.js");
12400
+ var import_web316 = require("@solana/web3.js");
12334
12401
  var import_hmac = require("@noble/hashes/hmac");
12335
12402
  var import_sha512 = require("@noble/hashes/sha512");
12336
12403
  var BRIDGE_ESCROW_LABEL = "cloak_bridge_escrow";
@@ -12345,11 +12412,11 @@ function deriveBridgeReceiver(nk, index) {
12345
12412
  );
12346
12413
  }
12347
12414
  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));
12415
+ return import_web316.Keypair.fromSeed(h.slice(0, 32));
12349
12416
  }
12350
12417
 
12351
12418
  // src/bridge/discover.ts
12352
- var import_web315 = require("@solana/web3.js");
12419
+ var import_web317 = require("@solana/web3.js");
12353
12420
  var import_spl_token4 = require("@solana/spl-token");
12354
12421
  function describeError(err) {
12355
12422
  return err instanceof Error ? err.message : String(err);
@@ -12371,7 +12438,7 @@ async function listBridgeDeposits(conn, nk, opts) {
12371
12438
  try {
12372
12439
  tokenBalance = BigInt((await conn.getTokenAccountBalance(tokenAccount)).value.amount);
12373
12440
  } catch (err) {
12374
- if (!(err instanceof import_web315.SolanaJSONRPCError && /could not find account/i.test(err.message))) {
12441
+ if (!(err instanceof import_web317.SolanaJSONRPCError && /could not find account/i.test(err.message))) {
12375
12442
  throw err;
12376
12443
  }
12377
12444
  }
@@ -12426,18 +12493,18 @@ async function listBridgeDeposits(conn, nk, opts) {
12426
12493
  }
12427
12494
 
12428
12495
  // src/bridge/deposit-core.ts
12429
- var import_web317 = require("@solana/web3.js");
12430
- var import_tweetnacl9 = __toESM(require("tweetnacl"), 1);
12496
+ var import_web319 = require("@solana/web3.js");
12497
+ var import_tweetnacl8 = __toESM(require("tweetnacl"), 1);
12431
12498
  init_utxo();
12432
12499
 
12433
12500
  // src/bridge/funder.ts
12434
- var import_web316 = require("@solana/web3.js");
12501
+ var import_web318 = require("@solana/web3.js");
12435
12502
  var import_spl_token5 = require("@solana/spl-token");
12436
12503
  var MAINNET_RENT_0 = 890880;
12437
12504
  var MAINNET_RENT_1 = 897840;
12438
12505
  var FEE_BUDGET = 13e4;
12439
12506
  var CLEANUP_FEE_BUDGET = 5e3;
12440
- var pda = (seeds, programId) => import_web316.PublicKey.findProgramAddressSync(seeds.map((s) => Buffer.from(s)), programId)[0];
12507
+ var pda = (seeds, programId) => import_web318.PublicKey.findProgramAddressSync(seeds.map((s) => Buffer.from(s)), programId)[0];
12441
12508
  function deriveFundingTargets(d) {
12442
12509
  const pool = pda([Buffer.from("pool"), d.mint.toBuffer()], d.programId);
12443
12510
  return {
@@ -12498,15 +12565,15 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
12498
12565
  if (heldByR >= grantR) {
12499
12566
  log(` R already holds ${heldByR} (>= ${grantR}) \u2014 no top-up needed`);
12500
12567
  } 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 })
12568
+ await (0, import_web319.sendAndConfirmTransaction)(conn, new import_web319.Transaction().add(
12569
+ import_web319.SystemProgram.transfer({ fromPubkey: funder.publicKey, toPubkey: R.publicKey, lamports: grantR - heldByR })
12503
12570
  ), [funder]);
12504
12571
  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
12572
  }
12506
12573
  let measuredSize = -1;
12507
12574
  let fundedAccounts = [];
12508
12575
  const signTransaction2 = async (tx) => {
12509
- if (tx instanceof import_web317.VersionedTransaction) {
12576
+ if (tx instanceof import_web319.VersionedTransaction) {
12510
12577
  measuredSize = tx.serialize().length;
12511
12578
  const alts = await Promise.all(
12512
12579
  tx.message.addressTableLookups.map(async (l) => (await conn.getAddressLookupTable(l.accountKey)).value)
@@ -12525,13 +12592,13 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
12525
12592
  address: t.a.toBase58(),
12526
12593
  lamportsSent: Math.max(0, t.need - (infos[i]?.lamports ?? 0))
12527
12594
  }));
12528
- const ixs = targets.flatMap((t, i) => (infos[i]?.lamports ?? 0) >= t.need ? [] : [import_web317.SystemProgram.transfer({
12595
+ const ixs = targets.flatMap((t, i) => (infos[i]?.lamports ?? 0) >= t.need ? [] : [import_web319.SystemProgram.transfer({
12529
12596
  fromPubkey: funder.publicKey,
12530
12597
  toPubkey: t.a,
12531
12598
  lamports: t.need - (infos[i]?.lamports ?? 0)
12532
12599
  })]);
12533
12600
  if (ixs.length) {
12534
- const sig = await (0, import_web317.sendAndConfirmTransaction)(conn, new import_web317.Transaction().add(...ixs), [funder]);
12601
+ const sig = await (0, import_web319.sendAndConfirmTransaction)(conn, new import_web319.Transaction().add(...ixs), [funder]);
12535
12602
  log(` seam: funded ${ixs.length} program accounts read off the built tx \u2014 ${sig.slice(0, 16)}\u2026`);
12536
12603
  }
12537
12604
  tx.sign([R]);
@@ -12540,7 +12607,7 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
12540
12607
  tx.partialSign(R);
12541
12608
  return tx;
12542
12609
  };
12543
- const signMessage = async (m) => import_tweetnacl9.default.sign.detached(m, R.secretKey);
12610
+ const signMessage = async (m) => import_tweetnacl8.default.sign.detached(m, R.secretKey);
12544
12611
  const utxoKeypair = await deriveUtxoKeypairFromSpendKey(opts.noteSpendKey);
12545
12612
  const nk = getNkFromUtxoPrivateKey(utxoKeypair.privateKey);
12546
12613
  const { utxo, noteSalt } = await createRecoverableDepositUtxo(amount, nk, mint);
@@ -12587,9 +12654,9 @@ async function depositFromDerivedKey(conn, R, funder, amount, log = console.log,
12587
12654
  }
12588
12655
 
12589
12656
  // src/bridge/cleanup.ts
12590
- var import_web318 = require("@solana/web3.js");
12657
+ var import_web320 = require("@solana/web3.js");
12591
12658
  var import_spl_token6 = require("@solana/spl-token");
12592
- var DEFAULT_MINT = new import_web318.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
12659
+ var DEFAULT_MINT = new import_web320.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
12593
12660
  async function cleanupReceivingAddress(conn, R, dustDestination, mint = DEFAULT_MINT) {
12594
12661
  assertAllowedRpcConnection(conn);
12595
12662
  const rAta = (0, import_spl_token6.getAssociatedTokenAddressSync)(mint, R.publicKey);
@@ -12635,7 +12702,7 @@ async function cleanupReceivingAddress(conn, R, dustDestination, mint = DEFAULT_
12635
12702
  destination = destAta.toBase58();
12636
12703
  }
12637
12704
  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], {
12705
+ const signature = await (0, import_web320.sendAndConfirmTransaction)(conn, new import_web320.Transaction().add(...ixs), [R], {
12639
12706
  commitment: "confirmed"
12640
12707
  });
12641
12708
  const after = await conn.getBalance(R.publicKey);
@@ -12837,6 +12904,7 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
12837
12904
  assessBridgeQuote,
12838
12905
  bigintToBytes32,
12839
12906
  bigintToHex,
12907
+ buildAuthTransactionMessage,
12840
12908
  buildMerkleTree,
12841
12909
  buildMerkleTreeFromChain,
12842
12910
  buildMerkleTreeFromRelay,
@@ -13017,10 +13085,12 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
13017
13085
  sdkLogger,
13018
13086
  selectUtxos,
13019
13087
  sendTransaction,
13088
+ serializeAuthTransactionMessage,
13020
13089
  serializeNote,
13021
13090
  serializeUtxo,
13022
13091
  setCircuitsPath,
13023
13092
  setDebugMode,
13093
+ signRelayAuthPayload,
13024
13094
  signTransaction,
13025
13095
  splitTo2Limbs,
13026
13096
  submitTransactToRelay,