Compare commits

..

2 Commits

Author SHA1 Message Date
d688f8a2b5
Update Dockerfile 2025-01-21 17:34:31 +00:00
0aa9f00383
Remove cross-fetch deps 2025-01-21 17:34:04 +00:00
29 changed files with 1239 additions and 2222 deletions

@ -7,7 +7,7 @@ RUN apt update && apt install --yes --no-install-recommends wget git apt-transpo
ENV GIT_REPOSITORY=https://github.com/tornadocontrib/tornado-scripts.git
# From main branch, double check with git.tornado.ws and codeberg.org
ENV GIT_COMMIT_HASH=5bfef2a2ae887b4cc065af34b6ea106fc3cacde1
ENV GIT_COMMIT_HASH=0aa9f0038354412e01b171df7dcff96b1c55976c
# clone the repository
RUN mkdir /app/

12
dist/hashes.json vendored

@ -1,11 +1,11 @@
{
"dist/index.js": "sha384-DMBnRJIMRwGIEYdgWy5NptEFmOmmB4DrUWvVNf60ZUMHDWnuHdogrjx1dkCSOWtN",
"dist/index.mjs": "sha384-3zq911CcPyyFDXeBw8eByPFafkAn/CA5zHaBTQnpU7wIXczHIYYMBvb9GN3ugnd/",
"dist/index.js": "sha384-iQ5shLTi2Nyi35ciUUQRXg2JSgjBguTRXafhYVZuuAyJug9BAXZIWYEwupPOUcCo",
"dist/index.mjs": "sha384-Lx8Qc+R6ak1AaPmSKJ06+EYyFuVF8gI7E+IvBFItO+3Yoc+JmsunEmytkd7mhSQt",
"dist/merkleTreeWorker.js": "sha384-gib4Z6KDvYxUpNTSc4YA2dX5FxaQe2FiorGkBJJDfm86tXdT+57T2Gt+ti6YXTeX",
"dist/merkleTreeWorker.umd.js": "sha384-R1mZHDfLUv9Y/WqKUvzOZY+2plbO/Bp51yBEjC/gR1i6s6/Bs2bvL8fUgayQj9tv",
"dist/merkleTreeWorker.umd.min.js": "sha384-Q+7eHKKDxI6F+EIEM2X0y3WYI8Y/UzQsB7iGjwEVTaqhN1B8cAk7faigdcMA9eZ5",
"dist/tornado.umd.js": "sha384-DlHTTaIvJDp54vY8Hsd7ACW3GYNpblowCkFERkIC75aWQp2g16pMwSWoJvkxG5nm",
"dist/tornado.umd.min.js": "sha384-SLYHCT9/tmX2h3G6DqPnEqaOrzH1ES+vQ1ge0WYaW6V3Zwd9Bcn6ihkqntxJRuqO",
"dist/merkleTreeWorker.umd.js": "sha384-yHNYOc2TzXlkKS8/5dzjggHQmOJw2mRIB8DqagRTQxUP/p6uPXyp07LqXeOHNfv7",
"dist/merkleTreeWorker.umd.min.js": "sha384-Hpupvso1ruJIgbYwq+dySfLb75sgwxUexPYSCJu+/i7U3XqR6JiBhWOEnAdxR/An",
"dist/tornado.umd.js": "sha384-ovBwiI34m1uBSV4UlKomzexgVturp0Uq7O207DMS96GwpOeOjdS1RMkh7rqmtMed",
"dist/tornado.umd.min.js": "sha384-z9UM5/+q0Z70nAb+8JebUO/78o9C/W1AZgOWOYsDAyL9sH8ANR9U9tfB467+QHCF",
"dist/tornadoContracts.umd.js": "sha384-Gmawcz/XTH7WFUFnMJKPUCy2zrjDOhf/DtSv9xfHBulPyCEJwI70Hw+n7E1Y60EU",
"dist/tornadoContracts.umd.min.js": "sha384-Sclkp3xkhjmDekfQaQFkgUctmauYUF7ieeyyFhFBnwAzyp2eFBS5qzxvOIBhlJza"
}

8
dist/idb.d.ts vendored

