testprivacycash-evm 1.2.0

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.
Files changed (52) hide show
  1. package/.github/workflows/npm-publish.yml +55 -0
  2. package/README.md +17 -0
  3. package/circuits/transaction2.wasm +0 -0
  4. package/circuits/transaction2.zkey +0 -0
  5. package/dist/balance.d.ts +10 -0
  6. package/dist/balance.js +57 -0
  7. package/dist/deposit.d.ts +10 -0
  8. package/dist/deposit.js +345 -0
  9. package/dist/index.d.ts +10 -0
  10. package/dist/index.js +8 -0
  11. package/dist/utils/ERCPool.abi.json +929 -0
  12. package/dist/utils/EtherPool.abi.json +798 -0
  13. package/dist/utils/constants.d.ts +8 -0
  14. package/dist/utils/constants.js +11 -0
  15. package/dist/utils/db.d.ts +17 -0
  16. package/dist/utils/db.js +276 -0
  17. package/dist/utils/encryption.d.ts +8 -0
  18. package/dist/utils/encryption.js +34 -0
  19. package/dist/utils/keypair.d.ts +9 -0
  20. package/dist/utils/keypair.js +19 -0
  21. package/dist/utils/logger.d.ts +9 -0
  22. package/dist/utils/logger.js +35 -0
  23. package/dist/utils/networkConfig.d.ts +54 -0
  24. package/dist/utils/networkConfig.js +126 -0
  25. package/dist/utils/prover.d.ts +15 -0
  26. package/dist/utils/prover.js +30 -0
  27. package/dist/utils/remoteConfig.d.ts +21 -0
  28. package/dist/utils/remoteConfig.js +24 -0
  29. package/dist/utils/utils.d.ts +83 -0
  30. package/dist/utils/utils.js +275 -0
  31. package/dist/utils/utxo.d.ts +20 -0
  32. package/dist/utils/utxo.js +55 -0
  33. package/dist/withdraw.d.ts +12 -0
  34. package/dist/withdraw.js +253 -0
  35. package/package.json +37 -0
  36. package/src/balance.ts +74 -0
  37. package/src/deposit.ts +406 -0
  38. package/src/index.ts +16 -0
  39. package/src/utils/ERCPool.abi.json +929 -0
  40. package/src/utils/EtherPool.abi.json +798 -0
  41. package/src/utils/constants.ts +15 -0
  42. package/src/utils/db.ts +311 -0
  43. package/src/utils/encryption.ts +40 -0
  44. package/src/utils/keypair.ts +24 -0
  45. package/src/utils/logger.ts +42 -0
  46. package/src/utils/networkConfig.ts +169 -0
  47. package/src/utils/prover.ts +39 -0
  48. package/src/utils/remoteConfig.ts +49 -0
  49. package/src/utils/utils.ts +387 -0
  50. package/src/utils/utxo.ts +74 -0
  51. package/src/withdraw.ts +351 -0
  52. package/tsconfig.json +29 -0
