es2022, use interfaces, minor func addition

This commit is contained in:
Tornado Contrib 2024-10-16 14:17:22 +00:00
parent 4f0aaea790
commit 666b0eba66
Signed by: tornadocontrib
GPG Key ID: 60B4DF1A076C64B1
21 changed files with 500 additions and 298 deletions

@ -32,7 +32,7 @@
], ],
"dependencies": { "dependencies": {
"@metamask/eth-sig-util": "^7.0.3", "@metamask/eth-sig-util": "^7.0.3",
"@tornado/contracts": "^1.0.1", "@tornado/contracts": "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4",
"@tornado/fixed-merkle-tree": "^0.7.3", "@tornado/fixed-merkle-tree": "^0.7.3",
"@tornado/snarkjs": "^0.1.20", "@tornado/snarkjs": "^0.1.20",
"@tornado/websnark": "^0.0.4", "@tornado/websnark": "^0.0.4",
@ -40,13 +40,13 @@
"bn.js": "^5.2.1", "bn.js": "^5.2.1",
"circomlibjs": "0.1.7", "circomlibjs": "0.1.7",
"cross-fetch": "^4.0.0", "cross-fetch": "^4.0.0",
"ethers": "^6.13.3", "ethers": "^6.13.4",
"ffjavascript": "0.2.48", "ffjavascript": "0.2.48",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"idb": "^8.0.0" "idb": "^8.0.0"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.3.0",
"@typechain/ethers-v6": "^0.5.1", "@typechain/ethers-v6": "^0.5.1",
@ -54,8 +54,8 @@
"@types/circomlibjs": "^0.1.6", "@types/circomlibjs": "^0.1.6",
"@types/node": "^22.7.5", "@types/node": "^22.7.5",
"@types/node-fetch": "^2.6.11", "@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^8.8.1", "@typescript-eslint/eslint-plugin": "^8.9.0",
"@typescript-eslint/parser": "^8.8.1", "@typescript-eslint/parser": "^8.9.0",
"esbuild-loader": "^4.2.2", "esbuild-loader": "^4.2.2",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",

@ -33,7 +33,7 @@ const config = [
include: /\.[jt]sx?$/, include: /\.[jt]sx?$/,
minify: false, minify: false,
sourceMap: true, sourceMap: true,
target: 'es2016', target: 'es2022',
}), }),
commonjs(), commonjs(),
nodeResolve(), nodeResolve(),
@ -54,7 +54,7 @@ const config = [
include: /\.[jt]sx?$/, include: /\.[jt]sx?$/,
minify: false, minify: false,
sourceMap: true, sourceMap: true,
target: 'es2016', target: 'es2022',
}), }),
nodeResolve(), nodeResolve(),
json() json()
@ -75,7 +75,7 @@ const config = [
include: /\.[jt]sx?$/, include: /\.[jt]sx?$/,
minify: false, minify: false,
sourceMap: true, sourceMap: true,
target: 'es2016', target: 'es2022',
}), }),
commonjs(), commonjs(),
nodeResolve(), nodeResolve(),

