Minor updates #1

Closed
tornadocontrib wants to merge 67 commits from tornadocontrib/tornado-core:main into main
21 changed files with 500 additions and 298 deletions
Showing only changes of commit 666b0eba66 - Show all commits

@ -32,7 +32,7 @@
],
"dependencies": {
"@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/snarkjs": "^0.1.20",
"@tornado/websnark": "^0.0.4",
@ -40,13 +40,13 @@
"bn.js": "^5.2.1",
"circomlibjs": "0.1.7",
"cross-fetch": "^4.0.0",
"ethers": "^6.13.3",
"ethers": "^6.13.4",
"ffjavascript": "0.2.48",
"fflate": "^0.8.2",
"idb": "^8.0.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@typechain/ethers-v6": "^0.5.1",
@ -54,8 +54,8 @@
"@types/circomlibjs": "^0.1.6",
"@types/node": "^22.7.5",
"@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^8.8.1",
"@typescript-eslint/eslint-plugin": "^8.9.0",
"@typescript-eslint/parser": "^8.9.0",
"esbuild-loader": "^4.2.2",
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",

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

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

@ -2,44 +2,34 @@ import { bnToBytes, bytesToBN, leBuff2Int, leInt2Buff, rBigInt, toFixedHex } fro
import { buffPedersenHash } from './pedersen';
import type { NetIdType } from './networkConfig';
export type DepositType = {
export interface DepositType {
currency: string;
amount: string;
netId: NetIdType;
};
}
export type createDepositParams = {
export interface createDepositParams {
nullifier: bigint;
secret: bigint;
};
}
export type createDepositObject = {
export interface createDepositObject {
preimage: Uint8Array;
noteHex: string;
commitment: bigint;
commitmentHex: string;
nullifierHash: bigint;
nullifierHex: string;
};
}
export type createNoteParams = DepositType & {
export interface createNoteParams extends DepositType {
nullifier?: bigint;
secret?: bigint;
};
}
export type parsedNoteExec = DepositType & {
export interface parsedNoteExec extends DepositType {
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> {
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;
};
}
export class Invoice {
currency: string;

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

@ -20,37 +20,37 @@ export interface MinimalEvents {
transactionHash: string;
}
export type GovernanceEvents = MinimalEvents & {
export interface GovernanceEvents extends MinimalEvents {
event: string;
};
}
export type GovernanceProposalCreatedEvents = GovernanceEvents & {
export interface GovernanceProposalCreatedEvents extends GovernanceEvents {
id: number;
proposer: string;
target: string;
startTime: number;
endTime: number;
description: string;
};
}
export type GovernanceVotedEvents = GovernanceEvents & {
export interface GovernanceVotedEvents extends GovernanceEvents {
proposalId: number;
voter: string;
support: boolean;
votes: string;
from: string;
input: string;
};
}
export type GovernanceDelegatedEvents = GovernanceEvents & {
export interface GovernanceDelegatedEvents extends GovernanceEvents {
account: string;
delegateTo: string;
};
}
export type GovernanceUndelegatedEvents = GovernanceEvents & {
export interface GovernanceUndelegatedEvents extends GovernanceEvents {
account: string;
delegateFrom: string;
};
}
export type AllGovernanceEvents =
| GovernanceProposalCreatedEvents
@ -60,25 +60,25 @@ export type AllGovernanceEvents =
export type RegistersEvents = MinimalEvents & RelayerParams;
export type DepositsEvents = MinimalEvents & {
export interface DepositsEvents extends MinimalEvents {
commitment: string;
leafIndex: number;
timestamp: number;
from: string;
};
}
export type WithdrawalsEvents = MinimalEvents & {
export interface WithdrawalsEvents extends MinimalEvents {
nullifierHash: string;
to: string;
fee: string;
timestamp: number;
};
}
export type EchoEvents = MinimalEvents & {
export interface EchoEvents extends MinimalEvents {
address: string;
encryptedAccount: string;
};
}
export type EncryptedNotesEvents = MinimalEvents & {
export interface EncryptedNotesEvents extends MinimalEvents {
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
const GRAPHQL_LIMIT = 1000;
export type queryGraphParams = {
export interface queryGraphParams {
graphApi: string;
subgraphName: string;
query: string;
@ -42,7 +42,7 @@ export type queryGraphParams = {
[key: string]: string | number;
};
fetchDataOptions?: fetchDataOptions;
};
}
export async function queryGraph<T>({
graphApi,

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

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

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

@ -1,6 +1,6 @@
import { parseEther, type Provider } from 'ethers';
import type { OffchainOracle, Multicall } from './typechain';
import { multicall } from './multicall';
import { formatEther, parseEther, type Provider } from 'ethers';
import { ERC20__factory, OffchainOracle, Multicall } from './typechain';
import { multicall, Call3 } from './multicall';
export class TokenPriceOracle {
oracle?: OffchainOracle;
@ -13,6 +13,46 @@ export class TokenPriceOracle {
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(
tokens: {
tokenAddress: string;
@ -24,17 +64,24 @@ export class TokenPriceOracle {
return new Promise((resolve) => resolve(tokens.map(() => parseEther('0.0001'))));
}
const prices = (await multicall(
this.multicall,
tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
})),
)) as bigint[];
const prices = (await multicall(this.multicall, this.buildCalls(tokens))) as bigint[];
return prices.map((price, index) => {
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;
};
export type TornadoWalletOptions = {
export interface TornadoWalletOptions {
gasPriceBump?: number;
gasLimitBump?: number;
gasFailover?: boolean;
bumpNonce?: boolean;
};
}
export class TornadoWallet extends Wallet {
nonce?: number;
@ -474,13 +474,13 @@ export type connectWalletFunc = (...args: any[]) => Promise<void>;
export type handleWalletFunc = (...args: any[]) => void;
/* eslint-enable @typescript-eslint/no-explicit-any */
export type TornadoBrowserProviderOptions = TornadoWalletOptions & {
export interface TornadoBrowserProviderOptions extends TornadoWalletOptions {
netId?: NetIdType;
connectWallet?: connectWalletFunc;
handleNetworkChanges?: handleWalletFunc;
handleAccountChanges?: handleWalletFunc;
handleAccountDisconnect?: handleWalletFunc;
};
}
export class TornadoBrowserProvider extends BrowserProvider {
options?: TornadoBrowserProviderOptions;

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

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

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

@ -10,7 +10,8 @@ import {
} from './relayerClient';
import { fetchData } from './providers';
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
export const MAX_TOVARISH_EVENTS = 5000;
@ -81,7 +82,7 @@ export interface BaseTovarishEvents<T> {
}
export class TovarishClient extends RelayerClient {
selectedRelayer?: TovarishInfo;
declare selectedRelayer?: TovarishInfo;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
super({ netId, config, fetchDataOptions });
@ -108,6 +109,82 @@ export class TovarishClient extends RelayerClient {
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> {
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>({
type,
currency,
@ -213,6 +346,13 @@ export class TovarishClient extends RelayerClient {
throw new Error(errMsg);
}
if (recent) {
return {
events: fetchedEvents,
lastSyncBlock: currentBlock,
};
}
lastSyncBlock = currentBlock;
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 { toFixedHex } from './utils';
export type snarkInputs = {
export interface snarkInputs {
// Public snark inputs
root: Element;
nullifierHex: string;
@ -19,7 +19,7 @@ export type snarkInputs = {
secret: bigint;
pathElements: Element[];
pathIndices: Element[];
};
}
export type snarkArgs = [
_root: string,
@ -30,10 +30,10 @@ export type snarkArgs = [
_refund: string,
];
export type snarkProofs = {
export interface snarkProofs {
proof: string;
args: snarkArgs;
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let groth16: any;

@ -15,7 +15,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* 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. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */

@ -7,7 +7,7 @@ const esbuildLoader = {
loader: 'esbuild-loader',
options: {
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"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
"@rollup/plugin-commonjs@^28.0.0":
version "28.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz#44b5e49cb5d5e6233f1e4996013a8649fdbb9557"
integrity sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg==
"@rollup/plugin-commonjs@^28.0.1":
version "28.0.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz#e2138e31cc0637676dc3d5cae7739131f7cd565e"
integrity sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==
dependencies:
"@rollup/pluginutils" "^5.0.1"
commondir "^1.0.1"
estree-walker "^2.0.2"
fdir "^6.1.1"
fdir "^6.2.0"
is-reference "1.2.1"
magic-string "^0.30.3"
picomatch "^2.3.1"
picomatch "^4.0.2"
"@rollup/plugin-json@^6.1.0":
version "6.1.0"
@ -872,14 +872,13 @@
"@noble/hashes" "~1.4.0"
"@scure/base" "~1.1.6"
"@tornado/contracts@^1.0.1":
version "1.0.1"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fcontracts/-/1.0.1/contracts-1.0.1.tgz#4ce0bb721c602155f087bc5526afb22b2dd05b31"
integrity sha512-5PHi2y/WybAF4uMjLenOEtqmaJ+sHkGYJJ9bHlOPlzbKooVzqVPpESKg1MEjofSpTLGG8XZAKEsXedyHX7+6qw==
"@tornado/contracts@git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4":
version "1.0.2"
resolved "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4"
dependencies:
"@openzeppelin/contracts" "5.0.2"
"@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":
version "0.7.3"
@ -968,12 +967,7 @@
dependencies:
undici-types "~6.19.2"
"@types/node@18.15.13":
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":
"@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==
@ -990,62 +984,62 @@
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
"@typescript-eslint/eslint-plugin@^8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371"
integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==
"@typescript-eslint/eslint-plugin@^8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz#bf0b25305b0bf014b4b194a6919103d7ac2a7907"
integrity sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==
dependencies:
"@eslint-community/regexpp" "^4.10.0"
"@typescript-eslint/scope-manager" "8.8.1"
"@typescript-eslint/type-utils" "8.8.1"
"@typescript-eslint/utils" "8.8.1"
"@typescript-eslint/visitor-keys" "8.8.1"
"@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/type-utils" "8.9.0"
"@typescript-eslint/utils" "8.9.0"
"@typescript-eslint/visitor-keys" "8.9.0"
graphemer "^1.4.0"
ignore "^5.3.1"
natural-compare "^1.4.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/parser@^8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8"
integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==
"@typescript-eslint/parser@^8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.9.0.tgz#0cecda6def8aef95d7c7098359c0fda5a362d6ad"
integrity sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==
dependencies:
"@typescript-eslint/scope-manager" "8.8.1"
"@typescript-eslint/types" "8.8.1"
"@typescript-eslint/typescript-estree" "8.8.1"
"@typescript-eslint/visitor-keys" "8.8.1"
"@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/types" "8.9.0"
"@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/visitor-keys" "8.9.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff"
integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==
"@typescript-eslint/scope-manager@8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz#c98fef0c4a82a484e6a1eb610a55b154d14d46f3"
integrity sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==
dependencies:
"@typescript-eslint/types" "8.8.1"
"@typescript-eslint/visitor-keys" "8.8.1"
"@typescript-eslint/types" "8.9.0"
"@typescript-eslint/visitor-keys" "8.9.0"
"@typescript-eslint/type-utils@8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e"
integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==
"@typescript-eslint/type-utils@8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz#aa86da3e4555fe7c8b42ab75e13561c4b5a8dfeb"
integrity sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==
dependencies:
"@typescript-eslint/typescript-estree" "8.8.1"
"@typescript-eslint/utils" "8.8.1"
"@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/utils" "8.9.0"
debug "^4.3.4"
ts-api-utils "^1.3.0"
"@typescript-eslint/types@8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1"
integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==
"@typescript-eslint/types@8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.9.0.tgz#b733af07fb340b32e962c6c63b1062aec2dc0fe6"
integrity sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==
"@typescript-eslint/typescript-estree@8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec"
integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==
"@typescript-eslint/typescript-estree@8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz#1714f167e9063062dc0df49c1d25afcbc7a96199"
integrity sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==
dependencies:
"@typescript-eslint/types" "8.8.1"
"@typescript-eslint/visitor-keys" "8.8.1"
"@typescript-eslint/types" "8.9.0"
"@typescript-eslint/visitor-keys" "8.9.0"
debug "^4.3.4"
fast-glob "^3.3.2"
is-glob "^4.0.3"
@ -1053,22 +1047,22 @@
semver "^7.6.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/utils@8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d"
integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==
"@typescript-eslint/utils@8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.9.0.tgz#748bbe3ea5bee526d9786d9405cf1b0df081c299"
integrity sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
"@typescript-eslint/scope-manager" "8.8.1"
"@typescript-eslint/types" "8.8.1"
"@typescript-eslint/typescript-estree" "8.8.1"
"@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/types" "8.9.0"
"@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/visitor-keys@8.8.1":
version "8.8.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5"
integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==
"@typescript-eslint/visitor-keys@8.9.0":
version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz#5f11f4d9db913f37da42776893ffe0dd1ae78f78"
integrity sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==
dependencies:
"@typescript-eslint/types" "8.8.1"
"@typescript-eslint/types" "8.9.0"
eslint-visitor-keys "^3.4.3"
"@ungap/structured-clone@^1.2.0":
@ -2602,17 +2596,17 @@ ethers@^5.5.1:
"@ethersproject/web" "5.7.1"
"@ethersproject/wordlists" "5.7.0"
ethers@^6.13.3, ethers@^6.4.0:
version "6.13.3"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.3.tgz#b87afdadb91cc8df5f56b9c59c96e5b206f4a600"
integrity sha512-/DzbZOLVtoO4fKvvQwpEucHAQgIwBGWuRvBdwE/lMXgXvvHHTSkn7XqAQ2b+gjJzZDJjWA9OD05bVceVOsBHbg==
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" "18.15.13"
"@types/node" "22.7.5"
aes-js "4.0.0-beta.5"
tslib "2.4.0"
tslib "2.7.0"
ws "8.17.1"
event-target-shim@^5.0.0:
@ -2703,7 +2697,7 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
fdir@^6.1.1:
fdir@^6.2.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae"
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"
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:
version "4.2.0"
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"
strip-bom "^3.0.0"
tslib@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
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==
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:
version "0.0.1"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"