Added additional RelayerRegistry events

This commit is contained in:
Tornado Contrib 2024-11-02 11:26:42 +00:00
parent f411159f15
commit f6e676fd0b
Signed by: tornadocontrib
GPG Key ID: 60B4DF1A076C64B1
24 changed files with 32270 additions and 4502 deletions

6
dist/batch.d.ts vendored

@ -1,4 +1,4 @@
import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog } from 'ethers';
import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog, TransactionReceipt } from 'ethers';
export interface BatchBlockServiceConstructor {
provider: Provider;
onProgress?: BatchBlockOnProgress;
@ -42,8 +42,10 @@ export declare class BatchTransactionService {
retryOn: number;
constructor({ provider, onProgress, concurrencySize, batchSize, shouldRetry, retryMax, retryOn, }: BatchBlockServiceConstructor);
getTransaction(txHash: string): Promise<TransactionResponse>;
createBatchRequest(batchArray: string[][]): Promise<TransactionResponse[]>[];
getTransactionReceipt(txHash: string): Promise<TransactionReceipt>;
createBatchRequest(batchArray: string[][], receipt?: boolean): Promise<TransactionResponse[] | TransactionReceipt[]>[];
getBatchTransactions(txs: string[]): Promise<TransactionResponse[]>;
getBatchReceipt(txs: string[]): Promise<TransactionReceipt[]>;
}
export interface BatchEventServiceConstructor {
provider: Provider;

2
dist/ens.d.ts vendored

@ -28,7 +28,7 @@ export declare class ENSUtils {
getOwner(name: string): Promise<string>;
unwrap(signer: Signer, name: string): Promise<import("ethers").ContractTransactionResponse>;
setSubnodeRecord(signer: Signer, name: string): Promise<import("ethers").ContractTransactionResponse>;
setText(signer: Signer, name: string, key: string, value: string): Promise<import("ethers").ContractTransactionResponse>;
getResolver(name: string): Promise<EnsResolver | null>;
getText(name: string, key: string): Promise<string | null>;
setText(signer: Signer, name: string, key: string, value: string): Promise<import("ethers").ContractTransactionResponse>;
}

74
dist/events/base.d.ts vendored

@ -1,5 +1,5 @@
import { BaseContract, Provider, EventLog, ContractEventName } from 'ethers';
import type { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer, Aggregator } from '@tornado/contracts';
import { BaseContract, Provider, EventLog } from 'ethers';
import { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer, Aggregator } from '@tornado/contracts';
import { BatchEventsService, BatchBlockService, BatchTransactionService, BatchEventOnProgress, BatchBlockOnProgress } from '../batch';
import { fetchDataOptions } from '../providers';
import { type NetIdType, type SubdomainMap } from '../networkConfig';
@ -7,53 +7,34 @@ import { RelayerParams } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient';
import type { ReverseRecords } from '../typechain';
import type { MerkleTreeService } from '../merkleTree';
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, GovernanceProposalCreatedEvents, GovernanceVotedEvents, RegistersEvents, EchoEvents } from './types';
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, GovernanceProposalCreatedEvents, GovernanceVotedEvents, EchoEvents, AllRelayerRegistryEvents, StakeBurnedEvents } from './types';
export declare const DEPOSIT = "deposit";
export declare const WITHDRAWAL = "withdrawal";
export interface BaseEventsServiceConstructor {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract;
type: string;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
}
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export interface BaseGraphParams {
graphApi: string;
subgraphName: string;
fetchDataOptions?: fetchDataOptions;
onProgress?: BatchGraphOnProgress;
}
export declare class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract;
type: string;
deployedBlock: number;
batchEventsService: BatchEventsService;
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
constructor({ netId, provider, graphApi, subgraphName, contract, type, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEventsServiceConstructor);
constructor({ netId, provider, contract, type, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEventsServiceConstructor);
getInstanceName(): string;
getType(): string;
getTovarishType(): string;
getGraphMethod(): string;
getGraphParams(): BaseGraphParams;
updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateBlockProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateTransactionProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchGraphOnProgress>[0]): void;
formatEvents(events: EventLog[]): Promise<EventType[]>;
/**
* Get saved or cached events
@ -64,13 +45,6 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
*/
getEventsFromCache(): Promise<CachedEvents<EventType>>;
getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>>;
/**
* Get latest events
*/
getEventsFromGraph({ fromBlock, methodName, }: {
fromBlock: number;
methodName?: string;
}): Promise<BaseEvents<EventType>>;
getEventsFromRpc({ fromBlock, toBlock, }: {
fromBlock: number;
toBlock?: number;
@ -101,10 +75,6 @@ export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceCon
optionalTree?: boolean;
merkleTreeService?: MerkleTreeService;
}
export interface DepositsGraphParams extends BaseGraphParams {
amount: string;
currency: string;
}
export declare class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string;
currency: string;
@ -114,8 +84,6 @@ export declare class BaseTornadoService extends BaseEventsService<DepositsEvents
batchBlockService: BatchBlockService;
constructor(serviceConstructor: BaseTornadoServiceConstructor);
getInstanceName(): string;
getGraphMethod(): string;
getGraphParams(): DepositsGraphParams;
formatEvents(events: EventLog[]): Promise<(DepositsEvents | WithdrawalsEvents)[]>;
validateEvents<S>({ events, hasNewEvents, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
hasNewEvents?: boolean;
@ -130,11 +98,7 @@ export interface BaseEchoServiceConstructor extends Omit<BaseEventsServiceConstr
export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
constructor(serviceConstructor: BaseEchoServiceConstructor);
getInstanceName(): string;
getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<EchoEvents[]>;
getEventsFromGraph({ fromBlock }: {
fromBlock: number;
}): Promise<BaseEvents<EchoEvents>>;
}
export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Router: TornadoRouter | TornadoProxyLight;
@ -143,7 +107,6 @@ export declare class BaseEncryptedNotesService extends BaseEventsService<Encrypt
constructor(serviceConstructor: BaseEncryptedNotesServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
}
export declare const proposalState: {
@ -178,11 +141,7 @@ export declare class BaseGovernanceService extends BaseEventsService<AllGovernan
constructor(serviceConstructor: BaseGovernanceServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
getEventsFromGraph({ fromBlock }: {
fromBlock: number;
}): Promise<BaseEvents<AllGovernanceEvents>>;
getAllProposals(): Promise<GovernanceProposals[]>;
getVotes(proposalId: number): Promise<GovernanceVotes[]>;
getDelegatedBalance(ethAccount: string): Promise<{
@ -221,21 +180,14 @@ export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceCo
Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap;
}
export declare class BaseRegistryService extends BaseEventsService<RegistersEvents> {
export declare class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> {
Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap;
updateInterval: number;
constructor(serviceConstructor: BaseRegistryServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<{
ensName: any;
relayerAddress: any;
blockNumber: number;
logIndex: number;
transactionHash: string;
}[]>;
formatEvents(events: EventLog[]): Promise<AllRelayerRegistryEvents[]>;
/**
* Get saved or cached relayers
*/
@ -255,3 +207,17 @@ export declare class BaseRegistryService extends BaseEventsService<RegistersEven
*/
updateRelayers(): Promise<CachedRelayers>;
}
export interface BaseRevenueServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
RelayerRegistry: RelayerRegistry;
}
/**
* Tracks TORN burned events from RelayerRegistry contract
*/
export declare class BaseRevenueService extends BaseEventsService<StakeBurnedEvents> {
batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService;
constructor(serviceConstructor: BaseRevenueServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<StakeBurnedEvents[]>;
}

28
dist/events/db.d.ts vendored

@ -1,6 +1,6 @@
import { IndexedDB } from '../idb';
import { BaseTornadoService, BaseTornadoServiceConstructor, BaseEchoService, BaseEchoServiceConstructor, BaseEncryptedNotesService, BaseEncryptedNotesServiceConstructor, BaseGovernanceService, BaseGovernanceServiceConstructor, BaseRegistryService, BaseRegistryServiceConstructor } from './base';
import { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, CachedEvents, EchoEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents } from './types';
import { BaseTornadoService, BaseTornadoServiceConstructor, BaseEchoService, BaseEchoServiceConstructor, BaseEncryptedNotesService, BaseEncryptedNotesServiceConstructor, BaseGovernanceService, BaseGovernanceServiceConstructor, BaseRegistryService, BaseRegistryServiceConstructor, BaseRevenueService, BaseRevenueServiceConstructor, CachedRelayers } from './base';
import { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, CachedEvents, EchoEvents, EncryptedNotesEvents, AllGovernanceEvents, AllRelayerRegistryEvents, StakeBurnedEvents } from './types';
export declare function saveDBEvents<T extends MinimalEvents>({ idb, instanceName, events, lastBlock, }: {
idb: IndexedDB;
instanceName: string;
@ -77,8 +77,26 @@ export declare class DBRegistryService extends BaseRegistryService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRegistryServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<RegistersEvents>>;
getEventsFromCache(): Promise<CachedEvents<RegistersEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<RegistersEvents>): Promise<void>;
getEventsFromDB(): Promise<BaseEvents<AllRelayerRegistryEvents>>;
getEventsFromCache(): Promise<CachedEvents<AllRelayerRegistryEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<AllRelayerRegistryEvents>): Promise<void>;
getRelayersFromDB(): Promise<CachedRelayers>;
getRelayersFromCache(): Promise<CachedRelayers>;
saveRelayers(cachedRelayers: CachedRelayers): Promise<void>;
}
export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBRevenueService extends BaseRevenueService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRevenueServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<StakeBurnedEvents>>;
getEventsFromCache(): Promise<CachedEvents<StakeBurnedEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<StakeBurnedEvents>): Promise<void>;
}

@ -43,6 +43,33 @@ export interface GovernanceUndelegatedEvents extends GovernanceEvents {
delegateFrom: string;
}
export type AllGovernanceEvents = GovernanceProposalCreatedEvents | GovernanceVotedEvents | GovernanceDelegatedEvents | GovernanceUndelegatedEvents;
export interface RelayerRegistryEvents extends MinimalEvents {
event: string;
}
export interface RelayerRegisteredEvents extends RelayerRegistryEvents, RelayerParams {
ensHash: string;
stakedAmount: string;
}
export interface RelayerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
}
export interface WorkerRegisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export interface WorkerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export type AllRelayerRegistryEvents = RelayerRegisteredEvents | RelayerUnregisteredEvents | WorkerRegisteredEvents | WorkerUnregisteredEvents;
export interface StakeBurnedEvents extends MinimalEvents {
relayerAddress: string;
amountBurned: string;
instanceAddress: string;
gasFee: string;
relayerFee: string;
timestamp: number;
}
export type RegistersEvents = MinimalEvents & RelayerParams;
export interface DepositsEvents extends MinimalEvents {
commitment: string;

@ -1,6 +1,13 @@
import { ContractEventName } from 'ethers';
import { fetchDataOptions } from '../providers';
import type { BaseGraphEvents, RegistersEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, BatchGraphOnProgress, EchoEvents, AllGovernanceEvents } from '../events';
import type { BaseGraphEvents, RegistersEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, EchoEvents, AllGovernanceEvents } from '../events';
export * from './queries';
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export interface queryGraphParams {
graphApi: string;
subgraphName: string;

1
dist/index.d.ts vendored

@ -1,5 +1,4 @@
export * from './events';
export * from './graphql';
export * from './schemas';
export * from './typechain';
export * from './batch';

2020
dist/index.js vendored

File diff suppressed because it is too large Load Diff

1993
dist/index.mjs vendored

File diff suppressed because it is too large Load Diff

2
dist/providers.d.ts vendored

@ -8,7 +8,7 @@ declare global {
ethereum?: Eip1193Provider & EventEmitter;
}
}
export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0";
export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
export declare const fetch: nodeFetch;
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export type fetchDataOptions = RequestInit & {

@ -144,11 +144,15 @@ export declare const governanceEventsSchema: {
}];
};
};
export declare const registeredEventsSchema: {
export declare const relayerRegistryEventsSchema: {
readonly type: "array";
readonly items: {
readonly anyOf: readonly [{
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly ensName: {
readonly type: "string";
};
@ -157,6 +161,36 @@ export declare const registeredEventsSchema: {
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly ensHash: {
readonly type: "string";
};
readonly stakedAmount: {
readonly type: "string";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "ensName", "relayerAddress", "ensHash", "stakedAmount"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
@ -168,7 +202,82 @@ export declare const registeredEventsSchema: {
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "ensName", "relayerAddress"];
readonly required: readonly [...string[], "event", "relayerAddress"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly workerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "relayerAddress", "workerAddress"];
readonly additionalProperties: false;
}];
};
};
export declare const stakeBurnedEventsSchema: {
readonly type: "array";
readonly items: {
readonly type: "object";
readonly properties: {
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly amountBurned: {
readonly type: "string";
readonly BN: true;
};
readonly instanceAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly gasFee: {
readonly type: "string";
readonly BN: true;
};
readonly relayerFee: {
readonly type: "string";
readonly BN: true;
};
readonly timestamp: {
readonly type: "number";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "relayerAddress", "amountBurned", "instanceAddress", "gasFee", "relayerFee", "timestamp"];
readonly additionalProperties: false;
};
};

31687
dist/tornado.umd.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,4 +1,13 @@
import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog } from 'ethers';
import type {
Provider,
BlockTag,
Block,
TransactionResponse,
BaseContract,
ContractEventName,
EventLog,
TransactionReceipt,
} from 'ethers';
import { chunk, sleep } from './utils';
export interface BatchBlockServiceConstructor {
@ -153,7 +162,21 @@ export class BatchTransactionService {
return txObject;
}
createBatchRequest(batchArray: string[][]): Promise<TransactionResponse[]>[] {
async getTransactionReceipt(txHash: string): Promise<TransactionReceipt> {
const txObject = await this.provider.getTransactionReceipt(txHash);
if (!txObject) {
const errMsg = `No transaction receipt for ${txHash}`;
throw new Error(errMsg);
}
return txObject;
}
createBatchRequest(
batchArray: string[][],
receipt?: boolean,
): Promise<TransactionResponse[] | TransactionReceipt[]>[] {
return batchArray.map(async (txs: string[], index: number) => {
await sleep(20 * index);
@ -164,7 +187,11 @@ export class BatchTransactionService {
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
if (!receipt) {
return await Promise.all(txs.map((tx) => this.getTransaction(tx)));
} else {
return await Promise.all(txs.map((tx) => this.getTransactionReceipt(tx)));
}
} catch (e) {
retries++;
err = e;
@ -184,7 +211,34 @@ export class BatchTransactionService {
const results = [];
for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) {
const chunksResult = (await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))).flat();
const chunksResult = (
await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))
).flat() as TransactionResponse[];
results.push(...chunksResult);
txCount += chunks.length;
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: txCount / txs.length,
currentIndex: txCount,
totalIndex: txs.length,
});
}
}
return results;
}
async getBatchReceipt(txs: string[]): Promise<TransactionReceipt[]> {
let txCount = 0;
const results = [];
for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) {
const chunksResult = (
await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize), true))
).flat() as TransactionReceipt[];
results.push(...chunksResult);

@ -121,13 +121,6 @@ export class ENSUtils {
return registry.setSubnodeRecord(parentNode, labelhash, owner, resolver.target, BigInt(0));
}
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/functions/wallet/setTextRecord.ts
async setText(signer: Signer, name: string, key: string, value: string) {
const resolver = ENSResolver__factory.connect((await this.getResolver(name))?.address as string, signer);
return resolver.setText(namehash(name), key, value);
}
getResolver(name: string) {
return EnsResolver.fromName(this.provider, name);
}
@ -142,4 +135,11 @@ export class ENSUtils {
return (await resolver.getText(key)) || '';
}
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/functions/wallet/setTextRecord.ts
async setText(signer: Signer, name: string, key: string, value: string) {
const resolver = ENSResolver__factory.connect((await this.getResolver(name))?.address as string, signer);
return resolver.setText(namehash(name), key, value);
}
}

