@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 +609 -539
- package/dist/index.d.cts +205 -154
- package/dist/index.d.ts +205 -154
- package/dist/index.js +432 -363
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
1394
|
+
var import_tweetnacl3 = __toESM(require("tweetnacl"), 1);
|
|
1392
1395
|
var import_blake32 = require("@noble/hashes/blake3");
|
|
1393
|
-
var
|
|
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 =
|
|
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 =
|
|
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
|
|
1989
|
+
return import_tweetnacl3.default.scalarMult(factor, masterCompliancePublicKey);
|
|
1717
1990
|
}
|
|
1718
|
-
function
|
|
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
|
|
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 =
|
|
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
|
|
1750
|
-
|
|
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
|
|
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 =
|
|
1867
|
-
const sharedSecret =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1959
|
-
const sharedSecret =
|
|
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
|
|
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] =
|
|
3177
|
+
const [pool] = import_web35.PublicKey.findProgramAddressSync(
|
|
2901
3178
|
[Buffer.from("pool"), mint.toBuffer()],
|
|
2902
3179
|
pid
|
|
2903
3180
|
);
|
|
2904
|
-
const [merkleTree] =
|
|
3181
|
+
const [merkleTree] = import_web35.PublicKey.findProgramAddressSync(
|
|
2905
3182
|
[Buffer.from("merkle_tree"), mint.toBuffer()],
|
|
2906
3183
|
pid
|
|
2907
3184
|
);
|
|
2908
|
-
const [treasury] =
|
|
3185
|
+
const [treasury] = import_web35.PublicKey.findProgramAddressSync(
|
|
2909
3186
|
[Buffer.from("treasury"), mint.toBuffer()],
|
|
2910
3187
|
pid
|
|
2911
3188
|
);
|
|
2912
|
-
const [vaultAuthority] =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
3605
|
-
|
|
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,
|
|
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
|
|
4052
|
+
var import_web37 = require("@solana/web3.js");
|
|
3771
4053
|
init_types();
|
|
3772
4054
|
function validateWalletConnected(wallet) {
|
|
3773
|
-
if (wallet instanceof
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
4918
|
-
const shared =
|
|
4919
|
-
const nonce =
|
|
4920
|
-
const ciphertext =
|
|
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 =
|
|
4947
|
-
const plaintext =
|
|
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
|
|
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] =
|
|
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] =
|
|
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
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
const
|
|
5570
|
-
|
|
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
|
|
5575
|
-
const preimage =
|
|
5576
|
-
|
|
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
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
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
|
|
5592
|
-
const
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
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
|
|
5600
|
-
|
|
5601
|
-
|
|
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
|
-
|
|
5609
|
-
|
|
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
|
-
|
|
5612
|
-
|
|
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
|
-
|
|
5615
|
-
|
|
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
|
-
|
|
5618
|
-
|
|
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
|
-
|
|
5621
|
-
|
|
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
|
|
5643
|
+
return out;
|
|
5624
5644
|
}
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
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
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
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
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
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
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
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
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
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
|
|
5661
|
-
const
|
|
5662
|
-
|
|
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
|
|
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
|
|
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] =
|
|
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
|
|
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
|
|
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 ??
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
6672
|
+
accounts.push({ pubkey: import_web311.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
|
|
6613
6673
|
} else {
|
|
6614
|
-
accounts.push({ pubkey:
|
|
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
|
|
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
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
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] =
|
|
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 =
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
7122
|
-
const cuPriceIx =
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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 =
|
|
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 (
|
|
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 ? "
|
|
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\`
|
|
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] =
|
|
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] =
|
|
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
|
|
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
|
|
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
|
-
|
|
10411
|
-
|
|
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
|
-
|
|
10418
|
-
|
|
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 :
|
|
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 `
|
|
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
|
|
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
|
|
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
|
|
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] =
|
|
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
|
|
11271
|
-
new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
12304
|
-
const paymentAddress = new
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
|
12415
|
+
return import_web316.Keypair.fromSeed(h.slice(0, 32));
|
|
12349
12416
|
}
|
|
12350
12417
|
|
|
12351
12418
|
// src/bridge/discover.ts
|
|
12352
|
-
var
|
|
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
|
|
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
|
|
12430
|
-
var
|
|
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
|
|
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) =>
|
|
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,
|
|
12502
|
-
|
|
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
|
|
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 ? [] : [
|
|
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,
|
|
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) =>
|
|
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
|
|
12657
|
+
var import_web320 = require("@solana/web3.js");
|
|
12591
12658
|
var import_spl_token6 = require("@solana/spl-token");
|
|
12592
|
-
var DEFAULT_MINT = new
|
|
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,
|
|
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,
|