@ -225,11 +225,11 @@ export type BatchEventOnProgress = ({
}) => void; }) => void;
// To enable iteration only numbers are accepted for fromBlock input // To enable iteration only numbers are accepted for fromBlock input
export type EventInput = { export interface EventInput {
fromBlock: number; fromBlock: number;
toBlock: number; toBlock: number;
type: ContractEventName; type: ContractEventName;
}; }
/** /**
* Fetch events from web3 provider on bulk * Fetch events from web3 provider on bulk

@ -2,44 +2,34 @@ import { bnToBytes, bytesToBN, leBuff2Int, leInt2Buff, rBigInt, toFixedHex } fro
import { buffPedersenHash } from './pedersen'; import { buffPedersenHash } from './pedersen';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
export type DepositType = { export interface DepositType {
currency: string; currency: string;
amount: string; amount: string;
netId: NetIdType; netId: NetIdType;
}; }
export type createDepositParams = { export interface createDepositParams {
nullifier: bigint; nullifier: bigint;
secret: bigint; secret: bigint;
}; }
export type createDepositObject = { export interface createDepositObject {
preimage: Uint8Array; preimage: Uint8Array;
noteHex: string; noteHex: string;
commitment: bigint; commitment: bigint;
commitmentHex: string; commitmentHex: string;
nullifierHash: bigint; nullifierHash: bigint;
nullifierHex: string; nullifierHex: string;
}; }
export type createNoteParams = DepositType & { export interface createNoteParams extends DepositType {
nullifier?: bigint; nullifier?: bigint;
secret?: bigint; secret?: bigint;
}; }
export type parsedNoteExec = DepositType & { export interface parsedNoteExec extends DepositType {
note: string; note: string;
}; }
export type depositTx = {
from: string;
transactionHash: string;
};
export type withdrawalTx = {
to: string;
transactionHash: string;
};
export async function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject> { export async function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject> {
const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]); const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]);
@ -199,9 +189,9 @@ export class Deposit {
} }
} }
export type parsedInvoiceExec = DepositType & { export interface parsedInvoiceExec extends DepositType {
commitment: string; commitment: string;
}; }
export class Invoice { export class Invoice {
currency: string; currency: string;

@ -55,17 +55,17 @@ import type {
export const DEPOSIT = 'deposit'; export const DEPOSIT = 'deposit';
export const WITHDRAWAL = 'withdrawal'; export const WITHDRAWAL = 'withdrawal';
export type BaseEventsServiceConstructor = { export interface BaseEventsServiceConstructor {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
graphApi?: string; graphApi?: string;
subgraphName?: string; subgraphName?: string;
contract: BaseContract; contract: BaseContract;
type?: string; type: string;
deployedBlock?: number; deployedBlock?: number;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient; tovarishClient?: TovarishClient;
}; }
export type BatchGraphOnProgress = ({ export type BatchGraphOnProgress = ({
type, type,
@ -79,12 +79,12 @@ export type BatchGraphOnProgress = ({
count?: number; count?: number;
}) => void; }) => void;
export type BaseGraphParams = { export interface BaseGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
onProgress?: BatchGraphOnProgress; onProgress?: BatchGraphOnProgress;
}; }
export class BaseEventsService<EventType extends MinimalEvents> { export class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType; netId: NetIdType;
@ -347,31 +347,22 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
} }
export type BaseTornadoServiceConstructor = { export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Tornado: Tornado; Tornado: Tornado;
type: string;
amount: string; amount: string;
currency: string; currency: string;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export type DepositsGraphParams = BaseGraphParams & { export interface DepositsGraphParams extends BaseGraphParams {
amount: string; amount: string;
currency: string; currency: string;
}; }
export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> { export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string; amount: string;
currency: string; currency: string;
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService; batchBlockService: BatchBlockService;
tovarishClient?: TovarishClient;
constructor({ constructor({
netId, netId,
@ -520,16 +511,9 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
} }
} }
export type BaseEchoServiceConstructor = { export interface BaseEchoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Echoer: Echoer; Echoer: Echoer;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseEchoService extends BaseEventsService<EchoEvents> { export class BaseEchoService extends BaseEventsService<EchoEvents> {
constructor({ constructor({
@ -548,6 +532,7 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
graphApi, graphApi,
subgraphName, subgraphName,
contract: Echoer, contract: Echoer,
type: 'Echo',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -558,10 +543,6 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
return `echo_${this.netId}`; return `echo_${this.netId}`;
} }
getType(): string {
return 'Echo';
}
getGraphMethod(): string { getGraphMethod(): string {
return 'getAllGraphEchoEvents'; return 'getAllGraphEchoEvents';
} }
@ -601,16 +582,9 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
} }
} }
export type BaseEncryptedNotesServiceConstructor = { export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Router: TornadoRouter | TornadoProxyLight; Router: TornadoRouter | TornadoProxyLight;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> { export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
constructor({ constructor({
@ -629,6 +603,7 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
graphApi, graphApi,
subgraphName, subgraphName,
contract: Router, contract: Router,
type: 'EncryptedNote',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -639,10 +614,6 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
return `encrypted_notes_${this.netId}`; return `encrypted_notes_${this.netId}`;
} }
getType(): string {
return 'EncryptedNote';
}
getTovarishType(): string { getTovarishType(): string {
return 'encrypted_notes'; return 'encrypted_notes';
} }
@ -673,16 +644,9 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
} }
} }
export type BaseGovernanceServiceConstructor = { export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Governance: Governance; Governance: Governance;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> { export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
@ -703,6 +667,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
graphApi, graphApi,
subgraphName, subgraphName,
contract: Governance, contract: Governance,
type: '*',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -718,10 +683,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
return `governance_${this.netId}`; return `governance_${this.netId}`;
} }
getType() {
return '*';
}
getTovarishType(): string { getTovarishType(): string {
return 'governance'; return 'governance';
} }
@ -841,7 +802,7 @@ export async function getTovarishNetworks(registryService: BaseRegistryService,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
timeout: 60000, timeout: 30000,
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0, maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0,
}); });
} catch { } catch {
@ -888,18 +849,11 @@ export interface CachedRelayers {
fromCache?: boolean; fromCache?: boolean;
} }
export type BaseRegistryServiceConstructor = { export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseRegistryService extends BaseEventsService<RegistersEvents> { export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
Aggregator: Aggregator; Aggregator: Aggregator;
@ -924,6 +878,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
graphApi, graphApi,
subgraphName, subgraphName,
contract: RelayerRegistry, contract: RelayerRegistry,
type: 'RelayerRegistered',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -939,11 +894,6 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
return `registered_${this.netId}`; return `registered_${this.netId}`;
} }
// Name of type used for events
getType() {
return 'RelayerRegistered';
}
getTovarishType(): string { getTovarishType(): string {
return 'registered'; return 'registered';
} }

@ -20,37 +20,37 @@ export interface MinimalEvents {
transactionHash: string; transactionHash: string;
} }
export type GovernanceEvents = MinimalEvents & { export interface GovernanceEvents extends MinimalEvents {
event: string; event: string;
}; }
export type GovernanceProposalCreatedEvents = GovernanceEvents & { export interface GovernanceProposalCreatedEvents extends GovernanceEvents {
id: number; id: number;
proposer: string; proposer: string;
target: string; target: string;
startTime: number; startTime: number;
endTime: number; endTime: number;
description: string; description: string;
}; }
export type GovernanceVotedEvents = GovernanceEvents & { export interface GovernanceVotedEvents extends GovernanceEvents {
proposalId: number; proposalId: number;
voter: string; voter: string;
support: boolean; support: boolean;
votes: string; votes: string;
from: string; from: string;
input: string; input: string;
}; }
export type GovernanceDelegatedEvents = GovernanceEvents & { export interface GovernanceDelegatedEvents extends GovernanceEvents {
account: string; account: string;
delegateTo: string; delegateTo: string;
}; }
export type GovernanceUndelegatedEvents = GovernanceEvents & { export interface GovernanceUndelegatedEvents extends GovernanceEvents {
account: string; account: string;
delegateFrom: string; delegateFrom: string;
}; }
export type AllGovernanceEvents = export type AllGovernanceEvents =
| GovernanceProposalCreatedEvents | GovernanceProposalCreatedEvents
@ -60,25 +60,25 @@ export type AllGovernanceEvents =
export type RegistersEvents = MinimalEvents & RelayerParams; export type RegistersEvents = MinimalEvents & RelayerParams;
export type DepositsEvents = MinimalEvents & { export interface DepositsEvents extends MinimalEvents {
commitment: string; commitment: string;
leafIndex: number; leafIndex: number;
timestamp: number; timestamp: number;
from: string; from: string;
}; }
export type WithdrawalsEvents = MinimalEvents & { export interface WithdrawalsEvents extends MinimalEvents {
nullifierHash: string; nullifierHash: string;
to: string; to: string;
fee: string; fee: string;
timestamp: number; timestamp: number;
}; }
export type EchoEvents = MinimalEvents & { export interface EchoEvents extends MinimalEvents {
address: string; address: string;
encryptedAccount: string; encryptedAccount: string;
}; }
export type EncryptedNotesEvents = MinimalEvents & { export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string; encryptedNote: string;
}; }

54
src/gaszip.ts Normal file

@ -0,0 +1,54 @@
import { isAddress } from 'ethers';
import { NetId, NetIdType } from './networkConfig';
// https://dev.gas.zip/gas/chain-support/inbound
export const gasZipInbounds: { [key in NetIdType]: string } = {
[NetId.MAINNET]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.BSC]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.POLYGON]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.OPTIMISM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.ARBITRUM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.GNOSIS]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.AVALANCHE]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
};
// https://dev.gas.zip/gas/chain-support/outbound
export const gasZipID: { [key in NetIdType]: number } = {
[NetId.MAINNET]: 255,
[NetId.BSC]: 14,
[NetId.POLYGON]: 17,
[NetId.OPTIMISM]: 55,
[NetId.ARBITRUM]: 57,
[NetId.GNOSIS]: 16,
[NetId.AVALANCHE]: 15,
[NetId.SEPOLIA]: 102,
};
// https://dev.gas.zip/gas/code-examples/eoaDeposit
export function gasZipInput(to: string, shorts: number[]): string | null {
let data = '0x';
if (isAddress(to)) {
if (to.length === 42) {
data += '02';
data += to.slice(2);
} else {
return null;
}
} else {
data += '01'; // to == sender
}
for (const i in shorts) {
data += '0x' + Number(shorts[i]).toString(16).slice(2).padStart(4, '0');
}
return data;
}
export function gasZipMinMax(ethUsd: number) {
return {
min: 1 / ethUsd,
max: 50 / ethUsd,
ethUsd,
};
}

@ -34,7 +34,7 @@ const isEmptyArray = (arr: object) => !Array.isArray(arr) || !arr.length;
// https://thegraph.com/docs/en/developing/developer-faqs/#23-is-there-a-limit-to-how-many-objects-the-graph-can-return-per-query // https://thegraph.com/docs/en/developing/developer-faqs/#23-is-there-a-limit-to-how-many-objects-the-graph-can-return-per-query
const GRAPHQL_LIMIT = 1000; const GRAPHQL_LIMIT = 1000;
export type queryGraphParams = { export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
query: string; query: string;
@ -42,7 +42,7 @@ export type queryGraphParams = {
[key: string]: string | number; [key: string]: string | number;
}; };
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
}; }
export async function queryGraph<T>({ export async function queryGraph<T>({
graphApi, graphApi,

@ -6,6 +6,7 @@ export * from './batch';
export * from './deposits'; export * from './deposits';
export * from './encryptedNotes'; export * from './encryptedNotes';
export * from './fees'; export * from './fees';
export * from './gaszip';
export * from './idb'; export * from './idb';
export * from './merkleTree'; export * from './merkleTree';
export * from './mimc'; export * from './mimc';

@ -7,13 +7,13 @@ import type { DepositType } from './deposits';
import type { DepositsEvents } from './events'; import type { DepositsEvents } from './events';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
export type MerkleTreeConstructor = DepositType & { export interface MerkleTreeConstructor extends DepositType {
Tornado: Tornado; Tornado: Tornado;
commitmentHex?: string; commitmentHex?: string;
merkleTreeHeight?: number; merkleTreeHeight?: number;
emptyElement?: string; emptyElement?: string;
merkleWorkerPath?: string; merkleWorkerPath?: string;
}; }
export class MerkleTreeService { export class MerkleTreeService {
currency: string; currency: string;

@ -19,22 +19,22 @@ export interface RpcUrl {
url: string; url: string;
} }
export type RpcUrls = { export interface RpcUrls {
[key in string]: RpcUrl; [key: string]: RpcUrl;
}; }
export interface SubgraphUrl { export interface SubgraphUrl {
name: string; name: string;
url: string; url: string;
} }
export type SubgraphUrls = { export interface SubgraphUrls {
[key in string]: SubgraphUrl; [key: string]: SubgraphUrl;
}; }
export type TornadoInstance = { export interface TornadoInstance {
instanceAddress: { instanceAddress: {
[key in string]: string; [key: string]: string;
}; };
optionalInstances?: string[]; optionalInstances?: string[];
tokenAddress?: string; tokenAddress?: string;
@ -42,13 +42,13 @@ export type TornadoInstance = {
symbol: string; symbol: string;
decimals: number; decimals: number;
gasLimit?: number; gasLimit?: number;
}; }
export type TokenInstances = { export interface TokenInstances {
[key in string]: TornadoInstance; [key: string]: TornadoInstance;
}; }
export type Config = { export interface Config {
rpcCallRetryAttempt?: number; rpcCallRetryAttempt?: number;
// Should be in gwei // Should be in gwei
gasPrices: { gasPrices: {
@ -68,6 +68,8 @@ export type Config = {
networkName: string; networkName: string;
deployedBlock: number; deployedBlock: number;
rpcUrls: RpcUrls; rpcUrls: RpcUrls;
// Contract Address of stablecoin token, used for fiat conversion
stablecoin: string;
multicallContract: string; multicallContract: string;
routerContract: string; routerContract: string;
echoContract: string; echoContract: string;
@ -97,15 +99,15 @@ export type Config = {
// Should be in seconds // Should be in seconds
MINING_BLOCK_TIME?: number; MINING_BLOCK_TIME?: number;
}; };
}; }
export type networkConfig = { export interface networkConfig {
[key in NetIdType]: Config; [key: NetIdType]: Config;
}; }
export type SubdomainMap = { export interface SubdomainMap {
[key in NetIdType]: string; [key: NetIdType]: string;
}; }
export const defaultConfig: networkConfig = { export const defaultConfig: networkConfig = {
[NetId.MAINNET]: { [NetId.MAINNET]: {
@ -140,11 +142,12 @@ export const defaultConfig: networkConfig = {
name: 'Stackup RPC', name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/ethereum-mainnet', url: 'https://public.stackup.sh/api/v1/node/ethereum-mainnet',
}, },
oneRPC: { oneRpc: {
name: '1RPC', name: '1RPC',
url: 'https://1rpc.io/eth', url: 'https://1rpc.io/eth',
}, },
}, },
stablecoin: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b', routerContract: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b',
echoContract: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42', echoContract: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42',
@ -258,6 +261,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Binance Smart Chain', networkName: 'Binance Smart Chain',
deployedBlock: 8158799, deployedBlock: 8158799,
stablecoin: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -281,7 +285,7 @@ export const defaultConfig: networkConfig = {
name: 'Stackup RPC', name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/bsc-mainnet', url: 'https://public.stackup.sh/api/v1/node/bsc-mainnet',
}, },
oneRPC: { oneRpc: {
name: '1RPC', name: '1RPC',
url: 'https://1rpc.io/bnb', url: 'https://1rpc.io/bnb',
}, },
@ -320,6 +324,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Polygon (Matic) Network', networkName: 'Polygon (Matic) Network',
deployedBlock: 16257962, deployedBlock: 16257962,
stablecoin: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -370,6 +375,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Optimism', networkName: 'Optimism',
deployedBlock: 2243689, deployedBlock: 2243689,
stablecoin: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -378,18 +384,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph', tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
optimism: { oneRpc: {
name: 'Optimism', name: '1RPC',
url: 'https://mainnet.optimism.io', url: 'https://1rpc.io/op',
}, },
stackup: { stackup: {
name: 'Stackup RPC', name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/optimism-mainnet', url: 'https://public.stackup.sh/api/v1/node/optimism-mainnet',
}, },
oneRpc: {
name: '1RPC',
url: 'https://1rpc.io/op',
},
}, },
tokens: { tokens: {
eth: { eth: {
@ -425,6 +427,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Arbitrum One', networkName: 'Arbitrum One',
deployedBlock: 3430648, deployedBlock: 3430648,
stablecoin: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -441,7 +444,7 @@ export const defaultConfig: networkConfig = {
url: 'https://public.stackup.sh/api/v1/node/arbitrum-one', url: 'https://public.stackup.sh/api/v1/node/arbitrum-one',
}, },
oneRpc: { oneRpc: {
name: '1rpc', name: '1RPC',
url: 'https://1rpc.io/arb', url: 'https://1rpc.io/arb',
}, },
}, },
@ -479,6 +482,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Gnosis Chain', networkName: 'Gnosis Chain',
deployedBlock: 17754561, deployedBlock: 17754561,
stablecoin: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -490,12 +494,8 @@ export const defaultConfig: networkConfig = {
name: 'Gnosis', name: 'Gnosis',
url: 'https://rpc.gnosischain.com', url: 'https://rpc.gnosischain.com',
}, },
blockPi: {
name: 'BlockPi',
url: 'https://gnosis.blockpi.network/v1/rpc/public',
},
oneRpc: { oneRpc: {
name: '1rpc', name: '1RPC',
url: 'https://1rpc.io/gnosis', url: 'https://1rpc.io/gnosis',
}, },
}, },
@ -533,6 +533,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Avalanche Mainnet', networkName: 'Avalanche Mainnet',
deployedBlock: 4429818, deployedBlock: 4429818,
stablecoin: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -540,14 +541,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph', tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
publicRpc: { oneRpc: {
name: 'Avalanche RPC', name: '1RPC',
url: 'https://api.avax.network/ext/bc/C/rpc',
},
oneRPC: {
name: 'OneRPC',
url: 'https://1rpc.io/avax/c', url: 'https://1rpc.io/avax/c',
}, },
stackup: {
name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/avalanche-mainnet',
},
}, },
tokens: { tokens: {
avax: { avax: {
@ -582,6 +583,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Ethereum Sepolia', networkName: 'Ethereum Sepolia',
deployedBlock: 5594395, deployedBlock: 5594395,
stablecoin: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee', routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -602,8 +604,8 @@ export const defaultConfig: networkConfig = {
name: 'Stackup', name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia', url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia',
}, },
onerpc: { oneRpc: {
name: '1rpc', name: '1RPC',
url: 'https://1rpc.io/sepolia', url: 'https://1rpc.io/sepolia',
}, },
ethpandaops: { ethpandaops: {

@ -1,6 +1,6 @@
import { parseEther, type Provider } from 'ethers'; import { formatEther, parseEther, type Provider } from 'ethers';
import type { OffchainOracle, Multicall } from './typechain'; import { ERC20__factory, OffchainOracle, Multicall } from './typechain';
import { multicall } from './multicall'; import { multicall, Call3 } from './multicall';
export class TokenPriceOracle { export class TokenPriceOracle {
oracle?: OffchainOracle; oracle?: OffchainOracle;
@ -13,6 +13,46 @@ export class TokenPriceOracle {
this.oracle = oracle; this.oracle = oracle;
} }
buildCalls(
tokens: {
tokenAddress: string;
decimals: number;
}[],
): Call3[] {
return tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
}));
}
buildStable(stablecoinAddress: string): Call3[] {
const stablecoin = ERC20__factory.connect(stablecoinAddress, this.provider);
return [
{
contract: stablecoin,
name: 'decimals',
},
{
contract: this.oracle,
name: 'getRateToEth',
params: [stablecoin.target, true],
},
];
}
async fetchPrice(tokenAddress: string, decimals: number): Promise<bigint> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(parseEther('0.0001')));
}
const price = await this.oracle.getRateToEth(tokenAddress, true);
return (price * BigInt(10 ** decimals)) / BigInt(10 ** 18);
}
async fetchPrices( async fetchPrices(
tokens: { tokens: {
tokenAddress: string; tokenAddress: string;
@ -24,17 +64,24 @@ export class TokenPriceOracle {
return new Promise((resolve) => resolve(tokens.map(() => parseEther('0.0001')))); return new Promise((resolve) => resolve(tokens.map(() => parseEther('0.0001'))));
} }
const prices = (await multicall( const prices = (await multicall(this.multicall, this.buildCalls(tokens))) as bigint[];
this.multicall,
tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
})),
)) as bigint[];
return prices.map((price, index) => { return prices.map((price, index) => {
return (price * BigInt(10 ** tokens[index].decimals)) / BigInt(10 ** 18); return (price * BigInt(10 ** tokens[index].decimals)) / BigInt(10 ** 18);
}); });
} }
async fetchEthUSD(stablecoinAddress: string): Promise<number> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(10000));
}
const [decimals, price] = await multicall(this.multicall, this.buildStable(stablecoinAddress));
// eth wei price of usdc token
const ethPrice = (price * BigInt(10n ** decimals)) / BigInt(10 ** 18);
return 1 / Number(formatEther(ethPrice));
}
} }

@ -371,12 +371,12 @@ export const populateTransaction = async (
return tx; return tx;
}; };
export type TornadoWalletOptions = { export interface TornadoWalletOptions {
gasPriceBump?: number; gasPriceBump?: number;
gasLimitBump?: number; gasLimitBump?: number;
gasFailover?: boolean; gasFailover?: boolean;
bumpNonce?: boolean; bumpNonce?: boolean;
}; }
export class TornadoWallet extends Wallet { export class TornadoWallet extends Wallet {
nonce?: number; nonce?: number;
@ -474,13 +474,13 @@ export type connectWalletFunc = (...args: any[]) => Promise<void>;
export type handleWalletFunc = (...args: any[]) => void; export type handleWalletFunc = (...args: any[]) => void;
/* eslint-enable @typescript-eslint/no-explicit-any */ /* eslint-enable @typescript-eslint/no-explicit-any */
export type TornadoBrowserProviderOptions = TornadoWalletOptions & { export interface TornadoBrowserProviderOptions extends TornadoWalletOptions {
netId?: NetIdType; netId?: NetIdType;
connectWallet?: connectWalletFunc; connectWallet?: connectWalletFunc;
handleNetworkChanges?: handleWalletFunc; handleNetworkChanges?: handleWalletFunc;
handleAccountChanges?: handleWalletFunc; handleAccountChanges?: handleWalletFunc;
handleAccountDisconnect?: handleWalletFunc; handleAccountDisconnect?: handleWalletFunc;
}; }
export class TornadoBrowserProvider extends BrowserProvider { export class TornadoBrowserProvider extends BrowserProvider {
options?: TornadoBrowserProviderOptions; options?: TornadoBrowserProviderOptions;

@ -2,7 +2,7 @@ import { getAddress, parseEther } from 'ethers';
import { sleep } from './utils'; import { sleep } from './utils';
import { NetId, NetIdType, Config } from './networkConfig'; import { NetId, NetIdType, Config } from './networkConfig';
import { fetchData, fetchDataOptions } from './providers'; import { fetchData, fetchDataOptions } from './providers';
import { ajv, jobsSchema, getStatusSchema } from './schemas'; import { ajv, jobsSchema, jobRequestSchema, getStatusSchema } from './schemas';
import type { snarkProofs } from './websnark'; import type { snarkProofs } from './websnark';
import type { CachedRelayerInfo } from './events'; import type { CachedRelayerInfo } from './events';
@ -20,7 +20,7 @@ export interface RelayerParams {
/** /**
* Info from relayer status * Info from relayer status
*/ */
export type RelayerInfo = RelayerParams & { export interface RelayerInfo extends RelayerParams {
netId: NetIdType; netId: NetIdType;
url: string; url: string;
hostname: string; hostname: string;
@ -33,14 +33,14 @@ export type RelayerInfo = RelayerParams & {
}; };
currentQueue: number; currentQueue: number;
tornadoServiceFee: number; tornadoServiceFee: number;
}; }
export type RelayerError = { export interface RelayerError {
hostname: string; hostname: string;
relayerAddress?: string; relayerAddress?: string;
errorMessage?: string; errorMessage?: string;
hasError: boolean; hasError: boolean;
}; }
export interface RelayerStatus { export interface RelayerStatus {
url: string; url: string;
@ -75,9 +75,9 @@ export interface RelayerStatus {
currentQueue: number; currentQueue: number;
} }
export type TornadoWithdrawParams = snarkProofs & { export interface TornadoWithdrawParams extends snarkProofs {
contract: string; contract: string;
}; }
export interface RelayerTornadoWithdraw { export interface RelayerTornadoWithdraw {
id?: string; id?: string;
@ -149,13 +149,13 @@ export function getWeightRandom(weightsScores: bigint[], random: bigint) {
return Math.floor(Math.random() * weightsScores.length); return Math.floor(Math.random() * weightsScores.length);
} }
export type RelayerInstanceList = { export interface RelayerInstanceList {
[key in string]: { [key: string]: {
instanceAddress: { instanceAddress: {
[key in string]: string; [key: string]: string;
}; };
}; };
}; }
export function getSupportedInstances(instanceList: RelayerInstanceList) { export function getSupportedInstances(instanceList: RelayerInstanceList) {
const rawList = Object.values(instanceList) const rawList = Object.values(instanceList)
@ -223,7 +223,7 @@ export class RelayerClient {
headers: { headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded', 'Content-Type': 'application/json, application/x-www-form-urlencoded',
}, },
timeout: 60000, timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0, maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object; })) as object;
@ -318,10 +318,14 @@ export class RelayerClient {
async tornadoWithdraw( async tornadoWithdraw(
{ contract, proof, args }: TornadoWithdrawParams, { contract, proof, args }: TornadoWithdrawParams,
callback?: (jobResp: RelayerTornadoJobs) => void, callback?: (jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs) => void,
) { ) {
const { url } = this.selectedRelayer as RelayerInfo; const { url } = this.selectedRelayer as RelayerInfo;
/**
* Request new job
*/
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, { const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
method: 'POST', method: 'POST',
@ -341,6 +345,21 @@ export class RelayerClient {
throw new Error(error); throw new Error(error);
} }
const jobValidator = ajv.compile(jobRequestSchema);
if (!jobValidator(withdrawResponse)) {
const errMsg = `${url}v1/tornadoWithdraw has an invalid job response`;
throw new Error(errMsg);
}
if (typeof callback === 'function') {
callback(withdrawResponse as unknown as RelayerTornadoWithdraw);
}
/**
* Get job status
*/
let relayerStatus: string | undefined; let relayerStatus: string | undefined;
const jobUrl = `${url}v1/jobs/${id}`; const jobUrl = `${url}v1/jobs/${id}`;

@ -1,4 +1,4 @@
export type jobsSchema = { export interface jobsSchema {
type: string; type: string;
properties: { properties: {
error: { error: {
@ -36,7 +36,7 @@ export type jobsSchema = {
}; };
}; };
required: string[]; required: string[];
}; }
export const jobsSchema: jobsSchema = { export const jobsSchema: jobsSchema = {
type: 'object', type: 'object',
@ -57,3 +57,8 @@ export const jobsSchema: jobsSchema = {
}, },
required: ['id', 'status'], required: ['id', 'status'],
}; };
export const jobRequestSchema: jobsSchema = {
...jobsSchema,
required: ['id'],
};

@ -1,7 +1,7 @@
import { Config, NetId, NetIdType } from '../networkConfig'; import { Config, NetId, NetIdType } from '../networkConfig';
import { addressSchemaType, bnSchemaType } from '.'; import { addressSchemaType, bnSchemaType } from '.';
export type statusInstanceType = { export interface statusInstanceType {
type: string; type: string;
properties: { properties: {
instanceAddress: { instanceAddress: {
@ -16,25 +16,25 @@ export type statusInstanceType = {
decimals: { enum: number[] }; decimals: { enum: number[] };
}; };
required: string[]; required: string[];
}; }
export type statusInstancesType = { export interface statusInstancesType {
type: string; type: string;
properties: { properties: {
[key in string]: statusInstanceType; [key in string]: statusInstanceType;
}; };
required: string[]; required: string[];
}; }
export type statusEthPricesType = { export interface statusEthPricesType {
type: string; type: string;
properties: { properties: {
[key in string]: typeof bnSchemaType; [key in string]: typeof bnSchemaType;
}; };
required?: string[]; required?: string[];
}; }
export type statusSchema = { export interface statusSchema {
type: string; type: string;
properties: { properties: {
rewardAccount: typeof addressSchemaType; rewardAccount: typeof addressSchemaType;
@ -90,7 +90,7 @@ export type statusSchema = {
}; };
}; };
required: string[]; required: string[];
}; }
const statusSchema: statusSchema = { const statusSchema: statusSchema = {
type: 'object', type: 'object',

@ -10,7 +10,8 @@ import {
} from './relayerClient'; } from './relayerClient';
import { fetchData } from './providers'; import { fetchData } from './providers';
import { CachedRelayerInfo, MinimalEvents } from './events'; import { CachedRelayerInfo, MinimalEvents } from './events';
import { getEventsSchemaValidator } from './schemas'; import { ajv, getEventsSchemaValidator, getStatusSchema } from './schemas';
import { enabledChains, getConfig, NetId, NetIdType } from './networkConfig';
// Return no more than 5K events per query // Return no more than 5K events per query
export const MAX_TOVARISH_EVENTS = 5000; export const MAX_TOVARISH_EVENTS = 5000;
@ -81,7 +82,7 @@ export interface BaseTovarishEvents<T> {
} }
export class TovarishClient extends RelayerClient { export class TovarishClient extends RelayerClient {
selectedRelayer?: TovarishInfo; declare selectedRelayer?: TovarishInfo;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) { constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
super({ netId, config, fetchDataOptions }); super({ netId, config, fetchDataOptions });
@ -108,6 +109,82 @@ export class TovarishClient extends RelayerClient {
return status; return status;
} }
/**
* Ask status for all enabled chains for tovarish relayer
*/
async askAllStatus({
hostname,
url,
relayerAddress,
}: {
hostname?: string;
// optional url if entered manually
url?: string;
// relayerAddress from registry contract to prevent cheating
relayerAddress?: string;
}): Promise<TovarishStatus[]> {
if (!url && hostname) {
url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
} else if (url && !url.endsWith('/')) {
url += '/';
} else {
url = '';
}
const statusArray = (await fetchData(`${url}status`, {
...this.fetchDataOptions,
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded',
},
timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object;
if (!Array.isArray(statusArray)) {
return [];
}
const tovarishStatus: TovarishStatus[] = [];
for (const rawStatus of statusArray) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const netId = (rawStatus as any).netId as NetIdType;
const config = getConfig(netId);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const statusValidator = ajv.compile(getStatusSchema((rawStatus as any).netId, config, this.tovarish));
if (!statusValidator) {
continue;
}
const status = {
...rawStatus,
url: `${url}${netId}/`,
} as TovarishStatus;
if (status.currentQueue > 5) {
throw new Error('Withdrawal queue is overloaded');
}
if (!enabledChains.includes(status.netId)) {
throw new Error('This relayer serves a different network');
}
if (relayerAddress && status.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error('The Relayer reward address must match registered address');
}
if (!status.version.includes('tovarish')) {
throw new Error('Not a tovarish relayer!');
}
tovarishStatus.push(status);
}
return tovarishStatus;
}
async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> { async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> {
const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer; const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer;
@ -175,6 +252,62 @@ export class TovarishClient extends RelayerClient {
}; };
} }
async getTovarishRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
}> {
const validRelayers: TovarishInfo[] = [];
const invalidRelayers: RelayerError[] = [];
await Promise.all(
relayers
.filter((r) => r.tovarishHost && r.tovarishNetworks?.length)
.map(async (relayer) => {
const { ensName, relayerAddress, tovarishHost } = relayer;
try {
const statusArray = await this.askAllStatus({ hostname: tovarishHost as string, relayerAddress });
for (const status of statusArray) {
validRelayers.push({
netId: status.netId,
url: status.url,
hostname: tovarishHost as string,
ensName,
relayerAddress,
rewardAccount: getAddress(status.rewardAccount),
instances: getSupportedInstances(status.instances),
stakeBalance: relayer.stakeBalance,
gasPrice: status.gasPrices?.fast,
ethPrices: status.ethPrices,
currentQueue: status.currentQueue,
tornadoServiceFee: status.tornadoServiceFee,
// Additional fields for tovarish relayer
latestBlock: Number(status.latestBlock),
latestBalance: status.latestBalance,
version: status.version,
events: status.events,
syncStatus: status.syncStatus,
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
invalidRelayers.push({
hostname: tovarishHost as string,
relayerAddress,
errorMessage: err.message,
hasError: true,
});
}
}),
);
return {
validRelayers,
invalidRelayers,
};
}
async getEvents<T extends MinimalEvents>({ async getEvents<T extends MinimalEvents>({
type, type,
currency, currency,
@ -213,6 +346,13 @@ export class TovarishClient extends RelayerClient {
throw new Error(errMsg); throw new Error(errMsg);
} }
if (recent) {
return {
events: fetchedEvents,
lastSyncBlock: currentBlock,
};
}
lastSyncBlock = currentBlock; lastSyncBlock = currentBlock;
if (!Array.isArray(fetchedEvents) || !fetchedEvents.length) { if (!Array.isArray(fetchedEvents) || !fetchedEvents.length) {

@ -5,7 +5,7 @@ import websnarkGroth from '@tornado/websnark/src/groth16';
import type { Element } from '@tornado/fixed-merkle-tree'; import type { Element } from '@tornado/fixed-merkle-tree';
import { toFixedHex } from './utils'; import { toFixedHex } from './utils';
export type snarkInputs = { export interface snarkInputs {
// Public snark inputs // Public snark inputs
root: Element; root: Element;
nullifierHex: string; nullifierHex: string;
@ -19,7 +19,7 @@ export type snarkInputs = {
secret: bigint; secret: bigint;
pathElements: Element[]; pathElements: Element[];
pathIndices: Element[]; pathIndices: Element[];
}; }
export type snarkArgs = [ export type snarkArgs = [
_root: string, _root: string,
@ -30,10 +30,10 @@ export type snarkArgs = [
_refund: string, _refund: string,
]; ];
export type snarkProofs = { export interface snarkProofs {
proof: string; proof: string;
args: snarkArgs; args: snarkArgs;
}; }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let groth16: any; let groth16: any;

@ -15,7 +15,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */ /* Language and Environment */
"target": "es2018", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */ // "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */

@ -7,7 +7,7 @@ const esbuildLoader = {
loader: 'esbuild-loader', loader: 'esbuild-loader',
options: { options: {
loader: 'ts', loader: 'ts',
target: 'es2016', target: 'es2022',
} }
} }

160
yarn.lock

@ -725,18 +725,18 @@
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
"@rollup/plugin-commonjs@^28.0.0": "@rollup/plugin-commonjs@^28.0.1":
version "28.0.0" version "28.0.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz#44b5e49cb5d5e6233f1e4996013a8649fdbb9557" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz#e2138e31cc0637676dc3d5cae7739131f7cd565e"
integrity sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg== integrity sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==
dependencies: dependencies:
"@rollup/pluginutils" "^5.0.1" "@rollup/pluginutils" "^5.0.1"
commondir "^1.0.1" commondir "^1.0.1"
estree-walker "^2.0.2" estree-walker "^2.0.2"
fdir "^6.1.1" fdir "^6.2.0"
is-reference "1.2.1" is-reference "1.2.1"
magic-string "^0.30.3" magic-string "^0.30.3"
picomatch "^2.3.1" picomatch "^4.0.2"
"@rollup/plugin-json@^6.1.0": "@rollup/plugin-json@^6.1.0":
version "6.1.0" version "6.1.0"
@ -872,14 +872,13 @@
"@noble/hashes" "~1.4.0" "@noble/hashes" "~1.4.0"
"@scure/base" "~1.1.6" "@scure/base" "~1.1.6"
"@tornado/contracts@^1.0.1": "@tornado/contracts@git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4":
version "1.0.1" version "1.0.2"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fcontracts/-/1.0.1/contracts-1.0.1.tgz#4ce0bb721c602155f087bc5526afb22b2dd05b31" resolved "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4"
integrity sha512-5PHi2y/WybAF4uMjLenOEtqmaJ+sHkGYJJ9bHlOPlzbKooVzqVPpESKg1MEjofSpTLGG8XZAKEsXedyHX7+6qw==
dependencies: dependencies:
"@openzeppelin/contracts" "5.0.2" "@openzeppelin/contracts" "5.0.2"
"@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0" "@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0"
ethers "^6.4.0" ethers "^6.13.4"
"@tornado/fixed-merkle-tree@^0.7.3": "@tornado/fixed-merkle-tree@^0.7.3":
version "0.7.3" version "0.7.3"
@ -968,12 +967,7 @@
dependencies: dependencies:
undici-types "~6.19.2" undici-types "~6.19.2"
"@types/node@18.15.13": "@types/node@22.7.5", "@types/node@^22.7.5":
version "18.15.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==
"@types/node@^22.7.5":
version "22.7.5" version "22.7.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b"
integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==
@ -990,62 +984,62 @@
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
"@typescript-eslint/eslint-plugin@^8.8.1": "@typescript-eslint/eslint-plugin@^8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz#bf0b25305b0bf014b4b194a6919103d7ac2a7907"
integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== integrity sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==
dependencies: dependencies:
"@eslint-community/regexpp" "^4.10.0" "@eslint-community/regexpp" "^4.10.0"
"@typescript-eslint/scope-manager" "8.8.1" "@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/type-utils" "8.8.1" "@typescript-eslint/type-utils" "8.9.0"
"@typescript-eslint/utils" "8.8.1" "@typescript-eslint/utils" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
graphemer "^1.4.0" graphemer "^1.4.0"
ignore "^5.3.1" ignore "^5.3.1"
natural-compare "^1.4.0" natural-compare "^1.4.0"
ts-api-utils "^1.3.0" ts-api-utils "^1.3.0"
"@typescript-eslint/parser@^8.8.1": "@typescript-eslint/parser@^8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.9.0.tgz#0cecda6def8aef95d7c7098359c0fda5a362d6ad"
integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== integrity sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==
dependencies: dependencies:
"@typescript-eslint/scope-manager" "8.8.1" "@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/typescript-estree" "8.8.1" "@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
debug "^4.3.4" debug "^4.3.4"
"@typescript-eslint/scope-manager@8.8.1": "@typescript-eslint/scope-manager@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz#c98fef0c4a82a484e6a1eb610a55b154d14d46f3"
integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== integrity sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==
dependencies: dependencies:
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
"@typescript-eslint/type-utils@8.8.1": "@typescript-eslint/type-utils@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz#aa86da3e4555fe7c8b42ab75e13561c4b5a8dfeb"
integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== integrity sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==
dependencies: dependencies:
"@typescript-eslint/typescript-estree" "8.8.1" "@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/utils" "8.8.1" "@typescript-eslint/utils" "8.9.0"
debug "^4.3.4" debug "^4.3.4"
ts-api-utils "^1.3.0" ts-api-utils "^1.3.0"
"@typescript-eslint/types@8.8.1": "@typescript-eslint/types@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.9.0.tgz#b733af07fb340b32e962c6c63b1062aec2dc0fe6"
integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== integrity sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==
"@typescript-eslint/typescript-estree@8.8.1": "@typescript-eslint/typescript-estree@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz#1714f167e9063062dc0df49c1d25afcbc7a96199"
integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== integrity sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==
dependencies: dependencies:
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
debug "^4.3.4" debug "^4.3.4"
fast-glob "^3.3.2" fast-glob "^3.3.2"
is-glob "^4.0.3" is-glob "^4.0.3"
@ -1053,22 +1047,22 @@
semver "^7.6.0" semver "^7.6.0"
ts-api-utils "^1.3.0" ts-api-utils "^1.3.0"
"@typescript-eslint/utils@8.8.1": "@typescript-eslint/utils@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.9.0.tgz#748bbe3ea5bee526d9786d9405cf1b0df081c299"
integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== integrity sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==
dependencies: dependencies:
"@eslint-community/eslint-utils" "^4.4.0" "@eslint-community/eslint-utils" "^4.4.0"
"@typescript-eslint/scope-manager" "8.8.1" "@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/typescript-estree" "8.8.1" "@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/visitor-keys@8.8.1": "@typescript-eslint/visitor-keys@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz#5f11f4d9db913f37da42776893ffe0dd1ae78f78"
integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== integrity sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==
dependencies: dependencies:
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
eslint-visitor-keys "^3.4.3" eslint-visitor-keys "^3.4.3"
"@ungap/structured-clone@^1.2.0": "@ungap/structured-clone@^1.2.0":
@ -2602,17 +2596,17 @@ ethers@^5.5.1:
"@ethersproject/web" "5.7.1" "@ethersproject/web" "5.7.1"
"@ethersproject/wordlists" "5.7.0" "@ethersproject/wordlists" "5.7.0"
ethers@^6.13.3, ethers@^6.4.0: ethers@^6.13.4:
version "6.13.3" version "6.13.4"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.3.tgz#b87afdadb91cc8df5f56b9c59c96e5b206f4a600" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c"
integrity sha512-/DzbZOLVtoO4fKvvQwpEucHAQgIwBGWuRvBdwE/lMXgXvvHHTSkn7XqAQ2b+gjJzZDJjWA9OD05bVceVOsBHbg== integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA==
dependencies: dependencies:
"@adraffy/ens-normalize" "1.10.1" "@adraffy/ens-normalize" "1.10.1"
"@noble/curves" "1.2.0" "@noble/curves" "1.2.0"
"@noble/hashes" "1.3.2" "@noble/hashes" "1.3.2"
"@types/node" "18.15.13" "@types/node" "22.7.5"
aes-js "4.0.0-beta.5" aes-js "4.0.0-beta.5"
tslib "2.4.0" tslib "2.7.0"
ws "8.17.1" ws "8.17.1"
event-target-shim@^5.0.0: event-target-shim@^5.0.0:
@ -2703,7 +2697,7 @@ fastq@^1.6.0:
dependencies: dependencies:
reusify "^1.0.4" reusify "^1.0.4"
fdir@^6.1.1: fdir@^6.2.0:
version "6.4.0" version "6.4.0"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae"
integrity sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ== integrity sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==
@ -4072,6 +4066,11 @@ picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
picomatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
pkg-dir@^4.2.0: pkg-dir@^4.2.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
@ -4866,21 +4865,16 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6" minimist "^1.2.6"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@2.4.0: tslib@2.7.0, tslib@^2.6.2:
version "2.4.0" version "2.7.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
tslib@^1.9.0: tslib@^1.9.0:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
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==
tty-browserify@^0.0.1: tty-browserify@^0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"