Initial client for Tovarish Relayer

This commit is contained in:
Tornado Contrib 2024-09-29 11:24:36 +00:00
parent be0e2419aa
commit 3f6394bbc4
Signed by: tornadocontrib
GPG Key ID: 60B4DF1A076C64B1
12 changed files with 849 additions and 73 deletions

24
dist/events/base.d.ts vendored

@ -4,6 +4,7 @@ import { BatchEventsService, BatchBlockService, BatchTransactionService, BatchEv
import { fetchDataOptions } from '../providers'; import { fetchDataOptions } from '../providers';
import type { NetIdType, SubdomainMap } from '../networkConfig'; import type { NetIdType, SubdomainMap } from '../networkConfig';
import { RelayerParams } from '../relayerClient'; import { RelayerParams } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient';
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types'; 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";
@ -16,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;
@ -39,7 +41,8 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
deployedBlock: number; deployedBlock: number;
batchEventsService: BatchEventsService; batchEventsService: BatchEventsService;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
constructor({ netId, provider, graphApi, subgraphName, contract, type, deployedBlock, fetchDataOptions, }: BaseEventsServiceConstructor); tovarishClient?: TovarishClient;
constructor({ netId, provider, graphApi, subgraphName, contract, type, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEventsServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getType(): string; getType(): string;
getTovarishType(): string; getTovarishType(): string;
@ -97,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;
@ -107,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;
@ -115,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;
@ -124,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;
@ -143,9 +152,10 @@ 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; getTovarishType(): string;
@ -160,10 +170,11 @@ 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; getTovarishType(): string;
@ -203,12 +214,13 @@ export type BaseRegistryServiceConstructor = {
relayerEnsSubdomains: SubdomainMap; 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> {
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
updateInterval: number; updateInterval: number;
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, }: BaseRegistryServiceConstructor); constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, tovarishClient, }: BaseRegistryServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getType(): string; getType(): string;
getTovarishType(): string; getTovarishType(): string;

137
dist/index.js vendored

@ -2399,11 +2399,21 @@ const 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"]
}; };
function getStatusSchema(netId, config) { function getStatusSchema(netId, config, tovarish) {
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config; const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
const schema = JSON.parse(JSON.stringify(statusSchema)); const schema = JSON.parse(JSON.stringify(statusSchema));
const instances = Object.keys(tokens).reduce( const instances = Object.keys(tokens).reduce(
@ -2447,17 +2457,29 @@ function getStatusSchema(netId, config) {
} }
); );
schema.properties.instances = instances; schema.properties.instances = instances;
const _tokens = Object.keys(tokens).filter(
(t) => {
var _a, _b;
return t !== nativeCurrency && !((_a = config.optionalTokens) == null ? void 0 : _a.includes(t)) && !((_b = config.disabledTokens) == null ? void 0 : _b.includes(t));
}
);
if (netId === NetId.MAINNET) { if (netId === NetId.MAINNET) {
const _tokens = Object.keys(tokens).filter((t) => t !== nativeCurrency); _tokens.push("torn");
}
if (_tokens.length) {
const ethPrices = { const ethPrices = {
type: "object", type: "object",
properties: _tokens.reduce((acc, token) => { properties: _tokens.reduce((acc, token) => {
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");
}
if (tovarish) {
schema.required.push("gasPrices", "latestBlock", "syncStatus", "onSyncEvents");
} }
return schema; return schema;
} }
@ -2579,6 +2601,7 @@ class RelayerClient {
this.netId = netId; this.netId = netId;
this.config = config; this.config = config;
this.fetchDataOptions = fetchDataOptions2; this.fetchDataOptions = fetchDataOptions2;
this.tovarish = false;
} }
askRelayerStatus(_0) { askRelayerStatus(_0) {
return __async$9(this, arguments, function* ({ return __async$9(this, arguments, function* ({
@ -2601,7 +2624,7 @@ class RelayerClient {
timeout: ((_a = this.fetchDataOptions) == null ? void 0 : _a.torPort) ? 1e4 : 3e3, timeout: ((_a = this.fetchDataOptions) == null ? void 0 : _a.torPort) ? 1e4 : 3e3,
maxRetry: ((_b = this.fetchDataOptions) == null ? void 0 : _b.torPort) ? 2 : 0 maxRetry: ((_b = this.fetchDataOptions) == null ? void 0 : _b.torPort) ? 2 : 0
})); }));
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");
} }
@ -2792,7 +2815,8 @@ class BaseEventsService {
contract, contract,
type = "", type = "",
deployedBlock = 0, deployedBlock = 0,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
this.netId = netId; this.netId = netId;
this.provider = provider; this.provider = provider;
@ -2807,6 +2831,7 @@ class BaseEventsService {
contract, contract,
onProgress: this.updateEventProgress onProgress: this.updateEventProgress
}); });
this.tovarishClient = tovarishClient;
} }
getInstanceName() { getInstanceName() {
return ""; return "";
@ -2932,6 +2957,17 @@ class BaseEventsService {
} }
getLatestEvents(_0) { getLatestEvents(_0) {
return __async$8(this, arguments, function* ({ fromBlock }) { return __async$8(this, arguments, function* ({ fromBlock }) {
var _a;
if (((_a = this.tovarishClient) == null ? void 0 : _a.selectedRelayer) && ![DEPOSIT, WITHDRAWAL].includes(this.type.toLowerCase())) {
const { events, lastSyncBlock: lastBlock } = yield this.tovarishClient.getEvents({
type: this.getTovarishType(),
fromBlock
});
return {
events,
lastBlock
};
}
const graphEvents = yield this.getEventsFromGraph({ fromBlock }); const graphEvents = yield this.getEventsFromGraph({ fromBlock });
const lastSyncBlock = graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock; const lastSyncBlock = graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
const rpcEvents = yield this.getEventsFromRpc({ fromBlock: lastSyncBlock }); const rpcEvents = yield this.getEventsFromRpc({ fromBlock: lastSyncBlock });
@ -2999,9 +3035,20 @@ class BaseTornadoService extends BaseEventsService {
amount, amount,
currency, currency,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Tornado, type, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Tornado,
type,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.amount = amount; this.amount = amount;
this.currency = currency; this.currency = currency;
this.batchTransactionService = new BatchTransactionService({ this.batchTransactionService = new BatchTransactionService({
@ -3086,6 +3133,22 @@ class BaseTornadoService extends BaseEventsService {
} }
} }
} }
getLatestEvents(_0) {
return __async$8(this, arguments, function* ({ fromBlock }) {
var _a;
if ((_a = this.tovarishClient) == null ? void 0 : _a.selectedRelayer) {
const { events, lastSyncBlock: lastBlock } = yield this.tovarishClient.getEvents({
type: this.getTovarishType(),
fromBlock
});
return {
events,
lastBlock
};
}
return __superGet(BaseTornadoService.prototype, this, "getLatestEvents").call(this, { fromBlock });
});
}
} }
class BaseEchoService extends BaseEventsService { class BaseEchoService extends BaseEventsService {
constructor({ constructor({
@ -3095,9 +3158,19 @@ class BaseEchoService extends BaseEventsService {
subgraphName, subgraphName,
Echoer, Echoer,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Echoer, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Echoer,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
} }
getInstanceName() { getInstanceName() {
return `echo_${this.netId}`; return `echo_${this.netId}`;
@ -3146,9 +3219,19 @@ class BaseEncryptedNotesService extends BaseEventsService {
subgraphName, subgraphName,
Router, Router,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Router, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Router,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
} }
getInstanceName() { getInstanceName() {
return `encrypted_notes_${this.netId}`; return `encrypted_notes_${this.netId}`;
@ -3188,9 +3271,19 @@ class BaseGovernanceService extends BaseEventsService {
subgraphName, subgraphName,
Governance, Governance,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Governance, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Governance,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.batchTransactionService = new BatchTransactionService({ this.batchTransactionService = new BatchTransactionService({
provider, provider,
onProgress: this.updateTransactionProgress onProgress: this.updateTransactionProgress
@ -3317,9 +3410,19 @@ class BaseRegistryService extends BaseEventsService {
Aggregator, Aggregator,
relayerEnsSubdomains, relayerEnsSubdomains,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: RelayerRegistry, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: RelayerRegistry,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.Aggregator = Aggregator; this.Aggregator = Aggregator;
this.relayerEnsSubdomains = relayerEnsSubdomains; this.relayerEnsSubdomains = relayerEnsSubdomains;
this.updateInterval = 86400; this.updateInterval = 86400;

137
dist/index.mjs vendored

@ -2378,11 +2378,21 @@ const 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"]
}; };
function getStatusSchema(netId, config) { function getStatusSchema(netId, config, tovarish) {
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config; const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
const schema = JSON.parse(JSON.stringify(statusSchema)); const schema = JSON.parse(JSON.stringify(statusSchema));
const instances = Object.keys(tokens).reduce( const instances = Object.keys(tokens).reduce(
@ -2426,17 +2436,29 @@ function getStatusSchema(netId, config) {
} }
); );
schema.properties.instances = instances; schema.properties.instances = instances;
const _tokens = Object.keys(tokens).filter(
(t) => {
var _a, _b;
return t !== nativeCurrency && !((_a = config.optionalTokens) == null ? void 0 : _a.includes(t)) && !((_b = config.disabledTokens) == null ? void 0 : _b.includes(t));
}
);
if (netId === NetId.MAINNET) { if (netId === NetId.MAINNET) {
const _tokens = Object.keys(tokens).filter((t) => t !== nativeCurrency); _tokens.push("torn");
}
if (_tokens.length) {
const ethPrices = { const ethPrices = {
type: "object", type: "object",
properties: _tokens.reduce((acc, token) => { properties: _tokens.reduce((acc, token) => {
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");
}
if (tovarish) {
schema.required.push("gasPrices", "latestBlock", "syncStatus", "onSyncEvents");
} }
return schema; return schema;
} }
@ -2558,6 +2580,7 @@ class RelayerClient {
this.netId = netId; this.netId = netId;
this.config = config; this.config = config;
this.fetchDataOptions = fetchDataOptions2; this.fetchDataOptions = fetchDataOptions2;
this.tovarish = false;
} }
askRelayerStatus(_0) { askRelayerStatus(_0) {
return __async$9(this, arguments, function* ({ return __async$9(this, arguments, function* ({
@ -2580,7 +2603,7 @@ class RelayerClient {
timeout: ((_a = this.fetchDataOptions) == null ? void 0 : _a.torPort) ? 1e4 : 3e3, timeout: ((_a = this.fetchDataOptions) == null ? void 0 : _a.torPort) ? 1e4 : 3e3,
maxRetry: ((_b = this.fetchDataOptions) == null ? void 0 : _b.torPort) ? 2 : 0 maxRetry: ((_b = this.fetchDataOptions) == null ? void 0 : _b.torPort) ? 2 : 0
})); }));
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");
} }
@ -2771,7 +2794,8 @@ class BaseEventsService {
contract, contract,
type = "", type = "",
deployedBlock = 0, deployedBlock = 0,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
this.netId = netId; this.netId = netId;
this.provider = provider; this.provider = provider;
@ -2786,6 +2810,7 @@ class BaseEventsService {
contract, contract,
onProgress: this.updateEventProgress onProgress: this.updateEventProgress
}); });
this.tovarishClient = tovarishClient;
} }
getInstanceName() { getInstanceName() {
return ""; return "";
@ -2911,6 +2936,17 @@ class BaseEventsService {
} }
getLatestEvents(_0) { getLatestEvents(_0) {
return __async$8(this, arguments, function* ({ fromBlock }) { return __async$8(this, arguments, function* ({ fromBlock }) {
var _a;
if (((_a = this.tovarishClient) == null ? void 0 : _a.selectedRelayer) && ![DEPOSIT, WITHDRAWAL].includes(this.type.toLowerCase())) {
const { events, lastSyncBlock: lastBlock } = yield this.tovarishClient.getEvents({
type: this.getTovarishType(),
fromBlock
});
return {
events,
lastBlock
};
}
const graphEvents = yield this.getEventsFromGraph({ fromBlock }); const graphEvents = yield this.getEventsFromGraph({ fromBlock });
const lastSyncBlock = graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock; const lastSyncBlock = graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
const rpcEvents = yield this.getEventsFromRpc({ fromBlock: lastSyncBlock }); const rpcEvents = yield this.getEventsFromRpc({ fromBlock: lastSyncBlock });
@ -2978,9 +3014,20 @@ class BaseTornadoService extends BaseEventsService {
amount, amount,
currency, currency,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Tornado, type, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Tornado,
type,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.amount = amount; this.amount = amount;
this.currency = currency; this.currency = currency;
this.batchTransactionService = new BatchTransactionService({ this.batchTransactionService = new BatchTransactionService({
@ -3065,6 +3112,22 @@ class BaseTornadoService extends BaseEventsService {
} }
} }
} }
getLatestEvents(_0) {
return __async$8(this, arguments, function* ({ fromBlock }) {
var _a;
if ((_a = this.tovarishClient) == null ? void 0 : _a.selectedRelayer) {
const { events, lastSyncBlock: lastBlock } = yield this.tovarishClient.getEvents({
type: this.getTovarishType(),
fromBlock
});
return {
events,
lastBlock
};
}
return __superGet(BaseTornadoService.prototype, this, "getLatestEvents").call(this, { fromBlock });
});
}
} }
class BaseEchoService extends BaseEventsService { class BaseEchoService extends BaseEventsService {
constructor({ constructor({
@ -3074,9 +3137,19 @@ class BaseEchoService extends BaseEventsService {
subgraphName, subgraphName,
Echoer, Echoer,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Echoer, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Echoer,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
} }
getInstanceName() { getInstanceName() {
return `echo_${this.netId}`; return `echo_${this.netId}`;
@ -3125,9 +3198,19 @@ class BaseEncryptedNotesService extends BaseEventsService {
subgraphName, subgraphName,
Router, Router,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Router, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Router,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
} }
getInstanceName() { getInstanceName() {
return `encrypted_notes_${this.netId}`; return `encrypted_notes_${this.netId}`;
@ -3167,9 +3250,19 @@ class BaseGovernanceService extends BaseEventsService {
subgraphName, subgraphName,
Governance, Governance,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Governance, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Governance,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.batchTransactionService = new BatchTransactionService({ this.batchTransactionService = new BatchTransactionService({
provider, provider,
onProgress: this.updateTransactionProgress onProgress: this.updateTransactionProgress
@ -3296,9 +3389,19 @@ class BaseRegistryService extends BaseEventsService {
Aggregator, Aggregator,
relayerEnsSubdomains, relayerEnsSubdomains,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: RelayerRegistry, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: RelayerRegistry,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.Aggregator = Aggregator; this.Aggregator = Aggregator;
this.relayerEnsSubdomains = relayerEnsSubdomains; this.relayerEnsSubdomains = relayerEnsSubdomains;
this.updateInterval = 86400; this.updateInterval = 86400;

@ -1,7 +1,7 @@
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 { CachedRelayerInfo } from './events/base'; import type { CachedRelayerInfo } from './events';
export declare const MIN_FEE = 0.1; export declare const MIN_FEE = 0.1;
export declare const MAX_FEE = 0.9; export declare const MAX_FEE = 0.9;
export declare const MIN_STAKE_BALANCE: bigint; export declare const MIN_STAKE_BALANCE: bigint;
@ -130,6 +130,7 @@ export declare class RelayerClient {
config: Config; config: Config;
selectedRelayer?: RelayerInfo; selectedRelayer?: RelayerInfo;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor); constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: { askRelayerStatus({ hostname, url, relayerAddress, }: {
hostname?: string; hostname?: string;

@ -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 {};

137
dist/tornado.umd.js vendored

@ -59136,7 +59136,8 @@ class BaseEventsService {
contract, contract,
type = "", type = "",
deployedBlock = 0, deployedBlock = 0,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
this.netId = netId; this.netId = netId;
this.provider = provider; this.provider = provider;
@ -59151,6 +59152,7 @@ class BaseEventsService {
contract, contract,
onProgress: this.updateEventProgress onProgress: this.updateEventProgress
}); });
this.tovarishClient = tovarishClient;
} }
getInstanceName() { getInstanceName() {
return ""; return "";
@ -59276,6 +59278,17 @@ class BaseEventsService {
} }
getLatestEvents(_0) { getLatestEvents(_0) {
return __async(this, arguments, function* ({ fromBlock }) { return __async(this, arguments, function* ({ fromBlock }) {
var _a;
if (((_a = this.tovarishClient) == null ? void 0 : _a.selectedRelayer) && ![DEPOSIT, WITHDRAWAL].includes(this.type.toLowerCase())) {
const { events, lastSyncBlock: lastBlock } = yield this.tovarishClient.getEvents({
type: this.getTovarishType(),
fromBlock
});
return {
events,
lastBlock
};
}
const graphEvents = yield this.getEventsFromGraph({ fromBlock }); const graphEvents = yield this.getEventsFromGraph({ fromBlock });
const lastSyncBlock = graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock; const lastSyncBlock = graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
const rpcEvents = yield this.getEventsFromRpc({ fromBlock: lastSyncBlock }); const rpcEvents = yield this.getEventsFromRpc({ fromBlock: lastSyncBlock });
@ -59343,9 +59356,20 @@ class BaseTornadoService extends BaseEventsService {
amount, amount,
currency, currency,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Tornado, type, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Tornado,
type,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.amount = amount; this.amount = amount;
this.currency = currency; this.currency = currency;
this.batchTransactionService = new _batch__WEBPACK_IMPORTED_MODULE_1__/* .BatchTransactionService */ .AF({ this.batchTransactionService = new _batch__WEBPACK_IMPORTED_MODULE_1__/* .BatchTransactionService */ .AF({
@ -59430,6 +59454,22 @@ class BaseTornadoService extends BaseEventsService {
} }
} }
} }
getLatestEvents(_0) {
return __async(this, arguments, function* ({ fromBlock }) {
var _a;
if ((_a = this.tovarishClient) == null ? void 0 : _a.selectedRelayer) {
const { events, lastSyncBlock: lastBlock } = yield this.tovarishClient.getEvents({
type: this.getTovarishType(),
fromBlock
});
return {
events,
lastBlock
};
}
return __superGet(BaseTornadoService.prototype, this, "getLatestEvents").call(this, { fromBlock });
});
}
} }
class BaseEchoService extends BaseEventsService { class BaseEchoService extends BaseEventsService {
constructor({ constructor({
@ -59439,9 +59479,19 @@ class BaseEchoService extends BaseEventsService {
subgraphName, subgraphName,
Echoer, Echoer,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Echoer, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Echoer,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
} }
getInstanceName() { getInstanceName() {
return `echo_${this.netId}`; return `echo_${this.netId}`;
@ -59490,9 +59540,19 @@ class BaseEncryptedNotesService extends BaseEventsService {
subgraphName, subgraphName,
Router, Router,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Router, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Router,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
} }
getInstanceName() { getInstanceName() {
return `encrypted_notes_${this.netId}`; return `encrypted_notes_${this.netId}`;
@ -59532,9 +59592,19 @@ class BaseGovernanceService extends BaseEventsService {
subgraphName, subgraphName,
Governance, Governance,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: Governance, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: Governance,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.batchTransactionService = new _batch__WEBPACK_IMPORTED_MODULE_1__/* .BatchTransactionService */ .AF({ this.batchTransactionService = new _batch__WEBPACK_IMPORTED_MODULE_1__/* .BatchTransactionService */ .AF({
provider, provider,
onProgress: this.updateTransactionProgress onProgress: this.updateTransactionProgress
@ -59661,9 +59731,19 @@ class BaseRegistryService extends BaseEventsService {
Aggregator, Aggregator,
relayerEnsSubdomains, relayerEnsSubdomains,
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2 fetchDataOptions: fetchDataOptions2,
tovarishClient
}) { }) {
super({ netId, provider, graphApi, subgraphName, contract: RelayerRegistry, deployedBlock, fetchDataOptions: fetchDataOptions2 }); super({
netId,
provider,
graphApi,
subgraphName,
contract: RelayerRegistry,
deployedBlock,
fetchDataOptions: fetchDataOptions2,
tovarishClient
});
this.Aggregator = Aggregator; this.Aggregator = Aggregator;
this.relayerEnsSubdomains = relayerEnsSubdomains; this.relayerEnsSubdomains = relayerEnsSubdomains;
this.updateInterval = 86400; this.updateInterval = 86400;
@ -71549,6 +71629,7 @@ class RelayerClient {
this.netId = netId; this.netId = netId;
this.config = config; this.config = config;
this.fetchDataOptions = fetchDataOptions2; this.fetchDataOptions = fetchDataOptions2;
this.tovarish = false;
} }
askRelayerStatus(_0) { askRelayerStatus(_0) {
return __async(this, arguments, function* ({ return __async(this, arguments, function* ({
@ -71571,7 +71652,7 @@ class RelayerClient {
timeout: ((_a = this.fetchDataOptions) == null ? void 0 : _a.torPort) ? 1e4 : 3e3, timeout: ((_a = this.fetchDataOptions) == null ? void 0 : _a.torPort) ? 1e4 : 3e3,
maxRetry: ((_b = this.fetchDataOptions) == null ? void 0 : _b.torPort) ? 2 : 0 maxRetry: ((_b = this.fetchDataOptions) == null ? void 0 : _b.torPort) ? 2 : 0
})); }));
const statusValidator = _schemas__WEBPACK_IMPORTED_MODULE_3__/* .ajv */ .SS.compile((0,_schemas__WEBPACK_IMPORTED_MODULE_3__/* .getStatusSchema */ .c_)(this.netId, this.config)); const statusValidator = _schemas__WEBPACK_IMPORTED_MODULE_3__/* .ajv */ .SS.compile((0,_schemas__WEBPACK_IMPORTED_MODULE_3__/* .getStatusSchema */ .c_)(this.netId, this.config, this.tovarish));
if (!statusValidator(rawStatus)) { if (!statusValidator(rawStatus)) {
throw new Error("Invalid status schema"); throw new Error("Invalid status schema");
} }
@ -71758,11 +71839,21 @@ const 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"]
}; };
function getStatusSchema(netId, config) { function getStatusSchema(netId, config, tovarish) {
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config; const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
const schema = JSON.parse(JSON.stringify(statusSchema)); const schema = JSON.parse(JSON.stringify(statusSchema));
const instances = Object.keys(tokens).reduce( const instances = Object.keys(tokens).reduce(
@ -71806,17 +71897,29 @@ function getStatusSchema(netId, config) {
} }
); );
schema.properties.instances = instances; schema.properties.instances = instances;
const _tokens = Object.keys(tokens).filter(
(t) => {
var _a, _b;
return t !== nativeCurrency && !((_a = config.optionalTokens) == null ? void 0 : _a.includes(t)) && !((_b = config.disabledTokens) == null ? void 0 : _b.includes(t));
}
);
if (netId === networkConfig/* NetId */.zr.MAINNET) { if (netId === networkConfig/* NetId */.zr.MAINNET) {
const _tokens = Object.keys(tokens).filter((t) => t !== nativeCurrency); _tokens.push("torn");
}
if (_tokens.length) {
const ethPrices = { const ethPrices = {
type: "object", type: "object",
properties: _tokens.reduce((acc, token) => { properties: _tokens.reduce((acc, token) => {
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");
}
if (tovarish) {
schema.required.push("gasPrices", "latestBlock", "syncStatus", "onSyncEvents");
} }
return schema; return schema;
} }

File diff suppressed because one or more lines are too long

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;
syncStats: TovarishSyncStatus;
onSyncEvents: boolean;
}
export interface TovarishInfo extends RelayerInfo {
latestBlock: number;
version: string;
events: TovarishEventsStatus;
syncStats: 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>>;
}

@ -33,6 +33,7 @@ import {
import { fetchData, fetchDataOptions } from '../providers'; import { fetchData, fetchDataOptions } from '../providers';
import type { NetIdType, SubdomainMap } from '../networkConfig'; import type { NetIdType, SubdomainMap } from '../networkConfig';
import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient'; import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient';
import type { import type {
BaseEvents, BaseEvents,
@ -63,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 = ({
@ -94,6 +96,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
deployedBlock: number; deployedBlock: number;
batchEventsService: BatchEventsService; batchEventsService: BatchEventsService;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
constructor({ constructor({
netId, netId,
@ -104,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;
@ -120,6 +124,8 @@ export class BaseEventsService<EventType extends MinimalEvents> {
contract, contract,
onProgress: this.updateEventProgress, onProgress: this.updateEventProgress,
}); });
this.tovarishClient = tovarishClient;
} }
getInstanceName(): string { getInstanceName(): string {
@ -262,6 +268,18 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EventType>> { async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EventType>> {
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;
@ -340,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 & {
@ -352,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,
@ -364,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;
@ -467,6 +498,24 @@ 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(),
fromBlock,
});
return {
events,
lastBlock,
};
}
return super.getLatestEvents({ fromBlock });
}
} }
export type BaseEchoServiceConstructor = { export type BaseEchoServiceConstructor = {
@ -477,6 +526,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> {
@ -488,8 +538,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 {
@ -547,6 +607,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> {
@ -558,8 +619,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 {
@ -608,6 +679,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> {
@ -621,8 +693,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,
@ -799,6 +881,7 @@ export type BaseRegistryServiceConstructor = {
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
deployedBlock?: number; deployedBlock?: number;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
}; };
export class BaseRegistryService extends BaseEventsService<RegistersEvents> { export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
@ -816,8 +899,18 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
relayerEnsSubdomains, 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.Aggregator = Aggregator;
this.relayerEnsSubdomains = relayerEnsSubdomains; this.relayerEnsSubdomains = relayerEnsSubdomains;

@ -4,7 +4,7 @@ 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 { CachedRelayerInfo } from './events/base'; import type { CachedRelayerInfo } from './events';
export const MIN_FEE = 0.1; export const MIN_FEE = 0.1;
@ -190,11 +190,13 @@ export class RelayerClient {
config: Config; config: Config;
selectedRelayer?: RelayerInfo; selectedRelayer?: RelayerInfo;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) { constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
this.netId = netId; this.netId = netId;
this.config = config; this.config = config;
this.fetchDataOptions = fetchDataOptions; this.fetchDataOptions = fetchDataOptions;
this.tovarish = false;
} }
async askRelayerStatus({ async askRelayerStatus({
@ -225,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');

@ -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,12 +115,22 @@ 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, disabledTokens, nativeCurrency } = config; const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
// deep copy schema // deep copy schema
@ -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

@ -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;
syncStats: TovarishSyncStatus;
onSyncEvents: boolean;
}
// Formatted TovarishStatus for Frontend usage
export interface TovarishInfo extends RelayerInfo {
latestBlock: number;
version: string;
events: TovarishEventsStatus;
syncStats: 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,
syncStats: status.syncStats,
} 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,
};
}
}
}