Minor updates #1
16
dist/batch.d.ts
vendored
16
dist/batch.d.ts
vendored
@ -1,4 +1,14 @@
|
||||
import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog, TransactionReceipt } from 'ethers';
|
||||
import { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog, TransactionReceipt, EventFragment, TopicFilter, Interface, Log } from 'ethers';
|
||||
/**
|
||||
* Copied from ethers.js as they don't export this function
|
||||
* https://github.com/ethers-io/ethers.js/blob/main/src.ts/contract/contract.ts#L464
|
||||
*/
|
||||
export declare function getSubInfo(abiInterface: Interface, event: ContractEventName): Promise<{
|
||||
fragment: null | EventFragment;
|
||||
tag: string;
|
||||
topics: TopicFilter;
|
||||
}>;
|
||||
export declare function multiQueryFilter(address: string | string[], contract: BaseContract, event: ContractEventName, fromBlock?: BlockTag, toBlock?: BlockTag): Promise<Log[]>;
|
||||
export interface BatchBlockServiceConstructor {
|
||||
provider: Provider;
|
||||
onProgress?: BatchBlockOnProgress;
|
||||
@ -50,6 +60,7 @@ export declare class BatchTransactionService {
|
||||
export interface BatchEventServiceConstructor {
|
||||
provider: Provider;
|
||||
contract: BaseContract;
|
||||
address?: string | string[];
|
||||
onProgress?: BatchEventOnProgress;
|
||||
concurrencySize?: number;
|
||||
blocksPerRequest?: number;
|
||||
@ -75,13 +86,14 @@ export interface EventInput {
|
||||
export declare class BatchEventsService {
|
||||
provider: Provider;
|
||||
contract: BaseContract;
|
||||
address?: string | string[];
|
||||
onProgress?: BatchEventOnProgress;
|
||||
concurrencySize: number;
|
||||
blocksPerRequest: number;
|
||||
shouldRetry: boolean;
|
||||
retryMax: number;
|
||||
retryOn: number;
|
||||
constructor({ provider, contract, onProgress, concurrencySize, blocksPerRequest, shouldRetry, retryMax, retryOn, }: BatchEventServiceConstructor);
|
||||
constructor({ provider, contract, address, onProgress, concurrencySize, blocksPerRequest, shouldRetry, retryMax, retryOn, }: BatchEventServiceConstructor);
|
||||
getPastEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]>;
|
||||
createBatchRequest(batchArray: EventInput[]): Promise<EventLog[]>[];
|
||||
getBatchEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]>;
|
||||
|
8
dist/events/base.d.ts
vendored
8
dist/events/base.d.ts
vendored
@ -50,8 +50,8 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
|
||||
getLatestEvents({ fromBlock }: {
|
||||
fromBlock: number;
|
||||
}): Promise<BaseEvents<EventType>>;
|
||||
validateEvents<S>({ events, lastBlock, hasNewEvents, }: BaseEvents<EventType> & {
|
||||
hasNewEvents?: boolean;
|
||||
validateEvents<S>({ events, newEvents, lastBlock, }: BaseEvents<EventType> & {
|
||||
newEvents: EventType[];
|
||||
}): Promise<S>;
|
||||
/**
|
||||
* Handle saving events
|
||||
@ -83,8 +83,8 @@ export declare class BaseTornadoService extends BaseEventsService<DepositsEvents
|
||||
constructor(serviceConstructor: BaseTornadoServiceConstructor);
|
||||
getInstanceName(): string;
|
||||
formatEvents(events: EventLog[]): Promise<(DepositsEvents | WithdrawalsEvents)[]>;
|
||||
validateEvents<S>({ events, hasNewEvents, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
|
||||
hasNewEvents?: boolean;
|
||||
validateEvents<S>({ events, newEvents, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
|
||||
newEvents: (DepositsEvents | WithdrawalsEvents)[];
|
||||
}): Promise<S>;
|
||||
getLatestEvents({ fromBlock, }: {
|
||||
fromBlock: number;
|
||||
|
133
dist/index.js
vendored
133
dist/index.js
vendored
@ -154,6 +154,107 @@ function fromContentHash(contentHash) {
|
||||
return contentHashUtils__namespace.decode(contentHash);
|
||||
}
|
||||
|
||||
function isDeferred(value) {
|
||||
return value && typeof value === "object" && "getTopicFilter" in value && typeof value.getTopicFilter === "function" && value.fragment;
|
||||
}
|
||||
async function getSubInfo(abiInterface, event) {
|
||||
let topics;
|
||||
let fragment = null;
|
||||
if (Array.isArray(event)) {
|
||||
const topicHashify = function(name) {
|
||||
if (ethers.isHexString(name, 32)) {
|
||||
return name;
|
||||
}
|
||||
const fragment2 = abiInterface.getEvent(name);
|
||||
ethers.assertArgument(fragment2, "unknown fragment", "name", name);
|
||||
return fragment2.topicHash;
|
||||
};
|
||||
topics = event.map((e) => {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(e)) {
|
||||
return e.map(topicHashify);
|
||||
}
|
||||
return topicHashify(e);
|
||||
});
|
||||
} else if (event === "*") {
|
||||
topics = [null];
|
||||
} else if (typeof event === "string") {
|
||||
if (ethers.isHexString(event, 32)) {
|
||||
topics = [event];
|
||||
} else {
|
||||
fragment = abiInterface.getEvent(event);
|
||||
ethers.assertArgument(fragment, "unknown fragment", "event", event);
|
||||
topics = [fragment.topicHash];
|
||||
}
|
||||
} else if (isDeferred(event)) {
|
||||
topics = await event.getTopicFilter();
|
||||
} else if ("fragment" in event) {
|
||||
fragment = event.fragment;
|
||||
topics = [fragment.topicHash];
|
||||
} else {
|
||||
ethers.assertArgument(false, "unknown event name", "event", event);
|
||||
}
|
||||
topics = topics.map((t) => {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(t)) {
|
||||
const items = Array.from(new Set(t.map((t2) => t2.toLowerCase())).values());
|
||||
if (items.length === 1) {
|
||||
return items[0];
|
||||
}
|
||||
items.sort();
|
||||
return items;
|
||||
}
|
||||
return t.toLowerCase();
|
||||
});
|
||||
const tag = topics.map((t) => {
|
||||
if (t == null) {
|
||||
return "null";
|
||||
}
|
||||
if (Array.isArray(t)) {
|
||||
return t.join("|");
|
||||
}
|
||||
return t;
|
||||
}).join("&");
|
||||
return { fragment, tag, topics };
|
||||
}
|
||||
async function multiQueryFilter(address, contract, event, fromBlock, toBlock) {
|
||||
if (fromBlock == null) {
|
||||
fromBlock = 0;
|
||||
}
|
||||
if (toBlock == null) {
|
||||
toBlock = "latest";
|
||||
}
|
||||
const { fragment, topics } = await getSubInfo(contract.interface, event);
|
||||
const filter = {
|
||||
address: address === "*" ? void 0 : address,
|
||||
topics,
|
||||
fromBlock,
|
||||
toBlock
|
||||
};
|
||||
const provider = contract.runner;
|
||||
ethers.assert(provider, "contract runner does not have a provider", "UNSUPPORTED_OPERATION", { operation: "queryFilter" });
|
||||
return (await provider.getLogs(filter)).map((log) => {
|
||||
let foundFragment = fragment;
|
||||
if (foundFragment == null) {
|
||||
try {
|
||||
foundFragment = contract.interface.getEvent(log.topics[0]);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
if (foundFragment) {
|
||||
try {
|
||||
return new ethers.EventLog(log, contract.interface, foundFragment);
|
||||
} catch (error) {
|
||||
return new ethers.UndecodedEventLog(log, error);
|
||||
}
|
||||
}
|
||||
return new ethers.Log(log, provider);
|
||||
});
|
||||
}
|
||||
class BatchBlockService {
|
||||
provider;
|
||||
onProgress;
|
||||
@ -326,6 +427,7 @@ class BatchTransactionService {
|
||||
class BatchEventsService {
|
||||
provider;
|
||||
contract;
|
||||
address;
|
||||
onProgress;
|
||||
concurrencySize;
|
||||
blocksPerRequest;
|
||||
@ -335,6 +437,7 @@ class BatchEventsService {
|
||||
constructor({
|
||||
provider,
|
||||
contract,
|
||||
address,
|
||||
onProgress,
|
||||
concurrencySize = 10,
|
||||
blocksPerRequest = 5e3,
|
||||
@ -344,6 +447,7 @@ class BatchEventsService {
|
||||
}) {
|
||||
this.provider = provider;
|
||||
this.contract = contract;
|
||||
this.address = address;
|
||||
this.onProgress = onProgress;
|
||||
this.concurrencySize = concurrencySize;
|
||||
this.blocksPerRequest = blocksPerRequest;
|
||||
@ -356,6 +460,15 @@ class BatchEventsService {
|
||||
let retries = 0;
|
||||
while (!this.shouldRetry && retries === 0 || this.shouldRetry && retries < this.retryMax) {
|
||||
try {
|
||||
if (this.address) {
|
||||
return await multiQueryFilter(
|
||||
this.address,
|
||||
this.contract,
|
||||
type,
|
||||
fromBlock,
|
||||
toBlock
|
||||
);
|
||||
}
|
||||
return await this.contract.queryFilter(type, fromBlock, toBlock);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
@ -2086,7 +2199,7 @@ class BaseEventsService {
|
||||
}
|
||||
}
|
||||
async getLatestEvents({ fromBlock }) {
|
||||
if (this.tovarishClient?.selectedRelayer && !["Deposit", "Withdrawal"].includes(this.type)) {
|
||||
if (this.tovarishClient?.selectedRelayer) {
|
||||
const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents({
|
||||
type: this.getTovarishType(),
|
||||
fromBlock
|
||||
@ -2103,8 +2216,8 @@ class BaseEventsService {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
async validateEvents({
|
||||
events,
|
||||
lastBlock,
|
||||
hasNewEvents
|
||||
newEvents,
|
||||
lastBlock
|
||||
}) {
|
||||
return void 0;
|
||||
}
|
||||
@ -2140,8 +2253,8 @@ class BaseEventsService {
|
||||
const lastBlock = newEvents.lastBlock || allEvents[allEvents.length - 1]?.blockNumber;
|
||||
const validateResult = await this.validateEvents({
|
||||
events: allEvents,
|
||||
lastBlock,
|
||||
hasNewEvents: Boolean(newEvents.events.length)
|
||||
newEvents: newEvents.events,
|
||||
lastBlock
|
||||
});
|
||||
if (savedEvents.fromCache || newEvents.events.length) {
|
||||
await this.saveEvents({ events: allEvents, lastBlock });
|
||||
@ -2220,7 +2333,7 @@ class BaseTornadoService extends BaseEventsService {
|
||||
}
|
||||
async validateEvents({
|
||||
events,
|
||||
hasNewEvents
|
||||
newEvents
|
||||
}) {
|
||||
if (events.length && this.getType() === "Deposit") {
|
||||
const depositEvents = events;
|
||||
@ -2229,7 +2342,7 @@ class BaseTornadoService extends BaseEventsService {
|
||||
const errMsg = `Deposit events invalid wants ${depositEvents.length - 1} leafIndex have ${lastEvent.leafIndex}`;
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
if (this.merkleTreeService && (!this.optionalTree || hasNewEvents)) {
|
||||
if (this.merkleTreeService && (!this.optionalTree || newEvents.length)) {
|
||||
return await this.merkleTreeService.verifyTree(depositEvents);
|
||||
}
|
||||
}
|
||||
@ -2250,7 +2363,9 @@ class BaseTornadoService extends BaseEventsService {
|
||||
lastBlock
|
||||
};
|
||||
}
|
||||
return super.getLatestEvents({ fromBlock });
|
||||
return await this.getEventsFromRpc({
|
||||
fromBlock
|
||||
});
|
||||
}
|
||||
}
|
||||
class BaseEchoService extends BaseEventsService {
|
||||
@ -10396,6 +10511,7 @@ exports.getProvider = getProvider;
|
||||
exports.getProviderWithNetId = getProviderWithNetId;
|
||||
exports.getRelayerEnsSubdomains = getRelayerEnsSubdomains;
|
||||
exports.getStatusSchema = getStatusSchema;
|
||||
exports.getSubInfo = getSubInfo;
|
||||
exports.getSupportedInstances = getSupportedInstances;
|
||||
exports.getTokenBalances = getTokenBalances;
|
||||
exports.getTovarishNetworks = getTovarishNetworks;
|
||||
@ -10415,6 +10531,7 @@ exports.loadDBEvents = loadDBEvents;
|
||||
exports.loadRemoteEvents = loadRemoteEvents;
|
||||
exports.makeLabelNodeAndParent = makeLabelNodeAndParent;
|
||||
exports.mimc = mimc;
|
||||
exports.multiQueryFilter = multiQueryFilter;
|
||||
exports.multicall = multicall;
|
||||
exports.numberFormatter = numberFormatter;
|
||||
exports.packEncryptedMessage = packEncryptedMessage;
|
||||
|
135
dist/index.mjs
vendored
135
dist/index.mjs
vendored
@ -1,4 +1,4 @@
|
||||
import { FetchRequest, JsonRpcProvider, Network, EnsPlugin, GasCostPlugin, Wallet, HDNodeWallet, VoidSigner, JsonRpcSigner, BrowserProvider, isAddress, parseEther, getAddress, AbiCoder, formatEther, namehash, dataSlice, dataLength, Interface, Contract, computeAddress, keccak256, EnsResolver, parseUnits, Transaction, Signature, MaxUint256, solidityPackedKeccak256, TypedDataEncoder, ZeroAddress } from 'ethers';
|
||||
import { isHexString, assertArgument, assert, EventLog, UndecodedEventLog, Log, FetchRequest, JsonRpcProvider, Network, EnsPlugin, GasCostPlugin, Wallet, HDNodeWallet, VoidSigner, JsonRpcSigner, BrowserProvider, isAddress, parseEther, getAddress, AbiCoder, formatEther, namehash, dataSlice, dataLength, Interface, Contract, computeAddress, keccak256, EnsResolver, parseUnits, Transaction, Signature, MaxUint256, solidityPackedKeccak256, TypedDataEncoder, ZeroAddress } from 'ethers';
|
||||
import { Tornado__factory } from '@tornado/contracts';
|
||||
import { webcrypto } from 'crypto';
|
||||
import BN from 'bn.js';
|
||||
@ -132,6 +132,107 @@ function fromContentHash(contentHash) {
|
||||
return contentHashUtils.decode(contentHash);
|
||||
}
|
||||
|
||||
function isDeferred(value) {
|
||||
return value && typeof value === "object" && "getTopicFilter" in value && typeof value.getTopicFilter === "function" && value.fragment;
|
||||
}
|
||||
async function getSubInfo(abiInterface, event) {
|
||||
let topics;
|
||||
let fragment = null;
|
||||
if (Array.isArray(event)) {
|
||||
const topicHashify = function(name) {
|
||||
if (isHexString(name, 32)) {
|
||||
return name;
|
||||
}
|
||||
const fragment2 = abiInterface.getEvent(name);
|
||||
assertArgument(fragment2, "unknown fragment", "name", name);
|
||||
return fragment2.topicHash;
|
||||
};
|
||||
topics = event.map((e) => {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(e)) {
|
||||
return e.map(topicHashify);
|
||||
}
|
||||
return topicHashify(e);
|
||||
});
|
||||
} else if (event === "*") {
|
||||
topics = [null];
|
||||
} else if (typeof event === "string") {
|
||||
if (isHexString(event, 32)) {
|
||||
topics = [event];
|
||||
} else {
|
||||
fragment = abiInterface.getEvent(event);
|
||||
assertArgument(fragment, "unknown fragment", "event", event);
|
||||
topics = [fragment.topicHash];
|
||||
}
|
||||
} else if (isDeferred(event)) {
|
||||
topics = await event.getTopicFilter();
|
||||
} else if ("fragment" in event) {
|
||||
fragment = event.fragment;
|
||||
topics = [fragment.topicHash];
|
||||
} else {
|
||||
assertArgument(false, "unknown event name", "event", event);
|
||||
}
|
||||
topics = topics.map((t) => {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(t)) {
|
||||
const items = Array.from(new Set(t.map((t2) => t2.toLowerCase())).values());
|
||||
if (items.length === 1) {
|
||||
return items[0];
|
||||
}
|
||||
items.sort();
|
||||
return items;
|
||||
}
|
||||
return t.toLowerCase();
|
||||
});
|
||||
const tag = topics.map((t) => {
|
||||
if (t == null) {
|
||||
return "null";
|
||||
}
|
||||
if (Array.isArray(t)) {
|
||||
return t.join("|");
|
||||
}
|
||||
return t;
|
||||
}).join("&");
|
||||
return { fragment, tag, topics };
|
||||
}
|
||||
async function multiQueryFilter(address, contract, event, fromBlock, toBlock) {
|
||||
if (fromBlock == null) {
|
||||
fromBlock = 0;
|
||||
}
|
||||
if (toBlock == null) {
|
||||
toBlock = "latest";
|
||||
}
|
||||
const { fragment, topics } = await getSubInfo(contract.interface, event);
|
||||
const filter = {
|
||||
address: address === "*" ? void 0 : address,
|
||||
topics,
|
||||
fromBlock,
|
||||
toBlock
|
||||
};
|
||||
const provider = contract.runner;
|
||||
assert(provider, "contract runner does not have a provider", "UNSUPPORTED_OPERATION", { operation: "queryFilter" });
|
||||
return (await provider.getLogs(filter)).map((log) => {
|
||||
let foundFragment = fragment;
|
||||
if (foundFragment == null) {
|
||||
try {
|
||||
foundFragment = contract.interface.getEvent(log.topics[0]);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
if (foundFragment) {
|
||||
try {
|
||||
return new EventLog(log, contract.interface, foundFragment);
|
||||
} catch (error) {
|
||||
return new UndecodedEventLog(log, error);
|
||||
}
|
||||
}
|
||||
return new Log(log, provider);
|
||||
});
|
||||
}
|
||||
class BatchBlockService {
|
||||
provider;
|
||||
onProgress;
|
||||
@ -304,6 +405,7 @@ class BatchTransactionService {
|
||||
class BatchEventsService {
|
||||
provider;
|
||||
contract;
|
||||
address;
|
||||
onProgress;
|
||||
concurrencySize;
|
||||
blocksPerRequest;
|
||||
@ -313,6 +415,7 @@ class BatchEventsService {
|
||||
constructor({
|
||||
provider,
|
||||
contract,
|
||||
address,
|
||||
onProgress,
|
||||
concurrencySize = 10,
|
||||
blocksPerRequest = 5e3,
|
||||
@ -322,6 +425,7 @@ class BatchEventsService {
|
||||
}) {
|
||||
this.provider = provider;
|
||||
this.contract = contract;
|
||||
this.address = address;
|
||||
this.onProgress = onProgress;
|
||||
this.concurrencySize = concurrencySize;
|
||||
this.blocksPerRequest = blocksPerRequest;
|
||||
@ -334,6 +438,15 @@ class BatchEventsService {
|
||||
let retries = 0;
|
||||
while (!this.shouldRetry && retries === 0 || this.shouldRetry && retries < this.retryMax) {
|
||||
try {
|
||||
if (this.address) {
|
||||
return await multiQueryFilter(
|
||||
this.address,
|
||||
this.contract,
|
||||
type,
|
||||
fromBlock,
|
||||
toBlock
|
||||
);
|
||||
}
|
||||
return await this.contract.queryFilter(type, fromBlock, toBlock);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
@ -2064,7 +2177,7 @@ class BaseEventsService {
|
||||
}
|
||||
}
|
||||
async getLatestEvents({ fromBlock }) {
|
||||
if (this.tovarishClient?.selectedRelayer && !["Deposit", "Withdrawal"].includes(this.type)) {
|
||||
if (this.tovarishClient?.selectedRelayer) {
|
||||
const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents({
|
||||
type: this.getTovarishType(),
|
||||
fromBlock
|
||||
@ -2081,8 +2194,8 @@ class BaseEventsService {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
async validateEvents({
|
||||
events,
|
||||
lastBlock,
|
||||
hasNewEvents
|
||||
newEvents,
|
||||
lastBlock
|
||||
}) {
|
||||
return void 0;
|
||||
}
|
||||
@ -2118,8 +2231,8 @@ class BaseEventsService {
|
||||
const lastBlock = newEvents.lastBlock || allEvents[allEvents.length - 1]?.blockNumber;
|
||||
const validateResult = await this.validateEvents({
|
||||
events: allEvents,
|
||||
lastBlock,
|
||||
hasNewEvents: Boolean(newEvents.events.length)
|
||||
newEvents: newEvents.events,
|
||||
lastBlock
|
||||
});
|
||||
if (savedEvents.fromCache || newEvents.events.length) {
|
||||
await this.saveEvents({ events: allEvents, lastBlock });
|
||||
@ -2198,7 +2311,7 @@ class BaseTornadoService extends BaseEventsService {
|
||||
}
|
||||
async validateEvents({
|
||||
events,
|
||||
hasNewEvents
|
||||
newEvents
|
||||
}) {
|
||||
if (events.length && this.getType() === "Deposit") {
|
||||
const depositEvents = events;
|
||||
@ -2207,7 +2320,7 @@ class BaseTornadoService extends BaseEventsService {
|
||||
const errMsg = `Deposit events invalid wants ${depositEvents.length - 1} leafIndex have ${lastEvent.leafIndex}`;
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
if (this.merkleTreeService && (!this.optionalTree || hasNewEvents)) {
|
||||
if (this.merkleTreeService && (!this.optionalTree || newEvents.length)) {
|
||||
return await this.merkleTreeService.verifyTree(depositEvents);
|
||||
}
|
||||
}
|
||||
@ -2228,7 +2341,9 @@ class BaseTornadoService extends BaseEventsService {
|
||||
lastBlock
|
||||
};
|
||||
}
|
||||
return super.getLatestEvents({ fromBlock });
|
||||
return await this.getEventsFromRpc({
|
||||
fromBlock
|
||||
});
|
||||
}
|
||||
}
|
||||
class BaseEchoService extends BaseEventsService {
|
||||
@ -10270,4 +10385,4 @@ async function calculateSnarkProof(input, circuit, provingKey) {
|
||||
return { proof, args };
|
||||
}
|
||||
|
||||
export { BaseEchoService, BaseEncryptedNotesService, BaseEventsService, BaseGovernanceService, BaseRegistryService, BaseRevenueService, BaseTornadoService, BatchBlockService, BatchEventsService, BatchTransactionService, DBEchoService, DBEncryptedNotesService, DBGovernanceService, DBRegistryService, DBRevenueService, DBTornadoService, Deposit, ENSNameWrapper__factory, ENSRegistry__factory, ENSResolver__factory, ENSUtils, ENS__factory, ERC20__factory, EnsContracts, INDEX_DB_ERROR, IndexedDB, Invoice, MAX_FEE, MAX_TOVARISH_EVENTS, MIN_FEE, MIN_STAKE_BALANCE, MerkleTreeService, Mimc, Multicall__factory, NetId, NoteAccount, OffchainOracle__factory, OvmGasPriceOracle__factory, Pedersen, RelayerClient, ReverseRecords__factory, TokenPriceOracle, TornadoBrowserProvider, TornadoFeeOracle, TornadoRpcSigner, TornadoVoidSigner, TornadoWallet, TovarishClient, addNetwork, addressSchemaType, ajv, base64ToBytes, bigIntReplacer, bnSchemaType, bnToBytes, buffPedersenHash, bufferToBytes, bytes32BNSchemaType, bytes32SchemaType, bytesToBN, bytesToBase64, bytesToHex, calculateScore, calculateSnarkProof, chunk, concatBytes, convertETHToTokenAmount, createDeposit, crypto, customConfig, defaultConfig, defaultUserAgent, deployHasher, depositsEventsSchema, digest, downloadZip, echoEventsSchema, enabledChains, encodedLabelToLabelhash, encryptedNotesSchema, index as factories, fetchData, fetchGetUrlFunc, fetchIp, fromContentHash, gasZipID, gasZipInbounds, gasZipInput, gasZipMinMax, getActiveTokenInstances, getActiveTokens, getConfig, getEventsSchemaValidator, getHttpAgent, getIndexedDB, getInstanceByAddress, getNetworkConfig, getPermit2CommitmentsSignature, getPermit2Signature, getPermitCommitmentsSignature, getPermitSignature, getProvider, getProviderWithNetId, getRelayerEnsSubdomains, getStatusSchema, getSupportedInstances, getTokenBalances, getTovarishNetworks, getWeightRandom, governanceEventsSchema, hasherBytecode, hexToBytes, initGroth16, isHex, isNode, jobRequestSchema, jobsSchema, labelhash, leBuff2Int, leInt2Buff, loadDBEvents, loadRemoteEvents, makeLabelNodeAndParent, mimc, multicall, numberFormatter, packEncryptedMessage, parseInvoice, parseNote, pedersen, permit2Address, pickWeightedRandomRelayer, populateTransaction, proofSchemaType, proposalState, rBigInt, rHex, relayerRegistryEventsSchema, saveDBEvents, sleep, stakeBurnedEventsSchema, substring, toContentHash, toFixedHex, toFixedLength, unpackEncryptedMessage, unzipAsync, validateUrl, withdrawalsEventsSchema, zipAsync };
|
||||
export { BaseEchoService, BaseEncryptedNotesService, BaseEventsService, BaseGovernanceService, BaseRegistryService, BaseRevenueService, BaseTornadoService, BatchBlockService, BatchEventsService, BatchTransactionService, DBEchoService, DBEncryptedNotesService, DBGovernanceService, DBRegistryService, DBRevenueService, DBTornadoService, Deposit, ENSNameWrapper__factory, ENSRegistry__factory, ENSResolver__factory, ENSUtils, ENS__factory, ERC20__factory, EnsContracts, INDEX_DB_ERROR, IndexedDB, Invoice, MAX_FEE, MAX_TOVARISH_EVENTS, MIN_FEE, MIN_STAKE_BALANCE, MerkleTreeService, Mimc, Multicall__factory, NetId, NoteAccount, OffchainOracle__factory, OvmGasPriceOracle__factory, Pedersen, RelayerClient, ReverseRecords__factory, TokenPriceOracle, TornadoBrowserProvider, TornadoFeeOracle, TornadoRpcSigner, TornadoVoidSigner, TornadoWallet, TovarishClient, addNetwork, addressSchemaType, ajv, base64ToBytes, bigIntReplacer, bnSchemaType, bnToBytes, buffPedersenHash, bufferToBytes, bytes32BNSchemaType, bytes32SchemaType, bytesToBN, bytesToBase64, bytesToHex, calculateScore, calculateSnarkProof, chunk, concatBytes, convertETHToTokenAmount, createDeposit, crypto, customConfig, defaultConfig, defaultUserAgent, deployHasher, depositsEventsSchema, digest, downloadZip, echoEventsSchema, enabledChains, encodedLabelToLabelhash, encryptedNotesSchema, index as factories, fetchData, fetchGetUrlFunc, fetchIp, fromContentHash, gasZipID, gasZipInbounds, gasZipInput, gasZipMinMax, getActiveTokenInstances, getActiveTokens, getConfig, getEventsSchemaValidator, getHttpAgent, getIndexedDB, getInstanceByAddress, getNetworkConfig, getPermit2CommitmentsSignature, getPermit2Signature, getPermitCommitmentsSignature, getPermitSignature, getProvider, getProviderWithNetId, getRelayerEnsSubdomains, getStatusSchema, getSubInfo, getSupportedInstances, getTokenBalances, getTovarishNetworks, getWeightRandom, governanceEventsSchema, hasherBytecode, hexToBytes, initGroth16, isHex, isNode, jobRequestSchema, jobsSchema, labelhash, leBuff2Int, leInt2Buff, loadDBEvents, loadRemoteEvents, makeLabelNodeAndParent, mimc, multiQueryFilter, multicall, numberFormatter, packEncryptedMessage, parseInvoice, parseNote, pedersen, permit2Address, pickWeightedRandomRelayer, populateTransaction, proofSchemaType, proposalState, rBigInt, rHex, relayerRegistryEventsSchema, saveDBEvents, sleep, stakeBurnedEventsSchema, substring, toContentHash, toFixedHex, toFixedLength, unpackEncryptedMessage, unzipAsync, validateUrl, withdrawalsEventsSchema, zipAsync };
|
||||
|
694
dist/tornado.umd.js
vendored
694
dist/tornado.umd.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/tornado.umd.min.js
vendored
2
dist/tornado.umd.min.js
vendored
File diff suppressed because one or more lines are too long
177
src/batch.ts
177
src/batch.ts
@ -1,4 +1,4 @@
|
||||
import type {
|
||||
import {
|
||||
Provider,
|
||||
BlockTag,
|
||||
Block,
|
||||
@ -7,9 +7,171 @@ import type {
|
||||
ContractEventName,
|
||||
EventLog,
|
||||
TransactionReceipt,
|
||||
isHexString,
|
||||
assert,
|
||||
assertArgument,
|
||||
DeferredTopicFilter,
|
||||
EventFragment,
|
||||
TopicFilter,
|
||||
Interface,
|
||||
UndecodedEventLog,
|
||||
Log,
|
||||
} from 'ethers';
|
||||
import { chunk, sleep } from './utils';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function isDeferred(value: any): value is DeferredTopicFilter {
|
||||
return (
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
'getTopicFilter' in value &&
|
||||
typeof value.getTopicFilter === 'function' &&
|
||||
value.fragment
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from ethers.js as they don't export this function
|
||||
* https://github.com/ethers-io/ethers.js/blob/main/src.ts/contract/contract.ts#L464
|
||||
*/
|
||||
export async function getSubInfo(
|
||||
abiInterface: Interface,
|
||||
event: ContractEventName,
|
||||
): Promise<{
|
||||
fragment: null | EventFragment;
|
||||
tag: string;
|
||||
topics: TopicFilter;
|
||||
}> {
|
||||
let topics: Array<null | string | Array<string>>;
|
||||
let fragment: null | EventFragment = null;
|
||||
|
||||
// Convert named events to topicHash and get the fragment for
|
||||
// events which need deconstructing.
|
||||
|
||||
if (Array.isArray(event)) {
|
||||
const topicHashify = function (name: string): string {
|
||||
if (isHexString(name, 32)) {
|
||||
return name;
|
||||
}
|
||||
const fragment = abiInterface.getEvent(name);
|
||||
assertArgument(fragment, 'unknown fragment', 'name', name);
|
||||
return fragment.topicHash;
|
||||
};
|
||||
|
||||
// Array of Topics and Names; e.g. `[ "0x1234...89ab", "Transfer(address)" ]`
|
||||
topics = event.map((e) => {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(e)) {
|
||||
return e.map(topicHashify);
|
||||
}
|
||||
return topicHashify(e);
|
||||
});
|
||||
} else if (event === '*') {
|
||||
topics = [null];
|
||||
} else if (typeof event === 'string') {
|
||||
if (isHexString(event, 32)) {
|
||||
// Topic Hash
|
||||
topics = [event];
|
||||
} else {
|
||||
// Name or Signature; e.g. `"Transfer", `"Transfer(address)"`
|
||||
fragment = abiInterface.getEvent(event);
|
||||
assertArgument(fragment, 'unknown fragment', 'event', event);
|
||||
topics = [fragment.topicHash];
|
||||
}
|
||||
} else if (isDeferred(event)) {
|
||||
// Deferred Topic Filter; e.g. `contract.filter.Transfer(from)`
|
||||
topics = await event.getTopicFilter();
|
||||
} else if ('fragment' in event) {
|
||||
// ContractEvent; e.g. `contract.filter.Transfer`
|
||||
fragment = event.fragment;
|
||||
topics = [fragment.topicHash];
|
||||
} else {
|
||||
assertArgument(false, 'unknown event name', 'event', event);
|
||||
}
|
||||
|
||||
// Normalize topics and sort TopicSets
|
||||
topics = topics.map((t) => {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(t)) {
|
||||
const items = Array.from(new Set(t.map((t) => t.toLowerCase())).values());
|
||||
if (items.length === 1) {
|
||||
return items[0];
|
||||
}
|
||||
items.sort();
|
||||
return items;
|
||||
}
|
||||
return t.toLowerCase();
|
||||
});
|
||||
|
||||
const tag = topics
|
||||
.map((t) => {
|
||||
if (t == null) {
|
||||
return 'null';
|
||||
}
|
||||
if (Array.isArray(t)) {
|
||||
return t.join('|');
|
||||
}
|
||||
return t;
|
||||
})
|
||||
.join('&');
|
||||
|
||||
return { fragment, tag, topics };
|
||||
}
|
||||
|
||||
export async function multiQueryFilter(
|
||||
// Single address will scan for a single contract, array for multiple, and * for all contracts with event topic
|
||||
address: string | string[],
|
||||
contract: BaseContract,
|
||||
event: ContractEventName,
|
||||
fromBlock?: BlockTag,
|
||||
toBlock?: BlockTag,
|
||||
) {
|
||||
if (fromBlock == null) {
|
||||
fromBlock = 0;
|
||||
}
|
||||
if (toBlock == null) {
|
||||
toBlock = 'latest';
|
||||
}
|
||||
|
||||
const { fragment, topics } = await getSubInfo(contract.interface, event);
|
||||
|
||||
const filter = {
|
||||
address: address === '*' ? undefined : address,
|
||||
topics,
|
||||
fromBlock,
|
||||
toBlock,
|
||||
};
|
||||
|
||||
const provider = contract.runner as Provider | null;
|
||||
|
||||
assert(provider, 'contract runner does not have a provider', 'UNSUPPORTED_OPERATION', { operation: 'queryFilter' });
|
||||
|
||||
return (await provider.getLogs(filter)).map((log) => {
|
||||
let foundFragment = fragment;
|
||||
if (foundFragment == null) {
|
||||
try {
|
||||
foundFragment = contract.interface.getEvent(log.topics[0]);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (foundFragment) {
|
||||
try {
|
||||
return new EventLog(log, contract.interface, foundFragment);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
return new UndecodedEventLog(log, error);
|
||||
}
|
||||
}
|
||||
|
||||
return new Log(log, provider);
|
||||
});
|
||||
}
|
||||
|
||||
export interface BatchBlockServiceConstructor {
|
||||
provider: Provider;
|
||||
onProgress?: BatchBlockOnProgress;
|
||||
@ -260,6 +422,7 @@ export class BatchTransactionService {
|
||||
export interface BatchEventServiceConstructor {
|
||||
provider: Provider;
|
||||
contract: BaseContract;
|
||||
address?: string | string[];
|
||||
onProgress?: BatchEventOnProgress;
|
||||
concurrencySize?: number;
|
||||
blocksPerRequest?: number;
|
||||
@ -295,6 +458,7 @@ export interface EventInput {
|
||||
export class BatchEventsService {
|
||||
provider: Provider;
|
||||
contract: BaseContract;
|
||||
address?: string | string[];
|
||||
onProgress?: BatchEventOnProgress;
|
||||
concurrencySize: number;
|
||||
blocksPerRequest: number;
|
||||
@ -304,6 +468,7 @@ export class BatchEventsService {
|
||||
constructor({
|
||||
provider,
|
||||
contract,
|
||||
address,
|
||||
onProgress,
|
||||
concurrencySize = 10,
|
||||
blocksPerRequest = 5000,
|
||||
@ -313,6 +478,7 @@ export class BatchEventsService {
|
||||
}: BatchEventServiceConstructor) {
|
||||
this.provider = provider;
|
||||
this.contract = contract;
|
||||
this.address = address;
|
||||
this.onProgress = onProgress;
|
||||
this.concurrencySize = concurrencySize;
|
||||
this.blocksPerRequest = blocksPerRequest;
|
||||
@ -328,6 +494,15 @@ export class BatchEventsService {
|
||||
// eslint-disable-next-line no-unmodified-loop-condition
|
||||
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
|
||||
try {
|
||||
if (this.address) {
|
||||
return (await multiQueryFilter(
|
||||
this.address,
|
||||
this.contract,
|
||||
type,
|
||||
fromBlock,
|
||||
toBlock,
|
||||
)) as EventLog[];
|
||||
}
|
||||
return (await this.contract.queryFilter(type, fromBlock, toBlock)) as EventLog[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
|
@ -205,7 +205,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
||||
}
|
||||
|
||||
async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EventType>> {
|
||||
if (this.tovarishClient?.selectedRelayer && !['Deposit', 'Withdrawal'].includes(this.type)) {
|
||||
if (this.tovarishClient?.selectedRelayer) {
|
||||
const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents<EventType>({
|
||||
type: this.getTovarishType(),
|
||||
fromBlock,
|
||||
@ -225,9 +225,9 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
async validateEvents<S>({
|
||||
events,
|
||||
newEvents,
|
||||
lastBlock,
|
||||
hasNewEvents,
|
||||
}: BaseEvents<EventType> & { hasNewEvents?: boolean }): Promise<S> {
|
||||
}: BaseEvents<EventType> & { newEvents: EventType[] }): Promise<S> {
|
||||
return undefined as S;
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
@ -274,8 +274,8 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
||||
|
||||
const validateResult = await this.validateEvents<S>({
|
||||
events: allEvents,
|
||||
newEvents: newEvents.events,
|
||||
lastBlock,
|
||||
hasNewEvents: Boolean(newEvents.events.length),
|
||||
});
|
||||
|
||||
// If the events are loaded from cache or we have found new events, save them
|
||||
@ -380,9 +380,9 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
|
||||
|
||||
async validateEvents<S>({
|
||||
events,
|
||||
hasNewEvents,
|
||||
newEvents,
|
||||
}: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
|
||||
hasNewEvents?: boolean;
|
||||
newEvents: (DepositsEvents | WithdrawalsEvents)[];
|
||||
}) {
|
||||
if (events.length && this.getType() === 'Deposit') {
|
||||
const depositEvents = events as DepositsEvents[];
|
||||
@ -394,7 +394,7 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
||||
if (this.merkleTreeService && (!this.optionalTree || hasNewEvents)) {
|
||||
if (this.merkleTreeService && (!this.optionalTree || newEvents.length)) {
|
||||
return (await this.merkleTreeService.verifyTree(depositEvents)) as S;
|
||||
}
|
||||
}
|
||||
@ -423,7 +423,9 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
|
||||
};
|
||||
}
|
||||
|
||||
return super.getLatestEvents({ fromBlock });
|
||||
return await this.getEventsFromRpc({
|
||||
fromBlock,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user