Compare commits
25 Commits
main
...
a0f11d6ff4
| Author | SHA1 | Date | |
|---|---|---|---|
|
a0f11d6ff4
|
|||
|
be0e2419aa
|
|||
|
bdcf48db73
|
|||
|
df1fcebfe3
|
|||
|
82aeabd739
|
|||
|
c155649719
|
|||
|
69faa7a974
|
|||
|
f7fdf7db0a
|
|||
|
d0b032d7be
|
|||
|
20368b243b
|
|||
|
29744cfce4
|
|||
|
48bb7aed82
|
|||
|
d6cfea1d19
|
|||
|
0bd87f9b67
|
|||
|
2bd991aa45
|
|||
|
700426acb7
|
|||
|
ef56beb29b
|
|||
|
e506c373de
|
|||
|
3df238e55f
|
|||
|
95dbf208c3
|
|||
|
84b6ed368e
|
|||
|
391ca0df37
|
|||
|
cf9e32f46d
|
|||
|
29bd7dc66e
|
|||
|
b32cf2dbbc
|
89
dist/events/base.d.ts
vendored
89
dist/events/base.d.ts
vendored
@@ -1,9 +1,11 @@
|
|||||||
import { BaseContract, Provider, EventLog, ContractEventName } from 'ethers';
|
import { BaseContract, Provider, EventLog, ContractEventName } from 'ethers';
|
||||||
import type { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer } from '@tornado/contracts';
|
import type { 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 } from '../networkConfig';
|
import type { NetIdType, SubdomainMap } from '../networkConfig';
|
||||||
import type { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types';
|
import { RelayerParams } from '../relayerClient';
|
||||||
|
import type { TovarishClient } from '../tovarishClient';
|
||||||
|
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types';
|
||||||
export declare const DEPOSIT = "deposit";
|
export declare const DEPOSIT = "deposit";
|
||||||
export declare const WITHDRAWAL = "withdrawal";
|
export declare const WITHDRAWAL = "withdrawal";
|
||||||
export type BaseEventsServiceConstructor = {
|
export type BaseEventsServiceConstructor = {
|
||||||
@@ -15,6 +17,7 @@ export type BaseEventsServiceConstructor = {
|
|||||||
type?: string;
|
type?: string;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
|
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
|
||||||
type?: ContractEventName;
|
type?: ContractEventName;
|
||||||
@@ -38,10 +41,11 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
deployedBlock: number;
|
deployedBlock: number;
|
||||||
batchEventsService: BatchEventsService;
|
batchEventsService: BatchEventsService;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
saveEventsPromise?: Promise<void>;
|
tovarishClient?: TovarishClient;
|
||||||
constructor({ netId, provider, graphApi, subgraphName, contract, type, deployedBlock, fetchDataOptions, }: BaseEventsServiceConstructor);
|
constructor({ netId, provider, graphApi, subgraphName, contract, type, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEventsServiceConstructor);
|
||||||
getInstanceName(): string;
|
getInstanceName(): string;
|
||||||
getType(): string;
|
getType(): string;
|
||||||
|
getTovarishType(): string;
|
||||||
getGraphMethod(): string;
|
getGraphMethod(): string;
|
||||||
getGraphParams(): BaseGraphParams;
|
getGraphParams(): BaseGraphParams;
|
||||||
updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
|
updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
|
||||||
@@ -53,8 +57,11 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
* Get saved or cached events
|
* Get saved or cached events
|
||||||
*/
|
*/
|
||||||
getEventsFromDB(): Promise<BaseEvents<EventType>>;
|
getEventsFromDB(): Promise<BaseEvents<EventType>>;
|
||||||
getEventsFromCache(): Promise<BaseEvents<EventType>>;
|
/**
|
||||||
getSavedEvents(): Promise<BaseEvents<EventType>>;
|
* Events from remote cache (Either from local cache, CDN, or from IPFS)
|
||||||
|
*/
|
||||||
|
getEventsFromCache(): Promise<CachedEvents<EventType>>;
|
||||||
|
getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>>;
|
||||||
/**
|
/**
|
||||||
* Get latest events
|
* Get latest events
|
||||||
*/
|
*/
|
||||||
@@ -79,7 +86,7 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
*/
|
*/
|
||||||
updateEvents(): Promise<{
|
updateEvents(): Promise<{
|
||||||
events: EventType[];
|
events: EventType[];
|
||||||
lastBlock: number | null;
|
lastBlock: number;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
export type BaseTornadoServiceConstructor = {
|
export type BaseTornadoServiceConstructor = {
|
||||||
@@ -93,6 +100,7 @@ export type BaseTornadoServiceConstructor = {
|
|||||||
currency: string;
|
currency: string;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
export type DepositsGraphParams = BaseGraphParams & {
|
export type DepositsGraphParams = BaseGraphParams & {
|
||||||
amount: string;
|
amount: string;
|
||||||
@@ -103,7 +111,8 @@ export declare class BaseTornadoService extends BaseEventsService<DepositsEvents
|
|||||||
currency: string;
|
currency: string;
|
||||||
batchTransactionService: BatchTransactionService;
|
batchTransactionService: BatchTransactionService;
|
||||||
batchBlockService: BatchBlockService;
|
batchBlockService: BatchBlockService;
|
||||||
constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, }: BaseTornadoServiceConstructor);
|
tovarishClient?: TovarishClient;
|
||||||
|
constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, tovarishClient, }: BaseTornadoServiceConstructor);
|
||||||
getInstanceName(): string;
|
getInstanceName(): string;
|
||||||
getGraphMethod(): string;
|
getGraphMethod(): string;
|
||||||
getGraphParams(): DepositsGraphParams;
|
getGraphParams(): DepositsGraphParams;
|
||||||
@@ -111,6 +120,9 @@ export declare class BaseTornadoService extends BaseEventsService<DepositsEvents
|
|||||||
validateEvents({ events }: {
|
validateEvents({ events }: {
|
||||||
events: (DepositsEvents | WithdrawalsEvents)[];
|
events: (DepositsEvents | WithdrawalsEvents)[];
|
||||||
}): void;
|
}): void;
|
||||||
|
getLatestEvents({ fromBlock }: {
|
||||||
|
fromBlock: number;
|
||||||
|
}): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
|
||||||
}
|
}
|
||||||
export type BaseEchoServiceConstructor = {
|
export type BaseEchoServiceConstructor = {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
@@ -120,9 +132,10 @@ export type BaseEchoServiceConstructor = {
|
|||||||
Echoer: Echoer;
|
Echoer: Echoer;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
|
export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
|
||||||
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, }: BaseEchoServiceConstructor);
|
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEchoServiceConstructor);
|
||||||
getInstanceName(): string;
|
getInstanceName(): string;
|
||||||
getType(): string;
|
getType(): string;
|
||||||
getGraphMethod(): string;
|
getGraphMethod(): string;
|
||||||
@@ -139,11 +152,13 @@ export type BaseEncryptedNotesServiceConstructor = {
|
|||||||
Router: TornadoRouter | TornadoProxyLight;
|
Router: TornadoRouter | TornadoProxyLight;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
export declare class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
|
export declare class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
|
||||||
constructor({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, }: BaseEncryptedNotesServiceConstructor);
|
constructor({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEncryptedNotesServiceConstructor);
|
||||||
getInstanceName(): string;
|
getInstanceName(): string;
|
||||||
getType(): string;
|
getType(): string;
|
||||||
|
getTovarishType(): string;
|
||||||
getGraphMethod(): string;
|
getGraphMethod(): string;
|
||||||
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
|
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
|
||||||
}
|
}
|
||||||
@@ -155,31 +170,60 @@ export type BaseGovernanceServiceConstructor = {
|
|||||||
Governance: Governance;
|
Governance: Governance;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
|
export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
|
||||||
batchTransactionService: BatchTransactionService;
|
batchTransactionService: BatchTransactionService;
|
||||||
constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, }: BaseGovernanceServiceConstructor);
|
constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, tovarishClient, }: BaseGovernanceServiceConstructor);
|
||||||
getInstanceName(): string;
|
getInstanceName(): string;
|
||||||
getType(): string;
|
getType(): string;
|
||||||
|
getTovarishType(): string;
|
||||||
getGraphMethod(): string;
|
getGraphMethod(): string;
|
||||||
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
|
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
|
||||||
getEventsFromGraph({ fromBlock }: {
|
getEventsFromGraph({ fromBlock }: {
|
||||||
fromBlock: number;
|
fromBlock: number;
|
||||||
}): Promise<BaseEvents<AllGovernanceEvents>>;
|
}): Promise<BaseEvents<AllGovernanceEvents>>;
|
||||||
}
|
}
|
||||||
|
export declare function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Essential params:
|
||||||
|
* ensName, relayerAddress, hostnames
|
||||||
|
* Other data is for historic purpose from relayer registry
|
||||||
|
*/
|
||||||
|
export interface CachedRelayerInfo extends RelayerParams {
|
||||||
|
isRegistered?: boolean;
|
||||||
|
owner?: string;
|
||||||
|
stakeBalance?: string;
|
||||||
|
hostnames: SubdomainMap;
|
||||||
|
tovarishHost?: string;
|
||||||
|
tovarishNetworks?: number[];
|
||||||
|
}
|
||||||
|
export interface CachedRelayers {
|
||||||
|
lastBlock: number;
|
||||||
|
timestamp: number;
|
||||||
|
relayers: CachedRelayerInfo[];
|
||||||
|
fromCache?: boolean;
|
||||||
|
}
|
||||||
export type BaseRegistryServiceConstructor = {
|
export type BaseRegistryServiceConstructor = {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
provider: Provider;
|
provider: Provider;
|
||||||
graphApi?: string;
|
graphApi?: string;
|
||||||
subgraphName?: string;
|
subgraphName?: string;
|
||||||
RelayerRegistry: RelayerRegistry;
|
RelayerRegistry: RelayerRegistry;
|
||||||
|
Aggregator: Aggregator;
|
||||||
|
relayerEnsSubdomains: SubdomainMap;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
export declare class BaseRegistryService extends BaseEventsService<RegistersEvents> {
|
export declare class BaseRegistryService extends BaseEventsService<RegistersEvents> {
|
||||||
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, deployedBlock, fetchDataOptions, }: BaseRegistryServiceConstructor);
|
Aggregator: Aggregator;
|
||||||
|
relayerEnsSubdomains: SubdomainMap;
|
||||||
|
updateInterval: number;
|
||||||
|
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, tovarishClient, }: BaseRegistryServiceConstructor);
|
||||||
getInstanceName(): string;
|
getInstanceName(): string;
|
||||||
getType(): string;
|
getType(): string;
|
||||||
|
getTovarishType(): string;
|
||||||
getGraphMethod(): string;
|
getGraphMethod(): string;
|
||||||
formatEvents(events: EventLog[]): Promise<{
|
formatEvents(events: EventLog[]): Promise<{
|
||||||
ensName: any;
|
ensName: any;
|
||||||
@@ -188,5 +232,22 @@ export declare class BaseRegistryService extends BaseEventsService<RegistersEven
|
|||||||
logIndex: number;
|
logIndex: number;
|
||||||
transactionHash: string;
|
transactionHash: string;
|
||||||
}[]>;
|
}[]>;
|
||||||
fetchRelayers(): Promise<RegistersEvents[]>;
|
/**
|
||||||
|
* Get saved or cached relayers
|
||||||
|
*/
|
||||||
|
getRelayersFromDB(): Promise<CachedRelayers>;
|
||||||
|
/**
|
||||||
|
* Relayers from remote cache (Either from local cache, CDN, or from IPFS)
|
||||||
|
*/
|
||||||
|
getRelayersFromCache(): Promise<CachedRelayers>;
|
||||||
|
getSavedRelayers(): Promise<CachedRelayers>;
|
||||||
|
getLatestRelayers(): Promise<CachedRelayers>;
|
||||||
|
/**
|
||||||
|
* Handle saving relayers
|
||||||
|
*/
|
||||||
|
saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Get cached or latest relayer and save to local
|
||||||
|
*/
|
||||||
|
updateRelayers(): Promise<CachedRelayers>;
|
||||||
}
|
}
|
||||||
|
|||||||
3
dist/events/types.d.ts
vendored
3
dist/events/types.d.ts
vendored
@@ -3,6 +3,9 @@ export interface BaseEvents<T> {
|
|||||||
events: T[];
|
events: T[];
|
||||||
lastBlock: number | null;
|
lastBlock: number | null;
|
||||||
}
|
}
|
||||||
|
export interface CachedEvents<T> extends BaseEvents<T> {
|
||||||
|
fromCache: boolean;
|
||||||
|
}
|
||||||
export interface BaseGraphEvents<T> {
|
export interface BaseGraphEvents<T> {
|
||||||
events: T[];
|
events: T[];
|
||||||
lastSyncBlock: number;
|
lastSyncBlock: number;
|
||||||
|
|||||||
1
dist/index.d.ts
vendored
1
dist/index.d.ts
vendored
@@ -15,5 +15,6 @@ export * from './prices';
|
|||||||
export * from './providers';
|
export * from './providers';
|
||||||
export * from './relayerClient';
|
export * from './relayerClient';
|
||||||
export * from './tokens';
|
export * from './tokens';
|
||||||
|
export * from './tovarishClient';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './websnark';
|
export * from './websnark';
|
||||||
|
|||||||
7472
dist/index.js
vendored
7472
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
7462
dist/index.mjs
vendored
7462
dist/index.mjs
vendored
File diff suppressed because it is too large
Load Diff
17963
dist/merkleTreeWorker.js
vendored
17963
dist/merkleTreeWorker.js
vendored
File diff suppressed because it is too large
Load Diff
26791
dist/merkleTreeWorker.umd.js
vendored
26791
dist/merkleTreeWorker.umd.js
vendored
File diff suppressed because one or more lines are too long
2
dist/merkleTreeWorker.umd.min.js
vendored
Normal file
2
dist/merkleTreeWorker.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
26
dist/merkleTreeWorker.umd.min.js.LICENSE.txt
vendored
Normal file
26
dist/merkleTreeWorker.umd.min.js.LICENSE.txt
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*!
|
||||||
|
* The buffer module from node.js, for the browser.
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The buffer module from node.js, for the browser.
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <https://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||||
|
|
||||||
|
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [js-sha3]{@link https://github.com/emn178/js-sha3}
|
||||||
|
*
|
||||||
|
* @version 0.8.0
|
||||||
|
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
||||||
|
* @copyright Chen, Yi-Cyuan 2015-2018
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
17
dist/networkConfig.d.ts
vendored
17
dist/networkConfig.d.ts
vendored
@@ -67,8 +67,6 @@ export type Config = {
|
|||||||
registryContract?: string;
|
registryContract?: string;
|
||||||
aggregatorContract?: string;
|
aggregatorContract?: string;
|
||||||
reverseRecordsContract?: string;
|
reverseRecordsContract?: string;
|
||||||
gasPriceOracleContract?: string;
|
|
||||||
gasStationApi?: string;
|
|
||||||
ovmGasPriceOracleContract?: string;
|
ovmGasPriceOracleContract?: string;
|
||||||
tornadoSubgraph: string;
|
tornadoSubgraph: string;
|
||||||
registrySubgraph?: string;
|
registrySubgraph?: string;
|
||||||
@@ -76,6 +74,7 @@ export type Config = {
|
|||||||
subgraphs: SubgraphUrls;
|
subgraphs: SubgraphUrls;
|
||||||
tokens: TokenInstances;
|
tokens: TokenInstances;
|
||||||
optionalTokens?: string[];
|
optionalTokens?: string[];
|
||||||
|
disabledTokens?: string[];
|
||||||
relayerEnsSubdomain: string;
|
relayerEnsSubdomain: string;
|
||||||
pollInterval: number;
|
pollInterval: number;
|
||||||
constants: {
|
constants: {
|
||||||
@@ -89,8 +88,11 @@ export type Config = {
|
|||||||
export type networkConfig = {
|
export type networkConfig = {
|
||||||
[key in NetIdType]: Config;
|
[key in NetIdType]: Config;
|
||||||
};
|
};
|
||||||
|
export type SubdomainMap = {
|
||||||
|
[key in NetIdType]: string;
|
||||||
|
};
|
||||||
export declare const defaultConfig: networkConfig;
|
export declare const defaultConfig: networkConfig;
|
||||||
export declare const enabledChains: number[];
|
export declare const enabledChains: NetIdType[];
|
||||||
/**
|
/**
|
||||||
* Custom config object to extend default config
|
* Custom config object to extend default config
|
||||||
*
|
*
|
||||||
@@ -106,11 +108,10 @@ export declare let customConfig: networkConfig;
|
|||||||
export declare function addNetwork(newConfig: networkConfig): void;
|
export declare function addNetwork(newConfig: networkConfig): void;
|
||||||
export declare function getNetworkConfig(): networkConfig;
|
export declare function getNetworkConfig(): networkConfig;
|
||||||
export declare function getConfig(netId: NetIdType): Config;
|
export declare function getConfig(netId: NetIdType): Config;
|
||||||
export declare function getInstanceByAddress({ netId, address }: {
|
export declare function getActiveTokens(config: Config): string[];
|
||||||
netId: NetIdType;
|
export declare function getActiveTokenInstances(config: Config): TokenInstances;
|
||||||
address: string;
|
export declare function getInstanceByAddress(config: Config, address: string): {
|
||||||
}): {
|
|
||||||
amount: string;
|
amount: string;
|
||||||
currency: string;
|
currency: string;
|
||||||
} | undefined;
|
} | undefined;
|
||||||
export declare function getSubdomains(): string[];
|
export declare function getRelayerEnsSubdomains(): SubdomainMap;
|
||||||
|
|||||||
9
dist/providers.d.ts
vendored
9
dist/providers.d.ts
vendored
@@ -1,9 +1,6 @@
|
|||||||
/// <reference types="node" />
|
|
||||||
/// <reference types="node" />
|
|
||||||
/// <reference types="node" />
|
|
||||||
import type { EventEmitter } from 'stream';
|
import type { EventEmitter } from 'stream';
|
||||||
import type { RequestOptions } from 'http';
|
import type { RequestOptions } from 'http';
|
||||||
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchUrlFeeDataNetworkPlugin } from 'ethers';
|
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner } from 'ethers';
|
||||||
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
|
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
|
||||||
import type { Config, NetIdType } from './networkConfig';
|
import type { Config, NetIdType } from './networkConfig';
|
||||||
declare global {
|
declare global {
|
||||||
@@ -35,11 +32,9 @@ export declare function getHttpAgent({ fetchUrl, proxyUrl, torPort, retry, }: {
|
|||||||
export declare function fetchData(url: string, options?: fetchDataOptions): Promise<any>;
|
export declare function fetchData(url: string, options?: fetchDataOptions): Promise<any>;
|
||||||
export declare const fetchGetUrlFunc: (options?: fetchDataOptions) => FetchGetUrlFunc;
|
export declare const fetchGetUrlFunc: (options?: fetchDataOptions) => FetchGetUrlFunc;
|
||||||
export type getProviderOptions = fetchDataOptions & {
|
export type getProviderOptions = fetchDataOptions & {
|
||||||
|
netId?: NetIdType;
|
||||||
pollingInterval?: number;
|
pollingInterval?: number;
|
||||||
gasPriceOracle?: string;
|
|
||||||
gasStationApi?: string;
|
|
||||||
};
|
};
|
||||||
export declare function getGasOraclePlugin(networkKey: string, fetchOptions?: getProviderOptions): FetchUrlFeeDataNetworkPlugin;
|
|
||||||
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
|
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
|
||||||
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
|
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
|
||||||
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
|
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
|
||||||
|
|||||||
69
dist/relayerClient.d.ts
vendored
69
dist/relayerClient.d.ts
vendored
@@ -1,35 +1,36 @@
|
|||||||
import type { Aggregator } from '@tornado/contracts';
|
|
||||||
import type { RelayerStructOutput } from '@tornado/contracts/dist/contracts/Governance/Aggregator/Aggregator';
|
|
||||||
import { NetIdType, Config } from './networkConfig';
|
import { NetIdType, Config } from './networkConfig';
|
||||||
import { fetchDataOptions } from './providers';
|
import { fetchDataOptions } from './providers';
|
||||||
import type { snarkProofs } from './websnark';
|
import type { snarkProofs } from './websnark';
|
||||||
|
import type { CachedRelayerInfo } from './events';
|
||||||
|
export declare const MIN_FEE = 0.1;
|
||||||
|
export declare const MAX_FEE = 0.9;
|
||||||
export declare const MIN_STAKE_BALANCE: bigint;
|
export declare const MIN_STAKE_BALANCE: bigint;
|
||||||
export interface RelayerParams {
|
export interface RelayerParams {
|
||||||
ensName: string;
|
ensName: string;
|
||||||
relayerAddress?: string;
|
relayerAddress: string;
|
||||||
}
|
}
|
||||||
export interface Relayer {
|
/**
|
||||||
|
* Info from relayer status
|
||||||
|
*/
|
||||||
|
export type RelayerInfo = RelayerParams & {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
url: string;
|
url: string;
|
||||||
hostname: string;
|
hostname: string;
|
||||||
rewardAccount: string;
|
rewardAccount: string;
|
||||||
instances: string[];
|
instances: string[];
|
||||||
|
stakeBalance?: string;
|
||||||
gasPrice?: number;
|
gasPrice?: number;
|
||||||
ethPrices?: {
|
ethPrices?: {
|
||||||
[key in string]: string;
|
[key in string]: string;
|
||||||
};
|
};
|
||||||
currentQueue: number;
|
currentQueue: number;
|
||||||
tornadoServiceFee: number;
|
tornadoServiceFee: number;
|
||||||
}
|
|
||||||
export type RelayerInfo = Relayer & {
|
|
||||||
ensName: string;
|
|
||||||
stakeBalance: bigint;
|
|
||||||
relayerAddress: string;
|
|
||||||
};
|
};
|
||||||
export type RelayerError = {
|
export type RelayerError = {
|
||||||
hostname: string;
|
hostname: string;
|
||||||
relayerAddress?: string;
|
relayerAddress?: string;
|
||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
|
hasError: boolean;
|
||||||
};
|
};
|
||||||
export interface RelayerStatus {
|
export interface RelayerStatus {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -62,6 +63,9 @@ export interface RelayerStatus {
|
|||||||
};
|
};
|
||||||
currentQueue: number;
|
currentQueue: number;
|
||||||
}
|
}
|
||||||
|
export type TornadoWithdrawParams = snarkProofs & {
|
||||||
|
contract: string;
|
||||||
|
};
|
||||||
export interface RelayerTornadoWithdraw {
|
export interface RelayerTornadoWithdraw {
|
||||||
id?: string;
|
id?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
@@ -78,6 +82,10 @@ export interface RelayerTornadoJobs {
|
|||||||
confirmations?: number;
|
confirmations?: number;
|
||||||
failedReason?: string;
|
failedReason?: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
const semVerRegex =
|
||||||
|
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
||||||
|
|
||||||
export interface semanticVersion {
|
export interface semanticVersion {
|
||||||
major: string;
|
major: string;
|
||||||
minor: string;
|
minor: string;
|
||||||
@@ -85,9 +93,23 @@ export interface semanticVersion {
|
|||||||
prerelease?: string;
|
prerelease?: string;
|
||||||
buildmetadata?: string;
|
buildmetadata?: string;
|
||||||
}
|
}
|
||||||
export declare function parseSemanticVersion(version: string): semanticVersion;
|
|
||||||
export declare function isRelayerUpdated(relayerVersion: string, netId: NetIdType): boolean;
|
export function parseSemanticVersion(version: string) {
|
||||||
export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo, minFee?: number, maxFee?: number): bigint;
|
const { groups } = semVerRegex.exec(version) as RegExpExecArray;
|
||||||
|
return groups as unknown as semanticVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
|
||||||
|
const { major, patch, prerelease } = parseSemanticVersion(relayerVersion);
|
||||||
|
// Save backwards compatibility with V4 relayers for Ethereum Mainnet
|
||||||
|
const requiredMajor = netId === NetId.MAINNET ? '4' : '5';
|
||||||
|
const isUpdatedMajor = major === requiredMajor;
|
||||||
|
|
||||||
|
if (prerelease) return false;
|
||||||
|
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
|
||||||
|
}
|
||||||
|
**/
|
||||||
|
export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo): bigint;
|
||||||
export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number;
|
export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number;
|
||||||
export type RelayerInstanceList = {
|
export type RelayerInstanceList = {
|
||||||
[key in string]: {
|
[key in string]: {
|
||||||
@@ -97,32 +119,29 @@ export type RelayerInstanceList = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[];
|
export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[];
|
||||||
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdType): RelayerInfo;
|
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
|
||||||
export interface RelayerClientConstructor {
|
export interface RelayerClientConstructor {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
config: Config;
|
config: Config;
|
||||||
Aggregator: Aggregator;
|
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
}
|
}
|
||||||
export type RelayerClientWithdraw = snarkProofs & {
|
|
||||||
contract: string;
|
|
||||||
};
|
|
||||||
export declare class RelayerClient {
|
export declare class RelayerClient {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
config: Config;
|
config: Config;
|
||||||
Aggregator: Aggregator;
|
selectedRelayer?: RelayerInfo;
|
||||||
selectedRelayer?: Relayer;
|
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
constructor({ netId, config, Aggregator, fetchDataOptions }: RelayerClientConstructor);
|
tovarish: boolean;
|
||||||
askRelayerStatus({ hostname, relayerAddress, }: {
|
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor);
|
||||||
hostname: string;
|
askRelayerStatus({ hostname, url, relayerAddress, }: {
|
||||||
|
hostname?: string;
|
||||||
|
url?: string;
|
||||||
relayerAddress?: string;
|
relayerAddress?: string;
|
||||||
}): Promise<RelayerStatus>;
|
}): Promise<RelayerStatus>;
|
||||||
filterRelayer(curr: RelayerStructOutput, relayer: RelayerParams, subdomains: string[], debugRelayer?: boolean): Promise<RelayerInfo | RelayerError>;
|
filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined>;
|
||||||
getValidRelayers(relayers: RelayerParams[], subdomains: string[], debugRelayer?: boolean): Promise<{
|
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
|
||||||
validRelayers: RelayerInfo[];
|
validRelayers: RelayerInfo[];
|
||||||
invalidRelayers: RelayerError[];
|
invalidRelayers: RelayerError[];
|
||||||
}>;
|
}>;
|
||||||
pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
|
pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
|
||||||
tornadoWithdraw({ contract, proof, args }: RelayerClientWithdraw): Promise<void>;
|
tornadoWithdraw({ contract, proof, args }: TornadoWithdrawParams): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
20
dist/schemas/status.d.ts
vendored
20
dist/schemas/status.d.ts
vendored
@@ -74,6 +74,24 @@ export type statusSchema = {
|
|||||||
};
|
};
|
||||||
required: string[];
|
required: string[];
|
||||||
};
|
};
|
||||||
|
syncStatus: {
|
||||||
|
type: string;
|
||||||
|
properties: {
|
||||||
|
events: {
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
tokenPrice: {
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
gasPrice: {
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
required: string[];
|
||||||
|
};
|
||||||
|
onSyncEvents: {
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
currentQueue: {
|
currentQueue: {
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
@@ -88,5 +106,5 @@ declare const bnType: {
|
|||||||
type: string;
|
type: string;
|
||||||
BN: boolean;
|
BN: boolean;
|
||||||
};
|
};
|
||||||
export declare function getStatusSchema(netId: NetIdType, config: Config): statusSchema;
|
export declare function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean): statusSchema;
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
37334
dist/index.umd.js → dist/tornado.umd.js
vendored
37334
dist/index.umd.js → dist/tornado.umd.js
vendored
File diff suppressed because one or more lines are too long
8
dist/tornado.umd.min.js
vendored
Normal file
8
dist/tornado.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
34
dist/tornado.umd.min.js.LICENSE.txt
vendored
Normal file
34
dist/tornado.umd.min.js.LICENSE.txt
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*!
|
||||||
|
* The buffer module from node.js, for the browser.
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The buffer module from node.js, for the browser.
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <https://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! MIT License. Copyright 2015-2022 Richard Moore <me@ricmoo.com>. See LICENSE.txt. */
|
||||||
|
|
||||||
|
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||||
|
|
||||||
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
|
|
||||||
|
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
|
|
||||||
|
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||||
|
|
||||||
|
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [js-sha3]{@link https://github.com/emn178/js-sha3}
|
||||||
|
*
|
||||||
|
* @version 0.8.0
|
||||||
|
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
||||||
|
* @copyright Chen, Yi-Cyuan 2015-2018
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
69
dist/tovarishClient.d.ts
vendored
Normal file
69
dist/tovarishClient.d.ts
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { RelayerClient, RelayerClientConstructor, RelayerError, RelayerInfo, RelayerStatus } from './relayerClient';
|
||||||
|
import { CachedRelayerInfo, MinimalEvents } from './events';
|
||||||
|
export declare const MAX_TOVARISH_EVENTS = 5000;
|
||||||
|
export interface EventsStatus {
|
||||||
|
events: number;
|
||||||
|
lastBlock: number;
|
||||||
|
}
|
||||||
|
export interface InstanceEventsStatus {
|
||||||
|
[index: string]: {
|
||||||
|
deposits: EventsStatus;
|
||||||
|
withdrawals: EventsStatus;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface CurrencyEventsStatus {
|
||||||
|
[index: string]: InstanceEventsStatus;
|
||||||
|
}
|
||||||
|
export interface TovarishEventsStatus {
|
||||||
|
governance?: EventsStatus;
|
||||||
|
registered?: {
|
||||||
|
lastBlock: number;
|
||||||
|
timestamp: number;
|
||||||
|
relayers: number;
|
||||||
|
};
|
||||||
|
echo: EventsStatus;
|
||||||
|
encrypted_notes: EventsStatus;
|
||||||
|
instances: CurrencyEventsStatus;
|
||||||
|
}
|
||||||
|
export interface TovarishSyncStatus {
|
||||||
|
events: boolean;
|
||||||
|
tokenPrice: boolean;
|
||||||
|
gasPrice: boolean;
|
||||||
|
}
|
||||||
|
export interface TovarishStatus extends RelayerStatus {
|
||||||
|
events: TovarishEventsStatus;
|
||||||
|
syncStatus: TovarishSyncStatus;
|
||||||
|
onSyncEvents: boolean;
|
||||||
|
}
|
||||||
|
export interface TovarishInfo extends RelayerInfo {
|
||||||
|
latestBlock: number;
|
||||||
|
version: string;
|
||||||
|
events: TovarishEventsStatus;
|
||||||
|
syncStatus: TovarishSyncStatus;
|
||||||
|
}
|
||||||
|
export interface TovarishEventsQuery {
|
||||||
|
type: string;
|
||||||
|
currency?: string;
|
||||||
|
amount?: string;
|
||||||
|
fromBlock: number;
|
||||||
|
recent?: boolean;
|
||||||
|
}
|
||||||
|
export interface BaseTovarishEvents<T> {
|
||||||
|
events: T[];
|
||||||
|
lastSyncBlock: number;
|
||||||
|
}
|
||||||
|
export declare class TovarishClient extends RelayerClient {
|
||||||
|
selectedRelayer?: TovarishInfo;
|
||||||
|
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor);
|
||||||
|
askRelayerStatus({ hostname, url, relayerAddress, }: {
|
||||||
|
hostname?: string;
|
||||||
|
url?: string;
|
||||||
|
relayerAddress?: string;
|
||||||
|
}): Promise<TovarishStatus>;
|
||||||
|
filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined>;
|
||||||
|
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
|
||||||
|
validRelayers: TovarishInfo[];
|
||||||
|
invalidRelayers: RelayerError[];
|
||||||
|
}>;
|
||||||
|
getEvents<T extends MinimalEvents>({ type, currency, amount, fromBlock, recent, }: TovarishEventsQuery): Promise<BaseTovarishEvents<T>>;
|
||||||
|
}
|
||||||
1
dist/typechain/factories/index.d.ts
vendored
1
dist/typechain/factories/index.d.ts
vendored
@@ -1,6 +1,5 @@
|
|||||||
export { ENS__factory } from "./ENS__factory";
|
export { ENS__factory } from "./ENS__factory";
|
||||||
export { ERC20__factory } from "./ERC20__factory";
|
export { ERC20__factory } from "./ERC20__factory";
|
||||||
export { GasPriceOracle__factory } from "./GasPriceOracle__factory";
|
|
||||||
export { Multicall__factory } from "./Multicall__factory";
|
export { Multicall__factory } from "./Multicall__factory";
|
||||||
export { OffchainOracle__factory } from "./OffchainOracle__factory";
|
export { OffchainOracle__factory } from "./OffchainOracle__factory";
|
||||||
export { OvmGasPriceOracle__factory } from "./OvmGasPriceOracle__factory";
|
export { OvmGasPriceOracle__factory } from "./OvmGasPriceOracle__factory";
|
||||||
|
|||||||
2
dist/typechain/index.d.ts
vendored
2
dist/typechain/index.d.ts
vendored
@@ -1,6 +1,5 @@
|
|||||||
export type { ENS } from "./ENS";
|
export type { ENS } from "./ENS";
|
||||||
export type { ERC20 } from "./ERC20";
|
export type { ERC20 } from "./ERC20";
|
||||||
export type { GasPriceOracle } from "./GasPriceOracle";
|
|
||||||
export type { Multicall } from "./Multicall";
|
export type { Multicall } from "./Multicall";
|
||||||
export type { OffchainOracle } from "./OffchainOracle";
|
export type { OffchainOracle } from "./OffchainOracle";
|
||||||
export type { OvmGasPriceOracle } from "./OvmGasPriceOracle";
|
export type { OvmGasPriceOracle } from "./OvmGasPriceOracle";
|
||||||
@@ -8,7 +7,6 @@ export type { ReverseRecords } from "./ReverseRecords";
|
|||||||
export * as factories from "./factories";
|
export * as factories from "./factories";
|
||||||
export { ENS__factory } from "./factories/ENS__factory";
|
export { ENS__factory } from "./factories/ENS__factory";
|
||||||
export { ERC20__factory } from "./factories/ERC20__factory";
|
export { ERC20__factory } from "./factories/ERC20__factory";
|
||||||
export { GasPriceOracle__factory } from "./factories/GasPriceOracle__factory";
|
|
||||||
export { Multicall__factory } from "./factories/Multicall__factory";
|
export { Multicall__factory } from "./factories/Multicall__factory";
|
||||||
export { OffchainOracle__factory } from "./factories/OffchainOracle__factory";
|
export { OffchainOracle__factory } from "./factories/OffchainOracle__factory";
|
||||||
export { OvmGasPriceOracle__factory } from "./factories/OvmGasPriceOracle__factory";
|
export { OvmGasPriceOracle__factory } from "./factories/OvmGasPriceOracle__factory";
|
||||||
|
|||||||
3
dist/utils.d.ts
vendored
3
dist/utils.d.ts
vendored
@@ -1,5 +1,3 @@
|
|||||||
/// <reference types="node" />
|
|
||||||
/// <reference types="node" />
|
|
||||||
import { webcrypto } from 'crypto';
|
import { webcrypto } from 'crypto';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import type { BigNumberish } from 'ethers';
|
import type { BigNumberish } from 'ethers';
|
||||||
@@ -24,4 +22,5 @@ export declare function toFixedLength(string: string, length?: number): string;
|
|||||||
export declare function rBigInt(nbytes?: number): bigint;
|
export declare function rBigInt(nbytes?: number): bigint;
|
||||||
export declare function bigIntReplacer(key: any, value: any): any;
|
export declare function bigIntReplacer(key: any, value: any): any;
|
||||||
export declare function substring(str: string, length?: number): string;
|
export declare function substring(str: string, length?: number): string;
|
||||||
|
export declare function digest(bytes: Uint8Array, algo?: string): Promise<Uint8Array>;
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
19
dist/websnark.d.ts
vendored
19
dist/websnark.d.ts
vendored
@@ -1,10 +1,9 @@
|
|||||||
import type { Element } from '@tornado/fixed-merkle-tree';
|
import type { Element } from '@tornado/fixed-merkle-tree';
|
||||||
import type { AddressLike, BytesLike, BigNumberish } from 'ethers';
|
|
||||||
export type snarkInputs = {
|
export type snarkInputs = {
|
||||||
root: Element;
|
root: Element;
|
||||||
nullifierHex: string;
|
nullifierHex: string;
|
||||||
recipient: AddressLike;
|
recipient: string;
|
||||||
relayer: AddressLike;
|
relayer: string;
|
||||||
fee: bigint;
|
fee: bigint;
|
||||||
refund: bigint;
|
refund: bigint;
|
||||||
nullifier: bigint;
|
nullifier: bigint;
|
||||||
@@ -13,15 +12,15 @@ export type snarkInputs = {
|
|||||||
pathIndices: Element[];
|
pathIndices: Element[];
|
||||||
};
|
};
|
||||||
export type snarkArgs = [
|
export type snarkArgs = [
|
||||||
_root: BytesLike,
|
_root: string,
|
||||||
_nullifierHash: BytesLike,
|
_nullifierHash: string,
|
||||||
_recipient: AddressLike,
|
_recipient: string,
|
||||||
_relayer: AddressLike,
|
_relayer: string,
|
||||||
_fee: BigNumberish,
|
_fee: string,
|
||||||
_refund: BigNumberish
|
_refund: string
|
||||||
];
|
];
|
||||||
export type snarkProofs = {
|
export type snarkProofs = {
|
||||||
proof: BytesLike;
|
proof: string;
|
||||||
args: snarkArgs;
|
args: snarkArgs;
|
||||||
};
|
};
|
||||||
export declare function initGroth16(): Promise<void>;
|
export declare function initGroth16(): Promise<void>;
|
||||||
|
|||||||
46
package.json
46
package.json
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@tornado/core",
|
"name": "@tornado/core",
|
||||||
"version": "1.0.1",
|
"version": "1.0.16",
|
||||||
"description": "An SDK for building applications on top of Privacy Pools",
|
"description": "An SDK for building applications on top of Privacy Pools",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"unpkg": "./dist/index.umd.js",
|
"unpkg": "./dist/tornado.umd.min.js",
|
||||||
"jsdelivr": "./dist/index.umd.js",
|
"jsdelivr": "./dist/tornado.umd.min.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
|
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
|
||||||
"types": "tsc --declaration --emitDeclarationOnly",
|
"types": "tsc --declaration --emitDeclarationOnly",
|
||||||
@@ -31,46 +31,44 @@
|
|||||||
"yarn.lock"
|
"yarn.lock"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@metamask/eth-sig-util": "^7.0.1",
|
"@metamask/eth-sig-util": "^7.0.3",
|
||||||
"@tornado/contracts": "^1.0.0",
|
"@tornado/contracts": "^1.0.1",
|
||||||
"@tornado/fixed-merkle-tree": "^0.7.3",
|
"@tornado/fixed-merkle-tree": "^0.7.3",
|
||||||
"@tornado/snarkjs": "^0.1.20",
|
"@tornado/snarkjs": "^0.1.20",
|
||||||
"@tornado/websnark": "^0.0.4",
|
"@tornado/websnark": "^0.0.4",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.17.1",
|
||||||
"bn.js": "^5.2.1",
|
"bn.js": "^5.2.1",
|
||||||
"circomlibjs": "0.1.7",
|
"circomlibjs": "0.1.7",
|
||||||
"cross-fetch": "^4.0.0",
|
"cross-fetch": "^4.0.0",
|
||||||
"ethers": "^6.4.0",
|
"ethers": "^6.13.2",
|
||||||
"ffjavascript": "0.2.48",
|
"ffjavascript": "0.2.48",
|
||||||
"fflate": "^0.8.2"
|
"fflate": "^0.8.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@rollup/plugin-commonjs": "^26.0.1",
|
||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@typechain/ethers-v6": "^0.5.1",
|
"@typechain/ethers-v6": "^0.5.1",
|
||||||
"@types/bn.js": "^5.1.5",
|
"@types/bn.js": "^5.1.6",
|
||||||
"@types/circomlibjs": "^0.1.6",
|
"@types/circomlibjs": "^0.1.6",
|
||||||
"@types/node": "^20.12.5",
|
"@types/node": "^22.5.5",
|
||||||
"@types/node-fetch": "^2.6.11",
|
"@types/node-fetch": "^2.6.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.6.0",
|
"@typescript-eslint/eslint-plugin": "^8.6.0",
|
||||||
"@typescript-eslint/parser": "^7.6.0",
|
"@typescript-eslint/parser": "^8.6.0",
|
||||||
"esbuild": "^0.20.2",
|
"esbuild-loader": "^4.2.2",
|
||||||
"esbuild-loader": "^4.1.0",
|
"eslint": "8.57.0",
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"eslint-import-resolver-typescript": "^3.6.3",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.30.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"node-polyfill-webpack-plugin": "^3.0.0",
|
"node-polyfill-webpack-plugin": "^4.0.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.3.3",
|
||||||
"rollup": "^4.14.1",
|
"rollup": "^4.22.0",
|
||||||
"rollup-plugin-esbuild": "^6.1.1",
|
"rollup-plugin-esbuild": "^6.1.1",
|
||||||
"tsc": "^2.0.4",
|
"tsc": "^2.0.4",
|
||||||
"typechain": "^8.3.2",
|
"typechain": "^8.3.2",
|
||||||
"typescript": "^5.4.4",
|
"typescript": "^5.6.2",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.94.0",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { readFileSync } from 'fs';
|
|||||||
const pkgJson = JSON.parse(readFileSync("./package.json"));
|
const pkgJson = JSON.parse(readFileSync("./package.json"));
|
||||||
|
|
||||||
const external = Object.keys(pkgJson.dependencies).concat(
|
const external = Object.keys(pkgJson.dependencies).concat(
|
||||||
Object.keys(pkgJson.optionalDependencies),
|
Object.keys(pkgJson.optionalDependencies || {}),
|
||||||
[
|
[
|
||||||
'http-proxy-agent',
|
'http-proxy-agent',
|
||||||
'https-proxy-agent',
|
'https-proxy-agent',
|
||||||
|
|||||||
@@ -1,189 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "GAS_UNIT",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "_derivationThresold",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "changeDerivationThresold",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "_gasUnit",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "changeGasUnit",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "_heartbeat",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "changeHeartbeat",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "changeOwnership",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "derivationThresold",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "gasPrice",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "heartbeat",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "maxFeePerGas",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "maxPriorityFeePerGas",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "owner",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "pastGasPrice",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "_gasPrice",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setGasPrice",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "timestamp",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,4 +1,15 @@
|
|||||||
import { BaseContract, Provider, EventLog, TransactionResponse, getAddress, Block, ContractEventName } from 'ethers';
|
import {
|
||||||
|
BaseContract,
|
||||||
|
Provider,
|
||||||
|
EventLog,
|
||||||
|
TransactionResponse,
|
||||||
|
getAddress,
|
||||||
|
Block,
|
||||||
|
ContractEventName,
|
||||||
|
namehash,
|
||||||
|
formatEther,
|
||||||
|
} from 'ethers';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
Tornado,
|
Tornado,
|
||||||
TornadoRouter,
|
TornadoRouter,
|
||||||
@@ -6,8 +17,11 @@ import type {
|
|||||||
Governance,
|
Governance,
|
||||||
RelayerRegistry,
|
RelayerRegistry,
|
||||||
Echoer,
|
Echoer,
|
||||||
|
Aggregator,
|
||||||
} from '@tornado/contracts';
|
} from '@tornado/contracts';
|
||||||
|
|
||||||
import * as graph from '../graphql';
|
import * as graph from '../graphql';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BatchEventsService,
|
BatchEventsService,
|
||||||
BatchBlockService,
|
BatchBlockService,
|
||||||
@@ -15,10 +29,15 @@ import {
|
|||||||
BatchEventOnProgress,
|
BatchEventOnProgress,
|
||||||
BatchBlockOnProgress,
|
BatchBlockOnProgress,
|
||||||
} from '../batch';
|
} from '../batch';
|
||||||
import { fetchDataOptions } from '../providers';
|
|
||||||
import type { NetIdType } from '../networkConfig';
|
import { fetchData, fetchDataOptions } from '../providers';
|
||||||
|
import type { NetIdType, SubdomainMap } from '../networkConfig';
|
||||||
|
import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient';
|
||||||
|
import type { TovarishClient } from '../tovarishClient';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
BaseEvents,
|
BaseEvents,
|
||||||
|
CachedEvents,
|
||||||
MinimalEvents,
|
MinimalEvents,
|
||||||
DepositsEvents,
|
DepositsEvents,
|
||||||
WithdrawalsEvents,
|
WithdrawalsEvents,
|
||||||
@@ -45,6 +64,7 @@ export type BaseEventsServiceConstructor = {
|
|||||||
type?: string;
|
type?: string;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BatchGraphOnProgress = ({
|
export type BatchGraphOnProgress = ({
|
||||||
@@ -76,8 +96,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
deployedBlock: number;
|
deployedBlock: number;
|
||||||
batchEventsService: BatchEventsService;
|
batchEventsService: BatchEventsService;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
saveEventsPromise?: Promise<void>;
|
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
netId,
|
netId,
|
||||||
@@ -88,6 +107,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
type = '',
|
type = '',
|
||||||
deployedBlock = 0,
|
deployedBlock = 0,
|
||||||
fetchDataOptions,
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
}: BaseEventsServiceConstructor) {
|
}: BaseEventsServiceConstructor) {
|
||||||
this.netId = netId;
|
this.netId = netId;
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
@@ -104,6 +124,8 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
contract,
|
contract,
|
||||||
onProgress: this.updateEventProgress,
|
onProgress: this.updateEventProgress,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.tovarishClient = tovarishClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstanceName(): string {
|
getInstanceName(): string {
|
||||||
@@ -114,6 +136,10 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
return this.type || '';
|
return this.type || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTovarishType(): string {
|
||||||
|
return String(this.getType() || '').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
getGraphMethod(): string {
|
getGraphMethod(): string {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -153,14 +179,18 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEventsFromCache(): Promise<BaseEvents<EventType>> {
|
/**
|
||||||
|
* Events from remote cache (Either from local cache, CDN, or from IPFS)
|
||||||
|
*/
|
||||||
|
async getEventsFromCache(): Promise<CachedEvents<EventType>> {
|
||||||
return {
|
return {
|
||||||
events: [],
|
events: [],
|
||||||
lastBlock: null,
|
lastBlock: null,
|
||||||
|
fromCache: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSavedEvents(): Promise<BaseEvents<EventType>> {
|
async getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>> {
|
||||||
let cachedEvents = await this.getEventsFromDB();
|
let cachedEvents = await this.getEventsFromDB();
|
||||||
|
|
||||||
if (!cachedEvents || !cachedEvents.events.length) {
|
if (!cachedEvents || !cachedEvents.events.length) {
|
||||||
@@ -224,13 +254,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
await this.batchEventsService.getBatchEvents({ fromBlock, toBlock, type: this.getType() }),
|
await this.batchEventsService.getBatchEvents({ fromBlock, toBlock, type: this.getType() }),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!events.length) {
|
|
||||||
return {
|
|
||||||
events,
|
|
||||||
lastBlock: toBlock,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
events,
|
events,
|
||||||
lastBlock: toBlock,
|
lastBlock: toBlock,
|
||||||
@@ -245,22 +268,25 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EventType>> {
|
async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EventType>> {
|
||||||
const allEvents = [];
|
if (this.tovarishClient?.selectedRelayer && ![DEPOSIT, WITHDRAWAL].includes(this.type.toLowerCase())) {
|
||||||
|
const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents<EventType>({
|
||||||
|
type: this.getTovarishType(),
|
||||||
|
fromBlock,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
events,
|
||||||
|
lastBlock,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const graphEvents = await this.getEventsFromGraph({ fromBlock });
|
const graphEvents = await this.getEventsFromGraph({ fromBlock });
|
||||||
const lastSyncBlock =
|
const lastSyncBlock =
|
||||||
graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
|
graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
|
||||||
const rpcEvents = await this.getEventsFromRpc({ fromBlock: lastSyncBlock });
|
const rpcEvents = await this.getEventsFromRpc({ fromBlock: lastSyncBlock });
|
||||||
allEvents.push(...graphEvents.events);
|
|
||||||
allEvents.push(...rpcEvents.events);
|
|
||||||
const lastBlock = rpcEvents
|
|
||||||
? rpcEvents.lastBlock
|
|
||||||
: allEvents[allEvents.length - 1]
|
|
||||||
? allEvents[allEvents.length - 1].blockNumber
|
|
||||||
: fromBlock;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
events: allEvents,
|
events: [...graphEvents.events, ...rpcEvents.events],
|
||||||
lastBlock,
|
lastBlock: rpcEvents.lastBlock,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,12 +317,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
|
|
||||||
const eventSet = new Set();
|
const eventSet = new Set();
|
||||||
|
|
||||||
let allEvents: EventType[] = [];
|
const allEvents: EventType[] = [...savedEvents.events, ...newEvents.events]
|
||||||
|
|
||||||
allEvents.push(...savedEvents.events);
|
|
||||||
allEvents.push(...newEvents.events);
|
|
||||||
|
|
||||||
allEvents = allEvents
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (a.blockNumber === b.blockNumber) {
|
if (a.blockNumber === b.blockNumber) {
|
||||||
return a.logIndex - b.logIndex;
|
return a.logIndex - b.logIndex;
|
||||||
@@ -309,15 +330,15 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
|||||||
eventSet.add(eventKey);
|
eventSet.add(eventKey);
|
||||||
return !hasEvent;
|
return !hasEvent;
|
||||||
});
|
});
|
||||||
const lastBlock = newEvents
|
|
||||||
? newEvents.lastBlock
|
const lastBlock = newEvents.lastBlock || allEvents[allEvents.length - 1]?.blockNumber;
|
||||||
: allEvents[allEvents.length - 1]
|
|
||||||
? allEvents[allEvents.length - 1].blockNumber
|
|
||||||
: null;
|
|
||||||
|
|
||||||
this.validateEvents({ events: allEvents, lastBlock });
|
this.validateEvents({ events: allEvents, lastBlock });
|
||||||
|
|
||||||
this.saveEventsPromise = this.saveEvents({ events: allEvents, lastBlock });
|
// If the events are loaded from cache or we have found new events, save them
|
||||||
|
if ((savedEvents as CachedEvents<EventType>).fromCache || newEvents.events.length) {
|
||||||
|
await this.saveEvents({ events: allEvents, lastBlock });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
events: allEvents,
|
events: allEvents,
|
||||||
@@ -337,6 +358,7 @@ export type BaseTornadoServiceConstructor = {
|
|||||||
currency: string;
|
currency: string;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DepositsGraphParams = BaseGraphParams & {
|
export type DepositsGraphParams = BaseGraphParams & {
|
||||||
@@ -349,6 +371,7 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
|
|||||||
currency: string;
|
currency: string;
|
||||||
batchTransactionService: BatchTransactionService;
|
batchTransactionService: BatchTransactionService;
|
||||||
batchBlockService: BatchBlockService;
|
batchBlockService: BatchBlockService;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
netId,
|
netId,
|
||||||
@@ -361,8 +384,19 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
|
|||||||
currency,
|
currency,
|
||||||
deployedBlock,
|
deployedBlock,
|
||||||
fetchDataOptions,
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
}: BaseTornadoServiceConstructor) {
|
}: BaseTornadoServiceConstructor) {
|
||||||
super({ netId, provider, graphApi, subgraphName, contract: Tornado, type, deployedBlock, fetchDataOptions });
|
super({
|
||||||
|
netId,
|
||||||
|
provider,
|
||||||
|
graphApi,
|
||||||
|
subgraphName,
|
||||||
|
contract: Tornado,
|
||||||
|
type,
|
||||||
|
deployedBlock,
|
||||||
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
|
});
|
||||||
|
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
@@ -464,6 +498,26 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>> {
|
||||||
|
if (this.tovarishClient?.selectedRelayer) {
|
||||||
|
const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents<
|
||||||
|
DepositsEvents | WithdrawalsEvents
|
||||||
|
>({
|
||||||
|
type: this.getTovarishType(),
|
||||||
|
currency: this.currency,
|
||||||
|
amount: this.amount,
|
||||||
|
fromBlock,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
events,
|
||||||
|
lastBlock,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getLatestEvents({ fromBlock });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BaseEchoServiceConstructor = {
|
export type BaseEchoServiceConstructor = {
|
||||||
@@ -474,6 +528,7 @@ export type BaseEchoServiceConstructor = {
|
|||||||
Echoer: Echoer;
|
Echoer: Echoer;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class BaseEchoService extends BaseEventsService<EchoEvents> {
|
export class BaseEchoService extends BaseEventsService<EchoEvents> {
|
||||||
@@ -485,8 +540,18 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
|
|||||||
Echoer,
|
Echoer,
|
||||||
deployedBlock,
|
deployedBlock,
|
||||||
fetchDataOptions,
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
}: BaseEchoServiceConstructor) {
|
}: BaseEchoServiceConstructor) {
|
||||||
super({ netId, provider, graphApi, subgraphName, contract: Echoer, deployedBlock, fetchDataOptions });
|
super({
|
||||||
|
netId,
|
||||||
|
provider,
|
||||||
|
graphApi,
|
||||||
|
subgraphName,
|
||||||
|
contract: Echoer,
|
||||||
|
deployedBlock,
|
||||||
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstanceName(): string {
|
getInstanceName(): string {
|
||||||
@@ -544,6 +609,7 @@ export type BaseEncryptedNotesServiceConstructor = {
|
|||||||
Router: TornadoRouter | TornadoProxyLight;
|
Router: TornadoRouter | TornadoProxyLight;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
|
export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
|
||||||
@@ -555,8 +621,18 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
|
|||||||
Router,
|
Router,
|
||||||
deployedBlock,
|
deployedBlock,
|
||||||
fetchDataOptions,
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
}: BaseEncryptedNotesServiceConstructor) {
|
}: BaseEncryptedNotesServiceConstructor) {
|
||||||
super({ netId, provider, graphApi, subgraphName, contract: Router, deployedBlock, fetchDataOptions });
|
super({
|
||||||
|
netId,
|
||||||
|
provider,
|
||||||
|
graphApi,
|
||||||
|
subgraphName,
|
||||||
|
contract: Router,
|
||||||
|
deployedBlock,
|
||||||
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstanceName(): string {
|
getInstanceName(): string {
|
||||||
@@ -567,6 +643,10 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
|
|||||||
return 'EncryptedNote';
|
return 'EncryptedNote';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTovarishType(): string {
|
||||||
|
return 'encrypted_notes';
|
||||||
|
}
|
||||||
|
|
||||||
getGraphMethod(): string {
|
getGraphMethod(): string {
|
||||||
return 'getAllEncryptedNotes';
|
return 'getAllEncryptedNotes';
|
||||||
}
|
}
|
||||||
@@ -576,7 +656,7 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
|
|||||||
.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
|
.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
|
||||||
const { encryptedNote } = args;
|
const { encryptedNote } = args;
|
||||||
|
|
||||||
if (encryptedNote) {
|
if (encryptedNote && encryptedNote !== '0x') {
|
||||||
const eventObjects = {
|
const eventObjects = {
|
||||||
blockNumber,
|
blockNumber,
|
||||||
logIndex,
|
logIndex,
|
||||||
@@ -601,6 +681,7 @@ export type BaseGovernanceServiceConstructor = {
|
|||||||
Governance: Governance;
|
Governance: Governance;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
|
export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
|
||||||
@@ -614,8 +695,18 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
|||||||
Governance,
|
Governance,
|
||||||
deployedBlock,
|
deployedBlock,
|
||||||
fetchDataOptions,
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
}: BaseGovernanceServiceConstructor) {
|
}: BaseGovernanceServiceConstructor) {
|
||||||
super({ netId, provider, graphApi, subgraphName, contract: Governance, deployedBlock, fetchDataOptions });
|
super({
|
||||||
|
netId,
|
||||||
|
provider,
|
||||||
|
graphApi,
|
||||||
|
subgraphName,
|
||||||
|
contract: Governance,
|
||||||
|
deployedBlock,
|
||||||
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
|
});
|
||||||
|
|
||||||
this.batchTransactionService = new BatchTransactionService({
|
this.batchTransactionService = new BatchTransactionService({
|
||||||
provider,
|
provider,
|
||||||
@@ -631,6 +722,10 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
|||||||
return '*';
|
return '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTovarishType(): string {
|
||||||
|
return 'governance';
|
||||||
|
}
|
||||||
|
|
||||||
getGraphMethod() {
|
getGraphMethod() {
|
||||||
return 'getAllGovernanceEvents';
|
return 'getAllGovernanceEvents';
|
||||||
}
|
}
|
||||||
@@ -735,27 +830,94 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]) {
|
||||||
|
await Promise.all(
|
||||||
|
relayers
|
||||||
|
.filter((r) => r.tovarishHost)
|
||||||
|
.map(async (relayer) => {
|
||||||
|
try {
|
||||||
|
relayer.tovarishNetworks = await fetchData(relayer.tovarishHost as string, {
|
||||||
|
...registryService.fetchDataOptions,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
timeout: registryService.fetchDataOptions?.torPort ? 10000 : 3000,
|
||||||
|
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Ignore error and disable relayer
|
||||||
|
relayer.tovarishNetworks = [];
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Essential params:
|
||||||
|
* ensName, relayerAddress, hostnames
|
||||||
|
* Other data is for historic purpose from relayer registry
|
||||||
|
*/
|
||||||
|
export interface CachedRelayerInfo extends RelayerParams {
|
||||||
|
isRegistered?: boolean;
|
||||||
|
owner?: string;
|
||||||
|
stakeBalance?: string;
|
||||||
|
hostnames: SubdomainMap;
|
||||||
|
tovarishHost?: string;
|
||||||
|
tovarishNetworks?: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CachedRelayers {
|
||||||
|
lastBlock: number;
|
||||||
|
timestamp: number;
|
||||||
|
relayers: CachedRelayerInfo[];
|
||||||
|
fromCache?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export type BaseRegistryServiceConstructor = {
|
export type BaseRegistryServiceConstructor = {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
provider: Provider;
|
provider: Provider;
|
||||||
graphApi?: string;
|
graphApi?: string;
|
||||||
subgraphName?: string;
|
subgraphName?: string;
|
||||||
RelayerRegistry: RelayerRegistry;
|
RelayerRegistry: RelayerRegistry;
|
||||||
|
Aggregator: Aggregator;
|
||||||
|
relayerEnsSubdomains: SubdomainMap;
|
||||||
deployedBlock?: number;
|
deployedBlock?: number;
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarishClient?: TovarishClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
|
export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
|
||||||
|
Aggregator: Aggregator;
|
||||||
|
relayerEnsSubdomains: SubdomainMap;
|
||||||
|
updateInterval: number;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
netId,
|
netId,
|
||||||
provider,
|
provider,
|
||||||
graphApi,
|
graphApi,
|
||||||
subgraphName,
|
subgraphName,
|
||||||
RelayerRegistry,
|
RelayerRegistry,
|
||||||
|
Aggregator,
|
||||||
|
relayerEnsSubdomains,
|
||||||
deployedBlock,
|
deployedBlock,
|
||||||
fetchDataOptions,
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
}: BaseRegistryServiceConstructor) {
|
}: BaseRegistryServiceConstructor) {
|
||||||
super({ netId, provider, graphApi, subgraphName, contract: RelayerRegistry, deployedBlock, fetchDataOptions });
|
super({
|
||||||
|
netId,
|
||||||
|
provider,
|
||||||
|
graphApi,
|
||||||
|
subgraphName,
|
||||||
|
contract: RelayerRegistry,
|
||||||
|
deployedBlock,
|
||||||
|
fetchDataOptions,
|
||||||
|
tovarishClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.Aggregator = Aggregator;
|
||||||
|
this.relayerEnsSubdomains = relayerEnsSubdomains;
|
||||||
|
|
||||||
|
this.updateInterval = 86400;
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstanceName() {
|
getInstanceName() {
|
||||||
@@ -767,6 +929,10 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
|
|||||||
return 'RelayerRegistered';
|
return 'RelayerRegistered';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTovarishType(): string {
|
||||||
|
return 'registered';
|
||||||
|
}
|
||||||
|
|
||||||
// Name of method used for graph
|
// Name of method used for graph
|
||||||
getGraphMethod() {
|
getGraphMethod() {
|
||||||
return 'getAllRegisters';
|
return 'getAllRegisters';
|
||||||
@@ -788,7 +954,135 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchRelayers(): Promise<RegistersEvents[]> {
|
/**
|
||||||
return (await this.updateEvents()).events;
|
* Get saved or cached relayers
|
||||||
|
*/
|
||||||
|
async getRelayersFromDB(): Promise<CachedRelayers> {
|
||||||
|
return {
|
||||||
|
lastBlock: 0,
|
||||||
|
timestamp: 0,
|
||||||
|
relayers: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relayers from remote cache (Either from local cache, CDN, or from IPFS)
|
||||||
|
*/
|
||||||
|
async getRelayersFromCache(): Promise<CachedRelayers> {
|
||||||
|
return {
|
||||||
|
lastBlock: 0,
|
||||||
|
timestamp: 0,
|
||||||
|
relayers: [],
|
||||||
|
fromCache: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSavedRelayers(): Promise<CachedRelayers> {
|
||||||
|
let cachedRelayers = await this.getRelayersFromDB();
|
||||||
|
|
||||||
|
if (!cachedRelayers || !cachedRelayers.relayers.length) {
|
||||||
|
cachedRelayers = await this.getRelayersFromCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedRelayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestRelayers(): Promise<CachedRelayers> {
|
||||||
|
const { events, lastBlock } = await this.updateEvents();
|
||||||
|
|
||||||
|
const subdomains = Object.values(this.relayerEnsSubdomains);
|
||||||
|
|
||||||
|
const registerSet = new Set();
|
||||||
|
|
||||||
|
const uniqueRegisters = events.filter(({ ensName }) => {
|
||||||
|
if (!registerSet.has(ensName)) {
|
||||||
|
registerSet.add(ensName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const relayerNameHashes = uniqueRegisters.map((r) => namehash(r.ensName));
|
||||||
|
|
||||||
|
const [relayersData, timestamp] = await Promise.all([
|
||||||
|
this.Aggregator.relayersData.staticCall(relayerNameHashes, subdomains.concat('tovarish-relayer')),
|
||||||
|
this.provider.getBlock(lastBlock).then((b) => Number(b?.timestamp)),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const relayers = relayersData
|
||||||
|
.map(({ owner, balance: stakeBalance, records, isRegistered }, index) => {
|
||||||
|
const { ensName, relayerAddress } = uniqueRegisters[index];
|
||||||
|
|
||||||
|
let tovarishHost = undefined;
|
||||||
|
|
||||||
|
const hostnames = records.reduce((acc, record, recordIndex) => {
|
||||||
|
if (record) {
|
||||||
|
// tovarish-relayer.relayer.eth
|
||||||
|
if (recordIndex === records.length - 1) {
|
||||||
|
tovarishHost = record;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc[Number(Object.keys(this.relayerEnsSubdomains)[recordIndex])] = record;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {} as SubdomainMap);
|
||||||
|
|
||||||
|
const isOwner = !relayerAddress || relayerAddress === owner;
|
||||||
|
const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE;
|
||||||
|
|
||||||
|
const preCondition = Object.keys(hostnames).length && isOwner && isRegistered && hasMinBalance;
|
||||||
|
|
||||||
|
if (preCondition) {
|
||||||
|
return {
|
||||||
|
ensName,
|
||||||
|
relayerAddress,
|
||||||
|
isRegistered,
|
||||||
|
owner,
|
||||||
|
stakeBalance: formatEther(stakeBalance),
|
||||||
|
hostnames,
|
||||||
|
tovarishHost,
|
||||||
|
} as CachedRelayerInfo;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((r) => r) as CachedRelayerInfo[];
|
||||||
|
|
||||||
|
await getTovarishNetworks(this, relayers);
|
||||||
|
|
||||||
|
return {
|
||||||
|
lastBlock,
|
||||||
|
timestamp,
|
||||||
|
relayers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle saving relayers
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached or latest relayer and save to local
|
||||||
|
*/
|
||||||
|
async updateRelayers(): Promise<CachedRelayers> {
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let { lastBlock, timestamp, relayers, fromCache } = await this.getSavedRelayers();
|
||||||
|
|
||||||
|
let shouldSave = fromCache ?? false;
|
||||||
|
|
||||||
|
if (!relayers.length || timestamp + this.updateInterval < Math.floor(Date.now() / 1000)) {
|
||||||
|
console.log('\nUpdating relayers from registry\n');
|
||||||
|
|
||||||
|
({ lastBlock, timestamp, relayers } = await this.getLatestRelayers());
|
||||||
|
|
||||||
|
shouldSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSave) {
|
||||||
|
await this.saveRelayers({ lastBlock, timestamp, relayers });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { lastBlock, timestamp, relayers };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ export interface BaseEvents<T> {
|
|||||||
lastBlock: number | null;
|
lastBlock: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CachedEvents<T> extends BaseEvents<T> {
|
||||||
|
fromCache: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BaseGraphEvents<T> {
|
export interface BaseGraphEvents<T> {
|
||||||
events: T[];
|
events: T[];
|
||||||
lastSyncBlock: number;
|
lastSyncBlock: number;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { OvmGasPriceOracle } from './typechain';
|
|||||||
|
|
||||||
const DUMMY_ADDRESS = '0x1111111111111111111111111111111111111111';
|
const DUMMY_ADDRESS = '0x1111111111111111111111111111111111111111';
|
||||||
|
|
||||||
const DUMMY_NONCE = '0x1111111111111111111111111111111111111111111111111111111111111111';
|
const DUMMY_NONCE = 1024;
|
||||||
|
|
||||||
const DUMMY_WITHDRAW_DATA =
|
const DUMMY_WITHDRAW_DATA =
|
||||||
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111';
|
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111';
|
||||||
@@ -61,10 +61,9 @@ export class TornadoFeeOracle {
|
|||||||
tx = {
|
tx = {
|
||||||
type: 0,
|
type: 0,
|
||||||
gasLimit: 1_000_000,
|
gasLimit: 1_000_000,
|
||||||
nonce: Number(DUMMY_NONCE),
|
nonce: DUMMY_NONCE,
|
||||||
data: DUMMY_WITHDRAW_DATA,
|
data: DUMMY_WITHDRAW_DATA,
|
||||||
gasPrice: parseUnits('1', 'gwei'),
|
gasPrice: parseUnits('1', 'gwei'),
|
||||||
from: DUMMY_ADDRESS,
|
|
||||||
to: DUMMY_ADDRESS,
|
to: DUMMY_ADDRESS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ export * from './prices';
|
|||||||
export * from './providers';
|
export * from './providers';
|
||||||
export * from './relayerClient';
|
export * from './relayerClient';
|
||||||
export * from './tokens';
|
export * from './tokens';
|
||||||
|
export * from './tovarishClient';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './websnark';
|
export * from './websnark';
|
||||||
|
|||||||
@@ -78,8 +78,6 @@ export type Config = {
|
|||||||
registryContract?: string;
|
registryContract?: string;
|
||||||
aggregatorContract?: string;
|
aggregatorContract?: string;
|
||||||
reverseRecordsContract?: string;
|
reverseRecordsContract?: string;
|
||||||
gasPriceOracleContract?: string;
|
|
||||||
gasStationApi?: string;
|
|
||||||
ovmGasPriceOracleContract?: string;
|
ovmGasPriceOracleContract?: string;
|
||||||
tornadoSubgraph: string;
|
tornadoSubgraph: string;
|
||||||
registrySubgraph?: string;
|
registrySubgraph?: string;
|
||||||
@@ -87,6 +85,7 @@ export type Config = {
|
|||||||
subgraphs: SubgraphUrls;
|
subgraphs: SubgraphUrls;
|
||||||
tokens: TokenInstances;
|
tokens: TokenInstances;
|
||||||
optionalTokens?: string[];
|
optionalTokens?: string[];
|
||||||
|
disabledTokens?: string[];
|
||||||
relayerEnsSubdomain: string;
|
relayerEnsSubdomain: string;
|
||||||
// Should be in seconds
|
// Should be in seconds
|
||||||
pollInterval: number;
|
pollInterval: number;
|
||||||
@@ -104,13 +103,8 @@ export type networkConfig = {
|
|||||||
[key in NetIdType]: Config;
|
[key in NetIdType]: Config;
|
||||||
};
|
};
|
||||||
|
|
||||||
const theGraph = {
|
export type SubdomainMap = {
|
||||||
name: 'Hosted Graph',
|
[key in NetIdType]: string;
|
||||||
url: 'https://api.thegraph.com',
|
|
||||||
};
|
|
||||||
const tornado = {
|
|
||||||
name: 'Tornado Subgraphs',
|
|
||||||
url: 'https://tornadocash-rpc.com',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultConfig: networkConfig = {
|
export const defaultConfig: networkConfig = {
|
||||||
@@ -130,18 +124,26 @@ export const defaultConfig: networkConfig = {
|
|||||||
networkName: 'Ethereum Mainnet',
|
networkName: 'Ethereum Mainnet',
|
||||||
deployedBlock: 9116966,
|
deployedBlock: 9116966,
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
tornadoRPC: {
|
|
||||||
name: 'Tornado RPC',
|
|
||||||
url: 'https://tornadocash-rpc.com/mainnet',
|
|
||||||
},
|
|
||||||
chainnodes: {
|
|
||||||
name: 'Chainnodes RPC',
|
|
||||||
url: 'https://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
|
||||||
},
|
|
||||||
mevblockerRPC: {
|
mevblockerRPC: {
|
||||||
name: 'MevblockerRPC',
|
name: 'MevblockerRPC',
|
||||||
url: 'https://rpc.mevblocker.io',
|
url: 'https://rpc.mevblocker.io',
|
||||||
},
|
},
|
||||||
|
keydonix: {
|
||||||
|
name: 'keydonix',
|
||||||
|
url: 'https://ethereum.keydonix.com/v1/mainnet',
|
||||||
|
},
|
||||||
|
SecureRpc: {
|
||||||
|
name: 'SecureRpc',
|
||||||
|
url: 'https://api.securerpc.com/v1',
|
||||||
|
},
|
||||||
|
meowrpc: {
|
||||||
|
name: 'Meow RPC',
|
||||||
|
url: 'https://eth.meowrpc.com',
|
||||||
|
},
|
||||||
|
stackup: {
|
||||||
|
name: 'Stackup RPC',
|
||||||
|
url: 'https://public.stackup.sh/api/v1/node/ethereum-mainnet',
|
||||||
|
},
|
||||||
oneRPC: {
|
oneRPC: {
|
||||||
name: '1RPC',
|
name: '1RPC',
|
||||||
url: 'https://1rpc.io/eth',
|
url: 'https://1rpc.io/eth',
|
||||||
@@ -160,10 +162,7 @@ export const defaultConfig: networkConfig = {
|
|||||||
tornadoSubgraph: 'tornadocash/mainnet-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/mainnet-tornado-subgraph',
|
||||||
registrySubgraph: 'tornadocash/tornado-relayer-registry',
|
registrySubgraph: 'tornadocash/tornado-relayer-registry',
|
||||||
governanceSubgraph: 'tornadocash/tornado-governance',
|
governanceSubgraph: 'tornadocash/tornado-governance',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
tokens: {
|
tokens: {
|
||||||
eth: {
|
eth: {
|
||||||
instanceAddress: {
|
instanceAddress: {
|
||||||
@@ -236,6 +235,8 @@ export const defaultConfig: networkConfig = {
|
|||||||
gasLimit: 700_000,
|
gasLimit: 700_000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Inactive tokens to filter from schema verification and syncing events
|
||||||
|
disabledTokens: ['cdai', 'usdt', 'usdc'],
|
||||||
relayerEnsSubdomain: 'mainnet-tornado',
|
relayerEnsSubdomain: 'mainnet-tornado',
|
||||||
pollInterval: 15,
|
pollInterval: 15,
|
||||||
constants: {
|
constants: {
|
||||||
@@ -266,18 +267,27 @@ export const defaultConfig: networkConfig = {
|
|||||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||||
tornadoSubgraph: 'tornadocash/bsc-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/bsc-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
tornadoRPC: {
|
bnbchain: {
|
||||||
name: 'Tornado RPC',
|
name: 'BNB Chain',
|
||||||
url: 'https://tornadocash-rpc.com/bsc',
|
url: 'https://bsc-dataseed.bnbchain.org',
|
||||||
},
|
},
|
||||||
chainnodes: {
|
ninicoin: {
|
||||||
name: 'Chainnodes RPC',
|
name: 'ninicoin',
|
||||||
url: 'https://bsc-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
url: 'https://bsc-dataseed1.ninicoin.io',
|
||||||
|
},
|
||||||
|
nodereal: {
|
||||||
|
name: 'NodeReal',
|
||||||
|
url: 'https://binance.nodereal.io',
|
||||||
|
},
|
||||||
|
meowrpc: {
|
||||||
|
name: 'Meow RPC',
|
||||||
|
url: 'https://bsc.meowrpc.com',
|
||||||
|
},
|
||||||
|
stackup: {
|
||||||
|
name: 'Stackup RPC',
|
||||||
|
url: 'https://public.stackup.sh/api/v1/node/bsc-mainnet',
|
||||||
},
|
},
|
||||||
oneRPC: {
|
oneRPC: {
|
||||||
name: '1RPC',
|
name: '1RPC',
|
||||||
@@ -322,21 +332,21 @@ export const defaultConfig: networkConfig = {
|
|||||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||||
gasPriceOracleContract: '0xF81A8D8D3581985D3969fe53bFA67074aDFa8F3C',
|
|
||||||
tornadoSubgraph: 'tornadocash/matic-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/matic-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
chainnodes: {
|
|
||||||
name: 'Chainnodes RPC',
|
|
||||||
url: 'https://polygon-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
|
||||||
},
|
|
||||||
oneRpc: {
|
oneRpc: {
|
||||||
name: '1RPC',
|
name: '1RPC',
|
||||||
url: 'https://1rpc.io/matic',
|
url: 'https://1rpc.io/matic',
|
||||||
},
|
},
|
||||||
|
meowrpc: {
|
||||||
|
name: 'Meow RPC',
|
||||||
|
url: 'https://polygon.meowrpc.com',
|
||||||
|
},
|
||||||
|
stackup: {
|
||||||
|
name: 'Stackup RPC',
|
||||||
|
url: 'https://public.stackup.sh/api/v1/node/polygon-mainnet',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
tokens: {
|
tokens: {
|
||||||
matic: {
|
matic: {
|
||||||
@@ -378,18 +388,19 @@ export const defaultConfig: networkConfig = {
|
|||||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||||
ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F',
|
ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F',
|
||||||
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
tornadoRPC: {
|
optimism: {
|
||||||
name: 'Tornado RPC',
|
name: 'Optimism',
|
||||||
url: 'https://tornadocash-rpc.com/op',
|
url: 'https://mainnet.optimism.io',
|
||||||
},
|
},
|
||||||
chainnodes: {
|
meowrpc: {
|
||||||
name: 'Chainnodes RPC',
|
name: 'Meow RPC',
|
||||||
url: 'https://optimism-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
url: 'https://optimism.meowrpc.com',
|
||||||
|
},
|
||||||
|
stackup: {
|
||||||
|
name: 'Stackup RPC',
|
||||||
|
url: 'https://public.stackup.sh/api/v1/node/optimism-mainnet',
|
||||||
},
|
},
|
||||||
oneRpc: {
|
oneRpc: {
|
||||||
name: '1RPC',
|
name: '1RPC',
|
||||||
@@ -435,27 +446,24 @@ export const defaultConfig: networkConfig = {
|
|||||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||||
tornadoSubgraph: 'tornadocash/arbitrum-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/arbitrum-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
tornadoRPC: {
|
Arbitrum: {
|
||||||
name: 'Tornado RPC',
|
name: 'Arbitrum RPC',
|
||||||
url: 'https://tornadocash-rpc.com/arbitrum',
|
url: 'https://arb1.arbitrum.io/rpc',
|
||||||
},
|
},
|
||||||
chainnodes: {
|
meowrpc: {
|
||||||
name: 'Chainnodes RPC',
|
name: 'Meow RPC',
|
||||||
url: 'https://arbitrum-one.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
url: 'https://arbitrum.meowrpc.com',
|
||||||
|
},
|
||||||
|
stackup: {
|
||||||
|
name: 'Stackup RPC',
|
||||||
|
url: 'https://public.stackup.sh/api/v1/node/arbitrum-one',
|
||||||
},
|
},
|
||||||
oneRpc: {
|
oneRpc: {
|
||||||
name: '1rpc',
|
name: '1rpc',
|
||||||
url: 'https://1rpc.io/arb',
|
url: 'https://1rpc.io/arb',
|
||||||
},
|
},
|
||||||
Arbitrum: {
|
|
||||||
name: 'Arbitrum RPC',
|
|
||||||
url: 'https://arb1.arbitrum.io/rpc',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
tokens: {
|
tokens: {
|
||||||
eth: {
|
eth: {
|
||||||
@@ -496,23 +504,20 @@ export const defaultConfig: networkConfig = {
|
|||||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||||
tornadoSubgraph: 'tornadocash/xdai-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/xdai-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
tornadoRPC: {
|
gnosis: {
|
||||||
name: 'Tornado RPC',
|
name: 'Gnosis',
|
||||||
url: 'https://tornadocash-rpc.com/gnosis',
|
url: 'https://rpc.gnosischain.com',
|
||||||
},
|
|
||||||
chainnodes: {
|
|
||||||
name: 'Chainnodes RPC',
|
|
||||||
url: 'https://gnosis-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
|
||||||
},
|
},
|
||||||
blockPi: {
|
blockPi: {
|
||||||
name: 'BlockPi',
|
name: 'BlockPi',
|
||||||
url: 'https://gnosis.blockpi.network/v1/rpc/public',
|
url: 'https://gnosis.blockpi.network/v1/rpc/public',
|
||||||
},
|
},
|
||||||
|
oneRpc: {
|
||||||
|
name: '1rpc',
|
||||||
|
url: 'https://1rpc.io/gnosis',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
tokens: {
|
tokens: {
|
||||||
xdai: {
|
xdai: {
|
||||||
@@ -553,9 +558,7 @@ export const defaultConfig: networkConfig = {
|
|||||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||||
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
theGraph,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
publicRpc: {
|
publicRpc: {
|
||||||
name: 'Avalanche RPC',
|
name: 'Avalanche RPC',
|
||||||
@@ -613,21 +616,23 @@ export const defaultConfig: networkConfig = {
|
|||||||
aggregatorContract: '0x4088712AC9fad39ea133cdb9130E465d235e9642',
|
aggregatorContract: '0x4088712AC9fad39ea133cdb9130E465d235e9642',
|
||||||
reverseRecordsContract: '0xEc29700C0283e5Be64AcdFe8077d6cC95dE23C23',
|
reverseRecordsContract: '0xEc29700C0283e5Be64AcdFe8077d6cC95dE23C23',
|
||||||
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
|
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
|
||||||
subgraphs: {
|
subgraphs: {},
|
||||||
tornado,
|
|
||||||
},
|
|
||||||
rpcUrls: {
|
rpcUrls: {
|
||||||
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',
|
||||||
},
|
},
|
||||||
chainnodes: {
|
stackup: {
|
||||||
name: 'Chainnodes RPC',
|
name: 'Stackup',
|
||||||
url: 'https://sepolia.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia',
|
||||||
|
},
|
||||||
|
onerpc: {
|
||||||
|
name: '1rpc',
|
||||||
|
url: 'https://1rpc.io/sepolia',
|
||||||
|
},
|
||||||
|
ethpandaops: {
|
||||||
|
name: 'ethpandaops',
|
||||||
|
url: 'https://rpc.sepolia.ethpandaops.io',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tokens: {
|
tokens: {
|
||||||
@@ -720,10 +725,30 @@ export function getConfig(netId: NetIdType) {
|
|||||||
return chainConfig;
|
return chainConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInstanceByAddress({ netId, address }: { netId: NetIdType; address: string }) {
|
export function getActiveTokens(config: Config): string[] {
|
||||||
const { tokens } = getConfig(netId);
|
const { tokens, disabledTokens } = config;
|
||||||
|
|
||||||
|
return Object.keys(tokens).filter((t) => !disabledTokens?.includes(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getActiveTokenInstances(config: Config): TokenInstances {
|
||||||
|
const { tokens, disabledTokens } = config;
|
||||||
|
|
||||||
|
return Object.entries(tokens).reduce((acc, [token, instances]) => {
|
||||||
|
if (!disabledTokens?.includes(token)) {
|
||||||
|
acc[token] = instances;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {} as TokenInstances);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getInstanceByAddress(config: Config, address: string) {
|
||||||
|
const { tokens, disabledTokens } = config;
|
||||||
|
|
||||||
for (const [currency, { instanceAddress }] of Object.entries(tokens)) {
|
for (const [currency, { instanceAddress }] of Object.entries(tokens)) {
|
||||||
|
if (disabledTokens?.includes(currency)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const [amount, instance] of Object.entries(instanceAddress)) {
|
for (const [amount, instance] of Object.entries(instanceAddress)) {
|
||||||
if (instance === address) {
|
if (instance === address) {
|
||||||
return {
|
return {
|
||||||
@@ -735,8 +760,11 @@ export function getInstanceByAddress({ netId, address }: { netId: NetIdType; add
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSubdomains() {
|
export function getRelayerEnsSubdomains() {
|
||||||
const allConfig = getNetworkConfig();
|
const allConfig = getNetworkConfig();
|
||||||
|
|
||||||
return enabledChains.map((chain) => allConfig[chain].relayerEnsSubdomain);
|
return enabledChains.reduce((acc, chain) => {
|
||||||
|
acc[chain] = allConfig[chain].relayerEnsSubdomain;
|
||||||
|
return acc;
|
||||||
|
}, {} as SubdomainMap);
|
||||||
}
|
}
|
||||||
|
|||||||
231
src/providers.ts
231
src/providers.ts
@@ -17,17 +17,14 @@ import {
|
|||||||
Eip1193Provider,
|
Eip1193Provider,
|
||||||
VoidSigner,
|
VoidSigner,
|
||||||
Network,
|
Network,
|
||||||
parseUnits,
|
|
||||||
FetchUrlFeeDataNetworkPlugin,
|
|
||||||
FeeData,
|
|
||||||
EnsPlugin,
|
EnsPlugin,
|
||||||
GasCostPlugin,
|
GasCostPlugin,
|
||||||
} from 'ethers';
|
} from 'ethers';
|
||||||
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
|
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
|
||||||
import { GasPriceOracle, GasPriceOracle__factory, Multicall, Multicall__factory } from './typechain';
|
// Temporary workaround until @types/node-fetch is compatible with @types/node
|
||||||
|
import type { AbortSignal as FetchAbortSignal } from 'node-fetch/externals';
|
||||||
import { isNode, sleep } from './utils';
|
import { isNode, sleep } from './utils';
|
||||||
import type { Config, NetIdType } from './networkConfig';
|
import type { Config, NetIdType } from './networkConfig';
|
||||||
import { multicall } from './multicall';
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@@ -51,7 +48,7 @@ export type fetchDataOptions = RequestInit & {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
proxy?: string;
|
proxy?: string;
|
||||||
torPort?: number;
|
torPort?: number;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||||
debug?: Function;
|
debug?: Function;
|
||||||
returnResponse?: boolean;
|
returnResponse?: boolean;
|
||||||
};
|
};
|
||||||
@@ -69,11 +66,11 @@ export function getHttpAgent({
|
|||||||
torPort?: number;
|
torPort?: number;
|
||||||
retry: number;
|
retry: number;
|
||||||
}): NodeAgent | undefined {
|
}): NodeAgent | undefined {
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
const { HttpProxyAgent } = require('http-proxy-agent');
|
const { HttpProxyAgent } = require('http-proxy-agent');
|
||||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||||
const { SocksProxyAgent } = require('socks-proxy-agent');
|
const { SocksProxyAgent } = require('socks-proxy-agent');
|
||||||
/* eslint-enable @typescript-eslint/no-var-requires */
|
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||||
|
|
||||||
if (torPort) {
|
if (torPort) {
|
||||||
return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
|
return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
|
||||||
@@ -128,7 +125,8 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
|
|||||||
if (!options.signal && options.timeout) {
|
if (!options.signal && options.timeout) {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
|
||||||
options.signal = controller.signal;
|
// Temporary workaround until @types/node-fetch is compatible with @types/node
|
||||||
|
options.signal = controller.signal as FetchAbortSignal;
|
||||||
|
|
||||||
// Define timeout in seconds
|
// Define timeout in seconds
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
@@ -223,7 +221,8 @@ export const fetchGetUrlFunc =
|
|||||||
|
|
||||||
if (_signal) {
|
if (_signal) {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
signal = controller.signal;
|
// Temporary workaround until @types/node-fetch is compatible with @types/node
|
||||||
|
signal = controller.signal as FetchAbortSignal;
|
||||||
_signal.addListener(() => {
|
_signal.addListener(() => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
});
|
});
|
||||||
@@ -257,114 +256,30 @@ export const fetchGetUrlFunc =
|
|||||||
};
|
};
|
||||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
// caching to improve performance
|
|
||||||
const oracleMapper = new Map();
|
|
||||||
const multicallMapper = new Map();
|
|
||||||
|
|
||||||
export type getProviderOptions = fetchDataOptions & {
|
export type getProviderOptions = fetchDataOptions & {
|
||||||
|
// NetId to check against rpc
|
||||||
|
netId?: NetIdType;
|
||||||
pollingInterval?: number;
|
pollingInterval?: number;
|
||||||
gasPriceOracle?: string;
|
|
||||||
gasStationApi?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getGasOraclePlugin(networkKey: string, fetchOptions?: getProviderOptions) {
|
|
||||||
const gasStationApi = fetchOptions?.gasStationApi || 'https://gasstation.polygon.technology/v2';
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
return new FetchUrlFeeDataNetworkPlugin(gasStationApi, async (fetchFeeData, provider, request) => {
|
|
||||||
if (!oracleMapper.has(networkKey)) {
|
|
||||||
oracleMapper.set(networkKey, GasPriceOracle__factory.connect(fetchOptions?.gasPriceOracle as string, provider));
|
|
||||||
}
|
|
||||||
if (!multicallMapper.has(networkKey)) {
|
|
||||||
multicallMapper.set(
|
|
||||||
networkKey,
|
|
||||||
Multicall__factory.connect('0xcA11bde05977b3631167028862bE2a173976CA11', provider),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const Oracle = oracleMapper.get(networkKey) as GasPriceOracle;
|
|
||||||
const Multicall = multicallMapper.get(networkKey) as Multicall;
|
|
||||||
|
|
||||||
const [timestamp, heartbeat, feePerGas, priorityFeePerGas] = await multicall(Multicall, [
|
|
||||||
{
|
|
||||||
contract: Oracle,
|
|
||||||
name: 'timestamp',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
contract: Oracle,
|
|
||||||
name: 'heartbeat',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
contract: Oracle,
|
|
||||||
name: 'maxFeePerGas',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
contract: Oracle,
|
|
||||||
name: 'maxPriorityFeePerGas',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const isOutdated = Number(timestamp) <= Date.now() / 1000 - Number(heartbeat);
|
|
||||||
|
|
||||||
if (!isOutdated) {
|
|
||||||
const maxPriorityFeePerGas = (priorityFeePerGas * BigInt(13)) / BigInt(10);
|
|
||||||
const maxFeePerGas = feePerGas * BigInt(2) + maxPriorityFeePerGas;
|
|
||||||
|
|
||||||
return {
|
|
||||||
gasPrice: maxFeePerGas,
|
|
||||||
maxFeePerGas,
|
|
||||||
maxPriorityFeePerGas,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchReq = new FetchRequest(gasStationApi);
|
|
||||||
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
|
|
||||||
if (isNode) {
|
|
||||||
// Prevent Cloudflare from blocking our request in node.js
|
|
||||||
fetchReq.setHeader('User-Agent', 'ethers');
|
|
||||||
}
|
|
||||||
|
|
||||||
const [
|
|
||||||
{
|
|
||||||
bodyJson: { fast },
|
|
||||||
},
|
|
||||||
{ gasPrice },
|
|
||||||
] = await Promise.all([fetchReq.send(), fetchFeeData()]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
gasPrice,
|
|
||||||
maxFeePerGas: parseUnits(`${fast.maxFee}`, 9),
|
|
||||||
maxPriorityFeePerGas: parseUnits(`${fast.maxPriorityFee}`, 9),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider> {
|
export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider> {
|
||||||
const fetchReq = new FetchRequest(rpcUrl);
|
const fetchReq = new FetchRequest(rpcUrl);
|
||||||
|
|
||||||
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
|
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
|
||||||
// omit network plugins and mimic registerEth function (required for polygon)
|
|
||||||
const _staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
|
const staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
|
||||||
const ensPlugin = _staticNetwork.getPlugin('org.ethers.plugins.network.Ens');
|
|
||||||
const gasCostPlugin = _staticNetwork.getPlugin('org.ethers.plugins.network.GasCost');
|
const chainId = Number(staticNetwork.chainId);
|
||||||
const gasStationPlugin = <FetchUrlFeeDataNetworkPlugin>(
|
|
||||||
_staticNetwork.getPlugin('org.ethers.plugins.network.FetchUrlFeeDataPlugin')
|
if (fetchOptions?.netId && fetchOptions.netId !== chainId) {
|
||||||
);
|
const errMsg = `Wrong network for ${rpcUrl}, wants ${fetchOptions.netId} got ${chainId}`;
|
||||||
const staticNetwork = new Network(_staticNetwork.name, _staticNetwork.chainId);
|
throw new Error(errMsg);
|
||||||
if (ensPlugin) {
|
|
||||||
staticNetwork.attachPlugin(ensPlugin);
|
|
||||||
}
|
}
|
||||||
if (gasCostPlugin) {
|
|
||||||
staticNetwork.attachPlugin(gasCostPlugin);
|
return new JsonRpcProvider(fetchReq, staticNetwork, {
|
||||||
}
|
|
||||||
if (fetchOptions?.gasPriceOracle) {
|
|
||||||
staticNetwork.attachPlugin(getGasOraclePlugin(`${_staticNetwork.chainId}_${rpcUrl}`, fetchOptions));
|
|
||||||
} else if (gasStationPlugin) {
|
|
||||||
staticNetwork.attachPlugin(gasStationPlugin);
|
|
||||||
}
|
|
||||||
const provider = new JsonRpcProvider(fetchReq, staticNetwork, {
|
|
||||||
staticNetwork,
|
staticNetwork,
|
||||||
|
pollingInterval: fetchOptions?.pollingInterval || 1000,
|
||||||
});
|
});
|
||||||
provider.pollingInterval = fetchOptions?.pollingInterval || 1000;
|
|
||||||
return provider;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProviderWithNetId(
|
export function getProviderWithNetId(
|
||||||
@@ -373,7 +288,7 @@ export function getProviderWithNetId(
|
|||||||
config: Config,
|
config: Config,
|
||||||
fetchOptions?: getProviderOptions,
|
fetchOptions?: getProviderOptions,
|
||||||
): JsonRpcProvider {
|
): JsonRpcProvider {
|
||||||
const { networkName, reverseRecordsContract, gasPriceOracleContract, gasStationApi, pollInterval } = config;
|
const { networkName, reverseRecordsContract, pollInterval } = config;
|
||||||
const hasEns = Boolean(reverseRecordsContract);
|
const hasEns = Boolean(reverseRecordsContract);
|
||||||
|
|
||||||
const fetchReq = new FetchRequest(rpcUrl);
|
const fetchReq = new FetchRequest(rpcUrl);
|
||||||
@@ -382,24 +297,13 @@ export function getProviderWithNetId(
|
|||||||
if (hasEns) {
|
if (hasEns) {
|
||||||
staticNetwork.attachPlugin(new EnsPlugin(null, Number(netId)));
|
staticNetwork.attachPlugin(new EnsPlugin(null, Number(netId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
staticNetwork.attachPlugin(new GasCostPlugin());
|
staticNetwork.attachPlugin(new GasCostPlugin());
|
||||||
|
|
||||||
if (gasPriceOracleContract) {
|
|
||||||
staticNetwork.attachPlugin(
|
|
||||||
getGasOraclePlugin(`${netId}_${rpcUrl}`, {
|
|
||||||
gasPriceOracle: gasPriceOracleContract,
|
|
||||||
gasStationApi,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const provider = new JsonRpcProvider(fetchReq, staticNetwork, {
|
const provider = new JsonRpcProvider(fetchReq, staticNetwork, {
|
||||||
staticNetwork,
|
staticNetwork,
|
||||||
|
pollingInterval: fetchOptions?.pollingInterval || pollInterval * 1000,
|
||||||
});
|
});
|
||||||
|
|
||||||
provider.pollingInterval = fetchOptions?.pollingInterval || pollInterval * 1000;
|
|
||||||
|
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,87 +321,52 @@ export const populateTransaction = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [feeData, nonce] = await Promise.all([
|
const [feeData, nonce] = await Promise.all([
|
||||||
(async () => {
|
tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(),
|
||||||
if (tx.maxFeePerGas && tx.maxPriorityFeePerGas) {
|
tx.nonce ? undefined : provider.getTransactionCount(signer.address, 'pending'),
|
||||||
return new FeeData(null, BigInt(tx.maxFeePerGas), BigInt(tx.maxPriorityFeePerGas));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.gasPrice) {
|
|
||||||
return new FeeData(BigInt(tx.gasPrice), null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchedFeeData = await provider.getFeeData();
|
|
||||||
|
|
||||||
if (fetchedFeeData.maxFeePerGas && fetchedFeeData.maxPriorityFeePerGas) {
|
|
||||||
return new FeeData(
|
|
||||||
null,
|
|
||||||
(fetchedFeeData.maxFeePerGas * (BigInt(10000) + BigInt(signer.gasPriceBump))) / BigInt(10000),
|
|
||||||
fetchedFeeData.maxPriorityFeePerGas,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return new FeeData(
|
|
||||||
((fetchedFeeData.gasPrice as bigint) * (BigInt(10000) + BigInt(signer.gasPriceBump))) / BigInt(10000),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
(async () => {
|
|
||||||
if (tx.nonce) {
|
|
||||||
return tx.nonce;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fetchedNonce = await provider.getTransactionCount(signer.address, 'pending');
|
|
||||||
|
|
||||||
// Deal with cached nonce results
|
|
||||||
if (signer.bumpNonce && signer.nonce && signer.nonce >= fetchedNonce) {
|
|
||||||
console.log(
|
|
||||||
`populateTransaction: bumping nonce from ${fetchedNonce} to ${fetchedNonce + 1} for ${signer.address}`,
|
|
||||||
);
|
|
||||||
fetchedNonce++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetchedNonce;
|
|
||||||
})(),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
tx.nonce = nonce;
|
if (feeData) {
|
||||||
|
|
||||||
// EIP-1559
|
// EIP-1559
|
||||||
if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) {
|
if (feeData.maxFeePerGas) {
|
||||||
tx.maxFeePerGas = feeData.maxFeePerGas;
|
|
||||||
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
|
|
||||||
if (!tx.type) {
|
if (!tx.type) {
|
||||||
tx.type = 2;
|
tx.type = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tx.maxFeePerGas = (feeData.maxFeePerGas * (BigInt(10000) + BigInt(signer.gasPriceBump))) / BigInt(10000);
|
||||||
|
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
|
||||||
delete tx.gasPrice;
|
delete tx.gasPrice;
|
||||||
} else if (feeData.gasPrice) {
|
} else if (feeData.gasPrice) {
|
||||||
tx.gasPrice = feeData.gasPrice;
|
|
||||||
if (!tx.type) {
|
if (!tx.type) {
|
||||||
tx.type = 0;
|
tx.type = 0;
|
||||||
}
|
}
|
||||||
|
tx.gasPrice = feeData.gasPrice;
|
||||||
delete tx.maxFeePerGas;
|
delete tx.maxFeePerGas;
|
||||||
delete tx.maxPriorityFeePerGas;
|
delete tx.maxPriorityFeePerGas;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// gasLimit
|
if (nonce) {
|
||||||
tx.gasLimit =
|
tx.nonce = nonce;
|
||||||
tx.gasLimit ||
|
}
|
||||||
(await (async () => {
|
|
||||||
|
if (!tx.gasLimit) {
|
||||||
try {
|
try {
|
||||||
const gasLimit = await provider.estimateGas(tx);
|
const gasLimit = await provider.estimateGas(tx);
|
||||||
return gasLimit === BigInt(21000)
|
|
||||||
|
tx.gasLimit =
|
||||||
|
gasLimit === BigInt(21000)
|
||||||
? gasLimit
|
? gasLimit
|
||||||
: (gasLimit * (BigInt(10000) + BigInt(signer.gasLimitBump))) / BigInt(10000);
|
: (gasLimit * (BigInt(10000) + BigInt(signer.gasLimitBump))) / BigInt(10000);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
if (signer.gasFailover) {
|
if (signer.gasFailover) {
|
||||||
console.log('populateTransaction: warning gas estimation failed falling back to 3M gas');
|
console.log('populateTransaction: warning gas estimation failed falling back to 3M gas');
|
||||||
// Gas failover
|
// Gas failover
|
||||||
return BigInt('3000000');
|
tx.gasLimit = BigInt('3000000');
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
})());
|
|
||||||
|
|
||||||
return tx;
|
return tx;
|
||||||
};
|
};
|
||||||
@@ -522,7 +391,7 @@ export class TornadoWallet extends Wallet {
|
|||||||
) {
|
) {
|
||||||
super(key, provider);
|
super(key, provider);
|
||||||
// 10% bump from the recommended fee
|
// 10% bump from the recommended fee
|
||||||
this.gasPriceBump = gasPriceBump ?? 1000;
|
this.gasPriceBump = gasPriceBump ?? 0;
|
||||||
// 30% bump from the recommended gaslimit
|
// 30% bump from the recommended gaslimit
|
||||||
this.gasLimitBump = gasLimitBump ?? 3000;
|
this.gasLimitBump = gasLimitBump ?? 3000;
|
||||||
this.gasFailover = gasFailover ?? false;
|
this.gasFailover = gasFailover ?? false;
|
||||||
@@ -557,7 +426,7 @@ export class TornadoVoidSigner extends VoidSigner {
|
|||||||
) {
|
) {
|
||||||
super(address, provider);
|
super(address, provider);
|
||||||
// 10% bump from the recommended fee
|
// 10% bump from the recommended fee
|
||||||
this.gasPriceBump = gasPriceBump ?? 1000;
|
this.gasPriceBump = gasPriceBump ?? 0;
|
||||||
// 30% bump from the recommended gaslimit
|
// 30% bump from the recommended gaslimit
|
||||||
this.gasLimitBump = gasLimitBump ?? 3000;
|
this.gasLimitBump = gasLimitBump ?? 3000;
|
||||||
this.gasFailover = gasFailover ?? false;
|
this.gasFailover = gasFailover ?? false;
|
||||||
@@ -586,7 +455,7 @@ export class TornadoRpcSigner extends JsonRpcSigner {
|
|||||||
) {
|
) {
|
||||||
super(provider, address);
|
super(provider, address);
|
||||||
// 10% bump from the recommended fee
|
// 10% bump from the recommended fee
|
||||||
this.gasPriceBump = gasPriceBump ?? 1000;
|
this.gasPriceBump = gasPriceBump ?? 0;
|
||||||
// 30% bump from the recommended gaslimit
|
// 30% bump from the recommended gaslimit
|
||||||
this.gasLimitBump = gasLimitBump ?? 3000;
|
this.gasLimitBump = gasLimitBump ?? 3000;
|
||||||
this.gasFailover = gasFailover ?? false;
|
this.gasFailover = gasFailover ?? false;
|
||||||
|
|||||||
@@ -1,43 +1,45 @@
|
|||||||
import { getAddress, namehash, parseEther } from 'ethers';
|
import { getAddress, parseEther } from 'ethers';
|
||||||
import type { Aggregator } from '@tornado/contracts';
|
|
||||||
import type { RelayerStructOutput } from '@tornado/contracts/dist/contracts/Governance/Aggregator/Aggregator';
|
|
||||||
import { sleep } from './utils';
|
import { sleep } from './utils';
|
||||||
import { NetId, NetIdType, Config } from './networkConfig';
|
import { NetId, NetIdType, Config } from './networkConfig';
|
||||||
import { fetchData, fetchDataOptions } from './providers';
|
import { fetchData, fetchDataOptions } from './providers';
|
||||||
import { ajv, jobsSchema, getStatusSchema } from './schemas';
|
import { ajv, jobsSchema, getStatusSchema } from './schemas';
|
||||||
import type { snarkProofs } from './websnark';
|
import type { snarkProofs } from './websnark';
|
||||||
|
import type { CachedRelayerInfo } from './events';
|
||||||
|
|
||||||
|
export const MIN_FEE = 0.1;
|
||||||
|
|
||||||
|
export const MAX_FEE = 0.9;
|
||||||
|
|
||||||
export const MIN_STAKE_BALANCE = parseEther('500');
|
export const MIN_STAKE_BALANCE = parseEther('500');
|
||||||
|
|
||||||
export interface RelayerParams {
|
export interface RelayerParams {
|
||||||
ensName: string;
|
ensName: string;
|
||||||
relayerAddress?: string;
|
relayerAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Relayer {
|
/**
|
||||||
|
* Info from relayer status
|
||||||
|
*/
|
||||||
|
export type RelayerInfo = RelayerParams & {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
url: string;
|
url: string;
|
||||||
hostname: string;
|
hostname: string;
|
||||||
rewardAccount: string;
|
rewardAccount: string;
|
||||||
instances: string[];
|
instances: string[];
|
||||||
|
stakeBalance?: string;
|
||||||
gasPrice?: number;
|
gasPrice?: number;
|
||||||
ethPrices?: {
|
ethPrices?: {
|
||||||
[key in string]: string;
|
[key in string]: string;
|
||||||
};
|
};
|
||||||
currentQueue: number;
|
currentQueue: number;
|
||||||
tornadoServiceFee: number;
|
tornadoServiceFee: number;
|
||||||
}
|
|
||||||
|
|
||||||
export type RelayerInfo = Relayer & {
|
|
||||||
ensName: string;
|
|
||||||
stakeBalance: bigint;
|
|
||||||
relayerAddress: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RelayerError = {
|
export type RelayerError = {
|
||||||
hostname: string;
|
hostname: string;
|
||||||
relayerAddress?: string;
|
relayerAddress?: string;
|
||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
|
hasError: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface RelayerStatus {
|
export interface RelayerStatus {
|
||||||
@@ -73,6 +75,10 @@ export interface RelayerStatus {
|
|||||||
currentQueue: number;
|
currentQueue: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TornadoWithdrawParams = snarkProofs & {
|
||||||
|
contract: string;
|
||||||
|
};
|
||||||
|
|
||||||
export interface RelayerTornadoWithdraw {
|
export interface RelayerTornadoWithdraw {
|
||||||
id?: string;
|
id?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
@@ -91,6 +97,7 @@ export interface RelayerTornadoJobs {
|
|||||||
failedReason?: string;
|
failedReason?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
const semVerRegex =
|
const semVerRegex =
|
||||||
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
||||||
|
|
||||||
@@ -116,19 +123,20 @@ export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
|
|||||||
if (prerelease) return false;
|
if (prerelease) return false;
|
||||||
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
|
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
|
||||||
}
|
}
|
||||||
|
**/
|
||||||
|
|
||||||
export function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo, minFee = 0.33, maxFee = 0.53) {
|
export function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo) {
|
||||||
if (tornadoServiceFee < minFee) {
|
if (tornadoServiceFee < MIN_FEE) {
|
||||||
tornadoServiceFee = minFee;
|
tornadoServiceFee = MIN_FEE;
|
||||||
} else if (tornadoServiceFee >= maxFee) {
|
} else if (tornadoServiceFee >= MAX_FEE) {
|
||||||
return BigInt(0);
|
return BigInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceFeeCoefficient = (tornadoServiceFee - minFee) ** 2;
|
const serviceFeeCoefficient = (tornadoServiceFee - MIN_FEE) ** 2;
|
||||||
const feeDiffCoefficient = 1 / (maxFee - minFee) ** 2;
|
const feeDiffCoefficient = 1 / (MAX_FEE - MIN_FEE) ** 2;
|
||||||
const coefficientsMultiplier = 1 - feeDiffCoefficient * serviceFeeCoefficient;
|
const coefficientsMultiplier = 1 - feeDiffCoefficient * serviceFeeCoefficient;
|
||||||
|
|
||||||
return BigInt(Math.floor(Number(stakeBalance) * coefficientsMultiplier));
|
return BigInt(Math.floor(Number(stakeBalance || '0') * coefficientsMultiplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeightRandom(weightsScores: bigint[], random: bigint) {
|
export function getWeightRandom(weightsScores: bigint[], random: bigint) {
|
||||||
@@ -159,20 +167,13 @@ export function getSupportedInstances(instanceList: RelayerInstanceList) {
|
|||||||
return rawList.map((l) => getAddress(l));
|
return rawList.map((l) => getAddress(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdType) {
|
export function pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
|
||||||
let minFee: number, maxFee: number;
|
const weightsScores = relayers.map((el) => calculateScore(el));
|
||||||
|
|
||||||
if (netId !== NetId.MAINNET) {
|
|
||||||
minFee = 0.01;
|
|
||||||
maxFee = 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
const weightsScores = relayers.map((el) => calculateScore(el, minFee, maxFee));
|
|
||||||
const totalWeight = weightsScores.reduce((acc, curr) => {
|
const totalWeight = weightsScores.reduce((acc, curr) => {
|
||||||
return (acc = acc + curr);
|
return (acc = acc + curr);
|
||||||
}, BigInt('0'));
|
}, BigInt('0'));
|
||||||
|
|
||||||
const random = BigInt(Number(totalWeight) * Math.random());
|
const random = BigInt(Math.floor(Number(totalWeight) * Math.random()));
|
||||||
const weightRandomIndex = getWeightRandom(weightsScores, random);
|
const weightRandomIndex = getWeightRandom(weightsScores, random);
|
||||||
|
|
||||||
return relayers[weightRandomIndex];
|
return relayers[weightRandomIndex];
|
||||||
@@ -181,36 +182,41 @@ export function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdT
|
|||||||
export interface RelayerClientConstructor {
|
export interface RelayerClientConstructor {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
config: Config;
|
config: Config;
|
||||||
Aggregator: Aggregator;
|
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RelayerClientWithdraw = snarkProofs & {
|
|
||||||
contract: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class RelayerClient {
|
export class RelayerClient {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
config: Config;
|
config: Config;
|
||||||
Aggregator: Aggregator;
|
selectedRelayer?: RelayerInfo;
|
||||||
selectedRelayer?: Relayer;
|
|
||||||
fetchDataOptions?: fetchDataOptions;
|
fetchDataOptions?: fetchDataOptions;
|
||||||
|
tovarish: boolean;
|
||||||
|
|
||||||
constructor({ netId, config, Aggregator, fetchDataOptions }: RelayerClientConstructor) {
|
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
|
||||||
this.netId = netId;
|
this.netId = netId;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.Aggregator = Aggregator;
|
|
||||||
this.fetchDataOptions = fetchDataOptions;
|
this.fetchDataOptions = fetchDataOptions;
|
||||||
|
this.tovarish = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async askRelayerStatus({
|
async askRelayerStatus({
|
||||||
hostname,
|
hostname,
|
||||||
|
url,
|
||||||
relayerAddress,
|
relayerAddress,
|
||||||
}: {
|
}: {
|
||||||
hostname: string;
|
hostname?: string;
|
||||||
|
// optional url if entered manually
|
||||||
|
url?: string;
|
||||||
|
// relayerAddress from registry contract to prevent cheating
|
||||||
relayerAddress?: string;
|
relayerAddress?: string;
|
||||||
}): Promise<RelayerStatus> {
|
}): Promise<RelayerStatus> {
|
||||||
const url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
|
if (!url && hostname) {
|
||||||
|
url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
|
||||||
|
} else if (url && !url.endsWith('/')) {
|
||||||
|
url += '/';
|
||||||
|
} else {
|
||||||
|
url = '';
|
||||||
|
}
|
||||||
|
|
||||||
const rawStatus = (await fetchData(`${url}status`, {
|
const rawStatus = (await fetchData(`${url}status`, {
|
||||||
...this.fetchDataOptions,
|
...this.fetchDataOptions,
|
||||||
@@ -221,7 +227,7 @@ export class RelayerClient {
|
|||||||
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
|
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
|
||||||
})) as object;
|
})) as object;
|
||||||
|
|
||||||
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config));
|
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
|
||||||
|
|
||||||
if (!statusValidator(rawStatus)) {
|
if (!statusValidator(rawStatus)) {
|
||||||
throw new Error('Invalid status schema');
|
throw new Error('Invalid status schema');
|
||||||
@@ -244,35 +250,17 @@ export class RelayerClient {
|
|||||||
throw new Error('The Relayer reward address must match registered address');
|
throw new Error('The Relayer reward address must match registered address');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isRelayerUpdated(status.version, this.netId)) {
|
|
||||||
throw new Error('Outdated version.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
async filterRelayer(
|
async filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined> {
|
||||||
curr: RelayerStructOutput,
|
const hostname = relayer.hostnames[this.netId];
|
||||||
relayer: RelayerParams,
|
|
||||||
subdomains: string[],
|
|
||||||
debugRelayer: boolean = false,
|
|
||||||
): Promise<RelayerInfo | RelayerError> {
|
|
||||||
const { relayerEnsSubdomain } = this.config;
|
|
||||||
const subdomainIndex = subdomains.indexOf(relayerEnsSubdomain);
|
|
||||||
const mainnetSubdomain = curr.records[0];
|
|
||||||
const hostname = curr.records[subdomainIndex];
|
|
||||||
const isHostWithProtocol = hostname.includes('http');
|
|
||||||
|
|
||||||
const { owner, balance: stakeBalance, isRegistered } = curr;
|
|
||||||
const { ensName, relayerAddress } = relayer;
|
const { ensName, relayerAddress } = relayer;
|
||||||
|
|
||||||
const isOwner = !relayerAddress || relayerAddress === owner;
|
if (!hostname) {
|
||||||
const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const preCondition =
|
|
||||||
hostname && isOwner && mainnetSubdomain && isRegistered && hasMinBalance && !isHostWithProtocol;
|
|
||||||
|
|
||||||
if (preCondition || debugRelayer) {
|
|
||||||
try {
|
try {
|
||||||
const status = await this.askRelayerStatus({ hostname, relayerAddress });
|
const status = await this.askRelayerStatus({ hostname, relayerAddress });
|
||||||
|
|
||||||
@@ -281,10 +269,10 @@ export class RelayerClient {
|
|||||||
url: status.url,
|
url: status.url,
|
||||||
hostname,
|
hostname,
|
||||||
ensName,
|
ensName,
|
||||||
stakeBalance,
|
|
||||||
relayerAddress,
|
relayerAddress,
|
||||||
rewardAccount: getAddress(status.rewardAccount),
|
rewardAccount: getAddress(status.rewardAccount),
|
||||||
instances: getSupportedInstances(status.instances),
|
instances: getSupportedInstances(status.instances),
|
||||||
|
stakeBalance: relayer.stakeBalance,
|
||||||
gasPrice: status.gasPrices?.fast,
|
gasPrice: status.gasPrices?.fast,
|
||||||
ethPrices: status.ethPrices,
|
ethPrices: status.ethPrices,
|
||||||
currentQueue: status.currentQueue,
|
currentQueue: status.currentQueue,
|
||||||
@@ -292,60 +280,27 @@ export class RelayerClient {
|
|||||||
} as RelayerInfo;
|
} as RelayerInfo;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (debugRelayer) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
hostname,
|
hostname,
|
||||||
relayerAddress,
|
relayerAddress,
|
||||||
errorMessage: err.message,
|
errorMessage: err.message,
|
||||||
|
hasError: true,
|
||||||
} as RelayerError;
|
} as RelayerError;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (debugRelayer) {
|
|
||||||
const errMsg = `Relayer ${hostname} condition not met`;
|
|
||||||
throw new Error(errMsg);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
hostname,
|
|
||||||
relayerAddress,
|
|
||||||
errorMessage: `Relayer ${hostname} condition not met`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getValidRelayers(
|
async getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
|
||||||
// this should be ascending order of events
|
|
||||||
relayers: RelayerParams[],
|
|
||||||
subdomains: string[],
|
|
||||||
debugRelayer: boolean = false,
|
|
||||||
): Promise<{
|
|
||||||
validRelayers: RelayerInfo[];
|
validRelayers: RelayerInfo[];
|
||||||
invalidRelayers: RelayerError[];
|
invalidRelayers: RelayerError[];
|
||||||
}> {
|
}> {
|
||||||
const relayersSet = new Set();
|
|
||||||
|
|
||||||
const uniqueRelayers = relayers.reverse().filter(({ ensName }) => {
|
|
||||||
if (!relayersSet.has(ensName)) {
|
|
||||||
relayersSet.add(ensName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const relayerNameHashes = uniqueRelayers.map((r) => namehash(r.ensName));
|
|
||||||
|
|
||||||
const relayersData = await this.Aggregator.relayersData.staticCall(relayerNameHashes, subdomains);
|
|
||||||
|
|
||||||
const invalidRelayers: RelayerError[] = [];
|
const invalidRelayers: RelayerError[] = [];
|
||||||
|
|
||||||
const validRelayers = (
|
const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter((r) => {
|
||||||
await Promise.all(
|
if (!r) {
|
||||||
relayersData.map((curr, index) => this.filterRelayer(curr, uniqueRelayers[index], subdomains, debugRelayer)),
|
return false;
|
||||||
)
|
}
|
||||||
).filter((r) => {
|
if ((r as RelayerError).hasError) {
|
||||||
if ((r as RelayerError).errorMessage) {
|
invalidRelayers.push(r as RelayerError);
|
||||||
invalidRelayers.push(r);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -358,11 +313,11 @@ export class RelayerClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
|
pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
|
||||||
return pickWeightedRandomRelayer(relayers, this.netId);
|
return pickWeightedRandomRelayer(relayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
async tornadoWithdraw({ contract, proof, args }: RelayerClientWithdraw) {
|
async tornadoWithdraw({ contract, proof, args }: TornadoWithdrawParams) {
|
||||||
const { url } = this.selectedRelayer as Relayer;
|
const { url } = this.selectedRelayer as RelayerInfo;
|
||||||
|
|
||||||
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
|
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
|
||||||
...this.fetchDataOptions,
|
...this.fetchDataOptions,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ ajv.addKeyword({
|
|||||||
try {
|
try {
|
||||||
BigInt(data);
|
BigInt(data);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -70,6 +70,16 @@ export type statusSchema = {
|
|||||||
};
|
};
|
||||||
required: string[];
|
required: string[];
|
||||||
};
|
};
|
||||||
|
syncStatus: {
|
||||||
|
type: string;
|
||||||
|
properties: {
|
||||||
|
events: { type: string };
|
||||||
|
tokenPrice: { type: string };
|
||||||
|
gasPrice: { type: string };
|
||||||
|
};
|
||||||
|
required: string[];
|
||||||
|
};
|
||||||
|
onSyncEvents: { type: string };
|
||||||
currentQueue: {
|
currentQueue: {
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
@@ -105,13 +115,23 @@ const statusSchema: statusSchema = {
|
|||||||
},
|
},
|
||||||
required: ['status'],
|
required: ['status'],
|
||||||
},
|
},
|
||||||
|
syncStatus: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
events: { type: 'boolean' },
|
||||||
|
tokenPrice: { type: 'boolean' },
|
||||||
|
gasPrice: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
required: ['events', 'tokenPrice', 'gasPrice'],
|
||||||
|
},
|
||||||
|
onSyncEvents: { type: 'boolean' },
|
||||||
currentQueue: { type: 'number' },
|
currentQueue: { type: 'number' },
|
||||||
},
|
},
|
||||||
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health'],
|
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health', 'currentQueue'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getStatusSchema(netId: NetIdType, config: Config) {
|
export function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean) {
|
||||||
const { tokens, optionalTokens = [], nativeCurrency } = config;
|
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
|
||||||
|
|
||||||
// deep copy schema
|
// deep copy schema
|
||||||
const schema = JSON.parse(JSON.stringify(statusSchema)) as statusSchema;
|
const schema = JSON.parse(JSON.stringify(statusSchema)) as statusSchema;
|
||||||
@@ -148,7 +168,7 @@ export function getStatusSchema(netId: NetIdType, config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
acc.properties[token] = instanceProperties;
|
acc.properties[token] = instanceProperties;
|
||||||
if (!optionalTokens.includes(token)) {
|
if (!optionalTokens?.includes(token) && !disabledTokens?.includes(token)) {
|
||||||
acc.required.push(token);
|
acc.required.push(token);
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
@@ -162,19 +182,29 @@ export function getStatusSchema(netId: NetIdType, config: Config) {
|
|||||||
|
|
||||||
schema.properties.instances = instances;
|
schema.properties.instances = instances;
|
||||||
|
|
||||||
if (netId === NetId.MAINNET) {
|
const _tokens = Object.keys(tokens).filter(
|
||||||
const _tokens = Object.keys(tokens).filter((t) => t !== nativeCurrency);
|
(t) => t !== nativeCurrency && !config.optionalTokens?.includes(t) && !config.disabledTokens?.includes(t),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (netId === NetId.MAINNET) {
|
||||||
|
_tokens.push('torn');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tokens.length) {
|
||||||
const ethPrices: statusEthPricesType = {
|
const ethPrices: statusEthPricesType = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: _tokens.reduce((acc: { [key in string]: typeof bnType }, token: string) => {
|
properties: _tokens.reduce((acc: { [key in string]: typeof bnType }, token: string) => {
|
||||||
acc[token] = bnType;
|
acc[token] = bnType;
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {}),
|
||||||
// required: _tokens
|
required: _tokens,
|
||||||
};
|
};
|
||||||
schema.properties.ethPrices = ethPrices;
|
schema.properties.ethPrices = ethPrices;
|
||||||
// schema.required.push('ethPrices')
|
schema.required.push('ethPrices');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tovarish) {
|
||||||
|
schema.required.push('gasPrices', 'latestBlock', 'syncStatus', 'onSyncEvents');
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
|
|||||||
242
src/tovarishClient.ts
Normal file
242
src/tovarishClient.ts
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
import { getAddress } from 'ethers';
|
||||||
|
|
||||||
|
import {
|
||||||
|
RelayerClient,
|
||||||
|
RelayerClientConstructor,
|
||||||
|
RelayerError,
|
||||||
|
RelayerInfo,
|
||||||
|
RelayerStatus,
|
||||||
|
getSupportedInstances,
|
||||||
|
} from './relayerClient';
|
||||||
|
import { fetchData } from './providers';
|
||||||
|
import { CachedRelayerInfo, MinimalEvents } from './events';
|
||||||
|
|
||||||
|
// Return no more than 5K events per query
|
||||||
|
export const MAX_TOVARISH_EVENTS = 5000;
|
||||||
|
|
||||||
|
export interface EventsStatus {
|
||||||
|
events: number;
|
||||||
|
lastBlock: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InstanceEventsStatus {
|
||||||
|
[index: string]: {
|
||||||
|
deposits: EventsStatus;
|
||||||
|
withdrawals: EventsStatus;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CurrencyEventsStatus {
|
||||||
|
[index: string]: InstanceEventsStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TovarishEventsStatus {
|
||||||
|
governance?: EventsStatus;
|
||||||
|
registered?: {
|
||||||
|
lastBlock: number;
|
||||||
|
timestamp: number;
|
||||||
|
relayers: number;
|
||||||
|
};
|
||||||
|
echo: EventsStatus;
|
||||||
|
encrypted_notes: EventsStatus;
|
||||||
|
instances: CurrencyEventsStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TovarishSyncStatus {
|
||||||
|
events: boolean;
|
||||||
|
tokenPrice: boolean;
|
||||||
|
gasPrice: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expected response from /status endpoint
|
||||||
|
export interface TovarishStatus extends RelayerStatus {
|
||||||
|
events: TovarishEventsStatus;
|
||||||
|
syncStatus: TovarishSyncStatus;
|
||||||
|
onSyncEvents: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatted TovarishStatus for Frontend usage
|
||||||
|
export interface TovarishInfo extends RelayerInfo {
|
||||||
|
latestBlock: number;
|
||||||
|
version: string;
|
||||||
|
events: TovarishEventsStatus;
|
||||||
|
syncStatus: TovarishSyncStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query input for TovarishEvents
|
||||||
|
export interface TovarishEventsQuery {
|
||||||
|
type: string;
|
||||||
|
currency?: string;
|
||||||
|
amount?: string;
|
||||||
|
fromBlock: number;
|
||||||
|
recent?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseTovarishEvents<T> {
|
||||||
|
events: T[];
|
||||||
|
lastSyncBlock: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TovarishClient extends RelayerClient {
|
||||||
|
selectedRelayer?: TovarishInfo;
|
||||||
|
|
||||||
|
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
|
||||||
|
super({ netId, config, fetchDataOptions });
|
||||||
|
this.tovarish = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async askRelayerStatus({
|
||||||
|
hostname,
|
||||||
|
url,
|
||||||
|
relayerAddress,
|
||||||
|
}: {
|
||||||
|
hostname?: string;
|
||||||
|
// optional url if entered manually
|
||||||
|
url?: string;
|
||||||
|
// relayerAddress from registry contract to prevent cheating
|
||||||
|
relayerAddress?: string;
|
||||||
|
}): Promise<TovarishStatus> {
|
||||||
|
const status = (await super.askRelayerStatus({ hostname, url, relayerAddress })) as TovarishStatus;
|
||||||
|
|
||||||
|
if (!status.version.includes('tovarish')) {
|
||||||
|
throw new Error('Not a tovarish relayer!');
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> {
|
||||||
|
const { ensName, relayerAddress, tovarishHost: hostname, tovarishNetworks } = relayer;
|
||||||
|
|
||||||
|
if (!hostname || !tovarishNetworks?.includes(this.netId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const status = await this.askRelayerStatus({ hostname, relayerAddress });
|
||||||
|
|
||||||
|
return {
|
||||||
|
netId: status.netId,
|
||||||
|
url: status.url,
|
||||||
|
hostname,
|
||||||
|
ensName,
|
||||||
|
relayerAddress,
|
||||||
|
rewardAccount: getAddress(status.rewardAccount),
|
||||||
|
instances: getSupportedInstances(status.instances),
|
||||||
|
stakeBalance: relayer.stakeBalance,
|
||||||
|
gasPrice: status.gasPrices?.fast,
|
||||||
|
ethPrices: status.ethPrices,
|
||||||
|
currentQueue: status.currentQueue,
|
||||||
|
tornadoServiceFee: status.tornadoServiceFee,
|
||||||
|
// Additional fields for tovarish relayer
|
||||||
|
latestBlock: Number(status.latestBlock),
|
||||||
|
version: status.version,
|
||||||
|
events: status.events,
|
||||||
|
syncStatus: status.syncStatus,
|
||||||
|
} as TovarishInfo;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
} catch (err: any) {
|
||||||
|
return {
|
||||||
|
hostname,
|
||||||
|
relayerAddress,
|
||||||
|
errorMessage: err.message,
|
||||||
|
hasError: true,
|
||||||
|
} as RelayerError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
|
||||||
|
validRelayers: TovarishInfo[];
|
||||||
|
invalidRelayers: RelayerError[];
|
||||||
|
}> {
|
||||||
|
const invalidRelayers: RelayerError[] = [];
|
||||||
|
|
||||||
|
const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter((r) => {
|
||||||
|
if (!r) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((r as RelayerError).hasError) {
|
||||||
|
invalidRelayers.push(r as RelayerError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}) as TovarishInfo[];
|
||||||
|
|
||||||
|
return {
|
||||||
|
validRelayers,
|
||||||
|
invalidRelayers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getEvents<T extends MinimalEvents>({
|
||||||
|
type,
|
||||||
|
currency,
|
||||||
|
amount,
|
||||||
|
fromBlock,
|
||||||
|
recent,
|
||||||
|
}: TovarishEventsQuery): Promise<BaseTovarishEvents<T>> {
|
||||||
|
const url = `${this.selectedRelayer?.url}events`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const events = [];
|
||||||
|
let lastSyncBlock = fromBlock;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-constant-condition
|
||||||
|
while (true) {
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let { events: fetchedEvents, lastSyncBlock: currentBlock } = (await fetchData(url, {
|
||||||
|
...this.fetchDataOptions,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
type,
|
||||||
|
currency,
|
||||||
|
amount,
|
||||||
|
fromBlock,
|
||||||
|
recent,
|
||||||
|
}),
|
||||||
|
})) as BaseTovarishEvents<T>;
|
||||||
|
|
||||||
|
lastSyncBlock = currentBlock;
|
||||||
|
|
||||||
|
if (!Array.isArray(fetchedEvents) || !fetchedEvents.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchedEvents = fetchedEvents.sort((a, b) => {
|
||||||
|
if (a.blockNumber === b.blockNumber) {
|
||||||
|
return a.logIndex - b.logIndex;
|
||||||
|
}
|
||||||
|
return a.blockNumber - b.blockNumber;
|
||||||
|
});
|
||||||
|
|
||||||
|
const [lastEvent] = fetchedEvents.slice(-1);
|
||||||
|
|
||||||
|
if (fetchedEvents.length < MAX_TOVARISH_EVENTS - 100) {
|
||||||
|
events.push(...fetchedEvents);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchedEvents = fetchedEvents.filter((e) => e.blockNumber !== lastEvent.blockNumber);
|
||||||
|
fromBlock = Number(lastEvent.blockNumber);
|
||||||
|
|
||||||
|
events.push(...fetchedEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
events,
|
||||||
|
lastSyncBlock,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Error from TovarishClient events endpoint');
|
||||||
|
console.log(err);
|
||||||
|
return {
|
||||||
|
events: [],
|
||||||
|
lastSyncBlock: fromBlock,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export { ENS__factory } from "./ENS__factory";
|
export { ENS__factory } from "./ENS__factory";
|
||||||
export { ERC20__factory } from "./ERC20__factory";
|
export { ERC20__factory } from "./ERC20__factory";
|
||||||
export { GasPriceOracle__factory } from "./GasPriceOracle__factory";
|
|
||||||
export { Multicall__factory } from "./Multicall__factory";
|
export { Multicall__factory } from "./Multicall__factory";
|
||||||
export { OffchainOracle__factory } from "./OffchainOracle__factory";
|
export { OffchainOracle__factory } from "./OffchainOracle__factory";
|
||||||
export { OvmGasPriceOracle__factory } from "./OvmGasPriceOracle__factory";
|
export { OvmGasPriceOracle__factory } from "./OvmGasPriceOracle__factory";
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export type { ENS } from "./ENS";
|
export type { ENS } from "./ENS";
|
||||||
export type { ERC20 } from "./ERC20";
|
export type { ERC20 } from "./ERC20";
|
||||||
export type { GasPriceOracle } from "./GasPriceOracle";
|
|
||||||
export type { Multicall } from "./Multicall";
|
export type { Multicall } from "./Multicall";
|
||||||
export type { OffchainOracle } from "./OffchainOracle";
|
export type { OffchainOracle } from "./OffchainOracle";
|
||||||
export type { OvmGasPriceOracle } from "./OvmGasPriceOracle";
|
export type { OvmGasPriceOracle } from "./OvmGasPriceOracle";
|
||||||
@@ -11,7 +10,6 @@ export type { ReverseRecords } from "./ReverseRecords";
|
|||||||
export * as factories from "./factories";
|
export * as factories from "./factories";
|
||||||
export { ENS__factory } from "./factories/ENS__factory";
|
export { ENS__factory } from "./factories/ENS__factory";
|
||||||
export { ERC20__factory } from "./factories/ERC20__factory";
|
export { ERC20__factory } from "./factories/ERC20__factory";
|
||||||
export { GasPriceOracle__factory } from "./factories/GasPriceOracle__factory";
|
|
||||||
export { Multicall__factory } from "./factories/Multicall__factory";
|
export { Multicall__factory } from "./factories/Multicall__factory";
|
||||||
export { OffchainOracle__factory } from "./factories/OffchainOracle__factory";
|
export { OffchainOracle__factory } from "./factories/OffchainOracle__factory";
|
||||||
export { OvmGasPriceOracle__factory } from "./factories/OvmGasPriceOracle__factory";
|
export { OvmGasPriceOracle__factory } from "./factories/OvmGasPriceOracle__factory";
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function bufferToBytes(b: Buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function bytesToBase64(bytes: Uint8Array) {
|
export function bytesToBase64(bytes: Uint8Array) {
|
||||||
return btoa(String.fromCharCode.apply(null, Array.from(bytes)));
|
return btoa(bytes.reduce((data, byte) => data + String.fromCharCode(byte), ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function base64ToBytes(base64: string) {
|
export function base64ToBytes(base64: string) {
|
||||||
@@ -143,3 +143,7 @@ export function substring(str: string, length: number = 10) {
|
|||||||
|
|
||||||
return `${str.substring(0, length)}...${str.substring(str.length - length)}`;
|
return `${str.substring(0, length)}...${str.substring(str.length - length)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function digest(bytes: Uint8Array, algo: string = 'SHA-384') {
|
||||||
|
return new Uint8Array(await crypto.subtle.digest(algo, bytes));
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,15 +3,14 @@ import * as websnarkUtils from '@tornado/websnark/src/utils';
|
|||||||
// @ts-expect-error no-websnark-types
|
// @ts-expect-error no-websnark-types
|
||||||
import websnarkGroth from '@tornado/websnark/src/groth16';
|
import websnarkGroth from '@tornado/websnark/src/groth16';
|
||||||
import type { Element } from '@tornado/fixed-merkle-tree';
|
import type { Element } from '@tornado/fixed-merkle-tree';
|
||||||
import type { AddressLike, BytesLike, BigNumberish } from 'ethers';
|
|
||||||
import { toFixedHex } from './utils';
|
import { toFixedHex } from './utils';
|
||||||
|
|
||||||
export type snarkInputs = {
|
export type snarkInputs = {
|
||||||
// Public snark inputs
|
// Public snark inputs
|
||||||
root: Element;
|
root: Element;
|
||||||
nullifierHex: string;
|
nullifierHex: string;
|
||||||
recipient: AddressLike;
|
recipient: string;
|
||||||
relayer: AddressLike;
|
relayer: string;
|
||||||
fee: bigint;
|
fee: bigint;
|
||||||
refund: bigint;
|
refund: bigint;
|
||||||
|
|
||||||
@@ -23,16 +22,16 @@ export type snarkInputs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type snarkArgs = [
|
export type snarkArgs = [
|
||||||
_root: BytesLike,
|
_root: string,
|
||||||
_nullifierHash: BytesLike,
|
_nullifierHash: string,
|
||||||
_recipient: AddressLike,
|
_recipient: string,
|
||||||
_relayer: AddressLike,
|
_relayer: string,
|
||||||
_fee: BigNumberish,
|
_fee: string,
|
||||||
_refund: BigNumberish,
|
_refund: string,
|
||||||
];
|
];
|
||||||
|
|
||||||
export type snarkProofs = {
|
export type snarkProofs = {
|
||||||
proof: BytesLike;
|
proof: string;
|
||||||
args: snarkArgs;
|
args: snarkArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,16 +70,16 @@ export async function calculateSnarkProof(
|
|||||||
console.log('Start generating SNARK proof', snarkInput);
|
console.log('Start generating SNARK proof', snarkInput);
|
||||||
console.time('SNARK proof time');
|
console.time('SNARK proof time');
|
||||||
const proofData = await websnarkUtils.genWitnessAndProve(await groth16, snarkInput, circuit, provingKey);
|
const proofData = await websnarkUtils.genWitnessAndProve(await groth16, snarkInput, circuit, provingKey);
|
||||||
const proof = websnarkUtils.toSolidityInput(proofData).proof as BytesLike;
|
const proof = websnarkUtils.toSolidityInput(proofData).proof;
|
||||||
console.timeEnd('SNARK proof time');
|
console.timeEnd('SNARK proof time');
|
||||||
|
|
||||||
const args = [
|
const args = [
|
||||||
toFixedHex(input.root, 32) as BytesLike,
|
toFixedHex(input.root, 32),
|
||||||
toFixedHex(input.nullifierHex, 32) as BytesLike,
|
toFixedHex(input.nullifierHex, 32),
|
||||||
input.recipient,
|
input.recipient,
|
||||||
input.relayer,
|
input.relayer,
|
||||||
toFixedHex(input.fee, 32) as BigNumberish,
|
toFixedHex(input.fee, 32),
|
||||||
toFixedHex(input.refund, 32) as BigNumberish,
|
toFixedHex(input.refund, 32),
|
||||||
] as snarkArgs;
|
] as snarkArgs;
|
||||||
|
|
||||||
return { proof, args };
|
return { proof, args };
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
/* Language and Environment */
|
/* Language and Environment */
|
||||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
"target": "es2018", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const esbuild = require('esbuild');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
||||||
|
|
||||||
@@ -8,7 +7,6 @@ const esbuildLoader = {
|
|||||||
options: {
|
options: {
|
||||||
loader: 'ts',
|
loader: 'ts',
|
||||||
target: 'es2016',
|
target: 'es2016',
|
||||||
implementation: esbuild
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +29,7 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
entry: './src/index.ts',
|
entry: './src/index.ts',
|
||||||
output: {
|
output: {
|
||||||
filename: 'index.umd.js',
|
filename: 'tornado.umd.js',
|
||||||
path: path.resolve(__dirname, './dist'),
|
path: path.resolve(__dirname, './dist'),
|
||||||
library: 'Tornado',
|
library: 'Tornado',
|
||||||
libraryTarget: 'umd'
|
libraryTarget: 'umd'
|
||||||
@@ -49,6 +47,28 @@ module.exports = [
|
|||||||
minimize: false,
|
minimize: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
mode: 'production',
|
||||||
|
module: {
|
||||||
|
rules: [esbuildLoader]
|
||||||
|
},
|
||||||
|
entry: './src/index.ts',
|
||||||
|
output: {
|
||||||
|
filename: 'tornado.umd.min.js',
|
||||||
|
path: path.resolve(__dirname, './dist'),
|
||||||
|
library: 'Tornado',
|
||||||
|
libraryTarget: 'umd'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new NodePolyfillPlugin(),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', '.js'],
|
||||||
|
alias: {
|
||||||
|
...commonAlias,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
module: {
|
module: {
|
||||||
@@ -72,5 +92,26 @@ module.exports = [
|
|||||||
optimization: {
|
optimization: {
|
||||||
minimize: false,
|
minimize: false,
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mode: 'production',
|
||||||
|
module: {
|
||||||
|
rules: [esbuildLoader]
|
||||||
|
},
|
||||||
|
entry: './src/merkleTreeWorker.ts',
|
||||||
|
output: {
|
||||||
|
filename: 'merkleTreeWorker.umd.min.js',
|
||||||
|
path: path.resolve(__dirname, './dist'),
|
||||||
|
libraryTarget: 'umd'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new NodePolyfillPlugin(),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', '.js'],
|
||||||
|
alias: {
|
||||||
|
...commonAlias,
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user