@ -1,5 +1,11 @@
import { OpenDBCallbacks, IDBPDatabase } from 'idb';
import type * as idb from 'idb';
import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import { NetIdType } from './networkConfig';
declare global {
interface Window {
idb: typeof idb;
}
}
export declare const INDEX_DB_ERROR = "A mutation operation was attempted on a database that did not allow mutations.";
export interface IDBIndex {
name: string;

294
dist/index.js vendored

@ -5,12 +5,10 @@ var tornadoContracts = require('tornado-contracts');
var crypto$1 = require('crypto');
var BN = require('bn.js');
var contentHashUtils = require('@ensdomains/content-hash');
var crossFetch = require('cross-fetch');
var Ajv = require('ajv');
var fflate = require('fflate');
var circomlibjs = require('circomlibjs');
var ethSigUtil = require('@metamask/eth-sig-util');
var idb = require('idb');
var worker_threads = require('worker_threads');
var fixedMerkleTree = require('fixed-merkle-tree');
var websnarkUtils = require('websnark/src/utils');
@ -519,37 +517,10 @@ class BatchEventsService {
}
const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
function getHttpAgent({
fetchUrl,
proxyUrl,
torPort,
retry
}) {
const { HttpProxyAgent } = require("http-proxy-agent");
const { HttpsProxyAgent } = require("https-proxy-agent");
const { SocksProxyAgent } = require("socks-proxy-agent");
if (torPort) {
return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
}
if (!proxyUrl) {
return;
}
const isHttps = fetchUrl.includes("https://");
if (proxyUrl.includes("socks://") || proxyUrl.includes("socks4://") || proxyUrl.includes("socks5://")) {
return new SocksProxyAgent(proxyUrl);
}
if (proxyUrl.includes("http://") || proxyUrl.includes("https://")) {
if (isHttps) {
return new HttpsProxyAgent(proxyUrl);
}
return new HttpProxyAgent(proxyUrl);
}
}
async function fetchData(url, options = {}) {
const MAX_RETRY = options.maxRetry ?? 3;
const RETRY_ON = options.retryOn ?? 500;
const userAgent = options.userAgent ?? defaultUserAgent;
const fetch = globalThis.useGlobalFetch ? globalThis.fetch : crossFetch;
let retry = 0;
let errorObject;
if (!options.method) {
@ -565,6 +536,9 @@ async function fetchData(url, options = {}) {
if (isNode && !options.headers["User-Agent"]) {
options.headers["User-Agent"] = userAgent;
}
if (typeof globalThis.fetch !== "function") {
throw new Error("Fetch API is not available, use latest browser or nodejs installation!");
}
while (retry < MAX_RETRY + 1) {
let timeout;
if (!options.signal && options.timeout) {
@ -582,15 +556,7 @@ async function fetchData(url, options = {}) {
});
}
}
if (!options.agent && isNode && (options.proxy || options.torPort)) {
options.agent = getHttpAgent({
fetchUrl: url,
proxyUrl: options.proxy,
torPort: options.torPort,
retry
});
}
if (options.debug && typeof options.debug === "function") {
if (typeof options.debug === "function") {
options.debug("request", {
url,
retry,
@ -599,13 +565,10 @@ async function fetchData(url, options = {}) {
});
}
try {
const resp = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.body,
redirect: options.redirect,
signal: options.signal,
agent: options.agent
const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
const resp = await globalThis.fetch(url, {
...options,
dispatcher
});
if (options.debug && typeof options.debug === "function") {
options.debug("response", resp);
@ -668,15 +631,25 @@ const fetchGetUrlFunc = (options = {}) => async (req, _signal) => {
body
};
};
const FeeDataNetworkPluginName = new ethers.FetchUrlFeeDataNetworkPlugin(
"",
() => new Promise((resolve) => resolve(new ethers.FeeData()))
).name;
async function getProvider(rpcUrl, fetchOptions) {
const fetchReq = new ethers.FetchRequest(rpcUrl);
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
const staticNetwork = await new ethers.JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(staticNetwork.chainId);
const fetchedNetwork = await new ethers.JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(fetchedNetwork.chainId);
if (fetchOptions?.netId && fetchOptions.netId !== chainId) {
const errMsg = `Wrong network for ${rpcUrl}, wants ${fetchOptions.netId} got ${chainId}`;
throw new Error(errMsg);
}
const staticNetwork = new ethers.Network(fetchedNetwork.name, fetchedNetwork.chainId);
fetchedNetwork.plugins.forEach((plugin) => {
if (plugin.name !== FeeDataNetworkPluginName) {
staticNetwork.attachPlugin(plugin.clone());
}
});
return new ethers.JsonRpcProvider(fetchReq, staticNetwork, {
staticNetwork,
pollingInterval: fetchOptions?.pollingInterval || 1e3
@ -708,7 +681,7 @@ const populateTransaction = async (signer, tx) => {
}
const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? void 0 : provider.getFeeData(),
tx.nonce ? void 0 : provider.getTransactionCount(signer.address, "pending")
tx.nonce || tx.nonce === 0 ? void 0 : provider.getTransactionCount(signer.address, "pending")
]);
if (feeData) {
if (feeData.maxFeePerGas) {
@ -727,7 +700,7 @@ const populateTransaction = async (signer, tx) => {
delete tx.maxPriorityFeePerGas;
}
}
if (nonce) {
if (nonce || nonce === 0) {
tx.nonce = nonce;
}
if (!tx.gasLimit) {
@ -743,7 +716,7 @@ const populateTransaction = async (signer, tx) => {
}
}
}
return tx;
return ethers.resolveProperties(tx);
};
class TornadoWallet extends ethers.Wallet {
nonce;
@ -766,7 +739,7 @@ class TornadoWallet extends ethers.Wallet {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return super.populateTransaction(txObject);
return txObject;
}
}
class TornadoVoidSigner extends ethers.VoidSigner {
@ -785,7 +758,7 @@ class TornadoVoidSigner extends ethers.VoidSigner {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return super.populateTransaction(txObject);
return txObject;
}
}
class TornadoRpcSigner extends ethers.JsonRpcSigner {
@ -846,13 +819,6 @@ var NetId = /* @__PURE__ */ ((NetId2) => {
})(NetId || {});
const defaultConfig = {
[1 /* MAINNET */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 80,
fast: 50,
standard: 25,
low: 8
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://etherscan.io",
@ -865,9 +831,9 @@ const defaultConfig = {
name: "MEV Blocker",
url: "https://rpc.mevblocker.io"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/mainnet"
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/mainnet"
},
keydonix: {
name: "Horswap ( Keydonix )",
@ -986,13 +952,6 @@ const defaultConfig = {
}
},
[56 /* BSC */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 3,
fast: 1,
standard: 1,
low: 1
},
nativeCurrency: "bnb",
currencyName: "BNB",
explorerUrl: "https://bscscan.com",
@ -1016,9 +975,9 @@ const defaultConfig = {
name: "BNB Chain 2",
url: "https://bsc-dataseed1.ninicoin.io"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/bsc"
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/bsc"
},
nodereal: {
name: "NodeReal",
@ -1082,13 +1041,6 @@ const defaultConfig = {
}
},
[137 /* POLYGON */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 60,
fast: 30,
standard: 30,
low: 30
},
nativeCurrency: "matic",
currencyName: "MATIC",
explorerUrl: "https://polygonscan.com",
@ -1104,9 +1056,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/matic-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/polygon"
lavaBuild: {
name: "polygon.lava.build",
url: "https://polygon.lava.build"
},
polygon: {
name: "Polygon",
@ -1141,13 +1093,6 @@ const defaultConfig = {
}
},
[10 /* OPTIMISM */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1e-3,
fast: 1e-3,
standard: 1e-3,
low: 1e-3
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://optimistic.etherscan.io",
@ -1164,9 +1109,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/optimism-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/op"
lavaBuild: {
name: "optimism.lava.build",
url: "https://optimism.lava.build"
},
optimism: {
name: "Optimism",
@ -1204,13 +1149,6 @@ const defaultConfig = {
}
},
[42161 /* ARBITRUM */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.02,
fast: 0.02,
standard: 0.02,
low: 0.02
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://arbiscan.io",
@ -1230,10 +1168,6 @@ const defaultConfig = {
name: "Arbitrum",
url: "https://arb1.arbitrum.io/rpc"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/arbitrum"
},
stackup: {
name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/arbitrum-one"
@ -1266,13 +1200,6 @@ const defaultConfig = {
}
},
[8453 /* BASE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.1,
fast: 0.06,
standard: 0.05,
low: 0.02
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://basescan.org",
@ -1293,10 +1220,6 @@ const defaultConfig = {
name: "Base",
url: "https://mainnet.base.org"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/base"
},
stackup: {
name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/base-mainnet"
@ -1358,13 +1281,6 @@ const defaultConfig = {
}
},
[81457 /* BLAST */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1e-3,
fast: 1e-3,
standard: 1e-3,
low: 1e-3
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://blastscan.io",
@ -1384,10 +1300,6 @@ const defaultConfig = {
name: "Blast",
url: "https://rpc.blast.io"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/blast"
},
blastApi: {
name: "BlastApi",
url: "https://blastl2-mainnet.public.blastapi.io"
@ -1415,13 +1327,6 @@ const defaultConfig = {
}
},
[100 /* GNOSIS */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 6,
fast: 5,
standard: 4,
low: 1
},
nativeCurrency: "xdai",
currencyName: "xDAI",
explorerUrl: "https://gnosisscan.io",
@ -1441,9 +1346,13 @@ const defaultConfig = {
name: "Gnosis",
url: "https://rpc.gnosischain.com"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/gnosis"
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/gnosis"
},
blastApi: {
name: "BlastApi",
url: "https://gnosis-mainnet.public.blastapi.io"
},
oneRpc: {
name: "1RPC",
@ -1470,13 +1379,6 @@ const defaultConfig = {
}
},
[43114 /* AVALANCHE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 225,
fast: 35,
standard: 25,
low: 25
},
nativeCurrency: "avax",
currencyName: "AVAX",
explorerUrl: "https://snowtrace.io",
@ -1492,9 +1394,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/avalanche-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/ext/bc/C/rpc"
blastApi: {
name: "BlastApi",
url: "https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc"
},
oneRpc: {
name: "1RPC",
@ -1528,13 +1430,6 @@ const defaultConfig = {
}
},
[11155111 /* SEPOLIA */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 2,
fast: 2,
standard: 2,
low: 2
},
nativeCurrency: "eth",
currencyName: "SepoliaETH",
explorerUrl: "https://sepolia.etherscan.io",
@ -1556,9 +1451,13 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/sepolia"
blastApi: {
name: "BlastApi",
url: "https://eth-sepolia.public.blastapi.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/sepolia"
},
oneRpc: {
name: "1RPC",
@ -1647,15 +1546,6 @@ function getActiveTokens(config) {
const { tokens, disabledTokens } = config;
return Object.keys(tokens).filter((t) => !disabledTokens?.includes(t));
}
function getActiveTokenInstances(config) {
const { tokens, disabledTokens } = config;
return Object.entries(tokens).reduce((acc, [token, instances]) => {
if (!disabledTokens?.includes(token)) {
acc[token] = instances;
}
return acc;
}, {});
}
function getInstanceByAddress(config, address) {
const { tokens, disabledTokens } = config;
for (const [currency, { instanceAddress, tokenAddress, symbol, decimals }] of Object.entries(tokens)) {
@ -2225,8 +2115,7 @@ class RelayerClient {
}
async askRelayerStatus({
hostname,
url,
relayerAddress
url
}) {
if (!url && hostname) {
url = `https://${!hostname.endsWith("/") ? hostname + "/" : hostname}`;
@ -2241,7 +2130,7 @@ class RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
});
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
if (!statusValidator(rawStatus)) {
@ -2257,9 +2146,6 @@ class RelayerClient {
if (status.netId !== this.netId) {
throw new Error("This relayer serves a different network");
}
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error("The Relayer reward address must match registered address");
}
return status;
}
async filterRelayer(relayer) {
@ -2270,8 +2156,7 @@ class RelayerClient {
}
try {
const status = await this.askRelayerStatus({
hostname,
relayerAddress
hostname
});
return {
netId: status.netId,
@ -3175,7 +3060,7 @@ async function getTovarishNetworks(registryService, relayers) {
"Content-Type": "application/json"
},
timeout: 3e4,
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0
maxRetry: registryService.fetchDataOptions?.dispatcher ? 2 : 0
});
} catch {
relayer.tovarishNetworks = [];
@ -3504,14 +3389,38 @@ function unzipAsync(data) {
});
});
}
function zlibAsync(data, options) {
return new Promise((res, rej) => {
fflate.zlib(data, { ...options || {} }, (err, data2) => {
if (err) {
rej(err);
return;
}
res(data2);
});
});
}
function unzlibAsync(data, options) {
return new Promise((res, rej) => {
fflate.unzlib(data, { ...options || {} }, (err, data2) => {
if (err) {
rej(err);
return;
}
res(data2);
});
});
}
async function downloadZip({
staticUrl = "",
zipName,
zipDigest,
parseJson = true
parseJson = true,
fetchOptions
}) {
const url = `${staticUrl}/${zipName}.zip`;
const resp = await fetchData(url, {
...fetchOptions || {},
method: "GET",
returnResponse: true
});
@ -9590,7 +9499,7 @@ class ENSUtils {
}
async getContracts() {
const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)] || EnsContracts[NetId.MAINNET];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);
this.ENSNameWrapper = ENSNameWrapper__factory.connect(ensNameWrapper, this.provider);
@ -9834,7 +9743,7 @@ class IndexedDB {
if (this.dbExists || this.isBlocked) {
return;
}
this.db = await idb.openDB(this.dbName, this.dbVersion, this.options);
this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener("onupgradeneeded", async () => {
await this._removeExist();
});
@ -9854,7 +9763,7 @@ class IndexedDB {
}
}
async _removeExist() {
await idb.deleteDB(this.dbName);
await window?.idb?.deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();
}
@ -10160,8 +10069,9 @@ async function getIndexedDB(netId) {
return idb;
}
async function fetchIp(ipEcho) {
return await fetchData(ipEcho, {
function fetchIp(ipEcho, fetchOptions) {
return fetchData(ipEcho, {
...fetchOptions || {},
method: "GET",
timeout: 3e4
});
@ -10546,13 +10456,11 @@ class TovarishClient extends RelayerClient {
}
async askRelayerStatus({
hostname,
url,
relayerAddress
url
}) {
const status = await super.askRelayerStatus({
hostname,
url,
relayerAddress
url
});
if (!status.version.includes("tovarish")) {
throw new Error("Not a tovarish relayer!");
@ -10580,24 +10488,17 @@ class TovarishClient extends RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
});
if (!Array.isArray(statusArray)) {
return [];
}
const tovarishStatus = [];
for (const rawStatus of statusArray) {
const netId = rawStatus.netId;
const netId = rawStatus?.netId;
const config = getConfig(netId);
const statusValidator = ajv.compile(
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rawStatus.netId,
config,
this.tovarish
)
);
if (!statusValidator) {
const statusValidator = ajv.compile(getStatusSchema(rawStatus?.netId, config, this.tovarish));
if (!statusValidator(rawStatus)) {
continue;
}
const status = {
@ -10863,6 +10764,7 @@ exports.ENSUtils = ENSUtils;
exports.ENS__factory = ENS__factory;
exports.ERC20__factory = ERC20__factory;
exports.EnsContracts = EnsContracts;
exports.FeeDataNetworkPluginName = FeeDataNetworkPluginName;
exports.INDEX_DB_ERROR = INDEX_DB_ERROR;
exports.IndexedDB = IndexedDB;
exports.Invoice = Invoice;
@ -10927,11 +10829,9 @@ exports.gasZipID = gasZipID;
exports.gasZipInbounds = gasZipInbounds;
exports.gasZipInput = gasZipInput;
exports.gasZipMinMax = gasZipMinMax;
exports.getActiveTokenInstances = getActiveTokenInstances;
exports.getActiveTokens = getActiveTokens;
exports.getConfig = getConfig;
exports.getEventsSchemaValidator = getEventsSchemaValidator;
exports.getHttpAgent = getHttpAgent;
exports.getIndexedDB = getIndexedDB;
exports.getInstanceByAddress = getInstanceByAddress;
exports.getMultiInstances = getMultiInstances;
@ -10986,6 +10886,8 @@ exports.toFixedLength = toFixedLength;
exports.tornadoEventsSchema = tornadoEventsSchema;
exports.unpackEncryptedMessage = unpackEncryptedMessage;
exports.unzipAsync = unzipAsync;
exports.unzlibAsync = unzlibAsync;
exports.validateUrl = validateUrl;
exports.withdrawalsEventsSchema = withdrawalsEventsSchema;
exports.zipAsync = zipAsync;
exports.zlibAsync = zlibAsync;

295
dist/index.mjs vendored

@ -1,14 +1,12 @@
import { isHexString, assertArgument, assert, EventLog, UndecodedEventLog, Log, FetchRequest, JsonRpcProvider, Network, EnsPlugin, GasCostPlugin, Wallet, HDNodeWallet, VoidSigner, JsonRpcSigner, BrowserProvider, isAddress, parseEther, getAddress, AbiCoder, formatEther, namehash, dataSlice, dataLength, Interface, Contract, computeAddress, keccak256, EnsResolver, parseUnits, Transaction, Signature, MaxUint256, ZeroAddress } from 'ethers';
import { isHexString, assertArgument, assert, EventLog, UndecodedEventLog, Log, FetchUrlFeeDataNetworkPlugin, FeeData, FetchRequest, JsonRpcProvider, Network, EnsPlugin, GasCostPlugin, resolveProperties, Wallet, HDNodeWallet, VoidSigner, JsonRpcSigner, BrowserProvider, isAddress, parseEther, getAddress, AbiCoder, formatEther, namehash, dataSlice, dataLength, Interface, Contract, computeAddress, keccak256, EnsResolver, parseUnits, Transaction, Signature, MaxUint256, ZeroAddress } from 'ethers';
import { Tornado__factory } from 'tornado-contracts';
import { webcrypto } from 'crypto';
import BN from 'bn.js';
import * as contentHashUtils from '@ensdomains/content-hash';
import crossFetch from 'cross-fetch';
import Ajv from 'ajv';
import { zip, unzip } from 'fflate';
import { zip, unzip, zlib, unzlib } from 'fflate';
import { buildPedersenHash, buildMimcSponge } from 'circomlibjs';
import { getEncryptionPublicKey, encrypt, decrypt } from '@metamask/eth-sig-util';
import { openDB, deleteDB } from 'idb';
import { Worker as Worker$1 } from 'worker_threads';
import { MerkleTree, PartialMerkleTree } from 'fixed-merkle-tree';
import * as websnarkUtils from 'websnark/src/utils';
@ -497,37 +495,10 @@ class BatchEventsService {
}
const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
function getHttpAgent({
fetchUrl,
proxyUrl,
torPort,
retry
}) {
const { HttpProxyAgent } = require("http-proxy-agent");
const { HttpsProxyAgent } = require("https-proxy-agent");
const { SocksProxyAgent } = require("socks-proxy-agent");
if (torPort) {
return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
}
if (!proxyUrl) {
return;
}
const isHttps = fetchUrl.includes("https://");
if (proxyUrl.includes("socks://") || proxyUrl.includes("socks4://") || proxyUrl.includes("socks5://")) {
return new SocksProxyAgent(proxyUrl);
}
if (proxyUrl.includes("http://") || proxyUrl.includes("https://")) {
if (isHttps) {
return new HttpsProxyAgent(proxyUrl);
}
return new HttpProxyAgent(proxyUrl);
}
}
async function fetchData(url, options = {}) {
const MAX_RETRY = options.maxRetry ?? 3;
const RETRY_ON = options.retryOn ?? 500;
const userAgent = options.userAgent ?? defaultUserAgent;
const fetch = globalThis.useGlobalFetch ? globalThis.fetch : crossFetch;
let retry = 0;
let errorObject;
if (!options.method) {
@ -543,6 +514,9 @@ async function fetchData(url, options = {}) {
if (isNode && !options.headers["User-Agent"]) {
options.headers["User-Agent"] = userAgent;
}
if (typeof globalThis.fetch !== "function") {
throw new Error("Fetch API is not available, use latest browser or nodejs installation!");
}
while (retry < MAX_RETRY + 1) {
let timeout;
if (!options.signal && options.timeout) {
@ -560,15 +534,7 @@ async function fetchData(url, options = {}) {
});
}
}
if (!options.agent && isNode && (options.proxy || options.torPort)) {
options.agent = getHttpAgent({
fetchUrl: url,
proxyUrl: options.proxy,
torPort: options.torPort,
retry
});
}
if (options.debug && typeof options.debug === "function") {
if (typeof options.debug === "function") {
options.debug("request", {
url,
retry,
@ -577,13 +543,10 @@ async function fetchData(url, options = {}) {
});
}
try {
const resp = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.body,
redirect: options.redirect,
signal: options.signal,
agent: options.agent
const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
const resp = await globalThis.fetch(url, {
...options,
dispatcher
});
if (options.debug && typeof options.debug === "function") {
options.debug("response", resp);
@ -646,15 +609,25 @@ const fetchGetUrlFunc = (options = {}) => async (req, _signal) => {
body
};
};
const FeeDataNetworkPluginName = new FetchUrlFeeDataNetworkPlugin(
"",
() => new Promise((resolve) => resolve(new FeeData()))
).name;
async function getProvider(rpcUrl, fetchOptions) {
const fetchReq = new FetchRequest(rpcUrl);
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
const staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(staticNetwork.chainId);
const fetchedNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(fetchedNetwork.chainId);
if (fetchOptions?.netId && fetchOptions.netId !== chainId) {
const errMsg = `Wrong network for ${rpcUrl}, wants ${fetchOptions.netId} got ${chainId}`;
throw new Error(errMsg);
}
const staticNetwork = new Network(fetchedNetwork.name, fetchedNetwork.chainId);
fetchedNetwork.plugins.forEach((plugin) => {
if (plugin.name !== FeeDataNetworkPluginName) {
staticNetwork.attachPlugin(plugin.clone());
}
});
return new JsonRpcProvider(fetchReq, staticNetwork, {
staticNetwork,
pollingInterval: fetchOptions?.pollingInterval || 1e3
@ -686,7 +659,7 @@ const populateTransaction = async (signer, tx) => {
}
const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? void 0 : provider.getFeeData(),
tx.nonce ? void 0 : provider.getTransactionCount(signer.address, "pending")
tx.nonce || tx.nonce === 0 ? void 0 : provider.getTransactionCount(signer.address, "pending")
]);
if (feeData) {
if (feeData.maxFeePerGas) {
@ -705,7 +678,7 @@ const populateTransaction = async (signer, tx) => {
delete tx.maxPriorityFeePerGas;
}
}
if (nonce) {
if (nonce || nonce === 0) {
tx.nonce = nonce;
}
if (!tx.gasLimit) {
@ -721,7 +694,7 @@ const populateTransaction = async (signer, tx) => {
}
}
}
return tx;
return resolveProperties(tx);
};
class TornadoWallet extends Wallet {
nonce;
@ -744,7 +717,7 @@ class TornadoWallet extends Wallet {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return super.populateTransaction(txObject);
return txObject;
}
}
class TornadoVoidSigner extends VoidSigner {
@ -763,7 +736,7 @@ class TornadoVoidSigner extends VoidSigner {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return super.populateTransaction(txObject);
return txObject;
}
}
class TornadoRpcSigner extends JsonRpcSigner {
@ -824,13 +797,6 @@ var NetId = /* @__PURE__ */ ((NetId2) => {
})(NetId || {});
const defaultConfig = {
[1 /* MAINNET */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 80,
fast: 50,
standard: 25,
low: 8
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://etherscan.io",
@ -843,9 +809,9 @@ const defaultConfig = {
name: "MEV Blocker",
url: "https://rpc.mevblocker.io"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/mainnet"
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/mainnet"
},
keydonix: {
name: "Horswap ( Keydonix )",
@ -964,13 +930,6 @@ const defaultConfig = {
}
},
[56 /* BSC */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 3,
fast: 1,
standard: 1,
low: 1
},
nativeCurrency: "bnb",
currencyName: "BNB",
explorerUrl: "https://bscscan.com",
@ -994,9 +953,9 @@ const defaultConfig = {
name: "BNB Chain 2",
url: "https://bsc-dataseed1.ninicoin.io"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/bsc"
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/bsc"
},
nodereal: {
name: "NodeReal",
@ -1060,13 +1019,6 @@ const defaultConfig = {
}
},
[137 /* POLYGON */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 60,
fast: 30,
standard: 30,
low: 30
},
nativeCurrency: "matic",
currencyName: "MATIC",
explorerUrl: "https://polygonscan.com",
@ -1082,9 +1034,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/matic-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/polygon"
lavaBuild: {
name: "polygon.lava.build",
url: "https://polygon.lava.build"
},
polygon: {
name: "Polygon",
@ -1119,13 +1071,6 @@ const defaultConfig = {
}
},
[10 /* OPTIMISM */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1e-3,
fast: 1e-3,
standard: 1e-3,
low: 1e-3
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://optimistic.etherscan.io",
@ -1142,9 +1087,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/optimism-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/op"
lavaBuild: {
name: "optimism.lava.build",
url: "https://optimism.lava.build"
},
optimism: {
name: "Optimism",
@ -1182,13 +1127,6 @@ const defaultConfig = {
}
},
[42161 /* ARBITRUM */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.02,
fast: 0.02,
standard: 0.02,
low: 0.02
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://arbiscan.io",
@ -1208,10 +1146,6 @@ const defaultConfig = {
name: "Arbitrum",
url: "https://arb1.arbitrum.io/rpc"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/arbitrum"
},
stackup: {
name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/arbitrum-one"
@ -1244,13 +1178,6 @@ const defaultConfig = {
}
},
[8453 /* BASE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.1,
fast: 0.06,
standard: 0.05,
low: 0.02
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://basescan.org",
@ -1271,10 +1198,6 @@ const defaultConfig = {
name: "Base",
url: "https://mainnet.base.org"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/base"
},
stackup: {
name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/base-mainnet"
@ -1336,13 +1259,6 @@ const defaultConfig = {
}
},
[81457 /* BLAST */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1e-3,
fast: 1e-3,
standard: 1e-3,
low: 1e-3
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://blastscan.io",
@ -1362,10 +1278,6 @@ const defaultConfig = {
name: "Blast",
url: "https://rpc.blast.io"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/blast"
},
blastApi: {
name: "BlastApi",
url: "https://blastl2-mainnet.public.blastapi.io"
@ -1393,13 +1305,6 @@ const defaultConfig = {
}
},
[100 /* GNOSIS */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 6,
fast: 5,
standard: 4,
low: 1
},
nativeCurrency: "xdai",
currencyName: "xDAI",
explorerUrl: "https://gnosisscan.io",
@ -1419,9 +1324,13 @@ const defaultConfig = {
name: "Gnosis",
url: "https://rpc.gnosischain.com"
},
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/gnosis"
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/gnosis"
},
blastApi: {
name: "BlastApi",
url: "https://gnosis-mainnet.public.blastapi.io"
},
oneRpc: {
name: "1RPC",
@ -1448,13 +1357,6 @@ const defaultConfig = {
}
},
[43114 /* AVALANCHE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 225,
fast: 35,
standard: 25,
low: 25
},
nativeCurrency: "avax",
currencyName: "AVAX",
explorerUrl: "https://snowtrace.io",
@ -1470,9 +1372,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/avalanche-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/ext/bc/C/rpc"
blastApi: {
name: "BlastApi",
url: "https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc"
},
oneRpc: {
name: "1RPC",
@ -1506,13 +1408,6 @@ const defaultConfig = {
}
},
[11155111 /* SEPOLIA */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 2,
fast: 2,
standard: 2,
low: 2
},
nativeCurrency: "eth",
currencyName: "SepoliaETH",
explorerUrl: "https://sepolia.etherscan.io",
@ -1534,9 +1429,13 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph",
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/sepolia"
blastApi: {
name: "BlastApi",
url: "https://eth-sepolia.public.blastapi.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/sepolia"
},
oneRpc: {
name: "1RPC",
@ -1625,15 +1524,6 @@ function getActiveTokens(config) {
const { tokens, disabledTokens } = config;
return Object.keys(tokens).filter((t) => !disabledTokens?.includes(t));
}
function getActiveTokenInstances(config) {
const { tokens, disabledTokens } = config;
return Object.entries(tokens).reduce((acc, [token, instances]) => {
if (!disabledTokens?.includes(token)) {
acc[token] = instances;
}
return acc;
}, {});
}
function getInstanceByAddress(config, address) {
const { tokens, disabledTokens } = config;
for (const [currency, { instanceAddress, tokenAddress, symbol, decimals }] of Object.entries(tokens)) {
@ -2203,8 +2093,7 @@ class RelayerClient {
}
async askRelayerStatus({
hostname,
url,
relayerAddress
url
}) {
if (!url && hostname) {
url = `https://${!hostname.endsWith("/") ? hostname + "/" : hostname}`;
@ -2219,7 +2108,7 @@ class RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
});
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
if (!statusValidator(rawStatus)) {
@ -2235,9 +2124,6 @@ class RelayerClient {
if (status.netId !== this.netId) {
throw new Error("This relayer serves a different network");
}
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error("The Relayer reward address must match registered address");
}
return status;
}
async filterRelayer(relayer) {
@ -2248,8 +2134,7 @@ class RelayerClient {
}
try {
const status = await this.askRelayerStatus({
hostname,
relayerAddress
hostname
});
return {
netId: status.netId,
@ -3153,7 +3038,7 @@ async function getTovarishNetworks(registryService, relayers) {
"Content-Type": "application/json"
},
timeout: 3e4,
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0
maxRetry: registryService.fetchDataOptions?.dispatcher ? 2 : 0
});
} catch {
relayer.tovarishNetworks = [];
@ -3482,14 +3367,38 @@ function unzipAsync(data) {
});
});
}
function zlibAsync(data, options) {
return new Promise((res, rej) => {
zlib(data, { ...options || {} }, (err, data2) => {
if (err) {
rej(err);
return;
}
res(data2);
});
});
}
function unzlibAsync(data, options) {
return new Promise((res, rej) => {
unzlib(data, { ...options || {} }, (err, data2) => {
if (err) {
rej(err);
return;
}
res(data2);
});
});
}
async function downloadZip({
staticUrl = "",
zipName,
zipDigest,
parseJson = true
parseJson = true,
fetchOptions
}) {
const url = `${staticUrl}/${zipName}.zip`;
const resp = await fetchData(url, {
...fetchOptions || {},
method: "GET",
returnResponse: true
});
@ -9568,7 +9477,7 @@ class ENSUtils {
}
async getContracts() {
const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)] || EnsContracts[NetId.MAINNET];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);
this.ENSNameWrapper = ENSNameWrapper__factory.connect(ensNameWrapper, this.provider);
@ -9812,7 +9721,7 @@ class IndexedDB {
if (this.dbExists || this.isBlocked) {
return;
}
this.db = await openDB(this.dbName, this.dbVersion, this.options);
this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener("onupgradeneeded", async () => {
await this._removeExist();
});
@ -9832,7 +9741,7 @@ class IndexedDB {
}
}
async _removeExist() {
await deleteDB(this.dbName);
await window?.idb?.deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();
}
@ -10138,8 +10047,9 @@ async function getIndexedDB(netId) {
return idb;
}
async function fetchIp(ipEcho) {
return await fetchData(ipEcho, {
function fetchIp(ipEcho, fetchOptions) {
return fetchData(ipEcho, {
...fetchOptions || {},
method: "GET",
timeout: 3e4
});
@ -10524,13 +10434,11 @@ class TovarishClient extends RelayerClient {
}
async askRelayerStatus({
hostname,
url,
relayerAddress
url
}) {
const status = await super.askRelayerStatus({
hostname,
url,
relayerAddress
url
});
if (!status.version.includes("tovarish")) {
throw new Error("Not a tovarish relayer!");
@ -10558,24 +10466,17 @@ class TovarishClient extends RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
});
if (!Array.isArray(statusArray)) {
return [];
}
const tovarishStatus = [];
for (const rawStatus of statusArray) {
const netId = rawStatus.netId;
const netId = rawStatus?.netId;
const config = getConfig(netId);
const statusValidator = ajv.compile(
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rawStatus.netId,
config,
this.tovarish
)
);
if (!statusValidator) {
const statusValidator = ajv.compile(getStatusSchema(rawStatus?.netId, config, this.tovarish));
if (!statusValidator(rawStatus)) {
continue;
}
const status = {
@ -10814,4 +10715,4 @@ async function calculateSnarkProof(input, circuit, provingKey) {
return { proof, args };
}
export { BaseEchoService, BaseEncryptedNotesService, BaseEventsService, BaseGovernanceService, BaseMultiTornadoService, BaseRegistryService, BaseRevenueService, BaseTornadoService, BaseTransferService, BatchBlockService, BatchEventsService, BatchTransactionService, DBEchoService, DBEncryptedNotesService, DBGovernanceService, DBMultiTornadoService, DBRegistryService, DBRevenueService, DBTornadoService, Deposit, ENSNameWrapper__factory, ENSRegistry__factory, ENSResolver__factory, ENSUtils, ENS__factory, ERC20__factory, EnsContracts, INDEX_DB_ERROR, IndexedDB, Invoice, MAX_FEE, MAX_TOVARISH_EVENTS, MIN_FEE, MIN_STAKE_BALANCE, MerkleTreeService, Mimc, Multicall__factory, NetId, NoteAccount, OffchainOracle__factory, OvmGasPriceOracle__factory, Pedersen, RelayerClient, ReverseRecords__factory, TokenPriceOracle, TornadoBrowserProvider, TornadoFeeOracle, TornadoRpcSigner, TornadoVoidSigner, TornadoWallet, TovarishClient, addNetwork, addressSchemaType, ajv, base64ToBytes, bigIntReplacer, bnSchemaType, bnToBytes, buffPedersenHash, bufferToBytes, bytes32BNSchemaType, bytes32SchemaType, bytesToBN, bytesToBase64, bytesToHex, calculateScore, calculateSnarkProof, chunk, concatBytes, convertETHToTokenAmount, createDeposit, crypto, customConfig, defaultConfig, defaultUserAgent, deployHasher, depositsEventsSchema, digest, downloadZip, echoEventsSchema, enabledChains, encodedLabelToLabelhash, encryptedNotesSchema, index as factories, fetchData, fetchGetUrlFunc, fetchIp, fromContentHash, gasZipID, gasZipInbounds, gasZipInput, gasZipMinMax, getActiveTokenInstances, getActiveTokens, getConfig, getEventsSchemaValidator, getHttpAgent, getIndexedDB, getInstanceByAddress, getMultiInstances, getNetworkConfig, getPermitSignature, getProvider, getProviderWithNetId, getRelayerEnsSubdomains, getStatusSchema, getSubInfo, getSupportedInstances, getTokenBalances, getTovarishNetworks, getWeightRandom, governanceEventsSchema, hasherBytecode, hexToBytes, initGroth16, isHex, isNode, jobRequestSchema, jobsSchema, labelhash, leBuff2Int, leInt2Buff, loadDBEvents, loadRemoteEvents, makeLabelNodeAndParent, mimc, multiQueryFilter, multicall, numberFormatter, packEncryptedMessage, parseInvoice, parseNote, pedersen, permit2Address, pickWeightedRandomRelayer, populateTransaction, proofSchemaType, proposalState, rBigInt, rHex, relayerRegistryEventsSchema, saveDBEvents, sleep, stakeBurnedEventsSchema, substring, toContentHash, toFixedHex, toFixedLength, tornadoEventsSchema, unpackEncryptedMessage, unzipAsync, validateUrl, withdrawalsEventsSchema, zipAsync };
export { BaseEchoService, BaseEncryptedNotesService, BaseEventsService, BaseGovernanceService, BaseMultiTornadoService, BaseRegistryService, BaseRevenueService, BaseTornadoService, BaseTransferService, BatchBlockService, BatchEventsService, BatchTransactionService, DBEchoService, DBEncryptedNotesService, DBGovernanceService, DBMultiTornadoService, DBRegistryService, DBRevenueService, DBTornadoService, Deposit, ENSNameWrapper__factory, ENSRegistry__factory, ENSResolver__factory, ENSUtils, ENS__factory, ERC20__factory, EnsContracts, FeeDataNetworkPluginName, INDEX_DB_ERROR, IndexedDB, Invoice, MAX_FEE, MAX_TOVARISH_EVENTS, MIN_FEE, MIN_STAKE_BALANCE, MerkleTreeService, Mimc, Multicall__factory, NetId, NoteAccount, OffchainOracle__factory, OvmGasPriceOracle__factory, Pedersen, RelayerClient, ReverseRecords__factory, TokenPriceOracle, TornadoBrowserProvider, TornadoFeeOracle, TornadoRpcSigner, TornadoVoidSigner, TornadoWallet, TovarishClient, addNetwork, addressSchemaType, ajv, base64ToBytes, bigIntReplacer, bnSchemaType, bnToBytes, buffPedersenHash, bufferToBytes, bytes32BNSchemaType, bytes32SchemaType, bytesToBN, bytesToBase64, bytesToHex, calculateScore, calculateSnarkProof, chunk, concatBytes, convertETHToTokenAmount, createDeposit, crypto, customConfig, defaultConfig, defaultUserAgent, deployHasher, depositsEventsSchema, digest, downloadZip, echoEventsSchema, enabledChains, encodedLabelToLabelhash, encryptedNotesSchema, index as factories, fetchData, fetchGetUrlFunc, fetchIp, fromContentHash, gasZipID, gasZipInbounds, gasZipInput, gasZipMinMax, getActiveTokens, getConfig, getEventsSchemaValidator, getIndexedDB, getInstanceByAddress, getMultiInstances, getNetworkConfig, getPermitSignature, getProvider, getProviderWithNetId, getRelayerEnsSubdomains, getStatusSchema, getSubInfo, getSupportedInstances, getTokenBalances, getTovarishNetworks, getWeightRandom, governanceEventsSchema, hasherBytecode, hexToBytes, initGroth16, isHex, isNode, jobRequestSchema, jobsSchema, labelhash, leBuff2Int, leInt2Buff, loadDBEvents, loadRemoteEvents, makeLabelNodeAndParent, mimc, multiQueryFilter, multicall, numberFormatter, packEncryptedMessage, parseInvoice, parseNote, pedersen, permit2Address, pickWeightedRandomRelayer, populateTransaction, proofSchemaType, proposalState, rBigInt, rHex, relayerRegistryEventsSchema, saveDBEvents, sleep, stakeBurnedEventsSchema, substring, toContentHash, toFixedHex, toFixedLength, tornadoEventsSchema, unpackEncryptedMessage, unzipAsync, unzlibAsync, validateUrl, withdrawalsEventsSchema, zipAsync, zlibAsync };

5
dist/ip.d.ts vendored

@ -1,6 +1,9 @@
import { fetchDataOptions } from './providers';
export interface IPResult {
ip: string;
iso?: string;
country?: string;
country_iso?: string;
tor?: boolean;
}
export declare function fetchIp(ipEcho: string): Promise<IPResult>;
export declare function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions): Promise<IPResult>;

@ -5793,6 +5793,7 @@ PEMEncoder.prototype.encode = function encode(data, options) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Currently in sync with Node.js lib/assert.js
// https://github.com/nodejs/node/commit/2a51ae424a513ec9a6aa3466baa0cc1d55dd4f3b
@ -6390,6 +6391,7 @@ assert.strict.strict = assert.strict;
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Currently in sync with Node.js lib/internal/assert/assertion_error.js
// https://github.com/nodejs/node/commit/0817840f775032169ddd70c85ac059f18ffcc81c
@ -14408,6 +14410,7 @@ PassThrough.prototype._transform = function (chunk, encoding, cb) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -15655,6 +15658,7 @@ function done(stream, er, data) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -47564,6 +47568,7 @@ module.exports = function (password, salt, iterations, keylen, digest, callback)
/***/ 2455:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
/* provided dependency */ var process = __webpack_require__(5606);
var defaultEncoding
/* istanbul ignore next */
if (__webpack_require__.g.process && __webpack_require__.g.process.browser) {
@ -47763,9 +47768,10 @@ module.exports = [
/***/ }),
/***/ 3225:
/***/ ((module) => {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
if (typeof process === 'undefined' ||
@ -47813,6 +47819,197 @@ function nextTick(fn, arg1, arg2, arg3) {
/***/ }),
/***/ 5606:
/***/ ((module) => {
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) { return [] }
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
/***/ }),
/***/ 7168:
@ -51557,6 +51754,7 @@ module.exports = function xor (a, b) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// limit of Crypto.getRandomValues()
@ -51615,6 +51813,7 @@ function randomBytes (size, cb) {
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
function oldBrowser () {
@ -51866,6 +52065,7 @@ module.exports.F = codes;
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -52043,6 +52243,7 @@ PassThrough.prototype._transform = function (chunk, encoding, cb) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -53274,6 +53475,7 @@ function done(stream, er, data) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -53922,6 +54124,7 @@ Writable.prototype._destroy = function (err, cb) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
var _Object$setPrototypeO;
@ -54296,9 +54499,10 @@ module.exports = /*#__PURE__*/function () {
/***/ }),
/***/ 5896:
/***/ ((module) => {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// undocumented cb() API, needed for core, not for public API
@ -56763,6 +56967,7 @@ exports.isAnyArrayBuffer = isAnyArrayBuffer;
/***/ 537:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
/* provided dependency */ var process = __webpack_require__(5606);
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -72273,6 +72478,7 @@ class ChaCha {
// EXTERNAL MODULE: ./node_modules/crypto-browserify/index.js
var crypto_browserify = __webpack_require__(1565);
;// ./node_modules/ffjavascript/src/random.js
/* provided dependency */ var process = __webpack_require__(5606);
@ -75277,6 +75483,7 @@ var browser = __webpack_require__(1072);
// EXTERNAL MODULE: ./node_modules/web-worker/cjs/browser.js
var cjs_browser = __webpack_require__(1723);
;// ./node_modules/ffjavascript/src/threadman.js
/* provided dependency */ var threadman_process = __webpack_require__(5606);
/* provided dependency */ var Buffer = __webpack_require__(8287)["Buffer"];
/*
Copyright 2019 0KIMS association.
@ -75321,7 +75528,7 @@ function sleep(ms) {
let workerSource;
const threadStr = `(${thread.toString()})(self)`;
if(process.browser) {
if(threadman_process.browser) {
if(globalThis?.Blob) {
const threadBytes= new TextEncoder().encode(threadStr);
const workerBlob = new Blob([threadBytes], { type: "application/javascript" }) ;
@ -75350,7 +75557,7 @@ async function buildThreadManager(wasm, singleThread) {
}
});
if(process.browser && !globalThis?.Worker) {
if(threadman_process.browser && !globalThis?.Worker) {
singleThread = true;
}
@ -75382,7 +75589,7 @@ async function buildThreadManager(wasm, singleThread) {
tm.working = [];
let concurrency = 2;
if (process.browser) {
if (threadman_process.browser) {
if (typeof navigator === "object" && navigator.hardwareConcurrency) {
concurrency = navigator.hardwareConcurrency;
}
@ -106399,6 +106606,7 @@ var bn = __webpack_require__(9404);
// EXTERNAL MODULE: ./node_modules/@ensdomains/content-hash/src/index.js
var src = __webpack_require__(1810);
;// ./src/utils.ts
/* provided dependency */ var utils_process = __webpack_require__(5606);
@ -106406,7 +106614,7 @@ var src = __webpack_require__(1810);
BigInt.prototype.toJSON = function() {
return this.toString();
};
const isNode = !process.browser && typeof globalThis.window === "undefined";
const isNode = !utils_process.browser && typeof globalThis.window === "undefined";
const utils_crypto = isNode ? crypto_browserify.webcrypto : globalThis.crypto;
const chunk = (arr, size) => [...Array(Math.ceil(arr.length / size))].map((_, i) => arr.slice(size * i, size + size * i));
function utils_sleep(ms) {

File diff suppressed because one or more lines are too long

@ -37,14 +37,6 @@ export interface TornadoInstance {
}
export type TokenInstances = Record<string, TornadoInstance>;
export interface Config {
rpcCallRetryAttempt?: number;
gasPrices: {
instant: number;
fast?: number;
standard?: number;
low?: number;
maxPriorityFeePerGas?: number;
};
nativeCurrency: string;
currencyName: string;
explorerUrl: string;
@ -65,16 +57,16 @@ export interface Config {
aggregatorContract?: string;
reverseRecordsContract?: string;
ovmGasPriceOracleContract?: string;
tornadoSubgraph: string;
tornadoSubgraph?: string;
registrySubgraph?: string;
governanceSubgraph?: string;
subgraphs: SubgraphUrls;
subgraphs?: SubgraphUrls;
tokens: TokenInstances;
optionalTokens?: string[];
disabledTokens?: string[];
relayerEnsSubdomain: string;
pollInterval: number;
constants: {
constants?: {
GOVERNANCE_BLOCK?: number;
NOTE_ACCOUNT_BLOCK?: number;
ENCRYPTED_NOTES_BLOCK?: number;
@ -102,7 +94,6 @@ export declare function addNetwork(newConfig: networkConfig): void;
export declare function getNetworkConfig(): networkConfig;
export declare function getConfig(netId: NetIdType): Config;
export declare function getActiveTokens(config: Config): string[];
export declare function getActiveTokenInstances(config: Config): TokenInstances;
export declare function getInstanceByAddress(config: Config, address: string): {
amount: string;
currency: string;

56
dist/providers.d.ts vendored

@ -1,7 +1,6 @@
import type { EventEmitter } from 'stream';
import type { RequestOptions } from 'http';
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchCancelSignal } from 'ethers';
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchCancelSignal, TransactionLike } from 'ethers';
import type { Dispatcher, RequestInit } from 'undici-types';
import type { Config, NetIdType } from './networkConfig';
declare global {
interface Window {
@ -9,35 +8,54 @@ declare global {
}
}
export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export type fetchDataOptions = RequestInit & {
export type DispatcherFunc = (retry?: number) => Dispatcher;
export interface fetchDataOptions extends Omit<RequestInit, 'headers'> {
/**
* Overriding RequestInit params
*/
headers?: HeadersInit | any;
/**
* Expanding RequestInit params
*/
maxRetry?: number;
retryOn?: number;
userAgent?: string;
timeout?: number;
proxy?: string;
torPort?: number;
debug?: Function;
returnResponse?: boolean;
cancelSignal?: FetchCancelSignal;
};
export type NodeAgent = RequestOptions['agent'] | ((parsedUrl: URL) => RequestOptions['agent']);
export declare function getHttpAgent({ fetchUrl, proxyUrl, torPort, retry, }: {
fetchUrl: string;
proxyUrl?: string;
torPort?: number;
retry: number;
}): NodeAgent | undefined;
export declare function fetchData(url: string, options?: fetchDataOptions): Promise<any>;
dispatcherFunc?: DispatcherFunc;
}
export declare function fetchData<T>(url: string, options?: fetchDataOptions): Promise<T>;
export declare const fetchGetUrlFunc: (options?: fetchDataOptions) => FetchGetUrlFunc;
export type getProviderOptions = fetchDataOptions & {
netId?: NetIdType;
pollingInterval?: number;
};
export declare const FeeDataNetworkPluginName: string;
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<{
type?: null | number | undefined;
to?: string | import("ethers").Addressable | null | undefined;
from?: string | import("ethers").Addressable | null | undefined;
nonce?: null | number | undefined;
gasLimit?: string | number | bigint | null | undefined;
gasPrice?: string | number | bigint | null | undefined;
maxPriorityFeePerGas?: string | number | bigint | null | undefined;
maxFeePerGas?: string | number | bigint | null | undefined;
data?: null | string | undefined;
value?: string | number | bigint | null | undefined;
chainId?: string | number | bigint | null | undefined;
accessList?: import("ethers").AccessList | [string, string[]][] | Record<string, string[]> | null | undefined;
customData?: any;
blockTag?: string | number | bigint | undefined;
enableCcipRead?: boolean | undefined;
blobVersionedHashes?: (null | Array<string>) | undefined;
maxFeePerBlobGas?: string | number | bigint | null | undefined;
blobs?: (null | Array<import("ethers").BlobLike>) | undefined;
kzg?: (null | import("ethers").KzgLibrary) | undefined;
}>;
export interface TornadoWalletOptions {
gasPriceBump?: number;
gasLimitBump?: number;
@ -53,7 +71,7 @@ export declare class TornadoWallet extends Wallet {
bumpNonce: boolean;
constructor(key: string | SigningKey, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
static fromMnemonic(mneomnic: string, provider: Provider, index?: number, options?: TornadoWalletOptions): TornadoWallet;
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>>;
}
export declare class TornadoVoidSigner extends VoidSigner {
nonce?: number;
@ -62,7 +80,7 @@ export declare class TornadoVoidSigner extends VoidSigner {
gasFailover: boolean;
bumpNonce: boolean;
constructor(address: string, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>>;
}
export declare class TornadoRpcSigner extends JsonRpcSigner {
nonce?: number;

@ -120,10 +120,9 @@ export declare class RelayerClient {
fetchDataOptions?: fetchDataOptions;
tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: {
askRelayerStatus({ hostname, url, }: {
hostname?: string;
url?: string;
relayerAddress?: string;
}): Promise<RelayerStatus>;
filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined>;
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{

2034
dist/tornado.umd.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -45,7 +45,7 @@ export interface BaseTovarishEvents<T> {
export declare class TovarishClient extends RelayerClient {
selectedRelayer?: TovarishInfo;
constructor(clientConstructor: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: {
askRelayerStatus({ hostname, url, }: {
hostname?: string;
url?: string;
relayerAddress?: string;

8
dist/zip.d.ts vendored

@ -1,9 +1,13 @@
import { AsyncZippable, Unzipped, ZipAttributes } from 'fflate';
import { AsyncZippable, Unzipped, ZipAttributes, AsyncZlibOptions, AsyncUnzlibOptions } from 'fflate';
import { fetchDataOptions } from './providers';
export declare function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array>;
export declare function unzipAsync(data: Uint8Array): Promise<Unzipped>;
export declare function downloadZip<T>({ staticUrl, zipName, zipDigest, parseJson, }: {
export declare function zlibAsync(data: Uint8Array, options?: AsyncZlibOptions): Promise<Uint8Array>;
export declare function unzlibAsync(data: Uint8Array, options?: AsyncUnzlibOptions): Promise<Uint8Array>;
export declare function downloadZip<T>({ staticUrl, zipName, zipDigest, parseJson, fetchOptions, }: {
staticUrl?: string;
zipName: string;
zipDigest?: string;
parseJson?: boolean;
fetchOptions?: fetchDataOptions;
}): Promise<T>;

@ -46,12 +46,10 @@
"ajv": "^8.17.1",
"bn.js": "^5.2.1",
"circomlibjs": "git+https://github.com/tornadocontrib/circomlibjs.git#2aef7aade8e2b8d103250e4b24c7f1526cf1dd8d",
"cross-fetch": "^4.1.0",
"ethers": "^6.13.4",
"ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109",
"fflate": "^0.8.2",
"fixed-merkle-tree": "0.7.3",
"idb": "^8.0.1",
"snarkjs": "git+https://github.com/tornadocontrib/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a",
"tornado-contracts": "git+https://github.com/tornadocontrib/tornado-contracts.git#9be1e1c308ae891e939944b2220d9e2810e579f5",
"websnark": "git+https://github.com/tornadocontrib/websnark.git#e5a79cca905d1ffb61a69739492be58d438c9f17"
@ -74,7 +72,6 @@
"@types/circomlibjs": "^0.1.6",
"@types/mocha": "^10.0.10",
"@types/node": "^22.10.2",
"@types/node-fetch": "^2.6.12",
"chai": "^4.5.0",
"esbuild-loader": "^4.2.2",
"eslint": "^9.17.0",
@ -85,6 +82,7 @@
"fetch-mock": "^12.2.0",
"hardhat": "^2.22.17",
"hardhat-gas-reporter": "^2.2.2",
"idb": "^8.0.1",
"mocha": "^11.0.1",
"node-polyfill-webpack-plugin": "^4.1.0",
"nyc": "^17.1.0",

@ -76,7 +76,8 @@ export class ENSUtils {
async getContracts() {
const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
const { ensRegistry, ensPublicResolver, ensNameWrapper } =
EnsContracts[Number(chainId)] || EnsContracts[NetId.MAINNET];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);

@ -1098,7 +1098,7 @@ export async function getTovarishNetworks(registryService: BaseRegistryService,
'Content-Type': 'application/json',
},
timeout: 30000,
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0,
maxRetry: registryService.fetchDataOptions?.dispatcher ? 2 : 0,
});
} catch {
// Ignore error and disable relayer

@ -471,7 +471,7 @@ export class DBRegistryService extends BaseRegistryService {
const url = `${this.staticUrl}/relayers.json`;
try {
const resp = await fetchData(url, {
const resp = await fetchData<Response>(url, {
method: 'GET',
returnResponse: true,
});

@ -62,7 +62,8 @@ export async function queryGraph<T>({
}: queryGraphParams): Promise<T> {
const graphUrl = `${graphApi}/subgraphs/name/${subgraphName}`;
const { data, errors } = await fetchData(graphUrl, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { data, errors } = await fetchData<{ data: T & { _meta: any }; errors: any }>(graphUrl, {
...fetchDataOptions,
method: 'POST',
headers: {

@ -1,7 +1,14 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { openDB, deleteDB, OpenDBCallbacks, IDBPDatabase } from 'idb';
/* eslint-disable @typescript-eslint/no-explicit-any, import/no-duplicates */
import type * as idb from 'idb';
import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import { getConfig, NetIdType } from './networkConfig';
declare global {
interface Window {
idb: typeof idb;
}
}
export const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.';
export interface IDBIndex {
@ -64,7 +71,7 @@ export class IndexedDB {
return;
}
this.db = await openDB(this.dbName, this.dbVersion, this.options);
this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener('onupgradeneeded', async () => {
await this._removeExist();
});
@ -89,7 +96,7 @@ export class IndexedDB {
}
async _removeExist() {
await deleteDB(this.dbName);
await window?.idb?.deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();

@ -1,14 +1,17 @@
import { fetchData } from './providers';
import { fetchData, fetchDataOptions } from './providers';
export interface IPResult {
ip: string;
iso?: string;
country?: string;
country_iso?: string;
tor?: boolean;
}
export async function fetchIp(ipEcho: string) {
return (await fetchData(ipEcho, {
export function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions) {
return fetchData<IPResult>(ipEcho, {
...(fetchOptions || {}),
method: 'GET',
timeout: 30000,
})) as IPResult;
});
}

@ -46,17 +46,6 @@ export interface TornadoInstance {
export type TokenInstances = Record<string, TornadoInstance>;
export interface Config {
rpcCallRetryAttempt?: number;
// Should be in gwei
gasPrices: {
// fallback gasPrice / maxFeePerGas value
instant: number;
fast?: number;
standard?: number;
low?: number;
// fallback EIP-1559 params
maxPriorityFeePerGas?: number;
};
nativeCurrency: string;
currencyName: string;
explorerUrl: string;
@ -78,17 +67,17 @@ export interface Config {
aggregatorContract?: string;
reverseRecordsContract?: string;
ovmGasPriceOracleContract?: string;
tornadoSubgraph: string;
tornadoSubgraph?: string;
registrySubgraph?: string;
governanceSubgraph?: string;
subgraphs: SubgraphUrls;
subgraphs?: SubgraphUrls;
tokens: TokenInstances;
optionalTokens?: string[];
disabledTokens?: string[];
relayerEnsSubdomain: string;
// Should be in seconds
pollInterval: number;
constants: {
constants?: {
GOVERNANCE_BLOCK?: number;
NOTE_ACCOUNT_BLOCK?: number;
ENCRYPTED_NOTES_BLOCK?: number;
@ -104,13 +93,6 @@ export type SubdomainMap = Record<NetIdType, string>;
export const defaultConfig: networkConfig = {
[NetId.MAINNET]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 80,
fast: 50,
standard: 25,
low: 8,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://etherscan.io',
@ -123,9 +105,9 @@ export const defaultConfig: networkConfig = {
name: 'MEV Blocker',
url: 'https://rpc.mevblocker.io',
},
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/mainnet',
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/mainnet',
},
keydonix: {
name: 'Horswap ( Keydonix )',
@ -244,13 +226,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.BSC]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 3,
fast: 1,
standard: 1,
low: 1,
},
nativeCurrency: 'bnb',
currencyName: 'BNB',
explorerUrl: 'https://bscscan.com',
@ -274,9 +249,9 @@ export const defaultConfig: networkConfig = {
name: 'BNB Chain 2',
url: 'https://bsc-dataseed1.ninicoin.io',
},
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/bsc',
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/bsc',
},
nodereal: {
name: 'NodeReal',
@ -340,13 +315,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.POLYGON]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 60,
fast: 30,
standard: 30,
low: 30,
},
nativeCurrency: 'matic',
currencyName: 'MATIC',
explorerUrl: 'https://polygonscan.com',
@ -362,9 +330,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/matic-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/polygon',
lavaBuild: {
name: 'polygon.lava.build',
url: 'https://polygon.lava.build',
},
polygon: {
name: 'Polygon',
@ -399,13 +367,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.OPTIMISM]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.001,
fast: 0.001,
standard: 0.001,
low: 0.001,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://optimistic.etherscan.io',
@ -422,9 +383,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/op',
lavaBuild: {
name: 'optimism.lava.build',
url: 'https://optimism.lava.build',
},
optimism: {
name: 'Optimism',
@ -462,13 +423,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.ARBITRUM]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.02,
fast: 0.02,
standard: 0.02,
low: 0.02,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://arbiscan.io',
@ -488,10 +442,6 @@ export const defaultConfig: networkConfig = {
name: 'Arbitrum',
url: 'https://arb1.arbitrum.io/rpc',
},
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/arbitrum',
},
stackup: {
name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/arbitrum-one',
@ -524,13 +474,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.BASE]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.1,
fast: 0.06,
standard: 0.05,
low: 0.02,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://basescan.org',
@ -551,10 +494,6 @@ export const defaultConfig: networkConfig = {
name: 'Base',
url: 'https://mainnet.base.org',
},
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/base',
},
stackup: {
name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/base-mainnet',
@ -616,13 +555,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.BLAST]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.001,
fast: 0.001,
standard: 0.001,
low: 0.001,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://blastscan.io',
@ -642,10 +574,6 @@ export const defaultConfig: networkConfig = {
name: 'Blast',
url: 'https://rpc.blast.io',
},
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/blast',
},
blastApi: {
name: 'BlastApi',
url: 'https://blastl2-mainnet.public.blastapi.io',
@ -673,13 +601,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.GNOSIS]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 6,
fast: 5,
standard: 4,
low: 1,
},
nativeCurrency: 'xdai',
currencyName: 'xDAI',
explorerUrl: 'https://gnosisscan.io',
@ -699,9 +620,13 @@ export const defaultConfig: networkConfig = {
name: 'Gnosis',
url: 'https://rpc.gnosischain.com',
},
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/gnosis',
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/gnosis',
},
blastApi: {
name: 'BlastApi',
url: 'https://gnosis-mainnet.public.blastapi.io',
},
oneRpc: {
name: '1RPC',
@ -728,13 +653,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.AVALANCHE]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 225,
fast: 35,
standard: 25,
low: 25,
},
nativeCurrency: 'avax',
currencyName: 'AVAX',
explorerUrl: 'https://snowtrace.io',
@ -750,9 +668,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/ext/bc/C/rpc',
blastApi: {
name: 'BlastApi',
url: 'https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc',
},
oneRpc: {
name: '1RPC',
@ -786,13 +704,6 @@ export const defaultConfig: networkConfig = {
},
},
[NetId.SEPOLIA]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 2,
fast: 2,
standard: 2,
low: 2,
},
nativeCurrency: 'eth',
currencyName: 'SepoliaETH',
explorerUrl: 'https://sepolia.etherscan.io',
@ -814,9 +725,13 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/sepolia',
blastApi: {
name: 'BlastApi',
url: 'https://eth-sepolia.public.blastapi.io',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/sepolia',
},
oneRpc: {
name: '1RPC',
@ -932,17 +847,6 @@ export function getActiveTokens(config: Config): string[] {
return Object.keys(tokens).filter((t) => !disabledTokens?.includes(t));
}
export function getActiveTokenInstances(config: Config): TokenInstances {
const { tokens, disabledTokens } = config;
return Object.entries(tokens).reduce((acc, [token, instances]) => {
if (!disabledTokens?.includes(token)) {
acc[token] = instances;
}
return acc;
}, {} as TokenInstances);
}
export function getInstanceByAddress(config: Config, address: string) {
const { tokens, disabledTokens } = config;

@ -1,6 +1,4 @@
import type { EventEmitter } from 'stream';
import type { RequestOptions } from 'http';
import crossFetch from 'cross-fetch';
import {
FetchRequest,
JsonRpcApiProvider,
@ -20,10 +18,13 @@ import {
EnsPlugin,
GasCostPlugin,
FetchCancelSignal,
resolveProperties,
TransactionLike,
FetchUrlFeeDataNetworkPlugin,
FeeData,
} from 'ethers';
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
// Temporary workaround until @types/node-fetch is compatible with @types/node
import type { AbortSignal as FetchAbortSignal } from 'node-fetch/externals';
import type { Dispatcher, RequestInit, fetch as undiciFetch } from 'undici-types';
import { isNode, sleep } from './utils';
import type { Config, NetIdType } from './networkConfig';
@ -36,73 +37,34 @@ declare global {
// Update this for every Tor Browser release
export const defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0';
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export type DispatcherFunc = (retry?: number) => Dispatcher;
export type fetchDataOptions = RequestInit & {
export interface fetchDataOptions extends Omit<RequestInit, 'headers'> {
/**
* Overriding RequestInit params
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
headers?: HeadersInit | any;
/**
* Expanding RequestInit params
*/
maxRetry?: number;
retryOn?: number;
userAgent?: string;
timeout?: number;
proxy?: string;
torPort?: number;
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
debug?: Function;
returnResponse?: boolean;
cancelSignal?: FetchCancelSignal;
};
export type NodeAgent = RequestOptions['agent'] | ((parsedUrl: URL) => RequestOptions['agent']);
export function getHttpAgent({
fetchUrl,
proxyUrl,
torPort,
retry,
}: {
fetchUrl: string;
proxyUrl?: string;
torPort?: number;
retry: number;
}): NodeAgent | undefined {
/* eslint-disable @typescript-eslint/no-require-imports */
const { HttpProxyAgent } = require('http-proxy-agent');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { SocksProxyAgent } = require('socks-proxy-agent');
/* eslint-enable @typescript-eslint/no-require-imports */
if (torPort) {
return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
}
if (!proxyUrl) {
return;
}
const isHttps = fetchUrl.includes('https://');
if (proxyUrl.includes('socks://') || proxyUrl.includes('socks4://') || proxyUrl.includes('socks5://')) {
return new SocksProxyAgent(proxyUrl);
}
if (proxyUrl.includes('http://') || proxyUrl.includes('https://')) {
if (isHttps) {
return new HttpsProxyAgent(proxyUrl);
}
return new HttpProxyAgent(proxyUrl);
}
dispatcherFunc?: DispatcherFunc;
}
export async function fetchData(url: string, options: fetchDataOptions = {}) {
export async function fetchData<T>(url: string, options: fetchDataOptions = {}): Promise<T> {
const MAX_RETRY = options.maxRetry ?? 3;
const RETRY_ON = options.retryOn ?? 500;
const userAgent = options.userAgent ?? defaultUserAgent;
const fetch = ((globalThis as unknown as { useGlobalFetch?: boolean }).useGlobalFetch
? globalThis.fetch
: crossFetch) as unknown as nodeFetch;
let retry = 0;
let errorObject;
@ -122,14 +84,17 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
options.headers['User-Agent'] = userAgent;
}
if (typeof globalThis.fetch !== 'function') {
throw new Error('Fetch API is not available, use latest browser or nodejs installation!');
}
while (retry < MAX_RETRY + 1) {
let timeout;
if (!options.signal && options.timeout) {
const controller = new AbortController();
// Temporary workaround until @types/node-fetch is compatible with @types/node
options.signal = controller.signal as FetchAbortSignal;
options.signal = controller.signal;
// Define timeout in seconds
timeout = setTimeout(() => {
@ -149,16 +114,7 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
}
}
if (!options.agent && isNode && (options.proxy || options.torPort)) {
options.agent = getHttpAgent({
fetchUrl: url,
proxyUrl: options.proxy,
torPort: options.torPort,
retry,
});
}
if (options.debug && typeof options.debug === 'function') {
if (typeof options.debug === 'function') {
options.debug('request', {
url,
retry,
@ -168,13 +124,11 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
}
try {
const resp = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.body,
redirect: options.redirect,
signal: options.signal,
agent: options.agent,
const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
const resp = await (globalThis.fetch as unknown as typeof undiciFetch)(url, {
...options,
dispatcher,
});
if (options.debug && typeof options.debug === 'function') {
@ -187,23 +141,23 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
}
if (options.returnResponse) {
return resp;
return resp as T;
}
const contentType = resp.headers.get('content-type');
// If server returns JSON object, parse it and return as an object
if (contentType?.includes('application/json')) {
return await resp.json();
return (await resp.json()) as T;
}
// Else if the server returns text parse it as a string
if (contentType?.includes('text')) {
return await resp.text();
return (await resp.text()) as T;
}
// Return as a response object https://developer.mozilla.org/en-US/docs/Web/API/Response
return resp;
return resp as T;
} catch (error) {
if (timeout) {
clearTimeout(timeout);
@ -242,7 +196,7 @@ export const fetchGetUrlFunc =
returnResponse: true,
};
const resp = await fetchData(req.url, init);
const resp = await fetchData<Response>(req.url, init);
const headers = {} as Record<string, any>;
resp.headers.forEach((value: any, key: string) => {
@ -267,20 +221,36 @@ export type getProviderOptions = fetchDataOptions & {
pollingInterval?: number;
};
export const FeeDataNetworkPluginName = new FetchUrlFeeDataNetworkPlugin(
'',
() => new Promise((resolve) => resolve(new FeeData())),
).name;
export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider> {
// Use our own fetchGetUrlFunc to support proxies and retries
const fetchReq = new FetchRequest(rpcUrl);
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
const staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const fetchedNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(staticNetwork.chainId);
// Audit if we are connected to right network
const chainId = Number(fetchedNetwork.chainId);
if (fetchOptions?.netId && fetchOptions.netId !== chainId) {
const errMsg = `Wrong network for ${rpcUrl}, wants ${fetchOptions.netId} got ${chainId}`;
throw new Error(errMsg);
}
// Clone to new network to exclude polygon gas station plugin
const staticNetwork = new Network(fetchedNetwork.name, fetchedNetwork.chainId);
fetchedNetwork.plugins.forEach((plugin) => {
if (plugin.name !== FeeDataNetworkPluginName) {
staticNetwork.attachPlugin(plugin.clone());
}
});
return new JsonRpcProvider(fetchReq, staticNetwork, {
staticNetwork,
pollingInterval: fetchOptions?.pollingInterval || 1000,
@ -327,7 +297,7 @@ export const populateTransaction = async (
const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(),
tx.nonce ? undefined : provider.getTransactionCount(signer.address, 'pending'),
tx.nonce || tx.nonce === 0 ? undefined : provider.getTransactionCount(signer.address, 'pending'),
]);
if (feeData) {
@ -350,7 +320,7 @@ export const populateTransaction = async (
}
}
if (nonce) {
if (nonce || nonce === 0) {
tx.nonce = nonce;
}
@ -373,7 +343,7 @@ export const populateTransaction = async (
}
}
return tx;
return resolveProperties(tx);
};
export interface TornadoWalletOptions {
@ -414,8 +384,7 @@ export class TornadoWallet extends Wallet {
async populateTransaction(tx: TransactionRequest) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return super.populateTransaction(txObject);
return txObject as Promise<TransactionLike<string>>;
}
}
@ -443,8 +412,7 @@ export class TornadoVoidSigner extends VoidSigner {
async populateTransaction(tx: TransactionRequest) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return super.populateTransaction(txObject);
return txObject as Promise<TransactionLike<string>>;
}
}

@ -1,6 +1,6 @@
import { getAddress, parseEther } from 'ethers';
import { sleep } from './utils';
import { NetId, NetIdType, Config } from './networkConfig';
import { NetIdType, Config } from './networkConfig';
import { fetchData, fetchDataOptions } from './providers';
import { ajv, jobsSchema, jobRequestSchema, getStatusSchema } from './schemas';
import type { snarkProofs } from './websnark';
@ -196,13 +196,10 @@ export class RelayerClient {
async askRelayerStatus({
hostname,
url,
relayerAddress,
}: {
hostname?: string;
// optional url if entered manually
url?: string;
// relayerAddress from registry contract to prevent cheating
relayerAddress?: string;
}): Promise<RelayerStatus> {
if (!url && hostname) {
url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
@ -212,14 +209,14 @@ export class RelayerClient {
url = '';
}
const rawStatus = (await fetchData(`${url}status`, {
const rawStatus = await fetchData<RelayerStatus>(`${url}status`, {
...this.fetchDataOptions,
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded',
},
timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object;
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0,
});
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
@ -240,9 +237,11 @@ export class RelayerClient {
throw new Error('This relayer serves a different network');
}
/**
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error('The Relayer reward address must match registered address');
}
**/
return status;
}
@ -258,7 +257,6 @@ export class RelayerClient {
try {
const status = await this.askRelayerStatus({
hostname,
relayerAddress,
});
return {
@ -325,7 +323,7 @@ export class RelayerClient {
* Request new job
*/
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
const withdrawResponse = await fetchData<RelayerTornadoWithdraw>(`${url}v1/tornadoWithdraw`, {
...this.fetchDataOptions,
method: 'POST',
headers: {
@ -336,7 +334,7 @@ export class RelayerClient {
proof,
args,
}),
})) as RelayerTornadoWithdraw;
});
const { id, error } = withdrawResponse;
@ -366,7 +364,7 @@ export class RelayerClient {
console.log(`Job submitted: ${jobUrl}\n`);
while (!relayerStatus || !['FAILED', 'CONFIRMED'].includes(relayerStatus)) {
const jobResponse = await fetchData(jobUrl, {
const jobResponse = await fetchData<RelayerTornadoJobs>(jobUrl, {
...this.fetchDataOptions,
method: 'GET',
headers: {
@ -385,7 +383,7 @@ export class RelayerClient {
throw new Error(errMsg);
}
const { status, txHash, confirmations, failedReason } = jobResponse as unknown as RelayerTornadoJobs;
const { status, txHash, confirmations, failedReason } = jobResponse;
if (relayerStatus !== status) {
if (status === 'FAILED') {

@ -78,7 +78,6 @@ export class TovarishClient extends RelayerClient {
async askRelayerStatus({
hostname,
url,
relayerAddress,
}: {
hostname?: string;
// optional url if entered manually
@ -89,7 +88,6 @@ export class TovarishClient extends RelayerClient {
const status = (await super.askRelayerStatus({
hostname,
url,
relayerAddress,
})) as TovarishStatus;
if (!status.version.includes('tovarish')) {
@ -121,14 +119,14 @@ export class TovarishClient extends RelayerClient {
url = '';
}
const statusArray = (await fetchData(`${url}status`, {
const statusArray = await fetchData<TovarishStatus[]>(`${url}status`, {
...this.fetchDataOptions,
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded',
},
timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object;
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0,
});
if (!Array.isArray(statusArray)) {
return [];
@ -137,27 +135,19 @@ export class TovarishClient extends RelayerClient {
const tovarishStatus: TovarishStatus[] = [];
for (const rawStatus of statusArray) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const netId = (rawStatus as any).netId as NetIdType;
const netId = rawStatus?.netId as NetIdType;
const config = getConfig(netId);
const statusValidator = ajv.compile(
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(rawStatus as any).netId,
config,
this.tovarish,
),
);
const statusValidator = ajv.compile(getStatusSchema(rawStatus?.netId, config, this.tovarish));
if (!statusValidator) {
if (!statusValidator(rawStatus)) {
continue;
}
const status = {
...rawStatus,
url: `${url}${netId}/`,
} as TovarishStatus;
};
if (status.currentQueue > 5) {
throw new Error('Withdrawal queue is overloaded');

@ -1,5 +1,15 @@
import { zip, unzip, AsyncZippable, Unzipped, ZipAttributes } from 'fflate';
import { fetchData } from './providers';
import {
zip,
unzip,
AsyncZippable,
Unzipped,
ZipAttributes,
zlib,
unzlib,
AsyncZlibOptions,
AsyncUnzlibOptions,
} from 'fflate';
import { fetchData, fetchDataOptions } from './providers';
import { bytesToBase64, digest } from './utils';
export function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array> {
@ -26,20 +36,47 @@ export function unzipAsync(data: Uint8Array): Promise<Unzipped> {
});
}
export function zlibAsync(data: Uint8Array, options?: AsyncZlibOptions): Promise<Uint8Array> {
return new Promise((res, rej) => {
zlib(data, { ...(options || {}) }, (err, data) => {
if (err) {
rej(err);
return;
}
res(data);
});
});
}
export function unzlibAsync(data: Uint8Array, options?: AsyncUnzlibOptions): Promise<Uint8Array> {
return new Promise((res, rej) => {
unzlib(data, { ...(options || {}) }, (err, data) => {
if (err) {
rej(err);
return;
}
res(data);
});
});
}
export async function downloadZip<T>({
staticUrl = '',
zipName,
zipDigest,
parseJson = true,
fetchOptions,
}: {
staticUrl?: string;
zipName: string;
zipDigest?: string;
parseJson?: boolean;
fetchOptions?: fetchDataOptions;
}): Promise<T> {
const url = `${staticUrl}/${zipName}.zip`;
const resp = (await fetchData(url, {
...(fetchOptions || {}),
method: 'GET',
returnResponse: true,
})) as Response;

@ -1,4 +1,4 @@
const { BannerPlugin } = require('webpack');
const { BannerPlugin, ProvidePlugin } = require('webpack');
const path = require('path');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
@ -46,11 +46,18 @@ module.exports = [
},
plugins: [
new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
],
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
}
},
optimization: {
@ -71,11 +78,18 @@ module.exports = [
},
plugins: [
new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
],
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
}
},
},
@ -92,6 +106,10 @@ module.exports = [
},
plugins: [
new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
new BannerPlugin({
banner: 'globalThis.process = { browser: true, env: {}, };\n',
raw: true,
@ -101,6 +119,9 @@ module.exports = [
extensions: ['.tsx', '.ts', '.js'],
alias: {
...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
}
},
optimization: {
@ -120,6 +141,10 @@ module.exports = [
},
plugins: [
new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
new BannerPlugin({
banner: 'globalThis.process = { browser: true, env: {}, };',
raw: true,
@ -129,6 +154,9 @@ module.exports = [
extensions: ['.tsx', '.ts', '.js'],
alias: {
...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
}
},
},

@ -1440,14 +1440,6 @@
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433"
integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
"@types/node-fetch@^2.6.12":
version "2.6.12"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03"
integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==
dependencies:
"@types/node" "*"
form-data "^4.0.0"
"@types/node@*":
version "22.5.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44"
@ -2665,13 +2657,6 @@ create-require@^1.1.0, create-require@^1.1.1:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-fetch@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.1.0.tgz#8f69355007ee182e47fa692ecbaa37a52e43c3d2"
integrity sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==
dependencies:
node-fetch "^2.7.0"
cross-spawn@^7.0.0, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -5125,13 +5110,6 @@ node-emoji@^1.10.0:
dependencies:
lodash "^4.17.21"
node-fetch@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
dependencies:
whatwg-url "^5.0.0"
node-gyp-build@^4.2.0, node-gyp-build@^4.2.2:
version "4.8.2"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa"
@ -6502,11 +6480,6 @@ toidentifier@1.0.1:
"@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0"
ethers "^6.13.4"
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
ts-api-utils@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
@ -6921,11 +6894,6 @@ web3-utils@^1.3.6:
randombytes "^2.1.0"
utf8 "3.0.0"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
webpack-cli@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-6.0.1.tgz#a1ce25da5ba077151afd73adfa12e208e5089207"
@ -7002,14 +6970,6 @@ webpack@^5.97.1:
dependencies:
big-integer "1.6.52"
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"