@ -4,8 +4,6 @@ import {
EventLog,
TransactionResponse,
getAddress,
Block,
ContractEventName,
namehash,
formatEther,
AbiCoder,
@ -13,7 +11,7 @@ import {
dataSlice,
} from 'ethers';
import type {
import {
Tornado,
TornadoRouter,
TornadoProxyLight,
@ -21,10 +19,9 @@ import type {
RelayerRegistry,
Echoer,
Aggregator,
Tornado__factory,
} from '@tornado/contracts';
import * as graph from '../graphql';
import {
BatchEventsService,
BatchBlockService,
@ -52,9 +49,13 @@ import type {
GovernanceVotedEvents,
GovernanceDelegatedEvents,
GovernanceUndelegatedEvents,
RegistersEvents,
BaseGraphEvents,
EchoEvents,
RelayerRegisteredEvents,
RelayerUnregisteredEvents,
WorkerRegisteredEvents,
WorkerUnregisteredEvents,
AllRelayerRegistryEvents,
StakeBurnedEvents,
} from './types';
export const DEPOSIT = 'deposit';
@ -63,8 +64,6 @@ export const WITHDRAWAL = 'withdrawal';
export interface BaseEventsServiceConstructor {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract;
type: string;
deployedBlock?: number;
@ -72,30 +71,9 @@ export interface BaseEventsServiceConstructor {
tovarishClient?: TovarishClient;
}
export type BatchGraphOnProgress = ({
type,
fromBlock,
toBlock,
count,
}: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export interface BaseGraphParams {
graphApi: string;
subgraphName: string;
fetchDataOptions?: fetchDataOptions;
onProgress?: BatchGraphOnProgress;
}
export class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract;
type: string;
deployedBlock: number;
@ -106,8 +84,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
constructor({
netId,
provider,
graphApi,
subgraphName,
contract,
type = '',
deployedBlock = 0,
@ -116,8 +92,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
}: BaseEventsServiceConstructor) {
this.netId = netId;
this.provider = provider;
this.graphApi = graphApi;
this.subgraphName = subgraphName;
this.fetchDataOptions = fetchDataOptions;
this.contract = contract;
@ -145,19 +119,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
return String(this.getType() || '').toLowerCase();
}
getGraphMethod(): string {
return '';
}
getGraphParams(): BaseGraphParams {
return {
graphApi: this.graphApi || '',
subgraphName: this.subgraphName || '',
fetchDataOptions: this.fetchDataOptions,
onProgress: this.updateGraphProgress,
};
}
/* eslint-disable @typescript-eslint/no-unused-vars */
updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) {}
@ -165,7 +126,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
updateTransactionProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]) {}
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchGraphOnProgress>[0]) {}
/* eslint-enable @typescript-eslint/no-unused-vars */
async formatEvents(events: EventLog[]): Promise<EventType[]> {
@ -205,35 +165,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
return dbEvents;
}
/**
* Get latest events
*/
async getEventsFromGraph({
fromBlock,
methodName = '',
}: {
fromBlock: number;
methodName?: string;
}): Promise<BaseEvents<EventType>> {
if (!this.graphApi || !this.subgraphName) {
return {
events: [],
lastBlock: fromBlock,
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { events, lastSyncBlock } = (await (graph as any)[methodName || this.getGraphMethod()]({
fromBlock,
...this.getGraphParams(),
})) as BaseGraphEvents<EventType>;
return {
events,
lastBlock: lastSyncBlock,
};
}
async getEventsFromRpc({
fromBlock,
toBlock,
@ -289,16 +220,9 @@ export class BaseEventsService<EventType extends MinimalEvents> {
};
}
const graphEvents = await this.getEventsFromGraph({ fromBlock });
const lastSyncBlock =
graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
const rpcEvents = await this.getEventsFromRpc({
fromBlock: lastSyncBlock,
return await this.getEventsFromRpc({
fromBlock,
});
return {
events: [...graphEvents.events, ...rpcEvents.events],
lastBlock: rpcEvents.lastBlock,
};
}
/* eslint-disable @typescript-eslint/no-unused-vars */
@ -378,11 +302,6 @@ export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceCon
merkleTreeService?: MerkleTreeService;
}
export interface DepositsGraphParams extends BaseGraphParams {
amount: string;
currency: string;
}
export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string;
currency: string;
@ -421,25 +340,14 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
return `${this.getType().toLowerCase()}s_${this.netId}_${this.currency}_${this.amount}`;
}
getGraphMethod(): string {
return `getAll${this.getType()}s`;
}
getGraphParams(): DepositsGraphParams {
return {
graphApi: this.graphApi || '',
subgraphName: this.subgraphName || '',
amount: this.amount,
currency: this.currency,
fetchDataOptions: this.fetchDataOptions,
onProgress: this.updateGraphProgress,
};
}
async formatEvents(events: EventLog[]): Promise<(DepositsEvents | WithdrawalsEvents)[]> {
const type = this.getType().toLowerCase();
if (type === DEPOSIT) {
const formattedEvents = events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const txs = await this.batchTransactionService.getBatchTransactions([
...new Set(events.map(({ transactionHash }) => transactionHash)),
]);
return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const { commitment, leafIndex, timestamp } = args;
return {
@ -449,23 +357,15 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
commitment: commitment as string,
leafIndex: Number(leafIndex),
timestamp: Number(timestamp),
};
});
const txs = await this.batchTransactionService.getBatchTransactions([
...new Set(formattedEvents.map(({ transactionHash }) => transactionHash)),
]);
return formattedEvents.map((event) => {
const { from } = txs.find(({ hash }) => hash === event.transactionHash) as TransactionResponse;
return {
...event,
from,
from: txs.find(({ hash }) => hash === transactionHash)?.from || '',
};
});
} else {
const formattedEvents = events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const blocks = await this.batchBlockService.getBatchBlocks([
...new Set(events.map(({ blockNumber }) => blockNumber)),
]);
return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const { nullifierHash, to, fee } = args;
return {
@ -475,19 +375,7 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
nullifierHash: String(nullifierHash),
to: getAddress(to),
fee: String(fee),
};
});
const blocks = await this.batchBlockService.getBatchBlocks([
...new Set(formattedEvents.map(({ blockNumber }) => blockNumber)),
]);
return formattedEvents.map((event) => {
const { timestamp } = blocks.find(({ number }) => number === event.blockNumber) as Block;
return {
...event,
timestamp,
timestamp: blocks.find(({ number }) => number === blockNumber)?.timestamp || 0,
};
});
}
@ -559,10 +447,6 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
return `echo_${this.netId}`;
}
getGraphMethod(): string {
return 'getAllGraphEchoEvents';
}
async formatEvents(events: EventLog[]) {
return events
.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
@ -584,18 +468,6 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
})
.filter((e) => e) as EchoEvents[];
}
async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EchoEvents>> {
// TheGraph doesn't support our batch sync due to missing blockNumber field
if (!this.graphApi || this.graphApi.includes('api.thegraph.com')) {
return {
events: [],
lastBlock: fromBlock,
};
}
return super.getEventsFromGraph({ fromBlock });
}
}
export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
@ -619,10 +491,6 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
return 'encrypted_notes';
}
getGraphMethod(): string {
return 'getAllEncryptedNotes';
}
async formatEvents(events: EventLog[]) {
return events
.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
@ -789,10 +657,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
return 'governance';
}
getGraphMethod() {
return 'getAllGovernanceEvents';
}
async formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]> {
const proposalEvents: GovernanceProposalCreatedEvents[] = [];
const votedEvents: GovernanceVotedEvents[] = [];
@ -880,18 +744,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
return [...proposalEvents, ...votedEvents, ...delegatedEvents, ...undelegatedEvents];
}
async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<AllGovernanceEvents>> {
// TheGraph doesn't support governance subgraphs
if (!this.graphApi || !this.subgraphName || this.graphApi.includes('api.thegraph.com')) {
return {
events: [],
lastBlock: fromBlock,
};
}
return super.getEventsFromGraph({ fromBlock });
}
async getAllProposals(): Promise<GovernanceProposals[]> {
const { events } = await this.updateEvents();
@ -1091,7 +943,7 @@ export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceCo
relayerEnsSubdomains: SubdomainMap;
}
export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> {
Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap;
updateInterval: number;
@ -1102,7 +954,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
super({
...serviceConstructor,
contract,
type: 'RelayerRegistered',
type: '*',
});
this.Aggregator = Aggregator;
@ -1112,34 +964,77 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
}
getInstanceName() {
return `registered_${this.netId}`;
return `registry_${this.netId}`;
}
getTovarishType(): string {
return 'registered';
return 'registry';
}
// Name of method used for graph
getGraphMethod() {
return 'getAllRegisters';
}
async formatEvents(events: EventLog[]): Promise<AllRelayerRegistryEvents[]> {
const relayerRegisteredEvents: RelayerRegisteredEvents[] = [];
const relayerUnregisteredEvents: RelayerUnregisteredEvents[] = [];
const workerRegisteredEvents: WorkerRegisteredEvents[] = [];
const workerUnregisteredEvents: WorkerUnregisteredEvents[] = [];
async formatEvents(events: EventLog[]) {
return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
events.forEach(({ blockNumber, index: logIndex, transactionHash, args, eventName: event }) => {
const eventObjects = {
blockNumber,
logIndex,
transactionHash,
event,
};
return {
if (event === 'RelayerRegistered') {
const { relayer: ensHash, ensName, relayerAddress, stakedAmount } = args;
relayerRegisteredEvents.push({
...eventObjects,
ensName: args.ensName,
relayerAddress: args.relayerAddress,
};
ensName,
relayerAddress,
ensHash,
stakedAmount: formatEther(stakedAmount),
});
}
if (event === 'RelayerUnregistered') {
const { relayer: relayerAddress } = args;
relayerUnregisteredEvents.push({
...eventObjects,
relayerAddress,
});
}
if (event === 'WorkerRegistered') {
const { relayer: relayerAddress, worker: workerAddress } = args;
workerRegisteredEvents.push({
...eventObjects,
relayerAddress,
workerAddress,
});
}
if (event === 'WorkerUnregistered') {
const { relayer: relayerAddress, worker: workerAddress } = args;
workerUnregisteredEvents.push({
...eventObjects,
relayerAddress,
workerAddress,
});
}
});
return [
...relayerRegisteredEvents,
...relayerUnregisteredEvents,
...workerRegisteredEvents,
...workerUnregisteredEvents,
];
}
/**
* Get saved or cached relayers
*/
@ -1174,7 +1069,9 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
}
async getLatestRelayers(): Promise<CachedRelayers> {
const { events, lastBlock } = await this.updateEvents();
const { events: allEvents, lastBlock } = await this.updateEvents();
const events = allEvents.filter((e) => e.event === 'RelayerRegistered') as RelayerRegisteredEvents[];
const subdomains = Object.values(this.relayerEnsSubdomains);
@ -1275,3 +1172,117 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
return { lastBlock, timestamp, relayers };
}
}
export interface BaseRevenueServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
RelayerRegistry: RelayerRegistry;
}
/**
* Tracks TORN burned events from RelayerRegistry contract
*/
export class BaseRevenueService extends BaseEventsService<StakeBurnedEvents> {
batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService;
constructor(serviceConstructor: BaseRevenueServiceConstructor) {
const { RelayerRegistry: contract, provider } = serviceConstructor;
super({
...serviceConstructor,
contract,
type: 'StakeBurned',
});
this.batchTransactionService = new BatchTransactionService({
provider,
onProgress: this.updateTransactionProgress,
});
this.batchBlockService = new BatchBlockService({
provider,
onProgress: this.updateBlockProgress,
});
}
getInstanceName() {
return `revenue_${this.netId}`;
}
getTovarishType(): string {
return 'revenue';
}
async formatEvents(events: EventLog[]): Promise<StakeBurnedEvents[]> {
const blocks = await this.batchBlockService.getBatchBlocks([
...new Set(events.map(({ blockNumber }) => blockNumber)),
]);
const receipts = await this.batchTransactionService.getBatchReceipt([
...new Set(events.map(({ transactionHash }) => transactionHash)),
]);
const registeredRelayers = new Set(events.map(({ args }) => args.relayer));
const tornadoInterface = Tornado__factory.createInterface();
const withdrawHash = tornadoInterface.getEvent('Withdrawal').topicHash;
const withdrawalLogs = receipts
.map(
(receipt) =>
receipt.logs
.map((log) => {
if (log.topics[0] === withdrawHash) {
const block = blocks.find((b) => b.number === log.blockNumber);
const parsedLog = tornadoInterface.parseLog(log);
if (parsedLog && registeredRelayers.has(parsedLog.args.relayer)) {
return {
instanceAddress: log.address,
gasFee: (receipt.cumulativeGasUsed * receipt.gasPrice).toString(),
relayerFee: parsedLog.args.fee.toString(),
timestamp: block?.timestamp || 0,
};
}
}
})
.filter((l) => l) as {
instanceAddress: string;
gasFee: string;
relayerFee: string;
timestamp: number;
}[],
)
.flat();
if (withdrawalLogs.length !== events.length) {
console.log(
`\nRevenueService: Mismatch on withdrawal logs (${withdrawalLogs.length} ) and events logs (${events.length})\n`,
);
}
return events.map(({ blockNumber, index: logIndex, transactionHash, args }, index) => {
const eventObjects = {
blockNumber,
logIndex,
transactionHash,
};
const { relayer: relayerAddress, amountBurned } = args;
const { instanceAddress, gasFee, relayerFee, timestamp } = withdrawalLogs[index];
return {
...eventObjects,
relayerAddress,
amountBurned: amountBurned.toString(),
instanceAddress,
gasFee,
relayerFee,
timestamp,
};
});
}
}