@@ -0,0 +1,8 @@
1
+ export declare const CONTRACT_ADDRESS: string;
2
+ export declare const FEE_RECIPIENT_ADDRESS: string;
3
+ export declare const INDEXER_URL: string;
4
+ export declare const BASE_SEPOLIA_RPC: string;
5
+ export declare const SIGN_PRIVACY_MESSAGE = "Privacy Money account sign in";
6
+ export declare const PRIVATE_USDC_CONTRACT_ADDRESS: string;
7
+ export declare const USDC_CONTRACT_ADDRESS: string;
8
+ export declare const USDC_DECIMALS = 6;
@@ -0,0 +1,11 @@
1
+ import { BASE_NETWORK } from './networkConfig.js';
2
+ // Backward-compatible re-exports — all resolve to the Base network.
3
+ // For multi-chain support, pass a `network` (NetworkConfig | chainId) to SDK functions.
4
+ export const CONTRACT_ADDRESS = BASE_NETWORK.etherPoolAddress;
5
+ export const FEE_RECIPIENT_ADDRESS = BASE_NETWORK.feeRecipientAddress;
6
+ export const INDEXER_URL = BASE_NETWORK.indexerUrl;
7
+ export const BASE_SEPOLIA_RPC = BASE_NETWORK.rpcUrl;
8
+ export const SIGN_PRIVACY_MESSAGE = 'Privacy Money account sign in';
9
+ export const PRIVATE_USDC_CONTRACT_ADDRESS = BASE_NETWORK.usdcPoolAddress;
10
+ export const USDC_CONTRACT_ADDRESS = BASE_NETWORK.usdcTokenAddress;
11
+ export const USDC_DECIMALS = 6;
@@ -0,0 +1,17 @@
1
+ export interface StorageAdapter {
2
+ setup(): Promise<void>;
3
+ set(key: string, value: any): Promise<void>;
4
+ get(key: string): Promise<any | null>;
5
+ getAll(): Promise<any[]>;
6
+ }
7
+ export declare class UniversalStorage {
8
+ private dbName;
9
+ private storeName;
10
+ private adapter;
11
+ constructor(dbName: string, storeName: string);
12
+ init(): Promise<UniversalStorage>;
13
+ private createServerAdapter;
14
+ set(key: string, value: any): Promise<void>;
15
+ get<T = any>(key: string): Promise<T | null>;
16
+ getAll<T = any>(): Promise<T[]>;
17
+ }
@@ -0,0 +1,276 @@
1
+ const isBrowser = typeof window !== 'undefined' && typeof indexedDB !== 'undefined';
2
+ const isNodeRuntime = typeof process !== 'undefined' &&
3
+ typeof process.versions !== 'undefined' &&
4
+ !!process.versions.node;
5
+ const isBunRuntime = typeof process !== 'undefined' &&
6
+ typeof process.versions !== 'undefined' &&
7
+ !!process.versions.bun;
8
+ const isDenoRuntime = typeof globalThis.Deno !== 'undefined';
9
+ export class UniversalStorage {
10
+ dbName;
11
+ storeName;
12
+ adapter;
13
+ constructor(dbName, storeName) {
14
+ this.dbName = dbName;
15
+ this.storeName = storeName;
16
+ }
17
+ async init() {
18
+ if (isBrowser) {
19
+ this.adapter = new BrowserIDBAdapter(this.dbName, this.storeName);
20
+ await this.adapter.setup();
21
+ }
22
+ else {
23
+ this.adapter = await this.createServerAdapter();
24
+ }
25
+ return this;
26
+ }
27
+ async createServerAdapter() {
28
+ // Prefer sqlite on Node.js when available because it is durable and scalable.
29
+ if (isNodeRuntime) {
30
+ const sqliteAdapter = new NodeSQLiteAdapter(this.dbName);
31
+ try {
32
+ await sqliteAdapter.setup();
33
+ return sqliteAdapter;
34
+ }
35
+ catch (error) {
36
+ if (!isSqliteUnavailableError(error)) {
37
+ throw error;
38
+ }
39
+ }
40
+ }
41
+ // Bun/Deno/other runtimes can still persist using a JSON file.
42
+ const fileAdapter = new ServerFileAdapter(this.dbName, this.storeName);
43
+ try {
44
+ await fileAdapter.setup();
45
+ return fileAdapter;
46
+ }
47
+ catch {
48
+ // Last resort for restricted server runtimes (e.g. no filesystem access).
49
+ const memoryAdapter = new ServerMemoryAdapter();
50
+ await memoryAdapter.setup();
51
+ return memoryAdapter;
52
+ }
53
+ }
54
+ async set(key, value) {
55
+ return await this.adapter.set(key, value);
56
+ }
57
+ async get(key) {
58
+ return await this.adapter.get(key);
59
+ }
60
+ async getAll() {
61
+ return await this.adapter.getAll();
62
+ }
63
+ }
64
+ class BrowserIDBAdapter {
65
+ dbName;
66
+ storeName;
67
+ db = null;
68
+ constructor(dbName, storeName) {
69
+ this.dbName = dbName;
70
+ this.storeName = storeName;
71
+ }
72
+ setup() {
73
+ return new Promise((resolve, reject) => {
74
+ const request = indexedDB.open(this.dbName, 3);
75
+ request.onupgradeneeded = (e) => {
76
+ const db = e.target.result;
77
+ if (!db.objectStoreNames.contains(this.storeName)) {
78
+ db.createObjectStore(this.storeName);
79
+ }
80
+ };
81
+ request.onsuccess = (e) => {
82
+ this.db = e.target.result;
83
+ resolve();
84
+ };
85
+ request.onerror = () => reject(new Error("IndexedDB initialization failed"));
86
+ });
87
+ }
88
+ async set(key, value) {
89
+ if (!this.db)
90
+ throw new Error("Database not initialized");
91
+ const tx = this.db.transaction(this.storeName, 'readwrite');
92
+ const store = tx.objectStore(this.storeName);
93
+ return new Promise((res, rej) => {
94
+ const req = store.put(value, key);
95
+ tx.oncomplete = () => res();
96
+ tx.onerror = () => rej(tx.error);
97
+ });
98
+ }
99
+ async get(key) {
100
+ if (!this.db)
101
+ throw new Error("Database not initialized");
102
+ const tx = this.db.transaction(this.storeName, 'readonly');
103
+ const store = tx.objectStore(this.storeName);
104
+ return new Promise((res) => {
105
+ const req = store.get(key);
106
+ req.onsuccess = () => res(req.result || null);
107
+ });
108
+ }
109
+ async getAll() {
110
+ if (!this.db)
111
+ throw new Error("Database not initialized");
112
+ const tx = this.db.transaction(this.storeName, 'readonly');
113
+ const store = tx.objectStore(this.storeName);
114
+ return new Promise((res) => {
115
+ const req = store.getAll();
116
+ req.onsuccess = () => res(req.result || []);
117
+ });
118
+ }
119
+ }
120
+ class NodeSQLiteAdapter {
121
+ db;
122
+ fileName;
123
+ constructor(dbName) {
124
+ this.fileName = `./cache/${dbName}.db`;
125
+ }
126
+ async setup() {
127
+ const sqlite3 = loadNodeSqlite();
128
+ const { Database } = sqlite3;
129
+ this.db = new Database(this.fileName);
130
+ await this.run('CREATE TABLE IF NOT EXISTS storage (key TEXT PRIMARY KEY, value TEXT)');
131
+ }
132
+ run(sql, ...params) {
133
+ return new Promise((resolve, reject) => {
134
+ this.db.run(sql, params, (err) => {
135
+ if (err)
136
+ reject(err);
137
+ else
138
+ resolve();
139
+ });
140
+ });
141
+ }
142
+ queryGet(sql, ...params) {
143
+ return new Promise((resolve, reject) => {
144
+ this.db.get(sql, params, (err, row) => {
145
+ if (err)
146
+ reject(err);
147
+ else
148
+ resolve(row);
149
+ });
150
+ });
151
+ }
152
+ queryAll(sql, ...params) {
153
+ return new Promise((resolve, reject) => {
154
+ this.db.all(sql, params, (err, rows) => {
155
+ if (err)
156
+ reject(err);
157
+ else
158
+ resolve(rows);
159
+ });
160
+ });
161
+ }
162
+ async set(key, value) {
163
+ await this.run('INSERT OR REPLACE INTO storage (key, value) VALUES (?, ?)', key, JSON.stringify(value));
164
+ }
165
+ async get(key) {
166
+ const row = await this.queryGet('SELECT value FROM storage WHERE key = ?', key);
167
+ return row ? JSON.parse(row.value) : null;
168
+ }
169
+ async getAll() {
170
+ const rows = await this.queryAll('SELECT value FROM storage');
171
+ return rows.map((row) => JSON.parse(row.value));
172
+ }
173
+ }
174
+ function loadNodeSqlite() {
175
+ // Use indirect eval so bundlers don't try to include sqlite3 in browser builds.
176
+ const nodeRequire = (0, eval)('typeof require !== "undefined" ? require : undefined');
177
+ if (!nodeRequire) {
178
+ const error = new Error('sqlite3 is only available when Node.js require is present');
179
+ error.code = 'SQLITE_UNAVAILABLE';
180
+ throw error;
181
+ }
182
+ try {
183
+ return nodeRequire('sqlite3');
184
+ }
185
+ catch (error) {
186
+ if (error && /Cannot find module 'sqlite3'|Cannot find module \"sqlite3\"/i.test(String(error.message))) {
187
+ error.code = 'SQLITE_UNAVAILABLE';
188
+ }
189
+ throw error;
190
+ }
191
+ }
192
+ function isSqliteUnavailableError(error) {
193
+ return error?.code === 'SQLITE_UNAVAILABLE';
194
+ }
195
+ class ServerFileAdapter {
196
+ fileName;
197
+ data = {};
198
+ constructor(dbName, storeName) {
199
+ this.fileName = `./cache/${dbName}.${storeName}.json`;
200
+ }
201
+ async setup() {
202
+ await ensureCacheDir();
203
+ const raw = await readFileSafe(this.fileName);
204
+ this.data = raw ? JSON.parse(raw) : {};
205
+ }
206
+ async set(key, value) {
207
+ this.data[key] = value;
208
+ await writeFileSafe(this.fileName, JSON.stringify(this.data));
209
+ }
210
+ async get(key) {
211
+ return key in this.data ? this.data[key] : null;
212
+ }
213
+ async getAll() {
214
+ return Object.values(this.data);
215
+ }
216
+ }
217
+ class ServerMemoryAdapter {
218
+ data = new Map();
219
+ async setup() {
220
+ return;
221
+ }
222
+ async set(key, value) {
223
+ this.data.set(key, value);
224
+ }
225
+ async get(key) {
226
+ return this.data.has(key) ? this.data.get(key) : null;
227
+ }
228
+ async getAll() {
229
+ return Array.from(this.data.values());
230
+ }
231
+ }
232
+ async function ensureCacheDir() {
233
+ if (isDenoRuntime) {
234
+ await globalThis.Deno.mkdir('./cache', { recursive: true });
235
+ return;
236
+ }
237
+ if (isNodeRuntime || isBunRuntime) {
238
+ const fs = await import('node:fs/promises');
239
+ await fs.mkdir('./cache', { recursive: true });
240
+ return;
241
+ }
242
+ throw new Error('Filesystem storage is not available in this runtime');
243
+ }
244
+ async function readFileSafe(path) {
245
+ try {
246
+ if (isDenoRuntime) {
247
+ return await globalThis.Deno.readTextFile(path);
248
+ }
249
+ if (isNodeRuntime || isBunRuntime) {
250
+ const fs = await import('node:fs/promises');
251
+ return await fs.readFile(path, 'utf8');
252
+ }
253
+ }
254
+ catch (error) {
255
+ if (isMissingFileError(error)) {
256
+ return null;
257
+ }
258
+ throw error;
259
+ }
260
+ throw new Error('Filesystem storage is not available in this runtime');
261
+ }
262
+ async function writeFileSafe(path, content) {
263
+ if (isDenoRuntime) {
264
+ await globalThis.Deno.writeTextFile(path, content);
265
+ return;
266
+ }
267
+ if (isNodeRuntime || isBunRuntime) {
268
+ const fs = await import('node:fs/promises');
269
+ await fs.writeFile(path, content, 'utf8');
270
+ return;
271
+ }
272
+ throw new Error('Filesystem storage is not available in this runtime');
273
+ }
274
+ function isMissingFileError(error) {
275
+ return error?.code === 'ENOENT' || error?.name === 'NotFound';
276
+ }
@@ -0,0 +1,8 @@
1
+ import { Keypair } from './keypair.js';
2
+ export declare function deriveKeys(signature: string): {
3
+ encryptionKey: Buffer<ArrayBuffer>;
4
+ utxoPrivateKey: string;
5
+ keypair: Keypair;
6
+ };
7
+ export declare function encrypt(data: string | Buffer, encryptionKey: Buffer): string;
8
+ export declare function decrypt(encryptedData: string | Buffer, encryptionKey: Buffer): Buffer;
@@ -0,0 +1,34 @@
1
+ import crypto from 'crypto';
2
+ import { ethers } from 'ethers';
3
+ import { Keypair } from './keypair.js';
4
+ export function deriveKeys(signature) {
5
+ const encryptionKeyHex = ethers.utils.keccak256(signature);
6
+ const encryptionKey = Buffer.from(encryptionKeyHex.slice(2), 'hex');
7
+ const utxoPrivateKey = ethers.utils.keccak256(encryptionKey);
8
+ const keypair = new Keypair(utxoPrivateKey);
9
+ return { encryptionKey, utxoPrivateKey, keypair };
10
+ }
11
+ // export async function signMessage(signer: ethers.Signer) {
12
+ // const signature = await signer.signMessage(SIGN_IN_MESSAGe);
13
+ // return deriveKeys(signature);
14
+ // }
15
+ export function encrypt(data, encryptionKey) {
16
+ const dataBuffer = typeof data === 'string' ? Buffer.from(data) : data;
17
+ const iv = crypto.randomBytes(12);
18
+ const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, iv);
19
+ const encrypted = Buffer.concat([cipher.update(dataBuffer), cipher.final()]);
20
+ const authTag = cipher.getAuthTag();
21
+ const result = Buffer.concat([iv, authTag, encrypted]);
22
+ return '0x' + result.toString('hex');
23
+ }
24
+ export function decrypt(encryptedData, encryptionKey) {
25
+ const buf = typeof encryptedData === 'string'
26
+ ? Buffer.from(encryptedData.replace(/^0x/, ''), 'hex')
27
+ : encryptedData;
28
+ const iv = buf.slice(0, 12);
29
+ const authTag = buf.slice(12, 28);
30
+ const data = buf.slice(28);
31
+ const decipher = crypto.createDecipheriv('aes-256-gcm', encryptionKey, iv);
32
+ decipher.setAuthTag(authTag);
33
+ return Buffer.concat([decipher.update(data), decipher.final()]);
34
+ }
@@ -0,0 +1,9 @@
1
+ import { BigNumber } from 'ethers';
2
+ export declare class Keypair {
3
+ privkey: string;
4
+ pubkey: BigNumber;
5
+ constructor(privkey?: string);
6
+ toString(): string;
7
+ address(): string;
8
+ sign(commitment: any, merklePath: any): BigNumber;
9
+ }
@@ -0,0 +1,19 @@
1
+ import { ethers } from 'ethers';
2
+ import { poseidonHash, toFixedHex } from './utils.js';
3
+ export class Keypair {
4
+ privkey;
5
+ pubkey;
6
+ constructor(privkey = ethers.Wallet.createRandom().privateKey) {
7
+ this.privkey = privkey;
8
+ this.pubkey = poseidonHash([this.privkey]);
9
+ }
10
+ toString() {
11
+ return toFixedHex(this.pubkey);
12
+ }
13
+ address() {
14
+ return this.toString();
15
+ }
16
+ sign(commitment, merklePath) {
17
+ return poseidonHash([this.privkey, commitment, merklePath]);
18
+ }
19
+ }
@@ -0,0 +1,9 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ export type LoggerFn = (level: LogLevel, message: string) => void;
3
+ export declare function setLogger(logger: LoggerFn): void;
4
+ export declare const logger: {
5
+ debug: (...args: unknown[]) => void;
6
+ info: (...args: unknown[]) => void;
7
+ warn: (...args: unknown[]) => void;
8
+ error: (...args: unknown[]) => void;
9
+ };
@@ -0,0 +1,35 @@
1
+ const defaultLogger = (level, message) => {
2
+ const prefix = `[${level.toUpperCase()}]`;
3
+ console.log(prefix, message);
4
+ };
5
+ let userLogger = defaultLogger;
6
+ export function setLogger(logger) {
7
+ userLogger = logger;
8
+ }
9
+ function argToStr(args) {
10
+ return args.map(arg => {
11
+ if (typeof arg === "object" && arg !== null) {
12
+ try {
13
+ return JSON.stringify(arg);
14
+ }
15
+ catch {
16
+ return String(arg);
17
+ }
18
+ }
19
+ return String(arg);
20
+ }).join(" ");
21
+ }
22
+ export const logger = {
23
+ debug: (...args) => {
24
+ userLogger('debug', argToStr(args));
25
+ },
26
+ info: (...args) => {
27
+ userLogger('info', argToStr(args));
28
+ },
29
+ warn: (...args) => {
30
+ userLogger('warn', argToStr(args));
31
+ },
32
+ error: (...args) => {
33
+ userLogger('error', argToStr(args));
34
+ },
35
+ };
@@ -0,0 +1,54 @@
1
+ export type Erc20Token = 'usdc' | 'usdt';
2
+ export type NativeToken = 'eth' | 'bnb';
3
+ export type PrivacyToken = NativeToken | Erc20Token;
4
+ export type SupportedChain = 'base' | 'eth' | 'bnb';
5
+ export interface NetworkConfig {
6
+ chainId: number;
7
+ /** Short identifier used in API calls and DB table prefixes. */
8
+ chainKey: SupportedChain;
9
+ rpcUrl: string;
10
+ indexerUrl: string;
11
+ etherPoolAddress: string;
12
+ usdcPoolAddress: string;
13
+ usdcTokenAddress: string;
14
+ usdcDecimals: number;
15
+ usdtPoolAddress: string;
16
+ usdtTokenAddress: string;
17
+ usdtDecimals: number;
18
+ feeRecipientAddress: string;
19
+ /** Namespace prefix for local UTXO cache files. Base keeps legacy names. */
20
+ cachePrefix: string;
21
+ /** Average block time in ms — used to scale confirmation polling timeouts. */
22
+ blockTimeMs: number;
23
+ /** Native token used by this chain. */
24
+ nativeToken?: NativeToken;
25
+ /** Human-readable native token symbol used in logs and errors. */
26
+ nativeSymbol?: 'ETH' | 'BNB';
27
+ /** Optional block explorer base URL. */
28
+ blockExplorerUrl?: string;
29
+ }
30
+ export declare const BASE_NETWORK: NetworkConfig;
31
+ export declare const ETH_NETWORK: NetworkConfig;
32
+ export declare const BNB_NETWORK: NetworkConfig;
33
+ export declare const NETWORKS: Record<number, NetworkConfig>;
34
+ export declare function getNetworkConfig(chainId: number): NetworkConfig;
35
+ /** Returns the default network driven by NEXT_PUBLIC_CHAIN_ID env var, falling back to Base. */
36
+ export declare function getDefaultNetworkConfig(): NetworkConfig;
37
+ /** Resolve a NetworkConfig from an object, a chain ID number, or the env-driven default. */
38
+ export declare function resolveNetwork(network?: NetworkConfig | number): NetworkConfig;
39
+ /** Resolve an omitted token to the selected chain's native token and reject cross-chain native symbols. */
40
+ export declare function resolvePrivacyToken(net: NetworkConfig, token?: PrivacyToken): PrivacyToken;
41
+ export declare function isNativeToken(net: NetworkConfig, token: PrivacyToken): boolean;
42
+ export declare function getErc20TokenConfig(net: NetworkConfig, token: PrivacyToken): {
43
+ token: "usdc";
44
+ symbol: "USDC";
45
+ poolAddress: string;
46
+ tokenAddress: string;
47
+ decimals: number;
48
+ } | {
49
+ token: "usdt";
50
+ symbol: "USDT";
51
+ poolAddress: string;
52
+ tokenAddress: string;
53
+ decimals: number;
54
+ } | null;
@@ -0,0 +1,126 @@
1
+ const EVM_INDEXER_URL = process.env.NEXT_PUBLIC_EVM_INDEXER_URL || process.env.EVM_INDEXER_URL || 'https://evm.privacycash.org';
2
+ function getIndexerRpcUrl(chain) {
3
+ return `${EVM_INDEXER_URL.replace(/\/$/, '')}/rpc/${chain}`;
4
+ }
5
+ export const BASE_NETWORK = {
6
+ chainId: 8453,
7
+ chainKey: 'base',
8
+ rpcUrl: process.env.NEXT_PUBLIC_BASE_RPC || process.env.BASE_RPC || getIndexerRpcUrl('base'),
9
+ indexerUrl: EVM_INDEXER_URL,
10
+ etherPoolAddress: '0x7F673790C08Ddf27c0Aa6fa9526CCC8dAaB081Ec',
11
+ usdcPoolAddress: '0xe91dd4AB03909f5CEb87f42B4308B222995a905b',
12
+ usdcTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
13
+ usdcDecimals: 6,
14
+ usdtPoolAddress: '',
15
+ usdtTokenAddress: '',
16
+ usdtDecimals: 6,
17
+ feeRecipientAddress: '0x8D772A68f2327409a7bb3F96f549297AEdf9312B',
18
+ cachePrefix: 'base',
19
+ blockTimeMs: 2000,
20
+ nativeToken: 'eth',
21
+ nativeSymbol: 'ETH',
22
+ };
23
+ export const ETH_NETWORK = {
24
+ chainId: 1,
25
+ chainKey: 'eth',
26
+ rpcUrl: process.env.NEXT_PUBLIC_ETH_RPC || process.env.ETH_RPC || getIndexerRpcUrl('eth'),
27
+ indexerUrl: EVM_INDEXER_URL,
28
+ etherPoolAddress: process.env.NEXT_PUBLIC_ETH_ETHER_POOL_ADDRESS || '0x77A10AE3E513c2D73D73eb52212c6918C8830dd0',
29
+ usdcPoolAddress: '',
30
+ usdcTokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
31
+ usdcDecimals: 6,
32
+ usdtPoolAddress: process.env.NEXT_PUBLIC_ETH_USDT_POOL_ADDRESS || '0xC88F4dF2B6EdDd6B6Bdf95A0177f50C90Fa7527f',
33
+ usdtTokenAddress: process.env.NEXT_PUBLIC_ETH_USDT_TOKEN_ADDRESS || '0xdAC17F958D2ee523a2206206994597C13D831ec7',
34
+ usdtDecimals: 6,
35
+ feeRecipientAddress: process.env.NEXT_PUBLIC_ETH_FEE_RECIPIENT_ADDRESS || '0x8D772A68f2327409a7bb3F96f549297AEdf9312B',
36
+ cachePrefix: 'eth',
37
+ blockTimeMs: 12000,
38
+ nativeToken: 'eth',
39
+ nativeSymbol: 'ETH',
40
+ };
41
+ const BNB_ALCHEMY_RPC = process.env.ALCHEMY_KEY
42
+ ? `https://bnb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`
43
+ : getIndexerRpcUrl('bnb');
44
+ export const BNB_NETWORK = {
45
+ chainId: 56,
46
+ chainKey: 'bnb',
47
+ rpcUrl: process.env.NEXT_PUBLIC_BNB_RPC || process.env.BNB_RPC || BNB_ALCHEMY_RPC,
48
+ indexerUrl: EVM_INDEXER_URL,
49
+ etherPoolAddress: '0x22D8509E7AF58b1EaFB311f8F76E81dC3a391F77',
50
+ usdcPoolAddress: '',
51
+ usdcTokenAddress: '',
52
+ usdcDecimals: 6,
53
+ usdtPoolAddress: '',
54
+ usdtTokenAddress: '',
55
+ usdtDecimals: 18,
56
+ feeRecipientAddress: '0x8D772A68f2327409a7bb3F96f549297AEdf9312B',
57
+ cachePrefix: 'bnb',
58
+ blockTimeMs: 1000,
59
+ nativeToken: 'bnb',
60
+ nativeSymbol: 'BNB',
61
+ blockExplorerUrl: 'https://bscscan.com/',
62
+ };
63
+ export const NETWORKS = {
64
+ 8453: BASE_NETWORK,
65
+ 1: ETH_NETWORK,
66
+ 56: BNB_NETWORK,
67
+ };
68
+ export function getNetworkConfig(chainId) {
69
+ const config = NETWORKS[chainId];
70
+ if (!config) {
71
+ throw new Error(`Unsupported chain ID: ${chainId}. Supported: ${Object.keys(NETWORKS).join(', ')}`);
72
+ }
73
+ return config;
74
+ }
75
+ /** Returns the default network driven by NEXT_PUBLIC_CHAIN_ID env var, falling back to Base. */
76
+ export function getDefaultNetworkConfig() {
77
+ const chainId = Number(process.env.NEXT_PUBLIC_CHAIN_ID) || 8453;
78
+ return getNetworkConfig(chainId);
79
+ }
80
+ /** Resolve a NetworkConfig from an object, a chain ID number, or the env-driven default. */
81
+ export function resolveNetwork(network) {
82
+ if (network === undefined || network === null)
83
+ return getDefaultNetworkConfig();
84
+ if (typeof network === 'number')
85
+ return getNetworkConfig(network);
86
+ return network;
87
+ }
88
+ /** Resolve an omitted token to the selected chain's native token and reject cross-chain native symbols. */
89
+ export function resolvePrivacyToken(net, token) {
90
+ const nativeToken = net.nativeToken ?? (net.chainKey === 'bnb' ? 'bnb' : 'eth');
91
+ const resolved = token ?? nativeToken;
92
+ if ((resolved === 'eth' || resolved === 'bnb') && resolved !== nativeToken) {
93
+ throw new Error(`${resolved.toUpperCase()} is not supported on ${net.chainKey}`);
94
+ }
95
+ return resolved;
96
+ }
97
+ export function isNativeToken(net, token) {
98
+ const nativeToken = net.nativeToken ?? (net.chainKey === 'bnb' ? 'bnb' : 'eth');
99
+ return token === nativeToken;
100
+ }
101
+ export function getErc20TokenConfig(net, token) {
102
+ if (isNativeToken(net, token))
103
+ return null;
104
+ if (token === 'eth' || token === 'bnb') {
105
+ throw new Error(`${token.toUpperCase()} is not supported on ${net.chainKey}`);
106
+ }
107
+ const config = token === 'usdc'
108
+ ? {
109
+ token,
110
+ symbol: 'USDC',
111
+ poolAddress: net.usdcPoolAddress,
112
+ tokenAddress: net.usdcTokenAddress,
113
+ decimals: net.usdcDecimals,
114
+ }
115
+ : {
116
+ token,
117
+ symbol: 'USDT',
118
+ poolAddress: net.usdtPoolAddress,
119
+ tokenAddress: net.usdtTokenAddress,
120
+ decimals: net.usdtDecimals,
121
+ };
122
+ if (!config.poolAddress || !config.tokenAddress) {
123
+ throw new Error(`${token.toUpperCase()} is not supported on ${net.chainKey}`);
124
+ }
125
+ return config;
126
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Generates a Zero-Knowledge proof for a transaction.
3
+ * Works across Node.js, Bun, Deno, and Browser — fully in-memory, no tmp files.
4
+ *
5
+ * Bun/Deno use single-threaded mode: passing { singleThread: true } to both
6
+ * wtnsCalcOptions (5th arg) and proverOptions (6th arg) of groth16.fullProve
7
+ * prevents snarkjs from spawning web-worker threads entirely, avoiding the
8
+ * Bun v1.3.x crash where worker threads dispatch plain Error objects to
9
+ * EventTarget.dispatchEvent (which requires a proper Event instance in Bun).
10
+ */
11
+ export declare function prove(input: any, keyBasePath: string): Promise<{
12
+ pA: string[];
13
+ pB: string[][];
14
+ pC: string[];
15
+ }>;
@@ -0,0 +1,30 @@
1
+ // @ts-ignore
2
+ import { utils } from 'ffjavascript';
3
+ import { toFixedHex } from './utils.js';
4
+ /**
5
+ * Generates a Zero-Knowledge proof for a transaction.
6
+ * Works across Node.js, Bun, Deno, and Browser — fully in-memory, no tmp files.
7
+ *
8
+ * Bun/Deno use single-threaded mode: passing { singleThread: true } to both
9
+ * wtnsCalcOptions (5th arg) and proverOptions (6th arg) of groth16.fullProve
10
+ * prevents snarkjs from spawning web-worker threads entirely, avoiding the
11
+ * Bun v1.3.x crash where worker threads dispatch plain Error objects to
12
+ * EventTarget.dispatchEvent (which requires a proper Event instance in Bun).
13
+ */
14
+ export async function prove(input, keyBasePath) {
15
+ // @ts-ignore
16
+ const useSingleThread = typeof Bun !== 'undefined' || typeof Deno !== 'undefined';
17
+ const singleThreadOpts = useSingleThread ? { singleThread: true } : undefined;
18
+ // @ts-ignore
19
+ const snarkjs = await import('snarkjs');
20
+ const { proof } = await snarkjs.groth16.fullProve(utils.stringifyBigInts(input), `${keyBasePath}.wasm`, `${keyBasePath}.zkey`, undefined, // logger
21
+ singleThreadOpts, // wtnsCalcOptions: controls witness calculation threading
22
+ singleThreadOpts);
23
+ const pA = [toFixedHex(proof.pi_a[0]), toFixedHex(proof.pi_a[1])];
24
+ const pB = [
25
+ [toFixedHex(proof.pi_b[0][1]), toFixedHex(proof.pi_b[0][0])],
26
+ [toFixedHex(proof.pi_b[1][1]), toFixedHex(proof.pi_b[1][0])],
27
+ ];
28
+ const pC = [toFixedHex(proof.pi_c[0]), toFixedHex(proof.pi_c[1])];
29
+ return { pA, pB, pC };
30
+ }