From 666b0eba664958219291fe7d1032c409b276099c Mon Sep 17 00:00:00 2001 From: tornadocontrib Date: Wed, 16 Oct 2024 14:17:22 +0000 Subject: [PATCH] es2022, use interfaces, minor func addition --- package.json | 10 +-- rollup.config.mjs | 6 +- src/batch.ts | 4 +- src/deposits.ts | 34 ++++----- src/events/base.ts | 94 ++++++------------------- src/events/types.ts | 36 +++++----- src/gaszip.ts | 54 ++++++++++++++ src/graphql/index.ts | 4 +- src/index.ts | 1 + src/merkleTree.ts | 4 +- src/networkConfig.ts | 88 +++++++++++------------ src/prices.ts | 69 +++++++++++++++--- src/providers.ts | 8 +-- src/relayerClient.ts | 45 ++++++++---- src/schemas/jobs.ts | 9 ++- src/schemas/status.ts | 16 ++--- src/tovarishClient.ts | 144 ++++++++++++++++++++++++++++++++++++- src/websnark.ts | 8 +-- tsconfig.json | 2 +- webpack.config.js | 2 +- yarn.lock | 160 ++++++++++++++++++++---------------------- 21 files changed, 500 insertions(+), 298 deletions(-) create mode 100644 src/gaszip.ts diff --git a/package.json b/package.json index 012f99c..dbef646 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/rollup.config.mjs b/rollup.config.mjs index f240b1a..0b9d4a2 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -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(), diff --git a/src/batch.ts b/src/batch.ts index aee3532..440adca 100644 --- a/src/batch.ts +++ b/src/batch.ts @@ -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 diff --git a/src/deposits.ts b/src/deposits.ts index 2e7d8e1..829584c 100644 --- a/src/deposits.ts +++ b/src/deposits.ts @@ -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 { 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; diff --git a/src/events/base.ts b/src/events/base.ts index 1817194..1eaf25a 100644 --- a/src/events/base.ts +++ b/src/events/base.ts @@ -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 { netId: NetIdType; @@ -347,31 +347,22 @@ export class BaseEventsService { } } -export type BaseTornadoServiceConstructor = { - netId: NetIdType; - provider: Provider; - graphApi?: string; - subgraphName?: string; +export interface BaseTornadoServiceConstructor extends Omit { 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 { amount: string; currency: string; batchTransactionService: BatchTransactionService; batchBlockService: BatchBlockService; - tovarishClient?: TovarishClient; constructor({ netId, @@ -520,16 +511,9 @@ export class BaseTornadoService extends BaseEventsService { Echoer: Echoer; - deployedBlock?: number; - fetchDataOptions?: fetchDataOptions; - tovarishClient?: TovarishClient; -}; +} export class BaseEchoService extends BaseEventsService { constructor({ @@ -548,6 +532,7 @@ export class BaseEchoService extends BaseEventsService { graphApi, subgraphName, contract: Echoer, + type: 'Echo', deployedBlock, fetchDataOptions, tovarishClient, @@ -558,10 +543,6 @@ export class BaseEchoService extends BaseEventsService { return `echo_${this.netId}`; } - getType(): string { - return 'Echo'; - } - getGraphMethod(): string { return 'getAllGraphEchoEvents'; } @@ -601,16 +582,9 @@ export class BaseEchoService extends BaseEventsService { } } -export type BaseEncryptedNotesServiceConstructor = { - netId: NetIdType; - provider: Provider; - graphApi?: string; - subgraphName?: string; +export interface BaseEncryptedNotesServiceConstructor extends Omit { Router: TornadoRouter | TornadoProxyLight; - deployedBlock?: number; - fetchDataOptions?: fetchDataOptions; - tovarishClient?: TovarishClient; -}; +} export class BaseEncryptedNotesService extends BaseEventsService { constructor({ @@ -629,6 +603,7 @@ export class BaseEncryptedNotesService extends BaseEventsService { Governance: Governance; - deployedBlock?: number; - fetchDataOptions?: fetchDataOptions; - tovarishClient?: TovarishClient; -}; +} export class BaseGovernanceService extends BaseEventsService { batchTransactionService: BatchTransactionService; @@ -703,6 +667,7 @@ export class BaseGovernanceService extends BaseEventsService { RelayerRegistry: RelayerRegistry; Aggregator: Aggregator; relayerEnsSubdomains: SubdomainMap; - deployedBlock?: number; - fetchDataOptions?: fetchDataOptions; - tovarishClient?: TovarishClient; -}; +} export class BaseRegistryService extends BaseEventsService { Aggregator: Aggregator; @@ -924,6 +878,7 @@ export class BaseRegistryService extends BaseEventsService { graphApi, subgraphName, contract: RelayerRegistry, + type: 'RelayerRegistered', deployedBlock, fetchDataOptions, tovarishClient, @@ -939,11 +894,6 @@ export class BaseRegistryService extends BaseEventsService { return `registered_${this.netId}`; } - // Name of type used for events - getType() { - return 'RelayerRegistered'; - } - getTovarishType(): string { return 'registered'; } diff --git a/src/events/types.ts b/src/events/types.ts index 4fa4646..ed656eb 100644 --- a/src/events/types.ts +++ b/src/events/types.ts @@ -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; -}; +} diff --git a/src/gaszip.ts b/src/gaszip.ts new file mode 100644 index 0000000..92cc3d6 --- /dev/null +++ b/src/gaszip.ts @@ -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, + }; +} diff --git a/src/graphql/index.ts b/src/graphql/index.ts index e5c9454..bebfb2e 100644 --- a/src/graphql/index.ts +++ b/src/graphql/index.ts @@ -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({ graphApi, diff --git a/src/index.ts b/src/index.ts index 4a79754..c44d68f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'; diff --git a/src/merkleTree.ts b/src/merkleTree.ts index 9c4aaaf..4880ca0 100644 --- a/src/merkleTree.ts +++ b/src/merkleTree.ts @@ -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; diff --git a/src/networkConfig.ts b/src/networkConfig.ts index 63d364f..13a1dc0 100644 --- a/src/networkConfig.ts +++ b/src/networkConfig.ts @@ -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: { diff --git a/src/prices.ts b/src/prices.ts index 35097d0..e7c3824 100644 --- a/src/prices.ts +++ b/src/prices.ts @@ -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 { + // 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 { + // 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)); + } } diff --git a/src/providers.ts b/src/providers.ts index 02951f7..7ffd523 100644 --- a/src/providers.ts +++ b/src/providers.ts @@ -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; 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; diff --git a/src/relayerClient.ts b/src/relayerClient.ts index 1ea647e..3c0aae3 100644 --- a/src/relayerClient.ts +++ b/src/relayerClient.ts @@ -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}`; diff --git a/src/schemas/jobs.ts b/src/schemas/jobs.ts index 30624a1..c79ddd7 100644 --- a/src/schemas/jobs.ts +++ b/src/schemas/jobs.ts @@ -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'], +}; diff --git a/src/schemas/status.ts b/src/schemas/status.ts index b41536e..914bd2b 100644 --- a/src/schemas/status.ts +++ b/src/schemas/status.ts @@ -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', diff --git a/src/tovarishClient.ts b/src/tovarishClient.ts index 2784e19..2024866 100644 --- a/src/tovarishClient.ts +++ b/src/tovarishClient.ts @@ -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 { } 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 { + 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 { 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({ 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) { diff --git a/src/websnark.ts b/src/websnark.ts index ecc1072..4754439 100644 --- a/src/websnark.ts +++ b/src/websnark.ts @@ -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; diff --git a/tsconfig.json b/tsconfig.json index ae01d22..3001bea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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. */ diff --git a/webpack.config.js b/webpack.config.js index c4d5dec..95dec2c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,7 +7,7 @@ const esbuildLoader = { loader: 'esbuild-loader', options: { loader: 'ts', - target: 'es2016', + target: 'es2022', } } diff --git a/yarn.lock b/yarn.lock index 0336b1b..22246b4 100644 --- a/yarn.lock +++ b/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"