@ -1,6 +1,8 @@
import { downloadZip } from '../zip';
import { IndexedDB } from '../idb';
import { bytesToBase64, digest } from '../utils';
import { fetchData } from '../providers';
import {
BaseTornadoService,
BaseTornadoServiceConstructor,
@ -12,6 +14,9 @@ import {
BaseGovernanceServiceConstructor,
BaseRegistryService,
BaseRegistryServiceConstructor,
BaseRevenueService,
BaseRevenueServiceConstructor,
CachedRelayers,
} from './base';
import {
@ -23,7 +28,8 @@ import {
EchoEvents,
EncryptedNotesEvents,
AllGovernanceEvents,
RegistersEvents,
AllRelayerRegistryEvents,
StakeBurnedEvents,
} from './types';
export async function saveDBEvents<T extends MinimalEvents>({
@ -338,6 +344,7 @@ export class DBRegistryService extends BaseRegistryService {
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRegistryServiceConstructor) {
super(params);
@ -347,14 +354,14 @@ export class DBRegistryService extends BaseRegistryService {
}
async getEventsFromDB() {
return await loadDBEvents<RegistersEvents>({
return await loadDBEvents<AllRelayerRegistryEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<RegistersEvents>({
return await loadRemoteEvents<AllRelayerRegistryEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
@ -362,8 +369,128 @@ export class DBRegistryService extends BaseRegistryService {
});
}
async saveEvents({ events, lastBlock }: BaseEvents<RegistersEvents>) {
await saveDBEvents<RegistersEvents>({
async saveEvents({ events, lastBlock }: BaseEvents<AllRelayerRegistryEvents>) {
await saveDBEvents<AllRelayerRegistryEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
events,
lastBlock,
});
}
async getRelayersFromDB(): Promise<CachedRelayers> {
try {
const allCachedRelayers = await this.idb.getAll<CachedRelayers[]>({
storeName: `relayers_${this.netId}`,
});
if (!allCachedRelayers?.length) {
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
return allCachedRelayers.slice(-1)[0];
} catch (err) {
console.log('Method getRelayersFromDB has error');
console.log(err);
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
}
async getRelayersFromCache(): Promise<CachedRelayers> {
const url = `${this.staticUrl}/relayers.json`;
try {
const resp = await fetchData(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
returnResponse: true,
});
const data = new Uint8Array(await resp.arrayBuffer());
if (this.relayerJsonDigest) {
const hash = 'sha384-' + bytesToBase64(await digest(data));
if (hash !== this.relayerJsonDigest) {
const errMsg = `Invalid digest hash for ${url}, wants ${this.relayerJsonDigest} has ${hash}`;
throw new Error(errMsg);
}
}
return JSON.parse(new TextDecoder().decode(data)) as CachedRelayers;
} catch (err) {
console.log('Method getRelayersFromCache has error');
console.log(err);
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
}
async saveRelayers(cachedRelayers: CachedRelayers): Promise<void> {
try {
await this.idb.putItem({
data: cachedRelayers,
storeName: `relayers_${this.netId}`,
});
} catch (err) {
console.log('Method saveRelayers has error');
console.log(err);
}
}
}
export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBRevenueService extends BaseRevenueService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRevenueServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<StakeBurnedEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<StakeBurnedEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({ events, lastBlock }: BaseEvents<StakeBurnedEvents>) {
await saveDBEvents<StakeBurnedEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
events,

@ -58,6 +58,45 @@ export type AllGovernanceEvents =
| GovernanceDelegatedEvents
| GovernanceUndelegatedEvents;
export interface RelayerRegistryEvents extends MinimalEvents {
event: string;
}
export interface RelayerRegisteredEvents extends RelayerRegistryEvents, RelayerParams {
ensHash: string;
stakedAmount: string;
}
export interface RelayerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
}
export interface WorkerRegisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export interface WorkerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export type AllRelayerRegistryEvents =
| RelayerRegisteredEvents
| RelayerUnregisteredEvents
| WorkerRegisteredEvents
| WorkerUnregisteredEvents;
export interface StakeBurnedEvents extends MinimalEvents {
relayerAddress: string;
amountBurned: string;
instanceAddress: string;
gasFee: string;
relayerFee: string;
timestamp: number;
}
// Deprecated type
export type RegistersEvents = MinimalEvents & RelayerParams;
export interface DepositsEvents extends MinimalEvents {

@ -1,4 +1,4 @@
import { getAddress } from 'ethers';
import { ContractEventName, getAddress } from 'ethers';
import { fetchData, fetchDataOptions } from '../providers';
import type {
@ -7,7 +7,6 @@ import type {
DepositsEvents,
WithdrawalsEvents,
EncryptedNotesEvents,
BatchGraphOnProgress,
EchoEvents,
AllGovernanceEvents,
GovernanceProposalCreatedEvents,
@ -34,6 +33,18 @@ 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 BatchGraphOnProgress = ({
type,
fromBlock,
toBlock,
count,
}: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export interface queryGraphParams {
graphApi: string;
subgraphName: string;

@ -370,16 +370,38 @@ export async function getIndexedDB(netId?: NetIdType) {
if (registryContract) {
stores.push({
name: `registered_${netId}`,
name: `registry_${netId}`,
keyPath: 'ensName',
indexes: [
...minimalIndexes,
{
name: 'relayerAddress',
name: 'event',
unique: false,
},
],
});
stores.push({
name: `relayers_${netId}`,
keyPath: 'timestamp',
indexes: [
{
name: 'timestamp',
unique: true,
},
],
});
stores.push({
name: `revenue_${netId}`,
keyPath: 'timestamp',
indexes: [
{
name: 'timestamp',
unique: true,
},
],
});
}
if (governanceContract) {

@ -1,5 +1,5 @@
export * from './events';
export * from './graphql';
//export * from './graphql';
export * from './schemas';
export * from './typechain';
export * from './batch';

@ -126,6 +126,14 @@ export const defaultConfig: networkConfig = {
networkName: 'Ethereum Mainnet',
deployedBlock: 9116966,
rpcUrls: {
tornadoWithdraw: {
name: 'tornadowithdraw.eth',
url: 'https://tornadowithdraw.com/mainnet',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com',
},
mevblockerRPC: {
name: 'MevblockerRPC',
url: 'https://rpc.mevblocker.io',
@ -269,6 +277,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/bsc-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'tornadowithdraw.eth',
url: 'https://tornadowithdraw.com/bsc',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/bsc',
},
bnbchain: {
name: 'BNB Chain',
url: 'https://bsc-dataseed.bnbchain.org',
@ -490,6 +506,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/xdai-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'tornadowithdraw.eth',
url: 'https://tornadowithdraw.com/gnosis',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/gnosis',
},
gnosis: {
name: 'Gnosis',
url: 'https://rpc.gnosischain.com',
@ -597,6 +621,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
subgraphs: {},
rpcUrls: {
tornadoWithdraw: {
name: 'tornadowithdraw.eth',
url: 'https://tornadowithdraw.com/sepolia',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/sepolia',
},
sepolia: {
name: 'Sepolia RPC',
url: 'https://rpc.sepolia.org',

@ -33,7 +33,7 @@ declare global {
}
// Update this for every Tor Browser release
export const defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0';
export const defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0';
export const fetch = crossFetch as unknown as nodeFetch;

@ -92,16 +92,80 @@ export const governanceEventsSchema = {
},
} as const;
export const registeredEventsSchema = {
export const relayerRegistryEventsSchema = {
type: 'array',
items: {
anyOf: [
// RelayerRegisteredEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
ensName: { type: 'string' },
relayerAddress: addressSchemaType,
ensHash: { type: 'string' },
stakedAmount: { type: 'string' },
},
required: [
...baseEventsSchemaRequired,
'event',
'ensName',
'relayerAddress',
'ensHash',
'stakedAmount',
],
additionalProperties: false,
},
// RelayerUnregisteredEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
relayerAddress: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'event', 'relayerAddress'],
additionalProperties: false,
},
// WorkerRegisteredEvents & WorkerUnregisteredEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
relayerAddress: addressSchemaType,
workerAddress: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'event', 'relayerAddress', 'workerAddress'],
additionalProperties: false,
},
],
},
} as const;
export const stakeBurnedEventsSchema = {
type: 'array',
items: {
type: 'object',
properties: {
...baseEventsSchemaProperty,
ensName: { type: 'string' },
relayerAddress: addressSchemaType,
amountBurned: bnSchemaType,
instanceAddress: addressSchemaType,
gasFee: bnSchemaType,
relayerFee: bnSchemaType,
timestamp: { type: 'number' },
},
required: [...baseEventsSchemaRequired, 'ensName', 'relayerAddress'],
required: [
...baseEventsSchemaRequired,
'relayerAddress',
'amountBurned',
'instanceAddress',
'gasFee',
'relayerFee',
'timestamp',
],
additionalProperties: false,
},
} as const;
@ -178,8 +242,12 @@ export function getEventsSchemaValidator(type: string) {
return ajv.compile(governanceEventsSchema);
}
if (type === 'registered') {
return ajv.compile(registeredEventsSchema);
if (type === 'registry') {
return ajv.compile(relayerRegistryEventsSchema);
}
if (type === 'revenue') {
return ajv.compile(stakeBurnedEventsSchema);
}
if (type === 'echo') {