@veil-cash/sdk 0.6.3 → 0.6.5
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/README.md +1 -0
- package/SDK.md +45 -0
- package/dist/cli/index.cjs +149 -92
- package/dist/index.cjs +118 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +102 -64
- package/dist/index.d.ts +102 -64
- package/dist/index.js +99 -48
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/compat.ts +23 -0
- package/src/ffjavascript.d.ts +33 -0
- package/src/index.ts +1 -1
- package/src/keypair.ts +2 -4
- package/src/prover.ts +108 -36
- package/src/subaccount.ts +2 -0
- package/src/transaction.ts +8 -2
- package/src/transfer.ts +5 -1
- package/src/types.ts +21 -0
- package/src/utils.ts +12 -5
- package/src/utxo.ts +1 -0
- package/src/withdraw.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
|
+
import { Buffer } from 'buffer';
|
|
2
3
|
import { privateKeyToAccount, privateKeyToAddress } from 'viem/accounts';
|
|
3
|
-
import * as
|
|
4
|
+
import * as _ethSigUtil from 'eth-sig-util';
|
|
5
|
+
import * as _circomlib from 'circomlib';
|
|
4
6
|
import { encodeFunctionData, parseEther, parseUnits, createPublicClient, http, formatUnits, keccak256, encodePacked, isAddress, formatEther } from 'viem';
|
|
5
7
|
import { base } from 'viem/chains';
|
|
6
8
|
import MerkleTree from 'fixed-merkle-tree-legacy';
|
|
7
9
|
import { groth16 } from 'snarkjs';
|
|
8
|
-
import
|
|
9
|
-
import * as fs from 'fs';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
10
|
+
import { utils } from 'ffjavascript';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
12
|
+
// src/keypair.ts
|
|
13
|
+
function resolveInterop(mod) {
|
|
14
|
+
if (mod && typeof mod === "object" && "default" in mod) {
|
|
15
|
+
const defaultVal = mod.default;
|
|
16
|
+
if (defaultVal != null) return defaultVal;
|
|
17
|
+
}
|
|
18
|
+
return mod;
|
|
19
|
+
}
|
|
20
|
+
var ethSigUtil = resolveInterop(_ethSigUtil);
|
|
21
|
+
var circomlib = resolveInterop(_circomlib);
|
|
19
22
|
var poseidon = circomlib.poseidon;
|
|
20
23
|
var FIELD_SIZE = BigInt(
|
|
21
24
|
"21888242871839275222246405745257275088548364400416034343698204186575808495617"
|
|
@@ -23,7 +26,11 @@ var FIELD_SIZE = BigInt(
|
|
|
23
26
|
var poseidonHash = (items) => BigInt(poseidon(items).toString());
|
|
24
27
|
var poseidonHash2 = (a, b) => poseidonHash([a, b]);
|
|
25
28
|
var randomBN = (nbytes = 31) => {
|
|
26
|
-
const
|
|
29
|
+
const cryptoApi = globalThis.crypto;
|
|
30
|
+
if (!cryptoApi?.getRandomValues) {
|
|
31
|
+
throw new Error("Secure random number generation is unavailable in this runtime");
|
|
32
|
+
}
|
|
33
|
+
const bytes = cryptoApi.getRandomValues(new Uint8Array(nbytes));
|
|
27
34
|
let hex = "0x";
|
|
28
35
|
for (let i = 0; i < bytes.length; i++) {
|
|
29
36
|
hex += bytes[i].toString(16).padStart(2, "0");
|
|
@@ -50,8 +57,7 @@ var toBuffer = (value, length) => {
|
|
|
50
57
|
return Buffer.from(hex, "hex");
|
|
51
58
|
};
|
|
52
59
|
function getExtDataHash(extData) {
|
|
53
|
-
const
|
|
54
|
-
const abi = ethers2.AbiCoder.defaultAbiCoder();
|
|
60
|
+
const abi = ethers.AbiCoder.defaultAbiCoder();
|
|
55
61
|
const encodedData = abi.encode(
|
|
56
62
|
["tuple(address,int256,address,uint256,bytes,bytes)"],
|
|
57
63
|
[[
|
|
@@ -63,7 +69,7 @@ function getExtDataHash(extData) {
|
|
|
63
69
|
extData.encryptedOutput2
|
|
64
70
|
]]
|
|
65
71
|
);
|
|
66
|
-
const hash =
|
|
72
|
+
const hash = ethers.keccak256(encodedData);
|
|
67
73
|
return BigInt(hash) % FIELD_SIZE;
|
|
68
74
|
}
|
|
69
75
|
function shuffle(array) {
|
|
@@ -79,7 +85,6 @@ function shuffle(array) {
|
|
|
79
85
|
|
|
80
86
|
// src/keypair.ts
|
|
81
87
|
var VEIL_SIGNED_MESSAGE = "Sign this message to create your Veil Wallet private key. This will be used to decrypt your balances. Ensure you are signing this message on the Veil Cash website.";
|
|
82
|
-
var ethSigUtil = __require("eth-sig-util");
|
|
83
88
|
function packEncryptedMessage(encryptedMessage) {
|
|
84
89
|
const nonceBuf = Buffer.from(encryptedMessage.nonce, "base64");
|
|
85
90
|
const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, "base64");
|
|
@@ -262,8 +267,6 @@ var Keypair = class _Keypair {
|
|
|
262
267
|
);
|
|
263
268
|
}
|
|
264
269
|
};
|
|
265
|
-
|
|
266
|
-
// src/utxo.ts
|
|
267
270
|
var Utxo = class _Utxo {
|
|
268
271
|
amount;
|
|
269
272
|
blinding;
|
|
@@ -1456,21 +1459,37 @@ function getMerklePath(tree, commitment) {
|
|
|
1456
1459
|
pathIndices: index
|
|
1457
1460
|
};
|
|
1458
1461
|
}
|
|
1459
|
-
var
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1462
|
+
var ffUtils = utils;
|
|
1463
|
+
function isBrowserRuntime() {
|
|
1464
|
+
return !(typeof process !== "undefined" && !!process.versions?.node);
|
|
1465
|
+
}
|
|
1466
|
+
function stripTrailingSlash(value) {
|
|
1467
|
+
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
1465
1468
|
}
|
|
1466
|
-
function
|
|
1469
|
+
function normalizeCircuitBasePath(provingKeyPath, circuitName) {
|
|
1470
|
+
const resolvedPath = typeof provingKeyPath === "function" ? provingKeyPath(circuitName) : provingKeyPath;
|
|
1471
|
+
const withoutExtension = resolvedPath.replace(/\.(wasm|zkey)$/i, "");
|
|
1472
|
+
if (withoutExtension.endsWith(`/${circuitName}`) || withoutExtension.endsWith(`\\${circuitName}`)) {
|
|
1473
|
+
return withoutExtension;
|
|
1474
|
+
}
|
|
1475
|
+
return `${stripTrailingSlash(withoutExtension)}/${circuitName}`;
|
|
1476
|
+
}
|
|
1477
|
+
function importNodeModule(specifier) {
|
|
1478
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
1479
|
+
return dynamicImport(specifier);
|
|
1480
|
+
}
|
|
1481
|
+
async function findNodeKeysDirectory() {
|
|
1482
|
+
const [{ existsSync }, pathModule, { fileURLToPath }] = await Promise.all([
|
|
1483
|
+
importNodeModule("node:fs"),
|
|
1484
|
+
importNodeModule("node:path"),
|
|
1485
|
+
importNodeModule("node:url")
|
|
1486
|
+
]);
|
|
1487
|
+
const path = pathModule;
|
|
1467
1488
|
const possiblePaths = [
|
|
1468
1489
|
// When running from package (installed via npm)
|
|
1469
|
-
path.resolve(
|
|
1470
|
-
path.resolve(__dirname, "..", "..", "keys"),
|
|
1490
|
+
path.resolve(process.cwd(), "node_modules", "@veil-cash", "sdk", "keys"),
|
|
1471
1491
|
// When running from source
|
|
1472
1492
|
path.resolve(process.cwd(), "keys")
|
|
1473
|
-
// ESM module path
|
|
1474
1493
|
];
|
|
1475
1494
|
try {
|
|
1476
1495
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
@@ -1479,7 +1498,7 @@ function findKeysDirectory() {
|
|
|
1479
1498
|
} catch {
|
|
1480
1499
|
}
|
|
1481
1500
|
for (const p of possiblePaths) {
|
|
1482
|
-
if (
|
|
1501
|
+
if (existsSync(p) && existsSync(path.join(p, "transaction2.wasm"))) {
|
|
1483
1502
|
return p;
|
|
1484
1503
|
}
|
|
1485
1504
|
}
|
|
@@ -1487,26 +1506,48 @@ function findKeysDirectory() {
|
|
|
1487
1506
|
"Circuit keys not found. Expected to find keys/ directory with transaction2.wasm and transaction2.zkey files."
|
|
1488
1507
|
);
|
|
1489
1508
|
}
|
|
1490
|
-
async function
|
|
1491
|
-
if (
|
|
1492
|
-
|
|
1509
|
+
async function resolveProvingKeyPaths(circuitName, provingKeyPath) {
|
|
1510
|
+
if (provingKeyPath) {
|
|
1511
|
+
const circuitBasePath = normalizeCircuitBasePath(provingKeyPath, circuitName);
|
|
1512
|
+
return {
|
|
1513
|
+
wasmPath: `${circuitBasePath}.wasm`,
|
|
1514
|
+
zkeyPath: `${circuitBasePath}.zkey`
|
|
1515
|
+
};
|
|
1493
1516
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1517
|
+
if (isBrowserRuntime()) {
|
|
1518
|
+
return {
|
|
1519
|
+
wasmPath: `/keys/${circuitName}.wasm`,
|
|
1520
|
+
zkeyPath: `/keys/${circuitName}.zkey`
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
const keysDir = await findNodeKeysDirectory();
|
|
1524
|
+
return {
|
|
1525
|
+
wasmPath: `${keysDir}/${circuitName}.wasm`,
|
|
1526
|
+
zkeyPath: `${keysDir}/${circuitName}.zkey`
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
async function assertNodeKeyFilesExist(wasmPath, zkeyPath) {
|
|
1530
|
+
if (isBrowserRuntime() || wasmPath.startsWith("http://") || wasmPath.startsWith("https://")) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const { existsSync } = await importNodeModule("node:fs");
|
|
1534
|
+
if (!existsSync(wasmPath)) {
|
|
1498
1535
|
throw new Error(`Circuit WASM file not found: ${wasmPath}`);
|
|
1499
1536
|
}
|
|
1500
|
-
if (!
|
|
1537
|
+
if (!existsSync(zkeyPath)) {
|
|
1501
1538
|
throw new Error(`Circuit zkey file not found: ${zkeyPath}`);
|
|
1502
1539
|
}
|
|
1540
|
+
}
|
|
1541
|
+
async function prove(input, circuitName, options = {}) {
|
|
1542
|
+
const { wasmPath, zkeyPath } = await resolveProvingKeyPaths(circuitName, options.provingKeyPath);
|
|
1543
|
+
await assertNodeKeyFilesExist(wasmPath, zkeyPath);
|
|
1503
1544
|
const result = await groth16.fullProve(
|
|
1504
|
-
|
|
1545
|
+
ffUtils.stringifyBigInts(input),
|
|
1505
1546
|
wasmPath,
|
|
1506
1547
|
zkeyPath,
|
|
1507
1548
|
void 0,
|
|
1508
1549
|
void 0,
|
|
1509
|
-
{ singleThread: true }
|
|
1550
|
+
{ singleThread: options.singleThread ?? true }
|
|
1510
1551
|
);
|
|
1511
1552
|
const proof = result.proof;
|
|
1512
1553
|
return "0x" + toFixedHex(proof.pi_a[0]).slice(2) + toFixedHex(proof.pi_a[1]).slice(2) + toFixedHex(proof.pi_b[0][1]).slice(2) + toFixedHex(proof.pi_b[0][0]).slice(2) + toFixedHex(proof.pi_b[1][1]).slice(2) + toFixedHex(proof.pi_b[1][0]).slice(2) + toFixedHex(proof.pi_c[0]).slice(2) + toFixedHex(proof.pi_c[1]).slice(2);
|
|
@@ -1534,7 +1575,8 @@ async function getProof({
|
|
|
1534
1575
|
fee,
|
|
1535
1576
|
recipient,
|
|
1536
1577
|
relayer,
|
|
1537
|
-
onProgress
|
|
1578
|
+
onProgress,
|
|
1579
|
+
provingKeyPath
|
|
1538
1580
|
}) {
|
|
1539
1581
|
inputs = shuffle([...inputs]);
|
|
1540
1582
|
outputs = shuffle([...outputs]);
|
|
@@ -1594,7 +1636,7 @@ async function getProof({
|
|
|
1594
1636
|
};
|
|
1595
1637
|
onProgress?.("Generating ZK proof...", `${inputs.length} inputs`);
|
|
1596
1638
|
const circuitName = selectCircuit(inputs.length);
|
|
1597
|
-
const proof = await prove(proofInput, circuitName);
|
|
1639
|
+
const proof = await prove(proofInput, circuitName, { provingKeyPath });
|
|
1598
1640
|
const args = {
|
|
1599
1641
|
proof,
|
|
1600
1642
|
root: toFixedHex(proofInput.root),
|
|
@@ -1616,7 +1658,8 @@ async function prepareTransaction({
|
|
|
1616
1658
|
fee = 0,
|
|
1617
1659
|
recipient = 0,
|
|
1618
1660
|
relayer = 0,
|
|
1619
|
-
onProgress
|
|
1661
|
+
onProgress,
|
|
1662
|
+
provingKeyPath
|
|
1620
1663
|
}) {
|
|
1621
1664
|
if (inputs.length > 16 || outputs.length > 2) {
|
|
1622
1665
|
throw new Error("Incorrect inputs/outputs count. Maximum: 16 inputs, 2 outputs.");
|
|
@@ -1638,7 +1681,8 @@ async function prepareTransaction({
|
|
|
1638
1681
|
fee: BigInt(fee),
|
|
1639
1682
|
recipient: String(recipient),
|
|
1640
1683
|
relayer: String(relayer),
|
|
1641
|
-
onProgress
|
|
1684
|
+
onProgress,
|
|
1685
|
+
provingKeyPath
|
|
1642
1686
|
});
|
|
1643
1687
|
return result;
|
|
1644
1688
|
}
|
|
@@ -1796,6 +1840,7 @@ async function buildWithdrawProof(options) {
|
|
|
1796
1840
|
keypair,
|
|
1797
1841
|
pool = "eth",
|
|
1798
1842
|
rpcUrl,
|
|
1843
|
+
provingKeyPath,
|
|
1799
1844
|
onProgress
|
|
1800
1845
|
} = options;
|
|
1801
1846
|
const poolConfig = POOL_CONFIG[pool];
|
|
@@ -1859,7 +1904,8 @@ async function buildWithdrawProof(options) {
|
|
|
1859
1904
|
fee: 0,
|
|
1860
1905
|
recipient,
|
|
1861
1906
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
1862
|
-
onProgress
|
|
1907
|
+
onProgress,
|
|
1908
|
+
provingKeyPath
|
|
1863
1909
|
});
|
|
1864
1910
|
return {
|
|
1865
1911
|
proofArgs: {
|
|
@@ -1956,6 +2002,7 @@ async function buildTransferProof(options) {
|
|
|
1956
2002
|
senderKeypair,
|
|
1957
2003
|
pool = "eth",
|
|
1958
2004
|
rpcUrl,
|
|
2005
|
+
provingKeyPath,
|
|
1959
2006
|
onProgress
|
|
1960
2007
|
} = options;
|
|
1961
2008
|
const poolConfig = POOL_CONFIG[pool];
|
|
@@ -2034,7 +2081,8 @@ async function buildTransferProof(options) {
|
|
|
2034
2081
|
fee: 0,
|
|
2035
2082
|
recipient: "0x0000000000000000000000000000000000000000",
|
|
2036
2083
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
2037
|
-
onProgress
|
|
2084
|
+
onProgress,
|
|
2085
|
+
provingKeyPath
|
|
2038
2086
|
});
|
|
2039
2087
|
return {
|
|
2040
2088
|
proofArgs: {
|
|
@@ -2076,7 +2124,7 @@ async function transfer(options) {
|
|
|
2076
2124
|
};
|
|
2077
2125
|
}
|
|
2078
2126
|
async function mergeUtxos(options) {
|
|
2079
|
-
const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
|
|
2127
|
+
const { amount, keypair, pool = "eth", rpcUrl, provingKeyPath, onProgress } = options;
|
|
2080
2128
|
const poolConfig = POOL_CONFIG[pool];
|
|
2081
2129
|
const poolAddress = getPoolAddress(pool);
|
|
2082
2130
|
onProgress?.("Fetching your UTXOs...");
|
|
@@ -2144,7 +2192,8 @@ async function mergeUtxos(options) {
|
|
|
2144
2192
|
fee: 0,
|
|
2145
2193
|
recipient: "0x0000000000000000000000000000000000000000",
|
|
2146
2194
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
2147
|
-
onProgress
|
|
2195
|
+
onProgress,
|
|
2196
|
+
provingKeyPath
|
|
2148
2197
|
});
|
|
2149
2198
|
onProgress?.("Submitting to relay...");
|
|
2150
2199
|
const relayResult = await submitRelay({
|
|
@@ -2556,6 +2605,7 @@ async function mergeSubaccount(options) {
|
|
|
2556
2605
|
pool = "eth",
|
|
2557
2606
|
rpcUrl,
|
|
2558
2607
|
relayUrl,
|
|
2608
|
+
provingKeyPath,
|
|
2559
2609
|
onProgress
|
|
2560
2610
|
} = options;
|
|
2561
2611
|
const normalizedSlot = normalizeSlot(slot);
|
|
@@ -2648,7 +2698,8 @@ async function mergeSubaccount(options) {
|
|
|
2648
2698
|
fee: 0,
|
|
2649
2699
|
recipient: "0x0000000000000000000000000000000000000000",
|
|
2650
2700
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
2651
|
-
onProgress
|
|
2701
|
+
onProgress,
|
|
2702
|
+
provingKeyPath
|
|
2652
2703
|
});
|
|
2653
2704
|
onProgress?.("Submitting to relay...");
|
|
2654
2705
|
const relayResult = await submitRelay({
|