commit d95635c4f815359ae18deef43029d1713c6d5f35 Author: tornadocontrib Date: Wed Nov 13 01:42:13 2024 +0000 Initial commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d39d464 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +node_modules +data +.git +.env \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..ca44f30 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,44 @@ +module.exports = { + env: { + es2021: true, + node: true, + }, + extends: [ + 'prettier', + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', + 'plugin:prettier/recommended', + ], + overrides: [ + { + env: { + node: true, + }, + files: ['.eslintrc.{js,cjs}'], + parserOptions: { + sourceType: 'script', + }, + }, + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['@typescript-eslint', 'prettier'], + rules: { + 'prettier/prettier': [ + 'error', + { + tabWidth: 4, + printWidth: 120, + singleQuote: true, + }, + ], + 'import/order': ['error'], + '@typescript-eslint/no-unused-vars': ['warn'], + '@typescript-eslint/no-unused-expressions': ['off'], + }, +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..705dacd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +lib/**/* linguist-vendored +static/**/* linguist-vendored \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f10206 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +data +.env \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..05ba80e --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..93ca0c3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package.json . +COPY yarn.lock . + +RUN yarn + +COPY . . + +ENTRYPOINT ["yarn", "start"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1b19437 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +
+ + + +# Товарищ Relayer + +Tovarish Relayer is a new Tornado Cash relayer applied with synced historic events API to help create withdrawal snark proofs in a decentralized, uncensorable manner. + +It runs on multiple chains (yes, you only need to run a single tovarish relayer instance to run across any Tornado Cash deployed chains), and it only requires a single URL endpoint to expose and advertise your relayer. + +
+ +## Disclaimer + +Currently, this relayer isn't compatible with the deployed UI on [tornadocash.eth](https://tornadocash-eth.ipns.dweb.link) or any other classic UI deployments. API or any REST requests are compatible with the [classic relayer software](https://git.tornado.ws/tornadocash/tornado-relayer), however since this relayer uses more optimized gas price calculation from [@tornado/core](https://git.tornado.ws/tornado-packages/tornado-core) package the relayer may require more fees for network gas price then the previous version of the relayer. Thus, we have blocked interaction with any previous classic UI until the UI is upgraded to support the new gas calculation optimized for EIP-1559 chains. + +## Technical Requirements + ++ Latest LTS version of Node.js (20.x recommended) + ++ RPC node (Supply them with 1_RPC or 56_RPC env value, see ./src/config.ts for available ENV variables). + ++ Nginx + +Note that unlike the classic version of relayer, this relayer doesn't require Redis DB or Docker installation, a single Relayer instance that runs on the top of Node.js would be sufficient (And it utilizes multi threading environment with Workers and Cluster support). + +## How to run the relayer? + +Note that this relayer is still on an early stage in which many components or source code can be changed in the foreseeable future. + +In order to work with the relayer properly you must + +1. Have your own RPC node or a paid plan with sufficient rate limits ( that allows 30 requests per second with historic events data ). + +2. On-chain registered relayer addresses + +You must register the relayer on the on-chain Relayer Registry contract. Follow the guidelines about registering the relayer on-chain. https://docs.tornado.ws/general/guides/relayer.html + +After you run the relayer locally and have registered the relayer on-chain, you must also register the main URL on `tovarish-relayer` ENS subdomain just like how you registered for each chain. + +Here is the example of registering tovarish relayer on the ENS domain https://app.ens.domains/tovarish-relayer.tornadowithdraw.eth?tab=records + +## Upcoming Updates + +This documentation will be likely updated in the near future. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d4b7704 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +services: + relayer: + container_name: relayer + image: relayer + build: + context: . + restart: always + env_file: + - ./.env + ports: + - '127.0.0.1:3000:3000' + volumes: + - './data:/app/data' diff --git a/lib/config.d.ts b/lib/config.d.ts new file mode 100644 index 0000000..8783169 --- /dev/null +++ b/lib/config.d.ts @@ -0,0 +1,33 @@ +import 'dotenv/config'; +import { NetIdType, SubdomainMap } from '@tornado/core'; +export declare const version: string; +export interface RelayerConfig { + /** + * Router config + */ + host: string; + port: number; + workers: number; + reverseProxy: boolean; + logLevel?: string; + /** + * Worker config + */ + rewardAccount: string; + serviceFee: number; + clearInterval: number; + /** + * Sync config + */ + enabledNetworks: NetIdType[]; + rpcUrls: SubdomainMap; + txRpcUrls: SubdomainMap; + merkleWorkerPath: string; + cacheDir: string; + userEventsDir: string; + userTreeDir: string; + syncInterval: number; +} +export declare function getPrivateKey(): string; +export declare function getRewardAccount(): string; +export declare function getRelayerConfig(): RelayerConfig; diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..0909da4 --- /dev/null +++ b/lib/config.js @@ -0,0 +1,75 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.version = void 0; +exports.getPrivateKey = getPrivateKey; +exports.getRewardAccount = getRewardAccount; +exports.getRelayerConfig = getRelayerConfig; +const path_1 = __importDefault(require("path")); +const process_1 = __importDefault(require("process")); +const os_1 = __importDefault(require("os")); +require("dotenv/config"); +const ethers_1 = require("ethers"); +const core_1 = require("@tornado/core"); +const package_json_1 = __importDefault(require("../package.json")); +exports.version = `${package_json_1.default.name} ${package_json_1.default.version}`; +function getPrivateKey() { + const privateKey = process_1.default.env.PRIVATE_KEY; + if (!privateKey || !(0, ethers_1.isHexString)(privateKey, 32)) { + throw new Error('Invalid private key, make sure it contains 0x prefix!'); + } + return privateKey; +} +function getRewardAccount() { + return (0, ethers_1.computeAddress)(getPrivateKey()); +} +function getRelayerConfig() { + const enabledNetworks = process_1.default.env.ENABLED_NETWORKS + ? process_1.default.env.ENABLED_NETWORKS.replaceAll(' ', '') + .split(',') + .map((n) => Number(n)) + .filter((n) => core_1.enabledChains.includes(n)) + : core_1.enabledChains; + const rpcUrls = enabledNetworks.reduce((acc, netId) => { + // If we have custom RPC url (like as 1_RPC from ENV) + if (process_1.default.env[`${netId}_RPC`]) { + acc[netId] = process_1.default.env[`${netId}_RPC`] || ''; + } + else { + acc[netId] = Object.values((0, core_1.getConfig)(netId).rpcUrls)[0]?.url; + } + return acc; + }, {}); + const txRpcUrls = enabledNetworks.reduce((acc, netId) => { + // If we have custom RPC url (like as 1_RPC from ENV) + if (process_1.default.env[`${netId}_TX_RPC`]) { + acc[netId] = process_1.default.env[`${netId}_TX_RPC`] || ''; + } + else { + acc[netId] = rpcUrls[netId]; + } + return acc; + }, {}); + const STATIC_DIR = process_1.default.env.CACHE_DIR || path_1.default.join(__dirname, '../static'); + const USER_DIR = process_1.default.env.USER_DIR || './data'; + return { + host: process_1.default.env.HOST || '0.0.0.0', + port: Number(process_1.default.env.PORT || 3000), + workers: Number(process_1.default.env.WORKERS || os_1.default.cpus().length), + reverseProxy: process_1.default.env.REVERSE_PROXY === 'true', + logLevel: process_1.default.env.LOG_LEVEL || undefined, + rewardAccount: getRewardAccount(), + serviceFee: Number(process_1.default.env.SERVICE_FEE || 0.5), + clearInterval: Number(process_1.default.env.CLEAR_INTERVAL || 86400), + enabledNetworks, + rpcUrls, + txRpcUrls, + merkleWorkerPath: path_1.default.join(STATIC_DIR, './merkleTreeWorker.js'), + cacheDir: path_1.default.join(STATIC_DIR, './events'), + userEventsDir: path_1.default.join(USER_DIR, './events'), + userTreeDir: path_1.default.join(USER_DIR, './trees'), + syncInterval: Number(process_1.default.env.SYNC_INTERVAL || 120), + }; +} diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..8418dc7 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,2 @@ +export * from './services'; +export * from './config'; diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..ab0efa3 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,18 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./services"), exports); +__exportStar(require("./config"), exports); diff --git a/lib/services/check.d.ts b/lib/services/check.d.ts new file mode 100644 index 0000000..ad2dcac --- /dev/null +++ b/lib/services/check.d.ts @@ -0,0 +1,5 @@ +import type { Logger } from 'winston'; +import { RelayerConfig } from '../config'; +export declare const CHECK_BALANCE: bigint; +export declare const DISABLE_LOW_BALANCE = true; +export declare function checkProviders(relayerConfig: RelayerConfig, logger: Logger): Promise; diff --git a/lib/services/check.js b/lib/services/check.js new file mode 100644 index 0000000..248f535 --- /dev/null +++ b/lib/services/check.js @@ -0,0 +1,42 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DISABLE_LOW_BALANCE = exports.CHECK_BALANCE = void 0; +exports.checkProviders = checkProviders; +const process_1 = __importDefault(require("process")); +const ethers_1 = require("ethers"); +const core_1 = require("@tornado/core"); +// Can use 0 to use network on low balance +exports.CHECK_BALANCE = (0, ethers_1.parseEther)(process_1.default.env.CHECK_BALANCE || '0.001'); +exports.DISABLE_LOW_BALANCE = true; +async function checkProviders(relayerConfig, logger) { + const { enabledNetworks, rpcUrls, rewardAccount } = relayerConfig; + const disabledNetworks = (await Promise.all(enabledNetworks.map(async (netId) => { + try { + const config = (0, core_1.getConfig)(netId); + const rpcUrl = rpcUrls[netId]; + const provider = await (0, core_1.getProvider)(rpcUrl, { + netId, + }); + const balance = await provider.getBalance(rewardAccount); + const symbol = config.nativeCurrency.toUpperCase(); + if (balance < exports.CHECK_BALANCE) { + logger.error(`Network ${netId} has lower balance than 0.001 ${symbol} and thus disabled (Balance: ${(0, ethers_1.formatEther)(balance)} ${symbol})`); + if (exports.DISABLE_LOW_BALANCE) { + return netId; + } + } + else { + logger.info(`Network ${netId} connected with ${rpcUrl} (Balance: ${(0, ethers_1.formatEther)(balance)} ${config.nativeCurrency.toUpperCase()})`); + } + } + catch (err) { + logger.error(`Failed to connect with ${netId} provider, make sure you have configured correct RPC url`); + throw err; + } + }))).filter((n) => n); + relayerConfig.enabledNetworks = relayerConfig.enabledNetworks.filter((n) => !disabledNetworks.includes(n)); + logger.info(`Enabled Networks: ${relayerConfig.enabledNetworks.join(', ')}`); +} diff --git a/lib/services/data.d.ts b/lib/services/data.d.ts new file mode 100644 index 0000000..3809ace --- /dev/null +++ b/lib/services/data.d.ts @@ -0,0 +1,33 @@ +import { AsyncZippable, Unzipped } from 'fflate'; +import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core'; +export declare function existsAsync(fileOrDir: string): Promise; +export declare function zipAsync(file: AsyncZippable): Promise; +export declare function unzipAsync(data: Uint8Array): Promise; +export declare function saveUserFile({ fileName, userDirectory, dataString, lastBlock, }: { + fileName: string; + userDirectory: string; + dataString: string; + lastBlock?: number; +}): Promise; +export declare function saveLastBlock({ fileName, userDirectory, lastBlock, }: { + fileName: string; + userDirectory: string; + lastBlock: number; +}): Promise; +export declare function loadLastBlock({ name, directory }: { + name: string; + directory: string; +}): Promise; +export declare function loadSavedEvents({ name, userDirectory, }: { + name: string; + userDirectory: string; +}): Promise>; +export declare function download({ name, cacheDirectory }: { + name: string; + cacheDirectory: string; +}): Promise; +export declare function loadCachedEvents({ name, cacheDirectory, deployedBlock, }: { + name: string; + cacheDirectory: string; + deployedBlock: number; +}): Promise>; diff --git a/lib/services/data.js b/lib/services/data.js new file mode 100644 index 0000000..f55e0b9 --- /dev/null +++ b/lib/services/data.js @@ -0,0 +1,151 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.existsAsync = existsAsync; +exports.zipAsync = zipAsync; +exports.unzipAsync = unzipAsync; +exports.saveUserFile = saveUserFile; +exports.saveLastBlock = saveLastBlock; +exports.loadLastBlock = loadLastBlock; +exports.loadSavedEvents = loadSavedEvents; +exports.download = download; +exports.loadCachedEvents = loadCachedEvents; +const path_1 = __importDefault(require("path")); +const promises_1 = require("fs/promises"); +const fflate_1 = require("fflate"); +async function existsAsync(fileOrDir) { + try { + await (0, promises_1.stat)(fileOrDir); + return true; + } + catch { + return false; + } +} +function zipAsync(file) { + return new Promise((res, rej) => { + (0, fflate_1.zip)(file, { mtime: new Date('1/1/1980') }, (err, data) => { + if (err) { + rej(err); + return; + } + res(data); + }); + }); +} +function unzipAsync(data) { + return new Promise((res, rej) => { + (0, fflate_1.unzip)(data, {}, (err, data) => { + if (err) { + rej(err); + return; + } + res(data); + }); + }); +} +async function saveUserFile({ fileName, userDirectory, dataString, lastBlock, }) { + fileName = fileName.toLowerCase(); + const filePath = path_1.default.join(userDirectory, fileName); + const payload = await zipAsync({ + [fileName]: new TextEncoder().encode(dataString), + }); + if (!(await existsAsync(userDirectory))) { + await (0, promises_1.mkdir)(userDirectory, { recursive: true }); + } + await (0, promises_1.writeFile)(filePath + '.zip', payload); + await (0, promises_1.writeFile)(filePath, dataString); + if (lastBlock) { + await saveLastBlock({ + fileName: fileName.replace('.json', ''), + userDirectory, + lastBlock, + }); + } +} +async function saveLastBlock({ fileName, userDirectory, lastBlock, }) { + const filePath = path_1.default.join(userDirectory, fileName); + if (lastBlock) { + await (0, promises_1.writeFile)(filePath + '.lastblock.txt', String(lastBlock)); + } +} +async function loadLastBlock({ name, directory }) { + const filePath = path_1.default.join(directory, `${name}.lastblock.txt`); + if (!(await existsAsync(filePath))) { + return; + } + try { + const lastBlock = Number(await (0, promises_1.readFile)(filePath, { encoding: 'utf8' })); + if (lastBlock) { + return lastBlock; + } + // eslint-disable-next-line no-empty + } + catch { } +} +async function loadSavedEvents({ name, userDirectory, }) { + const filePath = path_1.default.join(userDirectory, `${name}.json`.toLowerCase()); + if (!(await existsAsync(filePath))) { + return { + events: [], + lastBlock: 0, + }; + } + try { + const events = JSON.parse(await (0, promises_1.readFile)(filePath, { encoding: 'utf8' })); + const loadedBlock = await loadLastBlock({ + name, + directory: userDirectory, + }); + return { + events, + lastBlock: loadedBlock || events[events.length - 1]?.blockNumber || 0, + }; + } + catch (err) { + console.log('Method loadSavedEvents has error'); + console.log(err); + return { + events: [], + lastBlock: 0, + }; + } +} +async function download({ name, cacheDirectory }) { + const fileName = `${name}.json`.toLowerCase(); + const zipName = `${fileName}.zip`; + const zipPath = path_1.default.join(cacheDirectory, zipName); + const data = await (0, promises_1.readFile)(zipPath); + const { [fileName]: content } = await unzipAsync(data); + return new TextDecoder().decode(content); +} +async function loadCachedEvents({ name, cacheDirectory, deployedBlock, }) { + try { + const module = await download({ cacheDirectory, name }); + if (module) { + const events = JSON.parse(module); + const lastBlock = events && events.length ? events[events.length - 1].blockNumber : deployedBlock; + return { + events, + lastBlock, + fromCache: true, + }; + } + return { + events: [], + lastBlock: deployedBlock, + fromCache: true, + }; + } + catch (err) { + console.log('Method loadCachedEvents has error'); + console.log(err); + return { + events: [], + lastBlock: deployedBlock, + fromCache: true, + }; + } +} diff --git a/lib/services/error.d.ts b/lib/services/error.d.ts new file mode 100644 index 0000000..8d1fda0 --- /dev/null +++ b/lib/services/error.d.ts @@ -0,0 +1,11 @@ +import { NetIdType } from '@tornado/core'; +export interface ErrorTypes { + type: string; + netId: number; + timestamp: number; +} +export interface ErrorMessages extends ErrorTypes { + message?: string; + stack?: string; +} +export declare function newError(type: string, netId: NetIdType, err: any): ErrorMessages; diff --git a/lib/services/error.js b/lib/services/error.js new file mode 100644 index 0000000..5024350 --- /dev/null +++ b/lib/services/error.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.newError = newError; +function newError(type, netId, +// eslint-disable-next-line @typescript-eslint/no-explicit-any +err) { + return { + type, + netId, + timestamp: Math.floor(Date.now() / 1000), + message: err.message, + stack: err.stack, + }; +} diff --git a/lib/services/events.d.ts b/lib/services/events.d.ts new file mode 100644 index 0000000..85fecd3 --- /dev/null +++ b/lib/services/events.d.ts @@ -0,0 +1,144 @@ +import { BaseTornadoService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseTornadoServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseEchoServiceConstructor, BaseEchoService, CachedRelayers, BatchEventsService, BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, EchoEvents, BatchEventServiceConstructor, BatchEventOnProgress, NetIdType, AllRelayerRegistryEvents, BaseRevenueService, BaseRevenueServiceConstructor, StakeBurnedEvents } from '@tornado/core'; +import type { Logger } from 'winston'; +import { TreeCache } from './treeCache'; +export interface NodeEventsConstructor extends BatchEventServiceConstructor { + netId: NetIdType; + logger: Logger; + getInstanceName: () => string; +} +export declare class NodeEventsService extends BatchEventsService { + netId: NetIdType; + logger: Logger; + getInstanceName: () => string; + constructor(serviceConstructor: NodeEventsConstructor); +} +export interface NodeTornadoServiceConstructor extends BaseTornadoServiceConstructor { + cacheDirectory: string; + userDirectory: string; + nativeCurrency: string; + logger: Logger; + treeCache?: TreeCache; +} +export declare class NodeTornadoService extends BaseTornadoService { + cacheDirectory: string; + userDirectory: string; + nativeCurrency: string; + logger: Logger; + treeCache?: TreeCache; + constructor(serviceConstructor: NodeTornadoServiceConstructor); + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]): void; + getEventsFromDB(): Promise>; + getEventsFromCache(): Promise>; + validateEvents({ events, lastBlock, hasNewEvents, }: BaseEvents & { + hasNewEvents?: boolean; + }): Promise; + saveEvents({ events, lastBlock }: BaseEvents): Promise; + updateEvents(): Promise<{ + events: (DepositsEvents | WithdrawalsEvents)[]; + lastBlock: number; + validateResult: Awaited; + }>; +} +export interface NodeEchoServiceConstructor extends BaseEchoServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} +export declare class NodeEchoService extends BaseEchoService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + constructor(serviceConstructor: NodeEchoServiceConstructor); + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]): void; + getEventsFromDB(): Promise>; + getEventsFromCache(): Promise>; + saveEvents({ events, lastBlock }: BaseEvents): Promise; + updateEvents(): Promise<{ + events: EchoEvents[]; + lastBlock: number; + validateResult: Awaited; + }>; +} +export interface NodeEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} +export declare class NodeEncryptedNotesService extends BaseEncryptedNotesService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + constructor(serviceConstructor: NodeEncryptedNotesServiceConstructor); + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]): void; + getEventsFromDB(): Promise>; + getEventsFromCache(): Promise>; + saveEvents({ events, lastBlock }: BaseEvents): Promise; + updateEvents(): Promise<{ + events: EncryptedNotesEvents[]; + lastBlock: number; + validateResult: Awaited; + }>; +} +export interface NodeGovernanceServiceConstructor extends BaseGovernanceServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} +export declare class NodeGovernanceService extends BaseGovernanceService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + constructor(serviceConstructor: NodeGovernanceServiceConstructor); + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]): void; + getEventsFromDB(): Promise>; + getEventsFromCache(): Promise>; + saveEvents({ events, lastBlock }: BaseEvents): Promise; + updateEvents(): Promise<{ + events: AllGovernanceEvents[]; + lastBlock: number; + validateResult: Awaited; + }>; +} +export interface NodeRegistryServiceConstructor extends BaseRegistryServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} +export declare class NodeRegistryService extends BaseRegistryService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + constructor(serviceConstructor: NodeRegistryServiceConstructor); + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]): void; + getEventsFromDB(): Promise>; + getEventsFromCache(): Promise>; + saveEvents({ events, lastBlock }: BaseEvents): Promise; + updateEvents(): Promise<{ + events: AllRelayerRegistryEvents[]; + lastBlock: number; + validateResult: Awaited; + }>; + getRelayersFromDB(): Promise; + getRelayersFromCache(): Promise; + saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers): Promise; +} +export interface NodeRevenueServiceConstructor extends BaseRevenueServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} +export declare class NodeRevenueService extends BaseRevenueService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + constructor(serviceConstructor: NodeRevenueServiceConstructor); + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]): void; + getEventsFromDB(): Promise>; + getEventsFromCache(): Promise>; + saveEvents({ events, lastBlock }: BaseEvents): Promise; + updateEvents(): Promise<{ + events: StakeBurnedEvents[]; + lastBlock: number; + validateResult: Awaited; + }>; +} diff --git a/lib/services/events.js b/lib/services/events.js new file mode 100644 index 0000000..52032e0 --- /dev/null +++ b/lib/services/events.js @@ -0,0 +1,468 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NodeRevenueService = exports.NodeRegistryService = exports.NodeGovernanceService = exports.NodeEncryptedNotesService = exports.NodeEchoService = exports.NodeTornadoService = exports.NodeEventsService = void 0; +const path_1 = __importDefault(require("path")); +const promises_1 = require("fs/promises"); +const core_1 = require("@tornado/core"); +const data_1 = require("./data"); +class NodeEventsService extends core_1.BatchEventsService { + netId; + logger; + getInstanceName; + constructor(serviceConstructor) { + super(serviceConstructor); + this.netId = serviceConstructor.netId; + this.logger = serviceConstructor.logger; + this.getInstanceName = serviceConstructor.getInstanceName; + } +} +exports.NodeEventsService = NodeEventsService; +class NodeTornadoService extends core_1.BaseTornadoService { + cacheDirectory; + userDirectory; + nativeCurrency; + logger; + treeCache; + constructor(serviceConstructor) { + super(serviceConstructor); + const { netId, provider, Tornado, type, amount, currency, cacheDirectory, userDirectory, nativeCurrency, logger, treeCache, } = serviceConstructor; + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.nativeCurrency = nativeCurrency; + this.logger = logger; + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Tornado, + onProgress: this.updateEventProgress, + logger, + getInstanceName: () => `${type.toLowerCase()}s_${netId}_${currency}_${amount}`, + }); + this.treeCache = treeCache; + } + updateEventProgress({ fromBlock, toBlock, count }) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + async getEventsFromDB() { + return await (0, data_1.loadSavedEvents)({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + async getEventsFromCache() { + return await (0, data_1.loadCachedEvents)({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + async validateEvents({ events, lastBlock, hasNewEvents, }) { + const tree = await super.validateEvents({ + events, + lastBlock, + hasNewEvents, + }); + if (tree && this.currency === this.nativeCurrency && this.treeCache) { + const merkleTree = tree; + await this.treeCache.createTree(events, merkleTree); + console.log(`${this.getInstanceName()}: Updated tree cache with root ${(0, core_1.toFixedHex)(BigInt(merkleTree.root))}\n`); + } + return tree; + } + async saveEvents({ events, lastBlock }) { + await (0, data_1.saveUserFile)({ + fileName: this.getInstanceName() + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + await (0, data_1.saveLastBlock)({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + return { + events, + lastBlock, + validateResult, + }; + } +} +exports.NodeTornadoService = NodeTornadoService; +class NodeEchoService extends core_1.BaseEchoService { + cacheDirectory; + userDirectory; + logger; + constructor(serviceConstructor) { + super(serviceConstructor); + const { netId, provider, Echoer, cacheDirectory, userDirectory, logger } = serviceConstructor; + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Echoer, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + updateEventProgress({ fromBlock, toBlock, count }) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + async getEventsFromDB() { + return await (0, data_1.loadSavedEvents)({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + async getEventsFromCache() { + return await (0, data_1.loadCachedEvents)({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + async saveEvents({ events, lastBlock }) { + const instanceName = this.getInstanceName(); + await (0, data_1.saveUserFile)({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + await (0, data_1.saveLastBlock)({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + return { + events, + lastBlock, + validateResult, + }; + } +} +exports.NodeEchoService = NodeEchoService; +class NodeEncryptedNotesService extends core_1.BaseEncryptedNotesService { + cacheDirectory; + userDirectory; + logger; + constructor(serviceConstructor) { + super(serviceConstructor); + const { netId, provider, Router, cacheDirectory, userDirectory, logger } = serviceConstructor; + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Router, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + updateEventProgress({ fromBlock, toBlock, count }) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + async getEventsFromDB() { + return await (0, data_1.loadSavedEvents)({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + async getEventsFromCache() { + return await (0, data_1.loadCachedEvents)({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + async saveEvents({ events, lastBlock }) { + const instanceName = this.getInstanceName(); + await (0, data_1.saveUserFile)({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + await (0, data_1.saveLastBlock)({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + return { + events, + lastBlock, + validateResult, + }; + } +} +exports.NodeEncryptedNotesService = NodeEncryptedNotesService; +class NodeGovernanceService extends core_1.BaseGovernanceService { + cacheDirectory; + userDirectory; + logger; + constructor(serviceConstructor) { + super(serviceConstructor); + const { netId, provider, Governance, cacheDirectory, userDirectory, logger } = serviceConstructor; + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Governance, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + updateEventProgress({ fromBlock, toBlock, count }) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + async getEventsFromDB() { + return await (0, data_1.loadSavedEvents)({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + async getEventsFromCache() { + return await (0, data_1.loadCachedEvents)({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + async saveEvents({ events, lastBlock }) { + const instanceName = this.getInstanceName(); + await (0, data_1.saveUserFile)({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + await (0, data_1.saveLastBlock)({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + return { + events, + lastBlock, + validateResult, + }; + } +} +exports.NodeGovernanceService = NodeGovernanceService; +class NodeRegistryService extends core_1.BaseRegistryService { + cacheDirectory; + userDirectory; + logger; + constructor(serviceConstructor) { + super(serviceConstructor); + const { netId, provider, RelayerRegistry, cacheDirectory, userDirectory, logger } = serviceConstructor; + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: RelayerRegistry, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + updateEventProgress({ fromBlock, toBlock, count }) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + async getEventsFromDB() { + return await (0, data_1.loadSavedEvents)({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + async getEventsFromCache() { + return await (0, data_1.loadCachedEvents)({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + async saveEvents({ events, lastBlock }) { + const instanceName = this.getInstanceName(); + await (0, data_1.saveUserFile)({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + await (0, data_1.saveLastBlock)({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + return { + events, + lastBlock, + validateResult, + }; + } + async getRelayersFromDB() { + const filePath = path_1.default.join(this.userDirectory || '', 'relayers.json'); + if (!this.userDirectory || !(await (0, data_1.existsAsync)(filePath))) { + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + }; + } + try { + const { lastBlock, timestamp, relayers } = JSON.parse(await (0, promises_1.readFile)(filePath, { encoding: 'utf8' })); + return { + lastBlock, + timestamp, + relayers, + }; + } + catch (err) { + console.log('Method getRelayersFromDB has error'); + console.log(err); + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + }; + } + } + async getRelayersFromCache() { + const filePath = path_1.default.join(this.cacheDirectory || '', 'relayers.json'); + if (!this.cacheDirectory || !(await (0, data_1.existsAsync)(filePath))) { + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + fromCache: true, + }; + } + try { + const { lastBlock, timestamp, relayers } = JSON.parse(await (0, promises_1.readFile)(filePath, { encoding: 'utf8' })); + return { + lastBlock, + timestamp, + relayers, + fromCache: true, + }; + } + catch (err) { + console.log('Method getRelayersFromDB has error'); + console.log(err); + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + fromCache: true, + }; + } + } + async saveRelayers({ lastBlock, timestamp, relayers }) { + await (0, data_1.saveUserFile)({ + fileName: 'relayers.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify({ lastBlock, timestamp, relayers }, null, 2) + '\n', + }); + } +} +exports.NodeRegistryService = NodeRegistryService; +class NodeRevenueService extends core_1.BaseRevenueService { + cacheDirectory; + userDirectory; + logger; + constructor(serviceConstructor) { + super(serviceConstructor); + const { netId, provider, RelayerRegistry, cacheDirectory, userDirectory, logger } = serviceConstructor; + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: RelayerRegistry, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + updateEventProgress({ fromBlock, toBlock, count }) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + async getEventsFromDB() { + return await (0, data_1.loadSavedEvents)({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + async getEventsFromCache() { + return await (0, data_1.loadCachedEvents)({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + async saveEvents({ events, lastBlock }) { + const instanceName = this.getInstanceName(); + await (0, data_1.saveUserFile)({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + await (0, data_1.saveLastBlock)({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + return { + events, + lastBlock, + validateResult, + }; + } +} +exports.NodeRevenueService = NodeRevenueService; diff --git a/lib/services/index.d.ts b/lib/services/index.d.ts new file mode 100644 index 0000000..ad6f383 --- /dev/null +++ b/lib/services/index.d.ts @@ -0,0 +1,12 @@ +export * from './check'; +export * from './data'; +export * from './error'; +export * from './events'; +export * from './logger'; +export * from './router'; +export * from './routerMsg'; +export * from './schema'; +export * from './sync'; +export * from './treeCache'; +export * from './utils'; +export * from './worker'; diff --git a/lib/services/index.js b/lib/services/index.js new file mode 100644 index 0000000..e77ea9f --- /dev/null +++ b/lib/services/index.js @@ -0,0 +1,28 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./check"), exports); +__exportStar(require("./data"), exports); +__exportStar(require("./error"), exports); +__exportStar(require("./events"), exports); +__exportStar(require("./logger"), exports); +__exportStar(require("./router"), exports); +__exportStar(require("./routerMsg"), exports); +__exportStar(require("./schema"), exports); +__exportStar(require("./sync"), exports); +__exportStar(require("./treeCache"), exports); +__exportStar(require("./utils"), exports); +__exportStar(require("./worker"), exports); diff --git a/lib/services/logger.d.ts b/lib/services/logger.d.ts new file mode 100644 index 0000000..3c4a44d --- /dev/null +++ b/lib/services/logger.d.ts @@ -0,0 +1,2 @@ +import winston from 'winston'; +export declare function getLogger(label?: string, minLevel?: string): winston.Logger; diff --git a/lib/services/logger.js b/lib/services/logger.js new file mode 100644 index 0000000..8737589 --- /dev/null +++ b/lib/services/logger.js @@ -0,0 +1,26 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getLogger = getLogger; +const winston_1 = __importDefault(require("winston")); +const safe_1 = __importDefault(require("@colors/colors/safe")); +function getLogger(label, minLevel) { + return winston_1.default.createLogger({ + format: winston_1.default.format.combine(winston_1.default.format.label({ label }), winston_1.default.format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss', + }), + // Include timestamp on level + winston_1.default.format((info) => { + info.level = `[${info.level}]`; + while (info.level.length < 8) { + info.level += ' '; + } + info.level = `${info.timestamp} ${info.level}`.toUpperCase(); + return info; + })(), winston_1.default.format.colorize(), winston_1.default.format.printf((info) => `${info.level} ${info.label ? `${info.label} ` : ''}${safe_1.default.grey(info.message)}`)), + // Define level filter from config + transports: [new winston_1.default.transports.Console({ level: minLevel || 'debug' })], + }); +} diff --git a/lib/services/router.d.ts b/lib/services/router.d.ts new file mode 100644 index 0000000..131a3e8 --- /dev/null +++ b/lib/services/router.d.ts @@ -0,0 +1,38 @@ +import type { Logger } from 'winston'; +import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { NetIdType, DepositsEvents, WithdrawalsEvents, EchoEvents, EncryptedNotesEvents, AllGovernanceEvents, TovarishStatus, AllRelayerRegistryEvents, StakeBurnedEvents } from '@tornado/core'; +import { RelayerConfig } from '../config'; +import { SentMsg } from './routerMsg'; +import { SyncManagerStatus } from './sync'; +export declare function getHealthStatus(netId: NetIdType, syncManagerStatus: SyncManagerStatus): string; +export declare function getGasPrices(netId: NetIdType, syncManagerStatus: SyncManagerStatus): { + fast: number; + additionalProperties: number | undefined; +}; +export declare function formatStatus({ url, netId, relayerConfig, syncManagerStatus, pendingWorks, }: { + url: string; + netId: NetIdType; + relayerConfig: RelayerConfig; + syncManagerStatus: SyncManagerStatus; + pendingWorks: number; +}): TovarishStatus; +export declare function handleIndex(enabledNetworks: NetIdType[]): string; +export declare function handleStatus(url: string, router: Router, netId: NetIdType | NetIdType[], reply: FastifyReply): Promise; +/** + * Since we check gasLimit and fees, should extend timeout at any proxy more than 60s + */ +export declare function handleTornadoWithdraw(router: Router, netId: NetIdType, req: FastifyRequest, reply: FastifyReply): Promise; +export declare function handleGetJob(router: Router, req: FastifyRequest, reply: FastifyReply): Promise; +export type AllTovarishEvents = DepositsEvents | WithdrawalsEvents | EchoEvents | EncryptedNotesEvents | AllGovernanceEvents | AllRelayerRegistryEvents | StakeBurnedEvents; +export declare function handleEvents(router: Router, netId: NetIdType, req: FastifyRequest, reply: FastifyReply): Promise; +export declare function handleTrees(router: Router, req: FastifyRequest, reply: FastifyReply): Promise; +export declare function listenRouter(router: Router): void; +export declare class Router { + relayerConfig: RelayerConfig; + logger: Logger; + forkId: number; + app: FastifyInstance; + admin: FastifyInstance; + messages: SentMsg[]; + constructor(relayerConfig: RelayerConfig, forkId?: number); +} diff --git a/lib/services/router.js b/lib/services/router.js new file mode 100644 index 0000000..9ff7385 --- /dev/null +++ b/lib/services/router.js @@ -0,0 +1,311 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Router = void 0; +exports.getHealthStatus = getHealthStatus; +exports.getGasPrices = getGasPrices; +exports.formatStatus = formatStatus; +exports.handleIndex = handleIndex; +exports.handleStatus = handleStatus; +exports.handleTornadoWithdraw = handleTornadoWithdraw; +exports.handleGetJob = handleGetJob; +exports.handleEvents = handleEvents; +exports.handleTrees = handleTrees; +exports.listenRouter = listenRouter; +const path_1 = __importDefault(require("path")); +const fs_1 = require("fs"); +const fastify_1 = require("fastify"); +const cors_1 = require("@fastify/cors"); +const core_1 = require("@tornado/core"); +const ethers_1 = require("ethers"); +const config_1 = require("../config"); +const logger_1 = require("./logger"); +const routerMsg_1 = require("./routerMsg"); +const data_1 = require("./data"); +const schema_1 = require("./schema"); +function getHealthStatus(netId, syncManagerStatus) { + const { events, tokenPrice, gasPrice } = syncManagerStatus.syncStatus[netId]; + return String(Boolean(events && tokenPrice && gasPrice)); +} +function getGasPrices(netId, syncManagerStatus) { + const { gasPrice, l1Fee } = syncManagerStatus.cachedGasPrices[netId]; + return { + fast: Number(gasPrice), + additionalProperties: l1Fee ? Number(l1Fee) : undefined, + }; +} +function formatStatus({ url, netId, relayerConfig, syncManagerStatus, pendingWorks, }) { + const config = (0, core_1.getConfig)(netId); + return { + url, + rewardAccount: relayerConfig.rewardAccount, + instances: (0, core_1.getActiveTokenInstances)(config), + events: syncManagerStatus.cachedEvents[netId], + gasPrices: getGasPrices(netId, syncManagerStatus), + netId, + ethPrices: syncManagerStatus.cachedPrices[netId], + tornadoServiceFee: relayerConfig.serviceFee, + latestBlock: syncManagerStatus.latestBlocks[netId], + latestBalance: syncManagerStatus.latestBalances[netId], + version: config_1.version, + health: { + status: getHealthStatus(netId, syncManagerStatus), + error: '', + errorsLog: [...syncManagerStatus.errors.filter((e) => e.netId === netId)], + }, + syncStatus: syncManagerStatus.syncStatus[netId], + onSyncEvents: syncManagerStatus.onSyncEvents, + currentQueue: pendingWorks, + }; +} +function handleIndex(enabledNetworks) { + return ('This is Tornado Cash Relayer service. Check the ' + + enabledNetworks.map((netId) => `/${netId}/v1/status `).join(', ') + + 'for settings'); +} +async function handleStatus(url, router, netId, reply) { + const { relayerConfig } = router; + const { syncManagerStatus, pendingWorks } = await (0, routerMsg_1.sendMessage)(router, { type: 'status' }); + if (Array.isArray(netId)) { + reply.send(netId.map((n) => formatStatus({ + url, + netId: n, + relayerConfig, + syncManagerStatus, + pendingWorks, + }))); + return; + } + reply.send(formatStatus({ + url, + netId, + relayerConfig, + syncManagerStatus, + pendingWorks, + })); +} +/** + * Since we check gasLimit and fees, should extend timeout at any proxy more than 60s + */ +async function handleTornadoWithdraw(router, netId, req, reply) { + const { contract, proof, args } = req.body; + const { id, error } = await (0, routerMsg_1.sendMessage)(router, { + type: 'tornadoWithdraw', + netId, + contract, + proof, + args, + }); + if (error) { + reply.code(502).send({ error }); + return; + } + reply.send({ id }); +} +async function handleGetJob(router, req, reply) { + const { id } = req.params; + const job = await (0, routerMsg_1.sendMessage)(router, { type: 'job', id }); + if (job.error) { + reply.code(502).send(job); + return; + } + reply.send(job); +} +async function handleEvents(router, netId, req, reply) { + const { relayerConfig: { userEventsDir: userDirectory }, } = router; + const { type, currency, amount, fromBlock, recent } = req.body; + const name = [core_1.DEPOSIT, core_1.WITHDRAWAL].includes(type) ? `${type}s_${netId}_${currency}_${amount}` : `${type}_${netId}`; + // Can return 0 events but we just return error codes here + if (!(await (0, data_1.existsAsync)(path_1.default.join(userDirectory, `${name}.json`)))) { + reply.code(404).send(`Events ${name} not found!`); + return; + } + const { syncManagerStatus } = await (0, routerMsg_1.sendMessage)(router, { type: 'status' }); + const lastSyncBlock = Number([core_1.DEPOSIT, core_1.WITHDRAWAL].includes(type) + ? syncManagerStatus.cachedEvents[netId]?.instances?.[String(currency)]?.[String(amount)]?.[`${type}s`]?.lastBlock + : syncManagerStatus.cachedEvents[netId]?.[String(type)]?.lastBlock); + const { events } = await (0, data_1.loadSavedEvents)({ + name, + userDirectory, + }); + if (recent) { + reply.send({ + events: events.slice(-10).sort((a, b) => { + if (a.blockNumber === b.blockNumber) { + return b.logIndex - a.logIndex; + } + return b.blockNumber - a.blockNumber; + }), + lastSyncBlock, + }); + return; + } + reply.send({ + events: events.filter((e) => e.blockNumber >= (fromBlock || 0)).slice(0, core_1.MAX_TOVARISH_EVENTS), + lastSyncBlock, + }); +} +async function handleTrees(router, req, reply) { + const treeRegex = /deposits_(?\d+)_(?\w+)_(?[\d.]+)_(?\w+).json.zip/g; + const { netId, currency, amount, part } = treeRegex.exec(req.params.treeName)?.groups || {}; + const treeName = `deposits_${netId}_${currency}_${amount}_${part}.json.zip`; + const treePath = path_1.default.join(router.relayerConfig.userTreeDir, treeName); + if (!(await (0, data_1.existsAsync)(treePath))) { + reply.status(404).send(`Tree ${treeName} not found!`); + return; + } + reply.send((0, fs_1.createReadStream)(treePath)); +} +function listenRouter(router) { + const { relayerConfig, logger, app, admin, forkId } = router; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + app.register(cors_1.fastifyCors, () => (req, callback) => { + callback(null, { + origin: req.headers.origin || '*', + credentials: true, + methods: ['GET, POST, OPTIONS'], + headers: [ + 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type', + ], + maxAge: 1728000, + }); + }); + app.get('/', (_, reply) => { + reply.type('text/html').send(handleIndex(relayerConfig.enabledNetworks)); + }); + app.get('/relayer', (_, reply) => { + reply.type('text/html').send(handleIndex(relayerConfig.enabledNetworks)); + }); + app.get('/status', (req, reply) => { + handleStatus(`${req.protocol}://${req.hostname}`, router, relayerConfig.enabledNetworks, reply); + }); + app.get('/enabledNetworks', (_, reply) => { + reply.send(relayerConfig.enabledNetworks); + }); + if (forkId === 0) { + logger.info('Router listening on /, /status, /enabledNetworks'); + } + for (const netId of relayerConfig.enabledNetworks) { + app.get(`/${netId}`, (_, reply) => { + reply.type('text/html').send(handleIndex([netId])); + }); + app.get(`/${netId}/status`, (req, reply) => { + handleStatus(`${req.protocol}://${req.hostname}/${netId}`, router, netId, reply); + }); + const withdrawSchema = (0, schema_1.getWithdrawSchema)(netId); + app.post(`/${netId}/relay`, { schema: withdrawSchema }, (req, reply) => { + handleTornadoWithdraw(router, netId, req, reply); + }); + app.get(`/${netId}/v1/status`, (req, reply) => { + handleStatus(`${req.protocol}://${req.hostname}/${netId}`, router, netId, reply); + }); + app.post(`/${netId}/v1/tornadoWithdraw`, { schema: withdrawSchema }, (req, reply) => { + handleTornadoWithdraw(router, netId, req, reply); + }); + app.get(`/${netId}/v1/jobs/:id`, { schema: schema_1.idParamsSchema }, (req, reply) => { + handleGetJob(router, req, reply); + }); + const eventSchema = (0, schema_1.getEventsSchema)(netId); + app.post(`/${netId}/events`, { schema: eventSchema }, (req, reply) => { + handleEvents(router, netId, req, reply); + }); + app.get(`/${netId}/trees/:treeName`, { schema: schema_1.treeNameSchema }, (req, reply) => { + handleTrees(router, req, reply); + }); + if (forkId === 0) { + logger.info(`Router listening on /${netId}, /${netId}/status, /${netId}/relay, /${netId}/v1/status, /${netId}/v1/tornadoWithdraw, /${netId}/v1/jobs/:id, /${netId}/events, /${netId}/trees/:treeName`); + } + } + const { port, host } = relayerConfig; + app.listen({ port, host }, (err, address) => { + if (err) { + logger.error('Router Error'); + console.log(err); + throw err; + } + else { + logger.debug(`Router listening on ${address}`); + } + }); + admin.get('/errors', (_, reply) => { + (async () => { + const { errors } = await (0, routerMsg_1.sendMessage)(router, { type: 'errors' }); + reply.header('Content-Type', 'application/json').send(JSON.stringify(errors, null, 2)); + })(); + }); + admin.listen({ port: port + 100, host }, (err, address) => { + if (err) { + logger.error('Admin Router Error'); + console.log(err); + throw err; + } + else { + if (forkId === 0) { + logger.debug(`Admin Router listening on ${address}`); + } + } + }); + (0, routerMsg_1.resolveMessages)(router); +} +class Router { + relayerConfig; + logger; + forkId; + app; + // For viewing error logs + admin; + messages; + constructor(relayerConfig, forkId = 0) { + this.relayerConfig = relayerConfig; + this.logger = (0, logger_1.getLogger)(`[Router ${forkId}]`, relayerConfig.logLevel); + this.forkId = forkId; + const app = (0, fastify_1.fastify)({ + ajv: { + customOptions: { + keywords: [ + { + keyword: 'isAddress', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + validate: (schema, data) => { + try { + return (0, ethers_1.isAddress)(data); + } + catch { + return false; + } + }, + errors: true, + }, + { + keyword: 'BN', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + validate: (schema, data) => { + try { + BigInt(data); + return true; + } + catch { + return false; + } + }, + errors: true, + }, + (0, schema_1.getTreeNameKeyword)(), + ...(0, schema_1.getAllWithdrawKeyword)(relayerConfig.rewardAccount), + ...(0, schema_1.getAllEventsKeyword)(), + ], + }, + }, + trustProxy: relayerConfig.reverseProxy ? 1 : false, + ignoreTrailingSlash: true, + }); + const admin = (0, fastify_1.fastify)(); + this.app = app; + this.admin = admin; + this.messages = []; + listenRouter(this); + } +} +exports.Router = Router; diff --git a/lib/services/routerMsg.d.ts b/lib/services/routerMsg.d.ts new file mode 100644 index 0000000..d9156d5 --- /dev/null +++ b/lib/services/routerMsg.d.ts @@ -0,0 +1,9 @@ +import { Router } from './router'; +export interface SentMsg { + msgId: string; + resolve: (msg: any) => void; + reject: (err: any) => void; + resolved: boolean; +} +export declare function sendMessage(router: Router, msg: any): Promise; +export declare function resolveMessages(router: Router): void; diff --git a/lib/services/routerMsg.js b/lib/services/routerMsg.js new file mode 100644 index 0000000..9d0ae51 --- /dev/null +++ b/lib/services/routerMsg.js @@ -0,0 +1,45 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.sendMessage = sendMessage; +exports.resolveMessages = resolveMessages; +/* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Send and receive messages from worker to main thread + */ +const process_1 = __importDefault(require("process")); +const crypto_1 = require("crypto"); +const core_1 = require("@tornado/core"); +function sendMessage(router, msg) { + const msgId = (0, core_1.bytesToHex)(crypto_1.webcrypto.getRandomValues(new Uint8Array(8))); + return new Promise((resolve, reject) => { + if (!process_1.default.send) { + reject(new Error('Not worker')); + return; + } + const msgJson = JSON.parse(JSON.stringify(msg)); + msgJson.msgId = msgId; + process_1.default.send(msgJson); + router.messages.push({ + msgId, + resolve, + reject, + resolved: false, + }); + }); +} +function resolveMessages(router) { + process_1.default.on('message', (msg) => { + const message = router.messages.find((w) => w.msgId === msg.msgId); + if (!message) { + return; + } + const msgJson = JSON.parse(JSON.stringify(msg)); + delete msgJson.msgId; + message.resolve(msgJson); + message.resolved = true; + router.messages = router.messages.filter((w) => !w.resolved); + }); +} diff --git a/lib/services/schema.d.ts b/lib/services/schema.d.ts new file mode 100644 index 0000000..353d15c --- /dev/null +++ b/lib/services/schema.d.ts @@ -0,0 +1,132 @@ +import { NetIdType, TornadoWithdrawParams, TovarishEventsQuery } from '@tornado/core'; +export declare const idParamsSchema: { + readonly params: { + readonly type: "object"; + readonly properties: { + readonly id: { + readonly type: "string"; + readonly format: "uuid"; + }; + }; + readonly required: readonly ["id"]; + readonly additionalProperties: false; + }; +}; +export declare const withdrawBodySchema: { + readonly body: { + readonly type: "object"; + readonly properties: { + readonly proof: { + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{512}$"; + }; + readonly contract: { + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{40}$"; + readonly isAddress: true; + }; + readonly args: { + readonly type: "array"; + readonly maxItems: 6; + readonly minItems: 6; + readonly items: readonly [{ + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{64}$"; + }, { + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{64}$"; + }, { + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{40}$"; + readonly isAddress: true; + }, { + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{40}$"; + readonly isAddress: true; + }, { + readonly BN: true; + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{64}$"; + }, { + readonly BN: true; + readonly type: "string"; + readonly pattern: "^0x[a-fA-F0-9]{64}$"; + }]; + }; + }; + readonly additionalProperties: false; + readonly required: readonly ["proof", "contract", "args"]; + }; +}; +export declare const eventsSchema: { + readonly body: { + readonly type: "object"; + readonly properties: { + readonly type: { + readonly type: "string"; + readonly minLength: 1; + readonly maxLength: 30; + }; + readonly currency: { + readonly type: "string"; + readonly minLength: 1; + readonly maxLength: 30; + }; + readonly amount: { + readonly type: "string"; + readonly minLength: 1; + readonly maxLength: 30; + }; + readonly fromBlock: { + readonly type: "number"; + }; + readonly recent: { + readonly type: "boolean"; + }; + }; + readonly additionalProperties: false; + readonly required: readonly ["type", "fromBlock"]; + }; +}; +export declare const treeNameSchema: { + readonly params: { + readonly type: "object"; + readonly properties: { + readonly treeName: { + readonly type: "string"; + readonly minLength: 1; + readonly maxLength: 60; + readonly TreeName: true; + }; + }; + readonly additionalProperties: false; + readonly required: readonly ["treeName"]; + }; +}; +export declare function getWithdrawSchema(netId: NetIdType): typeof withdrawBodySchema & { [key in number | typeof Symbol.iterator | "length" | "toString" | "concat" | "slice" | "indexOf" | "lastIndexOf" | "includes" | "at" | "charAt" | "charCodeAt" | "localeCompare" | "match" | "replace" | "search" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" | "codePointAt" | "endsWith" | "normalize" | "repeat" | "startsWith" | "anchor" | "big" | "blink" | "bold" | "fixed" | "fontcolor" | "fontsize" | "italics" | "link" | "small" | "strike" | "sub" | "sup" | "padStart" | "padEnd" | "trimEnd" | "trimStart" | "trimLeft" | "trimRight" | "matchAll" | "replaceAll" | "isWellFormed" | "toWellFormed" | "valueOf"]: boolean; }; +export declare function getEventsSchema(netId: NetIdType): typeof eventsSchema & { [key in number | typeof Symbol.iterator | "length" | "toString" | "concat" | "slice" | "indexOf" | "lastIndexOf" | "includes" | "at" | "charAt" | "charCodeAt" | "localeCompare" | "match" | "replace" | "search" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" | "codePointAt" | "endsWith" | "normalize" | "repeat" | "startsWith" | "anchor" | "big" | "blink" | "bold" | "fixed" | "fontcolor" | "fontsize" | "italics" | "link" | "small" | "strike" | "sub" | "sup" | "padStart" | "padEnd" | "trimEnd" | "trimStart" | "trimLeft" | "trimRight" | "matchAll" | "replaceAll" | "isWellFormed" | "toWellFormed" | "valueOf"]: boolean; }; +export declare function getWithdrawKeyword(netId: NetIdType, rewardAccount: string): { + keyword: string; + validate: (schema: string, data: TornadoWithdrawParams) => boolean; + errors: boolean; +}; +export declare function getEventsKeyword(netId: NetIdType): { + keyword: string; + validate: (schema: string, data: TovarishEventsQuery) => boolean; + errors: boolean; +}; +export declare function getTreeNameKeyword(): { + keyword: string; + validate: (schema: string, data: string) => boolean; + errors: boolean; +}; +export declare function getAllWithdrawKeyword(rewardAccount: string): { + keyword: string; + validate: (schema: string, data: TornadoWithdrawParams) => boolean; + errors: boolean; +}[]; +export declare function getAllEventsKeyword(): { + keyword: string; + validate: (schema: string, data: TovarishEventsQuery) => boolean; + errors: boolean; +}[]; diff --git a/lib/services/schema.js b/lib/services/schema.js new file mode 100644 index 0000000..3555d0f --- /dev/null +++ b/lib/services/schema.js @@ -0,0 +1,200 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.treeNameSchema = exports.eventsSchema = exports.withdrawBodySchema = exports.idParamsSchema = void 0; +exports.getWithdrawSchema = getWithdrawSchema; +exports.getEventsSchema = getEventsSchema; +exports.getWithdrawKeyword = getWithdrawKeyword; +exports.getEventsKeyword = getEventsKeyword; +exports.getTreeNameKeyword = getTreeNameKeyword; +exports.getAllWithdrawKeyword = getAllWithdrawKeyword; +exports.getAllEventsKeyword = getAllEventsKeyword; +const ethers_1 = require("ethers"); +const core_1 = require("@tornado/core"); +exports.idParamsSchema = { + params: { + type: 'object', + properties: { + id: { type: 'string', format: 'uuid' }, + }, + required: ['id'], + additionalProperties: false, + }, +}; +exports.withdrawBodySchema = { + body: { + type: 'object', + properties: { + proof: core_1.proofSchemaType, + contract: core_1.addressSchemaType, + args: { + type: 'array', + maxItems: 6, + minItems: 6, + items: [ + core_1.bytes32SchemaType, + core_1.bytes32SchemaType, + core_1.addressSchemaType, + core_1.addressSchemaType, + core_1.bytes32BNSchemaType, + core_1.bytes32BNSchemaType, + ], + }, + }, + additionalProperties: false, + required: ['proof', 'contract', 'args'], + }, +}; +const stringParamsType = { + type: 'string', + minLength: 1, + maxLength: 30, +}; +exports.eventsSchema = { + body: { + type: 'object', + properties: { + type: stringParamsType, + currency: stringParamsType, + amount: stringParamsType, + fromBlock: { type: 'number' }, + recent: { type: 'boolean' }, + }, + additionalProperties: false, + required: ['type', 'fromBlock'], + }, +}; +exports.treeNameSchema = { + params: { + type: 'object', + properties: { + treeName: { + type: 'string', + minLength: 1, + maxLength: 60, + TreeName: true, + }, + }, + additionalProperties: false, + required: ['treeName'], + }, +}; +function getWithdrawSchema(netId) { + const keyword = `withdraw${netId}`; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const schema = JSON.parse(JSON.stringify(exports.withdrawBodySchema)); + schema.body[keyword] = true; + return schema; +} +function getEventsSchema(netId) { + const keyword = `events${netId}`; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const schema = JSON.parse(JSON.stringify(exports.eventsSchema)); + schema.body[keyword] = true; + return schema; +} +function getWithdrawKeyword(netId, rewardAccount) { + const keyword = `withdraw${netId}`; + const config = (0, core_1.getConfig)(netId); + return { + keyword, + validate: (schema, data) => { + try { + const { contract, args } = data; + const instance = (0, core_1.getInstanceByAddress)(config, contract); + // Unknown instance contract is unsupported + if (!instance) { + return false; + } + // Fee recipient should be a reward account + if (args[3] !== rewardAccount) { + return false; + } + const { amount, currency } = instance; + const { nativeCurrency, tokens: { [currency]: { decimals }, }, } = config; + const denomination = (0, ethers_1.parseUnits)(amount, decimals); + const fee = BigInt(args[4]); + // Fees can't exceed denomination + if (!fee || fee >= denomination) { + return false; + } + // ETHTornado instances can't have refunds + if (currency === nativeCurrency && BigInt(args[5])) { + return false; + } + return true; + } + catch { + return false; + } + }, + errors: true, + }; +} +function getEventsKeyword(netId) { + const keyword = `events${netId}`; + const config = (0, core_1.getConfig)(netId); + const { governanceContract, registryContract } = config; + return { + keyword, + validate: (schema, data) => { + try { + const { type, currency, amount } = data; + if ([core_1.DEPOSIT, core_1.WITHDRAWAL].includes(type)) { + const instanceAddress = config.tokens[String(currency)]?.instanceAddress?.[String(amount)]; + if (!instanceAddress) { + return false; + } + return true; + } + if (type === 'governance') { + if (!governanceContract) { + return false; + } + return true; + } + // todo: remove this after some time, remains for legacy client connection + if (['registered', 'registry', 'revenue'].includes(type)) { + if (!registryContract) { + return false; + } + return true; + } + return ['echo', 'encrypted_notes'].includes(type); + } + catch { + return false; + } + }, + errors: true, + }; +} +function getTreeNameKeyword() { + return { + keyword: 'TreeName', + validate: (schema, data) => { + try { + const treeRegex = /deposits_(?\d+)_(?\w+)_(?[\d.]+)_(?\w+).json.zip/g; + const { netId, currency, amount, part } = treeRegex.exec(data)?.groups || {}; + const config = (0, core_1.getConfig)(Number(netId)); + if (!currency || !amount || !part || currency !== config.nativeCurrency) { + return false; + } + const instanceAddress = config.tokens[String(currency)]?.instanceAddress?.[String(amount)]; + if (!instanceAddress) { + return false; + } + return true; + } + catch { + return false; + } + }, + errors: true, + }; +} +function getAllWithdrawKeyword(rewardAccount) { + return core_1.enabledChains.map((netId) => getWithdrawKeyword(netId, rewardAccount)); +} +function getAllEventsKeyword() { + return core_1.enabledChains.map((netId) => getEventsKeyword(netId)); +} diff --git a/lib/services/sync.d.ts b/lib/services/sync.d.ts new file mode 100644 index 0000000..02673b1 --- /dev/null +++ b/lib/services/sync.d.ts @@ -0,0 +1,92 @@ +import type { Provider } from 'ethers'; +import type { Logger } from 'winston'; +import { NetIdType, TokenPriceOracle, TornadoFeeOracle, TovarishEventsStatus, TovarishSyncStatus } from '@tornado/core'; +import { RelayerConfig } from '../config'; +import { NodeEchoService, NodeEncryptedNotesService, NodeGovernanceService, NodeRegistryService, NodeRevenueService, NodeTornadoService } from './events'; +import { ErrorTypes, ErrorMessages } from './error'; +export interface AmountsServices { + depositsService: NodeTornadoService; + withdrawalsService: NodeTornadoService; +} +export interface CurrencyServices { + [index: string]: AmountsServices; +} +export interface TornadoServices { + [index: string]: CurrencyServices; +} +export interface Services { + provider: Provider; + tokenPriceOracle: TokenPriceOracle; + tornadoFeeOracle: TornadoFeeOracle; + governanceService?: NodeGovernanceService; + registryService?: NodeRegistryService; + revenueService?: NodeRevenueService; + echoService: NodeEchoService; + encryptedNotesService: NodeEncryptedNotesService; + tornadoServices: TornadoServices; +} +export interface CachedServices { + [index: NetIdType]: Services; +} +export interface CachedEventsStatus { + [index: NetIdType]: TovarishEventsStatus; +} +export interface TokenPrices { + [index: string]: bigint; +} +export interface TokenPricesString { + [index: string]: string; +} +export interface CachedPrices { + [index: NetIdType]: TokenPrices; +} +export interface CachedPricesString { + [index: NetIdType]: TokenPricesString; +} +export interface GasPrices { + gasPrice: string; + l1Fee?: string; +} +export interface CachedGasPrices { + [index: NetIdType]: GasPrices; +} +export interface LatestBlocks { + [index: NetIdType]: number; +} +export interface LatestBalances { + [index: NetIdType]: string; +} +export interface CachedSyncStatus { + [index: NetIdType]: TovarishSyncStatus; +} +export declare function syncGasPrice(syncManager: SyncManager, netId: NetIdType): Promise; +export declare function syncPrices(syncManager: SyncManager, netId: NetIdType): Promise; +export declare function syncNetworkEvents(syncManager: SyncManager, netId: NetIdType): Promise; +export interface SyncManagerStatus { + cachedEvents: CachedEventsStatus; + cachedPrices: CachedPricesString; + cachedGasPrices: CachedGasPrices; + syncStatus: CachedSyncStatus; + latestBlocks: LatestBlocks; + latestBalances: LatestBalances; + errors: ErrorTypes[]; + onSyncEvents: boolean; +} +export declare class SyncManager { + relayerConfig: RelayerConfig; + logger: Logger; + cachedServices: CachedServices; + cachedEvents: CachedEventsStatus; + cachedPrices: CachedPrices; + cachedGasPrices: CachedGasPrices; + syncStatus: CachedSyncStatus; + latestBlocks: LatestBlocks; + latestBalances: LatestBalances; + errors: ErrorMessages[]; + onSyncEvents: boolean; + constructor(relayerConfig: RelayerConfig); + getStatus(): SyncManagerStatus; + getPrice(netId: NetIdType, token: string): bigint; + getGasPrice(netId: NetIdType): GasPrices; + syncEvents(): Promise; +} diff --git a/lib/services/sync.js b/lib/services/sync.js new file mode 100644 index 0000000..f8c11a0 --- /dev/null +++ b/lib/services/sync.js @@ -0,0 +1,365 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SyncManager = void 0; +exports.syncGasPrice = syncGasPrice; +exports.syncPrices = syncPrices; +exports.syncNetworkEvents = syncNetworkEvents; +const contracts_1 = require("@tornado/contracts"); +const core_1 = require("@tornado/core"); +const logger_1 = require("./logger"); +const treeCache_1 = require("./treeCache"); +const events_1 = require("./events"); +const error_1 = require("./error"); +function setupServices(syncManager) { + const { relayerConfig, logger, syncStatus } = syncManager; + const { cacheDir: cacheDirectory, userEventsDir: userDirectory, userTreeDir, merkleWorkerPath, enabledNetworks, } = relayerConfig; + const cachedServices = {}; + for (const netId of enabledNetworks) { + const config = (0, core_1.getConfig)(netId); + const rpcUrl = relayerConfig.rpcUrls[netId]; + const provider = (0, core_1.getProviderWithNetId)(netId, rpcUrl, config); + const { tokens, nativeCurrency, routerContract, echoContract, registryContract, aggregatorContract, reverseRecordsContract, governanceContract, multicallContract, offchainOracleContract, ovmGasPriceOracleContract, deployedBlock, constants: { GOVERNANCE_BLOCK, REGISTRY_BLOCK, NOTE_ACCOUNT_BLOCK, ENCRYPTED_NOTES_BLOCK }, } = config; + if (!syncStatus[netId]) { + syncStatus[netId] = { + events: false, + tokenPrice: false, + gasPrice: false, + }; + } + const services = (cachedServices[netId] = {}); + services.provider = provider; + services.tokenPriceOracle = new core_1.TokenPriceOracle(provider, core_1.Multicall__factory.connect(multicallContract, provider), offchainOracleContract ? core_1.OffchainOracle__factory.connect(offchainOracleContract, provider) : undefined); + services.tornadoFeeOracle = new core_1.TornadoFeeOracle(provider, ovmGasPriceOracleContract + ? core_1.OvmGasPriceOracle__factory.connect(ovmGasPriceOracleContract, provider) + : undefined); + if (governanceContract && aggregatorContract && reverseRecordsContract) { + services.governanceService = new events_1.NodeGovernanceService({ + netId, + provider, + Governance: contracts_1.Governance__factory.connect(governanceContract, provider), + Aggregator: contracts_1.Aggregator__factory.connect(aggregatorContract, provider), + ReverseRecords: core_1.ReverseRecords__factory.connect(reverseRecordsContract, provider), + deployedBlock: GOVERNANCE_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + } + if (registryContract && aggregatorContract) { + services.registryService = new events_1.NodeRegistryService({ + netId, + provider, + RelayerRegistry: contracts_1.RelayerRegistry__factory.connect(registryContract, provider), + Aggregator: contracts_1.Aggregator__factory.connect(aggregatorContract, provider), + relayerEnsSubdomains: (0, core_1.getRelayerEnsSubdomains)(), + deployedBlock: REGISTRY_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + services.revenueService = new events_1.NodeRevenueService({ + netId, + provider, + RelayerRegistry: contracts_1.RelayerRegistry__factory.connect(registryContract, provider), + deployedBlock: REGISTRY_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + } + services.echoService = new events_1.NodeEchoService({ + netId, + provider, + Echoer: contracts_1.Echoer__factory.connect(echoContract, provider), + deployedBlock: NOTE_ACCOUNT_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + services.encryptedNotesService = new events_1.NodeEncryptedNotesService({ + netId, + provider, + Router: contracts_1.TornadoRouter__factory.connect(routerContract, provider), + deployedBlock: ENCRYPTED_NOTES_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + services.tornadoServices = {}; + for (const currency of (0, core_1.getActiveTokens)(config)) { + const currencyConfig = tokens[currency]; + const currencyService = (services.tornadoServices[currency] = {}); + for (const [amount, instanceAddress] of Object.entries(currencyConfig.instanceAddress)) { + const Tornado = contracts_1.Tornado__factory.connect(instanceAddress, provider); + const amountService = (currencyService[amount] = {}); + const TornadoServiceConstructor = { + netId, + provider, + Tornado, + amount, + currency, + deployedBlock, + cacheDirectory, + userDirectory, + nativeCurrency, + logger, + }; + amountService.depositsService = new events_1.NodeTornadoService({ + ...TornadoServiceConstructor, + merkleTreeService: new core_1.MerkleTreeService({ + netId, + amount, + currency, + Tornado, + merkleWorkerPath, + }), + treeCache: new treeCache_1.TreeCache({ + netId, + amount, + currency, + userDirectory: userTreeDir, + }), + optionalTree: true, + type: 'Deposit', + }); + amountService.withdrawalsService = new events_1.NodeTornadoService({ + ...TornadoServiceConstructor, + type: 'Withdrawal', + }); + } + } + } + syncManager.cachedServices = cachedServices; +} +async function syncGasPrice(syncManager, netId) { + const { cachedServices, logger, errors, cachedGasPrices, latestBlocks, latestBalances, syncStatus, relayerConfig: { rewardAccount }, } = syncManager; + try { + const services = cachedServices[netId]; + const { provider, tornadoFeeOracle } = services; + const [blockNumber, balance, gasPrice, l1Fee] = await Promise.all([ + provider.getBlockNumber(), + provider.getBalance(rewardAccount), + tornadoFeeOracle.gasPrice(), + tornadoFeeOracle.fetchL1OptimismFee(), + ]); + cachedGasPrices[netId] = { + gasPrice: gasPrice.toString(), + l1Fee: l1Fee ? l1Fee.toString() : undefined, + }; + latestBlocks[netId] = blockNumber; + latestBalances[netId] = balance.toString(); + syncStatus[netId].gasPrice = true; + } + catch (err) { + logger.error(`${netId}: Failed to sync gas prices`); + console.log(err); + syncStatus[netId].gasPrice = false; + errors.push((0, error_1.newError)('SyncManager (gas)', netId, err)); + } +} +async function syncPrices(syncManager, netId) { + const { cachedServices, logger, errors, cachedPrices, syncStatus } = syncManager; + try { + const config = (0, core_1.getConfig)(netId); + const { nativeCurrency, tornContract } = config; + const services = cachedServices[netId]; + const { tokenPriceOracle } = services; + // Classic UI ajv validator requires all token prices to present + const allTokens = Object.keys(config.tokens); + if (tornContract && !allTokens.includes('torn')) { + allTokens.push('torn'); + } + const tokens = allTokens + .map((currency) => { + if (currency === nativeCurrency) { + return; + } + if (currency === 'torn') { + return { + currency, + tokenAddress: tornContract, + decimals: 18, + }; + } + const { tokenAddress, decimals } = config.tokens[currency]; + return { + currency, + tokenAddress, + decimals, + }; + }) + .filter((t) => t); + if (!tokens.length) { + syncStatus[netId].tokenPrice = true; + return; + } + cachedPrices[netId] = (await tokenPriceOracle.fetchPrices(tokens)).reduce((acc, price, index) => { + acc[tokens[index].currency] = price; + return acc; + }, {}); + syncStatus[netId].tokenPrice = true; + logger.info(`${netId}: Synced ${tokens.length} tokens price`); + } + catch (err) { + logger.error(`${netId}: Failed to sync prices`); + console.log(err); + syncStatus[netId].tokenPrice = false; + errors.push((0, error_1.newError)('SyncManager (price)', netId, err)); + } +} +async function syncNetworkEvents(syncManager, netId) { + const { cachedEvents, cachedServices, logger, errors, syncStatus } = syncManager; + try { + const services = cachedServices[netId]; + const { provider, governanceService, registryService, revenueService, echoService, encryptedNotesService, tornadoServices, } = services; + logger.info(`${netId}: Syncing events from block ${await provider.getBlockNumber()}`); + const eventsStatus = { + governance: governanceService ? {} : undefined, + registered: registryService ? {} : undefined, + registry: registryService ? {} : undefined, + revenue: revenueService ? {} : undefined, + echo: {}, + encrypted_notes: {}, + instances: {}, + }; + if (governanceService) { + const { events, lastBlock } = await governanceService.updateEvents(); + eventsStatus.governance = { + events: events.length, + lastBlock, + }; + logger.info(`${netId}: Updated governance events (total: ${events.length}, block: ${lastBlock})`); + } + if (registryService) { + { + const { events, lastBlock } = await registryService.updateEvents(); + eventsStatus.registry = { + events: events.length, + lastBlock, + }; + logger.info(`${netId}: Updated registry events (total: ${events.length}, block: ${lastBlock})`); + } + { + const { lastBlock, timestamp, relayers } = await registryService.updateRelayers(); + eventsStatus.registered = { + lastBlock, + timestamp, + relayers: relayers.length, + }; + logger.info(`${netId}: Updated registry relayers (total: ${relayers.length}, block: ${lastBlock}, timestamp: ${timestamp})`); + } + } + if (revenueService) { + const { events, lastBlock } = await revenueService.updateEvents(); + eventsStatus.revenue = { + events: events.length, + lastBlock, + }; + logger.info(`${netId}: Updated revenue events (total: ${events.length}, block: ${lastBlock})`); + } + const echoEvents = await echoService.updateEvents(); + eventsStatus.echo = { + events: echoEvents.events.length, + lastBlock: echoEvents.lastBlock, + }; + logger.info(`${netId}: Updated echo events (total: ${echoEvents.events.length}, block: ${echoEvents.lastBlock})`); + const encryptedNotesEvents = await encryptedNotesService.updateEvents(); + eventsStatus.encrypted_notes = { + events: encryptedNotesEvents.events.length, + lastBlock: encryptedNotesEvents.lastBlock, + }; + logger.info(`${netId}: Updated encrypted notes events (total: ${encryptedNotesEvents.events.length}, block: ${encryptedNotesEvents.lastBlock})`); + const currencies = Object.keys(tornadoServices); + for (const currency of currencies) { + const currencyStatus = (eventsStatus.instances[currency] = {}); + const amounts = Object.keys(tornadoServices[currency]); + for (const amount of amounts) { + const instanceStatus = (currencyStatus[amount] = { + deposits: {}, + withdrawals: {}, + }); + const { depositsService, withdrawalsService } = tornadoServices[currency][amount]; + const depositEvents = await depositsService.updateEvents(); + instanceStatus.deposits = { + events: depositEvents.events.length, + lastBlock: depositEvents.lastBlock, + }; + logger.info(`${netId}: Updated ${currency} ${amount} Tornado deposit events (total: ${depositEvents.events.length}, block: ${depositEvents.lastBlock})`); + const withdrawalEvents = await withdrawalsService.updateEvents(); + instanceStatus.withdrawals = { + events: withdrawalEvents.events.length, + lastBlock: withdrawalEvents.lastBlock, + }; + logger.info(`${netId}: Updated ${currency} ${amount} Tornado withdrawal events (total: ${withdrawalEvents.events.length}, block: ${withdrawalEvents.lastBlock})`); + } + } + cachedEvents[netId] = eventsStatus; + syncStatus[netId].events = true; + logger.info(`${netId}: Synced all events`); + await Promise.all([syncPrices(syncManager, netId), syncGasPrice(syncManager, netId)]); + } + catch (err) { + logger.error(`${netId}: Failed to sync events`); + console.log(err); + syncStatus[netId].events = false; + errors.push((0, error_1.newError)('SyncManager (events)', netId, err)); + } +} +class SyncManager { + relayerConfig; + logger; + cachedServices; + cachedEvents; + cachedPrices; + cachedGasPrices; + syncStatus; + latestBlocks; + latestBalances; + errors; + onSyncEvents; + constructor(relayerConfig) { + this.relayerConfig = relayerConfig; + this.logger = (0, logger_1.getLogger)('[SyncManager]', relayerConfig.logLevel); + this.cachedServices = {}; + this.cachedEvents = {}; + this.cachedPrices = {}; + this.cachedGasPrices = {}; + this.syncStatus = {}; + this.latestBlocks = {}; + this.latestBalances = {}; + this.errors = []; + this.onSyncEvents = false; + setupServices(this); + } + getStatus() { + return { + cachedEvents: this.cachedEvents, + cachedPrices: JSON.parse(JSON.stringify(this.cachedPrices)), + cachedGasPrices: JSON.parse(JSON.stringify(this.cachedGasPrices)), + syncStatus: this.syncStatus, + latestBlocks: this.latestBlocks, + latestBalances: this.latestBalances, + errors: this.errors.map(({ type, netId, timestamp }) => ({ + type, + netId, + timestamp, + })), + onSyncEvents: this.onSyncEvents, + }; + } + getPrice(netId, token) { + return this.cachedPrices[netId]?.[token] || BigInt(0); + } + getGasPrice(netId) { + return this.cachedGasPrices[netId]; + } + async syncEvents() { + if (this.onSyncEvents) { + return; + } + this.onSyncEvents = true; + await Promise.all(this.relayerConfig.enabledNetworks.map((netId) => syncNetworkEvents(this, Number(netId)))); + this.onSyncEvents = false; + } +} +exports.SyncManager = SyncManager; diff --git a/lib/services/treeCache.d.ts b/lib/services/treeCache.d.ts new file mode 100644 index 0000000..7ccfff8 --- /dev/null +++ b/lib/services/treeCache.d.ts @@ -0,0 +1,35 @@ +/** + * Create tree cache file from node.js + * + * Only works for node.js, modified from https://github.com/tornadocash/tornado-classic-ui/blob/master/scripts/updateTree.js + */ +import { MerkleTree } from '@tornado/fixed-merkle-tree'; +import { DepositsEvents } from '@tornado/core'; +import type { NetIdType } from '@tornado/core'; +export interface TreeCacheConstructor { + netId: NetIdType; + amount: string; + currency: string; + userDirectory: string; + PARTS_COUNT?: number; + LEAVES?: number; + zeroElement?: string; +} +export interface treeMetadata { + blockNumber: number; + logIndex: number; + transactionHash: string; + timestamp: number; + from: string; + leafIndex: number; +} +export declare class TreeCache { + netId: NetIdType; + amount: string; + currency: string; + userDirectory: string; + PARTS_COUNT: number; + constructor({ netId, amount, currency, userDirectory, PARTS_COUNT }: TreeCacheConstructor); + getInstanceName(): string; + createTree(events: DepositsEvents[], tree: MerkleTree): Promise; +} diff --git a/lib/services/treeCache.js b/lib/services/treeCache.js new file mode 100644 index 0000000..009f4ac --- /dev/null +++ b/lib/services/treeCache.js @@ -0,0 +1,65 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TreeCache = void 0; +const bloomfilter_js_1 = __importDefault(require("bloomfilter.js")); +const data_1 = require("./data"); +class TreeCache { + netId; + amount; + currency; + userDirectory; + PARTS_COUNT; + constructor({ netId, amount, currency, userDirectory, PARTS_COUNT = 4 }) { + this.netId = netId; + this.amount = amount; + this.currency = currency; + this.userDirectory = userDirectory; + this.PARTS_COUNT = PARTS_COUNT; + } + getInstanceName() { + return `deposits_${this.netId}_${this.currency}_${this.amount}`; + } + async createTree(events, tree) { + const bloom = new bloomfilter_js_1.default(events.length); + console.log(`Creating cached tree for ${this.getInstanceName()}\n`); + // events indexed by commitment + const eventsData = events.reduce((acc, { leafIndex, commitment, ...rest }, i) => { + if (leafIndex !== i) { + throw new Error(`leafIndex (${leafIndex}) !== i (${i})`); + } + acc[commitment] = { ...rest, leafIndex }; + return acc; + }, {}); + const slices = tree.getTreeSlices(this.PARTS_COUNT); + await Promise.all(slices.map(async (slice, index) => { + const metadata = slice.elements.reduce((acc, curr) => { + if (index < this.PARTS_COUNT - 1) { + bloom.add(curr); + } + acc.push(eventsData[curr]); + return acc; + }, []); + const dataString = JSON.stringify({ + ...slice, + metadata, + }, null, 2) + '\n'; + const fileName = `${this.getInstanceName()}_slice${index + 1}.json`; + await (0, data_1.saveUserFile)({ + fileName, + userDirectory: this.userDirectory, + dataString, + }); + })); + const dataString = bloom.serialize() + '\n'; + const fileName = `${this.getInstanceName()}_bloom.json`; + await (0, data_1.saveUserFile)({ + fileName, + userDirectory: this.userDirectory, + dataString, + }); + } +} +exports.TreeCache = TreeCache; diff --git a/lib/services/utils.d.ts b/lib/services/utils.d.ts new file mode 100644 index 0000000..7edec0b --- /dev/null +++ b/lib/services/utils.d.ts @@ -0,0 +1,2 @@ +export declare const chunk: (arr: T[], size: number) => T[][]; +export declare function sleep(ms: number): Promise; diff --git a/lib/services/utils.js b/lib/services/utils.js new file mode 100644 index 0000000..9cfc76a --- /dev/null +++ b/lib/services/utils.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.chunk = void 0; +exports.sleep = sleep; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +BigInt.prototype.toJSON = function () { + return this.toString(); +}; +const chunk = (arr, size) => [...Array(Math.ceil(arr.length / size))].map((_, i) => arr.slice(size * i, size + size * i)); +exports.chunk = chunk; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/lib/services/worker.d.ts b/lib/services/worker.d.ts new file mode 100644 index 0000000..60818c2 --- /dev/null +++ b/lib/services/worker.d.ts @@ -0,0 +1,80 @@ +import type { Logger } from 'winston'; +import { Provider } from 'ethers'; +import { TornadoRouter } from '@tornado/contracts'; +import { NetIdType, TornadoWithdrawParams, RelayerTornadoJobs, RelayerTornadoWithdraw, TornadoFeeOracle, snarkArgs, Config, TornadoWallet } from '@tornado/core'; +import { RelayerConfig } from '../config'; +import { SyncManager } from './sync'; +import { ErrorMessages } from './error'; +export declare enum RelayerStatus { + QUEUED = "QUEUED", + ACCEPTED = "ACCEPTED", + SENT = "SENT", + MINED = "MINED", + RESUBMITTED = "RESUBMITTED", + CONFIRMED = "CONFIRMED", + FAILED = "FAILED" +} +export declare const DEFAULT_GAS_LIMIT = 600000; +export interface RelayerServices { + provider: Provider; + signer: TornadoWallet; + tornadoFeeOracle: TornadoFeeOracle; + Router: TornadoRouter; +} +export interface CachedRelayerServices { + [key: NetIdType]: RelayerServices; +} +export declare function getFeeParams(config: Config, serviceFee: number, syncManager: SyncManager, { netId, contract, args }: RelayerTornadoQueue): { + amount: string; + symbol: string; + gasPrice: bigint; + gasLimit: bigint; + l1Fee: string | undefined; + denomination: bigint; + ethRefund: bigint; + tokenPriceInWei: bigint; + tokenDecimals: number; + relayerFeePercent: number; + isEth: boolean; + premiumPercent: number; +}; +export declare function checkWithdrawalFees(relayerWorker: RelayerWorker, work: RelayerTornadoQueue): Promise<{ + gasPrice: bigint; + gasLimit: bigint; + status: boolean; + error?: string; +}>; +export declare function processWithdrawals(relayerWorker: RelayerWorker): Promise; +export interface CreateWorkParams extends TornadoWithdrawParams { + netId: NetIdType; +} +export interface RelayerTornadoQueue extends Omit { + netId: NetIdType; + contract: string; + proof: string; + args: snarkArgs; + timestamp: number; +} +export interface RelayerQueueGas { + id: string; + gasPrice: bigint; + gasLimit: bigint; + timestamp: number; +} +export declare class RelayerWorker { + relayerConfig: RelayerConfig; + logger: Logger; + syncManager: SyncManager; + cachedRelayerServices: CachedRelayerServices; + queue: RelayerTornadoQueue[]; + queueGas: RelayerQueueGas[]; + queueTimer: null | NodeJS.Timeout; + errors: ErrorMessages[]; + constructor(relayerConfig: RelayerConfig, syncManager: SyncManager); + doWork(): Promise; + createWork({ netId, contract, proof, args, }: CreateWorkParams): Promise; + getWork({ id }: { + id: string; + }): RelayerTornadoWithdraw | RelayerTornadoQueue; + pendingWorks(): number; +} diff --git a/lib/services/worker.js b/lib/services/worker.js new file mode 100644 index 0000000..364cc1e --- /dev/null +++ b/lib/services/worker.js @@ -0,0 +1,285 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RelayerWorker = exports.DEFAULT_GAS_LIMIT = exports.RelayerStatus = void 0; +exports.getFeeParams = getFeeParams; +exports.checkWithdrawalFees = checkWithdrawalFees; +exports.processWithdrawals = processWithdrawals; +const crypto_1 = require("crypto"); +const ethers_1 = require("ethers"); +const contracts_1 = require("@tornado/contracts"); +const core_1 = require("@tornado/core"); +const config_1 = require("../config"); +const logger_1 = require("./logger"); +const error_1 = require("./error"); +var RelayerStatus; +(function (RelayerStatus) { + RelayerStatus["QUEUED"] = "QUEUED"; + RelayerStatus["ACCEPTED"] = "ACCEPTED"; + RelayerStatus["SENT"] = "SENT"; + RelayerStatus["MINED"] = "MINED"; + RelayerStatus["RESUBMITTED"] = "RESUBMITTED"; + RelayerStatus["CONFIRMED"] = "CONFIRMED"; + RelayerStatus["FAILED"] = "FAILED"; +})(RelayerStatus || (exports.RelayerStatus = RelayerStatus = {})); +exports.DEFAULT_GAS_LIMIT = 600_000; +function setupServices(relayerWorker) { + const { relayerConfig: { enabledNetworks, txRpcUrls }, } = relayerWorker; + for (const netId of enabledNetworks) { + const config = (0, core_1.getConfig)(netId); + const rpcUrl = txRpcUrls[netId]; + const provider = (0, core_1.getProviderWithNetId)(netId, rpcUrl, config); + const signer = new core_1.TornadoWallet((0, config_1.getPrivateKey)(), provider); + const Router = contracts_1.TornadoRouter__factory.connect(config.routerContract, signer); + const tornadoFeeOracle = new core_1.TornadoFeeOracle(provider); + relayerWorker.cachedRelayerServices[netId] = { + provider, + signer, + Router, + tornadoFeeOracle, + }; + } +} +function getFeeParams(config, serviceFee, syncManager, { netId, contract, args }) { + const { amount, currency } = (0, core_1.getInstanceByAddress)(config, contract); + const { nativeCurrency, tokens: { [currency]: { symbol: currencySymbol, decimals, gasLimit: instanceGasLimit }, }, } = config; + const symbol = currencySymbol.toLowerCase(); + const { gasPrice, l1Fee } = syncManager.getGasPrice(netId); + const gasLimit = BigInt(instanceGasLimit || exports.DEFAULT_GAS_LIMIT); + const denomination = (0, ethers_1.parseUnits)(amount, decimals); + const ethRefund = BigInt(args[5]); + const tokenPriceInWei = syncManager.getPrice(netId, symbol); + const isEth = nativeCurrency === currency; + return { + amount, + symbol, + gasPrice: BigInt(gasPrice), + gasLimit, + l1Fee, + denomination, + ethRefund, + tokenPriceInWei, + tokenDecimals: decimals, + relayerFeePercent: serviceFee, + isEth, + premiumPercent: 5, + }; +} +async function checkWithdrawalFees(relayerWorker, work) { + try { + const { id, netId, contract, proof, args } = work; + const { relayerConfig: { rewardAccount, serviceFee }, cachedRelayerServices: { [netId]: { tornadoFeeOracle, Router }, }, syncManager, } = relayerWorker; + const config = (0, core_1.getConfig)(netId); + const feeParams = getFeeParams(config, serviceFee, syncManager, work); + const { amount, symbol, tokenDecimals, denomination, ethRefund } = feeParams; + let fee = tornadoFeeOracle.calculateRelayerFee(feeParams); + const gasLimit = await Router.withdraw.estimateGas(contract, proof, ...args, { + from: rewardAccount, + value: ethRefund, + }); + // Recalculate fee based on correct gas limit + fee = tornadoFeeOracle.calculateRelayerFee({ + ...feeParams, + gasLimit, + }); + if (fee > denomination) { + return { + gasPrice: feeParams.gasPrice, + gasLimit, + status: false, + error: `Fee above deposit amount, requires ${(0, ethers_1.formatUnits)(fee, tokenDecimals)} ${symbol} while denomination is ${amount} ${symbol}`, + }; + } + if (fee > BigInt(args[4])) { + return { + gasPrice: feeParams.gasPrice, + gasLimit, + status: false, + error: `Insufficient fee, requires ${(0, ethers_1.formatUnits)(fee, tokenDecimals)} ${symbol} while user only wants to pay ${(0, ethers_1.formatUnits)(BigInt(args[4]), tokenDecimals)} ${symbol}`, + }; + } + relayerWorker.logger.info(`New job: ${id} ${netId} ${amount} ${symbol} (Fee: ${(0, ethers_1.formatUnits)(BigInt(args[4]), tokenDecimals)} ${symbol}, Refund: ${(0, ethers_1.formatUnits)(BigInt(args[5]), tokenDecimals)})`); + return { + gasPrice: feeParams.gasPrice, + gasLimit, + status: true, + }; + } + catch { + return { + gasPrice: BigInt(0), + gasLimit: BigInt(0), + status: false, + error: 'Withdrawal transaction expected to be reverted', + }; + } +} +async function processWithdrawals(relayerWorker) { + const { logger, cachedRelayerServices, errors } = relayerWorker; + for (const work of relayerWorker.queue) { + try { + if (work.status !== RelayerStatus.ACCEPTED) { + continue; + } + const { id, netId, contract, proof, args } = work; + // cancel duplicated jobs + const otherWork = relayerWorker.queue.find((q) => q.id !== id && + // find if other previous work is already sent (not pending or failed - to allow spending first and failed one) + q.status !== RelayerStatus.ACCEPTED && + q.status !== RelayerStatus.FAILED && + q.contract === contract && + q.args[1] === args[1]); + if (otherWork) { + const errMsg = `Found the same pending job ${otherWork.id}, wait until the previous one completes`; + throw new Error(errMsg); + } + const { gasLimit, gasPrice } = relayerWorker.queueGas.find((w) => w.id === id); + const config = (0, core_1.getConfig)(netId); + const { amount, currency } = (0, core_1.getInstanceByAddress)(config, contract); + const { decimals } = config.tokens[currency]; + const { Router, signer } = cachedRelayerServices[netId]; + /** + * Check fees to ensure that it didn't spike or revert (or has insane gas spendings) + */ + const txObj = await signer.populateTransaction(await Router.withdraw.populateTransaction(contract, proof, ...args, { + value: BigInt(args[5]), + })); + const txGasPrice = txObj.maxFeePerGas + ? txObj.maxFeePerGas + BigInt(txObj.maxPriorityFeePerGas || 0) + : txObj.gasPrice; + // Prevent tx on gas limit spike + if (txObj.gasLimit > (gasLimit * BigInt(15)) / BigInt(10)) { + const errMsg = `Job ${id} exceeds pre estimated gas limit, wants ${gasLimit * BigInt(2)} have ${txObj.gasLimit}`; + throw new Error(errMsg); + } + // Prevent tx on gas price spike + if (txGasPrice > gasPrice * BigInt(2)) { + const errMsg = `Job ${id} exceeds pre estimated gas price, wants ${gasPrice * BigInt(2)} have ${txGasPrice}`; + throw new Error(errMsg); + } + const tx = await signer.sendTransaction(txObj); + work.txHash = tx.hash; + work.confirmations = 0; + work.status = RelayerStatus.SENT; + logger.info(`Sent Job ${work.id} ${netId} ${amount} ${currency} tx (Fee: ${(0, ethers_1.formatUnits)(BigInt(args[4]), decimals)} ${currency}, Refund: ${(0, ethers_1.formatUnits)(BigInt(args[5]), decimals)} ${currency} ${tx.hash})`); + // Wait for 2 seconds so that the remote node could increment nonces + await (0, core_1.sleep)(2000); + // Head straight to confirmed status as the remote node oftenly doesn't report receipt correctly + work.confirmations = 1; + work.status = RelayerStatus.MINED; + work.confirmations = 3; + work.status = RelayerStatus.CONFIRMED; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } + catch (error) { + logger.error(`Failed to send job ${work.id}`); + console.log(error); + errors.push((0, error_1.newError)('Worker (processWithdrawals)', work.netId, error)); + work.status = RelayerStatus.FAILED; + if (error.message?.includes('exceeds pre estimated')) { + work.failedReason = error.message; + } + else if (error.message?.includes('Found the same pending job')) { + work.failedReason = error.message; + } + else { + work.failedReason = 'Relayer failed to send transaction'; + } + } + } + relayerWorker.queue = relayerWorker.queue.filter((w) => w.timestamp + relayerWorker.relayerConfig.clearInterval >= Math.floor(Date.now() / 1000)); + relayerWorker.queueGas = relayerWorker.queueGas.filter((w) => w.timestamp + relayerWorker.relayerConfig.clearInterval >= Math.floor(Date.now() / 1000)); +} +class RelayerWorker { + relayerConfig; + logger; + syncManager; + cachedRelayerServices; + queue; + queueGas; + queueTimer; + errors; + constructor(relayerConfig, syncManager) { + this.relayerConfig = relayerConfig; + this.syncManager = syncManager; + this.logger = (0, logger_1.getLogger)('[RelayerWorker]', relayerConfig.logLevel); + this.cachedRelayerServices = {}; + this.queue = []; + this.queueGas = []; + this.queueTimer = null; + this.errors = []; + setupServices(this); + } + async doWork() { + await processWithdrawals(this); + const pendingWorks = this.queue.filter((q) => q.status === RelayerStatus.QUEUED || q.status === RelayerStatus.ACCEPTED).length; + if (pendingWorks) { + if (pendingWorks < 5) { + this.doWork(); + return; + } + else { + this.queue.forEach((q) => { + q.status = RelayerStatus.FAILED; + q.error = 'Relayer has too many jobs, try it again later'; + q.failedReason = 'Relayer has too many jobs, try it again later'; + }); + this.logger.error(`Relayer has cleared the workload ( ${pendingWorks} ) due to overhaul`); + } + } + this.queueTimer = null; + } + async createWork({ netId, contract, proof, args, }) { + const work = { + netId, + id: crypto_1.webcrypto.randomUUID(), + type: 'TORNADO_WITHDRAW', + status: RelayerStatus.QUEUED, + contract, + proof, + args, + timestamp: Math.floor(Date.now() / 1000), + }; + if (this.queue.find((q) => q.status !== RelayerStatus.FAILED && q.contract === contract && q.args[1] === args[1])) { + work.status = RelayerStatus.FAILED; + return { + error: 'Found the same pending job, wait until the previous one completes', + }; + } + const { gasPrice, gasLimit, status, error } = await checkWithdrawalFees(this, work); + const workGas = { + id: work.id, + gasPrice, + gasLimit, + timestamp: work.timestamp, + }; + if (!status) { + work.status = RelayerStatus.FAILED; + return { + error, + }; + } + work.status = RelayerStatus.ACCEPTED; + this.queue.push(work); + this.queueGas.push(workGas); + if (!this.queueTimer) { + this.queueTimer = setTimeout(() => this.doWork(), 500); + } + return work; + } + getWork({ id }) { + const work = this.queue.find((w) => w.id === id); + if (!work) { + return { + error: `Work ${id} not found`, + }; + } + const copiedWork = JSON.parse(JSON.stringify(work)); + delete copiedWork.netId; + return copiedWork; + } + pendingWorks() { + return this.queue.filter((q) => q.status === RelayerStatus.QUEUED || q.status === RelayerStatus.ACCEPTED) + .length; + } +} +exports.RelayerWorker = RelayerWorker; diff --git a/lib/start.d.ts b/lib/start.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/start.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/start.js b/lib/start.js new file mode 100644 index 0000000..0a5cc0c --- /dev/null +++ b/lib/start.js @@ -0,0 +1,98 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const process_1 = __importDefault(require("process")); +const cluster_1 = __importDefault(require("cluster")); +const config_1 = require("./config"); +const services_1 = require("./services"); +if (cluster_1.default.isWorker) { + new services_1.Router(JSON.parse(process_1.default.env.relayerConfig), Number(process_1.default.env.forkId)); +} +else { + start(); +} +async function forkRouter({ relayerConfig, logger, syncManager, relayerWorker, forkId, }) { + const worker = cluster_1.default.fork({ + relayerConfig: JSON.stringify(relayerConfig), + forkId, + }); + worker + .on('exit', (code) => { + logger.error(`Router Worker ${forkId} died with code ${code}, respawning...`); + setTimeout(() => { + forkRouter({ + relayerConfig, + logger, + syncManager, + relayerWorker, + forkId, + }); + }, 5000); + }) + .on('message', async (msg) => { + const { msgId, type } = msg; + if (type === 'status') { + worker.send({ + msgId, + syncManagerStatus: syncManager.getStatus(), + pendingWorks: relayerWorker.pendingWorks(), + }); + return; + } + if (type === 'job') { + const work = relayerWorker.getWork({ + id: msg.id, + }); + worker.send({ + msgId, + ...work, + }); + return; + } + if (type === 'tornadoWithdraw') { + const newWork = await relayerWorker.createWork({ + netId: msg.netId, + contract: msg.contract, + proof: msg.proof, + args: msg.args, + }); + worker.send({ + msgId, + ...newWork, + }); + return; + } + if (type === 'errors') { + worker.send({ + msgId, + errors: [...syncManager.errors, ...relayerWorker.errors], + }); + return; + } + }); +} +async function start() { + const relayerConfig = (0, config_1.getRelayerConfig)(); + const logger = (0, services_1.getLogger)('[Main]', relayerConfig.logLevel); + console.log('Relayer config', relayerConfig); + await (0, services_1.checkProviders)(relayerConfig, logger); + const syncManager = new services_1.SyncManager(relayerConfig); + await syncManager.syncEvents(); + const relayerWorker = new services_1.RelayerWorker(relayerConfig, syncManager); + setInterval(() => syncManager.syncEvents(), relayerConfig.syncInterval * 1000); + // Spawn website + let i = 0; + while (i < relayerConfig.workers) { + forkRouter({ + relayerConfig, + logger, + syncManager, + relayerWorker, + forkId: i, + }); + i++; + } + logger.info(`Spawned ${i} Router Workers`); +} diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..fa28502 Binary files /dev/null and b/logo.png differ diff --git a/logo2.png b/logo2.png new file mode 100644 index 0000000..fd29d7e Binary files /dev/null and b/logo2.png differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..88ef637 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "tovarish-relayer", + "version": "1.0.0", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json", + "lint": "eslint src/**/*.ts --ext .ts --ignore-pattern src/typechain", + "build": "tsc --declaration", + "dev": "ts-node ./src/start.ts", + "start": "node ./lib/start.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "license": "MIT", + "dependencies": { + "@fastify/cors": "^10.0.1", + "@tornado/core": "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#94a62e6193c99457a8dfae0d8684bee299cb1097", + "bloomfilter.js": "^1.0.2", + "dotenv": "^16.4.5", + "fastify": "^5.0.0", + "winston": "^3.14.2" + }, + "devDependencies": { + "@typechain/ethers-v6": "^0.5.1", + "@types/node": "^22.7.5", + "@typescript-eslint/eslint-plugin": "^8.9.0", + "@typescript-eslint/parser": "^8.9.0", + "eslint": "8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-prettier": "^5.2.1", + "prettier": "^3.3.3", + "ts-node": "^10.9.2", + "typechain": "^8.3.2", + "typescript": "^5.6.3" + }, + "resolutions": { + "strip-ansi": "6.0.1" + } +} diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..f2efae5 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,103 @@ +import path from 'path'; +import process from 'process'; +import os from 'os'; +import 'dotenv/config'; +import { computeAddress, isHexString } from 'ethers'; +import { enabledChains, getConfig, NetIdType, SubdomainMap } from '@tornado/core'; +import pkgJson from '../package.json'; + +export const version = `${pkgJson.name} ${pkgJson.version}`; + +export interface RelayerConfig { + /** + * Router config + */ + host: string; + port: number; + workers: number; + reverseProxy: boolean; + logLevel?: string; + /** + * Worker config + */ + rewardAccount: string; + serviceFee: number; + // Clear work after this period + clearInterval: number; + /** + * Sync config + */ + enabledNetworks: NetIdType[]; + rpcUrls: SubdomainMap; + txRpcUrls: SubdomainMap; + merkleWorkerPath: string; + cacheDir: string; + userEventsDir: string; + userTreeDir: string; + syncInterval: number; +} + +export function getPrivateKey(): string { + const privateKey = process.env.PRIVATE_KEY; + + if (!privateKey || !isHexString(privateKey, 32)) { + throw new Error('Invalid private key, make sure it contains 0x prefix!'); + } + + return privateKey; +} + +export function getRewardAccount(): string { + return computeAddress(getPrivateKey()); +} + +export function getRelayerConfig(): RelayerConfig { + const enabledNetworks = process.env.ENABLED_NETWORKS + ? process.env.ENABLED_NETWORKS.replaceAll(' ', '') + .split(',') + .map((n) => Number(n)) + .filter((n) => enabledChains.includes(n)) + : enabledChains; + + const rpcUrls = enabledNetworks.reduce((acc, netId) => { + // If we have custom RPC url (like as 1_RPC from ENV) + if (process.env[`${netId}_RPC`]) { + acc[netId] = process.env[`${netId}_RPC`] || ''; + } else { + acc[netId] = Object.values(getConfig(netId).rpcUrls)[0]?.url; + } + return acc; + }, {} as SubdomainMap); + + const txRpcUrls = enabledNetworks.reduce((acc, netId) => { + // If we have custom RPC url (like as 1_RPC from ENV) + if (process.env[`${netId}_TX_RPC`]) { + acc[netId] = process.env[`${netId}_TX_RPC`] || ''; + } else { + acc[netId] = rpcUrls[netId]; + } + return acc; + }, {} as SubdomainMap); + + const STATIC_DIR = process.env.CACHE_DIR || path.join(__dirname, '../static'); + const USER_DIR = process.env.USER_DIR || './data'; + + return { + host: process.env.HOST || '0.0.0.0', + port: Number(process.env.PORT || 3000), + workers: Number(process.env.WORKERS || os.cpus().length), + reverseProxy: process.env.REVERSE_PROXY === 'true', + logLevel: process.env.LOG_LEVEL || undefined, + rewardAccount: getRewardAccount(), + serviceFee: Number(process.env.SERVICE_FEE || 0.5), + clearInterval: Number(process.env.CLEAR_INTERVAL || 86400), + enabledNetworks, + rpcUrls, + txRpcUrls, + merkleWorkerPath: path.join(STATIC_DIR, './merkleTreeWorker.js'), + cacheDir: path.join(STATIC_DIR, './events'), + userEventsDir: path.join(USER_DIR, './events'), + userTreeDir: path.join(USER_DIR, './trees'), + syncInterval: Number(process.env.SYNC_INTERVAL || 120), + }; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..8418dc7 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,2 @@ +export * from './services'; +export * from './config'; diff --git a/src/services/check.ts b/src/services/check.ts new file mode 100644 index 0000000..255974b --- /dev/null +++ b/src/services/check.ts @@ -0,0 +1,58 @@ +import process from 'process'; +import type { Logger } from 'winston'; +import { formatEther, parseEther } from 'ethers'; +import { getConfig, getProvider } from '@tornado/core'; + +import { RelayerConfig } from '../config'; + +// Can use 0 to use network on low balance +export const CHECK_BALANCE = parseEther(process.env.CHECK_BALANCE || '0.001'); + +export const DISABLE_LOW_BALANCE = true; + +export async function checkProviders(relayerConfig: RelayerConfig, logger: Logger) { + const { enabledNetworks, rpcUrls, rewardAccount } = relayerConfig; + + const disabledNetworks = ( + await Promise.all( + enabledNetworks.map(async (netId) => { + try { + const config = getConfig(netId); + + const rpcUrl = rpcUrls[netId]; + + const provider = await getProvider(rpcUrl, { + netId, + }); + + const balance = await provider.getBalance(rewardAccount); + + const symbol = config.nativeCurrency.toUpperCase(); + + if (balance < CHECK_BALANCE) { + logger.error( + `Network ${netId} has lower balance than 0.001 ${symbol} and thus disabled (Balance: ${formatEther(balance)} ${symbol})`, + ); + + if (DISABLE_LOW_BALANCE) { + return netId; + } + } else { + logger.info( + `Network ${netId} connected with ${rpcUrl} (Balance: ${formatEther(balance)} ${config.nativeCurrency.toUpperCase()})`, + ); + } + } catch (err) { + logger.error( + `Failed to connect with ${netId} provider, make sure you have configured correct RPC url`, + ); + throw err; + } + }), + ) + ).filter((n) => n); + + relayerConfig.enabledNetworks = relayerConfig.enabledNetworks.filter((n) => !disabledNetworks.includes(n)); + + logger.info(`Enabled Networks: ${relayerConfig.enabledNetworks.join(', ')}`); +} diff --git a/src/services/data.ts b/src/services/data.ts new file mode 100644 index 0000000..6e4ef41 --- /dev/null +++ b/src/services/data.ts @@ -0,0 +1,195 @@ +import path from 'path'; +import { stat, mkdir, readFile, writeFile } from 'fs/promises'; +import { zip, unzip, AsyncZippable, Unzipped } from 'fflate'; +import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core'; + +export async function existsAsync(fileOrDir: string): Promise { + try { + await stat(fileOrDir); + + return true; + } catch { + return false; + } +} + +export function zipAsync(file: AsyncZippable): Promise { + return new Promise((res, rej) => { + zip(file, { mtime: new Date('1/1/1980') }, (err, data) => { + if (err) { + rej(err); + return; + } + res(data); + }); + }); +} + +export function unzipAsync(data: Uint8Array): Promise { + return new Promise((res, rej) => { + unzip(data, {}, (err, data) => { + if (err) { + rej(err); + return; + } + res(data); + }); + }); +} + +export async function saveUserFile({ + fileName, + userDirectory, + dataString, + lastBlock, +}: { + fileName: string; + userDirectory: string; + dataString: string; + lastBlock?: number; +}) { + fileName = fileName.toLowerCase(); + + const filePath = path.join(userDirectory, fileName); + + const payload = await zipAsync({ + [fileName]: new TextEncoder().encode(dataString), + }); + + if (!(await existsAsync(userDirectory))) { + await mkdir(userDirectory, { recursive: true }); + } + + await writeFile(filePath + '.zip', payload); + await writeFile(filePath, dataString); + + if (lastBlock) { + await saveLastBlock({ + fileName: fileName.replace('.json', ''), + userDirectory, + lastBlock, + }); + } +} + +export async function saveLastBlock({ + fileName, + userDirectory, + lastBlock, +}: { + fileName: string; + userDirectory: string; + lastBlock: number; +}) { + const filePath = path.join(userDirectory, fileName); + + if (lastBlock) { + await writeFile(filePath + '.lastblock.txt', String(lastBlock)); + } +} + +export async function loadLastBlock({ name, directory }: { name: string; directory: string }) { + const filePath = path.join(directory, `${name}.lastblock.txt`); + + if (!(await existsAsync(filePath))) { + return; + } + + try { + const lastBlock = Number(await readFile(filePath, { encoding: 'utf8' })); + + if (lastBlock) { + return lastBlock; + } + // eslint-disable-next-line no-empty + } catch {} +} + +export async function loadSavedEvents({ + name, + userDirectory, +}: { + name: string; + userDirectory: string; +}): Promise> { + const filePath = path.join(userDirectory, `${name}.json`.toLowerCase()); + + if (!(await existsAsync(filePath))) { + return { + events: [] as T[], + lastBlock: 0, + }; + } + + try { + const events = JSON.parse(await readFile(filePath, { encoding: 'utf8' })) as T[]; + + const loadedBlock = await loadLastBlock({ + name, + directory: userDirectory, + }); + + return { + events, + lastBlock: loadedBlock || events[events.length - 1]?.blockNumber || 0, + }; + } catch (err) { + console.log('Method loadSavedEvents has error'); + console.log(err); + return { + events: [], + lastBlock: 0, + }; + } +} + +export async function download({ name, cacheDirectory }: { name: string; cacheDirectory: string }) { + const fileName = `${name}.json`.toLowerCase(); + const zipName = `${fileName}.zip`; + const zipPath = path.join(cacheDirectory, zipName); + + const data = await readFile(zipPath); + const { [fileName]: content } = await unzipAsync(data); + + return new TextDecoder().decode(content); +} + +export async function loadCachedEvents({ + name, + cacheDirectory, + deployedBlock, +}: { + name: string; + cacheDirectory: string; + deployedBlock: number; +}): Promise> { + try { + const module = await download({ cacheDirectory, name }); + + if (module) { + const events = JSON.parse(module); + + const lastBlock = events && events.length ? events[events.length - 1].blockNumber : deployedBlock; + + return { + events, + lastBlock, + fromCache: true, + }; + } + + return { + events: [], + lastBlock: deployedBlock, + fromCache: true, + }; + } catch (err) { + console.log('Method loadCachedEvents has error'); + console.log(err); + return { + events: [], + lastBlock: deployedBlock, + fromCache: true, + }; + } +} diff --git a/src/services/error.ts b/src/services/error.ts new file mode 100644 index 0000000..23ce18e --- /dev/null +++ b/src/services/error.ts @@ -0,0 +1,27 @@ +import { NetIdType } from '@tornado/core'; + +export interface ErrorTypes { + type: string; + netId: number; + timestamp: number; +} + +export interface ErrorMessages extends ErrorTypes { + message?: string; + stack?: string; +} + +export function newError( + type: string, + netId: NetIdType, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + err: any, +): ErrorMessages { + return { + type, + netId, + timestamp: Math.floor(Date.now() / 1000), + message: err.message, + stack: err.stack, + }; +} diff --git a/src/services/events.ts b/src/services/events.ts new file mode 100644 index 0000000..c9f5275 --- /dev/null +++ b/src/services/events.ts @@ -0,0 +1,651 @@ +import path from 'path'; +import { readFile } from 'fs/promises'; +import { + BaseTornadoService, + BaseEncryptedNotesService, + BaseGovernanceService, + BaseRegistryService, + BaseTornadoServiceConstructor, + BaseEncryptedNotesServiceConstructor, + BaseGovernanceServiceConstructor, + BaseRegistryServiceConstructor, + BaseEchoServiceConstructor, + BaseEchoService, + CachedRelayers, + BatchEventsService, + toFixedHex, + BaseEvents, + DepositsEvents, + WithdrawalsEvents, + EncryptedNotesEvents, + AllGovernanceEvents, + EchoEvents, + BatchEventServiceConstructor, + BatchEventOnProgress, + NetIdType, + AllRelayerRegistryEvents, + BaseRevenueService, + BaseRevenueServiceConstructor, + StakeBurnedEvents, +} from '@tornado/core'; +import type { MerkleTree } from '@tornado/fixed-merkle-tree'; +import type { Logger } from 'winston'; +import { saveUserFile, loadSavedEvents, loadCachedEvents, existsAsync, saveLastBlock } from './data'; +import { TreeCache } from './treeCache'; + +export interface NodeEventsConstructor extends BatchEventServiceConstructor { + netId: NetIdType; + logger: Logger; + getInstanceName: () => string; +} + +export class NodeEventsService extends BatchEventsService { + netId: NetIdType; + logger: Logger; + getInstanceName: () => string; + + constructor(serviceConstructor: NodeEventsConstructor) { + super(serviceConstructor); + + this.netId = serviceConstructor.netId; + this.logger = serviceConstructor.logger; + this.getInstanceName = serviceConstructor.getInstanceName; + } +} + +export interface NodeTornadoServiceConstructor extends BaseTornadoServiceConstructor { + cacheDirectory: string; + userDirectory: string; + nativeCurrency: string; + logger: Logger; + treeCache?: TreeCache; +} + +export class NodeTornadoService extends BaseTornadoService { + cacheDirectory: string; + userDirectory: string; + + nativeCurrency: string; + logger: Logger; + + treeCache?: TreeCache; + + constructor(serviceConstructor: NodeTornadoServiceConstructor) { + super(serviceConstructor); + + const { + netId, + provider, + Tornado, + type, + amount, + currency, + cacheDirectory, + userDirectory, + nativeCurrency, + logger, + treeCache, + } = serviceConstructor; + + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.nativeCurrency = nativeCurrency; + + this.logger = logger; + + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Tornado, + onProgress: this.updateEventProgress, + logger, + getInstanceName: () => `${type.toLowerCase()}s_${netId}_${currency}_${amount}`, + }); + + this.treeCache = treeCache; + } + + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + + async getEventsFromDB() { + return await loadSavedEvents({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + + async getEventsFromCache() { + return await loadCachedEvents({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + + async validateEvents({ + events, + lastBlock, + hasNewEvents, + }: BaseEvents & { + hasNewEvents?: boolean; + }): Promise { + const tree = await super.validateEvents({ + events, + lastBlock, + hasNewEvents, + }); + + if (tree && this.currency === this.nativeCurrency && this.treeCache) { + const merkleTree = tree as unknown as MerkleTree; + + await this.treeCache.createTree(events as DepositsEvents[], merkleTree); + + console.log( + `${this.getInstanceName()}: Updated tree cache with root ${toFixedHex(BigInt(merkleTree.root))}\n`, + ); + } + + return tree; + } + + async saveEvents({ events, lastBlock }: BaseEvents) { + await saveUserFile({ + fileName: this.getInstanceName() + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + + await saveLastBlock({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + + return { + events, + lastBlock, + validateResult, + }; + } +} + +export interface NodeEchoServiceConstructor extends BaseEchoServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} + +export class NodeEchoService extends BaseEchoService { + cacheDirectory: string; + userDirectory: string; + + logger: Logger; + + constructor(serviceConstructor: NodeEchoServiceConstructor) { + super(serviceConstructor); + + const { netId, provider, Echoer, cacheDirectory, userDirectory, logger } = serviceConstructor; + + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + + this.logger = logger; + + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Echoer, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + + async getEventsFromDB() { + return await loadSavedEvents({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + + async getEventsFromCache() { + return await loadCachedEvents({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + + async saveEvents({ events, lastBlock }: BaseEvents) { + const instanceName = this.getInstanceName(); + + await saveUserFile({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + + await saveLastBlock({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + + return { + events, + lastBlock, + validateResult, + }; + } +} + +export interface NodeEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} + +export class NodeEncryptedNotesService extends BaseEncryptedNotesService { + cacheDirectory: string; + userDirectory: string; + + logger: Logger; + + constructor(serviceConstructor: NodeEncryptedNotesServiceConstructor) { + super(serviceConstructor); + + const { netId, provider, Router, cacheDirectory, userDirectory, logger } = serviceConstructor; + + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Router, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + + async getEventsFromDB() { + return await loadSavedEvents({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + + async getEventsFromCache() { + return await loadCachedEvents({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + + async saveEvents({ events, lastBlock }: BaseEvents) { + const instanceName = this.getInstanceName(); + + await saveUserFile({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + + await saveLastBlock({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + + return { + events, + lastBlock, + validateResult, + }; + } +} + +export interface NodeGovernanceServiceConstructor extends BaseGovernanceServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} + +export class NodeGovernanceService extends BaseGovernanceService { + cacheDirectory: string; + userDirectory: string; + + logger: Logger; + + constructor(serviceConstructor: NodeGovernanceServiceConstructor) { + super(serviceConstructor); + + const { netId, provider, Governance, cacheDirectory, userDirectory, logger } = serviceConstructor; + + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: Governance, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + + async getEventsFromDB() { + return await loadSavedEvents({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + + async getEventsFromCache() { + return await loadCachedEvents({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + + async saveEvents({ events, lastBlock }: BaseEvents) { + const instanceName = this.getInstanceName(); + + await saveUserFile({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + + await saveLastBlock({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + + return { + events, + lastBlock, + validateResult, + }; + } +} + +export interface NodeRegistryServiceConstructor extends BaseRegistryServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} + +export class NodeRegistryService extends BaseRegistryService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + + constructor(serviceConstructor: NodeRegistryServiceConstructor) { + super(serviceConstructor); + + const { netId, provider, RelayerRegistry, cacheDirectory, userDirectory, logger } = serviceConstructor; + + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: RelayerRegistry, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + + async getEventsFromDB() { + return await loadSavedEvents({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + + async getEventsFromCache() { + return await loadCachedEvents({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + + async saveEvents({ events, lastBlock }: BaseEvents) { + const instanceName = this.getInstanceName(); + + await saveUserFile({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + + await saveLastBlock({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + + return { + events, + lastBlock, + validateResult, + }; + } + + async getRelayersFromDB(): Promise { + const filePath = path.join(this.userDirectory || '', 'relayers.json'); + + if (!this.userDirectory || !(await existsAsync(filePath))) { + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + }; + } + + try { + const { lastBlock, timestamp, relayers } = JSON.parse(await readFile(filePath, { encoding: 'utf8' })); + + return { + lastBlock, + timestamp, + relayers, + }; + } catch (err) { + console.log('Method getRelayersFromDB has error'); + console.log(err); + + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + }; + } + } + + async getRelayersFromCache(): Promise { + const filePath = path.join(this.cacheDirectory || '', 'relayers.json'); + + if (!this.cacheDirectory || !(await existsAsync(filePath))) { + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + fromCache: true, + }; + } + + try { + const { lastBlock, timestamp, relayers } = JSON.parse(await readFile(filePath, { encoding: 'utf8' })); + + return { + lastBlock, + timestamp, + relayers, + fromCache: true, + }; + } catch (err) { + console.log('Method getRelayersFromDB has error'); + console.log(err); + + return { + lastBlock: 0, + timestamp: 0, + relayers: [], + fromCache: true, + }; + } + } + + async saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers) { + await saveUserFile({ + fileName: 'relayers.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify({ lastBlock, timestamp, relayers }, null, 2) + '\n', + }); + } +} + +export interface NodeRevenueServiceConstructor extends BaseRevenueServiceConstructor { + cacheDirectory: string; + userDirectory: string; + logger: Logger; +} + +export class NodeRevenueService extends BaseRevenueService { + cacheDirectory: string; + userDirectory: string; + logger: Logger; + + constructor(serviceConstructor: NodeRevenueServiceConstructor) { + super(serviceConstructor); + + const { netId, provider, RelayerRegistry, cacheDirectory, userDirectory, logger } = serviceConstructor; + + this.cacheDirectory = cacheDirectory; + this.userDirectory = userDirectory; + this.logger = logger; + + this.batchEventsService = new NodeEventsService({ + netId, + provider, + contract: RelayerRegistry, + onProgress: this.updateEventProgress, + logger, + getInstanceName: this.getInstanceName, + }); + } + + updateEventProgress({ fromBlock, toBlock, count }: Parameters[0]) { + if (toBlock) { + this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); + } + } + + async getEventsFromDB() { + return await loadSavedEvents({ + name: this.getInstanceName(), + userDirectory: this.userDirectory, + }); + } + + async getEventsFromCache() { + return await loadCachedEvents({ + name: this.getInstanceName(), + cacheDirectory: this.cacheDirectory, + deployedBlock: this.deployedBlock, + }); + } + + async saveEvents({ events, lastBlock }: BaseEvents) { + const instanceName = this.getInstanceName(); + + await saveUserFile({ + fileName: instanceName + '.json', + userDirectory: this.userDirectory, + dataString: JSON.stringify(events, null, 2) + '\n', + lastBlock, + }); + } + + async updateEvents() { + const { events, lastBlock, validateResult } = await super.updateEvents(); + + await saveLastBlock({ + fileName: this.getInstanceName(), + userDirectory: this.userDirectory, + lastBlock, + }); + + return { + events, + lastBlock, + validateResult, + }; + } +} diff --git a/src/services/index.ts b/src/services/index.ts new file mode 100644 index 0000000..ad6f383 --- /dev/null +++ b/src/services/index.ts @@ -0,0 +1,12 @@ +export * from './check'; +export * from './data'; +export * from './error'; +export * from './events'; +export * from './logger'; +export * from './router'; +export * from './routerMsg'; +export * from './schema'; +export * from './sync'; +export * from './treeCache'; +export * from './utils'; +export * from './worker'; diff --git a/src/services/logger.ts b/src/services/logger.ts new file mode 100644 index 0000000..71e9b7d --- /dev/null +++ b/src/services/logger.ts @@ -0,0 +1,28 @@ +import winston from 'winston'; +import colors from '@colors/colors/safe'; + +export function getLogger(label?: string, minLevel?: string) { + return winston.createLogger({ + format: winston.format.combine( + winston.format.label({ label }), + winston.format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss', + }), + // Include timestamp on level + winston.format((info) => { + info.level = `[${info.level}]`; + while (info.level.length < 8) { + info.level += ' '; + } + info.level = `${info.timestamp} ${info.level}`.toUpperCase(); + return info; + })(), + winston.format.colorize(), + winston.format.printf( + (info) => `${info.level} ${info.label ? `${info.label} ` : ''}${colors.grey(info.message)}`, + ), + ), + // Define level filter from config + transports: [new winston.transports.Console({ level: minLevel || 'debug' })], + }); +} diff --git a/src/services/router.ts b/src/services/router.ts new file mode 100644 index 0000000..7da11ae --- /dev/null +++ b/src/services/router.ts @@ -0,0 +1,439 @@ +import path from 'path'; +import { createReadStream } from 'fs'; +import type { Logger } from 'winston'; +import { fastify, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { fastifyCors } from '@fastify/cors'; + +import { + NetIdType, + getConfig, + DEPOSIT, + WITHDRAWAL, + DepositsEvents, + WithdrawalsEvents, + EchoEvents, + EncryptedNotesEvents, + AllGovernanceEvents, + TornadoWithdrawParams, + RelayerTornadoWithdraw, + getActiveTokenInstances, + TovarishEventsStatus, + MAX_TOVARISH_EVENTS, + TovarishStatus, + TovarishEventsQuery, + BaseTovarishEvents, + AllRelayerRegistryEvents, + StakeBurnedEvents, +} from '@tornado/core'; + +import { isAddress, BigNumberish } from 'ethers'; + +import { RelayerConfig, version } from '../config'; +import { getLogger } from './logger'; +import { resolveMessages, sendMessage, SentMsg } from './routerMsg'; +import { SyncManagerStatus } from './sync'; +import { existsAsync, loadSavedEvents } from './data'; +import { RelayerTornadoQueue } from './worker'; +import { + getTreeNameKeyword, + getAllEventsKeyword, + getAllWithdrawKeyword, + getEventsSchema, + getWithdrawSchema, + idParamsSchema, + treeNameSchema, +} from './schema'; +import { ErrorMessages } from './error'; + +export function getHealthStatus(netId: NetIdType, syncManagerStatus: SyncManagerStatus) { + const { events, tokenPrice, gasPrice } = syncManagerStatus.syncStatus[netId]; + + return String(Boolean(events && tokenPrice && gasPrice)); +} + +export function getGasPrices(netId: NetIdType, syncManagerStatus: SyncManagerStatus) { + const { gasPrice, l1Fee } = syncManagerStatus.cachedGasPrices[netId]; + + return { + fast: Number(gasPrice), + additionalProperties: l1Fee ? Number(l1Fee) : undefined, + }; +} + +export function formatStatus({ + url, + netId, + relayerConfig, + syncManagerStatus, + pendingWorks, +}: { + url: string; + netId: NetIdType; + relayerConfig: RelayerConfig; + syncManagerStatus: SyncManagerStatus; + pendingWorks: number; +}): TovarishStatus { + const config = getConfig(netId); + + return { + url, + rewardAccount: relayerConfig.rewardAccount, + instances: getActiveTokenInstances(config), + events: syncManagerStatus.cachedEvents[netId], + gasPrices: getGasPrices(netId, syncManagerStatus), + netId, + ethPrices: syncManagerStatus.cachedPrices[netId], + tornadoServiceFee: relayerConfig.serviceFee, + latestBlock: syncManagerStatus.latestBlocks[netId], + latestBalance: syncManagerStatus.latestBalances[netId], + version, + health: { + status: getHealthStatus(netId, syncManagerStatus), + error: '', + errorsLog: [...syncManagerStatus.errors.filter((e) => e.netId === netId)], + }, + syncStatus: syncManagerStatus.syncStatus[netId], + onSyncEvents: syncManagerStatus.onSyncEvents, + currentQueue: pendingWorks, + }; +} + +export function handleIndex(enabledNetworks: NetIdType[]) { + return ( + 'This is Tornado Cash Relayer service. Check the ' + + enabledNetworks.map((netId) => `/${netId}/v1/status `).join(', ') + + 'for settings' + ); +} + +export async function handleStatus(url: string, router: Router, netId: NetIdType | NetIdType[], reply: FastifyReply) { + const { relayerConfig } = router; + + const { syncManagerStatus, pendingWorks } = await sendMessage<{ + syncManagerStatus: SyncManagerStatus; + pendingWorks: number; + }>(router, { type: 'status' }); + + if (Array.isArray(netId)) { + reply.send( + netId.map((n) => + formatStatus({ + url, + netId: n, + relayerConfig, + syncManagerStatus, + pendingWorks, + }), + ), + ); + return; + } + + reply.send( + formatStatus({ + url, + netId, + relayerConfig, + syncManagerStatus, + pendingWorks, + }), + ); +} + +/** + * Since we check gasLimit and fees, should extend timeout at any proxy more than 60s + */ +export async function handleTornadoWithdraw( + router: Router, + netId: NetIdType, + req: FastifyRequest, + reply: FastifyReply, +) { + const { contract, proof, args } = req.body as unknown as TornadoWithdrawParams; + + const { id, error } = await sendMessage(router, { + type: 'tornadoWithdraw', + netId, + contract, + proof, + args, + }); + + if (error) { + reply.code(502).send({ error }); + return; + } + + reply.send({ id }); +} + +export async function handleGetJob(router: Router, req: FastifyRequest, reply: FastifyReply) { + const { id } = req.params as unknown as { id: string }; + + const job = await sendMessage<{ error: string } | RelayerTornadoQueue>(router, { type: 'job', id }); + + if (job.error) { + reply.code(502).send(job); + return; + } + + reply.send(job as RelayerTornadoQueue); +} + +export type AllTovarishEvents = + | DepositsEvents + | WithdrawalsEvents + | EchoEvents + | EncryptedNotesEvents + | AllGovernanceEvents + | AllRelayerRegistryEvents + | StakeBurnedEvents; + +export async function handleEvents(router: Router, netId: NetIdType, req: FastifyRequest, reply: FastifyReply) { + const { + relayerConfig: { userEventsDir: userDirectory }, + } = router; + const { type, currency, amount, fromBlock, recent } = req.body as unknown as TovarishEventsQuery; + + const name = [DEPOSIT, WITHDRAWAL].includes(type) ? `${type}s_${netId}_${currency}_${amount}` : `${type}_${netId}`; + + // Can return 0 events but we just return error codes here + if (!(await existsAsync(path.join(userDirectory, `${name}.json`)))) { + reply.code(404).send(`Events ${name} not found!`); + return; + } + + const { syncManagerStatus } = await sendMessage<{ + syncManagerStatus: SyncManagerStatus; + }>(router, { type: 'status' }); + + const lastSyncBlock = Number( + [DEPOSIT, WITHDRAWAL].includes(type) + ? syncManagerStatus.cachedEvents[netId]?.instances?.[String(currency)]?.[String(amount)]?.[ + `${type}s` as 'deposits' | 'withdrawals' + ]?.lastBlock + : syncManagerStatus.cachedEvents[netId]?.[String(type) as keyof TovarishEventsStatus]?.lastBlock, + ); + + const { events } = await loadSavedEvents({ + name, + userDirectory, + }); + + if (recent) { + reply.send({ + events: events.slice(-10).sort((a, b) => { + if (a.blockNumber === b.blockNumber) { + return b.logIndex - a.logIndex; + } + return b.blockNumber - a.blockNumber; + }), + lastSyncBlock, + } as BaseTovarishEvents); + return; + } + + reply.send({ + events: events.filter((e) => e.blockNumber >= (fromBlock || 0)).slice(0, MAX_TOVARISH_EVENTS), + lastSyncBlock, + } as BaseTovarishEvents); +} + +export async function handleTrees(router: Router, req: FastifyRequest, reply: FastifyReply) { + const treeRegex = /deposits_(?\d+)_(?\w+)_(?[\d.]+)_(?\w+).json.zip/g; + const { netId, currency, amount, part } = + treeRegex.exec((req.params as unknown as { treeName: string }).treeName)?.groups || {}; + + const treeName = `deposits_${netId}_${currency}_${amount}_${part}.json.zip`; + const treePath = path.join(router.relayerConfig.userTreeDir, treeName); + + if (!(await existsAsync(treePath))) { + reply.status(404).send(`Tree ${treeName} not found!`); + return; + } + + reply.send(createReadStream(treePath)); +} + +export function listenRouter(router: Router) { + const { relayerConfig, logger, app, admin, forkId } = router; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + app.register(fastifyCors, () => (req: FastifyRequest, callback: any) => { + callback(null, { + origin: req.headers.origin || '*', + credentials: true, + methods: ['GET, POST, OPTIONS'], + headers: [ + 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type', + ], + maxAge: 1728000, + }); + }); + + app.get('/', (_, reply) => { + reply.type('text/html').send(handleIndex(relayerConfig.enabledNetworks)); + }); + + app.get('/relayer', (_, reply) => { + reply.type('text/html').send(handleIndex(relayerConfig.enabledNetworks)); + }); + + app.get('/status', (req, reply) => { + handleStatus(`${req.protocol}://${req.hostname}`, router, relayerConfig.enabledNetworks, reply); + }); + + app.get('/enabledNetworks', (_, reply) => { + reply.send(relayerConfig.enabledNetworks); + }); + + if (forkId === 0) { + logger.info('Router listening on /, /status, /enabledNetworks'); + } + + for (const netId of relayerConfig.enabledNetworks) { + app.get(`/${netId}`, (_, reply) => { + reply.type('text/html').send(handleIndex([netId])); + }); + + app.get(`/${netId}/status`, (req, reply) => { + handleStatus(`${req.protocol}://${req.hostname}/${netId}`, router, netId, reply); + }); + + const withdrawSchema = getWithdrawSchema(netId); + + app.post(`/${netId}/relay`, { schema: withdrawSchema }, (req, reply) => { + handleTornadoWithdraw(router, netId, req, reply); + }); + + app.get(`/${netId}/v1/status`, (req, reply) => { + handleStatus(`${req.protocol}://${req.hostname}/${netId}`, router, netId, reply); + }); + + app.post(`/${netId}/v1/tornadoWithdraw`, { schema: withdrawSchema }, (req, reply) => { + handleTornadoWithdraw(router, netId, req, reply); + }); + + app.get(`/${netId}/v1/jobs/:id`, { schema: idParamsSchema }, (req, reply) => { + handleGetJob(router, req, reply); + }); + + const eventSchema = getEventsSchema(netId); + + app.post(`/${netId}/events`, { schema: eventSchema }, (req, reply) => { + handleEvents(router, netId, req, reply); + }); + + app.get(`/${netId}/trees/:treeName`, { schema: treeNameSchema }, (req, reply) => { + handleTrees(router, req, reply); + }); + + if (forkId === 0) { + logger.info( + `Router listening on /${netId}, /${netId}/status, /${netId}/relay, /${netId}/v1/status, /${netId}/v1/tornadoWithdraw, /${netId}/v1/jobs/:id, /${netId}/events, /${netId}/trees/:treeName`, + ); + } + } + + const { port, host } = relayerConfig; + + app.listen({ port, host }, (err, address) => { + if (err) { + logger.error('Router Error'); + console.log(err); + throw err; + } else { + logger.debug(`Router listening on ${address}`); + } + }); + + admin.get('/errors', (_, reply) => { + (async () => { + const { errors } = await sendMessage<{ + errors: ErrorMessages[]; + }>(router, { type: 'errors' }); + + reply.header('Content-Type', 'application/json').send(JSON.stringify(errors, null, 2)); + })(); + }); + + admin.listen({ port: port + 100, host }, (err, address) => { + if (err) { + logger.error('Admin Router Error'); + console.log(err); + throw err; + } else { + if (forkId === 0) { + logger.debug(`Admin Router listening on ${address}`); + } + } + }); + + resolveMessages(router); +} + +export class Router { + relayerConfig: RelayerConfig; + logger: Logger; + forkId: number; + + app: FastifyInstance; + + // For viewing error logs + admin: FastifyInstance; + + messages: SentMsg[]; + + constructor(relayerConfig: RelayerConfig, forkId: number = 0) { + this.relayerConfig = relayerConfig; + this.logger = getLogger(`[Router ${forkId}]`, relayerConfig.logLevel); + this.forkId = forkId; + + const app = fastify({ + ajv: { + customOptions: { + keywords: [ + { + keyword: 'isAddress', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + validate: (schema: any, data: string) => { + try { + return isAddress(data); + } catch { + return false; + } + }, + errors: true, + }, + { + keyword: 'BN', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + validate: (schema: any, data: BigNumberish) => { + try { + BigInt(data); + return true; + } catch { + return false; + } + }, + errors: true, + }, + getTreeNameKeyword(), + ...getAllWithdrawKeyword(relayerConfig.rewardAccount), + ...getAllEventsKeyword(), + ], + }, + }, + trustProxy: relayerConfig.reverseProxy ? 1 : false, + ignoreTrailingSlash: true, + }); + + const admin = fastify(); + + this.app = app; + this.admin = admin; + this.messages = []; + + listenRouter(this); + } +} diff --git a/src/services/routerMsg.ts b/src/services/routerMsg.ts new file mode 100644 index 0000000..68a2982 --- /dev/null +++ b/src/services/routerMsg.ts @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Send and receive messages from worker to main thread + */ +import process from 'process'; +import { webcrypto as crypto } from 'crypto'; +import { bytesToHex } from '@tornado/core'; + +import { Router } from './router'; + +export interface SentMsg { + msgId: string; + resolve: (msg: any) => void; + reject: (err: any) => void; + resolved: boolean; +} + +export function sendMessage(router: Router, msg: any): Promise { + const msgId = bytesToHex(crypto.getRandomValues(new Uint8Array(8))); + + return new Promise((resolve, reject) => { + if (!process.send) { + reject(new Error('Not worker')); + return; + } + + const msgJson = JSON.parse(JSON.stringify(msg)) as any; + msgJson.msgId = msgId; + process.send(msgJson); + + router.messages.push({ + msgId, + resolve, + reject, + resolved: false, + }); + }); +} + +export function resolveMessages(router: Router) { + process.on('message', (msg: any) => { + const message = router.messages.find((w) => w.msgId === msg.msgId); + + if (!message) { + return; + } + + const msgJson = JSON.parse(JSON.stringify(msg)) as any; + delete msgJson.msgId; + message.resolve(msgJson); + + message.resolved = true; + + router.messages = router.messages.filter((w) => !w.resolved); + }); +} diff --git a/src/services/schema.ts b/src/services/schema.ts new file mode 100644 index 0000000..997d715 --- /dev/null +++ b/src/services/schema.ts @@ -0,0 +1,254 @@ +import { parseUnits } from 'ethers'; + +import { + NetIdType, + TornadoWithdrawParams, + getConfig, + getInstanceByAddress, + enabledChains, + TovarishEventsQuery, + WITHDRAWAL, + DEPOSIT, + addressSchemaType, + proofSchemaType, + bytes32SchemaType, + bytes32BNSchemaType, +} from '@tornado/core'; + +export const idParamsSchema = { + params: { + type: 'object', + properties: { + id: { type: 'string', format: 'uuid' }, + }, + required: ['id'], + additionalProperties: false, + }, +} as const; + +export const withdrawBodySchema = { + body: { + type: 'object', + properties: { + proof: proofSchemaType, + contract: addressSchemaType, + args: { + type: 'array', + maxItems: 6, + minItems: 6, + items: [ + bytes32SchemaType, + bytes32SchemaType, + addressSchemaType, + addressSchemaType, + bytes32BNSchemaType, + bytes32BNSchemaType, + ], + }, + }, + additionalProperties: false, + required: ['proof', 'contract', 'args'], + }, +} as const; + +const stringParamsType = { + type: 'string', + minLength: 1, + maxLength: 30, +} as const; + +export const eventsSchema = { + body: { + type: 'object', + properties: { + type: stringParamsType, + currency: stringParamsType, + amount: stringParamsType, + fromBlock: { type: 'number' }, + recent: { type: 'boolean' }, + }, + additionalProperties: false, + required: ['type', 'fromBlock'], + }, +} as const; + +export const treeNameSchema = { + params: { + type: 'object', + properties: { + treeName: { + type: 'string', + minLength: 1, + maxLength: 60, + TreeName: true, + }, + }, + additionalProperties: false, + required: ['treeName'], + }, +} as const; + +export function getWithdrawSchema(netId: NetIdType) { + const keyword = `withdraw${netId}`; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const schema = JSON.parse(JSON.stringify(withdrawBodySchema)) as any; + + schema.body[keyword] = true; + + return schema as typeof withdrawBodySchema & { + [key in keyof typeof keyword]: boolean; + }; +} + +export function getEventsSchema(netId: NetIdType) { + const keyword = `events${netId}`; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const schema = JSON.parse(JSON.stringify(eventsSchema)) as any; + + schema.body[keyword] = true; + + return schema as typeof eventsSchema & { + [key in keyof typeof keyword]: boolean; + }; +} + +export function getWithdrawKeyword(netId: NetIdType, rewardAccount: string) { + const keyword = `withdraw${netId}`; + + const config = getConfig(netId); + + return { + keyword, + validate: (schema: string, data: TornadoWithdrawParams) => { + try { + const { contract, args } = data; + + const instance = getInstanceByAddress(config, contract); + + // Unknown instance contract is unsupported + if (!instance) { + return false; + } + + // Fee recipient should be a reward account + if (args[3] !== rewardAccount) { + return false; + } + + const { amount, currency } = instance; + + const { + nativeCurrency, + tokens: { + [currency]: { decimals }, + }, + } = config; + + const denomination = parseUnits(amount, decimals); + + const fee = BigInt(args[4]); + + // Fees can't exceed denomination + if (!fee || fee >= denomination) { + return false; + } + + // ETHTornado instances can't have refunds + if (currency === nativeCurrency && BigInt(args[5])) { + return false; + } + + return true; + } catch { + return false; + } + }, + errors: true, + }; +} + +export function getEventsKeyword(netId: NetIdType) { + const keyword = `events${netId}`; + + const config = getConfig(netId); + + const { governanceContract, registryContract } = config; + + return { + keyword, + validate: (schema: string, data: TovarishEventsQuery) => { + try { + const { type, currency, amount } = data; + + if ([DEPOSIT, WITHDRAWAL].includes(type)) { + const instanceAddress = config.tokens[String(currency)]?.instanceAddress?.[String(amount)]; + + if (!instanceAddress) { + return false; + } + + return true; + } + + if (type === 'governance') { + if (!governanceContract) { + return false; + } + return true; + } + + // todo: remove this after some time, remains for legacy client connection + if (['registered', 'registry', 'revenue'].includes(type)) { + if (!registryContract) { + return false; + } + return true; + } + + return ['echo', 'encrypted_notes'].includes(type); + } catch { + return false; + } + }, + errors: true, + }; +} + +export function getTreeNameKeyword() { + return { + keyword: 'TreeName', + validate: (schema: string, data: string) => { + try { + const treeRegex = /deposits_(?\d+)_(?\w+)_(?[\d.]+)_(?\w+).json.zip/g; + const { netId, currency, amount, part } = treeRegex.exec(data)?.groups || {}; + + const config = getConfig(Number(netId)); + + if (!currency || !amount || !part || currency !== config.nativeCurrency) { + return false; + } + + const instanceAddress = config.tokens[String(currency)]?.instanceAddress?.[String(amount)]; + + if (!instanceAddress) { + return false; + } + + return true; + } catch { + return false; + } + }, + errors: true, + }; +} + +export function getAllWithdrawKeyword(rewardAccount: string) { + return enabledChains.map((netId) => getWithdrawKeyword(netId, rewardAccount)); +} + +export function getAllEventsKeyword() { + return enabledChains.map((netId) => getEventsKeyword(netId)); +} diff --git a/src/services/sync.ts b/src/services/sync.ts new file mode 100644 index 0000000..18d2cf1 --- /dev/null +++ b/src/services/sync.ts @@ -0,0 +1,634 @@ +import type { Provider } from 'ethers'; +import type { Logger } from 'winston'; + +import { + Governance__factory, + RelayerRegistry__factory, + Aggregator__factory, + Echoer__factory, + TornadoRouter__factory, + Tornado__factory, +} from '@tornado/contracts'; + +import { + getConfig, + getProviderWithNetId, + MerkleTreeService, + NetIdType, + getRelayerEnsSubdomains, + TokenPriceOracle, + Multicall__factory, + OffchainOracle__factory, + TornadoFeeOracle, + OvmGasPriceOracle__factory, + getActiveTokens, + TovarishEventsStatus, + InstanceEventsStatus, + TovarishSyncStatus, + EventsStatus, + ReverseRecords__factory, +} from '@tornado/core'; + +import { RelayerConfig } from '../config'; +import { getLogger } from './logger'; +import { TreeCache } from './treeCache'; +import { + NodeEchoService, + NodeEncryptedNotesService, + NodeGovernanceService, + NodeRegistryService, + NodeRevenueService, + NodeTornadoService, +} from './events'; +import { ErrorTypes, ErrorMessages, newError } from './error'; + +export interface AmountsServices { + depositsService: NodeTornadoService; + withdrawalsService: NodeTornadoService; +} + +export interface CurrencyServices { + [index: string]: AmountsServices; +} + +export interface TornadoServices { + [index: string]: CurrencyServices; +} + +export interface Services { + provider: Provider; + tokenPriceOracle: TokenPriceOracle; + tornadoFeeOracle: TornadoFeeOracle; + governanceService?: NodeGovernanceService; + registryService?: NodeRegistryService; + revenueService?: NodeRevenueService; + echoService: NodeEchoService; + encryptedNotesService: NodeEncryptedNotesService; + tornadoServices: TornadoServices; +} + +export interface CachedServices { + [index: NetIdType]: Services; +} + +export interface CachedEventsStatus { + [index: NetIdType]: TovarishEventsStatus; +} + +// Token prices in ETH wei +export interface TokenPrices { + [index: string]: bigint; +} + +export interface TokenPricesString { + [index: string]: string; +} + +export interface CachedPrices { + [index: NetIdType]: TokenPrices; +} + +export interface CachedPricesString { + [index: NetIdType]: TokenPricesString; +} + +export interface GasPrices { + gasPrice: string; + l1Fee?: string; +} + +export interface CachedGasPrices { + [index: NetIdType]: GasPrices; +} + +export interface LatestBlocks { + [index: NetIdType]: number; +} + +export interface LatestBalances { + [index: NetIdType]: string; +} + +export interface CachedSyncStatus { + [index: NetIdType]: TovarishSyncStatus; +} + +function setupServices(syncManager: SyncManager) { + const { relayerConfig, logger, syncStatus } = syncManager; + const { + cacheDir: cacheDirectory, + userEventsDir: userDirectory, + userTreeDir, + merkleWorkerPath, + enabledNetworks, + } = relayerConfig; + + const cachedServices = {} as CachedServices; + + for (const netId of enabledNetworks) { + const config = getConfig(netId); + const rpcUrl = relayerConfig.rpcUrls[netId]; + const provider = getProviderWithNetId(netId, rpcUrl, config); + + const { + tokens, + nativeCurrency, + routerContract, + echoContract, + registryContract, + aggregatorContract, + reverseRecordsContract, + governanceContract, + multicallContract, + offchainOracleContract, + ovmGasPriceOracleContract, + deployedBlock, + constants: { GOVERNANCE_BLOCK, REGISTRY_BLOCK, NOTE_ACCOUNT_BLOCK, ENCRYPTED_NOTES_BLOCK }, + } = config; + + if (!syncStatus[netId]) { + syncStatus[netId] = { + events: false, + tokenPrice: false, + gasPrice: false, + }; + } + + const services = (cachedServices[netId] = {} as Services); + + services.provider = provider; + + services.tokenPriceOracle = new TokenPriceOracle( + provider, + Multicall__factory.connect(multicallContract, provider), + offchainOracleContract ? OffchainOracle__factory.connect(offchainOracleContract, provider) : undefined, + ); + + services.tornadoFeeOracle = new TornadoFeeOracle( + provider, + ovmGasPriceOracleContract + ? OvmGasPriceOracle__factory.connect(ovmGasPriceOracleContract, provider) + : undefined, + ); + + if (governanceContract && aggregatorContract && reverseRecordsContract) { + services.governanceService = new NodeGovernanceService({ + netId, + provider, + Governance: Governance__factory.connect(governanceContract, provider), + Aggregator: Aggregator__factory.connect(aggregatorContract, provider), + ReverseRecords: ReverseRecords__factory.connect(reverseRecordsContract, provider), + deployedBlock: GOVERNANCE_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + } + + if (registryContract && aggregatorContract) { + services.registryService = new NodeRegistryService({ + netId, + provider, + RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider), + Aggregator: Aggregator__factory.connect(aggregatorContract, provider), + relayerEnsSubdomains: getRelayerEnsSubdomains(), + deployedBlock: REGISTRY_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + + services.revenueService = new NodeRevenueService({ + netId, + provider, + RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider), + deployedBlock: REGISTRY_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + } + + services.echoService = new NodeEchoService({ + netId, + provider, + Echoer: Echoer__factory.connect(echoContract, provider), + deployedBlock: NOTE_ACCOUNT_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + + services.encryptedNotesService = new NodeEncryptedNotesService({ + netId, + provider, + Router: TornadoRouter__factory.connect(routerContract, provider), + deployedBlock: ENCRYPTED_NOTES_BLOCK, + cacheDirectory, + userDirectory, + logger, + }); + + services.tornadoServices = {} as TornadoServices; + + for (const currency of getActiveTokens(config)) { + const currencyConfig = tokens[currency]; + + const currencyService = (services.tornadoServices[currency] = {} as CurrencyServices); + + for (const [amount, instanceAddress] of Object.entries(currencyConfig.instanceAddress)) { + const Tornado = Tornado__factory.connect(instanceAddress, provider); + + const amountService = (currencyService[amount] = {} as AmountsServices); + + const TornadoServiceConstructor = { + netId, + provider, + Tornado, + amount, + currency, + deployedBlock, + cacheDirectory, + userDirectory, + nativeCurrency, + logger, + }; + + amountService.depositsService = new NodeTornadoService({ + ...TornadoServiceConstructor, + merkleTreeService: new MerkleTreeService({ + netId, + amount, + currency, + Tornado, + merkleWorkerPath, + }), + treeCache: new TreeCache({ + netId, + amount, + currency, + userDirectory: userTreeDir, + }), + optionalTree: true, + type: 'Deposit', + }); + + amountService.withdrawalsService = new NodeTornadoService({ + ...TornadoServiceConstructor, + type: 'Withdrawal', + }); + } + } + } + + syncManager.cachedServices = cachedServices; +} + +export async function syncGasPrice(syncManager: SyncManager, netId: NetIdType) { + const { + cachedServices, + logger, + errors, + cachedGasPrices, + latestBlocks, + latestBalances, + syncStatus, + relayerConfig: { rewardAccount }, + } = syncManager; + + try { + const services = cachedServices[netId]; + + const { provider, tornadoFeeOracle } = services; + + const [blockNumber, balance, gasPrice, l1Fee] = await Promise.all([ + provider.getBlockNumber(), + provider.getBalance(rewardAccount), + tornadoFeeOracle.gasPrice(), + tornadoFeeOracle.fetchL1OptimismFee(), + ]); + + cachedGasPrices[netId] = { + gasPrice: gasPrice.toString(), + l1Fee: l1Fee ? l1Fee.toString() : undefined, + }; + + latestBlocks[netId] = blockNumber; + latestBalances[netId] = balance.toString(); + + syncStatus[netId].gasPrice = true; + } catch (err) { + logger.error(`${netId}: Failed to sync gas prices`); + console.log(err); + syncStatus[netId].gasPrice = false; + errors.push(newError('SyncManager (gas)', netId, err)); + } +} + +export async function syncPrices(syncManager: SyncManager, netId: NetIdType) { + const { cachedServices, logger, errors, cachedPrices, syncStatus } = syncManager; + + try { + const config = getConfig(netId); + + const { nativeCurrency, tornContract } = config; + + const services = cachedServices[netId]; + + const { tokenPriceOracle } = services; + + // Classic UI ajv validator requires all token prices to present + const allTokens = Object.keys(config.tokens); + + if (tornContract && !allTokens.includes('torn')) { + allTokens.push('torn'); + } + + const tokens = allTokens + .map((currency) => { + if (currency === nativeCurrency) { + return; + } + + if (currency === 'torn') { + return { + currency, + tokenAddress: tornContract, + decimals: 18, + }; + } + + const { tokenAddress, decimals } = config.tokens[currency]; + + return { + currency, + tokenAddress, + decimals, + }; + }) + .filter((t) => t) as { + currency: string; + tokenAddress: string; + decimals: number; + }[]; + + if (!tokens.length) { + syncStatus[netId].tokenPrice = true; + return; + } + + cachedPrices[netId] = (await tokenPriceOracle.fetchPrices(tokens)).reduce((acc, price, index) => { + acc[tokens[index].currency] = price; + return acc; + }, {} as TokenPrices); + + syncStatus[netId].tokenPrice = true; + + logger.info(`${netId}: Synced ${tokens.length} tokens price`); + } catch (err) { + logger.error(`${netId}: Failed to sync prices`); + console.log(err); + syncStatus[netId].tokenPrice = false; + errors.push(newError('SyncManager (price)', netId, err)); + } +} + +export async function syncNetworkEvents(syncManager: SyncManager, netId: NetIdType) { + const { cachedEvents, cachedServices, logger, errors, syncStatus } = syncManager; + + try { + const services = cachedServices[netId]; + + const { + provider, + governanceService, + registryService, + revenueService, + echoService, + encryptedNotesService, + tornadoServices, + } = services; + + logger.info(`${netId}: Syncing events from block ${await provider.getBlockNumber()}`); + + const eventsStatus = { + governance: governanceService ? {} : undefined, + registered: registryService ? {} : undefined, + registry: registryService ? {} : undefined, + revenue: revenueService ? {} : undefined, + echo: {}, + encrypted_notes: {}, + instances: {}, + } as TovarishEventsStatus; + + if (governanceService) { + const { events, lastBlock } = await governanceService.updateEvents(); + + eventsStatus.governance = { + events: events.length, + lastBlock, + }; + + logger.info(`${netId}: Updated governance events (total: ${events.length}, block: ${lastBlock})`); + } + + if (registryService) { + { + const { events, lastBlock } = await registryService.updateEvents(); + + eventsStatus.registry = { + events: events.length, + lastBlock, + }; + + logger.info(`${netId}: Updated registry events (total: ${events.length}, block: ${lastBlock})`); + } + + { + const { lastBlock, timestamp, relayers } = await registryService.updateRelayers(); + + eventsStatus.registered = { + lastBlock, + timestamp, + relayers: relayers.length, + }; + + logger.info( + `${netId}: Updated registry relayers (total: ${relayers.length}, block: ${lastBlock}, timestamp: ${timestamp})`, + ); + } + } + + if (revenueService) { + const { events, lastBlock } = await revenueService.updateEvents(); + + eventsStatus.revenue = { + events: events.length, + lastBlock, + }; + + logger.info(`${netId}: Updated revenue events (total: ${events.length}, block: ${lastBlock})`); + } + + const echoEvents = await echoService.updateEvents(); + + eventsStatus.echo = { + events: echoEvents.events.length, + lastBlock: echoEvents.lastBlock, + }; + + logger.info( + `${netId}: Updated echo events (total: ${echoEvents.events.length}, block: ${echoEvents.lastBlock})`, + ); + + const encryptedNotesEvents = await encryptedNotesService.updateEvents(); + + eventsStatus.encrypted_notes = { + events: encryptedNotesEvents.events.length, + lastBlock: encryptedNotesEvents.lastBlock, + }; + + logger.info( + `${netId}: Updated encrypted notes events (total: ${encryptedNotesEvents.events.length}, block: ${encryptedNotesEvents.lastBlock})`, + ); + + const currencies = Object.keys(tornadoServices); + + for (const currency of currencies) { + const currencyStatus = (eventsStatus.instances[currency] = {} as InstanceEventsStatus); + + const amounts = Object.keys(tornadoServices[currency]); + + for (const amount of amounts) { + const instanceStatus = (currencyStatus[amount] = { + deposits: {} as EventsStatus, + withdrawals: {} as EventsStatus, + }); + + const { depositsService, withdrawalsService } = tornadoServices[currency][amount]; + + const depositEvents = await depositsService.updateEvents(); + + instanceStatus.deposits = { + events: depositEvents.events.length, + lastBlock: depositEvents.lastBlock, + }; + + logger.info( + `${netId}: Updated ${currency} ${amount} Tornado deposit events (total: ${depositEvents.events.length}, block: ${depositEvents.lastBlock})`, + ); + + const withdrawalEvents = await withdrawalsService.updateEvents(); + + instanceStatus.withdrawals = { + events: withdrawalEvents.events.length, + lastBlock: withdrawalEvents.lastBlock, + }; + + logger.info( + `${netId}: Updated ${currency} ${amount} Tornado withdrawal events (total: ${withdrawalEvents.events.length}, block: ${withdrawalEvents.lastBlock})`, + ); + } + } + + cachedEvents[netId] = eventsStatus; + + syncStatus[netId].events = true; + + logger.info(`${netId}: Synced all events`); + + await Promise.all([syncPrices(syncManager, netId), syncGasPrice(syncManager, netId)]); + } catch (err) { + logger.error(`${netId}: Failed to sync events`); + console.log(err); + syncStatus[netId].events = false; + errors.push(newError('SyncManager (events)', netId, err)); + } +} + +export interface SyncManagerStatus { + cachedEvents: CachedEventsStatus; + cachedPrices: CachedPricesString; + cachedGasPrices: CachedGasPrices; + + syncStatus: CachedSyncStatus; + latestBlocks: LatestBlocks; + latestBalances: LatestBalances; + errors: ErrorTypes[]; + + onSyncEvents: boolean; +} + +export class SyncManager { + relayerConfig: RelayerConfig; + logger: Logger; + cachedServices: CachedServices; + + cachedEvents: CachedEventsStatus; + cachedPrices: CachedPrices; + cachedGasPrices: CachedGasPrices; + + syncStatus: CachedSyncStatus; + latestBlocks: LatestBlocks; + latestBalances: LatestBalances; + errors: ErrorMessages[]; + + onSyncEvents: boolean; + + constructor(relayerConfig: RelayerConfig) { + this.relayerConfig = relayerConfig; + this.logger = getLogger('[SyncManager]', relayerConfig.logLevel); + this.cachedServices = {} as CachedServices; + + this.cachedEvents = {} as CachedEventsStatus; + this.cachedPrices = {} as CachedPrices; + this.cachedGasPrices = {} as CachedGasPrices; + + this.syncStatus = {} as CachedSyncStatus; + this.latestBlocks = {} as LatestBlocks; + this.latestBalances = {} as LatestBalances; + this.errors = []; + + this.onSyncEvents = false; + + setupServices(this); + } + + getStatus(): SyncManagerStatus { + return { + cachedEvents: this.cachedEvents, + cachedPrices: JSON.parse(JSON.stringify(this.cachedPrices)), + cachedGasPrices: JSON.parse(JSON.stringify(this.cachedGasPrices)), + + syncStatus: this.syncStatus, + latestBlocks: this.latestBlocks, + latestBalances: this.latestBalances, + errors: this.errors.map(({ type, netId, timestamp }) => ({ + type, + netId, + timestamp, + })), + + onSyncEvents: this.onSyncEvents, + }; + } + + getPrice(netId: NetIdType, token: string) { + return this.cachedPrices[netId]?.[token] || BigInt(0); + } + + getGasPrice(netId: NetIdType) { + return this.cachedGasPrices[netId]; + } + + async syncEvents() { + if (this.onSyncEvents) { + return; + } + this.onSyncEvents = true; + + await Promise.all(this.relayerConfig.enabledNetworks.map((netId) => syncNetworkEvents(this, Number(netId)))); + + this.onSyncEvents = false; + } +} diff --git a/src/services/treeCache.ts b/src/services/treeCache.ts new file mode 100644 index 0000000..08ffce5 --- /dev/null +++ b/src/services/treeCache.ts @@ -0,0 +1,113 @@ +/** + * Create tree cache file from node.js + * + * Only works for node.js, modified from https://github.com/tornadocash/tornado-classic-ui/blob/master/scripts/updateTree.js + */ +import { MerkleTree } from '@tornado/fixed-merkle-tree'; +import BloomFilter from 'bloomfilter.js'; +import { DepositsEvents } from '@tornado/core'; +import type { NetIdType } from '@tornado/core'; +import { saveUserFile } from './data'; + +export interface TreeCacheConstructor { + netId: NetIdType; + amount: string; + currency: string; + userDirectory: string; + PARTS_COUNT?: number; + LEAVES?: number; + zeroElement?: string; +} + +export interface treeMetadata { + blockNumber: number; + logIndex: number; + transactionHash: string; + timestamp: number; + from: string; + leafIndex: number; +} + +export class TreeCache { + netId: NetIdType; + amount: string; + currency: string; + userDirectory: string; + + PARTS_COUNT: number; + + constructor({ netId, amount, currency, userDirectory, PARTS_COUNT = 4 }: TreeCacheConstructor) { + this.netId = netId; + this.amount = amount; + this.currency = currency; + this.userDirectory = userDirectory; + + this.PARTS_COUNT = PARTS_COUNT; + } + + getInstanceName(): string { + return `deposits_${this.netId}_${this.currency}_${this.amount}`; + } + + async createTree(events: DepositsEvents[], tree: MerkleTree) { + const bloom = new BloomFilter(events.length); + + console.log(`Creating cached tree for ${this.getInstanceName()}\n`); + + // events indexed by commitment + const eventsData = events.reduce( + (acc, { leafIndex, commitment, ...rest }, i) => { + if (leafIndex !== i) { + throw new Error(`leafIndex (${leafIndex}) !== i (${i})`); + } + + acc[commitment] = { ...rest, leafIndex }; + + return acc; + }, + {} as { [key in string]: treeMetadata }, + ); + + const slices = tree.getTreeSlices(this.PARTS_COUNT); + + await Promise.all( + slices.map(async (slice, index) => { + const metadata = slice.elements.reduce((acc, curr) => { + if (index < this.PARTS_COUNT - 1) { + bloom.add(curr); + } + acc.push(eventsData[curr]); + return acc; + }, [] as treeMetadata[]); + + const dataString = + JSON.stringify( + { + ...slice, + metadata, + }, + null, + 2, + ) + '\n'; + + const fileName = `${this.getInstanceName()}_slice${index + 1}.json`; + + await saveUserFile({ + fileName, + userDirectory: this.userDirectory, + dataString, + }); + }), + ); + + const dataString = bloom.serialize() + '\n'; + + const fileName = `${this.getInstanceName()}_bloom.json`; + + await saveUserFile({ + fileName, + userDirectory: this.userDirectory, + dataString, + }); + } +} diff --git a/src/services/utils.ts b/src/services/utils.ts new file mode 100644 index 0000000..5bcc5e6 --- /dev/null +++ b/src/services/utils.ts @@ -0,0 +1,11 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(BigInt.prototype as any).toJSON = function () { + return this.toString(); +}; + +export const chunk = (arr: T[], size: number): T[][] => + [...Array(Math.ceil(arr.length / size))].map((_, i) => arr.slice(size * i, size + size * i)); + +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/src/services/worker.ts b/src/services/worker.ts new file mode 100644 index 0000000..cc34741 --- /dev/null +++ b/src/services/worker.ts @@ -0,0 +1,458 @@ +import { webcrypto as crypto } from 'crypto'; +import type { Logger } from 'winston'; +import { formatUnits, parseUnits, Provider } from 'ethers'; + +import { TornadoRouter, TornadoRouter__factory } from '@tornado/contracts'; + +import { + getConfig, + getProviderWithNetId, + NetIdType, + TornadoWithdrawParams, + RelayerTornadoJobs, + RelayerTornadoWithdraw, + TornadoFeeOracle, + snarkArgs, + Config, + getInstanceByAddress, + TornadoWallet, + sleep, +} from '@tornado/core'; + +import { getPrivateKey, RelayerConfig } from '../config'; +import { getLogger } from './logger'; +import { SyncManager } from './sync'; +import { ErrorMessages, newError } from './error'; + +export enum RelayerStatus { + QUEUED = 'QUEUED', + ACCEPTED = 'ACCEPTED', + SENT = 'SENT', + MINED = 'MINED', + RESUBMITTED = 'RESUBMITTED', + CONFIRMED = 'CONFIRMED', + FAILED = 'FAILED', +} + +export const DEFAULT_GAS_LIMIT = 600_000; + +export interface RelayerServices { + provider: Provider; + signer: TornadoWallet; + tornadoFeeOracle: TornadoFeeOracle; + Router: TornadoRouter; +} + +export interface CachedRelayerServices { + [key: NetIdType]: RelayerServices; +} + +function setupServices(relayerWorker: RelayerWorker) { + const { + relayerConfig: { enabledNetworks, txRpcUrls }, + } = relayerWorker; + + for (const netId of enabledNetworks) { + const config = getConfig(netId); + const rpcUrl = txRpcUrls[netId]; + const provider = getProviderWithNetId(netId, rpcUrl, config); + const signer = new TornadoWallet(getPrivateKey(), provider); + + const Router = TornadoRouter__factory.connect(config.routerContract, signer); + + const tornadoFeeOracle = new TornadoFeeOracle(provider); + + relayerWorker.cachedRelayerServices[netId] = { + provider, + signer, + Router, + tornadoFeeOracle, + }; + } +} + +export function getFeeParams( + config: Config, + serviceFee: number, + syncManager: SyncManager, + { netId, contract, args }: RelayerTornadoQueue, +) { + const { amount, currency } = getInstanceByAddress(config, contract) as { + amount: string; + currency: string; + }; + + const { + nativeCurrency, + tokens: { + [currency]: { symbol: currencySymbol, decimals, gasLimit: instanceGasLimit }, + }, + } = config; + + const symbol = currencySymbol.toLowerCase(); + + const { gasPrice, l1Fee } = syncManager.getGasPrice(netId); + + const gasLimit = BigInt(instanceGasLimit || DEFAULT_GAS_LIMIT); + + const denomination = parseUnits(amount, decimals); + + const ethRefund = BigInt(args[5]); + + const tokenPriceInWei = syncManager.getPrice(netId, symbol); + + const isEth = nativeCurrency === currency; + + return { + amount, + symbol, + gasPrice: BigInt(gasPrice), + gasLimit, + l1Fee, + denomination, + ethRefund, + tokenPriceInWei, + tokenDecimals: decimals, + relayerFeePercent: serviceFee, + isEth, + premiumPercent: 5, + }; +} + +export async function checkWithdrawalFees( + relayerWorker: RelayerWorker, + work: RelayerTornadoQueue, +): Promise<{ + gasPrice: bigint; + gasLimit: bigint; + status: boolean; + error?: string; +}> { + try { + const { id, netId, contract, proof, args } = work; + + const { + relayerConfig: { rewardAccount, serviceFee }, + cachedRelayerServices: { + [netId]: { tornadoFeeOracle, Router }, + }, + syncManager, + } = relayerWorker; + + const config = getConfig(netId); + + const feeParams = getFeeParams(config, serviceFee, syncManager, work); + + const { amount, symbol, tokenDecimals, denomination, ethRefund } = feeParams; + + let fee = tornadoFeeOracle.calculateRelayerFee(feeParams); + + const gasLimit = await Router.withdraw.estimateGas(contract, proof, ...args, { + from: rewardAccount, + value: ethRefund, + }); + + // Recalculate fee based on correct gas limit + fee = tornadoFeeOracle.calculateRelayerFee({ + ...feeParams, + gasLimit, + }); + + if (fee > denomination) { + return { + gasPrice: feeParams.gasPrice, + gasLimit, + status: false, + error: `Fee above deposit amount, requires ${formatUnits(fee, tokenDecimals)} ${symbol} while denomination is ${amount} ${symbol}`, + }; + } + + if (fee > BigInt(args[4])) { + return { + gasPrice: feeParams.gasPrice, + gasLimit, + status: false, + error: `Insufficient fee, requires ${formatUnits(fee, tokenDecimals)} ${symbol} while user only wants to pay ${formatUnits(BigInt(args[4]), tokenDecimals)} ${symbol}`, + }; + } + + relayerWorker.logger.info( + `New job: ${id} ${netId} ${amount} ${symbol} (Fee: ${formatUnits(BigInt(args[4]), tokenDecimals)} ${symbol}, Refund: ${formatUnits(BigInt(args[5]), tokenDecimals)})`, + ); + + return { + gasPrice: feeParams.gasPrice, + gasLimit, + status: true, + }; + } catch { + return { + gasPrice: BigInt(0), + gasLimit: BigInt(0), + status: false, + error: 'Withdrawal transaction expected to be reverted', + }; + } +} + +export async function processWithdrawals(relayerWorker: RelayerWorker) { + const { logger, cachedRelayerServices, errors } = relayerWorker; + + for (const work of relayerWorker.queue) { + try { + if (work.status !== RelayerStatus.ACCEPTED) { + continue; + } + + const { id, netId, contract, proof, args } = work; + + // cancel duplicated jobs + const otherWork = relayerWorker.queue.find( + (q) => + q.id !== id && + // find if other previous work is already sent (not pending or failed - to allow spending first and failed one) + q.status !== RelayerStatus.ACCEPTED && + q.status !== RelayerStatus.FAILED && + q.contract === contract && + q.args[1] === args[1], + ); + + if (otherWork) { + const errMsg = `Found the same pending job ${otherWork.id}, wait until the previous one completes`; + throw new Error(errMsg); + } + + const { gasLimit, gasPrice } = relayerWorker.queueGas.find((w) => w.id === id) as { + gasLimit: bigint; + gasPrice: bigint; + }; + + const config = getConfig(netId); + + const { amount, currency } = getInstanceByAddress(config, contract) as { + amount: string; + currency: string; + }; + const { decimals } = config.tokens[currency]; + const { Router, signer } = cachedRelayerServices[netId]; + + /** + * Check fees to ensure that it didn't spike or revert (or has insane gas spendings) + */ + const txObj = await signer.populateTransaction( + await Router.withdraw.populateTransaction(contract, proof, ...args, { + value: BigInt(args[5]), + }), + ); + + const txGasPrice = txObj.maxFeePerGas + ? (txObj.maxFeePerGas as bigint) + BigInt(txObj.maxPriorityFeePerGas || 0) + : (txObj.gasPrice as bigint); + + // Prevent tx on gas limit spike + if ((txObj.gasLimit as bigint) > (gasLimit * BigInt(15)) / BigInt(10)) { + const errMsg = `Job ${id} exceeds pre estimated gas limit, wants ${gasLimit * BigInt(2)} have ${txObj.gasLimit}`; + throw new Error(errMsg); + } + + // Prevent tx on gas price spike + if (txGasPrice > gasPrice * BigInt(2)) { + const errMsg = `Job ${id} exceeds pre estimated gas price, wants ${gasPrice * BigInt(2)} have ${txGasPrice}`; + throw new Error(errMsg); + } + + const tx = await signer.sendTransaction(txObj); + + work.txHash = tx.hash; + work.confirmations = 0; + work.status = RelayerStatus.SENT; + + logger.info( + `Sent Job ${work.id} ${netId} ${amount} ${currency} tx (Fee: ${formatUnits(BigInt(args[4]), decimals)} ${currency}, Refund: ${formatUnits(BigInt(args[5]), decimals)} ${currency} ${tx.hash})`, + ); + + // Wait for 2 seconds so that the remote node could increment nonces + await sleep(2000); + + // Head straight to confirmed status as the remote node oftenly doesn't report receipt correctly + work.confirmations = 1; + work.status = RelayerStatus.MINED; + + work.confirmations = 3; + work.status = RelayerStatus.CONFIRMED; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + logger.error(`Failed to send job ${work.id}`); + console.log(error); + errors.push(newError('Worker (processWithdrawals)', work.netId, error)); + + work.status = RelayerStatus.FAILED; + + if (error.message?.includes('exceeds pre estimated')) { + work.failedReason = error.message; + } else if (error.message?.includes('Found the same pending job')) { + work.failedReason = error.message; + } else { + work.failedReason = 'Relayer failed to send transaction'; + } + } + } + + relayerWorker.queue = relayerWorker.queue.filter( + (w) => w.timestamp + relayerWorker.relayerConfig.clearInterval >= Math.floor(Date.now() / 1000), + ); + + relayerWorker.queueGas = relayerWorker.queueGas.filter( + (w) => w.timestamp + relayerWorker.relayerConfig.clearInterval >= Math.floor(Date.now() / 1000), + ); +} + +export interface CreateWorkParams extends TornadoWithdrawParams { + netId: NetIdType; +} + +export interface RelayerTornadoQueue extends Omit { + netId: NetIdType; + contract: string; + proof: string; + args: snarkArgs; + timestamp: number; +} + +export interface RelayerQueueGas { + id: string; + gasPrice: bigint; + gasLimit: bigint; + timestamp: number; +} + +export class RelayerWorker { + relayerConfig: RelayerConfig; + logger: Logger; + syncManager: SyncManager; + + cachedRelayerServices: CachedRelayerServices; + + queue: RelayerTornadoQueue[]; + queueGas: RelayerQueueGas[]; + + queueTimer: null | NodeJS.Timeout; + + errors: ErrorMessages[]; + + constructor(relayerConfig: RelayerConfig, syncManager: SyncManager) { + this.relayerConfig = relayerConfig; + this.syncManager = syncManager; + this.logger = getLogger('[RelayerWorker]', relayerConfig.logLevel); + this.cachedRelayerServices = {} as CachedRelayerServices; + this.queue = []; + this.queueGas = []; + this.queueTimer = null; + this.errors = []; + + setupServices(this); + } + + async doWork() { + await processWithdrawals(this); + + const pendingWorks = this.queue.filter( + (q) => q.status === RelayerStatus.QUEUED || q.status === RelayerStatus.ACCEPTED, + ).length; + + if (pendingWorks) { + if (pendingWorks < 5) { + this.doWork(); + return; + } else { + this.queue.forEach((q) => { + q.status = RelayerStatus.FAILED; + q.error = 'Relayer has too many jobs, try it again later'; + q.failedReason = 'Relayer has too many jobs, try it again later'; + }); + + this.logger.error(`Relayer has cleared the workload ( ${pendingWorks} ) due to overhaul`); + } + } + + this.queueTimer = null; + } + + async createWork({ + netId, + contract, + proof, + args, + }: CreateWorkParams): Promise { + const work: RelayerTornadoQueue = { + netId, + id: crypto.randomUUID(), + type: 'TORNADO_WITHDRAW', + status: RelayerStatus.QUEUED, + contract, + proof, + args, + timestamp: Math.floor(Date.now() / 1000), + }; + + if ( + this.queue.find( + (q) => q.status !== RelayerStatus.FAILED && q.contract === contract && q.args[1] === args[1], + ) + ) { + work.status = RelayerStatus.FAILED; + + return { + error: 'Found the same pending job, wait until the previous one completes', + }; + } + + const { gasPrice, gasLimit, status, error } = await checkWithdrawalFees(this, work); + + const workGas = { + id: work.id, + gasPrice, + gasLimit, + timestamp: work.timestamp, + }; + + if (!status) { + work.status = RelayerStatus.FAILED; + + return { + error, + }; + } + + work.status = RelayerStatus.ACCEPTED; + + this.queue.push(work); + this.queueGas.push(workGas); + + if (!this.queueTimer) { + this.queueTimer = setTimeout(() => this.doWork(), 500); + } + + return work; + } + + getWork({ id }: { id: string }): RelayerTornadoWithdraw | RelayerTornadoQueue { + const work = this.queue.find((w) => w.id === id); + + if (!work) { + return { + error: `Work ${id} not found`, + }; + } + + const copiedWork = JSON.parse(JSON.stringify(work)); + delete copiedWork.netId; + return copiedWork as RelayerTornadoQueue; + } + + pendingWorks() { + return this.queue.filter((q) => q.status === RelayerStatus.QUEUED || q.status === RelayerStatus.ACCEPTED) + .length; + } +} diff --git a/src/start.ts b/src/start.ts new file mode 100644 index 0000000..77e8b23 --- /dev/null +++ b/src/start.ts @@ -0,0 +1,125 @@ +import process from 'process'; +import cluster from 'cluster'; +import type { Logger } from 'winston'; + +import { getRelayerConfig, RelayerConfig } from './config'; +import { getLogger, SyncManager, Router, RelayerWorker, checkProviders } from './services'; + +if (cluster.isWorker) { + new Router(JSON.parse(process.env.relayerConfig as string) as RelayerConfig, Number(process.env.forkId)); +} else { + start(); +} + +async function forkRouter({ + relayerConfig, + logger, + syncManager, + relayerWorker, + forkId, +}: { + relayerConfig: RelayerConfig; + logger: Logger; + syncManager: SyncManager; + relayerWorker: RelayerWorker; + forkId: number; +}) { + const worker = cluster.fork({ + relayerConfig: JSON.stringify(relayerConfig), + forkId, + }); + + worker + .on('exit', (code) => { + logger.error(`Router Worker ${forkId} died with code ${code}, respawning...`); + + setTimeout(() => { + forkRouter({ + relayerConfig, + logger, + syncManager, + relayerWorker, + forkId, + }); + }, 5000); + }) + .on('message', async (msg) => { + const { msgId, type } = msg; + + if (type === 'status') { + worker.send({ + msgId, + syncManagerStatus: syncManager.getStatus(), + pendingWorks: relayerWorker.pendingWorks(), + }); + return; + } + + if (type === 'job') { + const work = relayerWorker.getWork({ + id: msg.id, + }); + + worker.send({ + msgId, + ...work, + }); + return; + } + + if (type === 'tornadoWithdraw') { + const newWork = await relayerWorker.createWork({ + netId: msg.netId, + contract: msg.contract, + proof: msg.proof, + args: msg.args, + }); + + worker.send({ + msgId, + ...newWork, + }); + return; + } + + if (type === 'errors') { + worker.send({ + msgId, + errors: [...syncManager.errors, ...relayerWorker.errors], + }); + return; + } + }); +} + +async function start() { + const relayerConfig = getRelayerConfig(); + const logger = getLogger('[Main]', relayerConfig.logLevel); + + console.log('Relayer config', relayerConfig); + + await checkProviders(relayerConfig, logger); + + const syncManager = new SyncManager(relayerConfig); + + await syncManager.syncEvents(); + + const relayerWorker = new RelayerWorker(relayerConfig, syncManager); + + setInterval(() => syncManager.syncEvents(), relayerConfig.syncInterval * 1000); + + // Spawn website + let i = 0; + while (i < relayerConfig.workers) { + forkRouter({ + relayerConfig, + logger, + syncManager, + relayerWorker, + forkId: i, + }); + i++; + } + + logger.info(`Spawned ${i} Router Workers`); +} diff --git a/src/types/bloomfilter.js.d.ts b/src/types/bloomfilter.js.d.ts new file mode 100644 index 0000000..3813634 --- /dev/null +++ b/src/types/bloomfilter.js.d.ts @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +declare module 'bloomfilter.js' { + export default class BloomFilter { + m: number; + k: number; + size: number; + bitview: any; + + constructor(n: number, false_postive_tolerance?: number); + + calculateHash(x: number, m: number, i: number): number; + + test(data: any): boolean; + + add(data: any): void; + + bytelength(): number; + + view(): Uint8Array; + + serialize(): string; + + deserialize(serialized: string): BloomFilter; + } +} diff --git a/static/events/deposits_100_xdai_100.json.zip b/static/events/deposits_100_xdai_100.json.zip new file mode 100644 index 0000000..2a00478 Binary files /dev/null and b/static/events/deposits_100_xdai_100.json.zip differ diff --git a/static/events/deposits_100_xdai_1000.json.zip b/static/events/deposits_100_xdai_1000.json.zip new file mode 100644 index 0000000..24e1266 Binary files /dev/null and b/static/events/deposits_100_xdai_1000.json.zip differ diff --git a/static/events/deposits_100_xdai_10000.json.zip b/static/events/deposits_100_xdai_10000.json.zip new file mode 100644 index 0000000..503c732 Binary files /dev/null and b/static/events/deposits_100_xdai_10000.json.zip differ diff --git a/static/events/deposits_100_xdai_100000.json.zip b/static/events/deposits_100_xdai_100000.json.zip new file mode 100644 index 0000000..b6b7698 Binary files /dev/null and b/static/events/deposits_100_xdai_100000.json.zip differ diff --git a/static/events/deposits_10_eth_0.1.json.zip b/static/events/deposits_10_eth_0.1.json.zip new file mode 100644 index 0000000..d18522e Binary files /dev/null and b/static/events/deposits_10_eth_0.1.json.zip differ diff --git a/static/events/deposits_10_eth_1.json.zip b/static/events/deposits_10_eth_1.json.zip new file mode 100644 index 0000000..d690f10 Binary files /dev/null and b/static/events/deposits_10_eth_1.json.zip differ diff --git a/static/events/deposits_10_eth_10.json.zip b/static/events/deposits_10_eth_10.json.zip new file mode 100644 index 0000000..b16bbc4 Binary files /dev/null and b/static/events/deposits_10_eth_10.json.zip differ diff --git a/static/events/deposits_10_eth_100.json.zip b/static/events/deposits_10_eth_100.json.zip new file mode 100644 index 0000000..1961d16 Binary files /dev/null and b/static/events/deposits_10_eth_100.json.zip differ diff --git a/static/events/deposits_11155111_dai_100.json.zip b/static/events/deposits_11155111_dai_100.json.zip new file mode 100644 index 0000000..dc65ca1 Binary files /dev/null and b/static/events/deposits_11155111_dai_100.json.zip differ diff --git a/static/events/deposits_11155111_dai_1000.json.zip b/static/events/deposits_11155111_dai_1000.json.zip new file mode 100644 index 0000000..0971a0b Binary files /dev/null and b/static/events/deposits_11155111_dai_1000.json.zip differ diff --git a/static/events/deposits_11155111_dai_10000.json.zip b/static/events/deposits_11155111_dai_10000.json.zip new file mode 100644 index 0000000..6355e13 Binary files /dev/null and b/static/events/deposits_11155111_dai_10000.json.zip differ diff --git a/static/events/deposits_11155111_dai_100000.json.zip b/static/events/deposits_11155111_dai_100000.json.zip new file mode 100644 index 0000000..4ef8f93 Binary files /dev/null and b/static/events/deposits_11155111_dai_100000.json.zip differ diff --git a/static/events/deposits_11155111_eth_0.1.json.zip b/static/events/deposits_11155111_eth_0.1.json.zip new file mode 100644 index 0000000..58cd7c8 Binary files /dev/null and b/static/events/deposits_11155111_eth_0.1.json.zip differ diff --git a/static/events/deposits_11155111_eth_1.json.zip b/static/events/deposits_11155111_eth_1.json.zip new file mode 100644 index 0000000..5f26ecc Binary files /dev/null and b/static/events/deposits_11155111_eth_1.json.zip differ diff --git a/static/events/deposits_11155111_eth_10.json.zip b/static/events/deposits_11155111_eth_10.json.zip new file mode 100644 index 0000000..d5208a1 Binary files /dev/null and b/static/events/deposits_11155111_eth_10.json.zip differ diff --git a/static/events/deposits_11155111_eth_100.json.zip b/static/events/deposits_11155111_eth_100.json.zip new file mode 100644 index 0000000..807e734 Binary files /dev/null and b/static/events/deposits_11155111_eth_100.json.zip differ diff --git a/static/events/deposits_137_matic_100.json.zip b/static/events/deposits_137_matic_100.json.zip new file mode 100644 index 0000000..207d119 Binary files /dev/null and b/static/events/deposits_137_matic_100.json.zip differ diff --git a/static/events/deposits_137_matic_1000.json.zip b/static/events/deposits_137_matic_1000.json.zip new file mode 100644 index 0000000..5a2aff2 Binary files /dev/null and b/static/events/deposits_137_matic_1000.json.zip differ diff --git a/static/events/deposits_137_matic_10000.json.zip b/static/events/deposits_137_matic_10000.json.zip new file mode 100644 index 0000000..f26ee31 Binary files /dev/null and b/static/events/deposits_137_matic_10000.json.zip differ diff --git a/static/events/deposits_137_matic_100000.json.zip b/static/events/deposits_137_matic_100000.json.zip new file mode 100644 index 0000000..b415691 Binary files /dev/null and b/static/events/deposits_137_matic_100000.json.zip differ diff --git a/static/events/deposits_1_cdai_5000.json.zip b/static/events/deposits_1_cdai_5000.json.zip new file mode 100644 index 0000000..f9d281f Binary files /dev/null and b/static/events/deposits_1_cdai_5000.json.zip differ diff --git a/static/events/deposits_1_cdai_50000.json.zip b/static/events/deposits_1_cdai_50000.json.zip new file mode 100644 index 0000000..c514138 Binary files /dev/null and b/static/events/deposits_1_cdai_50000.json.zip differ diff --git a/static/events/deposits_1_cdai_500000.json.zip b/static/events/deposits_1_cdai_500000.json.zip new file mode 100644 index 0000000..e603acf Binary files /dev/null and b/static/events/deposits_1_cdai_500000.json.zip differ diff --git a/static/events/deposits_1_cdai_5000000.json.zip b/static/events/deposits_1_cdai_5000000.json.zip new file mode 100644 index 0000000..a0c3a73 Binary files /dev/null and b/static/events/deposits_1_cdai_5000000.json.zip differ diff --git a/static/events/deposits_1_dai_100.json.zip b/static/events/deposits_1_dai_100.json.zip new file mode 100644 index 0000000..72518a1 Binary files /dev/null and b/static/events/deposits_1_dai_100.json.zip differ diff --git a/static/events/deposits_1_dai_1000.json.zip b/static/events/deposits_1_dai_1000.json.zip new file mode 100644 index 0000000..976c99b Binary files /dev/null and b/static/events/deposits_1_dai_1000.json.zip differ diff --git a/static/events/deposits_1_dai_10000.json.zip b/static/events/deposits_1_dai_10000.json.zip new file mode 100644 index 0000000..6b7d347 Binary files /dev/null and b/static/events/deposits_1_dai_10000.json.zip differ diff --git a/static/events/deposits_1_dai_100000.json.zip b/static/events/deposits_1_dai_100000.json.zip new file mode 100644 index 0000000..083db2f Binary files /dev/null and b/static/events/deposits_1_dai_100000.json.zip differ diff --git a/static/events/deposits_1_eth_0.1.json.zip b/static/events/deposits_1_eth_0.1.json.zip new file mode 100644 index 0000000..5273e55 Binary files /dev/null and b/static/events/deposits_1_eth_0.1.json.zip differ diff --git a/static/events/deposits_1_eth_1.json.zip b/static/events/deposits_1_eth_1.json.zip new file mode 100644 index 0000000..3cdc273 Binary files /dev/null and b/static/events/deposits_1_eth_1.json.zip differ diff --git a/static/events/deposits_1_eth_10.json.zip b/static/events/deposits_1_eth_10.json.zip new file mode 100644 index 0000000..40c0af7 Binary files /dev/null and b/static/events/deposits_1_eth_10.json.zip differ diff --git a/static/events/deposits_1_eth_100.json.zip b/static/events/deposits_1_eth_100.json.zip new file mode 100644 index 0000000..fe0ce83 Binary files /dev/null and b/static/events/deposits_1_eth_100.json.zip differ diff --git a/static/events/deposits_1_usdc_100.json.zip b/static/events/deposits_1_usdc_100.json.zip new file mode 100644 index 0000000..9f87d83 Binary files /dev/null and b/static/events/deposits_1_usdc_100.json.zip differ diff --git a/static/events/deposits_1_usdc_1000.json.zip b/static/events/deposits_1_usdc_1000.json.zip new file mode 100644 index 0000000..16b172b Binary files /dev/null and b/static/events/deposits_1_usdc_1000.json.zip differ diff --git a/static/events/deposits_1_usdt_100.json.zip b/static/events/deposits_1_usdt_100.json.zip new file mode 100644 index 0000000..54529b6 Binary files /dev/null and b/static/events/deposits_1_usdt_100.json.zip differ diff --git a/static/events/deposits_1_usdt_1000.json.zip b/static/events/deposits_1_usdt_1000.json.zip new file mode 100644 index 0000000..8978db9 Binary files /dev/null and b/static/events/deposits_1_usdt_1000.json.zip differ diff --git a/static/events/deposits_1_wbtc_0.1.json.zip b/static/events/deposits_1_wbtc_0.1.json.zip new file mode 100644 index 0000000..fcaaf3b Binary files /dev/null and b/static/events/deposits_1_wbtc_0.1.json.zip differ diff --git a/static/events/deposits_1_wbtc_1.json.zip b/static/events/deposits_1_wbtc_1.json.zip new file mode 100644 index 0000000..49df00e Binary files /dev/null and b/static/events/deposits_1_wbtc_1.json.zip differ diff --git a/static/events/deposits_1_wbtc_10.json.zip b/static/events/deposits_1_wbtc_10.json.zip new file mode 100644 index 0000000..67b2fbc Binary files /dev/null and b/static/events/deposits_1_wbtc_10.json.zip differ diff --git a/static/events/deposits_42161_eth_0.1.json.zip b/static/events/deposits_42161_eth_0.1.json.zip new file mode 100644 index 0000000..c0bbaa8 Binary files /dev/null and b/static/events/deposits_42161_eth_0.1.json.zip differ diff --git a/static/events/deposits_42161_eth_1.json.zip b/static/events/deposits_42161_eth_1.json.zip new file mode 100644 index 0000000..50a7457 Binary files /dev/null and b/static/events/deposits_42161_eth_1.json.zip differ diff --git a/static/events/deposits_42161_eth_10.json.zip b/static/events/deposits_42161_eth_10.json.zip new file mode 100644 index 0000000..4a90a22 Binary files /dev/null and b/static/events/deposits_42161_eth_10.json.zip differ diff --git a/static/events/deposits_42161_eth_100.json.zip b/static/events/deposits_42161_eth_100.json.zip new file mode 100644 index 0000000..ce1810d Binary files /dev/null and b/static/events/deposits_42161_eth_100.json.zip differ diff --git a/static/events/deposits_43114_avax_10.json.zip b/static/events/deposits_43114_avax_10.json.zip new file mode 100644 index 0000000..3d61d80 Binary files /dev/null and b/static/events/deposits_43114_avax_10.json.zip differ diff --git a/static/events/deposits_43114_avax_100.json.zip b/static/events/deposits_43114_avax_100.json.zip new file mode 100644 index 0000000..26ea41f Binary files /dev/null and b/static/events/deposits_43114_avax_100.json.zip differ diff --git a/static/events/deposits_43114_avax_500.json.zip b/static/events/deposits_43114_avax_500.json.zip new file mode 100644 index 0000000..b8081e1 Binary files /dev/null and b/static/events/deposits_43114_avax_500.json.zip differ diff --git a/static/events/deposits_56_bnb_0.1.json.zip b/static/events/deposits_56_bnb_0.1.json.zip new file mode 100644 index 0000000..48a958e Binary files /dev/null and b/static/events/deposits_56_bnb_0.1.json.zip differ diff --git a/static/events/deposits_56_bnb_1.json.zip b/static/events/deposits_56_bnb_1.json.zip new file mode 100644 index 0000000..253c181 Binary files /dev/null and b/static/events/deposits_56_bnb_1.json.zip differ diff --git a/static/events/deposits_56_bnb_10.json.zip b/static/events/deposits_56_bnb_10.json.zip new file mode 100644 index 0000000..fa47c02 Binary files /dev/null and b/static/events/deposits_56_bnb_10.json.zip differ diff --git a/static/events/deposits_56_bnb_100.json.zip b/static/events/deposits_56_bnb_100.json.zip new file mode 100644 index 0000000..5aa5351 Binary files /dev/null and b/static/events/deposits_56_bnb_100.json.zip differ diff --git a/static/events/echo_1.json.zip b/static/events/echo_1.json.zip new file mode 100644 index 0000000..fc99d19 Binary files /dev/null and b/static/events/echo_1.json.zip differ diff --git a/static/events/echo_10.json.zip b/static/events/echo_10.json.zip new file mode 100644 index 0000000..675a45c Binary files /dev/null and b/static/events/echo_10.json.zip differ diff --git a/static/events/echo_100.json.zip b/static/events/echo_100.json.zip new file mode 100644 index 0000000..89d5c40 Binary files /dev/null and b/static/events/echo_100.json.zip differ diff --git a/static/events/echo_11155111.json.zip b/static/events/echo_11155111.json.zip new file mode 100644 index 0000000..ee1251d Binary files /dev/null and b/static/events/echo_11155111.json.zip differ diff --git a/static/events/echo_137.json.zip b/static/events/echo_137.json.zip new file mode 100644 index 0000000..75aa965 Binary files /dev/null and b/static/events/echo_137.json.zip differ diff --git a/static/events/echo_42161.json.zip b/static/events/echo_42161.json.zip new file mode 100644 index 0000000..bb688ec Binary files /dev/null and b/static/events/echo_42161.json.zip differ diff --git a/static/events/echo_43114.json.zip b/static/events/echo_43114.json.zip new file mode 100644 index 0000000..939d3b4 Binary files /dev/null and b/static/events/echo_43114.json.zip differ diff --git a/static/events/echo_56.json.zip b/static/events/echo_56.json.zip new file mode 100644 index 0000000..683b716 Binary files /dev/null and b/static/events/echo_56.json.zip differ diff --git a/static/events/encrypted_notes_1.json.zip b/static/events/encrypted_notes_1.json.zip new file mode 100644 index 0000000..6bbb0e0 Binary files /dev/null and b/static/events/encrypted_notes_1.json.zip differ diff --git a/static/events/encrypted_notes_10.json.zip b/static/events/encrypted_notes_10.json.zip new file mode 100644 index 0000000..fd107a1 Binary files /dev/null and b/static/events/encrypted_notes_10.json.zip differ diff --git a/static/events/encrypted_notes_100.json.zip b/static/events/encrypted_notes_100.json.zip new file mode 100644 index 0000000..64daa1d Binary files /dev/null and b/static/events/encrypted_notes_100.json.zip differ diff --git a/static/events/encrypted_notes_11155111.json.zip b/static/events/encrypted_notes_11155111.json.zip new file mode 100644 index 0000000..454f9ff Binary files /dev/null and b/static/events/encrypted_notes_11155111.json.zip differ diff --git a/static/events/encrypted_notes_137.json.zip b/static/events/encrypted_notes_137.json.zip new file mode 100644 index 0000000..46e840d Binary files /dev/null and b/static/events/encrypted_notes_137.json.zip differ diff --git a/static/events/encrypted_notes_42161.json.zip b/static/events/encrypted_notes_42161.json.zip new file mode 100644 index 0000000..9abc870 Binary files /dev/null and b/static/events/encrypted_notes_42161.json.zip differ diff --git a/static/events/encrypted_notes_43114.json.zip b/static/events/encrypted_notes_43114.json.zip new file mode 100644 index 0000000..e8e2ca0 Binary files /dev/null and b/static/events/encrypted_notes_43114.json.zip differ diff --git a/static/events/encrypted_notes_56.json.zip b/static/events/encrypted_notes_56.json.zip new file mode 100644 index 0000000..62d1150 Binary files /dev/null and b/static/events/encrypted_notes_56.json.zip differ diff --git a/static/events/governance_1.json.zip b/static/events/governance_1.json.zip new file mode 100644 index 0000000..5a06596 Binary files /dev/null and b/static/events/governance_1.json.zip differ diff --git a/static/events/governance_11155111.json.zip b/static/events/governance_11155111.json.zip new file mode 100644 index 0000000..979b93a Binary files /dev/null and b/static/events/governance_11155111.json.zip differ diff --git a/static/events/registered_1.json.zip b/static/events/registered_1.json.zip new file mode 100644 index 0000000..b5191d2 Binary files /dev/null and b/static/events/registered_1.json.zip differ diff --git a/static/events/registered_11155111.json.zip b/static/events/registered_11155111.json.zip new file mode 100644 index 0000000..b2416c1 Binary files /dev/null and b/static/events/registered_11155111.json.zip differ diff --git a/static/events/registry_1.json.zip b/static/events/registry_1.json.zip new file mode 100644 index 0000000..52b4992 Binary files /dev/null and b/static/events/registry_1.json.zip differ diff --git a/static/events/registry_11155111.json.zip b/static/events/registry_11155111.json.zip new file mode 100644 index 0000000..8d6410b Binary files /dev/null and b/static/events/registry_11155111.json.zip differ diff --git a/static/events/relayers.json b/static/events/relayers.json new file mode 100644 index 0000000..a5173ba --- /dev/null +++ b/static/events/relayers.json @@ -0,0 +1,384 @@ +{ + "lastBlock": 20874000, + "timestamp": 1727826179, + "relayers": [ + { + "ensName": "tornadowithdraw.eth", + "relayerAddress": "0x40c3d1656a26C9266f4A10fed0D87EFf79F54E64", + "hostnames": {}, + "tovarishHost": "tornadowithdraw.com", + "tovarishNetworks": [ + 1, + 56, + 137, + 10, + 42161, + 100, + 43114, + 11155111 + ] + }, + { + "ensName": "therelayer.eth", + "relayerAddress": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1", + "isRegistered": true, + "owner": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1", + "stakeBalance": "1335.888771359625809238", + "hostnames": { + "1": "mainnet.therelayer.xyz", + "10": "optimism.therelayer.xyz", + "56": "bsc.therelayer.xyz", + "100": "xdai.therelayer.xyz", + "137": "polygon.therelayer.xyz", + "42161": "arbitrum.therelayer.xyz", + "43114": "avalanche.therelayer.xyz" + } + }, + { + "ensName": "cheap-relayer.eth", + "relayerAddress": "0x076D4E32C6A5D888fC4658281539c94E778C796d", + "isRegistered": true, + "owner": "0x076D4E32C6A5D888fC4658281539c94E778C796d", + "stakeBalance": "500.878420081833044818", + "hostnames": { + "1": "mainnet-tornado.cheap-relayer.xyz", + "56": "bsc-tornado.cheap-relayer.xyz", + "137": "polygon-tornado.cheap-relayer.xyz", + "43114": "avalanche-tornado.cheap-relayer.xyz" + } + }, + { + "ensName": "lowcost.eth", + "relayerAddress": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d", + "isRegistered": true, + "owner": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d", + "stakeBalance": "500.279638085962965981", + "hostnames": { + "1": "mainnet-tornado.low-fee.xyz", + "56": "bsc-tornado.low-fee.xyz", + "137": "polygon-tornado.low-fee.xyz", + "43114": "avalanche-tornado.low-fee.xyz" + } + }, + { + "ensName": "relayernews.eth", + "relayerAddress": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70", + "isRegistered": true, + "owner": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70", + "stakeBalance": "1661.181918638614466424", + "hostnames": { + "1": "mainnet-tornado.relayernews.xyz", + "56": "bsc-tornado.relayernews.xyz" + } + }, + { + "ensName": "on-sale.eth", + "relayerAddress": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E", + "isRegistered": true, + "owner": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E", + "stakeBalance": "4476.543684932880020592", + "hostnames": { + "1": "mainnet-tornado.appleworld.club", + "56": "bsc-tornado.appleworld.club" + } + }, + { + "ensName": "em3tornado.eth", + "relayerAddress": "0x3a1d526D09b7E59Fd88De4726f68A8246dDC2742", + "isRegistered": true, + "owner": "0x3a1d526D09b7E59Fd88De4726f68A8246dDC2742", + "stakeBalance": "16864.242955629118561145", + "hostnames": { + "1": "em3torn.com", + "10": "optimism.em3torn.com", + "56": "bsc.em3torn.com", + "137": "polygon.em3torn.com", + "42161": "arbitrum.em3torn.com", + "43114": "avax.em3torn.com" + } + }, + { + "ensName": "reslayer.eth", + "relayerAddress": "0x7Ba6781620c91676B070D319E7E894BFd4A9eC81", + "isRegistered": true, + "owner": "0x7Ba6781620c91676B070D319E7E894BFd4A9eC81", + "stakeBalance": "879.305690438201312145", + "hostnames": { + "1": "mainnet-tornado.reslayer.xyz", + "56": "bsc-tornado.reslayer.xyz", + "100": "gnosis-tornado.reslayer.xyz", + "137": "polygon-tornado.reslayer.xyz", + "42161": "arbitrum-tornado.reslayer.xyz", + "43114": "avalanche-tornado.reslayer.xyz" + } + }, + { + "ensName": "0xtorn.eth", + "relayerAddress": "0x9Ffbd3f9eE795A4fDa880ED553A2A4BD6D45CE5B", + "isRegistered": true, + "owner": "0x9Ffbd3f9eE795A4fDa880ED553A2A4BD6D45CE5B", + "stakeBalance": "4627.036617270139345308", + "hostnames": { + "1": "mainnet.al1n.cc", + "56": "bsc-tornado.al1n.cc" + } + }, + { + "ensName": "wetez.eth", + "relayerAddress": "0xe6184DA55174Cc0263a17eA2fc24E48511766505", + "isRegistered": true, + "owner": "0xe6184DA55174Cc0263a17eA2fc24E48511766505", + "stakeBalance": "567.980734786905511868", + "hostnames": { + "1": "tornado-1.wetez.io" + } + }, + { + "ensName": "0xproxy.eth", + "relayerAddress": "0x08657a1f4C1F06d657F31767831421EE7FaDf549", + "isRegistered": true, + "owner": "0x08657a1f4C1F06d657F31767831421EE7FaDf549", + "stakeBalance": "705.605817336537209483", + "hostnames": { + "1": "mainnet.0x0relayer.xyz", + "56": "bsc.0x0relayer.xyz", + "137": "polygon.0x0relayer.xyz" + } + }, + { + "ensName": "torn-eth.eth", + "relayerAddress": "0x42FecB4137aFF76E0E85702ff4F339DbFe6D859E", + "isRegistered": true, + "owner": "0x42FecB4137aFF76E0E85702ff4F339DbFe6D859E", + "stakeBalance": "978.62598484549460861", + "hostnames": { + "1": "mainnet-tornado.50swap.com" + } + }, + { + "ensName": "shadow-out.eth", + "relayerAddress": "0x9Ee26a4bFd731E8e742B65bF955814EADdd7F151", + "isRegistered": true, + "owner": "0x9Ee26a4bFd731E8e742B65bF955814EADdd7F151", + "stakeBalance": "3571.639136672079169166", + "hostnames": { + "1": "livetobecomeavillain", + "56": "justarandomdude", + "100": "everythingisburning" + } + }, + { + "ensName": "bitah.eth", + "relayerAddress": "0x7E3893725d4e238B4c8c83375bBAd024a66Ffa42", + "isRegistered": true, + "owner": "0x7E3893725d4e238B4c8c83375bBAd024a66Ffa42", + "stakeBalance": "503.237718892072788154", + "hostnames": { + "1": "tornado.bitah.link", + "56": "bsc-tornado.bitah.link", + "137": "polygon-tornado.bitah.link" + } + }, + { + "ensName": "torntorn.eth", + "relayerAddress": "0x1247749d7E28D357B4279110af0802603AC526cE", + "isRegistered": true, + "owner": "0x1247749d7E28D357B4279110af0802603AC526cE", + "stakeBalance": "5535.435044583932530913", + "hostnames": { + "1": "eth.fsdhreu39jfk.com", + "56": "bsc.fsdhreu39jfk.com", + "100": "gnosis.tornad0.com", + "137": "polygon.tornad0.com" + } + }, + { + "ensName": "secure-relay.eth", + "relayerAddress": "0x1036AF02bCDb2e3A4db2d3D40b29e5054EDc79BA", + "isRegistered": true, + "owner": "0x1036AF02bCDb2e3A4db2d3D40b29e5054EDc79BA", + "stakeBalance": "6751.661507930994067422", + "hostnames": { + "1": "torn-relayer.duckdns.org" + } + }, + { + "ensName": "relayer007.eth", + "relayerAddress": "0xa0109274F53609f6Be97ec5f3052C659AB80f012", + "isRegistered": true, + "owner": "0xa0109274F53609f6Be97ec5f3052C659AB80f012", + "stakeBalance": "2075.677151387681021207", + "hostnames": { + "1": "torn.relayersdao.finance", + "56": "bsc.relayersdao.finance", + "137": "matic.relayersdao.finance" + } + }, + { + "ensName": "reltor.eth", + "relayerAddress": "0x4750BCfcC340AA4B31be7e71fa072716d28c29C5", + "isRegistered": true, + "owner": "0x4750BCfcC340AA4B31be7e71fa072716d28c29C5", + "stakeBalance": "17078.896444585792890283", + "hostnames": { + "1": "eth.reltor.su", + "56": "binance.reltor.su", + "137": "polygon.reltor.su" + } + }, + { + "ensName": "t-relayer.eth", + "relayerAddress": "0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe", + "isRegistered": true, + "owner": "0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe", + "stakeBalance": "9393.81613250700489948", + "hostnames": { + "1": "eth.t-relayer.com", + "56": "bsc.t-relayer.com" + } + }, + { + "ensName": "default-relayer.eth", + "relayerAddress": "0x5555555731006f71f121144534Ca7C8799F66AA3", + "isRegistered": true, + "owner": "0x5555555731006f71f121144534Ca7C8799F66AA3", + "stakeBalance": "12244.203047120053584442", + "hostnames": { + "1": "eth.default-relayer.com", + "56": "bsc.default-relayer.com" + } + }, + { + "ensName": "relayer-secure.eth", + "relayerAddress": "0xCEdac436cEA98E93F471331eCC693fF41D730921", + "isRegistered": true, + "owner": "0xCEdac436cEA98E93F471331eCC693fF41D730921", + "stakeBalance": "548.198082306127582623", + "hostnames": { + "1": "relsecc-mainnet.moon-relayer.app" + } + }, + { + "ensName": "0xgm777.eth", + "relayerAddress": "0x94596B6A626392F5D972D6CC4D929a42c2f0008c", + "isRegistered": true, + "owner": "0x94596B6A626392F5D972D6CC4D929a42c2f0008c", + "stakeBalance": "1649.22629774180421325", + "hostnames": { + "1": "main.gm777.xyz", + "56": "bsc.gm777.xyz", + "42161": "arb.gm777.xyz" + } + }, + { + "ensName": "k-relayer.eth", + "relayerAddress": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c", + "isRegistered": true, + "owner": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c", + "stakeBalance": "2392.026618435010858225", + "hostnames": { + "1": "black-hardy.com", + "56": "bsc.black-hardy.com" + } + }, + { + "ensName": "tornxdo.eth", + "relayerAddress": "0xB399aa4c2F1678f72529Cd125F82cEA2c2a823eD", + "isRegistered": true, + "owner": "0xB399aa4c2F1678f72529Cd125F82cEA2c2a823eD", + "stakeBalance": "983.310689667160962345", + "hostnames": { + "1": "tornado.evmjunkie.xyz" + } + }, + { + "ensName": "torrelayer.eth", + "relayerAddress": "0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C", + "isRegistered": true, + "owner": "0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C", + "stakeBalance": "4150.327987173762878437", + "hostnames": { + "1": "tornima.xyz", + "56": "binance.tornima.xyz" + } + }, + { + "ensName": "torn-city.eth", + "relayerAddress": "0xd04e9f0945DEA8373D882C730e2c93a74B591796", + "isRegistered": true, + "owner": "0xd04e9f0945DEA8373D882C730e2c93a74B591796", + "stakeBalance": "6636.564618899564311691", + "hostnames": { + "1": "torn-city.com", + "56": "bsc.torn-city.com" + } + }, + { + "ensName": "crelayer.eth", + "relayerAddress": "0x180c58B7305152357142b33Eea94cBB152058B61", + "isRegistered": true, + "owner": "0x180c58B7305152357142b33Eea94cBB152058B61", + "stakeBalance": "1460.389956347917729137", + "hostnames": { + "1": "eth.crelayer.xyz", + "56": "bsc.crelayer.xyz" + } + }, + { + "ensName": "best-relay.eth", + "relayerAddress": "0xe5A4c70113b90566BC5f80a3866935d0d52F990E", + "isRegistered": true, + "owner": "0xe5A4c70113b90566BC5f80a3866935d0d52F990E", + "stakeBalance": "2002.0", + "hostnames": { + "1": "best-relay.gato-miaouw.xyz", + "56": "bsc.gato-miaouw.xyz" + } + }, + { + "ensName": "safety-relayer.eth", + "relayerAddress": "0xF1F4F76c9969eFbFB5C9A90a6E44c0E3696D3EF8", + "isRegistered": true, + "owner": "0xF1F4F76c9969eFbFB5C9A90a6E44c0E3696D3EF8", + "stakeBalance": "500.879215977529089999", + "hostnames": { + "1": "a-relayer.top", + "56": "bsc.a-relayer.top", + "137": "polygon.a-relayer.top" + } + }, + { + "ensName": "quick-relayer.eth", + "relayerAddress": "0x187541D7D312F742040f270d0221B4Fe577934B0", + "isRegistered": true, + "owner": "0x187541D7D312F742040f270d0221B4Fe577934B0", + "stakeBalance": "2931.033250737658918569", + "hostnames": { + "1": "quick-relayer.xyz" + } + }, + { + "ensName": "okrelayer.eth", + "relayerAddress": "0x0e9D9a828247F5eed7f6D31D213A39805De52441", + "isRegistered": true, + "owner": "0x0e9D9a828247F5eed7f6D31D213A39805De52441", + "stakeBalance": "4668.726167448982243314", + "hostnames": { + "1": "okrelayer.xyz", + "56": "binance.okrelayer.xyz", + "137": "polygon.okrelayer.xyz", + "42161": "arb.okrelayer.xyz" + } + }, + { + "ensName": "s-relayer.eth", + "relayerAddress": "0xc6398b4e8B60720051ed33f5C5a692f9785f5580", + "isRegistered": true, + "owner": "0xc6398b4e8B60720051ed33f5C5a692f9785f5580", + "stakeBalance": "5000.0", + "hostnames": { + "1": "s-relayer.xyz" + } + } + ] +} diff --git a/static/events/relayers.json.zip b/static/events/relayers.json.zip new file mode 100644 index 0000000..8c9dc53 Binary files /dev/null and b/static/events/relayers.json.zip differ diff --git a/static/events/revenue_1.json.zip b/static/events/revenue_1.json.zip new file mode 100644 index 0000000..300eeac Binary files /dev/null and b/static/events/revenue_1.json.zip differ diff --git a/static/events/revenue_11155111.json.zip b/static/events/revenue_11155111.json.zip new file mode 100644 index 0000000..8407d51 Binary files /dev/null and b/static/events/revenue_11155111.json.zip differ diff --git a/static/events/withdrawals_100_xdai_100.json.zip b/static/events/withdrawals_100_xdai_100.json.zip new file mode 100644 index 0000000..1db156f Binary files /dev/null and b/static/events/withdrawals_100_xdai_100.json.zip differ diff --git a/static/events/withdrawals_100_xdai_1000.json.zip b/static/events/withdrawals_100_xdai_1000.json.zip new file mode 100644 index 0000000..ae6c1c0 Binary files /dev/null and b/static/events/withdrawals_100_xdai_1000.json.zip differ diff --git a/static/events/withdrawals_100_xdai_10000.json.zip b/static/events/withdrawals_100_xdai_10000.json.zip new file mode 100644 index 0000000..1f2b1b9 Binary files /dev/null and b/static/events/withdrawals_100_xdai_10000.json.zip differ diff --git a/static/events/withdrawals_100_xdai_100000.json.zip b/static/events/withdrawals_100_xdai_100000.json.zip new file mode 100644 index 0000000..1c6609b Binary files /dev/null and b/static/events/withdrawals_100_xdai_100000.json.zip differ diff --git a/static/events/withdrawals_10_eth_0.1.json.zip b/static/events/withdrawals_10_eth_0.1.json.zip new file mode 100644 index 0000000..9fb0fb1 Binary files /dev/null and b/static/events/withdrawals_10_eth_0.1.json.zip differ diff --git a/static/events/withdrawals_10_eth_1.json.zip b/static/events/withdrawals_10_eth_1.json.zip new file mode 100644 index 0000000..40418b1 Binary files /dev/null and b/static/events/withdrawals_10_eth_1.json.zip differ diff --git a/static/events/withdrawals_10_eth_10.json.zip b/static/events/withdrawals_10_eth_10.json.zip new file mode 100644 index 0000000..8b4ade6 Binary files /dev/null and b/static/events/withdrawals_10_eth_10.json.zip differ diff --git a/static/events/withdrawals_10_eth_100.json.zip b/static/events/withdrawals_10_eth_100.json.zip new file mode 100644 index 0000000..a9e8041 Binary files /dev/null and b/static/events/withdrawals_10_eth_100.json.zip differ diff --git a/static/events/withdrawals_11155111_dai_100.json.zip b/static/events/withdrawals_11155111_dai_100.json.zip new file mode 100644 index 0000000..c5a61c7 Binary files /dev/null and b/static/events/withdrawals_11155111_dai_100.json.zip differ diff --git a/static/events/withdrawals_11155111_dai_1000.json.zip b/static/events/withdrawals_11155111_dai_1000.json.zip new file mode 100644 index 0000000..c8822cb Binary files /dev/null and b/static/events/withdrawals_11155111_dai_1000.json.zip differ diff --git a/static/events/withdrawals_11155111_dai_10000.json.zip b/static/events/withdrawals_11155111_dai_10000.json.zip new file mode 100644 index 0000000..de16c6d Binary files /dev/null and b/static/events/withdrawals_11155111_dai_10000.json.zip differ diff --git a/static/events/withdrawals_11155111_dai_100000.json.zip b/static/events/withdrawals_11155111_dai_100000.json.zip new file mode 100644 index 0000000..ff43a64 Binary files /dev/null and b/static/events/withdrawals_11155111_dai_100000.json.zip differ diff --git a/static/events/withdrawals_11155111_eth_0.1.json.zip b/static/events/withdrawals_11155111_eth_0.1.json.zip new file mode 100644 index 0000000..ad8d199 Binary files /dev/null and b/static/events/withdrawals_11155111_eth_0.1.json.zip differ diff --git a/static/events/withdrawals_11155111_eth_1.json.zip b/static/events/withdrawals_11155111_eth_1.json.zip new file mode 100644 index 0000000..205b8ca Binary files /dev/null and b/static/events/withdrawals_11155111_eth_1.json.zip differ diff --git a/static/events/withdrawals_11155111_eth_10.json.zip b/static/events/withdrawals_11155111_eth_10.json.zip new file mode 100644 index 0000000..95a1b77 Binary files /dev/null and b/static/events/withdrawals_11155111_eth_10.json.zip differ diff --git a/static/events/withdrawals_11155111_eth_100.json.zip b/static/events/withdrawals_11155111_eth_100.json.zip new file mode 100644 index 0000000..4bf3205 Binary files /dev/null and b/static/events/withdrawals_11155111_eth_100.json.zip differ diff --git a/static/events/withdrawals_137_matic_100.json.zip b/static/events/withdrawals_137_matic_100.json.zip new file mode 100644 index 0000000..3b7027c Binary files /dev/null and b/static/events/withdrawals_137_matic_100.json.zip differ diff --git a/static/events/withdrawals_137_matic_1000.json.zip b/static/events/withdrawals_137_matic_1000.json.zip new file mode 100644 index 0000000..c7cf2bb Binary files /dev/null and b/static/events/withdrawals_137_matic_1000.json.zip differ diff --git a/static/events/withdrawals_137_matic_10000.json.zip b/static/events/withdrawals_137_matic_10000.json.zip new file mode 100644 index 0000000..356255a Binary files /dev/null and b/static/events/withdrawals_137_matic_10000.json.zip differ diff --git a/static/events/withdrawals_137_matic_100000.json.zip b/static/events/withdrawals_137_matic_100000.json.zip new file mode 100644 index 0000000..5a58d01 Binary files /dev/null and b/static/events/withdrawals_137_matic_100000.json.zip differ diff --git a/static/events/withdrawals_1_cdai_5000.json.zip b/static/events/withdrawals_1_cdai_5000.json.zip new file mode 100644 index 0000000..9986ef9 Binary files /dev/null and b/static/events/withdrawals_1_cdai_5000.json.zip differ diff --git a/static/events/withdrawals_1_cdai_50000.json.zip b/static/events/withdrawals_1_cdai_50000.json.zip new file mode 100644 index 0000000..b241a39 Binary files /dev/null and b/static/events/withdrawals_1_cdai_50000.json.zip differ diff --git a/static/events/withdrawals_1_cdai_500000.json.zip b/static/events/withdrawals_1_cdai_500000.json.zip new file mode 100644 index 0000000..be6a21e Binary files /dev/null and b/static/events/withdrawals_1_cdai_500000.json.zip differ diff --git a/static/events/withdrawals_1_cdai_5000000.json.zip b/static/events/withdrawals_1_cdai_5000000.json.zip new file mode 100644 index 0000000..ce80440 Binary files /dev/null and b/static/events/withdrawals_1_cdai_5000000.json.zip differ diff --git a/static/events/withdrawals_1_dai_100.json.zip b/static/events/withdrawals_1_dai_100.json.zip new file mode 100644 index 0000000..3ad8e1c Binary files /dev/null and b/static/events/withdrawals_1_dai_100.json.zip differ diff --git a/static/events/withdrawals_1_dai_1000.json.zip b/static/events/withdrawals_1_dai_1000.json.zip new file mode 100644 index 0000000..35242b4 Binary files /dev/null and b/static/events/withdrawals_1_dai_1000.json.zip differ diff --git a/static/events/withdrawals_1_dai_10000.json.zip b/static/events/withdrawals_1_dai_10000.json.zip new file mode 100644 index 0000000..acc6a65 Binary files /dev/null and b/static/events/withdrawals_1_dai_10000.json.zip differ diff --git a/static/events/withdrawals_1_dai_100000.json.zip b/static/events/withdrawals_1_dai_100000.json.zip new file mode 100644 index 0000000..53065c0 Binary files /dev/null and b/static/events/withdrawals_1_dai_100000.json.zip differ diff --git a/static/events/withdrawals_1_eth_0.1.json.zip b/static/events/withdrawals_1_eth_0.1.json.zip new file mode 100644 index 0000000..abb4c23 Binary files /dev/null and b/static/events/withdrawals_1_eth_0.1.json.zip differ diff --git a/static/events/withdrawals_1_eth_1.json.zip b/static/events/withdrawals_1_eth_1.json.zip new file mode 100644 index 0000000..5a7eedb Binary files /dev/null and b/static/events/withdrawals_1_eth_1.json.zip differ diff --git a/static/events/withdrawals_1_eth_10.json.zip b/static/events/withdrawals_1_eth_10.json.zip new file mode 100644 index 0000000..8493ef9 Binary files /dev/null and b/static/events/withdrawals_1_eth_10.json.zip differ diff --git a/static/events/withdrawals_1_eth_100.json.zip b/static/events/withdrawals_1_eth_100.json.zip new file mode 100644 index 0000000..2b1b576 Binary files /dev/null and b/static/events/withdrawals_1_eth_100.json.zip differ diff --git a/static/events/withdrawals_1_usdc_100.json.zip b/static/events/withdrawals_1_usdc_100.json.zip new file mode 100644 index 0000000..1a49183 Binary files /dev/null and b/static/events/withdrawals_1_usdc_100.json.zip differ diff --git a/static/events/withdrawals_1_usdc_1000.json.zip b/static/events/withdrawals_1_usdc_1000.json.zip new file mode 100644 index 0000000..dd453e4 Binary files /dev/null and b/static/events/withdrawals_1_usdc_1000.json.zip differ diff --git a/static/events/withdrawals_1_usdt_100.json.zip b/static/events/withdrawals_1_usdt_100.json.zip new file mode 100644 index 0000000..2e31e84 Binary files /dev/null and b/static/events/withdrawals_1_usdt_100.json.zip differ diff --git a/static/events/withdrawals_1_usdt_1000.json.zip b/static/events/withdrawals_1_usdt_1000.json.zip new file mode 100644 index 0000000..7ef49c9 Binary files /dev/null and b/static/events/withdrawals_1_usdt_1000.json.zip differ diff --git a/static/events/withdrawals_1_wbtc_0.1.json.zip b/static/events/withdrawals_1_wbtc_0.1.json.zip new file mode 100644 index 0000000..1ce31f4 Binary files /dev/null and b/static/events/withdrawals_1_wbtc_0.1.json.zip differ diff --git a/static/events/withdrawals_1_wbtc_1.json.zip b/static/events/withdrawals_1_wbtc_1.json.zip new file mode 100644 index 0000000..82e1d25 Binary files /dev/null and b/static/events/withdrawals_1_wbtc_1.json.zip differ diff --git a/static/events/withdrawals_1_wbtc_10.json.zip b/static/events/withdrawals_1_wbtc_10.json.zip new file mode 100644 index 0000000..36ce62a Binary files /dev/null and b/static/events/withdrawals_1_wbtc_10.json.zip differ diff --git a/static/events/withdrawals_42161_eth_0.1.json.zip b/static/events/withdrawals_42161_eth_0.1.json.zip new file mode 100644 index 0000000..178c42d Binary files /dev/null and b/static/events/withdrawals_42161_eth_0.1.json.zip differ diff --git a/static/events/withdrawals_42161_eth_1.json.zip b/static/events/withdrawals_42161_eth_1.json.zip new file mode 100644 index 0000000..298de78 Binary files /dev/null and b/static/events/withdrawals_42161_eth_1.json.zip differ diff --git a/static/events/withdrawals_42161_eth_10.json.zip b/static/events/withdrawals_42161_eth_10.json.zip new file mode 100644 index 0000000..9fe2d77 Binary files /dev/null and b/static/events/withdrawals_42161_eth_10.json.zip differ diff --git a/static/events/withdrawals_42161_eth_100.json.zip b/static/events/withdrawals_42161_eth_100.json.zip new file mode 100644 index 0000000..fa80b01 Binary files /dev/null and b/static/events/withdrawals_42161_eth_100.json.zip differ diff --git a/static/events/withdrawals_43114_avax_10.json.zip b/static/events/withdrawals_43114_avax_10.json.zip new file mode 100644 index 0000000..5733579 Binary files /dev/null and b/static/events/withdrawals_43114_avax_10.json.zip differ diff --git a/static/events/withdrawals_43114_avax_100.json.zip b/static/events/withdrawals_43114_avax_100.json.zip new file mode 100644 index 0000000..51d2866 Binary files /dev/null and b/static/events/withdrawals_43114_avax_100.json.zip differ diff --git a/static/events/withdrawals_43114_avax_500.json.zip b/static/events/withdrawals_43114_avax_500.json.zip new file mode 100644 index 0000000..f6b8282 Binary files /dev/null and b/static/events/withdrawals_43114_avax_500.json.zip differ diff --git a/static/events/withdrawals_56_bnb_0.1.json.zip b/static/events/withdrawals_56_bnb_0.1.json.zip new file mode 100644 index 0000000..d0736d2 Binary files /dev/null and b/static/events/withdrawals_56_bnb_0.1.json.zip differ diff --git a/static/events/withdrawals_56_bnb_1.json.zip b/static/events/withdrawals_56_bnb_1.json.zip new file mode 100644 index 0000000..31c045c Binary files /dev/null and b/static/events/withdrawals_56_bnb_1.json.zip differ diff --git a/static/events/withdrawals_56_bnb_10.json.zip b/static/events/withdrawals_56_bnb_10.json.zip new file mode 100644 index 0000000..5f887e2 Binary files /dev/null and b/static/events/withdrawals_56_bnb_10.json.zip differ diff --git a/static/events/withdrawals_56_bnb_100.json.zip b/static/events/withdrawals_56_bnb_100.json.zip new file mode 100644 index 0000000..f44f345 Binary files /dev/null and b/static/events/withdrawals_56_bnb_100.json.zip differ diff --git a/static/merkleTreeWorker.js b/static/merkleTreeWorker.js new file mode 100644 index 0000000..2d7356e --- /dev/null +++ b/static/merkleTreeWorker.js @@ -0,0 +1,1879 @@ +'use strict'; + +var workerThreads = require('worker_threads'); +var ffjavascript = require('ffjavascript'); + +var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +var lib = {}; + +var FixedMerkleTree = {}; + +var simpleHash = {}; + +var hasRequiredSimpleHash; + +function requireSimpleHash () { + if (hasRequiredSimpleHash) return simpleHash; + hasRequiredSimpleHash = 1; + Object.defineProperty(simpleHash, "__esModule", { value: true }); + simpleHash.simpleHash = void 0; + /*** + * This is insecure hash function, just for example only + * @param data + * @param seed + * @param hashLength + */ + function simpleHash$1(data, seed, hashLength = 40) { + const str = data.join(''); + let i, l, hval = seed !== null && seed !== void 0 ? seed : 0x811c9dcc5; + for (i = 0, l = str.length; i < l; i++) { + hval ^= str.charCodeAt(i); + hval += (hval << 1) + (hval << 4) + (hval << 6) + (hval << 8) + (hval << 24); + } + const hash = (hval >>> 0).toString(16); + return BigInt('0x' + hash.padEnd(hashLength - (hash.length - 1), '0')).toString(10); + } + simpleHash.simpleHash = simpleHash$1; + simpleHash.default = (left, right) => simpleHash$1([left, right]); + return simpleHash; +} + +var BaseTree = {}; + +var hasRequiredBaseTree; + +function requireBaseTree () { + if (hasRequiredBaseTree) return BaseTree; + hasRequiredBaseTree = 1; + Object.defineProperty(BaseTree, "__esModule", { value: true }); + BaseTree.BaseTree = void 0; + let BaseTree$1 = class BaseTree { + get capacity() { + return 2 ** this.levels; + } + get layers() { + return this._layers.slice(); + } + get zeros() { + return this._zeros.slice(); + } + get elements() { + return this._layers[0].slice(); + } + get root() { + var _a; + return (_a = this._layers[this.levels][0]) !== null && _a !== void 0 ? _a : this._zeros[this.levels]; + } + /** + * Find an element in the tree + * @param elements elements of tree + * @param element An element to find + * @param comparator A function that checks leaf value equality + * @param fromIndex The index to start the search at. If the index is greater than or equal to the array's length, -1 is returned + * @returns {number} Index if element is found, otherwise -1 + */ + static indexOf(elements, element, fromIndex, comparator) { + if (comparator) { + return elements.findIndex((el) => comparator(element, el)); + } + else { + return elements.indexOf(element, fromIndex); + } + } + /** + * Insert new element into the tree + * @param element Element to insert + */ + insert(element) { + if (this._layers[0].length >= this.capacity) { + throw new Error('Tree is full'); + } + this.update(this._layers[0].length, element); + } + /* + * Insert multiple elements into the tree. + * @param {Array} elements Elements to insert + */ + bulkInsert(elements) { + if (!elements.length) { + return; + } + if (this._layers[0].length + elements.length > this.capacity) { + throw new Error('Tree is full'); + } + // First we insert all elements except the last one + // updating only full subtree hashes (all layers where inserted element has odd index) + // the last element will update the full path to the root making the tree consistent again + for (let i = 0; i < elements.length - 1; i++) { + this._layers[0].push(elements[i]); + let level = 0; + let index = this._layers[0].length - 1; + while (index % 2 === 1) { + level++; + index >>= 1; + const left = this._layers[level - 1][index * 2]; + const right = this._layers[level - 1][index * 2 + 1]; + this._layers[level][index] = this._hashFn(left, right); + } + } + this.insert(elements[elements.length - 1]); + } + /** + * Change an element in the tree + * @param {number} index Index of element to change + * @param element Updated element value + */ + update(index, element) { + if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) { + throw new Error('Insert index out of bounds: ' + index); + } + this._layers[0][index] = element; + this._processUpdate(index); + } + /** + * Get merkle path to a leaf + * @param {number} index Leaf index to generate path for + * @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index + */ + path(index) { + if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) { + throw new Error('Index out of bounds: ' + index); + } + let elIndex = +index; + const pathElements = []; + const pathIndices = []; + const pathPositions = []; + for (let level = 0; level < this.levels; level++) { + pathIndices[level] = elIndex % 2; + const leafIndex = elIndex ^ 1; + if (leafIndex < this._layers[level].length) { + pathElements[level] = this._layers[level][leafIndex]; + pathPositions[level] = leafIndex; + } + else { + pathElements[level] = this._zeros[level]; + pathPositions[level] = 0; + } + elIndex >>= 1; + } + return { + pathElements, + pathIndices, + pathPositions, + pathRoot: this.root, + }; + } + _buildZeros() { + this._zeros = [this.zeroElement]; + for (let i = 1; i <= this.levels; i++) { + this._zeros[i] = this._hashFn(this._zeros[i - 1], this._zeros[i - 1]); + } + } + _processNodes(nodes, layerIndex) { + const length = nodes.length; + let currentLength = Math.ceil(length / 2); + const currentLayer = new Array(currentLength); + currentLength--; + const starFrom = length - ((length % 2) ^ 1); + let j = 0; + for (let i = starFrom; i >= 0; i -= 2) { + if (nodes[i - 1] === undefined) + break; + const left = nodes[i - 1]; + const right = (i === starFrom && length % 2 === 1) ? this._zeros[layerIndex - 1] : nodes[i]; + currentLayer[currentLength - j] = this._hashFn(left, right); + j++; + } + return currentLayer; + } + _processUpdate(index) { + for (let level = 1; level <= this.levels; level++) { + index >>= 1; + const left = this._layers[level - 1][index * 2]; + const right = index * 2 + 1 < this._layers[level - 1].length + ? this._layers[level - 1][index * 2 + 1] + : this._zeros[level - 1]; + this._layers[level][index] = this._hashFn(left, right); + } + } + }; + BaseTree.BaseTree = BaseTree$1; + return BaseTree; +} + +var hasRequiredFixedMerkleTree; + +function requireFixedMerkleTree () { + if (hasRequiredFixedMerkleTree) return FixedMerkleTree; + hasRequiredFixedMerkleTree = 1; + var __importDefault = (FixedMerkleTree && FixedMerkleTree.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; + }; + Object.defineProperty(FixedMerkleTree, "__esModule", { value: true }); + const simpleHash_1 = __importDefault(/*@__PURE__*/ requireSimpleHash()); + const BaseTree_1 = /*@__PURE__*/ requireBaseTree(); + class MerkleTree extends BaseTree_1.BaseTree { + constructor(levels, elements = [], { hashFunction = simpleHash_1.default, zeroElement = 0, } = {}) { + super(); + this.levels = levels; + if (elements.length > this.capacity) { + throw new Error('Tree is full'); + } + this._hashFn = hashFunction; + this.zeroElement = zeroElement; + this._layers = []; + const leaves = elements.slice(); + this._layers = [leaves]; + this._buildZeros(); + this._buildHashes(); + } + _buildHashes() { + for (let layerIndex = 1; layerIndex <= this.levels; layerIndex++) { + const nodes = this._layers[layerIndex - 1]; + this._layers[layerIndex] = this._processNodes(nodes, layerIndex); + } + } + /** + * Insert multiple elements into the tree. + * @param {Array} elements Elements to insert + */ + bulkInsert(elements) { + if (!elements.length) { + return; + } + if (this._layers[0].length + elements.length > this.capacity) { + throw new Error('Tree is full'); + } + // First we insert all elements except the last one + // updating only full subtree hashes (all layers where inserted element has odd index) + // the last element will update the full path to the root making the tree consistent again + for (let i = 0; i < elements.length - 1; i++) { + this._layers[0].push(elements[i]); + let level = 0; + let index = this._layers[0].length - 1; + while (index % 2 === 1) { + level++; + index >>= 1; + this._layers[level][index] = this._hashFn(this._layers[level - 1][index * 2], this._layers[level - 1][index * 2 + 1]); + } + } + this.insert(elements[elements.length - 1]); + } + indexOf(element, comparator) { + return BaseTree_1.BaseTree.indexOf(this._layers[0], element, 0, comparator); + } + proof(element) { + const index = this.indexOf(element); + return this.path(index); + } + getTreeEdge(edgeIndex) { + const edgeElement = this._layers[0][edgeIndex]; + if (edgeElement === undefined) { + throw new Error('Element not found'); + } + const edgePath = this.path(edgeIndex); + return { edgePath, edgeElement, edgeIndex, edgeElementsCount: this._layers[0].length }; + } + /** + * 🪓 + * @param count + */ + getTreeSlices(count = 4) { + const length = this._layers[0].length; + let size = Math.ceil(length / count); + if (size % 2) + size++; + const slices = []; + for (let i = 0; i < length; i += size) { + const edgeLeft = i; + const edgeRight = i + size; + slices.push({ edge: this.getTreeEdge(edgeLeft), elements: this.elements.slice(edgeLeft, edgeRight) }); + } + return slices; + } + /** + * Serialize entire tree state including intermediate layers into a plain object + * Deserializing it back will not require to recompute any hashes + * Elements are not converted to a plain type, this is responsibility of the caller + */ + serialize() { + return { + levels: this.levels, + _zeros: this._zeros, + _layers: this._layers, + }; + } + /** + * Deserialize data into a MerkleTree instance + * Make sure to provide the same hashFunction as was used in the source tree, + * otherwise the tree state will be invalid + */ + static deserialize(data, hashFunction) { + const instance = Object.assign(Object.create(this.prototype), data); + instance._hashFn = hashFunction || simpleHash_1.default; + instance.zeroElement = instance._zeros[0]; + return instance; + } + toString() { + return JSON.stringify(this.serialize()); + } + } + FixedMerkleTree.default = MerkleTree; + return FixedMerkleTree; +} + +var PartialMerkleTree = {}; + +var hasRequiredPartialMerkleTree; + +function requirePartialMerkleTree () { + if (hasRequiredPartialMerkleTree) return PartialMerkleTree; + hasRequiredPartialMerkleTree = 1; + var __importDefault = (PartialMerkleTree && PartialMerkleTree.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; + }; + Object.defineProperty(PartialMerkleTree, "__esModule", { value: true }); + PartialMerkleTree.PartialMerkleTree = void 0; + const simpleHash_1 = __importDefault(/*@__PURE__*/ requireSimpleHash()); + const BaseTree_1 = /*@__PURE__*/ requireBaseTree(); + let PartialMerkleTree$1 = class PartialMerkleTree extends BaseTree_1.BaseTree { + constructor(levels, { edgePath, edgeElement, edgeIndex, edgeElementsCount, }, leaves, { hashFunction, zeroElement } = {}) { + super(); + if (edgeIndex + leaves.length !== edgeElementsCount) + throw new Error('Invalid number of elements'); + this._edgeLeafProof = edgePath; + this._initialRoot = edgePath.pathRoot; + this.zeroElement = zeroElement !== null && zeroElement !== void 0 ? zeroElement : 0; + this._edgeLeaf = { data: edgeElement, index: edgeIndex }; + this._leavesAfterEdge = leaves; + this.levels = levels; + this._hashFn = hashFunction || simpleHash_1.default; + this._createProofMap(); + this._buildTree(); + } + get edgeIndex() { + return this._edgeLeaf.index; + } + get edgeElement() { + return this._edgeLeaf.data; + } + get edgeLeafProof() { + return this._edgeLeafProof; + } + _createProofMap() { + this._proofMap = this.edgeLeafProof.pathPositions.reduce((p, c, i) => { + p.set(i, [c, this.edgeLeafProof.pathElements[i]]); + return p; + }, new Map()); + this._proofMap.set(this.levels, [0, this.edgeLeafProof.pathRoot]); + } + _buildTree() { + const edgeLeafIndex = this._edgeLeaf.index; + this._leaves = Array(edgeLeafIndex).concat(this._leavesAfterEdge); + if (this._proofMap.has(0)) { + const [proofPos, proofEl] = this._proofMap.get(0); + this._leaves[proofPos] = proofEl; + } + this._layers = [this._leaves]; + this._buildZeros(); + this._buildHashes(); + } + _buildHashes() { + for (let layerIndex = 1; layerIndex <= this.levels; layerIndex++) { + const nodes = this._layers[layerIndex - 1]; + const currentLayer = this._processNodes(nodes, layerIndex); + if (this._proofMap.has(layerIndex)) { + const [proofPos, proofEl] = this._proofMap.get(layerIndex); + if (!currentLayer[proofPos]) + currentLayer[proofPos] = proofEl; + } + this._layers[layerIndex] = currentLayer; + } + } + /** + * Change an element in the tree + * @param {number} index Index of element to change + * @param element Updated element value + */ + update(index, element) { + if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) { + throw new Error('Insert index out of bounds: ' + index); + } + if (index < this._edgeLeaf.index) { + throw new Error(`Index ${index} is below the edge: ${this._edgeLeaf.index}`); + } + this._layers[0][index] = element; + this._processUpdate(index); + } + path(index) { + var _a; + if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) { + throw new Error('Index out of bounds: ' + index); + } + if (index < this._edgeLeaf.index) { + throw new Error(`Index ${index} is below the edge: ${this._edgeLeaf.index}`); + } + let elIndex = Number(index); + const pathElements = []; + const pathIndices = []; + const pathPositions = []; + for (let level = 0; level < this.levels; level++) { + pathIndices[level] = elIndex % 2; + const leafIndex = elIndex ^ 1; + if (leafIndex < this._layers[level].length) { + pathElements[level] = this._layers[level][leafIndex]; + pathPositions[level] = leafIndex; + } + else { + pathElements[level] = this._zeros[level]; + pathPositions[level] = 0; + } + const [proofPos, proofEl] = this._proofMap.get(level); + pathElements[level] = (_a = pathElements[level]) !== null && _a !== void 0 ? _a : (proofPos === leafIndex ? proofEl : this._zeros[level]); + elIndex >>= 1; + } + return { + pathElements, + pathIndices, + pathPositions, + pathRoot: this.root, + }; + } + indexOf(element, comparator) { + return BaseTree_1.BaseTree.indexOf(this._layers[0], element, this.edgeIndex, comparator); + } + proof(element) { + const index = this.indexOf(element); + return this.path(index); + } + /** + * Shifts edge of tree to left + * @param edge new TreeEdge below current edge + * @param elements leaves between old and new edge + */ + shiftEdge(edge, elements) { + if (this._edgeLeaf.index <= edge.edgeIndex) { + throw new Error(`New edgeIndex should be smaller then ${this._edgeLeaf.index}`); + } + if (elements.length !== (this._edgeLeaf.index - edge.edgeIndex)) { + throw new Error(`Elements length should be ${this._edgeLeaf.index - edge.edgeIndex}`); + } + this._edgeLeafProof = edge.edgePath; + this._edgeLeaf = { index: edge.edgeIndex, data: edge.edgeElement }; + this._leavesAfterEdge = [...elements, ...this._leavesAfterEdge]; + this._createProofMap(); + this._buildTree(); + } + serialize() { + return { + _edgeLeafProof: this._edgeLeafProof, + _edgeLeaf: this._edgeLeaf, + _layers: this._layers, + _zeros: this._zeros, + levels: this.levels, + }; + } + static deserialize(data, hashFunction) { + const instance = Object.assign(Object.create(this.prototype), data); + instance._hashFn = hashFunction || simpleHash_1.default; + instance._initialRoot = data._edgeLeafProof.pathRoot; + instance.zeroElement = instance._zeros[0]; + instance._leavesAfterEdge = instance._layers[0].slice(data._edgeLeaf.index); + instance._createProofMap(); + return instance; + } + toString() { + return JSON.stringify(this.serialize()); + } + }; + PartialMerkleTree.PartialMerkleTree = PartialMerkleTree$1; + return PartialMerkleTree; +} + +var hasRequiredLib; + +function requireLib () { + if (hasRequiredLib) return lib; + hasRequiredLib = 1; + (function (exports) { + var __importDefault = (lib && lib.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; + }; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.MerkleTree = exports.simpleHash = exports.PartialMerkleTree = void 0; + const FixedMerkleTree_1 = __importDefault(/*@__PURE__*/ requireFixedMerkleTree()); + Object.defineProperty(exports, "MerkleTree", { enumerable: true, get: function () { return FixedMerkleTree_1.default; } }); + var PartialMerkleTree_1 = /*@__PURE__*/ requirePartialMerkleTree(); + Object.defineProperty(exports, "PartialMerkleTree", { enumerable: true, get: function () { return PartialMerkleTree_1.PartialMerkleTree; } }); + var simpleHash_1 = /*@__PURE__*/ requireSimpleHash(); + Object.defineProperty(exports, "simpleHash", { enumerable: true, get: function () { return simpleHash_1.simpleHash; } }); + exports.default = FixedMerkleTree_1.default; + } (lib)); + return lib; +} + +var libExports = /*@__PURE__*/ requireLib(); + +const version$2 = "logger/5.7.0"; + +let _permanentCensorErrors = false; +let _censorErrors = false; +const LogLevels = { debug: 1, "default": 2, info: 2, warning: 3, error: 4, off: 5 }; +let _logLevel = LogLevels["default"]; +let _globalLogger = null; +function _checkNormalize() { + try { + const missing = []; + // Make sure all forms of normalization are supported + ["NFD", "NFC", "NFKD", "NFKC"].forEach((form) => { + try { + if ("test".normalize(form) !== "test") { + throw new Error("bad normalize"); + } + } + catch (error) { + missing.push(form); + } + }); + if (missing.length) { + throw new Error("missing " + missing.join(", ")); + } + if (String.fromCharCode(0xe9).normalize("NFD") !== String.fromCharCode(0x65, 0x0301)) { + throw new Error("broken implementation"); + } + } + catch (error) { + return error.message; + } + return null; +} +const _normalizeError = _checkNormalize(); +var LogLevel; +(function (LogLevel) { + LogLevel["DEBUG"] = "DEBUG"; + LogLevel["INFO"] = "INFO"; + LogLevel["WARNING"] = "WARNING"; + LogLevel["ERROR"] = "ERROR"; + LogLevel["OFF"] = "OFF"; +})(LogLevel || (LogLevel = {})); +var ErrorCode; +(function (ErrorCode) { + /////////////////// + // Generic Errors + // Unknown Error + ErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR"; + // Not Implemented + ErrorCode["NOT_IMPLEMENTED"] = "NOT_IMPLEMENTED"; + // Unsupported Operation + // - operation + ErrorCode["UNSUPPORTED_OPERATION"] = "UNSUPPORTED_OPERATION"; + // Network Error (i.e. Ethereum Network, such as an invalid chain ID) + // - event ("noNetwork" is not re-thrown in provider.ready; otherwise thrown) + ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR"; + // Some sort of bad response from the server + ErrorCode["SERVER_ERROR"] = "SERVER_ERROR"; + // Timeout + ErrorCode["TIMEOUT"] = "TIMEOUT"; + /////////////////// + // Operational Errors + // Buffer Overrun + ErrorCode["BUFFER_OVERRUN"] = "BUFFER_OVERRUN"; + // Numeric Fault + // - operation: the operation being executed + // - fault: the reason this faulted + ErrorCode["NUMERIC_FAULT"] = "NUMERIC_FAULT"; + /////////////////// + // Argument Errors + // Missing new operator to an object + // - name: The name of the class + ErrorCode["MISSING_NEW"] = "MISSING_NEW"; + // Invalid argument (e.g. value is incompatible with type) to a function: + // - argument: The argument name that was invalid + // - value: The value of the argument + ErrorCode["INVALID_ARGUMENT"] = "INVALID_ARGUMENT"; + // Missing argument to a function: + // - count: The number of arguments received + // - expectedCount: The number of arguments expected + ErrorCode["MISSING_ARGUMENT"] = "MISSING_ARGUMENT"; + // Too many arguments + // - count: The number of arguments received + // - expectedCount: The number of arguments expected + ErrorCode["UNEXPECTED_ARGUMENT"] = "UNEXPECTED_ARGUMENT"; + /////////////////// + // Blockchain Errors + // Call exception + // - transaction: the transaction + // - address?: the contract address + // - args?: The arguments passed into the function + // - method?: The Solidity method signature + // - errorSignature?: The EIP848 error signature + // - errorArgs?: The EIP848 error parameters + // - reason: The reason (only for EIP848 "Error(string)") + ErrorCode["CALL_EXCEPTION"] = "CALL_EXCEPTION"; + // Insufficient funds (< value + gasLimit * gasPrice) + // - transaction: the transaction attempted + ErrorCode["INSUFFICIENT_FUNDS"] = "INSUFFICIENT_FUNDS"; + // Nonce has already been used + // - transaction: the transaction attempted + ErrorCode["NONCE_EXPIRED"] = "NONCE_EXPIRED"; + // The replacement fee for the transaction is too low + // - transaction: the transaction attempted + ErrorCode["REPLACEMENT_UNDERPRICED"] = "REPLACEMENT_UNDERPRICED"; + // The gas limit could not be estimated + // - transaction: the transaction passed to estimateGas + ErrorCode["UNPREDICTABLE_GAS_LIMIT"] = "UNPREDICTABLE_GAS_LIMIT"; + // The transaction was replaced by one with a higher gas price + // - reason: "cancelled", "replaced" or "repriced" + // - cancelled: true if reason == "cancelled" or reason == "replaced") + // - hash: original transaction hash + // - replacement: the full TransactionsResponse for the replacement + // - receipt: the receipt of the replacement + ErrorCode["TRANSACTION_REPLACED"] = "TRANSACTION_REPLACED"; + /////////////////// + // Interaction Errors + // The user rejected the action, such as signing a message or sending + // a transaction + ErrorCode["ACTION_REJECTED"] = "ACTION_REJECTED"; +})(ErrorCode || (ErrorCode = {})); +const HEX = "0123456789abcdef"; +class Logger { + constructor(version) { + Object.defineProperty(this, "version", { + enumerable: true, + value: version, + writable: false + }); + } + _log(logLevel, args) { + const level = logLevel.toLowerCase(); + if (LogLevels[level] == null) { + this.throwArgumentError("invalid log level name", "logLevel", logLevel); + } + if (_logLevel > LogLevels[level]) { + return; + } + console.log.apply(console, args); + } + debug(...args) { + this._log(Logger.levels.DEBUG, args); + } + info(...args) { + this._log(Logger.levels.INFO, args); + } + warn(...args) { + this._log(Logger.levels.WARNING, args); + } + makeError(message, code, params) { + // Errors are being censored + if (_censorErrors) { + return this.makeError("censored error", code, {}); + } + if (!code) { + code = Logger.errors.UNKNOWN_ERROR; + } + if (!params) { + params = {}; + } + const messageDetails = []; + Object.keys(params).forEach((key) => { + const value = params[key]; + try { + if (value instanceof Uint8Array) { + let hex = ""; + for (let i = 0; i < value.length; i++) { + hex += HEX[value[i] >> 4]; + hex += HEX[value[i] & 0x0f]; + } + messageDetails.push(key + "=Uint8Array(0x" + hex + ")"); + } + else { + messageDetails.push(key + "=" + JSON.stringify(value)); + } + } + catch (error) { + messageDetails.push(key + "=" + JSON.stringify(params[key].toString())); + } + }); + messageDetails.push(`code=${code}`); + messageDetails.push(`version=${this.version}`); + const reason = message; + let url = ""; + switch (code) { + case ErrorCode.NUMERIC_FAULT: { + url = "NUMERIC_FAULT"; + const fault = message; + switch (fault) { + case "overflow": + case "underflow": + case "division-by-zero": + url += "-" + fault; + break; + case "negative-power": + case "negative-width": + url += "-unsupported"; + break; + case "unbound-bitwise-result": + url += "-unbound-result"; + break; + } + break; + } + case ErrorCode.CALL_EXCEPTION: + case ErrorCode.INSUFFICIENT_FUNDS: + case ErrorCode.MISSING_NEW: + case ErrorCode.NONCE_EXPIRED: + case ErrorCode.REPLACEMENT_UNDERPRICED: + case ErrorCode.TRANSACTION_REPLACED: + case ErrorCode.UNPREDICTABLE_GAS_LIMIT: + url = code; + break; + } + if (url) { + message += " [ See: https:/\/links.ethers.org/v5-errors-" + url + " ]"; + } + if (messageDetails.length) { + message += " (" + messageDetails.join(", ") + ")"; + } + // @TODO: Any?? + const error = new Error(message); + error.reason = reason; + error.code = code; + Object.keys(params).forEach(function (key) { + error[key] = params[key]; + }); + return error; + } + throwError(message, code, params) { + throw this.makeError(message, code, params); + } + throwArgumentError(message, name, value) { + return this.throwError(message, Logger.errors.INVALID_ARGUMENT, { + argument: name, + value: value + }); + } + assert(condition, message, code, params) { + if (!!condition) { + return; + } + this.throwError(message, code, params); + } + assertArgument(condition, message, name, value) { + if (!!condition) { + return; + } + this.throwArgumentError(message, name, value); + } + checkNormalize(message) { + if (_normalizeError) { + this.throwError("platform missing String.prototype.normalize", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "String.prototype.normalize", form: _normalizeError + }); + } + } + checkSafeUint53(value, message) { + if (typeof (value) !== "number") { + return; + } + if (message == null) { + message = "value not safe"; + } + if (value < 0 || value >= 0x1fffffffffffff) { + this.throwError(message, Logger.errors.NUMERIC_FAULT, { + operation: "checkSafeInteger", + fault: "out-of-safe-range", + value: value + }); + } + if (value % 1) { + this.throwError(message, Logger.errors.NUMERIC_FAULT, { + operation: "checkSafeInteger", + fault: "non-integer", + value: value + }); + } + } + checkArgumentCount(count, expectedCount, message) { + if (message) { + message = ": " + message; + } + else { + message = ""; + } + if (count < expectedCount) { + this.throwError("missing argument" + message, Logger.errors.MISSING_ARGUMENT, { + count: count, + expectedCount: expectedCount + }); + } + if (count > expectedCount) { + this.throwError("too many arguments" + message, Logger.errors.UNEXPECTED_ARGUMENT, { + count: count, + expectedCount: expectedCount + }); + } + } + checkNew(target, kind) { + if (target === Object || target == null) { + this.throwError("missing new", Logger.errors.MISSING_NEW, { name: kind.name }); + } + } + checkAbstract(target, kind) { + if (target === kind) { + this.throwError("cannot instantiate abstract class " + JSON.stringify(kind.name) + " directly; use a sub-class", Logger.errors.UNSUPPORTED_OPERATION, { name: target.name, operation: "new" }); + } + else if (target === Object || target == null) { + this.throwError("missing new", Logger.errors.MISSING_NEW, { name: kind.name }); + } + } + static globalLogger() { + if (!_globalLogger) { + _globalLogger = new Logger(version$2); + } + return _globalLogger; + } + static setCensorship(censorship, permanent) { + if (!censorship && permanent) { + this.globalLogger().throwError("cannot permanently disable censorship", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "setCensorship" + }); + } + if (_permanentCensorErrors) { + if (!censorship) { + return; + } + this.globalLogger().throwError("error censorship permanent", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "setCensorship" + }); + } + _censorErrors = !!censorship; + _permanentCensorErrors = !!permanent; + } + static setLogLevel(logLevel) { + const level = LogLevels[logLevel.toLowerCase()]; + if (level == null) { + Logger.globalLogger().warn("invalid log level - " + logLevel); + return; + } + _logLevel = level; + } + static from(version) { + return new Logger(version); + } +} +Logger.errors = ErrorCode; +Logger.levels = LogLevel; + +const version$1 = "bytes/5.7.0"; + +const logger$1 = new Logger(version$1); +/////////////////////////////// +function isHexable(value) { + return !!(value.toHexString); +} +function addSlice(array) { + if (array.slice) { + return array; + } + array.slice = function () { + const args = Array.prototype.slice.call(arguments); + return addSlice(new Uint8Array(Array.prototype.slice.apply(array, args))); + }; + return array; +} +function isInteger(value) { + return (typeof (value) === "number" && value == value && (value % 1) === 0); +} +function isBytes(value) { + if (value == null) { + return false; + } + if (value.constructor === Uint8Array) { + return true; + } + if (typeof (value) === "string") { + return false; + } + if (!isInteger(value.length) || value.length < 0) { + return false; + } + for (let i = 0; i < value.length; i++) { + const v = value[i]; + if (!isInteger(v) || v < 0 || v >= 256) { + return false; + } + } + return true; +} +function arrayify(value, options) { + if (!options) { + options = {}; + } + if (typeof (value) === "number") { + logger$1.checkSafeUint53(value, "invalid arrayify value"); + const result = []; + while (value) { + result.unshift(value & 0xff); + value = parseInt(String(value / 256)); + } + if (result.length === 0) { + result.push(0); + } + return addSlice(new Uint8Array(result)); + } + if (options.allowMissingPrefix && typeof (value) === "string" && value.substring(0, 2) !== "0x") { + value = "0x" + value; + } + if (isHexable(value)) { + value = value.toHexString(); + } + if (isHexString(value)) { + let hex = value.substring(2); + if (hex.length % 2) { + if (options.hexPad === "left") { + hex = "0" + hex; + } + else if (options.hexPad === "right") { + hex += "0"; + } + else { + logger$1.throwArgumentError("hex data is odd-length", "value", value); + } + } + const result = []; + for (let i = 0; i < hex.length; i += 2) { + result.push(parseInt(hex.substring(i, i + 2), 16)); + } + return addSlice(new Uint8Array(result)); + } + if (isBytes(value)) { + return addSlice(new Uint8Array(value)); + } + return logger$1.throwArgumentError("invalid arrayify value", "value", value); +} +function isHexString(value, length) { + if (typeof (value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) { + return false; + } + return true; +} + +var sha3$1 = {exports: {}}; + +/** + * [js-sha3]{@link https://github.com/emn178/js-sha3} + * + * @version 0.8.0 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2015-2018 + * @license MIT + */ + +var hasRequiredSha3; + +function requireSha3 () { + if (hasRequiredSha3) return sha3$1.exports; + hasRequiredSha3 = 1; + (function (module) { + /*jslint bitwise: true */ + (function () { + + var INPUT_ERROR = 'input is invalid type'; + var FINALIZE_ERROR = 'finalize already called'; + var WINDOW = typeof window === 'object'; + var root = WINDOW ? window : {}; + if (root.JS_SHA3_NO_WINDOW) { + WINDOW = false; + } + var WEB_WORKER = !WINDOW && typeof self === 'object'; + var NODE_JS = !root.JS_SHA3_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; + if (NODE_JS) { + root = commonjsGlobal; + } else if (WEB_WORKER) { + root = self; + } + var COMMON_JS = !root.JS_SHA3_NO_COMMON_JS && 'object' === 'object' && module.exports; + var ARRAY_BUFFER = !root.JS_SHA3_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; + var HEX_CHARS = '0123456789abcdef'.split(''); + var SHAKE_PADDING = [31, 7936, 2031616, 520093696]; + var CSHAKE_PADDING = [4, 1024, 262144, 67108864]; + var KECCAK_PADDING = [1, 256, 65536, 16777216]; + var PADDING = [6, 1536, 393216, 100663296]; + var SHIFT = [0, 8, 16, 24]; + var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649, + 0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0, + 2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771, + 2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648, + 2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648]; + var BITS = [224, 256, 384, 512]; + var SHAKE_BITS = [128, 256]; + var OUTPUT_TYPES = ['hex', 'buffer', 'arrayBuffer', 'array', 'digest']; + var CSHAKE_BYTEPAD = { + '128': 168, + '256': 136 + }; + + if (root.JS_SHA3_NO_NODE_JS || !Array.isArray) { + Array.isArray = function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + } + + if (ARRAY_BUFFER && (root.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { + ArrayBuffer.isView = function (obj) { + return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; + }; + } + + var createOutputMethod = function (bits, padding, outputType) { + return function (message) { + return new Keccak(bits, padding, bits).update(message)[outputType](); + }; + }; + + var createShakeOutputMethod = function (bits, padding, outputType) { + return function (message, outputBits) { + return new Keccak(bits, padding, outputBits).update(message)[outputType](); + }; + }; + + var createCshakeOutputMethod = function (bits, padding, outputType) { + return function (message, outputBits, n, s) { + return methods['cshake' + bits].update(message, outputBits, n, s)[outputType](); + }; + }; + + var createKmacOutputMethod = function (bits, padding, outputType) { + return function (key, message, outputBits, s) { + return methods['kmac' + bits].update(key, message, outputBits, s)[outputType](); + }; + }; + + var createOutputMethods = function (method, createMethod, bits, padding) { + for (var i = 0; i < OUTPUT_TYPES.length; ++i) { + var type = OUTPUT_TYPES[i]; + method[type] = createMethod(bits, padding, type); + } + return method; + }; + + var createMethod = function (bits, padding) { + var method = createOutputMethod(bits, padding, 'hex'); + method.create = function () { + return new Keccak(bits, padding, bits); + }; + method.update = function (message) { + return method.create().update(message); + }; + return createOutputMethods(method, createOutputMethod, bits, padding); + }; + + var createShakeMethod = function (bits, padding) { + var method = createShakeOutputMethod(bits, padding, 'hex'); + method.create = function (outputBits) { + return new Keccak(bits, padding, outputBits); + }; + method.update = function (message, outputBits) { + return method.create(outputBits).update(message); + }; + return createOutputMethods(method, createShakeOutputMethod, bits, padding); + }; + + var createCshakeMethod = function (bits, padding) { + var w = CSHAKE_BYTEPAD[bits]; + var method = createCshakeOutputMethod(bits, padding, 'hex'); + method.create = function (outputBits, n, s) { + if (!n && !s) { + return methods['shake' + bits].create(outputBits); + } else { + return new Keccak(bits, padding, outputBits).bytepad([n, s], w); + } + }; + method.update = function (message, outputBits, n, s) { + return method.create(outputBits, n, s).update(message); + }; + return createOutputMethods(method, createCshakeOutputMethod, bits, padding); + }; + + var createKmacMethod = function (bits, padding) { + var w = CSHAKE_BYTEPAD[bits]; + var method = createKmacOutputMethod(bits, padding, 'hex'); + method.create = function (key, outputBits, s) { + return new Kmac(bits, padding, outputBits).bytepad(['KMAC', s], w).bytepad([key], w); + }; + method.update = function (key, message, outputBits, s) { + return method.create(key, outputBits, s).update(message); + }; + return createOutputMethods(method, createKmacOutputMethod, bits, padding); + }; + + var algorithms = [ + { name: 'keccak', padding: KECCAK_PADDING, bits: BITS, createMethod: createMethod }, + { name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod }, + { name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod }, + { name: 'cshake', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createCshakeMethod }, + { name: 'kmac', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createKmacMethod } + ]; + + var methods = {}, methodNames = []; + + for (var i = 0; i < algorithms.length; ++i) { + var algorithm = algorithms[i]; + var bits = algorithm.bits; + for (var j = 0; j < bits.length; ++j) { + var methodName = algorithm.name + '_' + bits[j]; + methodNames.push(methodName); + methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding); + if (algorithm.name !== 'sha3') { + var newMethodName = algorithm.name + bits[j]; + methodNames.push(newMethodName); + methods[newMethodName] = methods[methodName]; + } + } + } + + function Keccak(bits, padding, outputBits) { + this.blocks = []; + this.s = []; + this.padding = padding; + this.outputBits = outputBits; + this.reset = true; + this.finalized = false; + this.block = 0; + this.start = 0; + this.blockCount = (1600 - (bits << 1)) >> 5; + this.byteCount = this.blockCount << 2; + this.outputBlocks = outputBits >> 5; + this.extraBytes = (outputBits & 31) >> 3; + + for (var i = 0; i < 50; ++i) { + this.s[i] = 0; + } + } + + Keccak.prototype.update = function (message) { + if (this.finalized) { + throw new Error(FINALIZE_ERROR); + } + var notString, type = typeof message; + if (type !== 'string') { + if (type === 'object') { + if (message === null) { + throw new Error(INPUT_ERROR); + } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) { + message = new Uint8Array(message); + } else if (!Array.isArray(message)) { + if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { + throw new Error(INPUT_ERROR); + } + } + } else { + throw new Error(INPUT_ERROR); + } + notString = true; + } + var blocks = this.blocks, byteCount = this.byteCount, length = message.length, + blockCount = this.blockCount, index = 0, s = this.s, i, code; + + while (index < length) { + if (this.reset) { + this.reset = false; + blocks[0] = this.block; + for (i = 1; i < blockCount + 1; ++i) { + blocks[i] = 0; + } + } + if (notString) { + for (i = this.start; index < length && i < byteCount; ++index) { + blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; + } + } else { + for (i = this.start; index < length && i < byteCount; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + blocks[i >> 2] |= code << SHIFT[i++ & 3]; + } else if (code < 0x800) { + blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else if (code < 0xd800 || code >= 0xe000) { + blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + } + } + this.lastByteIndex = i; + if (i >= byteCount) { + this.start = i - byteCount; + this.block = blocks[blockCount]; + for (i = 0; i < blockCount; ++i) { + s[i] ^= blocks[i]; + } + f(s); + this.reset = true; + } else { + this.start = i; + } + } + return this; + }; + + Keccak.prototype.encode = function (x, right) { + var o = x & 255, n = 1; + var bytes = [o]; + x = x >> 8; + o = x & 255; + while (o > 0) { + bytes.unshift(o); + x = x >> 8; + o = x & 255; + ++n; + } + if (right) { + bytes.push(n); + } else { + bytes.unshift(n); + } + this.update(bytes); + return bytes.length; + }; + + Keccak.prototype.encodeString = function (str) { + var notString, type = typeof str; + if (type !== 'string') { + if (type === 'object') { + if (str === null) { + throw new Error(INPUT_ERROR); + } else if (ARRAY_BUFFER && str.constructor === ArrayBuffer) { + str = new Uint8Array(str); + } else if (!Array.isArray(str)) { + if (!ARRAY_BUFFER || !ArrayBuffer.isView(str)) { + throw new Error(INPUT_ERROR); + } + } + } else { + throw new Error(INPUT_ERROR); + } + notString = true; + } + var bytes = 0, length = str.length; + if (notString) { + bytes = length; + } else { + for (var i = 0; i < str.length; ++i) { + var code = str.charCodeAt(i); + if (code < 0x80) { + bytes += 1; + } else if (code < 0x800) { + bytes += 2; + } else if (code < 0xd800 || code >= 0xe000) { + bytes += 3; + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff)); + bytes += 4; + } + } + } + bytes += this.encode(bytes * 8); + this.update(str); + return bytes; + }; + + Keccak.prototype.bytepad = function (strs, w) { + var bytes = this.encode(w); + for (var i = 0; i < strs.length; ++i) { + bytes += this.encodeString(strs[i]); + } + var paddingBytes = w - bytes % w; + var zeros = []; + zeros.length = paddingBytes; + this.update(zeros); + return this; + }; + + Keccak.prototype.finalize = function () { + if (this.finalized) { + return; + } + this.finalized = true; + var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s; + blocks[i >> 2] |= this.padding[i & 3]; + if (this.lastByteIndex === this.byteCount) { + blocks[0] = blocks[blockCount]; + for (i = 1; i < blockCount + 1; ++i) { + blocks[i] = 0; + } + } + blocks[blockCount - 1] |= 0x80000000; + for (i = 0; i < blockCount; ++i) { + s[i] ^= blocks[i]; + } + f(s); + }; + + Keccak.prototype.toString = Keccak.prototype.hex = function () { + this.finalize(); + + var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, + extraBytes = this.extraBytes, i = 0, j = 0; + var hex = '', block; + while (j < outputBlocks) { + for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) { + block = s[i]; + hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] + + HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] + + HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] + + HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F]; + } + if (j % blockCount === 0) { + f(s); + i = 0; + } + } + if (extraBytes) { + block = s[i]; + hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F]; + if (extraBytes > 1) { + hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F]; + } + if (extraBytes > 2) { + hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F]; + } + } + return hex; + }; + + Keccak.prototype.arrayBuffer = function () { + this.finalize(); + + var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, + extraBytes = this.extraBytes, i = 0, j = 0; + var bytes = this.outputBits >> 3; + var buffer; + if (extraBytes) { + buffer = new ArrayBuffer((outputBlocks + 1) << 2); + } else { + buffer = new ArrayBuffer(bytes); + } + var array = new Uint32Array(buffer); + while (j < outputBlocks) { + for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) { + array[j] = s[i]; + } + if (j % blockCount === 0) { + f(s); + } + } + if (extraBytes) { + array[i] = s[i]; + buffer = buffer.slice(0, bytes); + } + return buffer; + }; + + Keccak.prototype.buffer = Keccak.prototype.arrayBuffer; + + Keccak.prototype.digest = Keccak.prototype.array = function () { + this.finalize(); + + var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, + extraBytes = this.extraBytes, i = 0, j = 0; + var array = [], offset, block; + while (j < outputBlocks) { + for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) { + offset = j << 2; + block = s[i]; + array[offset] = block & 0xFF; + array[offset + 1] = (block >> 8) & 0xFF; + array[offset + 2] = (block >> 16) & 0xFF; + array[offset + 3] = (block >> 24) & 0xFF; + } + if (j % blockCount === 0) { + f(s); + } + } + if (extraBytes) { + offset = j << 2; + block = s[i]; + array[offset] = block & 0xFF; + if (extraBytes > 1) { + array[offset + 1] = (block >> 8) & 0xFF; + } + if (extraBytes > 2) { + array[offset + 2] = (block >> 16) & 0xFF; + } + } + return array; + }; + + function Kmac(bits, padding, outputBits) { + Keccak.call(this, bits, padding, outputBits); + } + + Kmac.prototype = new Keccak(); + + Kmac.prototype.finalize = function () { + this.encode(this.outputBits, true); + return Keccak.prototype.finalize.call(this); + }; + + var f = function (s) { + var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, + b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, + b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33, + b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49; + for (n = 0; n < 48; n += 2) { + c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40]; + c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41]; + c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42]; + c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43]; + c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44]; + c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45]; + c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46]; + c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47]; + c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48]; + c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49]; + + h = c8 ^ ((c2 << 1) | (c3 >>> 31)); + l = c9 ^ ((c3 << 1) | (c2 >>> 31)); + s[0] ^= h; + s[1] ^= l; + s[10] ^= h; + s[11] ^= l; + s[20] ^= h; + s[21] ^= l; + s[30] ^= h; + s[31] ^= l; + s[40] ^= h; + s[41] ^= l; + h = c0 ^ ((c4 << 1) | (c5 >>> 31)); + l = c1 ^ ((c5 << 1) | (c4 >>> 31)); + s[2] ^= h; + s[3] ^= l; + s[12] ^= h; + s[13] ^= l; + s[22] ^= h; + s[23] ^= l; + s[32] ^= h; + s[33] ^= l; + s[42] ^= h; + s[43] ^= l; + h = c2 ^ ((c6 << 1) | (c7 >>> 31)); + l = c3 ^ ((c7 << 1) | (c6 >>> 31)); + s[4] ^= h; + s[5] ^= l; + s[14] ^= h; + s[15] ^= l; + s[24] ^= h; + s[25] ^= l; + s[34] ^= h; + s[35] ^= l; + s[44] ^= h; + s[45] ^= l; + h = c4 ^ ((c8 << 1) | (c9 >>> 31)); + l = c5 ^ ((c9 << 1) | (c8 >>> 31)); + s[6] ^= h; + s[7] ^= l; + s[16] ^= h; + s[17] ^= l; + s[26] ^= h; + s[27] ^= l; + s[36] ^= h; + s[37] ^= l; + s[46] ^= h; + s[47] ^= l; + h = c6 ^ ((c0 << 1) | (c1 >>> 31)); + l = c7 ^ ((c1 << 1) | (c0 >>> 31)); + s[8] ^= h; + s[9] ^= l; + s[18] ^= h; + s[19] ^= l; + s[28] ^= h; + s[29] ^= l; + s[38] ^= h; + s[39] ^= l; + s[48] ^= h; + s[49] ^= l; + + b0 = s[0]; + b1 = s[1]; + b32 = (s[11] << 4) | (s[10] >>> 28); + b33 = (s[10] << 4) | (s[11] >>> 28); + b14 = (s[20] << 3) | (s[21] >>> 29); + b15 = (s[21] << 3) | (s[20] >>> 29); + b46 = (s[31] << 9) | (s[30] >>> 23); + b47 = (s[30] << 9) | (s[31] >>> 23); + b28 = (s[40] << 18) | (s[41] >>> 14); + b29 = (s[41] << 18) | (s[40] >>> 14); + b20 = (s[2] << 1) | (s[3] >>> 31); + b21 = (s[3] << 1) | (s[2] >>> 31); + b2 = (s[13] << 12) | (s[12] >>> 20); + b3 = (s[12] << 12) | (s[13] >>> 20); + b34 = (s[22] << 10) | (s[23] >>> 22); + b35 = (s[23] << 10) | (s[22] >>> 22); + b16 = (s[33] << 13) | (s[32] >>> 19); + b17 = (s[32] << 13) | (s[33] >>> 19); + b48 = (s[42] << 2) | (s[43] >>> 30); + b49 = (s[43] << 2) | (s[42] >>> 30); + b40 = (s[5] << 30) | (s[4] >>> 2); + b41 = (s[4] << 30) | (s[5] >>> 2); + b22 = (s[14] << 6) | (s[15] >>> 26); + b23 = (s[15] << 6) | (s[14] >>> 26); + b4 = (s[25] << 11) | (s[24] >>> 21); + b5 = (s[24] << 11) | (s[25] >>> 21); + b36 = (s[34] << 15) | (s[35] >>> 17); + b37 = (s[35] << 15) | (s[34] >>> 17); + b18 = (s[45] << 29) | (s[44] >>> 3); + b19 = (s[44] << 29) | (s[45] >>> 3); + b10 = (s[6] << 28) | (s[7] >>> 4); + b11 = (s[7] << 28) | (s[6] >>> 4); + b42 = (s[17] << 23) | (s[16] >>> 9); + b43 = (s[16] << 23) | (s[17] >>> 9); + b24 = (s[26] << 25) | (s[27] >>> 7); + b25 = (s[27] << 25) | (s[26] >>> 7); + b6 = (s[36] << 21) | (s[37] >>> 11); + b7 = (s[37] << 21) | (s[36] >>> 11); + b38 = (s[47] << 24) | (s[46] >>> 8); + b39 = (s[46] << 24) | (s[47] >>> 8); + b30 = (s[8] << 27) | (s[9] >>> 5); + b31 = (s[9] << 27) | (s[8] >>> 5); + b12 = (s[18] << 20) | (s[19] >>> 12); + b13 = (s[19] << 20) | (s[18] >>> 12); + b44 = (s[29] << 7) | (s[28] >>> 25); + b45 = (s[28] << 7) | (s[29] >>> 25); + b26 = (s[38] << 8) | (s[39] >>> 24); + b27 = (s[39] << 8) | (s[38] >>> 24); + b8 = (s[48] << 14) | (s[49] >>> 18); + b9 = (s[49] << 14) | (s[48] >>> 18); + + s[0] = b0 ^ (~b2 & b4); + s[1] = b1 ^ (~b3 & b5); + s[10] = b10 ^ (~b12 & b14); + s[11] = b11 ^ (~b13 & b15); + s[20] = b20 ^ (~b22 & b24); + s[21] = b21 ^ (~b23 & b25); + s[30] = b30 ^ (~b32 & b34); + s[31] = b31 ^ (~b33 & b35); + s[40] = b40 ^ (~b42 & b44); + s[41] = b41 ^ (~b43 & b45); + s[2] = b2 ^ (~b4 & b6); + s[3] = b3 ^ (~b5 & b7); + s[12] = b12 ^ (~b14 & b16); + s[13] = b13 ^ (~b15 & b17); + s[22] = b22 ^ (~b24 & b26); + s[23] = b23 ^ (~b25 & b27); + s[32] = b32 ^ (~b34 & b36); + s[33] = b33 ^ (~b35 & b37); + s[42] = b42 ^ (~b44 & b46); + s[43] = b43 ^ (~b45 & b47); + s[4] = b4 ^ (~b6 & b8); + s[5] = b5 ^ (~b7 & b9); + s[14] = b14 ^ (~b16 & b18); + s[15] = b15 ^ (~b17 & b19); + s[24] = b24 ^ (~b26 & b28); + s[25] = b25 ^ (~b27 & b29); + s[34] = b34 ^ (~b36 & b38); + s[35] = b35 ^ (~b37 & b39); + s[44] = b44 ^ (~b46 & b48); + s[45] = b45 ^ (~b47 & b49); + s[6] = b6 ^ (~b8 & b0); + s[7] = b7 ^ (~b9 & b1); + s[16] = b16 ^ (~b18 & b10); + s[17] = b17 ^ (~b19 & b11); + s[26] = b26 ^ (~b28 & b20); + s[27] = b27 ^ (~b29 & b21); + s[36] = b36 ^ (~b38 & b30); + s[37] = b37 ^ (~b39 & b31); + s[46] = b46 ^ (~b48 & b40); + s[47] = b47 ^ (~b49 & b41); + s[8] = b8 ^ (~b0 & b2); + s[9] = b9 ^ (~b1 & b3); + s[18] = b18 ^ (~b10 & b12); + s[19] = b19 ^ (~b11 & b13); + s[28] = b28 ^ (~b20 & b22); + s[29] = b29 ^ (~b21 & b23); + s[38] = b38 ^ (~b30 & b32); + s[39] = b39 ^ (~b31 & b33); + s[48] = b48 ^ (~b40 & b42); + s[49] = b49 ^ (~b41 & b43); + + s[0] ^= RC[n]; + s[1] ^= RC[n + 1]; + } + }; + + if (COMMON_JS) { + module.exports = methods; + } else { + for (i = 0; i < methodNames.length; ++i) { + root[methodNames[i]] = methods[methodNames[i]]; + } + } + })(); + } (sha3$1)); + return sha3$1.exports; +} + +var sha3Exports = /*@__PURE__*/ requireSha3(); +var sha3 = /*@__PURE__*/getDefaultExportFromCjs(sha3Exports); + +function keccak256(data) { + return '0x' + sha3.keccak_256(arrayify(data)); +} + +const version = "strings/5.7.0"; + +const logger = new Logger(version); +/////////////////////////////// +var UnicodeNormalizationForm; +(function (UnicodeNormalizationForm) { + UnicodeNormalizationForm["current"] = ""; + UnicodeNormalizationForm["NFC"] = "NFC"; + UnicodeNormalizationForm["NFD"] = "NFD"; + UnicodeNormalizationForm["NFKC"] = "NFKC"; + UnicodeNormalizationForm["NFKD"] = "NFKD"; +})(UnicodeNormalizationForm || (UnicodeNormalizationForm = {})); +var Utf8ErrorReason; +(function (Utf8ErrorReason) { + // A continuation byte was present where there was nothing to continue + // - offset = the index the codepoint began in + Utf8ErrorReason["UNEXPECTED_CONTINUE"] = "unexpected continuation byte"; + // An invalid (non-continuation) byte to start a UTF-8 codepoint was found + // - offset = the index the codepoint began in + Utf8ErrorReason["BAD_PREFIX"] = "bad codepoint prefix"; + // The string is too short to process the expected codepoint + // - offset = the index the codepoint began in + Utf8ErrorReason["OVERRUN"] = "string overrun"; + // A missing continuation byte was expected but not found + // - offset = the index the continuation byte was expected at + Utf8ErrorReason["MISSING_CONTINUE"] = "missing continuation byte"; + // The computed code point is outside the range for UTF-8 + // - offset = start of this codepoint + // - badCodepoint = the computed codepoint; outside the UTF-8 range + Utf8ErrorReason["OUT_OF_RANGE"] = "out of UTF-8 range"; + // UTF-8 strings may not contain UTF-16 surrogate pairs + // - offset = start of this codepoint + // - badCodepoint = the computed codepoint; inside the UTF-16 surrogate range + Utf8ErrorReason["UTF16_SURROGATE"] = "UTF-16 surrogate"; + // The string is an overlong representation + // - offset = start of this codepoint + // - badCodepoint = the computed codepoint; already bounds checked + Utf8ErrorReason["OVERLONG"] = "overlong representation"; +})(Utf8ErrorReason || (Utf8ErrorReason = {})); +// http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array +function toUtf8Bytes(str, form = UnicodeNormalizationForm.current) { + if (form != UnicodeNormalizationForm.current) { + logger.checkNormalize(); + str = str.normalize(form); + } + let result = []; + for (let i = 0; i < str.length; i++) { + const c = str.charCodeAt(i); + if (c < 0x80) { + result.push(c); + } + else if (c < 0x800) { + result.push((c >> 6) | 0xc0); + result.push((c & 0x3f) | 0x80); + } + else if ((c & 0xfc00) == 0xd800) { + i++; + const c2 = str.charCodeAt(i); + if (i >= str.length || (c2 & 0xfc00) !== 0xdc00) { + throw new Error("invalid utf-8 string"); + } + // Surrogate Pair + const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff); + result.push((pair >> 18) | 0xf0); + result.push(((pair >> 12) & 0x3f) | 0x80); + result.push(((pair >> 6) & 0x3f) | 0x80); + result.push((pair & 0x3f) | 0x80); + } + else { + result.push((c >> 12) | 0xe0); + result.push(((c >> 6) & 0x3f) | 0x80); + result.push((c & 0x3f) | 0x80); + } + } + return arrayify(result); +} + +const SEED = "mimcsponge"; +const NROUNDS = 220; + +async function buildMimcSponge() { + const bn128 = await ffjavascript.getCurveFromName("bn128", true); + return new MimcSponge(bn128.Fr); +} + +class MimcSponge { + constructor (F) { + this.F = F; + this.cts = this.getConstants(SEED, NROUNDS); + } + + getIV (seed) { + const F = this.F; + if (typeof seed === "undefined") seed = SEED; + const c = keccak256(toUtf8Bytes(seed+"_iv")); + const cn = ffjavascript.Scalar.e(c); + const iv = cn.mod(F.p); + return iv; + }; + + getConstants (seed, nRounds) { + const F = this.F; + if (typeof nRounds === "undefined") nRounds = NROUNDS; + const cts = new Array(nRounds); + let c = keccak256(toUtf8Bytes(SEED)); for (let i=1; i this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)])); + } + async getHash() { + await this.mimcPromise; + return { + sponge: this.sponge, + hash: this.hash + }; + } +} +const mimc = new Mimc(); + +BigInt.prototype.toJSON = function() { + return this.toString(); +}; +const isNode = !process.browser && typeof globalThis.window === "undefined"; + +async function nodePostWork() { + const { hash: hashFunction } = await mimc.getHash(); + const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData; + if (edge) { + const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, { + zeroElement, + hashFunction + }); + workerThreads.parentPort.postMessage(merkleTree2.toString()); + return; + } + const merkleTree = new libExports.MerkleTree(merkleTreeHeight, elements, { + zeroElement, + hashFunction + }); + workerThreads.parentPort.postMessage(merkleTree.toString()); +} +if (isNode && workerThreads) { + nodePostWork(); +} else if (!isNode && typeof addEventListener === "function" && typeof postMessage === "function") { + addEventListener("message", async (e) => { + let data; + if (e.data) { + data = e.data; + } else { + data = e; + } + const { hash: hashFunction } = await mimc.getHash(); + const { merkleTreeHeight, edge, elements, zeroElement } = data; + if (edge) { + const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, { + zeroElement, + hashFunction + }); + postMessage(merkleTree2.toString()); + return; + } + const merkleTree = new libExports.MerkleTree(merkleTreeHeight, elements, { + zeroElement, + hashFunction + }); + postMessage(merkleTree.toString()); + }); +} else { + throw new Error("This browser / environment does not support workers!"); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..96d9961 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "typeRoots": [ + "./node_modules/@types", + "./src/types" + ], + "target": "es2022", + "lib": ["ES2016", "ES2021", "ES2022", "ESNext"], + "module": "commonjs", + "rootDir": "./src", + "resolveJsonModule": true, + "outDir": "./lib", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..d6c1bea --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4459 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + +"@babel/code-frame@^7.0.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@ensdomains/content-hash@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@ensdomains/content-hash/-/content-hash-2.5.7.tgz#180e4ceb6e585a05d69ba307619d4a0cf12948f1" + integrity sha512-WNdGKCeubMIAfyPYTMlKeX6cgXKIEo42OcWPOLBiclzJwMibkVqpaGgWKVH9dniJq7bLXLa2tQ0k/F1pt6gUxA== + dependencies: + cids "^1.1.5" + js-base64 "^3.6.0" + multicodec "^3.2.0" + multihashes "^2.0.0" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + +"@ethereumjs/common@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-3.2.0.tgz#b71df25845caf5456449163012074a55f048e0a0" + integrity sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA== + dependencies: + "@ethereumjs/util" "^8.1.0" + crc-32 "^1.2.0" + +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/tx@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-4.2.0.tgz#5988ae15daf5a3b3c815493bc6b495e76009e853" + integrity sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw== + dependencies: + "@ethereumjs/common" "^3.2.0" + "@ethereumjs/rlp" "^4.0.1" + "@ethereumjs/util" "^8.1.0" + ethereum-cryptography "^2.0.0" + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@fastify/ajv-compiler@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-4.0.1.tgz#9567b4c09149a0f342e931c7196a8ed9dc292954" + integrity sha512-DxrBdgsjNLP0YM6W5Hd6/Fmj43S8zMKiFJYgi+Ri3htTGAowPVG/tG1wpnWLMjufEnehRivUCKZ1pLDIoZdTuw== + dependencies: + ajv "^8.12.0" + ajv-formats "^3.0.1" + fast-uri "^3.0.0" + +"@fastify/cors@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@fastify/cors/-/cors-10.0.1.tgz#c208fa5f672db31a8383400349e9852762903d64" + integrity sha512-O8JIf6448uQbOgzSkCqhClw6gFTAqrdfeA6R3fc/3gwTJGUp7gl8/3tbNB+6INuu4RmgVOq99BmvdGbtu5pgOA== + dependencies: + fastify-plugin "^5.0.0" + mnemonist "0.39.8" + +"@fastify/error@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@fastify/error/-/error-4.0.0.tgz#7842d6161fbce78953638318be99033a0c2d5070" + integrity sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA== + +"@fastify/fast-json-stringify-compiler@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.1.tgz#659c74f3181fb4f984fe27dcc95d14366ae85ca0" + integrity sha512-f2d3JExJgFE3UbdFcpPwqNUEoHWmt8pAKf8f+9YuLESdefA0WgqxeT6DrGL4Yrf/9ihXNSKOqpjEmurV405meA== + dependencies: + fast-json-stringify "^6.0.0" + +"@fastify/merge-json-schemas@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz#3551857b8a17a24e8c799e9f51795edb07baa0bc" + integrity sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA== + dependencies: + fast-deep-equal "^3.1.3" + +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@metamask/abi-utils@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.4.tgz#20908c1d910f7a17a89fdf5778a5c59d5cb8b8be" + integrity sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ== + dependencies: + "@metamask/superstruct" "^3.1.0" + "@metamask/utils" "^9.0.0" + +"@metamask/eth-sig-util@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-8.0.0.tgz#6310d93cd1101cab3cc6bc2a1ff526290ed2695b" + integrity sha512-IwE6aoxUL39IhmsAgE4nk+OZbNo+ThFZRNsUjE1pjdEa4MFpWzm1Rue4zJ5DMy1oUyZBi/aiCLMhdMnjl2bh2Q== + dependencies: + "@ethereumjs/util" "^8.1.0" + "@metamask/abi-utils" "^2.0.4" + "@metamask/utils" "^9.0.0" + "@scure/base" "~1.1.3" + ethereum-cryptography "^2.1.2" + tweetnacl "^1.0.3" + +"@metamask/superstruct@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@metamask/superstruct/-/superstruct-3.1.0.tgz#148f786a674fba3ac885c1093ab718515bf7f648" + integrity sha512-N08M56HdOgBfRKkrgCMZvQppkZGcArEop3kixNEtVbJKm6P9Cfg0YkI6X0s1g78sNrj2fWUwvJADdZuzJgFttA== + +"@metamask/utils@^9.0.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.2.1.tgz#d9f84706ff97e0c8d1bde5778549365b14269e81" + integrity sha512-/u663aUaB6+Xe75i3Mt/1cCljm41HDYIsna5oBrwGvgkY2zH7/9k9Zjd706cxoAbxN7QgLSVAReUiGnuxCuXrQ== + dependencies: + "@ethereumjs/tx" "^4.2.0" + "@metamask/superstruct" "^3.1.0" + "@noble/hashes" "^1.3.1" + "@scure/base" "^1.1.3" + "@types/debug" "^4.1.7" + debug "^4.3.4" + pony-cause "^2.1.10" + semver "^7.5.4" + uuid "^9.0.1" + +"@multiformats/base-x@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121" + integrity sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw== + +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + +"@noble/curves@1.4.2", "@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@noble/hashes@^1.3.1": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + +"@openzeppelin/contracts-v3@npm:@openzeppelin/contracts@3.2.0-rc.0": + version "3.2.0-rc.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.2.0-rc.0.tgz#1f39e49df5f7a7b42fd49343ac1d758bbd24b826" + integrity sha512-EcEho5UFNZN1ZUHuD5ka38qgs+XWlzBM1FFfpu4YNVoo0xtwWeg7X52jm8pK+NYq8tJAI8ySjGYPM+4S5+N8iA== + +"@openzeppelin/contracts@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" + integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== + +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + +"@scure/base@^1.1.3", "@scure/base@~1.1.3", "@scure/base@~1.1.6": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.8.tgz#8f23646c352f020c83bca750a82789e246d42b50" + integrity sha512-6CyAclxj3Nb0XT7GHK6K4zK6k2xJm6E4Ft0Ohjt4WgegiFUHEtFb2CGzmPmGBwoIhrLsqNLYfLr04Y1GePrzZg== + +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== + dependencies: + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@tornado/contracts@git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#1b1d707878c16a3dc60d295299d4f0e7ce6ba831": + version "1.0.2" + resolved "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#1b1d707878c16a3dc60d295299d4f0e7ce6ba831" + dependencies: + "@openzeppelin/contracts" "5.0.2" + "@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0" + ethers "^6.13.4" + +"@tornado/core@git+https://git.tornado.ws/tornadocontrib/tornado-core.git#94a62e6193c99457a8dfae0d8684bee299cb1097": + version "1.0.19" + resolved "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#94a62e6193c99457a8dfae0d8684bee299cb1097" + dependencies: + "@ensdomains/content-hash" "2.5.7" + "@metamask/eth-sig-util" "^8.0.0" + "@tornado/contracts" "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#1b1d707878c16a3dc60d295299d4f0e7ce6ba831" + "@tornado/fixed-merkle-tree" "^0.7.3" + "@tornado/snarkjs" "^0.1.20" + "@tornado/websnark" "^0.0.4" + ajv "^8.17.1" + bn.js "^5.2.1" + circomlibjs "0.1.7" + cross-fetch "^4.0.0" + ethers "^6.13.4" + ffjavascript "0.2.48" + fflate "^0.8.2" + idb "^8.0.0" + +"@tornado/fixed-merkle-tree@^0.7.3": + version "0.7.3" + resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ffixed-merkle-tree/-/0.7.3/fixed-merkle-tree-0.7.3.tgz#6636ce9d334553c5f17e5a564fd22f2e9ec04472" + integrity sha512-8UWvIzz0/rMGBkzXACwmCv/5I1VJmnshAKc4C+nkTfOdmnX8Pf1bBa0GlxUIZ25ZFGiU/h2IKEHYckmHovwzEA== + +"@tornado/snarkjs@^0.1.20": + version "0.1.20" + resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fsnarkjs/-/0.1.20/snarkjs-0.1.20.tgz#d7610cd3c8dc10598da7dc3e40e5d7470c3aa8c7" + integrity sha512-mn+ePoQjqOHyDyK8AMy8SXYqNSxJWVswWVmMYvuc75/9bBtJ7SNtwrTByxmfWjrf4S3BM3IrGfHqBHEXY6gR4Q== + dependencies: + big-integer "^1.6.43" + chai "^4.2.0" + escape-string-regexp "^1.0.5" + eslint "^5.16.0" + keccak "^2.0.0" + yargs "^12.0.5" + +"@tornado/websnark@^0.0.4": + version "0.0.4" + resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fwebsnark/-/0.0.4/websnark-0.0.4.tgz#4c603259b71172225a70e3d454344fa172710970" + integrity sha512-dHbaS41ILPq5NyVBDW8AmUPoSKvamtkTeIhyuKKmoyOrZMAUhJ9y1B2zRcejUKfhCZkIjAgCt9bvdzdOGGswwQ== + dependencies: + "@tornado/snarkjs" "^0.1.20" + big-integer "1.6.42" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@typechain/ethers-v6@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz#42fe214a19a8b687086c93189b301e2b878797ea" + integrity sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + +"@types/debug@^4.1.7": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== + dependencies: + "@types/ms" "*" + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/ms@*": + version "0.7.34" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" + integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== + +"@types/node@22.7.5", "@types/node@^22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + +"@types/prettier@^2.1.1": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + +"@typescript-eslint/eslint-plugin@^8.9.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz#c3f087d20715fa94310b30666c08b3349e0ab084" + integrity sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.11.0" + "@typescript-eslint/type-utils" "8.11.0" + "@typescript-eslint/utils" "8.11.0" + "@typescript-eslint/visitor-keys" "8.11.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^8.9.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.11.0.tgz#2ad1481388dc1c937f50b2d138c9ca57cc6c5cce" + integrity sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg== + dependencies: + "@typescript-eslint/scope-manager" "8.11.0" + "@typescript-eslint/types" "8.11.0" + "@typescript-eslint/typescript-estree" "8.11.0" + "@typescript-eslint/visitor-keys" "8.11.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz#9d399ce624118966732824878bc9a83593a30405" + integrity sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ== + dependencies: + "@typescript-eslint/types" "8.11.0" + "@typescript-eslint/visitor-keys" "8.11.0" + +"@typescript-eslint/type-utils@8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz#b7f9e6120c1ddee8a1a07615646642ad85fc91b5" + integrity sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg== + dependencies: + "@typescript-eslint/typescript-estree" "8.11.0" + "@typescript-eslint/utils" "8.11.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.11.0.tgz#7c766250502097f49bbc2e651132e6bf489e20b8" + integrity sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw== + +"@typescript-eslint/typescript-estree@8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz#35fe5d3636fc5727c52429393415412e552e222b" + integrity sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg== + dependencies: + "@typescript-eslint/types" "8.11.0" + "@typescript-eslint/visitor-keys" "8.11.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.11.0.tgz#4480d1e9f2bb18ea3510c79f870a1aefc118103d" + integrity sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.11.0" + "@typescript-eslint/types" "8.11.0" + "@typescript-eslint/typescript-estree" "8.11.0" + +"@typescript-eslint/visitor-keys@8.11.0": + version "8.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz#273de1cbffe63d9f9cd7dfc20b5a5af66310cb92" + integrity sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw== + dependencies: + "@typescript-eslint/types" "8.11.0" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@zxing/text-encoding@0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" + integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abstract-logging@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" + integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== + +acorn-jsx@^5.0.0, acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^6.0.7: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + +ajv-formats@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== + dependencies: + ajv "^8.0.0" + +ajv@^6.10.2, ajv@^6.12.4, ajv@^6.9.1: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.12.0, ajv@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + is-string "^1.0.7" + +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async@^3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +avvio@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/avvio/-/avvio-9.0.0.tgz#3ae02fb318377006e0e06a3f47842c98d8668607" + integrity sha512-UbYrOXgE/I+knFG+3kJr9AgC7uNo8DG+FGGODpH9Bj1O1kL/QDjBXnTem9leD3VdQKtaHjV3O85DQ7hHh4IIHw== + dependencies: + "@fastify/error" "^4.0.0" + fastq "^1.17.1" + +b4a@^1.0.1: + version "1.6.6" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.6.tgz#a4cc349a3851987c3c4ac2d7785c18744f6da9ba" + integrity sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.8: + version "3.0.10" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.10.tgz#62de58653f8762b5d6f8d9fe30fa75f7b2585a75" + integrity sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +big-integer@1.6.42: + version "1.6.42" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.42.tgz#91623ae5ceeff9a47416c56c9440a66f12f534f1" + integrity sha512-3UQFKcRMx+5Z+IK5vYTMYK2jzLRJkt+XqyDdacgWgtMjjuifKpKTFneJLEgeBElOE2/lXZ1LcMcb5s8pwG2U8Q== + +big-integer@^1.6.42, big-integer@^1.6.43, big-integer@^1.6.48: + version "1.6.52" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +blake-hash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/blake-hash/-/blake-hash-2.0.0.tgz#af184dce641951126d05b7d1c3de3224f538d66e" + integrity sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w== + dependencies: + node-addon-api "^3.0.0" + node-gyp-build "^4.2.2" + readable-stream "^3.6.0" + +blake2b-wasm@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz#9115649111edbbd87eb24ce7c04b427e4e2be5be" + integrity sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w== + dependencies: + b4a "^1.0.1" + nanoassert "^2.0.0" + +blake2b@^2.1.3: + version "2.1.4" + resolved "https://registry.yarnpkg.com/blake2b/-/blake2b-2.1.4.tgz#817d278526ddb4cd673bfb1af16d1ad61e393ba3" + integrity sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A== + dependencies: + blake2b-wasm "^2.4.0" + nanoassert "^2.0.0" + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bloomfilter.js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bloomfilter.js/-/bloomfilter.js-1.0.2.tgz#63449e4b055dc08e5e4db75367d48cc0a395e704" + integrity sha512-x3SG+7/NlT5m6hHy1GCerNoWm38kxWZeUIsBs1LaMwnTLM0hidmGalhAfXH07DtP3s9QAp+JAQagpgVIxtUl9g== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +chai@^4.2.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +chalk@^2.1.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +cids@^1.1.5: + version "1.1.9" + resolved "https://registry.yarnpkg.com/cids/-/cids-1.1.9.tgz#402c26db5c07059377bcd6fb82f2a24e7f2f4a4f" + integrity sha512-l11hWRfugIcbGuTZwAM5PwpjPPjyb6UZOGwlHSnOBV5o07XhQ4gNpBN67FbODvpjyHtd+0Xs6KNvUcGBiDRsdg== + dependencies: + multibase "^4.0.1" + multicodec "^3.0.1" + multihashes "^4.0.1" + uint8arrays "^3.0.0" + +circomlibjs@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/circomlibjs/-/circomlibjs-0.1.7.tgz#9f5a7d9a23323744b11ee456b05b0cd81f48b554" + integrity sha512-GRAUoAlKAsiiTa+PA725G9RmEmJJRc8tRFxw/zKktUxlQISGznT4hH4ESvW8FNTsrGg/nNd06sGP/Wlx0LUHVg== + dependencies: + blake-hash "^2.0.0" + blake2b "^2.1.3" + ethers "^5.5.1" + ffjavascript "^0.2.45" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.1.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cookie@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-require@^1.1.0: + version "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.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== + dependencies: + node-fetch "^2.6.12" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== + dependencies: + type-detect "^4.0.0" + +deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.15.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" + integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.5" + enhanced-resolve "^5.15.0" + eslint-module-utils "^2.8.1" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" + is-glob "^4.0.3" + +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== + dependencies: + debug "^3.2.7" + +eslint-module-utils@^2.8.1: + version "2.11.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz#b99b211ca4318243f09661fae088f373ad5243c4" + integrity sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + string.prototype.trimend "^1.0.8" + tsconfig-paths "^3.15.0" + +eslint-plugin-prettier@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95" + integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.9.1" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^1.3.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@8.57.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +eslint@^5.16.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1, esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0, esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" + integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== + dependencies: + "@noble/curves" "1.4.2" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" + +ethers@^5.5.1: + version "5.7.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + +ethers@^6.13.4: + version "6.13.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c" + integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-json-stringify@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-6.0.0.tgz#15c5e85b567ead695773bf55938b56aaaa57d805" + integrity sha512-FGMKZwniMTgZh7zQp9b6XnBVxUmKVahQLQeRQHqwYmPDqDhcEKZ3BaQsxelFFI5PY7nN71OEeiL47/zUWcYe1A== + dependencies: + "@fastify/merge-json-schemas" "^0.1.1" + ajv "^8.12.0" + ajv-formats "^3.0.1" + fast-deep-equal "^3.1.3" + fast-uri "^2.3.0" + json-schema-ref-resolver "^1.0.1" + rfdc "^1.2.0" + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-querystring@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.2.tgz#a6d24937b4fc6f791b4ee31dcb6f53aeafb89f53" + integrity sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg== + dependencies: + fast-decode-uri-component "^1.0.1" + +fast-redact@^3.1.1: + version "3.5.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" + integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== + +fast-uri@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-2.4.0.tgz#67eae6fbbe9f25339d5d3f4c4234787b65d7d55e" + integrity sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA== + +fast-uri@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.2.tgz#d78b298cf70fd3b752fd951175a3da6a7b48f024" + integrity sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row== + +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + +fastify-plugin@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-5.0.1.tgz#82d44e6fe34d1420bb5a4f7bee434d501e41939f" + integrity sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ== + +fastify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-5.0.0.tgz#f8f80bd741bde2de1997c25dbe31e61c91978111" + integrity sha512-Qe4dU+zGOzg7vXjw4EvcuyIbNnMwTmcuOhlOrOJsgwzvjEZmsM/IeHulgJk+r46STjdJS/ZJbxO8N70ODXDMEQ== + dependencies: + "@fastify/ajv-compiler" "^4.0.0" + "@fastify/error" "^4.0.0" + "@fastify/fast-json-stringify-compiler" "^5.0.0" + abstract-logging "^2.0.1" + avvio "^9.0.0" + fast-json-stringify "^6.0.0" + find-my-way "^9.0.0" + light-my-request "^6.0.0" + pino "^9.0.0" + process-warning "^4.0.0" + proxy-addr "^2.0.7" + rfdc "^1.3.1" + secure-json-parse "^2.7.0" + semver "^7.6.0" + toad-cache "^3.7.0" + +fastq@^1.17.1, fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +ffjavascript@0.2.48: + version "0.2.48" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.48.tgz#0ca408471d7b18bfc096a9631aa3ef3549c8c82b" + integrity sha512-uNrWP+odLofNmmO+iCCPi/Xt/sJh1ku3pVKmKWVWCLFfdCP69hvRrogKUIGnsdiINcWn0lGxcEh5oEjStMFXQQ== + dependencies: + big-integer "^1.6.48" + wasmbuilder "^0.0.12" + wasmcurves "0.1.0" + web-worker "^1.2.0" + +ffjavascript@^0.2.45: + version "0.2.63" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.63.tgz#0c1216a1f123dc9181df69e144473704d2f115eb" + integrity sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A== + dependencies: + wasmbuilder "0.0.16" + wasmcurves "0.2.2" + web-worker "1.2.0" + +fflate@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-my-way@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-9.1.0.tgz#df941d61198b6380bc962250652c2dff43468880" + integrity sha512-Y5jIsuYR4BwWDYYQ2A/RWWE6gD8a0FMgtU+HOq1WKku+Cwdz8M1v8wcAmRXXM1/iqtoqg06v+LjAxMYbCjViMw== + dependencies: + fast-deep-equal "^3.1.3" + fast-querystring "^1.0.0" + safe-regex2 "^4.0.0" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2, glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +idb@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/idb/-/idb-8.0.0.tgz#33d7ed894ed36e23bcb542fb701ad579bfaad41f" + integrity sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw== + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^6.2.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-bun-module@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.2.1.tgz#495e706f42e29f086fd5fe1ac3c51f106062b9fc" + integrity sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q== + dependencies: + semver "^7.6.3" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== + +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.13, is-typed-array@^1.1.3: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-base64@^3.6.0: + version "3.7.7" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79" + integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw== + +js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-ref-resolver@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz#6586f483b76254784fc1d2120f717bdc9f0a99bf" + integrity sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw== + dependencies: + fast-deep-equal "^3.1.3" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +keccak@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-2.1.0.tgz#734ea53f2edcfd0f42cdb8d5f4c358fef052752b" + integrity sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q== + dependencies: + bindings "^1.5.0" + inherits "^2.0.4" + nan "^2.14.0" + safe-buffer "^5.2.0" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +light-my-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-6.0.0.tgz#97c6d0d5448ea2fc37836f0aefe94298f5a87dde" + integrity sha512-kFkFXrmKCL0EEeOmJybMH5amWFd+AFvlvMlvFTRxCUwbhfapZqDmeLMPoWihntnYY6JpoQDE9k+vOzObF1fDqg== + dependencies: + cookie "^0.6.0" + process-warning "^4.0.0" + set-cookie-parser "^2.6.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +logform@^2.6.0, logform@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" + integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mnemonist@0.39.8: + version "0.39.8" + resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.39.8.tgz#9078cd8386081afd986cca34b52b5d84ea7a4d38" + integrity sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ== + dependencies: + obliterator "^2.0.1" + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multibase@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-2.0.0.tgz#e20a2a14813fa435dc69c702909209ac0741919e" + integrity sha512-xIrqUVsinSlFjqj+OtEgCJ6MRl5hXjHMBPWsUt1ZGSRMx8rzm+7hCLE4wDeSA3COomlUC9zHCoUlvWjvAMtfDg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + web-encoding "^1.0.2" + +multibase@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.6.tgz#6e624341483d6123ca1ede956208cb821b440559" + integrity sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ== + dependencies: + "@multiformats/base-x" "^4.0.1" + +multicodec@^3.0.1, multicodec@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-3.2.1.tgz#82de3254a0fb163a107c1aab324f2a91ef51efb2" + integrity sha512-+expTPftro8VAW8kfvcuNNNBgb9gPeNYV9dn+z1kJRWF2vih+/S79f2RVeIwmrJBUJ6NT9IUPWnZDQvegEh5pw== + dependencies: + uint8arrays "^3.0.0" + varint "^6.0.0" + +multiformats@^9.4.2: + version "9.9.0" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" + integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== + +multihashes@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-2.0.0.tgz#4fa599d2d726ec6de33bf1e6f6d9f04b2351ace9" + integrity sha512-Mp94Y+7h3oWQx8JickVghlWR6VhRPDnlv/KZEUyNP0ISSkNEe3kQkWoyIGt1B45D6cTLoulg+MP6bugVewx32Q== + dependencies: + buffer "^5.6.0" + multibase "^2.0.0" + varint "^5.0.0" + web-encoding "^1.0.2" + +multihashes@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-4.0.3.tgz#426610539cd2551edbf533adeac4c06b3b90fb05" + integrity sha512-0AhMH7Iu95XjDLxIeuCOOE4t9+vQZsACyKZ9Fxw2pcsRmlX4iCn1mby0hS0bb+nQOVpdQYWPpnyusw4da5RPhA== + dependencies: + multibase "^4.0.1" + uint8arrays "^3.0.0" + varint "^5.0.2" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ== + +nan@^2.14.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== + +nanoassert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-2.0.0.tgz#a05f86de6c7a51618038a620f88878ed1e490c09" + integrity sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-addon-api@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-fetch@^2.6.12: + 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.2: + version "4.8.2" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa" + integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +obliterator@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" + integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== + +on-exit-leak-free@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" + integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picocolors@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pino-abstract-transport@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz#97f9f2631931e242da531b5c66d3079c12c9d1b5" + integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q== + dependencies: + readable-stream "^4.0.0" + split2 "^4.0.0" + +pino-std-serializers@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b" + integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== + +pino@^9.0.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-9.4.0.tgz#e4600ff199efc744856a5b3b71c53e38998eae5a" + integrity sha512-nbkQb5+9YPhQRz/BeQmrWpEknAaqjpAqRK8NwJpmrX/JHu7JuZC5G1CeAwJDJfGes4h+YihC6in3Q2nGb+Y09w== + dependencies: + atomic-sleep "^1.0.0" + fast-redact "^3.1.1" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^1.2.0" + pino-std-serializers "^7.0.0" + process-warning "^4.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + sonic-boom "^4.0.1" + thread-stream "^3.0.0" + +pony-cause@^2.1.10: + version "2.1.11" + resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.11.tgz#d69a20aaccdb3bdb8f74dd59e5c68d8e6772e4bd" + integrity sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg== + +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.3.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + +process-warning@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.0.tgz#581e3a7a1fb456c5f4fd239f76bce75897682d5a" + integrity sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +pump@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + +readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^4.0.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" + integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + dependencies: + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.5.0.tgz#30a4d38a7e704bd96dc5ffcbe7ce2a9274c41c95" + integrity sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.2.0, rfdc@^1.3.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-async@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^6.4.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@^5.0.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" + +safe-regex2@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-4.0.0.tgz#5e04d8362cd4884753c8bce9715d4759a5239c0a" + integrity sha512-Hvjfv25jPDVr3U+4LDzBuZPPOymELG3PYcSk5hcevooo1yxxamQL/bHs/GrEPGmMoMEwRrHVGiCA1pXi97B8Ew== + dependencies: + ret "~0.5.0" + +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secure-json-parse@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" + integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== + +semver@^5.5.0, semver@^5.5.1: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-cookie-parser@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz#ef5552b56dc01baae102acb5fc9fb8cd060c30f9" + integrity sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sonic-boom@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.1.0.tgz#4f039663ba191fac5cfe4f1dc330faac079e4342" + integrity sha512-NGipjjRicyJJ03rPiZCJYjwlsuP2d1/5QUviozRXC7S3WdVWNK5e3Ojieb9CCyfhq2UC+3+SRd9nG3I2lPRvUw== + dependencies: + atomic-sleep "^1.0.0" + +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + +string-format@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" + integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@6.0.1, strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@^4.0.0, strip-ansi@^5.1.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== + +strip-json-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +synckit@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.1.tgz#febbfbb6649979450131f64735aa3f6c14575c88" + integrity sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thread-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-3.1.0.tgz#4b2ef252a7c215064507d4ef70c05a5e2d34c4f1" + integrity sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A== + dependencies: + real-require "^0.2.0" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toad-cache@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/toad-cache/-/toad-cache-3.7.0.tgz#b9b63304ea7c45ec34d91f1d2fa513517025c441" + integrity sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +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" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-command-line-args@^2.2.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" + integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== + dependencies: + chalk "^4.1.0" + command-line-args "^5.1.1" + command-line-usage "^6.1.0" + string-format "^2.0.0" + +ts-essentials@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" + integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== + +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@2.7.0, tslib@^2.6.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typechain@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.3.2.tgz#1090dd8d9c57b6ef2aed3640a516bdbf01b00d73" + integrity sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q== + dependencies: + "@types/prettier" "^2.1.1" + debug "^4.3.1" + fs-extra "^7.0.0" + glob "7.1.7" + js-sha3 "^0.8.0" + lodash "^4.17.15" + mkdirp "^1.0.4" + prettier "^2.3.1" + ts-command-line-args "^2.2.0" + ts-essentials "^7.0.1" + +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + +typescript@^5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +uint8arrays@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" + integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg== + dependencies: + multiformats "^9.4.2" + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util@^0.12.3: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +varint@^5.0.0, varint@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== + +varint@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" + integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== + +wasmbuilder@0.0.16: + version "0.0.16" + resolved "https://registry.yarnpkg.com/wasmbuilder/-/wasmbuilder-0.0.16.tgz#f34c1f2c047d2f6e1065cbfec5603988f16d8549" + integrity sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA== + +wasmbuilder@^0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/wasmbuilder/-/wasmbuilder-0.0.12.tgz#a60cb25d6d11f314fe5ab3f4ee041ccb493cb78a" + integrity sha512-dTMpBgrnLOXrN58i2zakn2ScynsBhq9LfyQIsPz4CyxRF9k1GAORniuqn3xmE9NnI1l7g3iiVCkoB2Cl0/oG8w== + dependencies: + big-integer "^1.6.48" + +wasmcurves@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.1.0.tgz#0bc3f9d465367fcd8243395cb0094a05577e5609" + integrity sha512-kIlcgbVUAv2uQ6lGsepGz/m5V40+Z6rvTBkqCYn3Y2+OcXst+UaP4filJYLh/xDxjJl62FFjZZeAnpeli1Y5/Q== + dependencies: + big-integer "^1.6.42" + blakejs "^1.1.0" + +wasmcurves@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.2.tgz#ca444f6a6f6e2a5cbe6629d98ff478a62b4ccb2b" + integrity sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ== + dependencies: + wasmbuilder "0.0.16" + +web-encoding@^1.0.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" + integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== + dependencies: + util "^0.12.3" + optionalDependencies: + "@zxing/text-encoding" "0.9.0" + +web-worker@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da" + integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA== + +web-worker@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.3.0.tgz#e5f2df5c7fe356755a5fb8f8410d4312627e6776" + integrity sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA== + +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== + +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" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +winston-transport@^4.7.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.1.tgz#52ff1bcfe452ad89991a0aaff9c3b18e7f392569" + integrity sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA== + dependencies: + logform "^2.6.1" + readable-stream "^3.6.2" + triple-beam "^1.3.0" + +winston@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.14.2.tgz#94ce5fd26d374f563c969d12f0cd9c641065adab" + integrity sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.6.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + +word-wrap@^1.2.5, word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +"y18n@^3.2.1 || ^4.0.0": + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==