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 { export interface BatchBlockServiceConstructor {
provider: Provider; provider: Provider;
onProgress?: BatchBlockOnProgress; onProgress?: BatchBlockOnProgress;
@ -42,8 +42,10 @@ export declare class BatchTransactionService {
retryOn: number; retryOn: number;
constructor({ provider, onProgress, concurrencySize, batchSize, shouldRetry, retryMax, retryOn, }: BatchBlockServiceConstructor); constructor({ provider, onProgress, concurrencySize, batchSize, shouldRetry, retryMax, retryOn, }: BatchBlockServiceConstructor);
getTransaction(txHash: string): Promise<TransactionResponse>; 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[]>; getBatchTransactions(txs: string[]): Promise<TransactionResponse[]>;
getBatchReceipt(txs: string[]): Promise<TransactionReceipt[]>;
} }
export interface BatchEventServiceConstructor { export interface BatchEventServiceConstructor {
provider: Provider; provider: Provider;

2
dist/ens.d.ts vendored

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

@ -1,6 +1,13 @@
import { ContractEventName } from 'ethers';
import { fetchDataOptions } from '../providers'; 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 * from './queries';
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export interface queryGraphParams { export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;

1
dist/index.d.ts vendored

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

2022
dist/index.js vendored

File diff suppressed because it is too large Load Diff

1995
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; 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 declare const fetch: nodeFetch;
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>; export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export type fetchDataOptions = RequestInit & { export type fetchDataOptions = RequestInit & {

@ -144,19 +144,128 @@ 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";
};
readonly relayerAddress: {
readonly type: "string";
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";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
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 type: "array";
readonly items: { readonly items: {
readonly type: "object"; readonly type: "object";
readonly properties: { readonly properties: {
readonly ensName: {
readonly type: "string";
};
readonly relayerAddress: { readonly relayerAddress: {
readonly type: "string"; readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$"; readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true; 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 blockNumber: {
readonly type: "number"; readonly type: "number";
}; };
@ -168,7 +277,7 @@ export declare const registeredEventsSchema: {
readonly pattern: "^0x[a-fA-F0-9]{64}$"; readonly pattern: "^0x[a-fA-F0-9]{64}$";
}; };
}; };
readonly required: readonly [...string[], "ensName", "relayerAddress"]; readonly required: readonly [...string[], "relayerAddress", "amountBurned", "instanceAddress", "gasFee", "relayerFee", "timestamp"];
readonly additionalProperties: false; readonly additionalProperties: false;
}; };
}; };

31691
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'; import { chunk, sleep } from './utils';
export interface BatchBlockServiceConstructor { export interface BatchBlockServiceConstructor {
@ -153,7 +162,21 @@ export class BatchTransactionService {
return txObject; 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) => { return batchArray.map(async (txs: string[], index: number) => {
await sleep(20 * index); await sleep(20 * index);
@ -164,7 +187,11 @@ export class BatchTransactionService {
// eslint-disable-next-line no-unmodified-loop-condition // eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) { while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try { try {
return await Promise.all(txs.map((tx) => this.getTransaction(tx))); 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) { } catch (e) {
retries++; retries++;
err = e; err = e;
@ -184,7 +211,34 @@ export class BatchTransactionService {
const results = []; const results = [];
for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) { 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); results.push(...chunksResult);

@ -121,13 +121,6 @@ export class ENSUtils {
return registry.setSubnodeRecord(parentNode, labelhash, owner, resolver.target, BigInt(0)); 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) { getResolver(name: string) {
return EnsResolver.fromName(this.provider, name); return EnsResolver.fromName(this.provider, name);
} }
@ -142,4 +135,11 @@ export class ENSUtils {
return (await resolver.getText(key)) || ''; 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, EventLog,
TransactionResponse, TransactionResponse,
getAddress, getAddress,
Block,
ContractEventName,
namehash, namehash,
formatEther, formatEther,
AbiCoder, AbiCoder,
@ -13,7 +11,7 @@ import {
dataSlice, dataSlice,
} from 'ethers'; } from 'ethers';
import type { import {
Tornado, Tornado,
TornadoRouter, TornadoRouter,
TornadoProxyLight, TornadoProxyLight,
@ -21,10 +19,9 @@ import type {
RelayerRegistry, RelayerRegistry,
Echoer, Echoer,
Aggregator, Aggregator,
Tornado__factory,
} from '@tornado/contracts'; } from '@tornado/contracts';
import * as graph from '../graphql';
import { import {
BatchEventsService, BatchEventsService,
BatchBlockService, BatchBlockService,
@ -52,9 +49,13 @@ import type {
GovernanceVotedEvents, GovernanceVotedEvents,
GovernanceDelegatedEvents, GovernanceDelegatedEvents,
GovernanceUndelegatedEvents, GovernanceUndelegatedEvents,
RegistersEvents,
BaseGraphEvents,
EchoEvents, EchoEvents,
RelayerRegisteredEvents,
RelayerUnregisteredEvents,
WorkerRegisteredEvents,
WorkerUnregisteredEvents,
AllRelayerRegistryEvents,
StakeBurnedEvents,
} from './types'; } from './types';
export const DEPOSIT = 'deposit'; export const DEPOSIT = 'deposit';
@ -63,8 +64,6 @@ export const WITHDRAWAL = 'withdrawal';
export interface BaseEventsServiceConstructor { export interface BaseEventsServiceConstructor {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract; contract: BaseContract;
type: string; type: string;
deployedBlock?: number; deployedBlock?: number;
@ -72,30 +71,9 @@ export interface BaseEventsServiceConstructor {
tovarishClient?: TovarishClient; 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> { export class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract; contract: BaseContract;
type: string; type: string;
deployedBlock: number; deployedBlock: number;
@ -106,8 +84,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
constructor({ constructor({
netId, netId,
provider, provider,
graphApi,
subgraphName,
contract, contract,
type = '', type = '',
deployedBlock = 0, deployedBlock = 0,
@ -116,8 +92,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
}: BaseEventsServiceConstructor) { }: BaseEventsServiceConstructor) {
this.netId = netId; this.netId = netId;
this.provider = provider; this.provider = provider;
this.graphApi = graphApi;
this.subgraphName = subgraphName;
this.fetchDataOptions = fetchDataOptions; this.fetchDataOptions = fetchDataOptions;
this.contract = contract; this.contract = contract;
@ -145,19 +119,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
return String(this.getType() || '').toLowerCase(); 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 */ /* eslint-disable @typescript-eslint/no-unused-vars */
updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) {} 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]) {} updateTransactionProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]) {}
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchGraphOnProgress>[0]) {}
/* eslint-enable @typescript-eslint/no-unused-vars */ /* eslint-enable @typescript-eslint/no-unused-vars */
async formatEvents(events: EventLog[]): Promise<EventType[]> { async formatEvents(events: EventLog[]): Promise<EventType[]> {
@ -205,35 +165,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
return dbEvents; 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({ async getEventsFromRpc({
fromBlock, fromBlock,
toBlock, toBlock,
@ -289,16 +220,9 @@ export class BaseEventsService<EventType extends MinimalEvents> {
}; };
} }
const graphEvents = await this.getEventsFromGraph({ fromBlock }); return await this.getEventsFromRpc({
const lastSyncBlock = fromBlock,
graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
const rpcEvents = await this.getEventsFromRpc({
fromBlock: lastSyncBlock,
}); });
return {
events: [...graphEvents.events, ...rpcEvents.events],
lastBlock: rpcEvents.lastBlock,
};
} }
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
@ -378,11 +302,6 @@ export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceCon
merkleTreeService?: MerkleTreeService; merkleTreeService?: MerkleTreeService;
} }
export interface DepositsGraphParams extends BaseGraphParams {
amount: string;
currency: string;
}
export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> { export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string; amount: string;
currency: string; currency: string;
@ -421,25 +340,14 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
return `${this.getType().toLowerCase()}s_${this.netId}_${this.currency}_${this.amount}`; 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)[]> { async formatEvents(events: EventLog[]): Promise<(DepositsEvents | WithdrawalsEvents)[]> {
const type = this.getType().toLowerCase(); const type = this.getType().toLowerCase();
if (type === DEPOSIT) { 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; const { commitment, leafIndex, timestamp } = args;
return { return {
@ -449,23 +357,15 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
commitment: commitment as string, commitment: commitment as string,
leafIndex: Number(leafIndex), leafIndex: Number(leafIndex),
timestamp: Number(timestamp), timestamp: Number(timestamp),
}; from: txs.find(({ hash }) => hash === transactionHash)?.from || '',
});
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,
}; };
}); });
} else { } 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; const { nullifierHash, to, fee } = args;
return { return {
@ -475,19 +375,7 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
nullifierHash: String(nullifierHash), nullifierHash: String(nullifierHash),
to: getAddress(to), to: getAddress(to),
fee: String(fee), fee: String(fee),
}; timestamp: blocks.find(({ number }) => number === blockNumber)?.timestamp || 0,
});
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,
}; };
}); });
} }
@ -559,10 +447,6 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
return `echo_${this.netId}`; return `echo_${this.netId}`;
} }
getGraphMethod(): string {
return 'getAllGraphEchoEvents';
}
async formatEvents(events: EventLog[]) { async formatEvents(events: EventLog[]) {
return events return events
.map(({ blockNumber, index: logIndex, transactionHash, args }) => { .map(({ blockNumber, index: logIndex, transactionHash, args }) => {
@ -584,18 +468,6 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
}) })
.filter((e) => e) as 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'> { export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
@ -619,10 +491,6 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
return 'encrypted_notes'; return 'encrypted_notes';
} }
getGraphMethod(): string {
return 'getAllEncryptedNotes';
}
async formatEvents(events: EventLog[]) { async formatEvents(events: EventLog[]) {
return events return events
.map(({ blockNumber, index: logIndex, transactionHash, args }) => { .map(({ blockNumber, index: logIndex, transactionHash, args }) => {
@ -789,10 +657,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
return 'governance'; return 'governance';
} }
getGraphMethod() {
return 'getAllGovernanceEvents';
}
async formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]> { async formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]> {
const proposalEvents: GovernanceProposalCreatedEvents[] = []; const proposalEvents: GovernanceProposalCreatedEvents[] = [];
const votedEvents: GovernanceVotedEvents[] = []; const votedEvents: GovernanceVotedEvents[] = [];
@ -880,18 +744,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
return [...proposalEvents, ...votedEvents, ...delegatedEvents, ...undelegatedEvents]; 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[]> { async getAllProposals(): Promise<GovernanceProposals[]> {
const { events } = await this.updateEvents(); const { events } = await this.updateEvents();
@ -1091,7 +943,7 @@ export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceCo
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
} }
export class BaseRegistryService extends BaseEventsService<RegistersEvents> { export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> {
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
updateInterval: number; updateInterval: number;
@ -1102,7 +954,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
super({ super({
...serviceConstructor, ...serviceConstructor,
contract, contract,
type: 'RelayerRegistered', type: '*',
}); });
this.Aggregator = Aggregator; this.Aggregator = Aggregator;
@ -1112,32 +964,75 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
} }
getInstanceName() { getInstanceName() {
return `registered_${this.netId}`; return `registry_${this.netId}`;
} }
getTovarishType(): string { getTovarishType(): string {
return 'registered'; return 'registry';
} }
// Name of method used for graph async formatEvents(events: EventLog[]): Promise<AllRelayerRegistryEvents[]> {
getGraphMethod() { const relayerRegisteredEvents: RelayerRegisteredEvents[] = [];
return 'getAllRegisters'; const relayerUnregisteredEvents: RelayerUnregisteredEvents[] = [];
} const workerRegisteredEvents: WorkerRegisteredEvents[] = [];
const workerUnregisteredEvents: WorkerUnregisteredEvents[] = [];
async formatEvents(events: EventLog[]) { events.forEach(({ blockNumber, index: logIndex, transactionHash, args, eventName: event }) => {
return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const eventObjects = { const eventObjects = {
blockNumber, blockNumber,
logIndex, logIndex,
transactionHash, transactionHash,
event,
}; };
return { if (event === 'RelayerRegistered') {
...eventObjects, const { relayer: ensHash, ensName, relayerAddress, stakedAmount } = args;
ensName: args.ensName,
relayerAddress: args.relayerAddress, relayerRegisteredEvents.push({
}; ...eventObjects,
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,
];
} }
/** /**
@ -1174,7 +1069,9 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
} }
async getLatestRelayers(): Promise<CachedRelayers> { 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); const subdomains = Object.values(this.relayerEnsSubdomains);
@ -1275,3 +1172,117 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
return { lastBlock, timestamp, relayers }; 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 { downloadZip } from '../zip';
import { IndexedDB } from '../idb'; import { IndexedDB } from '../idb';
import { bytesToBase64, digest } from '../utils';
import { fetchData } from '../providers';
import { import {
BaseTornadoService, BaseTornadoService,
BaseTornadoServiceConstructor, BaseTornadoServiceConstructor,
@ -12,6 +14,9 @@ import {
BaseGovernanceServiceConstructor, BaseGovernanceServiceConstructor,
BaseRegistryService, BaseRegistryService,
BaseRegistryServiceConstructor, BaseRegistryServiceConstructor,
BaseRevenueService,
BaseRevenueServiceConstructor,
CachedRelayers,
} from './base'; } from './base';
import { import {
@ -23,7 +28,8 @@ import {
EchoEvents, EchoEvents,
EncryptedNotesEvents, EncryptedNotesEvents,
AllGovernanceEvents, AllGovernanceEvents,
RegistersEvents, AllRelayerRegistryEvents,
StakeBurnedEvents,
} from './types'; } from './types';
export async function saveDBEvents<T extends MinimalEvents>({ export async function saveDBEvents<T extends MinimalEvents>({
@ -338,6 +344,7 @@ export class DBRegistryService extends BaseRegistryService {
idb: IndexedDB; idb: IndexedDB;
zipDigest?: string; zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRegistryServiceConstructor) { constructor(params: DBRegistryServiceConstructor) {
super(params); super(params);
@ -347,14 +354,14 @@ export class DBRegistryService extends BaseRegistryService {
} }
async getEventsFromDB() { async getEventsFromDB() {
return await loadDBEvents<RegistersEvents>({ return await loadDBEvents<AllRelayerRegistryEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
}); });
} }
async getEventsFromCache() { async getEventsFromCache() {
return await loadRemoteEvents<RegistersEvents>({ return await loadRemoteEvents<AllRelayerRegistryEvents>({
staticUrl: this.staticUrl, staticUrl: this.staticUrl,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock, deployedBlock: this.deployedBlock,
@ -362,8 +369,128 @@ export class DBRegistryService extends BaseRegistryService {
}); });
} }
async saveEvents({ events, lastBlock }: BaseEvents<RegistersEvents>) { async saveEvents({ events, lastBlock }: BaseEvents<AllRelayerRegistryEvents>) {
await saveDBEvents<RegistersEvents>({ 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, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
events, events,

@ -58,6 +58,45 @@ export type AllGovernanceEvents =
| GovernanceDelegatedEvents | GovernanceDelegatedEvents
| GovernanceUndelegatedEvents; | 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 type RegistersEvents = MinimalEvents & RelayerParams;
export interface DepositsEvents extends MinimalEvents { export interface DepositsEvents extends MinimalEvents {

@ -1,4 +1,4 @@
import { getAddress } from 'ethers'; import { ContractEventName, getAddress } from 'ethers';
import { fetchData, fetchDataOptions } from '../providers'; import { fetchData, fetchDataOptions } from '../providers';
import type { import type {
@ -7,7 +7,6 @@ import type {
DepositsEvents, DepositsEvents,
WithdrawalsEvents, WithdrawalsEvents,
EncryptedNotesEvents, EncryptedNotesEvents,
BatchGraphOnProgress,
EchoEvents, EchoEvents,
AllGovernanceEvents, AllGovernanceEvents,
GovernanceProposalCreatedEvents, 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 // https://thegraph.com/docs/en/developing/developer-faqs/#23-is-there-a-limit-to-how-many-objects-the-graph-can-return-per-query
const GRAPHQL_LIMIT = 1000; const GRAPHQL_LIMIT = 1000;
export type BatchGraphOnProgress = ({
type,
fromBlock,
toBlock,
count,
}: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export interface queryGraphParams { export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;

@ -370,16 +370,38 @@ export async function getIndexedDB(netId?: NetIdType) {
if (registryContract) { if (registryContract) {
stores.push({ stores.push({
name: `registered_${netId}`, name: `registry_${netId}`,
keyPath: 'ensName', keyPath: 'ensName',
indexes: [ indexes: [
...minimalIndexes, ...minimalIndexes,
{ {
name: 'relayerAddress', name: 'event',
unique: false, 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) { if (governanceContract) {

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

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

@ -33,7 +33,7 @@ declare global {
} }
// Update this for every Tor Browser release // 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; export const fetch = crossFetch as unknown as nodeFetch;

@ -92,16 +92,80 @@ export const governanceEventsSchema = {
}, },
} as const; } 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', type: 'array',
items: { items: {
type: 'object', type: 'object',
properties: { properties: {
...baseEventsSchemaProperty, ...baseEventsSchemaProperty,
ensName: { type: 'string' },
relayerAddress: addressSchemaType, 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, additionalProperties: false,
}, },
} as const; } as const;
@ -178,8 +242,12 @@ export function getEventsSchemaValidator(type: string) {
return ajv.compile(governanceEventsSchema); return ajv.compile(governanceEventsSchema);
} }
if (type === 'registered') { if (type === 'registry') {
return ajv.compile(registeredEventsSchema); return ajv.compile(relayerRegistryEventsSchema);
}
if (type === 'revenue') {
return ajv.compile(stakeBurnedEventsSchema);
} }
if (type === 'echo') { if (type === 'echo') {