Compare commits

..

No commits in common. "d688f8a2b537f3bfda237b67573b409bad989d33" and "e19f5a1373bfc3d176890de9359840a496467539" have entirely different histories.

29 changed files with 2222 additions and 1239 deletions

View File

@ -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=0aa9f0038354412e01b171df7dcff96b1c55976c
ENV GIT_COMMIT_HASH=5bfef2a2ae887b4cc065af34b6ea106fc3cacde1
# clone the repository
RUN mkdir /app/

12
dist/hashes.json vendored
View File

@ -1,11 +1,11 @@
{
"dist/index.js": "sha384-iQ5shLTi2Nyi35ciUUQRXg2JSgjBguTRXafhYVZuuAyJug9BAXZIWYEwupPOUcCo",
"dist/index.mjs": "sha384-Lx8Qc+R6ak1AaPmSKJ06+EYyFuVF8gI7E+IvBFItO+3Yoc+JmsunEmytkd7mhSQt",
"dist/index.js": "sha384-DMBnRJIMRwGIEYdgWy5NptEFmOmmB4DrUWvVNf60ZUMHDWnuHdogrjx1dkCSOWtN",
"dist/index.mjs": "sha384-3zq911CcPyyFDXeBw8eByPFafkAn/CA5zHaBTQnpU7wIXczHIYYMBvb9GN3ugnd/",
"dist/merkleTreeWorker.js": "sha384-gib4Z6KDvYxUpNTSc4YA2dX5FxaQe2FiorGkBJJDfm86tXdT+57T2Gt+ti6YXTeX",
"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/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/tornadoContracts.umd.js": "sha384-Gmawcz/XTH7WFUFnMJKPUCy2zrjDOhf/DtSv9xfHBulPyCEJwI70Hw+n7E1Y60EU",
"dist/tornadoContracts.umd.min.js": "sha384-Sclkp3xkhjmDekfQaQFkgUctmauYUF7ieeyyFhFBnwAzyp2eFBS5qzxvOIBhlJza"
}

8
dist/idb.d.ts vendored
View File

