@veil-cash/sdk 0.6.3 → 0.6.4
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 +145 -115
- package/dist/index.cjs +113 -90
- 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 +90 -48
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/ffjavascript.d.ts +28 -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,15 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
|
+
import { Buffer } from 'buffer';
|
|
2
3
|
import { privateKeyToAccount, privateKeyToAddress } from 'viem/accounts';
|
|
3
|
-
import
|
|
4
|
+
import ethSigUtil from 'eth-sig-util';
|
|
5
|
+
import 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
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
14
|
-
}) : x)(function(x) {
|
|
15
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
16
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
17
|
-
});
|
|
18
|
-
var circomlib = __require("circomlib");
|
|
12
|
+
// src/keypair.ts
|
|
19
13
|
var poseidon = circomlib.poseidon;
|
|
20
14
|
var FIELD_SIZE = BigInt(
|
|
21
15
|
"21888242871839275222246405745257275088548364400416034343698204186575808495617"
|
|
@@ -23,7 +17,11 @@ var FIELD_SIZE = BigInt(
|
|
|
23
17
|
var poseidonHash = (items) => BigInt(poseidon(items).toString());
|
|
24
18
|
var poseidonHash2 = (a, b) => poseidonHash([a, b]);
|
|
25
19
|
var randomBN = (nbytes = 31) => {
|
|
26
|
-
const
|
|
20
|
+
const cryptoApi = globalThis.crypto;
|
|
21
|
+
if (!cryptoApi?.getRandomValues) {
|
|
22
|
+
throw new Error("Secure random number generation is unavailable in this runtime");
|
|
23
|
+
}
|
|
24
|
+
const bytes = cryptoApi.getRandomValues(new Uint8Array(nbytes));
|
|
27
25
|
let hex = "0x";
|
|
28
26
|
for (let i = 0; i < bytes.length; i++) {
|
|
29
27
|
hex += bytes[i].toString(16).padStart(2, "0");
|
|
@@ -50,8 +48,7 @@ var toBuffer = (value, length) => {
|
|
|
50
48
|
return Buffer.from(hex, "hex");
|
|
51
49
|
};
|
|
52
50
|
function getExtDataHash(extData) {
|
|
53
|
-
const
|
|
54
|
-
const abi = ethers2.AbiCoder.defaultAbiCoder();
|
|
51
|
+
const abi = ethers.AbiCoder.defaultAbiCoder();
|
|
55
52
|
const encodedData = abi.encode(
|
|
56
53
|
["tuple(address,int256,address,uint256,bytes,bytes)"],
|
|
57
54
|
[[
|
|
@@ -63,7 +60,7 @@ function getExtDataHash(extData) {
|
|
|
63
60
|
extData.encryptedOutput2
|
|
64
61
|
]]
|
|
65
62
|
);
|
|
66
|
-
const hash =
|
|
63
|
+
const hash = ethers.keccak256(encodedData);
|
|
67
64
|
return BigInt(hash) % FIELD_SIZE;
|
|
68
65
|
}
|
|
69
66
|
function shuffle(array) {
|
|
@@ -79,7 +76,6 @@ function shuffle(array) {
|
|
|
79
76
|
|
|
80
77
|
// src/keypair.ts
|
|
81
78
|
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
79
|
function packEncryptedMessage(encryptedMessage) {
|
|
84
80
|
const nonceBuf = Buffer.from(encryptedMessage.nonce, "base64");
|
|
85
81
|
const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, "base64");
|
|
@@ -262,8 +258,6 @@ var Keypair = class _Keypair {
|
|
|
262
258
|
);
|
|
263
259
|
}
|
|
264
260
|
};
|
|
265
|
-
|
|
266
|
-
// src/utxo.ts
|
|
267
261
|
var Utxo = class _Utxo {
|
|
268
262
|
amount;
|
|
269
263
|
blinding;
|
|
@@ -1456,21 +1450,37 @@ function getMerklePath(tree, commitment) {
|
|
|
1456
1450
|
pathIndices: index
|
|
1457
1451
|
};
|
|
1458
1452
|
}
|
|
1459
|
-
var
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1453
|
+
var ffUtils = utils;
|
|
1454
|
+
function isBrowserRuntime() {
|
|
1455
|
+
return !(typeof process !== "undefined" && !!process.versions?.node);
|
|
1456
|
+
}
|
|
1457
|
+
function stripTrailingSlash(value) {
|
|
1458
|
+
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
1459
|
+
}
|
|
1460
|
+
function normalizeCircuitBasePath(provingKeyPath, circuitName) {
|
|
1461
|
+
const resolvedPath = typeof provingKeyPath === "function" ? provingKeyPath(circuitName) : provingKeyPath;
|
|
1462
|
+
const withoutExtension = resolvedPath.replace(/\.(wasm|zkey)$/i, "");
|
|
1463
|
+
if (withoutExtension.endsWith(`/${circuitName}`) || withoutExtension.endsWith(`\\${circuitName}`)) {
|
|
1464
|
+
return withoutExtension;
|
|
1465
|
+
}
|
|
1466
|
+
return `${stripTrailingSlash(withoutExtension)}/${circuitName}`;
|
|
1467
|
+
}
|
|
1468
|
+
function importNodeModule(specifier) {
|
|
1469
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
1470
|
+
return dynamicImport(specifier);
|
|
1465
1471
|
}
|
|
1466
|
-
function
|
|
1472
|
+
async function findNodeKeysDirectory() {
|
|
1473
|
+
const [{ existsSync }, pathModule, { fileURLToPath }] = await Promise.all([
|
|
1474
|
+
importNodeModule("node:fs"),
|
|
1475
|
+
importNodeModule("node:path"),
|
|
1476
|
+
importNodeModule("node:url")
|
|
1477
|
+
]);
|
|
1478
|
+
const path = pathModule;
|
|
1467
1479
|
const possiblePaths = [
|
|
1468
1480
|
// When running from package (installed via npm)
|
|
1469
|
-
path.resolve(
|
|
1470
|
-
path.resolve(__dirname, "..", "..", "keys"),
|
|
1481
|
+
path.resolve(process.cwd(), "node_modules", "@veil-cash", "sdk", "keys"),
|
|
1471
1482
|
// When running from source
|
|
1472
1483
|
path.resolve(process.cwd(), "keys")
|
|
1473
|
-
// ESM module path
|
|
1474
1484
|
];
|
|
1475
1485
|
try {
|
|
1476
1486
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
@@ -1479,7 +1489,7 @@ function findKeysDirectory() {
|
|
|
1479
1489
|
} catch {
|
|
1480
1490
|
}
|
|
1481
1491
|
for (const p of possiblePaths) {
|
|
1482
|
-
if (
|
|
1492
|
+
if (existsSync(p) && existsSync(path.join(p, "transaction2.wasm"))) {
|
|
1483
1493
|
return p;
|
|
1484
1494
|
}
|
|
1485
1495
|
}
|
|
@@ -1487,26 +1497,48 @@ function findKeysDirectory() {
|
|
|
1487
1497
|
"Circuit keys not found. Expected to find keys/ directory with transaction2.wasm and transaction2.zkey files."
|
|
1488
1498
|
);
|
|
1489
1499
|
}
|
|
1490
|
-
async function
|
|
1491
|
-
if (
|
|
1492
|
-
|
|
1500
|
+
async function resolveProvingKeyPaths(circuitName, provingKeyPath) {
|
|
1501
|
+
if (provingKeyPath) {
|
|
1502
|
+
const circuitBasePath = normalizeCircuitBasePath(provingKeyPath, circuitName);
|
|
1503
|
+
return {
|
|
1504
|
+
wasmPath: `${circuitBasePath}.wasm`,
|
|
1505
|
+
zkeyPath: `${circuitBasePath}.zkey`
|
|
1506
|
+
};
|
|
1493
1507
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1508
|
+
if (isBrowserRuntime()) {
|
|
1509
|
+
return {
|
|
1510
|
+
wasmPath: `/keys/${circuitName}.wasm`,
|
|
1511
|
+
zkeyPath: `/keys/${circuitName}.zkey`
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
const keysDir = await findNodeKeysDirectory();
|
|
1515
|
+
return {
|
|
1516
|
+
wasmPath: `${keysDir}/${circuitName}.wasm`,
|
|
1517
|
+
zkeyPath: `${keysDir}/${circuitName}.zkey`
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
async function assertNodeKeyFilesExist(wasmPath, zkeyPath) {
|
|
1521
|
+
if (isBrowserRuntime() || wasmPath.startsWith("http://") || wasmPath.startsWith("https://")) {
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1524
|
+
const { existsSync } = await importNodeModule("node:fs");
|
|
1525
|
+
if (!existsSync(wasmPath)) {
|
|
1498
1526
|
throw new Error(`Circuit WASM file not found: ${wasmPath}`);
|
|
1499
1527
|
}
|
|
1500
|
-
if (!
|
|
1528
|
+
if (!existsSync(zkeyPath)) {
|
|
1501
1529
|
throw new Error(`Circuit zkey file not found: ${zkeyPath}`);
|
|
1502
1530
|
}
|
|
1531
|
+
}
|
|
1532
|
+
async function prove(input, circuitName, options = {}) {
|
|
1533
|
+
const { wasmPath, zkeyPath } = await resolveProvingKeyPaths(circuitName, options.provingKeyPath);
|
|
1534
|
+
await assertNodeKeyFilesExist(wasmPath, zkeyPath);
|
|
1503
1535
|
const result = await groth16.fullProve(
|
|
1504
|
-
|
|
1536
|
+
ffUtils.stringifyBigInts(input),
|
|
1505
1537
|
wasmPath,
|
|
1506
1538
|
zkeyPath,
|
|
1507
1539
|
void 0,
|
|
1508
1540
|
void 0,
|
|
1509
|
-
{ singleThread: true }
|
|
1541
|
+
{ singleThread: options.singleThread ?? true }
|
|
1510
1542
|
);
|
|
1511
1543
|
const proof = result.proof;
|
|
1512
1544
|
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 +1566,8 @@ async function getProof({
|
|
|
1534
1566
|
fee,
|
|
1535
1567
|
recipient,
|
|
1536
1568
|
relayer,
|
|
1537
|
-
onProgress
|
|
1569
|
+
onProgress,
|
|
1570
|
+
provingKeyPath
|
|
1538
1571
|
}) {
|
|
1539
1572
|
inputs = shuffle([...inputs]);
|
|
1540
1573
|
outputs = shuffle([...outputs]);
|
|
@@ -1594,7 +1627,7 @@ async function getProof({
|
|
|
1594
1627
|
};
|
|
1595
1628
|
onProgress?.("Generating ZK proof...", `${inputs.length} inputs`);
|
|
1596
1629
|
const circuitName = selectCircuit(inputs.length);
|
|
1597
|
-
const proof = await prove(proofInput, circuitName);
|
|
1630
|
+
const proof = await prove(proofInput, circuitName, { provingKeyPath });
|
|
1598
1631
|
const args = {
|
|
1599
1632
|
proof,
|
|
1600
1633
|
root: toFixedHex(proofInput.root),
|
|
@@ -1616,7 +1649,8 @@ async function prepareTransaction({
|
|
|
1616
1649
|
fee = 0,
|
|
1617
1650
|
recipient = 0,
|
|
1618
1651
|
relayer = 0,
|
|
1619
|
-
onProgress
|
|
1652
|
+
onProgress,
|
|
1653
|
+
provingKeyPath
|
|
1620
1654
|
}) {
|
|
1621
1655
|
if (inputs.length > 16 || outputs.length > 2) {
|
|
1622
1656
|
throw new Error("Incorrect inputs/outputs count. Maximum: 16 inputs, 2 outputs.");
|
|
@@ -1638,7 +1672,8 @@ async function prepareTransaction({
|
|
|
1638
1672
|
fee: BigInt(fee),
|
|
1639
1673
|
recipient: String(recipient),
|
|
1640
1674
|
relayer: String(relayer),
|
|
1641
|
-
onProgress
|
|
1675
|
+
onProgress,
|
|
1676
|
+
provingKeyPath
|
|
1642
1677
|
});
|
|
1643
1678
|
return result;
|
|
1644
1679
|
}
|
|
@@ -1796,6 +1831,7 @@ async function buildWithdrawProof(options) {
|
|
|
1796
1831
|
keypair,
|
|
1797
1832
|
pool = "eth",
|
|
1798
1833
|
rpcUrl,
|
|
1834
|
+
provingKeyPath,
|
|
1799
1835
|
onProgress
|
|
1800
1836
|
} = options;
|
|
1801
1837
|
const poolConfig = POOL_CONFIG[pool];
|
|
@@ -1859,7 +1895,8 @@ async function buildWithdrawProof(options) {
|
|
|
1859
1895
|
fee: 0,
|
|
1860
1896
|
recipient,
|
|
1861
1897
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
1862
|
-
onProgress
|
|
1898
|
+
onProgress,
|
|
1899
|
+
provingKeyPath
|
|
1863
1900
|
});
|
|
1864
1901
|
return {
|
|
1865
1902
|
proofArgs: {
|
|
@@ -1956,6 +1993,7 @@ async function buildTransferProof(options) {
|
|
|
1956
1993
|
senderKeypair,
|
|
1957
1994
|
pool = "eth",
|
|
1958
1995
|
rpcUrl,
|
|
1996
|
+
provingKeyPath,
|
|
1959
1997
|
onProgress
|
|
1960
1998
|
} = options;
|
|
1961
1999
|
const poolConfig = POOL_CONFIG[pool];
|
|
@@ -2034,7 +2072,8 @@ async function buildTransferProof(options) {
|
|
|
2034
2072
|
fee: 0,
|
|
2035
2073
|
recipient: "0x0000000000000000000000000000000000000000",
|
|
2036
2074
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
2037
|
-
onProgress
|
|
2075
|
+
onProgress,
|
|
2076
|
+
provingKeyPath
|
|
2038
2077
|
});
|
|
2039
2078
|
return {
|
|
2040
2079
|
proofArgs: {
|
|
@@ -2076,7 +2115,7 @@ async function transfer(options) {
|
|
|
2076
2115
|
};
|
|
2077
2116
|
}
|
|
2078
2117
|
async function mergeUtxos(options) {
|
|
2079
|
-
const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
|
|
2118
|
+
const { amount, keypair, pool = "eth", rpcUrl, provingKeyPath, onProgress } = options;
|
|
2080
2119
|
const poolConfig = POOL_CONFIG[pool];
|
|
2081
2120
|
const poolAddress = getPoolAddress(pool);
|
|
2082
2121
|
onProgress?.("Fetching your UTXOs...");
|
|
@@ -2144,7 +2183,8 @@ async function mergeUtxos(options) {
|
|
|
2144
2183
|
fee: 0,
|
|
2145
2184
|
recipient: "0x0000000000000000000000000000000000000000",
|
|
2146
2185
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
2147
|
-
onProgress
|
|
2186
|
+
onProgress,
|
|
2187
|
+
provingKeyPath
|
|
2148
2188
|
});
|
|
2149
2189
|
onProgress?.("Submitting to relay...");
|
|
2150
2190
|
const relayResult = await submitRelay({
|
|
@@ -2556,6 +2596,7 @@ async function mergeSubaccount(options) {
|
|
|
2556
2596
|
pool = "eth",
|
|
2557
2597
|
rpcUrl,
|
|
2558
2598
|
relayUrl,
|
|
2599
|
+
provingKeyPath,
|
|
2559
2600
|
onProgress
|
|
2560
2601
|
} = options;
|
|
2561
2602
|
const normalizedSlot = normalizeSlot(slot);
|
|
@@ -2648,7 +2689,8 @@ async function mergeSubaccount(options) {
|
|
|
2648
2689
|
fee: 0,
|
|
2649
2690
|
recipient: "0x0000000000000000000000000000000000000000",
|
|
2650
2691
|
relayer: "0x0000000000000000000000000000000000000000",
|
|
2651
|
-
onProgress
|
|
2692
|
+
onProgress,
|
|
2693
|
+
provingKeyPath
|
|
2652
2694
|
});
|
|
2653
2695
|
onProgress?.("Submitting to relay...");
|
|
2654
2696
|
const relayResult = await submitRelay({
|