@ -1,11 +1,5 @@
import type * as idb from 'idb';
import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import { 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
View File

@ -5,10 +5,12 @@ 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');
@ -517,10 +519,37 @@ 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) {
@ -536,9 +565,6 @@ 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) {
@ -556,7 +582,15 @@ async function fetchData(url, options = {}) {
});
}
}
if (typeof options.debug === "function") {
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") {
options.debug("request", {
url,
retry,
@ -565,10 +599,13 @@ async function fetchData(url, options = {}) {
});
}
try {
const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
const resp = await globalThis.fetch(url, {
...options,
dispatcher
const resp = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.body,
redirect: options.redirect,
signal: options.signal,
agent: options.agent
});
if (options.debug && typeof options.debug === "function") {
options.debug("response", resp);
@ -631,25 +668,15 @@ 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 fetchedNetwork = await new ethers.JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(fetchedNetwork.chainId);
const staticNetwork = await new ethers.JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(staticNetwork.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
@ -681,7 +708,7 @@ const populateTransaction = async (signer, tx) => {
}
const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? void 0 : provider.getFeeData(),
tx.nonce || tx.nonce === 0 ? void 0 : provider.getTransactionCount(signer.address, "pending")
tx.nonce ? void 0 : provider.getTransactionCount(signer.address, "pending")
]);
if (feeData) {
if (feeData.maxFeePerGas) {
@ -700,7 +727,7 @@ const populateTransaction = async (signer, tx) => {
delete tx.maxPriorityFeePerGas;
}
}
if (nonce || nonce === 0) {
if (nonce) {
tx.nonce = nonce;
}
if (!tx.gasLimit) {
@ -716,7 +743,7 @@ const populateTransaction = async (signer, tx) => {
}
}
}
return ethers.resolveProperties(tx);
return tx;
};
class TornadoWallet extends ethers.Wallet {
nonce;
@ -739,7 +766,7 @@ class TornadoWallet extends ethers.Wallet {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return txObject;
return super.populateTransaction(txObject);
}
}
class TornadoVoidSigner extends ethers.VoidSigner {
@ -758,7 +785,7 @@ class TornadoVoidSigner extends ethers.VoidSigner {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return txObject;
return super.populateTransaction(txObject);
}
}
class TornadoRpcSigner extends ethers.JsonRpcSigner {
@ -819,6 +846,13 @@ 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",
@ -831,9 +865,9 @@ const defaultConfig = {
name: "MEV Blocker",
url: "https://rpc.mevblocker.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/mainnet"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/mainnet"
},
keydonix: {
name: "Horswap ( Keydonix )",
@ -952,6 +986,13 @@ const defaultConfig = {
}
},
[56 /* BSC */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 3,
fast: 1,
standard: 1,
low: 1
},
nativeCurrency: "bnb",
currencyName: "BNB",
explorerUrl: "https://bscscan.com",
@ -975,9 +1016,9 @@ const defaultConfig = {
name: "BNB Chain 2",
url: "https://bsc-dataseed1.ninicoin.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/bsc"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/bsc"
},
nodereal: {
name: "NodeReal",
@ -1041,6 +1082,13 @@ const defaultConfig = {
}
},
[137 /* POLYGON */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 60,
fast: 30,
standard: 30,
low: 30
},
nativeCurrency: "matic",
currencyName: "MATIC",
explorerUrl: "https://polygonscan.com",
@ -1056,9 +1104,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/matic-tornado-subgraph",
subgraphs: {},
rpcUrls: {
lavaBuild: {
name: "polygon.lava.build",
url: "https://polygon.lava.build"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/polygon"
},
polygon: {
name: "Polygon",
@ -1093,6 +1141,13 @@ 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",
@ -1109,9 +1164,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/optimism-tornado-subgraph",
subgraphs: {},
rpcUrls: {
lavaBuild: {
name: "optimism.lava.build",
url: "https://optimism.lava.build"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/op"
},
optimism: {
name: "Optimism",
@ -1149,6 +1204,13 @@ 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",
@ -1168,6 +1230,10 @@ 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"
@ -1200,6 +1266,13 @@ 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",
@ -1220,6 +1293,10 @@ 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"
@ -1281,6 +1358,13 @@ 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",
@ -1300,6 +1384,10 @@ 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"
@ -1327,6 +1415,13 @@ const defaultConfig = {
}
},
[100 /* GNOSIS */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 6,
fast: 5,
standard: 4,
low: 1
},
nativeCurrency: "xdai",
currencyName: "xDAI",
explorerUrl: "https://gnosisscan.io",
@ -1346,13 +1441,9 @@ const defaultConfig = {
name: "Gnosis",
url: "https://rpc.gnosischain.com"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/gnosis"
},
blastApi: {
name: "BlastApi",
url: "https://gnosis-mainnet.public.blastapi.io"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/gnosis"
},
oneRpc: {
name: "1RPC",
@ -1379,6 +1470,13 @@ const defaultConfig = {
}
},
[43114 /* AVALANCHE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 225,
fast: 35,
standard: 25,
low: 25
},
nativeCurrency: "avax",
currencyName: "AVAX",
explorerUrl: "https://snowtrace.io",
@ -1394,9 +1492,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/avalanche-tornado-subgraph",
subgraphs: {},
rpcUrls: {
blastApi: {
name: "BlastApi",
url: "https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/ext/bc/C/rpc"
},
oneRpc: {
name: "1RPC",
@ -1430,6 +1528,13 @@ const defaultConfig = {
}
},
[11155111 /* SEPOLIA */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 2,
fast: 2,
standard: 2,
low: 2
},
nativeCurrency: "eth",
currencyName: "SepoliaETH",
explorerUrl: "https://sepolia.etherscan.io",
@ -1451,13 +1556,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph",
subgraphs: {},
rpcUrls: {
blastApi: {
name: "BlastApi",
url: "https://eth-sepolia.public.blastapi.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/sepolia"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/sepolia"
},
oneRpc: {
name: "1RPC",
@ -1546,6 +1647,15 @@ 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)) {
@ -2115,7 +2225,8 @@ class RelayerClient {
}
async askRelayerStatus({
hostname,
url
url,
relayerAddress
}) {
if (!url && hostname) {
url = `https://${!hostname.endsWith("/") ? hostname + "/" : hostname}`;
@ -2130,7 +2241,7 @@ class RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0
});
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
if (!statusValidator(rawStatus)) {
@ -2146,6 +2257,9 @@ 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) {
@ -2156,7 +2270,8 @@ class RelayerClient {
}
try {
const status = await this.askRelayerStatus({
hostname
hostname,
relayerAddress
});
return {
netId: status.netId,
@ -3060,7 +3175,7 @@ async function getTovarishNetworks(registryService, relayers) {
"Content-Type": "application/json"
},
timeout: 3e4,
maxRetry: registryService.fetchDataOptions?.dispatcher ? 2 : 0
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0
});
} catch {
relayer.tovarishNetworks = [];
@ -3389,38 +3504,14 @@ 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,
fetchOptions
parseJson = true
}) {
const url = `${staticUrl}/${zipName}.zip`;
const resp = await fetchData(url, {
...fetchOptions || {},
method: "GET",
returnResponse: true
});
@ -9499,7 +9590,7 @@ class ENSUtils {
}
async getContracts() {
const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)] || EnsContracts[NetId.MAINNET];
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);
this.ENSNameWrapper = ENSNameWrapper__factory.connect(ensNameWrapper, this.provider);
@ -9743,7 +9834,7 @@ class IndexedDB {
if (this.dbExists || this.isBlocked) {
return;
}
this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db = await idb.openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener("onupgradeneeded", async () => {
await this._removeExist();
});
@ -9763,7 +9854,7 @@ class IndexedDB {
}
}
async _removeExist() {
await window?.idb?.deleteDB(this.dbName);
await idb.deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();
}
@ -10069,9 +10160,8 @@ async function getIndexedDB(netId) {
return idb;
}
function fetchIp(ipEcho, fetchOptions) {
return fetchData(ipEcho, {
...fetchOptions || {},
async function fetchIp(ipEcho) {
return await fetchData(ipEcho, {
method: "GET",
timeout: 3e4
});
@ -10456,11 +10546,13 @@ class TovarishClient extends RelayerClient {
}
async askRelayerStatus({
hostname,
url
url,
relayerAddress
}) {
const status = await super.askRelayerStatus({
hostname,
url
url,
relayerAddress
});
if (!status.version.includes("tovarish")) {
throw new Error("Not a tovarish relayer!");
@ -10488,17 +10580,24 @@ class TovarishClient extends RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
maxRetry: this.fetchDataOptions?.torPort ? 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(rawStatus?.netId, config, this.tovarish));
if (!statusValidator(rawStatus)) {
const statusValidator = ajv.compile(
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rawStatus.netId,
config,
this.tovarish
)
);
if (!statusValidator) {
continue;
}
const status = {
@ -10764,7 +10863,6 @@ 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;
@ -10829,9 +10927,11 @@ 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;
@ -10886,8 +10986,6 @@ 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
View File

@ -1,12 +1,14 @@
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 { 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 { 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, zlib, unzlib } from 'fflate';
import { zip, unzip } 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';
@ -495,10 +497,37 @@ 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) {
@ -514,9 +543,6 @@ 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) {
@ -534,7 +560,15 @@ async function fetchData(url, options = {}) {
});
}
}
if (typeof options.debug === "function") {
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") {
options.debug("request", {
url,
retry,
@ -543,10 +577,13 @@ async function fetchData(url, options = {}) {
});
}
try {
const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
const resp = await globalThis.fetch(url, {
...options,
dispatcher
const resp = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.body,
redirect: options.redirect,
signal: options.signal,
agent: options.agent
});
if (options.debug && typeof options.debug === "function") {
options.debug("response", resp);
@ -609,25 +646,15 @@ 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 fetchedNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(fetchedNetwork.chainId);
const staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(staticNetwork.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
@ -659,7 +686,7 @@ const populateTransaction = async (signer, tx) => {
}
const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? void 0 : provider.getFeeData(),
tx.nonce || tx.nonce === 0 ? void 0 : provider.getTransactionCount(signer.address, "pending")
tx.nonce ? void 0 : provider.getTransactionCount(signer.address, "pending")
]);
if (feeData) {
if (feeData.maxFeePerGas) {
@ -678,7 +705,7 @@ const populateTransaction = async (signer, tx) => {
delete tx.maxPriorityFeePerGas;
}
}
if (nonce || nonce === 0) {
if (nonce) {
tx.nonce = nonce;
}
if (!tx.gasLimit) {
@ -694,7 +721,7 @@ const populateTransaction = async (signer, tx) => {
}
}
}
return resolveProperties(tx);
return tx;
};
class TornadoWallet extends Wallet {
nonce;
@ -717,7 +744,7 @@ class TornadoWallet extends Wallet {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return txObject;
return super.populateTransaction(txObject);
}
}
class TornadoVoidSigner extends VoidSigner {
@ -736,7 +763,7 @@ class TornadoVoidSigner extends VoidSigner {
async populateTransaction(tx) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return txObject;
return super.populateTransaction(txObject);
}
}
class TornadoRpcSigner extends JsonRpcSigner {
@ -797,6 +824,13 @@ 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",
@ -809,9 +843,9 @@ const defaultConfig = {
name: "MEV Blocker",
url: "https://rpc.mevblocker.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/mainnet"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/mainnet"
},
keydonix: {
name: "Horswap ( Keydonix )",
@ -930,6 +964,13 @@ const defaultConfig = {
}
},
[56 /* BSC */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 3,
fast: 1,
standard: 1,
low: 1
},
nativeCurrency: "bnb",
currencyName: "BNB",
explorerUrl: "https://bscscan.com",
@ -953,9 +994,9 @@ const defaultConfig = {
name: "BNB Chain 2",
url: "https://bsc-dataseed1.ninicoin.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/bsc"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/bsc"
},
nodereal: {
name: "NodeReal",
@ -1019,6 +1060,13 @@ const defaultConfig = {
}
},
[137 /* POLYGON */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 60,
fast: 30,
standard: 30,
low: 30
},
nativeCurrency: "matic",
currencyName: "MATIC",
explorerUrl: "https://polygonscan.com",
@ -1034,9 +1082,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/matic-tornado-subgraph",
subgraphs: {},
rpcUrls: {
lavaBuild: {
name: "polygon.lava.build",
url: "https://polygon.lava.build"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/polygon"
},
polygon: {
name: "Polygon",
@ -1071,6 +1119,13 @@ 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",
@ -1087,9 +1142,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/optimism-tornado-subgraph",
subgraphs: {},
rpcUrls: {
lavaBuild: {
name: "optimism.lava.build",
url: "https://optimism.lava.build"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/op"
},
optimism: {
name: "Optimism",
@ -1127,6 +1182,13 @@ 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",
@ -1146,6 +1208,10 @@ 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"
@ -1178,6 +1244,13 @@ 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",
@ -1198,6 +1271,10 @@ 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"
@ -1259,6 +1336,13 @@ 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",
@ -1278,6 +1362,10 @@ 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"
@ -1305,6 +1393,13 @@ const defaultConfig = {
}
},
[100 /* GNOSIS */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 6,
fast: 5,
standard: 4,
low: 1
},
nativeCurrency: "xdai",
currencyName: "xDAI",
explorerUrl: "https://gnosisscan.io",
@ -1324,13 +1419,9 @@ const defaultConfig = {
name: "Gnosis",
url: "https://rpc.gnosischain.com"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/gnosis"
},
blastApi: {
name: "BlastApi",
url: "https://gnosis-mainnet.public.blastapi.io"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/gnosis"
},
oneRpc: {
name: "1RPC",
@ -1357,6 +1448,13 @@ const defaultConfig = {
}
},
[43114 /* AVALANCHE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 225,
fast: 35,
standard: 25,
low: 25
},
nativeCurrency: "avax",
currencyName: "AVAX",
explorerUrl: "https://snowtrace.io",
@ -1372,9 +1470,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/avalanche-tornado-subgraph",
subgraphs: {},
rpcUrls: {
blastApi: {
name: "BlastApi",
url: "https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/ext/bc/C/rpc"
},
oneRpc: {
name: "1RPC",
@ -1408,6 +1506,13 @@ const defaultConfig = {
}
},
[11155111 /* SEPOLIA */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 2,
fast: 2,
standard: 2,
low: 2
},
nativeCurrency: "eth",
currencyName: "SepoliaETH",
explorerUrl: "https://sepolia.etherscan.io",
@ -1429,13 +1534,9 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph",
subgraphs: {},
rpcUrls: {
blastApi: {
name: "BlastApi",
url: "https://eth-sepolia.public.blastapi.io"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/sepolia"
tornadoWithdraw: {
name: "Tornado Withdraw",
url: "https://tornadowithdraw.com/sepolia"
},
oneRpc: {
name: "1RPC",
@ -1524,6 +1625,15 @@ 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)) {
@ -2093,7 +2203,8 @@ class RelayerClient {
}
async askRelayerStatus({
hostname,
url
url,
relayerAddress
}) {
if (!url && hostname) {
url = `https://${!hostname.endsWith("/") ? hostname + "/" : hostname}`;
@ -2108,7 +2219,7 @@ class RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0
});
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
if (!statusValidator(rawStatus)) {
@ -2124,6 +2235,9 @@ 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) {
@ -2134,7 +2248,8 @@ class RelayerClient {
}
try {
const status = await this.askRelayerStatus({
hostname
hostname,
relayerAddress
});
return {
netId: status.netId,
@ -3038,7 +3153,7 @@ async function getTovarishNetworks(registryService, relayers) {
"Content-Type": "application/json"
},
timeout: 3e4,
maxRetry: registryService.fetchDataOptions?.dispatcher ? 2 : 0
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0
});
} catch {
relayer.tovarishNetworks = [];
@ -3367,38 +3482,14 @@ 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,
fetchOptions
parseJson = true
}) {
const url = `${staticUrl}/${zipName}.zip`;
const resp = await fetchData(url, {
...fetchOptions || {},
method: "GET",
returnResponse: true
});
@ -9477,7 +9568,7 @@ class ENSUtils {
}
async getContracts() {
const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)] || EnsContracts[NetId.MAINNET];
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);
this.ENSNameWrapper = ENSNameWrapper__factory.connect(ensNameWrapper, this.provider);
@ -9721,7 +9812,7 @@ class IndexedDB {
if (this.dbExists || this.isBlocked) {
return;
}
this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db = await openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener("onupgradeneeded", async () => {
await this._removeExist();
});
@ -9741,7 +9832,7 @@ class IndexedDB {
}
}
async _removeExist() {
await window?.idb?.deleteDB(this.dbName);
await deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();
}
@ -10047,9 +10138,8 @@ async function getIndexedDB(netId) {
return idb;
}
function fetchIp(ipEcho, fetchOptions) {
return fetchData(ipEcho, {
...fetchOptions || {},
async function fetchIp(ipEcho) {
return await fetchData(ipEcho, {
method: "GET",
timeout: 3e4
});
@ -10434,11 +10524,13 @@ class TovarishClient extends RelayerClient {
}
async askRelayerStatus({
hostname,
url
url,
relayerAddress
}) {
const status = await super.askRelayerStatus({
hostname,
url
url,
relayerAddress
});
if (!status.version.includes("tovarish")) {
throw new Error("Not a tovarish relayer!");
@ -10466,17 +10558,24 @@ class TovarishClient extends RelayerClient {
"Content-Type": "application/json, application/x-www-form-urlencoded"
},
timeout: 3e4,
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0
maxRetry: this.fetchDataOptions?.torPort ? 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(rawStatus?.netId, config, this.tovarish));
if (!statusValidator(rawStatus)) {
const statusValidator = ajv.compile(
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rawStatus.netId,
config,
this.tovarish
)
);
if (!statusValidator) {
continue;
}
const status = {
@ -10715,4 +10814,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, 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 };
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 };

5
dist/ip.d.ts vendored
View File

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

View File

@ -5793,7 +5793,6 @@ 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
@ -6391,7 +6390,6 @@ 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
@ -14410,7 +14408,6 @@ 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
@ -15658,7 +15655,6 @@ 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
@ -47568,7 +47564,6 @@ 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) {
@ -47768,10 +47763,9 @@ module.exports = [
/***/ }),
/***/ 3225:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
/***/ ((module) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
if (typeof process === 'undefined' ||
@ -47819,197 +47813,6 @@ 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:
@ -51754,7 +51557,6 @@ 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()
@ -51813,7 +51615,6 @@ function randomBytes (size, cb) {
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
function oldBrowser () {
@ -52065,7 +51866,6 @@ 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
@ -52243,7 +52043,6 @@ 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
@ -53475,7 +53274,6 @@ 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
@ -54124,7 +53922,6 @@ Writable.prototype._destroy = function (err, cb) {
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
var _Object$setPrototypeO;
@ -54499,10 +54296,9 @@ module.exports = /*#__PURE__*/function () {
/***/ }),
/***/ 5896:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
/***/ ((module) => {
"use strict";
/* provided dependency */ var process = __webpack_require__(5606);
// undocumented cb() API, needed for core, not for public API
@ -56967,7 +56763,6 @@ 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
@ -72478,7 +72273,6 @@ 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);
@ -75483,7 +75277,6 @@ 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.
@ -75528,7 +75321,7 @@ function sleep(ms) {
let workerSource;
const threadStr = `(${thread.toString()})(self)`;
if(threadman_process.browser) {
if(process.browser) {
if(globalThis?.Blob) {
const threadBytes= new TextEncoder().encode(threadStr);
const workerBlob = new Blob([threadBytes], { type: "application/javascript" }) ;
@ -75557,7 +75350,7 @@ async function buildThreadManager(wasm, singleThread) {
}
});
if(threadman_process.browser && !globalThis?.Worker) {
if(process.browser && !globalThis?.Worker) {
singleThread = true;
}
@ -75589,7 +75382,7 @@ async function buildThreadManager(wasm, singleThread) {
tm.working = [];
let concurrency = 2;
if (threadman_process.browser) {
if (process.browser) {
if (typeof navigator === "object" && navigator.hardwareConcurrency) {
concurrency = navigator.hardwareConcurrency;
}
@ -106606,7 +106399,6 @@ 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);
@ -106614,7 +106406,7 @@ var src = __webpack_require__(1810);
BigInt.prototype.toJSON = function() {
return this.toString();
};
const isNode = !utils_process.browser && typeof globalThis.window === "undefined";
const isNode = !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

View File

@ -37,6 +37,14 @@ 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;
@ -57,16 +65,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;
@ -94,6 +102,7 @@ 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
View File

@ -1,6 +1,7 @@
import type { EventEmitter } from 'stream';
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 { 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 type { Config, NetIdType } from './networkConfig';
declare global {
interface Window {
@ -8,54 +9,35 @@ 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 DispatcherFunc = (retry?: number) => Dispatcher;
export interface fetchDataOptions extends Omit<RequestInit, 'headers'> {
/**
* Overriding RequestInit params
*/
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export type fetchDataOptions = RequestInit & {
headers?: HeadersInit | any;
/**
* Expanding RequestInit params
*/
maxRetry?: number;
retryOn?: number;
userAgent?: string;
timeout?: number;
proxy?: string;
torPort?: number;
debug?: Function;
returnResponse?: boolean;
cancelSignal?: FetchCancelSignal;
dispatcherFunc?: DispatcherFunc;
}
export declare function fetchData<T>(url: string, options?: fetchDataOptions): Promise<T>;
};
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>;
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<{
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 declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
export interface TornadoWalletOptions {
gasPriceBump?: number;
gasLimitBump?: number;
@ -71,7 +53,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<TransactionLike<string>>;
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
}
export declare class TornadoVoidSigner extends VoidSigner {
nonce?: number;
@ -80,7 +62,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<TransactionLike<string>>;
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
}
export declare class TornadoRpcSigner extends JsonRpcSigner {
nonce?: number;

View File

@ -120,9 +120,10 @@ export declare class RelayerClient {
fetchDataOptions?: fetchDataOptions;
tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor);
askRelayerStatus({ hostname, url, }: {
askRelayerStatus({ hostname, url, relayerAddress, }: {
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

View File

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

8
dist/zip.d.ts vendored
View File

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

View File

@ -46,10 +46,12 @@
"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"
@ -72,6 +74,7 @@
"@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",
@ -82,7 +85,6 @@
"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",

View File

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

View File

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

View File

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

View File

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

View File

@ -1,14 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any, import/no-duplicates */
import type * as idb from 'idb';
import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
/* eslint-disable @typescript-eslint/no-explicit-any */
import { openDB, deleteDB, 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 {
@ -71,7 +64,7 @@ export class IndexedDB {
return;
}
this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db = await openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener('onupgradeneeded', async () => {
await this._removeExist();
});
@ -96,7 +89,7 @@ export class IndexedDB {
}
async _removeExist() {
await window?.idb?.deleteDB(this.dbName);
await deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();

View File

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

View File

@ -46,6 +46,17 @@ 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;
@ -67,17 +78,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;
@ -93,6 +104,13 @@ 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',
@ -105,9 +123,9 @@ export const defaultConfig: networkConfig = {
name: 'MEV Blocker',
url: 'https://rpc.mevblocker.io',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/mainnet',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/mainnet',
},
keydonix: {
name: 'Horswap ( Keydonix )',
@ -226,6 +244,13 @@ 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',
@ -249,9 +274,9 @@ export const defaultConfig: networkConfig = {
name: 'BNB Chain 2',
url: 'https://bsc-dataseed1.ninicoin.io',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/bsc',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/bsc',
},
nodereal: {
name: 'NodeReal',
@ -315,6 +340,13 @@ 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',
@ -330,9 +362,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/matic-tornado-subgraph',
subgraphs: {},
rpcUrls: {
lavaBuild: {
name: 'polygon.lava.build',
url: 'https://polygon.lava.build',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/polygon',
},
polygon: {
name: 'Polygon',
@ -367,6 +399,13 @@ 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',
@ -383,9 +422,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
subgraphs: {},
rpcUrls: {
lavaBuild: {
name: 'optimism.lava.build',
url: 'https://optimism.lava.build',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/op',
},
optimism: {
name: 'Optimism',
@ -423,6 +462,13 @@ 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',
@ -442,6 +488,10 @@ 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',
@ -474,6 +524,13 @@ 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',
@ -494,6 +551,10 @@ 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',
@ -555,6 +616,13 @@ 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',
@ -574,6 +642,10 @@ 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',
@ -601,6 +673,13 @@ 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',
@ -620,13 +699,9 @@ export const defaultConfig: networkConfig = {
name: 'Gnosis',
url: 'https://rpc.gnosischain.com',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/gnosis',
},
blastApi: {
name: 'BlastApi',
url: 'https://gnosis-mainnet.public.blastapi.io',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/gnosis',
},
oneRpc: {
name: '1RPC',
@ -653,6 +728,13 @@ 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',
@ -668,9 +750,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
subgraphs: {},
rpcUrls: {
blastApi: {
name: 'BlastApi',
url: 'https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/ext/bc/C/rpc',
},
oneRpc: {
name: '1RPC',
@ -704,6 +786,13 @@ 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',
@ -725,13 +814,9 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
subgraphs: {},
rpcUrls: {
blastApi: {
name: 'BlastApi',
url: 'https://eth-sepolia.public.blastapi.io',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/sepolia',
tornadoWithdraw: {
name: 'Tornado Withdraw',
url: 'https://tornadowithdraw.com/sepolia',
},
oneRpc: {
name: '1RPC',
@ -847,6 +932,17 @@ 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;

View File

@ -1,4 +1,6 @@
import type { EventEmitter } from 'stream';
import type { RequestOptions } from 'http';
import crossFetch from 'cross-fetch';
import {
FetchRequest,
JsonRpcApiProvider,
@ -18,13 +20,10 @@ import {
EnsPlugin,
GasCostPlugin,
FetchCancelSignal,
resolveProperties,
TransactionLike,
FetchUrlFeeDataNetworkPlugin,
FeeData,
} from 'ethers';
import type { Dispatcher, RequestInit, fetch as undiciFetch } from 'undici-types';
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 { isNode, sleep } from './utils';
import type { Config, NetIdType } from './networkConfig';
@ -37,34 +36,73 @@ 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 DispatcherFunc = (retry?: number) => Dispatcher;
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export interface fetchDataOptions extends Omit<RequestInit, 'headers'> {
/**
* Overriding RequestInit params
*/
export type fetchDataOptions = RequestInit & {
// 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;
dispatcherFunc?: DispatcherFunc;
};
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}`);
}
export async function fetchData<T>(url: string, options: fetchDataOptions = {}): Promise<T> {
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);
}
}
export async function fetchData(url: string, options: fetchDataOptions = {}) {
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;
@ -84,17 +122,14 @@ export async function fetchData<T>(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();
options.signal = controller.signal;
// Temporary workaround until @types/node-fetch is compatible with @types/node
options.signal = controller.signal as FetchAbortSignal;
// Define timeout in seconds
timeout = setTimeout(() => {
@ -114,7 +149,16 @@ export async function fetchData<T>(url: string, options: fetchDataOptions = {}):
}
}
if (typeof options.debug === 'function') {
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') {
options.debug('request', {
url,
retry,
@ -124,11 +168,13 @@ export async function fetchData<T>(url: string, options: fetchDataOptions = {}):
}
try {
const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
const resp = await (globalThis.fetch as unknown as typeof undiciFetch)(url, {
...options,
dispatcher,
const resp = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.body,
redirect: options.redirect,
signal: options.signal,
agent: options.agent,
});
if (options.debug && typeof options.debug === 'function') {
@ -141,23 +187,23 @@ export async function fetchData<T>(url: string, options: fetchDataOptions = {}):
}
if (options.returnResponse) {
return resp as T;
return resp;
}
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()) as T;
return await resp.json();
}
// Else if the server returns text parse it as a string
if (contentType?.includes('text')) {
return (await resp.text()) as T;
return await resp.text();
}
// Return as a response object https://developer.mozilla.org/en-US/docs/Web/API/Response
return resp as T;
return resp;
} catch (error) {
if (timeout) {
clearTimeout(timeout);
@ -196,7 +242,7 @@ export const fetchGetUrlFunc =
returnResponse: true,
};
const resp = await fetchData<Response>(req.url, init);
const resp = await fetchData(req.url, init);
const headers = {} as Record<string, any>;
resp.headers.forEach((value: any, key: string) => {
@ -221,36 +267,20 @@ 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 fetchedNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
// Audit if we are connected to right network
const chainId = Number(fetchedNetwork.chainId);
const chainId = Number(staticNetwork.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,
@ -297,7 +327,7 @@ export const populateTransaction = async (
const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(),
tx.nonce || tx.nonce === 0 ? undefined : provider.getTransactionCount(signer.address, 'pending'),
tx.nonce ? undefined : provider.getTransactionCount(signer.address, 'pending'),
]);
if (feeData) {
@ -320,7 +350,7 @@ export const populateTransaction = async (
}
}
if (nonce || nonce === 0) {
if (nonce) {
tx.nonce = nonce;
}
@ -343,7 +373,7 @@ export const populateTransaction = async (
}
}
return resolveProperties(tx);
return tx;
};
export interface TornadoWalletOptions {
@ -384,7 +414,8 @@ export class TornadoWallet extends Wallet {
async populateTransaction(tx: TransactionRequest) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return txObject as Promise<TransactionLike<string>>;
return super.populateTransaction(txObject);
}
}
@ -412,7 +443,8 @@ export class TornadoVoidSigner extends VoidSigner {
async populateTransaction(tx: TransactionRequest) {
const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce);
return txObject as Promise<TransactionLike<string>>;
return super.populateTransaction(txObject);
}
}

View File

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

View File

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

View File

@ -1,15 +1,5 @@
import {
zip,
unzip,
AsyncZippable,
Unzipped,
ZipAttributes,
zlib,
unzlib,
AsyncZlibOptions,
AsyncUnzlibOptions,
} from 'fflate';
import { fetchData, fetchDataOptions } from './providers';
import { zip, unzip, AsyncZippable, Unzipped, ZipAttributes } from 'fflate';
import { fetchData } from './providers';
import { bytesToBase64, digest } from './utils';
export function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array> {
@ -36,47 +26,20 @@ 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;

View File

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

View File

@ -1440,6 +1440,14 @@
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"
@ -2657,6 +2665,13 @@ 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"
@ -5110,6 +5125,13 @@ 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"
@ -6480,6 +6502,11 @@ 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"
@ -6894,6 +6921,11 @@ 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"
@ -6970,6 +7002,14 @@ 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"