Compare commits

..

1 Commits

43 changed files with 1792 additions and 4225 deletions

View File

@ -33,6 +33,7 @@ module.exports = {
'error', 'error',
{ {
tabWidth: 4, tabWidth: 4,
printWidth: 120,
singleQuote: true, singleQuote: true,
}, },
], ],

4
dist/batch.d.ts vendored
View File

@ -80,7 +80,7 @@ export declare class BatchEventsService {
retryMax: number; retryMax: number;
retryOn: number; retryOn: number;
constructor({ provider, contract, onProgress, concurrencySize, blocksPerRequest, shouldRetry, retryMax, retryOn, }: BatchEventServiceConstructor); constructor({ provider, contract, onProgress, concurrencySize, blocksPerRequest, shouldRetry, retryMax, retryOn, }: BatchEventServiceConstructor);
getPastEvents({ fromBlock, toBlock, type, }: EventInput): Promise<EventLog[]>; getPastEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]>;
createBatchRequest(batchArray: EventInput[]): Promise<EventLog[]>[]; createBatchRequest(batchArray: EventInput[]): Promise<EventLog[]>[];
getBatchEvents({ fromBlock, toBlock, type, }: EventInput): Promise<EventLog[]>; getBatchEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]>;
} }

4
dist/deposits.d.ts vendored
View File

@ -30,7 +30,7 @@ export interface parsedInvoiceExec extends DepositType {
} }
export declare function parseNote(noteString: string): parsedNoteExec | undefined; export declare function parseNote(noteString: string): parsedNoteExec | undefined;
export declare function parseInvoice(invoiceString: string): parsedInvoiceExec | undefined; export declare function parseInvoice(invoiceString: string): parsedInvoiceExec | undefined;
export declare function createDeposit({ nullifier, secret, }: createDepositParams): Promise<createDepositObject>; export declare function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject>;
export interface DepositConstructor { export interface DepositConstructor {
currency: string; currency: string;
amount: string; amount: string;
@ -56,7 +56,7 @@ export declare class Deposit {
nullifierHex: string; nullifierHex: string;
constructor({ currency, amount, netId, nullifier, secret, note, noteHex, invoice, commitmentHex, nullifierHex, }: DepositConstructor); constructor({ currency, amount, netId, nullifier, secret, note, noteHex, invoice, commitmentHex, nullifierHex, }: DepositConstructor);
toString(): string; toString(): string;
static createNote({ currency, amount, netId, nullifier, secret, }: createNoteParams): Promise<Deposit>; static createNote({ currency, amount, netId, nullifier, secret }: createNoteParams): Promise<Deposit>;
static parseNote(noteString: string): Promise<Deposit>; static parseNote(noteString: string): Promise<Deposit>;
} }
export declare class Invoice { export declare class Invoice {

View File

@ -10,7 +10,7 @@ export interface DecryptedNotes {
address: string; address: string;
noteHex: string; noteHex: string;
} }
export declare function packEncryptedMessage({ nonce, ephemPublicKey, ciphertext, }: EthEncryptedData): string; export declare function packEncryptedMessage({ nonce, ephemPublicKey, ciphertext }: EthEncryptedData): string;
export declare function unpackEncryptedMessage(encryptedMessage: string): EthEncryptedData & { export declare function unpackEncryptedMessage(encryptedMessage: string): EthEncryptedData & {
messageBuff: string; messageBuff: string;
}; };

14
dist/events/base.d.ts vendored
View File

@ -50,10 +50,10 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
getTovarishType(): string; getTovarishType(): string;
getGraphMethod(): string; getGraphMethod(): string;
getGraphParams(): BaseGraphParams; getGraphParams(): BaseGraphParams;
updateEventProgress({ percentage, type, fromBlock, toBlock, count, }: Parameters<BatchEventOnProgress>[0]): void; updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateBlockProgress({ percentage, currentIndex, totalIndex, }: Parameters<BatchBlockOnProgress>[0]): void; updateBlockProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateTransactionProgress({ percentage, currentIndex, totalIndex, }: Parameters<BatchBlockOnProgress>[0]): void; updateTransactionProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count, }: Parameters<BatchGraphOnProgress>[0]): void; updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchGraphOnProgress>[0]): void;
formatEvents(events: EventLog[]): Promise<EventType[]>; formatEvents(events: EventLog[]): Promise<EventType[]>;
/** /**
* Get saved or cached events * Get saved or cached events
@ -75,7 +75,7 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
fromBlock: number; fromBlock: number;
toBlock?: number; toBlock?: number;
}): Promise<BaseEvents<EventType>>; }): Promise<BaseEvents<EventType>>;
getLatestEvents({ fromBlock, }: { getLatestEvents({ fromBlock }: {
fromBlock: number; fromBlock: number;
}): Promise<BaseEvents<EventType>>; }): Promise<BaseEvents<EventType>>;
validateEvents<S>({ events, lastBlock, hasNewEvents, }: BaseEvents<EventType> & { validateEvents<S>({ events, lastBlock, hasNewEvents, }: BaseEvents<EventType> & {
@ -132,7 +132,7 @@ export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
getInstanceName(): string; getInstanceName(): string;
getGraphMethod(): string; getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<EchoEvents[]>; formatEvents(events: EventLog[]): Promise<EchoEvents[]>;
getEventsFromGraph({ fromBlock, }: { getEventsFromGraph({ fromBlock }: {
fromBlock: number; fromBlock: number;
}): Promise<BaseEvents<EchoEvents>>; }): Promise<BaseEvents<EchoEvents>>;
} }
@ -180,7 +180,7 @@ export declare class BaseGovernanceService extends BaseEventsService<AllGovernan
getTovarishType(): string; getTovarishType(): string;
getGraphMethod(): string; getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>; formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
getEventsFromGraph({ fromBlock, }: { getEventsFromGraph({ fromBlock }: {
fromBlock: number; fromBlock: number;
}): Promise<BaseEvents<AllGovernanceEvents>>; }): Promise<BaseEvents<AllGovernanceEvents>>;
getAllProposals(): Promise<GovernanceProposals[]>; getAllProposals(): Promise<GovernanceProposals[]>;

2
dist/events/db.d.ts vendored
View File

@ -28,7 +28,7 @@ export declare class DBTornadoService extends BaseTornadoService {
constructor(params: DBTornadoServiceConstructor); constructor(params: DBTornadoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>; getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
getEventsFromCache(): Promise<CachedEvents<DepositsEvents | WithdrawalsEvents>>; getEventsFromCache(): Promise<CachedEvents<DepositsEvents | WithdrawalsEvents>>;
saveEvents({ events, lastBlock, }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>;
} }
export interface DBEchoServiceConstructor extends BaseEchoServiceConstructor { export interface DBEchoServiceConstructor extends BaseEchoServiceConstructor {
staticUrl: string; staticUrl: string;

View File

@ -57,7 +57,7 @@ export interface getMetaReturns {
lastSyncBlock: null | number; lastSyncBlock: null | number;
hasIndexingErrors: null | boolean; hasIndexingErrors: null | boolean;
} }
export declare function getMeta({ graphApi, subgraphName, fetchDataOptions, }: getMetaParams): Promise<getMetaReturns>; export declare function getMeta({ graphApi, subgraphName, fetchDataOptions }: getMetaParams): Promise<getMetaReturns>;
export interface GraphRegisters { export interface GraphRegisters {
relayers: { relayers: {
id: string; id: string;

8
dist/idb.d.ts vendored
View File

@ -35,16 +35,16 @@ export declare class IndexedDB {
key?: string; key?: string;
count?: number; count?: number;
}): Promise<T>; }): Promise<T>;
getItem<T>({ storeName, key, }: { getItem<T>({ storeName, key }: {
storeName: string; storeName: string;
key: string; key: string;
}): Promise<T | undefined>; }): Promise<T | undefined>;
addItem({ storeName, data, key, }: { addItem({ storeName, data, key }: {
storeName: string; storeName: string;
data: any; data: any;
key: string; key: string;
}): Promise<void>; }): Promise<void>;
putItem({ storeName, data, key, }: { putItem({ storeName, data, key }: {
storeName: string; storeName: string;
data: any; data: any;
key?: string; key?: string;
@ -62,7 +62,7 @@ export declare class IndexedDB {
getValue<T>(key: string): Promise<T | undefined>; getValue<T>(key: string): Promise<T | undefined>;
setValue(key: string, data: any): Promise<void>; setValue(key: string, data: any): Promise<void>;
delValue(key: string): Promise<void>; delValue(key: string): Promise<void>;
clearStore({ storeName, mode, }: { clearStore({ storeName, mode }: {
storeName: string; storeName: string;
mode: IDBTransactionMode; mode: IDBTransactionMode;
}): Promise<void>; }): Promise<void>;

880
dist/index.js vendored

File diff suppressed because it is too large Load Diff

880
dist/index.mjs vendored

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ export declare class MerkleTreeService {
merkleWorkerPath?: string; merkleWorkerPath?: string;
constructor({ netId, amount, currency, Tornado, commitmentHex, merkleTreeHeight, emptyElement, merkleWorkerPath, }: MerkleTreeConstructor); constructor({ netId, amount, currency, Tornado, commitmentHex, merkleTreeHeight, emptyElement, merkleWorkerPath, }: MerkleTreeConstructor);
createTree(events: Element[]): Promise<MerkleTree>; createTree(events: Element[]): Promise<MerkleTree>;
createPartialTree({ edge, elements, }: { createPartialTree({ edge, elements }: {
edge: TreeEdge; edge: TreeEdge;
elements: Element[]; elements: Element[];
}): Promise<PartialMerkleTree>; }): Promise<PartialMerkleTree>;

View File

@ -1814,9 +1814,7 @@ class Mimc {
} }
async initMimc() { async initMimc() {
this.sponge = await buildMimcSponge(); this.sponge = await buildMimcSponge();
this.hash = (left, right) => this.sponge?.F.toString( this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
this.sponge?.multiHash([BigInt(left), BigInt(right)])
);
} }
async getHash() { async getHash() {
await this.mimcPromise; await this.mimcPromise;
@ -1837,27 +1835,18 @@ async function nodePostWork() {
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData; const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData;
if (edge) { if (edge) {
const merkleTree2 = new libExports.PartialMerkleTree( const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, {
merkleTreeHeight,
edge,
elements,
{
zeroElement, zeroElement,
hashFunction hashFunction
} });
); workerThreads.parentPort.postMessage(merkleTree2.toString());
workerThreads.parentPort.postMessage(
merkleTree2.toString()
);
return; return;
} }
const merkleTree = new libExports.MerkleTree(merkleTreeHeight, elements, { const merkleTree = new libExports.MerkleTree(merkleTreeHeight, elements, {
zeroElement, zeroElement,
hashFunction hashFunction
}); });
workerThreads.parentPort.postMessage( workerThreads.parentPort.postMessage(merkleTree.toString());
merkleTree.toString()
);
} }
if (isNode && workerThreads) { if (isNode && workerThreads) {
nodePostWork(); nodePostWork();
@ -1872,15 +1861,10 @@ if (isNode && workerThreads) {
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = data; const { merkleTreeHeight, edge, elements, zeroElement } = data;
if (edge) { if (edge) {
const merkleTree2 = new libExports.PartialMerkleTree( const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, {
merkleTreeHeight,
edge,
elements,
{
zeroElement, zeroElement,
hashFunction hashFunction
} });
);
postMessage(merkleTree2.toString()); postMessage(merkleTree2.toString());
return; return;
} }

View File

@ -101986,9 +101986,7 @@ class Mimc {
} }
async initMimc() { async initMimc() {
this.sponge = await mimcsponge_buildMimcSponge(); this.sponge = await mimcsponge_buildMimcSponge();
this.hash = (left, right) => this.sponge?.F.toString( this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
this.sponge?.multiHash([BigInt(left), BigInt(right)])
);
} }
async getHash() { async getHash() {
await this.mimcPromise; await this.mimcPromise;
@ -102013,9 +102011,7 @@ BigInt.prototype.toJSON = function() {
}; };
const isNode = !process.browser && typeof globalThis.window === "undefined"; const isNode = !process.browser && typeof globalThis.window === "undefined";
const utils_crypto = isNode ? crypto_browserify.webcrypto : globalThis.crypto; const utils_crypto = isNode ? crypto_browserify.webcrypto : globalThis.crypto;
const chunk = (arr, size) => [...Array(Math.ceil(arr.length / size))].map( const chunk = (arr, size) => [...Array(Math.ceil(arr.length / size))].map((_, i) => arr.slice(size * i, size + size * i));
(_, i) => arr.slice(size * i, size + size * i)
);
function utils_sleep(ms) { function utils_sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
@ -102043,9 +102039,7 @@ function bufferToBytes(b) {
return new Uint8Array(b.buffer); return new Uint8Array(b.buffer);
} }
function bytesToBase64(bytes) { function bytesToBase64(bytes) {
return btoa( return btoa(bytes.reduce((data, byte) => data + String.fromCharCode(byte), ""));
bytes.reduce((data, byte) => data + String.fromCharCode(byte), "")
);
} }
function base64ToBytes(base64) { function base64ToBytes(base64) {
return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)); return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
@ -102060,11 +102054,7 @@ function hexToBytes(hexString) {
if (hexString.length % 2 !== 0) { if (hexString.length % 2 !== 0) {
hexString = "0" + hexString; hexString = "0" + hexString;
} }
return Uint8Array.from( return Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
hexString.match(/.{1,2}/g).map(
(byte) => parseInt(byte, 16)
)
);
} }
function bytesToBN(bytes) { function bytesToBN(bytes) {
return BigInt(bytesToHex(bytes)); return BigInt(bytesToHex(bytes));
@ -102077,11 +102067,7 @@ function bnToBytes(bigint) {
if (hexString.length % 2 !== 0) { if (hexString.length % 2 !== 0) {
hexString = "0" + hexString; hexString = "0" + hexString;
} }
return Uint8Array.from( return Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
hexString.match(/.{1,2}/g).map(
(byte) => parseInt(byte, 16)
)
);
} }
function leBuff2Int(bytes) { function leBuff2Int(bytes) {
return new BN(bytes, 16, "le"); return new BN(bytes, 16, "le");
@ -102142,27 +102128,18 @@ async function nodePostWork() {
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = (worker_threads_ignored_default()).workerData; const { merkleTreeHeight, edge, elements, zeroElement } = (worker_threads_ignored_default()).workerData;
if (edge) { if (edge) {
const merkleTree2 = new lib.PartialMerkleTree( const merkleTree2 = new lib.PartialMerkleTree(merkleTreeHeight, edge, elements, {
merkleTreeHeight,
edge,
elements,
{
zeroElement, zeroElement,
hashFunction hashFunction
} });
); worker_threads_ignored_default().parentPort.postMessage(merkleTree2.toString());
worker_threads_ignored_default().parentPort.postMessage(
merkleTree2.toString()
);
return; return;
} }
const merkleTree = new lib.MerkleTree(merkleTreeHeight, elements, { const merkleTree = new lib.MerkleTree(merkleTreeHeight, elements, {
zeroElement, zeroElement,
hashFunction hashFunction
}); });
worker_threads_ignored_default().parentPort.postMessage( worker_threads_ignored_default().parentPort.postMessage(merkleTree.toString());
merkleTree.toString()
);
} }
if (isNode && (worker_threads_ignored_default())) { if (isNode && (worker_threads_ignored_default())) {
nodePostWork(); nodePostWork();
@ -102177,15 +102154,10 @@ if (isNode && (worker_threads_ignored_default())) {
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = data; const { merkleTreeHeight, edge, elements, zeroElement } = data;
if (edge) { if (edge) {
const merkleTree2 = new lib.PartialMerkleTree( const merkleTree2 = new lib.PartialMerkleTree(merkleTreeHeight, edge, elements, {
merkleTreeHeight,
edge,
elements,
{
zeroElement, zeroElement,
hashFunction hashFunction
} });
);
postMessage(merkleTree2.toString()); postMessage(merkleTree2.toString());
return; return;
} }

6
dist/providers.d.ts vendored
View File

@ -50,7 +50,7 @@ export declare class TornadoWallet extends Wallet {
gasLimitBump: number; gasLimitBump: number;
gasFailover: boolean; gasFailover: boolean;
bumpNonce: boolean; bumpNonce: boolean;
constructor(key: string | SigningKey, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, }?: TornadoWalletOptions); constructor(key: string | SigningKey, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
static fromMnemonic(mneomnic: string, provider: Provider, index?: number, options?: TornadoWalletOptions): TornadoWallet; static fromMnemonic(mneomnic: string, provider: Provider, index?: number, options?: TornadoWalletOptions): TornadoWallet;
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>; populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
} }
@ -60,7 +60,7 @@ export declare class TornadoVoidSigner extends VoidSigner {
gasLimitBump: number; gasLimitBump: number;
gasFailover: boolean; gasFailover: boolean;
bumpNonce: boolean; bumpNonce: boolean;
constructor(address: string, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, }?: TornadoWalletOptions); constructor(address: string, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>; populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
} }
export declare class TornadoRpcSigner extends JsonRpcSigner { export declare class TornadoRpcSigner extends JsonRpcSigner {
@ -69,7 +69,7 @@ export declare class TornadoRpcSigner extends JsonRpcSigner {
gasLimitBump: number; gasLimitBump: number;
gasFailover: boolean; gasFailover: boolean;
bumpNonce: boolean; bumpNonce: boolean;
constructor(provider: JsonRpcApiProvider, address: string, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, }?: TornadoWalletOptions); constructor(provider: JsonRpcApiProvider, address: string, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
sendUncheckedTransaction(tx: TransactionRequest): Promise<string>; sendUncheckedTransaction(tx: TransactionRequest): Promise<string>;
} }
export type connectWalletFunc = (...args: any[]) => Promise<void>; export type connectWalletFunc = (...args: any[]) => Promise<void>;

View File

@ -109,7 +109,7 @@ export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
} }
**/ **/
export declare function calculateScore({ stakeBalance, tornadoServiceFee, }: RelayerInfo): bigint; export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo): bigint;
export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number; export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number;
export interface RelayerInstanceList { export interface RelayerInstanceList {
[key: string]: { [key: string]: {

880
dist/tornado.umd.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,4 @@
import type { import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog } from 'ethers';
Provider,
BlockTag,
Block,
TransactionResponse,
BaseContract,
ContractEventName,
EventLog,
} from 'ethers';
import { chunk, sleep } from './utils'; import { chunk, sleep } from './utils';
export interface BatchBlockServiceConstructor { export interface BatchBlockServiceConstructor {
@ -80,14 +72,9 @@ export class BatchBlockService {
let err; let err;
// eslint-disable-next-line no-unmodified-loop-condition // eslint-disable-next-line no-unmodified-loop-condition
while ( while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
(!this.shouldRetry && retries === 0) ||
(this.shouldRetry && retries < this.retryMax)
) {
try { try {
return await Promise.all( return await Promise.all(blocks.map((b) => this.getBlock(b)));
blocks.map((b) => this.getBlock(b)),
);
} catch (e) { } catch (e) {
retries++; retries++;
err = e; err = e;
@ -106,15 +93,8 @@ export class BatchBlockService {
let blockCount = 0; let blockCount = 0;
const results: Block[] = []; const results: Block[] = [];
for (const chunks of chunk( for (const chunks of chunk(blocks, this.concurrencySize * this.batchSize)) {
blocks, const chunksResult = (await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))).flat();
this.concurrencySize * this.batchSize,
)) {
const chunksResult = (
await Promise.all(
this.createBatchRequest(chunk(chunks, this.batchSize)),
)
).flat();
results.push(...chunksResult); results.push(...chunksResult);
@ -173,9 +153,7 @@ export class BatchTransactionService {
return txObject; return txObject;
} }
createBatchRequest( createBatchRequest(batchArray: string[][]): Promise<TransactionResponse[]>[] {
batchArray: string[][],
): Promise<TransactionResponse[]>[] {
return batchArray.map(async (txs: string[], index: number) => { return batchArray.map(async (txs: string[], index: number) => {
await sleep(20 * index); await sleep(20 * index);
@ -184,14 +162,9 @@ export class BatchTransactionService {
let err; let err;
// eslint-disable-next-line no-unmodified-loop-condition // eslint-disable-next-line no-unmodified-loop-condition
while ( while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
(!this.shouldRetry && retries === 0) ||
(this.shouldRetry && retries < this.retryMax)
) {
try { try {
return await Promise.all( return await Promise.all(txs.map((tx) => this.getTransaction(tx)));
txs.map((tx) => this.getTransaction(tx)),
);
} catch (e) { } catch (e) {
retries++; retries++;
err = e; err = e;
@ -210,15 +183,8 @@ export class BatchTransactionService {
let txCount = 0; let txCount = 0;
const results = []; const results = [];
for (const chunks of chunk( for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) {
txs, const chunksResult = (await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))).flat();
this.concurrencySize * this.batchSize,
)) {
const chunksResult = (
await Promise.all(
this.createBatchRequest(chunk(chunks, this.batchSize)),
)
).flat();
results.push(...chunksResult); results.push(...chunksResult);
@ -301,25 +267,14 @@ export class BatchEventsService {
this.retryOn = retryOn; this.retryOn = retryOn;
} }
async getPastEvents({ async getPastEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]> {
fromBlock,
toBlock,
type,
}: EventInput): Promise<EventLog[]> {
let err; let err;
let retries = 0; let retries = 0;
// eslint-disable-next-line no-unmodified-loop-condition // eslint-disable-next-line no-unmodified-loop-condition
while ( while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
(!this.shouldRetry && retries === 0) ||
(this.shouldRetry && retries < this.retryMax)
) {
try { try {
return (await this.contract.queryFilter( return (await this.contract.queryFilter(type, fromBlock, toBlock)) as EventLog[];
type,
fromBlock,
toBlock,
)) as EventLog[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) { } catch (e: any) {
err = e; err = e;
@ -328,9 +283,7 @@ export class BatchEventsService {
// If provider.getBlockNumber returned last block that isn't accepted (happened on Avalanche/Gnosis), // If provider.getBlockNumber returned last block that isn't accepted (happened on Avalanche/Gnosis),
// get events to last accepted block // get events to last accepted block
if (e.message.includes('after last accepted block')) { if (e.message.includes('after last accepted block')) {
const acceptedBlock = parseInt( const acceptedBlock = parseInt(e.message.split('after last accepted block ')[1]);
e.message.split('after last accepted block ')[1],
);
toBlock = acceptedBlock; toBlock = acceptedBlock;
} }
@ -350,11 +303,7 @@ export class BatchEventsService {
}); });
} }
async getBatchEvents({ async getBatchEvents({ fromBlock, toBlock, type = '*' }: EventInput): Promise<EventLog[]> {
fromBlock,
toBlock,
type = '*',
}: EventInput): Promise<EventLog[]> {
if (!toBlock) { if (!toBlock) {
toBlock = await this.provider.getBlockNumber(); toBlock = await this.provider.getBlockNumber();
} }
@ -362,10 +311,7 @@ export class BatchEventsService {
const eventsToSync = []; const eventsToSync = [];
for (let i = fromBlock; i < toBlock; i += this.blocksPerRequest) { for (let i = fromBlock; i < toBlock; i += this.blocksPerRequest) {
const j = const j = i + this.blocksPerRequest - 1 > toBlock ? toBlock : i + this.blocksPerRequest - 1;
i + this.blocksPerRequest - 1 > toBlock
? toBlock
: i + this.blocksPerRequest - 1;
eventsToSync.push({ fromBlock: i, toBlock: j, type }); eventsToSync.push({ fromBlock: i, toBlock: j, type });
} }
@ -378,9 +324,7 @@ export class BatchEventsService {
for (const chunk of eventChunk) { for (const chunk of eventChunk) {
chunkCount++; chunkCount++;
const fetchedEvents = ( const fetchedEvents = (await Promise.all(this.createBatchRequest(chunk))).flat();
await Promise.all(this.createBatchRequest(chunk))
).flat();
events.push(...fetchedEvents); events.push(...fetchedEvents);
if (typeof this.onProgress === 'function') { if (typeof this.onProgress === 'function') {

View File

@ -1,11 +1,4 @@
import { import { bnToBytes, bytesToBN, leBuff2Int, leInt2Buff, rBigInt, toFixedHex } from './utils';
bnToBytes,
bytesToBN,
leBuff2Int,
leInt2Buff,
rBigInt,
toFixedHex,
} from './utils';
import { buffPedersenHash } from './pedersen'; import { buffPedersenHash } from './pedersen';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
@ -45,15 +38,13 @@ export interface parsedInvoiceExec extends DepositType {
} }
export function parseNote(noteString: string): parsedNoteExec | undefined { export function parseNote(noteString: string): parsedNoteExec | undefined {
const noteRegex = const noteRegex = /tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<noteHex>[0-9a-fA-F]{124})/g;
/tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<noteHex>[0-9a-fA-F]{124})/g;
const match = noteRegex.exec(noteString); const match = noteRegex.exec(noteString);
if (!match) { if (!match) {
return; return;
} }
const { currency, amount, netId, noteHex } = const { currency, amount, netId, noteHex } = match.groups as unknown as parsedNoteExec;
match.groups as unknown as parsedNoteExec;
return { return {
currency: currency.toLowerCase(), currency: currency.toLowerCase(),
@ -64,9 +55,7 @@ export function parseNote(noteString: string): parsedNoteExec | undefined {
}; };
} }
export function parseInvoice( export function parseInvoice(invoiceString: string): parsedInvoiceExec | undefined {
invoiceString: string,
): parsedInvoiceExec | undefined {
const invoiceRegex = const invoiceRegex =
/tornadoInvoice-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<commitmentHex>[0-9a-fA-F]{64})/g; /tornadoInvoice-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<commitmentHex>[0-9a-fA-F]{64})/g;
const match = invoiceRegex.exec(invoiceString); const match = invoiceRegex.exec(invoiceString);
@ -74,8 +63,7 @@ export function parseInvoice(
return; return;
} }
const { currency, amount, netId, commitmentHex } = const { currency, amount, netId, commitmentHex } = match.groups as unknown as parsedInvoiceExec;
match.groups as unknown as parsedInvoiceExec;
return { return {
currency: currency.toLowerCase(), currency: currency.toLowerCase(),
@ -86,14 +74,8 @@ export function parseInvoice(
}; };
} }
export async function createDeposit({ export async function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject> {
nullifier, const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]);
secret,
}: createDepositParams): Promise<createDepositObject> {
const preimage = new Uint8Array([
...leInt2Buff(nullifier),
...leInt2Buff(secret),
]);
const noteHex = toFixedHex(bytesToBN(preimage), 62); const noteHex = toFixedHex(bytesToBN(preimage), 62);
const commitment = BigInt(await buffPedersenHash(preimage)); const commitment = BigInt(await buffPedersenHash(preimage));
const commitmentHex = toFixedHex(commitment); const commitmentHex = toFixedHex(commitment);
@ -184,13 +166,7 @@ export class Deposit {
); );
} }
static async createNote({ static async createNote({ currency, amount, netId, nullifier, secret }: createNoteParams): Promise<Deposit> {
currency,
amount,
netId,
nullifier,
secret,
}: createNoteParams): Promise<Deposit> {
if (!nullifier) { if (!nullifier) {
nullifier = rBigInt(31); nullifier = rBigInt(31);
} }
@ -226,13 +202,7 @@ export class Deposit {
throw new Error('The note has invalid format'); throw new Error('The note has invalid format');
} }
const { const { currency, amount, netId, note, noteHex: parsedNoteHex } = parsedNote;
currency,
amount,
netId,
note,
noteHex: parsedNoteHex,
} = parsedNote;
const bytes = bnToBytes(parsedNoteHex); const bytes = bnToBytes(parsedNoteHex);
const nullifier = BigInt(leBuff2Int(bytes.slice(0, 31)).toString()); const nullifier = BigInt(leBuff2Int(bytes.slice(0, 31)).toString());
@ -276,8 +246,7 @@ export class Invoice {
throw new Error('The invoice has invalid format'); throw new Error('The invoice has invalid format');
} }
const { currency, amount, netId, invoice, commitmentHex } = const { currency, amount, netId, invoice, commitmentHex } = parsedInvoice;
parsedInvoice;
this.currency = currency; this.currency = currency;
this.amount = amount; this.amount = amount;

View File

@ -1,25 +1,6 @@
import { import { getEncryptionPublicKey, encrypt, decrypt, EthEncryptedData } from '@metamask/eth-sig-util';
getEncryptionPublicKey, import { JsonRpcApiProvider, Signer, Wallet, computeAddress, getAddress } from 'ethers';
encrypt, import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, toFixedHex, concatBytes, rHex } from './utils';
decrypt,
EthEncryptedData,
} from '@metamask/eth-sig-util';
import {
JsonRpcApiProvider,
Signer,
Wallet,
computeAddress,
getAddress,
} from 'ethers';
import {
base64ToBytes,
bytesToBase64,
bytesToHex,
hexToBytes,
toFixedHex,
concatBytes,
rHex,
} from './utils';
import { EchoEvents, EncryptedNotesEvents } from './events'; import { EchoEvents, EncryptedNotesEvents } from './events';
export interface NoteToEncrypt { export interface NoteToEncrypt {
@ -33,23 +14,12 @@ export interface DecryptedNotes {
noteHex: string; noteHex: string;
} }
export function packEncryptedMessage({ export function packEncryptedMessage({ nonce, ephemPublicKey, ciphertext }: EthEncryptedData) {
nonce,
ephemPublicKey,
ciphertext,
}: EthEncryptedData) {
const nonceBuf = toFixedHex(bytesToHex(base64ToBytes(nonce)), 24); const nonceBuf = toFixedHex(bytesToHex(base64ToBytes(nonce)), 24);
const ephemPublicKeyBuf = toFixedHex( const ephemPublicKeyBuf = toFixedHex(bytesToHex(base64ToBytes(ephemPublicKey)), 32);
bytesToHex(base64ToBytes(ephemPublicKey)),
32,
);
const ciphertextBuf = bytesToHex(base64ToBytes(ciphertext)); const ciphertextBuf = bytesToHex(base64ToBytes(ciphertext));
const messageBuff = concatBytes( const messageBuff = concatBytes(hexToBytes(nonceBuf), hexToBytes(ephemPublicKeyBuf), hexToBytes(ciphertextBuf));
hexToBytes(nonceBuf),
hexToBytes(ephemPublicKeyBuf),
hexToBytes(ciphertextBuf),
);
return bytesToHex(messageBuff); return bytesToHex(messageBuff);
} }
@ -105,10 +75,7 @@ export class NoteAccount {
static async getSignerPublicKey(signer: Signer | Wallet) { static async getSignerPublicKey(signer: Signer | Wallet) {
if ((signer as Wallet).privateKey) { if ((signer as Wallet).privateKey) {
const wallet = signer as Wallet; const wallet = signer as Wallet;
const privateKey = const privateKey = wallet.privateKey.slice(0, 2) === '0x' ? wallet.privateKey.slice(2) : wallet.privateKey;
wallet.privateKey.slice(0, 2) === '0x'
? wallet.privateKey.slice(2)
: wallet.privateKey;
// Should return base64 encoded public key // Should return base64 encoded public key
return getEncryptionPublicKey(privateKey); return getEncryptionPublicKey(privateKey);
@ -146,13 +113,8 @@ export class NoteAccount {
/** /**
* Decrypt Echoer backuped note encryption account with private keys * Decrypt Echoer backuped note encryption account with private keys
*/ */
static async decryptSignerNoteAccounts( static async decryptSignerNoteAccounts(signer: Signer | Wallet, events: EchoEvents[]): Promise<NoteAccount[]> {
signer: Signer | Wallet, const signerAddress = (signer as (Signer & { address: string }) | Wallet).address;
events: EchoEvents[],
): Promise<NoteAccount[]> {
const signerAddress = (
signer as (Signer & { address: string }) | Wallet
).address;
const decryptedEvents = []; const decryptedEvents = [];
@ -162,26 +124,21 @@ export class NoteAccount {
} }
try { try {
const unpackedMessage = unpackEncryptedMessage( const unpackedMessage = unpackEncryptedMessage(event.encryptedAccount);
event.encryptedAccount,
);
let recoveryKey; let recoveryKey;
if ((signer as Wallet).privateKey) { if ((signer as Wallet).privateKey) {
const wallet = signer as Wallet; const wallet = signer as Wallet;
const privateKey = const privateKey =
wallet.privateKey.slice(0, 2) === '0x' wallet.privateKey.slice(0, 2) === '0x' ? wallet.privateKey.slice(2) : wallet.privateKey;
? wallet.privateKey.slice(2)
: wallet.privateKey;
recoveryKey = decrypt({ recoveryKey = decrypt({
encryptedData: unpackedMessage, encryptedData: unpackedMessage,
privateKey, privateKey,
}); });
} else { } else {
const { version, nonce, ephemPublicKey, ciphertext } = const { version, nonce, ephemPublicKey, ciphertext } = unpackedMessage;
unpackedMessage;
const unpackedBuffer = bytesToHex( const unpackedBuffer = bytesToHex(
new TextEncoder().encode( new TextEncoder().encode(
@ -196,10 +153,7 @@ export class NoteAccount {
const provider = signer.provider as JsonRpcApiProvider; const provider = signer.provider as JsonRpcApiProvider;
recoveryKey = await provider.send('eth_decrypt', [ recoveryKey = await provider.send('eth_decrypt', [unpackedBuffer, signerAddress]);
unpackedBuffer,
signerAddress,
]);
} }
decryptedEvents.push( decryptedEvents.push(
@ -222,9 +176,7 @@ export class NoteAccount {
for (const event of events) { for (const event of events) {
try { try {
const unpackedMessage = unpackEncryptedMessage( const unpackedMessage = unpackEncryptedMessage(event.encryptedNote);
event.encryptedNote,
);
const [address, noteHex] = decrypt({ const [address, noteHex] = decrypt({
encryptedData: unpackedMessage, encryptedData: unpackedMessage,

View File

@ -1,10 +1,4 @@
import { import { namehash, EnsResolver, AbstractProvider, keccak256, Signer } from 'ethers';
namehash,
EnsResolver,
AbstractProvider,
keccak256,
Signer,
} from 'ethers';
import { import {
ENSNameWrapper, ENSNameWrapper,
@ -30,10 +24,7 @@ export function labelhash(label: string) {
if (!label) { if (!label) {
return bytesToHex(new Uint8Array(32).fill(0)); return bytesToHex(new Uint8Array(32).fill(0));
} }
return ( return encodedLabelToLabelhash(label) || keccak256(new TextEncoder().encode(label));
encodedLabelToLabelhash(label) ||
keccak256(new TextEncoder().encode(label))
);
} }
export function makeLabelNodeAndParent(name: string) { export function makeLabelNodeAndParent(name: string) {
@ -84,21 +75,11 @@ export class ENSUtils {
async getContracts() { async getContracts() {
const { chainId } = await this.provider.getNetwork(); const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
EnsContracts[Number(chainId)];
this.ENSRegistry = ENSRegistry__factory.connect( this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
ensRegistry, this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);
this.provider, this.ENSNameWrapper = ENSNameWrapper__factory.connect(ensNameWrapper, this.provider);
);
this.ENSResolver = ENSResolver__factory.connect(
ensPublicResolver,
this.provider,
);
this.ENSNameWrapper = ENSNameWrapper__factory.connect(
ensNameWrapper,
this.provider,
);
} }
async getOwner(name: string) { async getOwner(name: string) {
@ -117,9 +98,7 @@ export class ENSUtils {
const owner = (signer as unknown as { address: string }).address; const owner = (signer as unknown as { address: string }).address;
const nameWrapper = (this.ENSNameWrapper as ENSNameWrapper).connect( const nameWrapper = (this.ENSNameWrapper as ENSNameWrapper).connect(signer);
signer,
);
const { labelhash } = makeLabelNodeAndParent(name); const { labelhash } = makeLabelNodeAndParent(name);
@ -139,21 +118,12 @@ export class ENSUtils {
const { labelhash, parentNode } = makeLabelNodeAndParent(name); const { labelhash, parentNode } = makeLabelNodeAndParent(name);
return registry.setSubnodeRecord( return registry.setSubnodeRecord(parentNode, labelhash, owner, resolver.target, BigInt(0));
parentNode,
labelhash,
owner,
resolver.target,
BigInt(0),
);
} }
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/functions/wallet/setTextRecord.ts // https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/functions/wallet/setTextRecord.ts
async setText(signer: Signer, name: string, key: string, value: string) { async setText(signer: Signer, name: string, key: string, value: string) {
const resolver = ENSResolver__factory.connect( const resolver = ENSResolver__factory.connect((await this.getResolver(name))?.address as string, signer);
(await this.getResolver(name))?.address as string,
signer,
);
return resolver.setText(namehash(name), key, value); return resolver.setText(namehash(name), key, value);
} }

View File

@ -34,11 +34,7 @@ import {
} from '../batch'; } from '../batch';
import { fetchData, fetchDataOptions } from '../providers'; import { fetchData, fetchDataOptions } from '../providers';
import { import { enabledChains, type NetIdType, type SubdomainMap } from '../networkConfig';
enabledChains,
type NetIdType,
type SubdomainMap,
} from '../networkConfig';
import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient'; import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient'; import type { TovarishClient } from '../tovarishClient';
@ -163,39 +159,18 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
updateEventProgress({ updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) {}
percentage,
type,
fromBlock,
toBlock,
count,
}: Parameters<BatchEventOnProgress>[0]) {}
updateBlockProgress({ updateBlockProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]) {}
percentage,
currentIndex,
totalIndex,
}: Parameters<BatchBlockOnProgress>[0]) {}
updateTransactionProgress({ updateTransactionProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]) {}
percentage,
currentIndex,
totalIndex,
}: Parameters<BatchBlockOnProgress>[0]) {}
updateGraphProgress({ updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchGraphOnProgress>[0]) {}
type,
fromBlock,
toBlock,
count,
}: Parameters<BatchGraphOnProgress>[0]) {}
/* eslint-enable @typescript-eslint/no-unused-vars */ /* eslint-enable @typescript-eslint/no-unused-vars */
async formatEvents(events: EventLog[]): Promise<EventType[]> { async formatEvents(events: EventLog[]): Promise<EventType[]> {
// eslint-disable-next-line no-return-await // eslint-disable-next-line no-return-await
return await new Promise((resolve) => return await new Promise((resolve) => resolve(events as unknown as EventType[]));
resolve(events as unknown as EventType[]),
);
} }
/** /**
@ -220,9 +195,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
}; };
} }
async getSavedEvents(): Promise< async getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>> {
BaseEvents<EventType> | CachedEvents<EventType>
> {
let dbEvents = await this.getEventsFromDB(); let dbEvents = await this.getEventsFromDB();
if (!dbEvents.lastBlock) { if (!dbEvents.lastBlock) {
@ -251,9 +224,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const { events, lastSyncBlock } = (await (graph as any)[ const { events, lastSyncBlock } = (await (graph as any)[methodName || this.getGraphMethod()]({
methodName || this.getGraphMethod()
]({
fromBlock, fromBlock,
...this.getGraphParams(), ...this.getGraphParams(),
})) as BaseGraphEvents<EventType>; })) as BaseGraphEvents<EventType>;
@ -305,17 +276,9 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
} }
async getLatestEvents({ async getLatestEvents({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EventType>> {
fromBlock, if (this.tovarishClient?.selectedRelayer && ![DEPOSIT, WITHDRAWAL].includes(this.type.toLowerCase())) {
}: { const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents<EventType>({
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(), type: this.getTovarishType(),
fromBlock, fromBlock,
}); });
@ -328,9 +291,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
const graphEvents = await this.getEventsFromGraph({ fromBlock }); const graphEvents = await this.getEventsFromGraph({ fromBlock });
const lastSyncBlock = const lastSyncBlock =
graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock graphEvents.lastBlock && graphEvents.lastBlock >= fromBlock ? graphEvents.lastBlock : fromBlock;
? graphEvents.lastBlock
: fromBlock;
const rpcEvents = await this.getEventsFromRpc({ const rpcEvents = await this.getEventsFromRpc({
fromBlock: lastSyncBlock, fromBlock: lastSyncBlock,
}); });
@ -374,10 +335,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
const eventSet = new Set(); const eventSet = new Set();
const allEvents: EventType[] = [ const allEvents: EventType[] = [...savedEvents.events, ...newEvents.events]
...savedEvents.events,
...newEvents.events,
]
.sort((a, b) => { .sort((a, b) => {
if (a.blockNumber === b.blockNumber) { if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex; return a.logIndex - b.logIndex;
@ -391,8 +349,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
return !hasEvent; return !hasEvent;
}); });
const lastBlock = const lastBlock = newEvents.lastBlock || allEvents[allEvents.length - 1]?.blockNumber;
newEvents.lastBlock || allEvents[allEvents.length - 1]?.blockNumber;
const validateResult = await this.validateEvents<S>({ const validateResult = await this.validateEvents<S>({
events: allEvents, events: allEvents,
@ -401,10 +358,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
}); });
// If the events are loaded from cache or we have found new events, save them // If the events are loaded from cache or we have found new events, save them
if ( if ((savedEvents as CachedEvents<EventType>).fromCache || newEvents.events.length) {
(savedEvents as CachedEvents<EventType>).fromCache ||
newEvents.events.length
) {
await this.saveEvents({ events: allEvents, lastBlock }); await this.saveEvents({ events: allEvents, lastBlock });
} }
@ -416,8 +370,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
} }
export interface BaseTornadoServiceConstructor export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract'> {
extends Omit<BaseEventsServiceConstructor, 'contract'> {
Tornado: Tornado; Tornado: Tornado;
amount: string; amount: string;
currency: string; currency: string;
@ -430,9 +383,7 @@ export interface DepositsGraphParams extends BaseGraphParams {
currency: string; currency: string;
} }
export class BaseTornadoService extends BaseEventsService< export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
DepositsEvents | WithdrawalsEvents
> {
amount: string; amount: string;
currency: string; currency: string;
@ -442,14 +393,7 @@ export class BaseTornadoService extends BaseEventsService<
batchBlockService: BatchBlockService; batchBlockService: BatchBlockService;
constructor(serviceConstructor: BaseTornadoServiceConstructor) { constructor(serviceConstructor: BaseTornadoServiceConstructor) {
const { const { Tornado: contract, amount, currency, provider, optionalTree, merkleTreeService } = serviceConstructor;
Tornado: contract,
amount,
currency,
provider,
optionalTree,
merkleTreeService,
} = serviceConstructor;
super({ super({
...serviceConstructor, ...serviceConstructor,
@ -492,13 +436,10 @@ export class BaseTornadoService extends BaseEventsService<
}; };
} }
async formatEvents( async formatEvents(events: EventLog[]): Promise<(DepositsEvents | WithdrawalsEvents)[]> {
events: EventLog[],
): Promise<(DepositsEvents | WithdrawalsEvents)[]> {
const type = this.getType().toLowerCase(); const type = this.getType().toLowerCase();
if (type === DEPOSIT) { if (type === DEPOSIT) {
const formattedEvents = events.map( const formattedEvents = events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
({ blockNumber, index: logIndex, transactionHash, args }) => {
const { commitment, leafIndex, timestamp } = args; const { commitment, leafIndex, timestamp } = args;
return { return {
@ -509,23 +450,14 @@ export class BaseTornadoService extends BaseEventsService<
leafIndex: Number(leafIndex), leafIndex: Number(leafIndex),
timestamp: Number(timestamp), timestamp: Number(timestamp),
}; };
}, });
);
const txs = await this.batchTransactionService.getBatchTransactions( const txs = await this.batchTransactionService.getBatchTransactions([
[ ...new Set(formattedEvents.map(({ transactionHash }) => transactionHash)),
...new Set( ]);
formattedEvents.map(
({ transactionHash }) => transactionHash,
),
),
],
);
return formattedEvents.map((event) => { return formattedEvents.map((event) => {
const { from } = txs.find( const { from } = txs.find(({ hash }) => hash === event.transactionHash) as TransactionResponse;
({ hash }) => hash === event.transactionHash,
) as TransactionResponse;
return { return {
...event, ...event,
@ -533,8 +465,7 @@ export class BaseTornadoService extends BaseEventsService<
}; };
}); });
} else { } else {
const formattedEvents = events.map( const formattedEvents = events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
({ blockNumber, index: logIndex, transactionHash, args }) => {
const { nullifierHash, to, fee } = args; const { nullifierHash, to, fee } = args;
return { return {
@ -545,19 +476,14 @@ export class BaseTornadoService extends BaseEventsService<
to: getAddress(to), to: getAddress(to),
fee: String(fee), fee: String(fee),
}; };
}, });
);
const blocks = await this.batchBlockService.getBatchBlocks([ const blocks = await this.batchBlockService.getBatchBlocks([
...new Set( ...new Set(formattedEvents.map(({ blockNumber }) => blockNumber)),
formattedEvents.map(({ blockNumber }) => blockNumber),
),
]); ]);
return formattedEvents.map((event) => { return formattedEvents.map((event) => {
const { timestamp } = blocks.find( const { timestamp } = blocks.find(({ number }) => number === event.blockNumber) as Block;
({ number }) => number === event.blockNumber,
) as Block;
return { return {
...event, ...event,
@ -583,13 +509,8 @@ export class BaseTornadoService extends BaseEventsService<
throw new Error(errMsg); throw new Error(errMsg);
} }
if ( if (this.merkleTreeService && (!this.optionalTree || hasNewEvents)) {
this.merkleTreeService && return (await this.merkleTreeService.verifyTree(depositEvents)) as S;
(!this.optionalTree || hasNewEvents)
) {
return (await this.merkleTreeService.verifyTree(
depositEvents,
)) as S;
} }
} }
@ -602,8 +523,7 @@ export class BaseTornadoService extends BaseEventsService<
fromBlock: number; fromBlock: number;
}): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>> { }): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>> {
if (this.tovarishClient?.selectedRelayer) { if (this.tovarishClient?.selectedRelayer) {
const { events, lastSyncBlock: lastBlock } = const { events, lastSyncBlock: lastBlock } = await this.tovarishClient.getEvents<
await this.tovarishClient.getEvents<
DepositsEvents | WithdrawalsEvents DepositsEvents | WithdrawalsEvents
>({ >({
type: this.getTovarishType(), type: this.getTovarishType(),
@ -622,8 +542,7 @@ export class BaseTornadoService extends BaseEventsService<
} }
} }
export interface BaseEchoServiceConstructor export interface BaseEchoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Echoer: Echoer; Echoer: Echoer;
} }
@ -666,11 +585,7 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
.filter((e) => e) as EchoEvents[]; .filter((e) => e) as EchoEvents[];
} }
async getEventsFromGraph({ async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EchoEvents>> {
fromBlock,
}: {
fromBlock: number;
}): Promise<BaseEvents<EchoEvents>> {
// TheGraph doesn't support our batch sync due to missing blockNumber field // TheGraph doesn't support our batch sync due to missing blockNumber field
if (!this.graphApi || this.graphApi.includes('api.thegraph.com')) { if (!this.graphApi || this.graphApi.includes('api.thegraph.com')) {
return { return {
@ -683,8 +598,7 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
} }
} }
export interface BaseEncryptedNotesServiceConstructor export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Router: TornadoRouter | TornadoProxyLight; Router: TornadoRouter | TornadoProxyLight;
} }
@ -743,16 +657,12 @@ export const proposalState: { [key: string]: string } = {
6: 'Expired', 6: 'Expired',
}; };
function parseDescription( function parseDescription(id: number, text: string): { title: string; description: string } {
id: number,
text: string,
): { title: string; description: string } {
switch (id) { switch (id) {
case 1: case 1:
return { return {
title: text, title: text,
description: description: 'See: https://torn.community/t/proposal-1-enable-torn-transfers/38',
'See: https://torn.community/t/proposal-1-enable-torn-transfers/38',
}; };
case 10: case 10:
text = text.replace('\n', '\\n\\n'); text = text.replace('\n', '\\n\\n');
@ -795,16 +705,10 @@ function parseDescription(
}; };
} }
function parseComment( function parseComment(Governance: Governance, calldata: string): { contact: string; message: string } {
Governance: Governance,
calldata: string,
): { contact: string; message: string } {
try { try {
const methodLength = 4; const methodLength = 4;
const result = abiCoder.decode( const result = abiCoder.decode(['address[]', 'uint256', 'bool'], dataSlice(calldata, methodLength));
['address[]', 'uint256', 'bool'],
dataSlice(calldata, methodLength),
);
const data = Governance.interface.encodeFunctionData( const data = Governance.interface.encodeFunctionData(
// @ts-expect-error encodeFunctionData is broken lol // @ts-expect-error encodeFunctionData is broken lol
'castDelegatedVote', 'castDelegatedVote',
@ -812,10 +716,7 @@ function parseComment(
); );
const length = dataLength(data); const length = dataLength(data);
const str: string = abiCoder.decode( const str: string = abiCoder.decode(['string'], dataSlice(calldata, length))[0];
['string'],
dataSlice(calldata, length),
)[0];
const [contact, message] = JSON.parse(str) as string[]; const [contact, message] = JSON.parse(str) as string[];
return { return {
@ -848,8 +749,7 @@ export interface GovernanceVotes extends GovernanceVotedEvents {
voterName?: string; voterName?: string;
} }
export interface BaseGovernanceServiceConstructor export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Governance: Governance; Governance: Governance;
Aggregator: Aggregator; Aggregator: Aggregator;
ReverseRecords: ReverseRecords; ReverseRecords: ReverseRecords;
@ -863,8 +763,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
constructor(serviceConstructor: BaseGovernanceServiceConstructor) { constructor(serviceConstructor: BaseGovernanceServiceConstructor) {
const { Governance, Aggregator, ReverseRecords, provider } = const { Governance, Aggregator, ReverseRecords, provider } = serviceConstructor;
serviceConstructor;
super({ super({
...serviceConstructor, ...serviceConstructor,
@ -900,14 +799,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
const delegatedEvents: GovernanceDelegatedEvents[] = []; const delegatedEvents: GovernanceDelegatedEvents[] = [];
const undelegatedEvents: GovernanceUndelegatedEvents[] = []; const undelegatedEvents: GovernanceUndelegatedEvents[] = [];
events.forEach( events.forEach(({ blockNumber, index: logIndex, transactionHash, args, eventName: event }) => {
({
blockNumber,
index: logIndex,
transactionHash,
args,
eventName: event,
}) => {
const eventObjects = { const eventObjects = {
blockNumber, blockNumber,
logIndex, logIndex,
@ -916,14 +808,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
}; };
if (event === 'ProposalCreated') { if (event === 'ProposalCreated') {
const { const { id, proposer, target, startTime, endTime, description } = args;
id,
proposer,
target,
startTime,
endTime,
description,
} = args;
proposalEvents.push({ proposalEvents.push({
...eventObjects, ...eventObjects,
@ -969,27 +854,18 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
delegateFrom, delegateFrom,
}); });
} }
}, });
);
if (votedEvents.length) { if (votedEvents.length) {
this.updateTransactionProgress({ percentage: 0 }); this.updateTransactionProgress({ percentage: 0 });
const txs = await this.batchTransactionService.getBatchTransactions( const txs = await this.batchTransactionService.getBatchTransactions([
[ ...new Set(votedEvents.map(({ transactionHash }) => transactionHash)),
...new Set( ]);
votedEvents.map(
({ transactionHash }) => transactionHash,
),
),
],
);
votedEvents.forEach((event, index) => { votedEvents.forEach((event, index) => {
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let { data: input, from } = txs.find( let { data: input, from } = txs.find((t) => t.hash === event.transactionHash) as TransactionResponse;
(t) => t.hash === event.transactionHash,
) as TransactionResponse;
// Filter spammy txs // Filter spammy txs
if (!input || input.length > 2048) { if (!input || input.length > 2048) {
@ -1001,25 +877,12 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
}); });
} }
return [ return [...proposalEvents, ...votedEvents, ...delegatedEvents, ...undelegatedEvents];
...proposalEvents,
...votedEvents,
...delegatedEvents,
...undelegatedEvents,
];
} }
async getEventsFromGraph({ async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<AllGovernanceEvents>> {
fromBlock,
}: {
fromBlock: number;
}): Promise<BaseEvents<AllGovernanceEvents>> {
// TheGraph doesn't support governance subgraphs // TheGraph doesn't support governance subgraphs
if ( if (!this.graphApi || !this.subgraphName || this.graphApi.includes('api.thegraph.com')) {
!this.graphApi ||
!this.subgraphName ||
this.graphApi.includes('api.thegraph.com')
) {
return { return {
events: [], events: [],
lastBlock: fromBlock, lastBlock: fromBlock,
@ -1032,16 +895,11 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
async getAllProposals(): Promise<GovernanceProposals[]> { async getAllProposals(): Promise<GovernanceProposals[]> {
const { events } = await this.updateEvents(); const { events } = await this.updateEvents();
const proposalEvents = events.filter( const proposalEvents = events.filter((e) => e.event === 'ProposalCreated') as GovernanceProposalCreatedEvents[];
(e) => e.event === 'ProposalCreated',
) as GovernanceProposalCreatedEvents[];
const allProposers = [ const allProposers = [...new Set(proposalEvents.map((e) => [e.proposer]).flat())];
...new Set(proposalEvents.map((e) => [e.proposer]).flat()),
];
const [QUORUM_VOTES, proposalStatus, proposerNameRecords] = const [QUORUM_VOTES, proposalStatus, proposerNameRecords] = await Promise.all([
await Promise.all([
this.Governance.QUORUM_VOTES(), this.Governance.QUORUM_VOTES(),
this.Aggregator.getAllProposals(this.Governance.target), this.Aggregator.getAllProposals(this.Governance.target),
this.ReverseRecords.getNames(allProposers), this.ReverseRecords.getNames(allProposers),
@ -1062,16 +920,11 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
const status = proposalStatus[index]; const status = proposalStatus[index];
const { forVotes, againstVotes, executed, extended, state } = const { forVotes, againstVotes, executed, extended, state } = status;
status;
const { title, description } = parseDescription(id, text); const { title, description } = parseDescription(id, text);
const quorum = const quorum = ((Number(forVotes + againstVotes) / Number(QUORUM_VOTES)) * 100).toFixed(0) + '%';
(
(Number(forVotes + againstVotes) / Number(QUORUM_VOTES)) *
100
).toFixed(0) + '%';
return { return {
...event, ...event,
@ -1092,14 +945,10 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
const { events } = await this.getSavedEvents(); const { events } = await this.getSavedEvents();
const votedEvents = events.filter( const votedEvents = events.filter(
(e) => (e) => e.event === 'Voted' && (e as GovernanceVotedEvents).proposalId === proposalId,
e.event === 'Voted' &&
(e as GovernanceVotedEvents).proposalId === proposalId,
) as GovernanceVotedEvents[]; ) as GovernanceVotedEvents[];
const allVoters = [ const allVoters = [...new Set(votedEvents.map((e) => [e.from, e.voter]).flat())];
...new Set(votedEvents.map((e) => [e.from, e.voter]).flat()),
];
const names = await this.ReverseRecords.getNames(allVoters); const names = await this.ReverseRecords.getNames(allVoters);
@ -1116,10 +965,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
const votes = votedEvents.map((event) => { const votes = votedEvents.map((event) => {
const { from, voter } = event; const { from, voter } = event;
const { contact, message } = parseComment( const { contact, message } = parseComment(this.Governance, event.input);
this.Governance,
event.input,
);
return { return {
...event, ...event,
@ -1137,20 +983,11 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
const { events } = await this.getSavedEvents(); const { events } = await this.getSavedEvents();
const delegatedAccs = events const delegatedAccs = events
.filter( .filter((e) => e.event === 'Delegated' && (e as GovernanceDelegatedEvents).delegateTo === ethAccount)
(e) =>
e.event === 'Delegated' &&
(e as GovernanceDelegatedEvents).delegateTo === ethAccount,
)
.map((e) => (e as GovernanceDelegatedEvents).account); .map((e) => (e as GovernanceDelegatedEvents).account);
const undelegatedAccs = events const undelegatedAccs = events
.filter( .filter((e) => e.event === 'Undelegated' && (e as GovernanceUndelegatedEvents).delegateFrom === ethAccount)
(e) =>
e.event === 'Undelegated' &&
(e as GovernanceUndelegatedEvents).delegateFrom ===
ethAccount,
)
.map((e) => (e as GovernanceUndelegatedEvents).account); .map((e) => (e as GovernanceUndelegatedEvents).account);
const undel = [...undelegatedAccs]; const undel = [...undelegatedAccs];
@ -1190,28 +1027,20 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
} }
export async function getTovarishNetworks( export async function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]) {
registryService: BaseRegistryService,
relayers: CachedRelayerInfo[],
) {
await Promise.all( await Promise.all(
relayers relayers
.filter((r) => r.tovarishHost) .filter((r) => r.tovarishHost)
.map(async (relayer) => { .map(async (relayer) => {
try { try {
relayer.tovarishNetworks = await fetchData( relayer.tovarishNetworks = await fetchData(relayer.tovarishHost as string, {
relayer.tovarishHost as string,
{
...registryService.fetchDataOptions, ...registryService.fetchDataOptions,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
timeout: 30000, timeout: 30000,
maxRetry: registryService.fetchDataOptions?.torPort maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0,
? 2 });
: 0,
},
);
} catch { } catch {
// Ignore error and disable relayer // Ignore error and disable relayer
relayer.tovarishNetworks = []; relayer.tovarishNetworks = [];
@ -1256,8 +1085,7 @@ export interface CachedRelayers {
fromCache?: boolean; fromCache?: boolean;
} }
export interface BaseRegistryServiceConstructor export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
@ -1269,11 +1097,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
updateInterval: number; updateInterval: number;
constructor(serviceConstructor: BaseRegistryServiceConstructor) { constructor(serviceConstructor: BaseRegistryServiceConstructor) {
const { const { RelayerRegistry: contract, Aggregator, relayerEnsSubdomains } = serviceConstructor;
RelayerRegistry: contract,
Aggregator,
relayerEnsSubdomains,
} = serviceConstructor;
super({ super({
...serviceConstructor, ...serviceConstructor,
@ -1301,8 +1125,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
} }
async formatEvents(events: EventLog[]) { async formatEvents(events: EventLog[]) {
return events.map( return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
({ blockNumber, index: logIndex, transactionHash, args }) => {
const eventObjects = { const eventObjects = {
blockNumber, blockNumber,
logIndex, logIndex,
@ -1314,8 +1137,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
ensName: args.ensName, ensName: args.ensName,
relayerAddress: args.relayerAddress, relayerAddress: args.relayerAddress,
}; };
}, });
);
} }
/** /**
@ -1366,30 +1188,20 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
return false; return false;
}); });
const relayerNameHashes = uniqueRegisters.map((r) => const relayerNameHashes = uniqueRegisters.map((r) => namehash(r.ensName));
namehash(r.ensName),
);
const [relayersData, timestamp] = await Promise.all([ const [relayersData, timestamp] = await Promise.all([
this.Aggregator.relayersData.staticCall( this.Aggregator.relayersData.staticCall(relayerNameHashes, subdomains.concat('tovarish-relayer')),
relayerNameHashes,
subdomains.concat('tovarish-relayer'),
),
this.provider.getBlock(lastBlock).then((b) => Number(b?.timestamp)), this.provider.getBlock(lastBlock).then((b) => Number(b?.timestamp)),
]); ]);
const relayers = relayersData const relayers = relayersData
.map( .map(({ owner, balance: stakeBalance, records, isRegistered }, index) => {
(
{ owner, balance: stakeBalance, records, isRegistered },
index,
) => {
const { ensName, relayerAddress } = uniqueRegisters[index]; const { ensName, relayerAddress } = uniqueRegisters[index];
let tovarishHost = undefined; let tovarishHost = undefined;
const hostnames = records.reduce( const hostnames = records.reduce((acc, record, recordIndex) => {
(acc, record, recordIndex) => {
if (record) { if (record) {
// tovarish-relayer.relayer.eth // tovarish-relayer.relayer.eth
if (recordIndex === records.length - 1) { if (recordIndex === records.length - 1) {
@ -1397,42 +1209,27 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
return acc; return acc;
} }
acc[ acc[Number(Object.keys(this.relayerEnsSubdomains)[recordIndex])] = record;
Number(
Object.keys(this.relayerEnsSubdomains)[
recordIndex
],
)
] = record;
} }
return acc; return acc;
}, }, {} as SubdomainMap);
{} as SubdomainMap,
);
const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE; const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE;
const preCondition = const preCondition = Object.keys(hostnames).length && isRegistered && hasMinBalance;
Object.keys(hostnames).length &&
isRegistered &&
hasMinBalance;
if (preCondition) { if (preCondition) {
return { return {
ensName, ensName,
relayerAddress: owner, relayerAddress: owner,
registeredAddress: registeredAddress: owner !== relayerAddress ? relayerAddress : undefined,
owner !== relayerAddress
? relayerAddress
: undefined,
isRegistered, isRegistered,
stakeBalance: formatEther(stakeBalance), stakeBalance: formatEther(stakeBalance),
hostnames, hostnames,
tovarishHost, tovarishHost,
} as CachedRelayerInfo; } as CachedRelayerInfo;
} }
}, })
)
.filter((r) => r) as CachedRelayerInfo[]; .filter((r) => r) as CachedRelayerInfo[];
await getTovarishNetworks(this, relayers); await getTovarishNetworks(this, relayers);
@ -1459,19 +1256,14 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
*/ */
async updateRelayers(): Promise<CachedRelayers> { async updateRelayers(): Promise<CachedRelayers> {
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let { lastBlock, timestamp, relayers, fromCache } = let { lastBlock, timestamp, relayers, fromCache } = await this.getSavedRelayers();
await this.getSavedRelayers();
let shouldSave = fromCache ?? false; let shouldSave = fromCache ?? false;
if ( if (!relayers.length || timestamp + this.updateInterval < Math.floor(Date.now() / 1000)) {
!relayers.length ||
timestamp + this.updateInterval < Math.floor(Date.now() / 1000)
) {
console.log('\nUpdating relayers from registry\n'); console.log('\nUpdating relayers from registry\n');
({ lastBlock, timestamp, relayers } = ({ lastBlock, timestamp, relayers } = await this.getLatestRelayers());
await this.getLatestRelayers());
shouldSave = true; shouldSave = true;
} }

View File

@ -152,8 +152,7 @@ export async function loadRemoteEvents<T extends MinimalEvents>({
} }
} }
export interface DBTornadoServiceConstructor export interface DBTornadoServiceConstructor extends BaseTornadoServiceConstructor {
extends BaseTornadoServiceConstructor {
staticUrl: string; staticUrl: string;
idb: IndexedDB; idb: IndexedDB;
} }
@ -187,10 +186,7 @@ export class DBTornadoService extends BaseTornadoService {
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>) {
events,
lastBlock,
}: BaseEvents<DepositsEvents | WithdrawalsEvents>) {
await saveDBEvents<DepositsEvents | WithdrawalsEvents>({ await saveDBEvents<DepositsEvents | WithdrawalsEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
@ -244,8 +240,7 @@ export class DBEchoService extends BaseEchoService {
} }
} }
export interface DBEncryptedNotesServiceConstructor export interface DBEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor {
extends BaseEncryptedNotesServiceConstructor {
staticUrl: string; staticUrl: string;
idb: IndexedDB; idb: IndexedDB;
} }
@ -289,8 +284,7 @@ export class DBEncryptedNotesService extends BaseEncryptedNotesService {
} }
} }
export interface DBGovernanceServiceConstructor export interface DBGovernanceServiceConstructor extends BaseGovernanceServiceConstructor {
extends BaseGovernanceServiceConstructor {
staticUrl: string; staticUrl: string;
idb: IndexedDB; idb: IndexedDB;
} }
@ -334,8 +328,7 @@ export class DBGovernanceService extends BaseGovernanceService {
} }
} }
export interface DBRegistryServiceConstructor export interface DBRegistryServiceConstructor extends BaseRegistryServiceConstructor {
extends BaseRegistryServiceConstructor {
staticUrl: string; staticUrl: string;
idb: IndexedDB; idb: IndexedDB;
} }

View File

@ -20,10 +20,7 @@ export function convertETHToTokenAmount(
tokenDecimals: number = 18, tokenDecimals: number = 18,
): bigint { ): bigint {
const tokenDecimalsMultiplier = BigInt(10 ** Number(tokenDecimals)); const tokenDecimalsMultiplier = BigInt(10 ** Number(tokenDecimals));
return ( return (BigInt(amountInWei) * tokenDecimalsMultiplier) / BigInt(tokenPriceInWei);
(BigInt(amountInWei) * tokenDecimalsMultiplier) /
BigInt(tokenPriceInWei)
);
} }
export interface RelayerFeeParams { export interface RelayerFeeParams {
@ -43,10 +40,7 @@ export class TornadoFeeOracle {
provider: JsonRpcApiProvider; provider: JsonRpcApiProvider;
ovmGasPriceOracle?: OvmGasPriceOracle; ovmGasPriceOracle?: OvmGasPriceOracle;
constructor( constructor(provider: JsonRpcApiProvider, ovmGasPriceOracle?: OvmGasPriceOracle) {
provider: JsonRpcApiProvider,
ovmGasPriceOracle?: OvmGasPriceOracle,
) {
this.provider = provider; this.provider = provider;
if (ovmGasPriceOracle) { if (ovmGasPriceOracle) {
@ -73,21 +67,14 @@ export class TornadoFeeOracle {
})(), })(),
(async () => { (async () => {
try { try {
return BigInt( return BigInt(await this.provider.send('eth_maxPriorityFeePerGas', []));
await this.provider.send(
'eth_maxPriorityFeePerGas',
[],
),
);
} catch { } catch {
return BigInt(0); return BigInt(0);
} }
})(), })(),
]); ]);
return block?.baseFeePerGas return block?.baseFeePerGas ? (block.baseFeePerGas * BigInt(15)) / BigInt(10) + getPriorityFee : getGasPrice;
? (block.baseFeePerGas * BigInt(15)) / BigInt(10) + getPriorityFee
: getGasPrice;
} }
/** /**
@ -113,9 +100,7 @@ export class TornadoFeeOracle {
}; };
} }
return this.ovmGasPriceOracle.getL1Fee.staticCall( return this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized);
Transaction.from(tx).unsignedSerialized,
);
} }
/** /**
@ -124,25 +109,14 @@ export class TornadoFeeOracle {
* Using 30 gwei for default but it is recommended to supply cached gasPrice value from the UI * Using 30 gwei for default but it is recommended to supply cached gasPrice value from the UI
*/ */
defaultEthRefund(gasPrice?: BigNumberish, gasLimit?: BigNumberish): bigint { defaultEthRefund(gasPrice?: BigNumberish, gasLimit?: BigNumberish): bigint {
return ( return (gasPrice ? BigInt(gasPrice) : parseUnits('30', 'gwei')) * BigInt(gasLimit || 1_000_000);
(gasPrice ? BigInt(gasPrice) : parseUnits('30', 'gwei')) *
BigInt(gasLimit || 1_000_000)
);
} }
/** /**
* Calculates token amount for required ethRefund purchases required to calculate fees * Calculates token amount for required ethRefund purchases required to calculate fees
*/ */
calculateTokenAmount( calculateTokenAmount(ethRefund: BigNumberish, tokenPriceInEth: BigNumberish, tokenDecimals?: number): bigint {
ethRefund: BigNumberish, return convertETHToTokenAmount(ethRefund, tokenPriceInEth, tokenDecimals);
tokenPriceInEth: BigNumberish,
tokenDecimals?: number,
): bigint {
return convertETHToTokenAmount(
ethRefund,
tokenPriceInEth,
tokenDecimals,
);
} }
/** /**
@ -163,29 +137,17 @@ export class TornadoFeeOracle {
}: RelayerFeeParams): bigint { }: RelayerFeeParams): bigint {
const gasCosts = BigInt(gasPrice) * BigInt(gasLimit) + BigInt(l1Fee); const gasCosts = BigInt(gasPrice) * BigInt(gasLimit) + BigInt(l1Fee);
const relayerFee = const relayerFee = (BigInt(denomination) * BigInt(Math.floor(10000 * relayerFeePercent))) / BigInt(10000 * 100);
(BigInt(denomination) *
BigInt(Math.floor(10000 * relayerFeePercent))) /
BigInt(10000 * 100);
if (isEth) { if (isEth) {
// Add 20% premium // Add 20% premium
return ( return ((gasCosts + relayerFee) * BigInt(premiumPercent ? 100 + premiumPercent : 100)) / BigInt(100);
((gasCosts + relayerFee) *
BigInt(premiumPercent ? 100 + premiumPercent : 100)) /
BigInt(100)
);
} }
const feeInEth = gasCosts + BigInt(ethRefund); const feeInEth = gasCosts + BigInt(ethRefund);
return ( return (
((convertETHToTokenAmount( ((convertETHToTokenAmount(feeInEth, tokenPriceInWei, tokenDecimals) + relayerFee) *
feeInEth,
tokenPriceInWei,
tokenDecimals,
) +
relayerFee) *
BigInt(premiumPercent ? 100 + premiumPercent : 100)) / BigInt(premiumPercent ? 100 + premiumPercent : 100)) /
BigInt(100) BigInt(100)
); );

View File

@ -147,9 +147,7 @@ export async function getStatistic({
return { return {
events, events,
lastSyncBlock: lastSyncBlock:
lastEvent && lastEvent.blockNumber >= lastSyncBlock lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
? lastEvent.blockNumber + 1
: lastSyncBlock,
}; };
} catch (err) { } catch (err) {
console.log('Error from getStatistic query'); console.log('Error from getStatistic query');
@ -181,11 +179,7 @@ export interface getMetaReturns {
hasIndexingErrors: null | boolean; hasIndexingErrors: null | boolean;
} }
export async function getMeta({ export async function getMeta({ graphApi, subgraphName, fetchDataOptions }: getMetaParams): Promise<getMetaReturns> {
graphApi,
subgraphName,
fetchDataOptions,
}: getMetaParams): Promise<getMetaReturns> {
try { try {
const { const {
_meta: { _meta: {
@ -303,10 +297,7 @@ export async function getAllRegisters({
break; break;
} }
result = result.filter( result = result.filter(({ blockRegistration }) => blockRegistration !== lastEvent.blockRegistration);
({ blockRegistration }) =>
blockRegistration !== lastEvent.blockRegistration,
);
fromBlock = Number(lastEvent.blockRegistration); fromBlock = Number(lastEvent.blockRegistration);
events.push(...result); events.push(...result);
@ -319,8 +310,7 @@ export async function getAllRegisters({
}; };
} }
const result = events.map( const result = events.map(({ id, address, ensName, blockRegistration }) => {
({ id, address, ensName, blockRegistration }) => {
const [transactionHash, logIndex] = id.split('-'); const [transactionHash, logIndex] = id.split('-');
return { return {
@ -330,8 +320,7 @@ export async function getAllRegisters({
ensName, ensName,
relayerAddress: getAddress(address), relayerAddress: getAddress(address),
}; };
}, });
);
return { return {
events: result, events: result,
@ -446,9 +435,7 @@ export async function getAllDeposits({
break; break;
} }
result = result.filter( result = result.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
({ blockNumber }) => blockNumber !== lastEvent.blockNumber,
);
fromBlock = Number(lastEvent.blockNumber); fromBlock = Number(lastEvent.blockNumber);
events.push(...result); events.push(...result);
@ -461,8 +448,7 @@ export async function getAllDeposits({
}; };
} }
const result = events.map( const result = events.map(({ id, blockNumber, commitment, index, timestamp, from }) => {
({ id, blockNumber, commitment, index, timestamp, from }) => {
const [transactionHash, logIndex] = id.split('-'); const [transactionHash, logIndex] = id.split('-');
return { return {
@ -474,17 +460,14 @@ export async function getAllDeposits({
timestamp: Number(timestamp), timestamp: Number(timestamp),
from: getAddress(from), from: getAddress(from),
}; };
}, });
);
const [lastEvent] = result.slice(-1); const [lastEvent] = result.slice(-1);
return { return {
events: result, events: result,
lastSyncBlock: lastSyncBlock:
lastEvent && lastEvent.blockNumber >= lastSyncBlock lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
? lastEvent.blockNumber + 1
: lastSyncBlock,
}; };
} catch (err) { } catch (err) {
console.log('Error from getAllDeposits query'); console.log('Error from getAllDeposits query');
@ -598,9 +581,7 @@ export async function getAllWithdrawals({
break; break;
} }
result = result.filter( result = result.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
({ blockNumber }) => blockNumber !== lastEvent.blockNumber,
);
fromBlock = Number(lastEvent.blockNumber); fromBlock = Number(lastEvent.blockNumber);
events.push(...result); events.push(...result);
@ -613,8 +594,7 @@ export async function getAllWithdrawals({
}; };
} }
const result = events.map( const result = events.map(({ id, blockNumber, nullifier, to, fee, timestamp }) => {
({ id, blockNumber, nullifier, to, fee, timestamp }) => {
const [transactionHash, logIndex] = id.split('-'); const [transactionHash, logIndex] = id.split('-');
return { return {
@ -626,17 +606,14 @@ export async function getAllWithdrawals({
fee, fee,
timestamp: Number(timestamp), timestamp: Number(timestamp),
}; };
}, });
);
const [lastEvent] = result.slice(-1); const [lastEvent] = result.slice(-1);
return { return {
events: result, events: result,
lastSyncBlock: lastSyncBlock:
lastEvent && lastEvent.blockNumber >= lastSyncBlock lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
? lastEvent.blockNumber + 1
: lastSyncBlock,
}; };
} catch (err) { } catch (err) {
console.log('Error from getAllWithdrawals query'); console.log('Error from getAllWithdrawals query');
@ -806,9 +783,7 @@ export async function getAllGraphEchoEvents({
break; break;
} }
result = result.filter( result = result.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
({ blockNumber }) => blockNumber !== lastEvent.blockNumber,
);
fromBlock = Number(lastEvent.blockNumber); fromBlock = Number(lastEvent.blockNumber);
events.push(...result); events.push(...result);
@ -838,9 +813,7 @@ export async function getAllGraphEchoEvents({
return { return {
events: result, events: result,
lastSyncBlock: lastSyncBlock:
lastEvent && lastEvent.blockNumber >= lastSyncBlock lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
? lastEvent.blockNumber + 1
: lastSyncBlock,
}; };
} catch (err) { } catch (err) {
console.log('Error from getAllGraphEchoEvents query'); console.log('Error from getAllGraphEchoEvents query');
@ -942,9 +915,7 @@ export async function getAllEncryptedNotes({
break; break;
} }
result = result.filter( result = result.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
({ blockNumber }) => blockNumber !== lastEvent.blockNumber,
);
fromBlock = Number(lastEvent.blockNumber); fromBlock = Number(lastEvent.blockNumber);
events.push(...result); events.push(...result);
@ -969,9 +940,7 @@ export async function getAllEncryptedNotes({
return { return {
events: result, events: result,
lastSyncBlock: lastSyncBlock:
lastEvent && lastEvent.blockNumber >= lastSyncBlock lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
? lastEvent.blockNumber + 1
: lastSyncBlock,
}; };
} catch (err) { } catch (err) {
console.log('Error from getAllEncryptedNotes query'); console.log('Error from getAllEncryptedNotes query');
@ -1085,18 +1054,13 @@ export async function getAllGovernanceEvents({
lastSyncBlock = currentBlock; lastSyncBlock = currentBlock;
const eventsLength = const eventsLength = proposals.length + votes.length + delegates.length + undelegates.length;
proposals.length +
votes.length +
delegates.length +
undelegates.length;
if (eventsLength === 0) { if (eventsLength === 0) {
break; break;
} }
const formattedProposals: GovernanceProposalCreatedEvents[] = const formattedProposals: GovernanceProposalCreatedEvents[] = proposals.map(
proposals.map(
({ ({
blockNumber, blockNumber,
logIndex, logIndex,
@ -1124,17 +1088,7 @@ export async function getAllGovernanceEvents({
); );
const formattedVotes: GovernanceVotedEvents[] = votes.map( const formattedVotes: GovernanceVotedEvents[] = votes.map(
({ ({ blockNumber, logIndex, transactionHash, proposalId, voter, support, votes, from, input }) => {
blockNumber,
logIndex,
transactionHash,
proposalId,
voter,
support,
votes,
from,
input,
}) => {
// Filter spammy txs // Filter spammy txs
if (!input || input.length > 2048) { if (!input || input.length > 2048) {
input = ''; input = '';
@ -1155,15 +1109,8 @@ export async function getAllGovernanceEvents({
}, },
); );
const formattedDelegates: GovernanceDelegatedEvents[] = const formattedDelegates: GovernanceDelegatedEvents[] = delegates.map(
delegates.map( ({ blockNumber, logIndex, transactionHash, account, delegateTo }) => {
({
blockNumber,
logIndex,
transactionHash,
account,
delegateTo,
}) => {
return { return {
blockNumber: Number(blockNumber), blockNumber: Number(blockNumber),
logIndex: Number(logIndex), logIndex: Number(logIndex),
@ -1175,15 +1122,8 @@ export async function getAllGovernanceEvents({
}, },
); );
const formattedUndelegates: GovernanceUndelegatedEvents[] = const formattedUndelegates: GovernanceUndelegatedEvents[] = undelegates.map(
undelegates.map( ({ blockNumber, logIndex, transactionHash, account, delegateFrom }) => {
({
blockNumber,
logIndex,
transactionHash,
account,
delegateFrom,
}) => {
return { return {
blockNumber: Number(blockNumber), blockNumber: Number(blockNumber),
logIndex: Number(logIndex), logIndex: Number(logIndex),
@ -1224,9 +1164,7 @@ export async function getAllGovernanceEvents({
}); });
} }
formattedEvents = formattedEvents.filter( formattedEvents = formattedEvents.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
({ blockNumber }) => blockNumber !== lastEvent.blockNumber,
);
fromBlock = Number(lastEvent.blockNumber); fromBlock = Number(lastEvent.blockNumber);
@ -1238,9 +1176,7 @@ export async function getAllGovernanceEvents({
return { return {
events: result, events: result,
lastSyncBlock: lastSyncBlock:
lastEvent && lastEvent.blockNumber >= lastSyncBlock lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
? lastEvent.blockNumber + 1
: lastSyncBlock,
}; };
} catch (err) { } catch (err) {
console.log('Error from getAllGovernance query'); console.log('Error from getAllGovernance query');

View File

@ -2,8 +2,7 @@
import { openDB, deleteDB, OpenDBCallbacks, IDBPDatabase } from 'idb'; import { openDB, deleteDB, OpenDBCallbacks, IDBPDatabase } from 'idb';
import { getConfig, NetIdType } from './networkConfig'; import { getConfig, NetIdType } from './networkConfig';
export const INDEX_DB_ERROR = export const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.';
'A mutation operation was attempted on a database that did not allow mutations.';
export interface IDBIndex { export interface IDBIndex {
name: string; name: string;
@ -40,8 +39,7 @@ export class IndexedDB {
db.deleteObjectStore(value); db.deleteObjectStore(value);
}); });
[{ name: 'keyval' }, ...(stores || [])].forEach( [{ name: 'keyval' }, ...(stores || [])].forEach(({ name, keyPath, indexes }) => {
({ name, keyPath, indexes }) => {
const store = db.createObjectStore(name, { const store = db.createObjectStore(name, {
keyPath, keyPath,
autoIncrement: true, autoIncrement: true,
@ -52,8 +50,7 @@ export class IndexedDB {
store.createIndex(name, name, { unique }); store.createIndex(name, name, { unique });
}); });
} }
}, });
);
}, },
}; };
@ -138,24 +135,13 @@ export class IndexedDB {
} }
try { try {
return (await this.db.getAllFromIndex( return (await this.db.getAllFromIndex(storeName, indexName, key, count)) as T;
storeName,
indexName,
key,
count,
)) as T;
} catch (err: any) { } catch (err: any) {
throw new Error(`Method getAllFromIndex has error: ${err.message}`); throw new Error(`Method getAllFromIndex has error: ${err.message}`);
} }
} }
async getItem<T>({ async getItem<T>({ storeName, key }: { storeName: string; key: string }): Promise<T | undefined> {
storeName,
key,
}: {
storeName: string;
key: string;
}): Promise<T | undefined> {
await this.initDB(); await this.initDB();
if (!this.db) { if (!this.db) {
@ -171,15 +157,7 @@ export class IndexedDB {
} }
} }
async addItem({ async addItem({ storeName, data, key = '' }: { storeName: string; data: any; key: string }) {
storeName,
data,
key = '',
}: {
storeName: string;
data: any;
key: string;
}) {
await this.initDB(); await this.initDB();
if (!this.db) { if (!this.db) {
@ -198,15 +176,7 @@ export class IndexedDB {
} }
} }
async putItem({ async putItem({ storeName, data, key }: { storeName: string; data: any; key?: string }) {
storeName,
data,
key,
}: {
storeName: string;
data: any;
key?: string;
}) {
await this.initDB(); await this.initDB();
if (!this.db) { if (!this.db) {
@ -269,13 +239,7 @@ export class IndexedDB {
return this.deleteItem({ storeName: 'keyval', key }); return this.deleteItem({ storeName: 'keyval', key });
} }
async clearStore({ async clearStore({ storeName, mode = 'readwrite' }: { storeName: string; mode: IDBTransactionMode }) {
storeName,
mode = 'readwrite',
}: {
storeName: string;
mode: IDBTransactionMode;
}) {
await this.initDB(); await this.initDB();
if (!this.db) { if (!this.db) {
@ -309,17 +273,10 @@ export class IndexedDB {
try { try {
const tx = this.db.transaction(storeName, mode); const tx = this.db.transaction(storeName, mode);
await ( await (tx.objectStore(storeName).add as (value: any, key?: any) => Promise<any>)(data);
tx.objectStore(storeName).add as (
value: any,
key?: any,
) => Promise<any>
)(data);
await tx.done; await tx.done;
} catch (err: any) { } catch (err: any) {
throw new Error( throw new Error(`Method createTransactions has error: ${err.message}`);
`Method createTransactions has error: ${err.message}`,
);
} }
} }
@ -345,15 +302,11 @@ export class IndexedDB {
for (const item of data) { for (const item of data) {
if (item) { if (item) {
await ( await (tx.store.put as (value: any, key?: any) => Promise<any>)({ ...item, ...index });
tx.store.put as (value: any, key?: any) => Promise<any>
)({ ...item, ...index });
} }
} }
} catch (err: any) { } catch (err: any) {
throw new Error( throw new Error(`Method createMultipleTransactions has error: ${err.message}`);
`Method createMultipleTransactions has error: ${err.message}`,
);
} }
} }
} }
@ -411,8 +364,7 @@ export async function getIndexedDB(netId?: NetIdType) {
const config = getConfig(netId); const config = getConfig(netId);
const { tokens, nativeCurrency, registryContract, governanceContract } = const { tokens, nativeCurrency, registryContract, governanceContract } = config;
config;
const stores = [...defaultState]; const stores = [...defaultState];

View File

@ -1,10 +1,5 @@
import { Worker as NodeWorker } from 'worker_threads'; import { Worker as NodeWorker } from 'worker_threads';
import { import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
MerkleTree,
PartialMerkleTree,
Element,
TreeEdge,
} from '@tornado/fixed-merkle-tree';
import type { Tornado } from '@tornado/contracts'; import type { Tornado } from '@tornado/contracts';
import { isNode, toFixedHex } from './utils'; import { isNode, toFixedHex } from './utils';
import { mimc } from './mimc'; import { mimc } from './mimc';
@ -66,43 +61,28 @@ export class MerkleTreeService {
try { try {
if (isNode) { if (isNode) {
const merkleWorkerPromise = new Promise( const merkleWorkerPromise = new Promise((resolve, reject) => {
(resolve, reject) => { const worker = new NodeWorker(this.merkleWorkerPath as string, {
const worker = new NodeWorker(
this.merkleWorkerPath as string,
{
workerData: { workerData: {
merkleTreeHeight: this.merkleTreeHeight, merkleTreeHeight: this.merkleTreeHeight,
elements: events, elements: events,
zeroElement: this.emptyElement, zeroElement: this.emptyElement,
}, },
}, });
);
worker.on('message', resolve); worker.on('message', resolve);
worker.on('error', reject); worker.on('error', reject);
worker.on('exit', (code) => { worker.on('exit', (code) => {
if (code !== 0) { if (code !== 0) {
reject( reject(new Error(`Worker stopped with exit code ${code}`));
new Error(
`Worker stopped with exit code ${code}`,
),
);
} }
}); });
}, }) as Promise<string>;
) as Promise<string>;
return MerkleTree.deserialize( return MerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
JSON.parse(await merkleWorkerPromise),
hashFunction,
);
} else { } else {
const merkleWorkerPromise = new Promise( const merkleWorkerPromise = new Promise((resolve, reject) => {
(resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const worker = new (Worker as any)( const worker = new (Worker as any)(this.merkleWorkerPath);
this.merkleWorkerPath,
);
worker.onmessage = (e: { data: string }) => { worker.onmessage = (e: { data: string }) => {
resolve(e.data); resolve(e.data);
@ -118,18 +98,12 @@ export class MerkleTreeService {
elements: events, elements: events,
zeroElement: this.emptyElement, zeroElement: this.emptyElement,
}); });
}, }) as Promise<string>;
) as Promise<string>;
return MerkleTree.deserialize( return MerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
JSON.parse(await merkleWorkerPromise),
hashFunction,
);
} }
} catch (err) { } catch (err) {
console.log( console.log('merkleWorker failed, falling back to synchronous merkle tree');
'merkleWorker failed, falling back to synchronous merkle tree',
);
console.log(err); console.log(err);
} }
} }
@ -140,13 +114,7 @@ export class MerkleTreeService {
}); });
} }
async createPartialTree({ async createPartialTree({ edge, elements }: { edge: TreeEdge; elements: Element[] }) {
edge,
elements,
}: {
edge: TreeEdge;
elements: Element[];
}) {
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
if (this.merkleWorkerPath) { if (this.merkleWorkerPath) {
@ -154,44 +122,29 @@ export class MerkleTreeService {
try { try {
if (isNode) { if (isNode) {
const merkleWorkerPromise = new Promise( const merkleWorkerPromise = new Promise((resolve, reject) => {
(resolve, reject) => { const worker = new NodeWorker(this.merkleWorkerPath as string, {
const worker = new NodeWorker(
this.merkleWorkerPath as string,
{
workerData: { workerData: {
merkleTreeHeight: this.merkleTreeHeight, merkleTreeHeight: this.merkleTreeHeight,
edge, edge,
elements, elements,
zeroElement: this.emptyElement, zeroElement: this.emptyElement,
}, },
}, });
);
worker.on('message', resolve); worker.on('message', resolve);
worker.on('error', reject); worker.on('error', reject);
worker.on('exit', (code) => { worker.on('exit', (code) => {
if (code !== 0) { if (code !== 0) {
reject( reject(new Error(`Worker stopped with exit code ${code}`));
new Error(
`Worker stopped with exit code ${code}`,
),
);
} }
}); });
}, }) as Promise<string>;
) as Promise<string>;
return PartialMerkleTree.deserialize( return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
JSON.parse(await merkleWorkerPromise),
hashFunction,
);
} else { } else {
const merkleWorkerPromise = new Promise( const merkleWorkerPromise = new Promise((resolve, reject) => {
(resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const worker = new (Worker as any)( const worker = new (Worker as any)(this.merkleWorkerPath);
this.merkleWorkerPath,
);
worker.onmessage = (e: { data: string }) => { worker.onmessage = (e: { data: string }) => {
resolve(e.data); resolve(e.data);
@ -208,18 +161,12 @@ export class MerkleTreeService {
elements, elements,
zeroElement: this.emptyElement, zeroElement: this.emptyElement,
}); });
}, }) as Promise<string>;
) as Promise<string>;
return PartialMerkleTree.deserialize( return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
JSON.parse(await merkleWorkerPromise),
hashFunction,
);
} }
} catch (err) { } catch (err) {
console.log( console.log('merkleWorker failed, falling back to synchronous merkle tree');
'merkleWorker failed, falling back to synchronous merkle tree',
);
console.log(err); console.log(err);
} }
} }
@ -237,13 +184,9 @@ export class MerkleTreeService {
const timeStart = Date.now(); const timeStart = Date.now();
const tree = await this.createTree( const tree = await this.createTree(events.map(({ commitment }) => commitment));
events.map(({ commitment }) => commitment),
);
const isKnownRoot = await this.Tornado.isKnownRoot( const isKnownRoot = await this.Tornado.isKnownRoot(toFixedHex(BigInt(tree.root)));
toFixedHex(BigInt(tree.root)),
);
if (!isKnownRoot) { if (!isKnownRoot) {
const errMsg = `Deposit Event ${this.netId} ${this.amount} ${this.currency} is invalid`; const errMsg = `Deposit Event ${this.netId} ${this.amount} ${this.currency} is invalid`;

View File

@ -1,11 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import workerThreads from 'worker_threads'; import workerThreads from 'worker_threads';
import { import { MerkleTree, Element, TreeEdge, PartialMerkleTree } from '@tornado/fixed-merkle-tree';
MerkleTree,
Element,
TreeEdge,
PartialMerkleTree,
} from '@tornado/fixed-merkle-tree';
import { mimc } from './mimc'; import { mimc } from './mimc';
import { isNode } from './utils'; import { isNode } from './utils';
@ -18,23 +13,15 @@ interface WorkData {
async function nodePostWork() { async function nodePostWork() {
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData as WorkData;
workerThreads.workerData as WorkData;
if (edge) { if (edge) {
const merkleTree = new PartialMerkleTree( const merkleTree = new PartialMerkleTree(merkleTreeHeight, edge, elements, {
merkleTreeHeight,
edge,
elements,
{
zeroElement, zeroElement,
hashFunction, hashFunction,
}, });
);
(workerThreads.parentPort as workerThreads.MessagePort).postMessage( (workerThreads.parentPort as workerThreads.MessagePort).postMessage(merkleTree.toString());
merkleTree.toString(),
);
return; return;
} }
@ -43,18 +30,12 @@ async function nodePostWork() {
hashFunction, hashFunction,
}); });
(workerThreads.parentPort as workerThreads.MessagePort).postMessage( (workerThreads.parentPort as workerThreads.MessagePort).postMessage(merkleTree.toString());
merkleTree.toString(),
);
} }
if (isNode && workerThreads) { if (isNode && workerThreads) {
nodePostWork(); nodePostWork();
} else if ( } else if (!isNode && typeof addEventListener === 'function' && typeof postMessage === 'function') {
!isNode &&
typeof addEventListener === 'function' &&
typeof postMessage === 'function'
) {
addEventListener('message', async (e: any) => { addEventListener('message', async (e: any) => {
let data; let data;
@ -65,19 +46,13 @@ if (isNode && workerThreads) {
} }
const { hash: hashFunction } = await mimc.getHash(); const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = const { merkleTreeHeight, edge, elements, zeroElement } = data as WorkData;
data as WorkData;
if (edge) { if (edge) {
const merkleTree = new PartialMerkleTree( const merkleTree = new PartialMerkleTree(merkleTreeHeight, edge, elements, {
merkleTreeHeight,
edge,
elements,
{
zeroElement, zeroElement,
hashFunction, hashFunction,
}, });
);
postMessage(merkleTree.toString()); postMessage(merkleTree.toString());
return; return;

View File

@ -12,10 +12,7 @@ export class Mimc {
async initMimc() { async initMimc() {
this.sponge = await buildMimcSponge(); this.sponge = await buildMimcSponge();
this.hash = (left, right) => this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
this.sponge?.F.toString(
this.sponge?.multiHash([BigInt(left), BigInt(right)]),
);
} }
async getHash() { async getHash() {

View File

@ -14,8 +14,7 @@ export interface Call3 {
export async function multicall(Multicall: Multicall, calls: Call3[]) { export async function multicall(Multicall: Multicall, calls: Call3[]) {
const calldata = calls.map((call) => { const calldata = calls.map((call) => {
const target = (call.contract?.target || call.address) as string; const target = (call.contract?.target || call.address) as string;
const callInterface = (call.contract?.interface || const callInterface = (call.contract?.interface || call.interface) as Interface;
call.interface) as Interface;
return { return {
target, target,
@ -27,18 +26,11 @@ export async function multicall(Multicall: Multicall, calls: Call3[]) {
const returnData = await Multicall.aggregate3.staticCall(calldata); const returnData = await Multicall.aggregate3.staticCall(calldata);
const res = returnData.map((call, i) => { const res = returnData.map((call, i) => {
const callInterface = (calls[i].contract?.interface || const callInterface = (calls[i].contract?.interface || calls[i].interface) as Interface;
calls[i].interface) as Interface;
const [result, data] = call; const [result, data] = call;
const decodeResult = const decodeResult =
result && data && data !== '0x' result && data && data !== '0x' ? callInterface.decodeFunctionResult(calls[i].name, data) : null;
? callInterface.decodeFunctionResult(calls[i].name, data) return !decodeResult ? null : decodeResult.length === 1 ? decodeResult[0] : decodeResult;
: null;
return !decodeResult
? null
: decodeResult.length === 1
? decodeResult[0]
: decodeResult;
}); });
return res; return res;

View File

@ -122,8 +122,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'ETH', currencyName: 'ETH',
explorerUrl: 'https://etherscan.io', explorerUrl: 'https://etherscan.io',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Ethereum Mainnet', networkName: 'Ethereum Mainnet',
deployedBlock: 9116966, deployedBlock: 9116966,
rpcUrls: { rpcUrls: {
@ -259,8 +258,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'BNB', currencyName: 'BNB',
explorerUrl: 'https://bscscan.com', explorerUrl: 'https://bscscan.com',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Binance Smart Chain', networkName: 'Binance Smart Chain',
deployedBlock: 8158799, deployedBlock: 8158799,
stablecoin: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', stablecoin: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
@ -323,8 +321,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'MATIC', currencyName: 'MATIC',
explorerUrl: 'https://polygonscan.com', explorerUrl: 'https://polygonscan.com',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Polygon (Matic) Network', networkName: 'Polygon (Matic) Network',
deployedBlock: 16257962, deployedBlock: 16257962,
stablecoin: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', stablecoin: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
@ -375,8 +372,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'ETH', currencyName: 'ETH',
explorerUrl: 'https://optimistic.etherscan.io', explorerUrl: 'https://optimistic.etherscan.io',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Optimism', networkName: 'Optimism',
deployedBlock: 2243689, deployedBlock: 2243689,
stablecoin: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', stablecoin: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',
@ -428,8 +424,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'ETH', currencyName: 'ETH',
explorerUrl: 'https://arbiscan.io', explorerUrl: 'https://arbiscan.io',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Arbitrum One', networkName: 'Arbitrum One',
deployedBlock: 3430648, deployedBlock: 3430648,
stablecoin: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', stablecoin: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
@ -484,8 +479,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'xDAI', currencyName: 'xDAI',
explorerUrl: 'https://gnosisscan.io', explorerUrl: 'https://gnosisscan.io',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Gnosis Chain', networkName: 'Gnosis Chain',
deployedBlock: 17754561, deployedBlock: 17754561,
stablecoin: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83', stablecoin: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83',
@ -536,8 +530,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'AVAX', currencyName: 'AVAX',
explorerUrl: 'https://snowtrace.io', explorerUrl: 'https://snowtrace.io',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Avalanche Mainnet', networkName: 'Avalanche Mainnet',
deployedBlock: 4429818, deployedBlock: 4429818,
stablecoin: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', stablecoin: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
@ -587,8 +580,7 @@ export const defaultConfig: networkConfig = {
currencyName: 'SepoliaETH', currencyName: 'SepoliaETH',
explorerUrl: 'https://sepolia.etherscan.io', explorerUrl: 'https://sepolia.etherscan.io',
merkleTreeHeight: 20, merkleTreeHeight: 20,
emptyElement: emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
'21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Ethereum Sepolia', networkName: 'Ethereum Sepolia',
deployedBlock: 5594395, deployedBlock: 5594395,
stablecoin: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', stablecoin: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
@ -658,9 +650,7 @@ export const defaultConfig: networkConfig = {
}, },
}; };
export const enabledChains = Object.values(NetId).filter( export const enabledChains = Object.values(NetId).filter((n) => typeof n === 'number') as NetIdType[];
(n) => typeof n === 'number',
) as NetIdType[];
/** /**
* Custom config object to extend default config * Custom config object to extend default config

View File

@ -16,9 +16,7 @@ export class Pedersen {
async unpackPoint(buffer: Uint8Array) { async unpackPoint(buffer: Uint8Array) {
await this.pedersenPromise; await this.pedersenPromise;
return this.babyJub?.unpackPoint( return this.babyJub?.unpackPoint(this.pedersenHash?.hash(buffer) as Uint8Array);
this.pedersenHash?.hash(buffer) as Uint8Array,
);
} }
toStringBuffer(buffer: Uint8Array): string { toStringBuffer(buffer: Uint8Array): string {

View File

@ -1,9 +1,4 @@
import { import { ERC20Permit, ERC20Mock, TORN, PermitTornado } from '@tornado/contracts';
ERC20Permit,
ERC20Mock,
TORN,
PermitTornado,
} from '@tornado/contracts';
import { import {
BaseContract, BaseContract,
MaxUint256, MaxUint256,
@ -105,10 +100,7 @@ export async function getPermitCommitmentsSignature({
signer?: Signer; signer?: Signer;
}) { }) {
const value = BigInt(commitments.length) * denomination; const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256( const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
['bytes32[]'],
[commitments],
);
return await getPermitSignature({ return await getPermitSignature({
Token, Token,
@ -199,9 +191,7 @@ export async function getPermit2Signature({
const hash = new TypedDataEncoder(types).hash(values); const hash = new TypedDataEncoder(types).hash(values);
const signature = Signature.from( const signature = Signature.from(await sigSigner.signTypedData(domain, types, values));
await sigSigner.signTypedData(domain, types, values),
);
return { return {
domain, domain,
@ -226,10 +216,7 @@ export async function getPermit2CommitmentsSignature({
signer?: Signer; signer?: Signer;
}) { }) {
const value = BigInt(commitments.length) * denomination; const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256( const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
['bytes32[]'],
[commitments],
);
return await getPermit2Signature({ return await getPermit2Signature({
Token, Token,

View File

@ -9,11 +9,7 @@ export class TokenPriceOracle {
fallbackPrice: bigint; fallbackPrice: bigint;
constructor( constructor(provider: Provider, multicall: Multicall, oracle?: OffchainOracle) {
provider: Provider,
multicall: Multicall,
oracle?: OffchainOracle,
) {
this.provider = provider; this.provider = provider;
this.multicall = multicall; this.multicall = multicall;
this.oracle = oracle; this.oracle = oracle;
@ -35,10 +31,7 @@ export class TokenPriceOracle {
} }
buildStable(stablecoinAddress: string): Call3[] { buildStable(stablecoinAddress: string): Call3[] {
const stablecoin = ERC20__factory.connect( const stablecoin = ERC20__factory.connect(stablecoinAddress, this.provider);
stablecoinAddress,
this.provider,
);
return [ return [
{ {
@ -81,44 +74,29 @@ export class TokenPriceOracle {
): Promise<bigint[]> { ): Promise<bigint[]> {
// setup mock price for testnets // setup mock price for testnets
if (!this.oracle) { if (!this.oracle) {
return new Promise((resolve) => return new Promise((resolve) => resolve(tokens.map(() => this.fallbackPrice)));
resolve(tokens.map(() => this.fallbackPrice)),
);
} }
const prices = (await multicall( const prices = (await multicall(this.multicall, this.buildCalls(tokens))) as (bigint | null)[];
this.multicall,
this.buildCalls(tokens),
)) as (bigint | null)[];
return prices.map((price, index) => { return prices.map((price, index) => {
if (!price) { if (!price) {
price = this.fallbackPrice; price = this.fallbackPrice;
} }
return ( return (price * BigInt(10 ** tokens[index].decimals)) / BigInt(10 ** 18);
(price * BigInt(10 ** tokens[index].decimals)) /
BigInt(10 ** 18)
);
}); });
} }
async fetchEthUSD(stablecoinAddress: string): Promise<number> { async fetchEthUSD(stablecoinAddress: string): Promise<number> {
// setup mock price for testnets // setup mock price for testnets
if (!this.oracle) { if (!this.oracle) {
return new Promise((resolve) => return new Promise((resolve) => resolve(10 ** 18 / Number(this.fallbackPrice)));
resolve(10 ** 18 / Number(this.fallbackPrice)),
);
} }
const [decimals, price] = await multicall( const [decimals, price] = await multicall(this.multicall, this.buildStable(stablecoinAddress));
this.multicall,
this.buildStable(stablecoinAddress),
);
// eth wei price of usdc token // eth wei price of usdc token
const ethPrice = const ethPrice = ((price || this.fallbackPrice) * BigInt(10n ** decimals)) / BigInt(10 ** 18);
((price || this.fallbackPrice) * BigInt(10n ** decimals)) /
BigInt(10 ** 18);
return 1 / Number(formatEther(ethPrice)); return 1 / Number(formatEther(ethPrice));
} }

View File

@ -20,12 +20,7 @@ import {
EnsPlugin, EnsPlugin,
GasCostPlugin, GasCostPlugin,
} from 'ethers'; } from 'ethers';
import type { import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
RequestInfo,
RequestInit,
Response,
HeadersInit,
} from 'node-fetch';
// Temporary workaround until @types/node-fetch is compatible with @types/node // Temporary workaround until @types/node-fetch is compatible with @types/node
import type { AbortSignal as FetchAbortSignal } from 'node-fetch/externals'; import type { AbortSignal as FetchAbortSignal } from 'node-fetch/externals';
import { isNode, sleep } from './utils'; import { isNode, sleep } from './utils';
@ -38,15 +33,11 @@ declare global {
} }
// Update this for every Tor Browser release // Update this for every Tor Browser release
export const defaultUserAgent = export const defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0';
'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0';
export const fetch = crossFetch as unknown as nodeFetch; export const fetch = crossFetch as unknown as nodeFetch;
export type nodeFetch = ( export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
url: RequestInfo,
init?: RequestInit,
) => Promise<Response>;
export type fetchDataOptions = RequestInit & { export type fetchDataOptions = RequestInit & {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -62,9 +53,7 @@ export type fetchDataOptions = RequestInit & {
returnResponse?: boolean; returnResponse?: boolean;
}; };
export type NodeAgent = export type NodeAgent = RequestOptions['agent'] | ((parsedUrl: URL) => RequestOptions['agent']);
| RequestOptions['agent']
| ((parsedUrl: URL) => RequestOptions['agent']);
export function getHttpAgent({ export function getHttpAgent({
fetchUrl, fetchUrl,
@ -84,9 +73,7 @@ export function getHttpAgent({
/* eslint-enable @typescript-eslint/no-require-imports */ /* eslint-enable @typescript-eslint/no-require-imports */
if (torPort) { if (torPort) {
return new SocksProxyAgent( return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
`socks5h://tor${retry}@127.0.0.1:${torPort}`,
);
} }
if (!proxyUrl) { if (!proxyUrl) {
@ -95,11 +82,7 @@ export function getHttpAgent({
const isHttps = fetchUrl.includes('https://'); const isHttps = fetchUrl.includes('https://');
if ( if (proxyUrl.includes('socks://') || proxyUrl.includes('socks4://') || proxyUrl.includes('socks5://')) {
proxyUrl.includes('socks://') ||
proxyUrl.includes('socks4://') ||
proxyUrl.includes('socks5://')
) {
return new SocksProxyAgent(proxyUrl); return new SocksProxyAgent(proxyUrl);
} }
@ -184,9 +167,7 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
} }
if (!resp.ok) { if (!resp.ok) {
const errMsg = const errMsg = `Request to ${url} failed with error code ${resp.status}:\n` + (await resp.text());
`Request to ${url} failed with error code ${resp.status}:\n` +
(await resp.text());
throw new Error(errMsg); throw new Error(errMsg);
} }
@ -281,10 +262,7 @@ export type getProviderOptions = fetchDataOptions & {
pollingInterval?: number; pollingInterval?: number;
}; };
export async function getProvider( export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider> {
rpcUrl: string,
fetchOptions?: getProviderOptions,
): Promise<JsonRpcProvider> {
const fetchReq = new FetchRequest(rpcUrl); const fetchReq = new FetchRequest(rpcUrl);
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions); fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
@ -344,9 +322,7 @@ export const populateTransaction = async (
const [feeData, nonce] = await Promise.all([ const [feeData, nonce] = await Promise.all([
tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(), tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(),
tx.nonce tx.nonce ? undefined : provider.getTransactionCount(signer.address, 'pending'),
? undefined
: provider.getTransactionCount(signer.address, 'pending'),
]); ]);
if (feeData) { if (feeData) {
@ -356,10 +332,7 @@ export const populateTransaction = async (
tx.type = 2; tx.type = 2;
} }
tx.maxFeePerGas = tx.maxFeePerGas = (feeData.maxFeePerGas * (BigInt(10000) + BigInt(signer.gasPriceBump))) / BigInt(10000);
(feeData.maxFeePerGas *
(BigInt(10000) + BigInt(signer.gasPriceBump))) /
BigInt(10000);
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas; tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
delete tx.gasPrice; delete tx.gasPrice;
} else if (feeData.gasPrice) { } else if (feeData.gasPrice) {
@ -383,14 +356,10 @@ export const populateTransaction = async (
tx.gasLimit = tx.gasLimit =
gasLimit === BigInt(21000) gasLimit === BigInt(21000)
? gasLimit ? gasLimit
: (gasLimit * : (gasLimit * (BigInt(10000) + BigInt(signer.gasLimitBump))) / BigInt(10000);
(BigInt(10000) + BigInt(signer.gasLimitBump))) /
BigInt(10000);
} catch (error) { } catch (error) {
if (signer.gasFailover) { if (signer.gasFailover) {
console.log( console.log('populateTransaction: warning gas estimation failed falling back to 3M gas');
'populateTransaction: warning gas estimation failed falling back to 3M gas',
);
// Gas failover // Gas failover
tx.gasLimit = BigInt('3000000'); tx.gasLimit = BigInt('3000000');
} else { } else {
@ -418,12 +387,7 @@ export class TornadoWallet extends Wallet {
constructor( constructor(
key: string | SigningKey, key: string | SigningKey,
provider?: Provider, provider?: Provider,
{ { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }: TornadoWalletOptions = {},
gasPriceBump,
gasLimitBump,
gasFailover,
bumpNonce,
}: TornadoWalletOptions = {},
) { ) {
super(key, provider); super(key, provider);
// 10% bump from the recommended fee // 10% bump from the recommended fee
@ -435,23 +399,10 @@ export class TornadoWallet extends Wallet {
this.bumpNonce = bumpNonce ?? false; this.bumpNonce = bumpNonce ?? false;
} }
static fromMnemonic( static fromMnemonic(mneomnic: string, provider: Provider, index = 0, options?: TornadoWalletOptions) {
mneomnic: string,
provider: Provider,
index = 0,
options?: TornadoWalletOptions,
) {
const defaultPath = `m/44'/60'/0'/0/${index}`; const defaultPath = `m/44'/60'/0'/0/${index}`;
const { privateKey } = HDNodeWallet.fromPhrase( const { privateKey } = HDNodeWallet.fromPhrase(mneomnic, undefined, defaultPath);
mneomnic, return new TornadoWallet(privateKey as unknown as SigningKey, provider, options);
undefined,
defaultPath,
);
return new TornadoWallet(
privateKey as unknown as SigningKey,
provider,
options,
);
} }
async populateTransaction(tx: TransactionRequest) { async populateTransaction(tx: TransactionRequest) {
@ -471,12 +422,7 @@ export class TornadoVoidSigner extends VoidSigner {
constructor( constructor(
address: string, address: string,
provider?: Provider, provider?: Provider,
{ { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }: TornadoWalletOptions = {},
gasPriceBump,
gasLimitBump,
gasFailover,
bumpNonce,
}: TornadoWalletOptions = {},
) { ) {
super(address, provider); super(address, provider);
// 10% bump from the recommended fee // 10% bump from the recommended fee
@ -505,12 +451,7 @@ export class TornadoRpcSigner extends JsonRpcSigner {
constructor( constructor(
provider: JsonRpcApiProvider, provider: JsonRpcApiProvider,
address: string, address: string,
{ { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }: TornadoWalletOptions = {},
gasPriceBump,
gasLimitBump,
gasFailover,
bumpNonce,
}: TornadoWalletOptions = {},
) { ) {
super(provider, address); super(provider, address);
// 10% bump from the recommended fee // 10% bump from the recommended fee
@ -523,9 +464,7 @@ export class TornadoRpcSigner extends JsonRpcSigner {
} }
async sendUncheckedTransaction(tx: TransactionRequest) { async sendUncheckedTransaction(tx: TransactionRequest) {
return super.sendUncheckedTransaction( return super.sendUncheckedTransaction(await populateTransaction(this, tx));
await populateTransaction(this, tx),
);
} }
} }
@ -545,11 +484,7 @@ export interface TornadoBrowserProviderOptions extends TornadoWalletOptions {
export class TornadoBrowserProvider extends BrowserProvider { export class TornadoBrowserProvider extends BrowserProvider {
options?: TornadoBrowserProviderOptions; options?: TornadoBrowserProviderOptions;
constructor( constructor(ethereum: Eip1193Provider, network?: Networkish, options?: TornadoBrowserProviderOptions) {
ethereum: Eip1193Provider,
network?: Networkish,
options?: TornadoBrowserProviderOptions,
) {
super(ethereum, network); super(ethereum, network);
this.options = options; this.options = options;
} }
@ -566,24 +501,15 @@ export class TornadoBrowserProvider extends BrowserProvider {
} }
if (this.options?.handleNetworkChanges) { if (this.options?.handleNetworkChanges) {
window?.ethereum?.on( window?.ethereum?.on('chainChanged', this.options.handleNetworkChanges);
'chainChanged',
this.options.handleNetworkChanges,
);
} }
if (this.options?.handleAccountChanges) { if (this.options?.handleAccountChanges) {
window?.ethereum?.on( window?.ethereum?.on('accountsChanged', this.options.handleAccountChanges);
'accountsChanged',
this.options.handleAccountChanges,
);
} }
if (this.options?.handleAccountDisconnect) { if (this.options?.handleAccountDisconnect) {
window?.ethereum?.on( window?.ethereum?.on('disconnect', this.options.handleAccountDisconnect);
'disconnect',
this.options.handleAccountDisconnect,
);
} }
return new TornadoRpcSigner(this, signerAddress, this.options); return new TornadoRpcSigner(this, signerAddress, this.options);

View File

@ -125,10 +125,7 @@ export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
} }
**/ **/
export function calculateScore({ export function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo) {
stakeBalance,
tornadoServiceFee,
}: RelayerInfo) {
if (tornadoServiceFee < MIN_FEE) { if (tornadoServiceFee < MIN_FEE) {
tornadoServiceFee = MIN_FEE; tornadoServiceFee = MIN_FEE;
} else if (tornadoServiceFee >= MAX_FEE) { } else if (tornadoServiceFee >= MAX_FEE) {
@ -137,12 +134,9 @@ export function calculateScore({
const serviceFeeCoefficient = (tornadoServiceFee - MIN_FEE) ** 2; const serviceFeeCoefficient = (tornadoServiceFee - MIN_FEE) ** 2;
const feeDiffCoefficient = 1 / (MAX_FEE - MIN_FEE) ** 2; const feeDiffCoefficient = 1 / (MAX_FEE - MIN_FEE) ** 2;
const coefficientsMultiplier = const coefficientsMultiplier = 1 - feeDiffCoefficient * serviceFeeCoefficient;
1 - feeDiffCoefficient * serviceFeeCoefficient;
return BigInt( return BigInt(Math.floor(Number(stakeBalance || '0') * coefficientsMultiplier));
Math.floor(Number(stakeBalance || '0') * coefficientsMultiplier),
);
} }
export function getWeightRandom(weightsScores: bigint[], random: bigint) { export function getWeightRandom(weightsScores: bigint[], random: bigint) {
@ -227,16 +221,13 @@ export class RelayerClient {
const rawStatus = (await fetchData(`${url}status`, { const rawStatus = (await fetchData(`${url}status`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
headers: { headers: {
'Content-Type': 'Content-Type': 'application/json, application/x-www-form-urlencoded',
'application/json, application/x-www-form-urlencoded',
}, },
timeout: 30000, timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0, maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object; })) as object;
const statusValidator = ajv.compile( const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
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');
@ -255,22 +246,14 @@ export class RelayerClient {
throw new Error('This relayer serves a different network'); throw new Error('This relayer serves a different network');
} }
if ( if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
relayerAddress && throw new Error('The Relayer reward address must match registered address');
this.netId === NetId.MAINNET &&
status.rewardAccount !== relayerAddress
) {
throw new Error(
'The Relayer reward address must match registered address',
);
} }
return status; return status;
} }
async filterRelayer( async filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined> {
relayer: CachedRelayerInfo,
): Promise<RelayerInfo | RelayerError | undefined> {
const hostname = relayer.hostnames[this.netId]; const hostname = relayer.hostnames[this.netId];
const { ensName, relayerAddress } = relayer; const { ensName, relayerAddress } = relayer;
@ -315,11 +298,8 @@ export class RelayerClient {
}> { }> {
const invalidRelayers: RelayerError[] = []; const invalidRelayers: RelayerError[] = [];
const validRelayers = ( const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter(
await Promise.all( (r) => {
relayers.map((relayer) => this.filterRelayer(relayer)),
)
).filter((r) => {
if (!r) { if (!r) {
return false; return false;
} }
@ -328,7 +308,8 @@ export class RelayerClient {
return false; return false;
} }
return true; return true;
}) as RelayerInfo[]; },
) as RelayerInfo[];
return { return {
validRelayers, validRelayers,
@ -342,9 +323,7 @@ export class RelayerClient {
async tornadoWithdraw( async tornadoWithdraw(
{ contract, proof, args }: TornadoWithdrawParams, { contract, proof, args }: TornadoWithdrawParams,
callback?: ( callback?: (jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs) => void,
jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs,
) => void,
) { ) {
const { url } = this.selectedRelayer as RelayerInfo; const { url } = this.selectedRelayer as RelayerInfo;
@ -392,10 +371,7 @@ export class RelayerClient {
console.log(`Job submitted: ${jobUrl}\n`); console.log(`Job submitted: ${jobUrl}\n`);
while ( while (!relayerStatus || !['FAILED', 'CONFIRMED'].includes(relayerStatus)) {
!relayerStatus ||
!['FAILED', 'CONFIRMED'].includes(relayerStatus)
) {
const jobResponse = await fetchData(jobUrl, { const jobResponse = await fetchData(jobUrl, {
...this.fetchDataOptions, ...this.fetchDataOptions,
method: 'GET', method: 'GET',
@ -415,25 +391,18 @@ export class RelayerClient {
throw new Error(errMsg); throw new Error(errMsg);
} }
const { status, txHash, confirmations, failedReason } = const { status, txHash, confirmations, failedReason } = jobResponse as unknown as RelayerTornadoJobs;
jobResponse as unknown as RelayerTornadoJobs;
if (relayerStatus !== status) { if (relayerStatus !== status) {
if (status === 'FAILED') { if (status === 'FAILED') {
const errMsg = `Job ${status}: ${jobUrl} failed reason: ${failedReason}`; const errMsg = `Job ${status}: ${jobUrl} failed reason: ${failedReason}`;
throw new Error(errMsg); throw new Error(errMsg);
} else if (status === 'SENT') { } else if (status === 'SENT') {
console.log( console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}\n`);
`Job ${status}: ${jobUrl}, txhash: ${txHash}\n`,
);
} else if (status === 'MINED') { } else if (status === 'MINED') {
console.log( console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`);
`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`,
);
} else if (status === 'CONFIRMED') { } else if (status === 'CONFIRMED') {
console.log( console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`);
`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`,
);
} else { } else {
console.log(`Job ${status}: ${jobUrl}\n`); console.log(`Job ${status}: ${jobUrl}\n`);
} }

View File

@ -12,9 +12,7 @@ const baseEventsSchemaProperty = {
transactionHash: bytes32SchemaType, transactionHash: bytes32SchemaType,
} as const; } as const;
const baseEventsSchemaRequired = Object.keys( const baseEventsSchemaRequired = Object.keys(baseEventsSchemaProperty) as string[];
baseEventsSchemaProperty,
) as string[];
export const governanceEventsSchema = { export const governanceEventsSchema = {
type: 'array', type: 'array',
@ -76,11 +74,7 @@ export const governanceEventsSchema = {
account: addressSchemaType, account: addressSchemaType,
delegateTo: addressSchemaType, delegateTo: addressSchemaType,
}, },
required: [ required: [...baseEventsSchemaRequired, 'account', 'delegateTo'],
...baseEventsSchemaRequired,
'account',
'delegateTo',
],
additionalProperties: false, additionalProperties: false,
}, },
{ {
@ -91,11 +85,7 @@ export const governanceEventsSchema = {
account: addressSchemaType, account: addressSchemaType,
delegateFrom: addressSchemaType, delegateFrom: addressSchemaType,
}, },
required: [ required: [...baseEventsSchemaRequired, 'account', 'delegateFrom'],
...baseEventsSchemaRequired,
'account',
'delegateFrom',
],
additionalProperties: false, additionalProperties: false,
}, },
], ],
@ -127,13 +117,7 @@ export const depositsEventsSchema = {
timestamp: { type: 'number' }, timestamp: { type: 'number' },
from: addressSchemaType, from: addressSchemaType,
}, },
required: [ required: [...baseEventsSchemaRequired, 'commitment', 'leafIndex', 'timestamp', 'from'],
...baseEventsSchemaRequired,
'commitment',
'leafIndex',
'timestamp',
'from',
],
additionalProperties: false, additionalProperties: false,
}, },
} as const; } as const;
@ -149,13 +133,7 @@ export const withdrawalsEventsSchema = {
fee: bnSchemaType, fee: bnSchemaType,
timestamp: { type: 'number' }, timestamp: { type: 'number' },
}, },
required: [ required: [...baseEventsSchemaRequired, 'nullifierHash', 'to', 'fee', 'timestamp'],
...baseEventsSchemaRequired,
'nullifierHash',
'to',
'fee',
'timestamp',
],
additionalProperties: false, additionalProperties: false,
}, },
} as const; } as const;

View File

@ -129,22 +129,10 @@ const statusSchema: statusSchema = {
onSyncEvents: { type: 'boolean' }, onSyncEvents: { type: 'boolean' },
currentQueue: { type: 'number' }, currentQueue: { type: 'number' },
}, },
required: [ required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health', 'currentQueue'],
'rewardAccount',
'instances',
'netId',
'tornadoServiceFee',
'version',
'health',
'currentQueue',
],
}; };
export function getStatusSchema( export function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean) {
netId: NetIdType,
config: Config,
tovarish: boolean,
) {
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config; const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
// deep copy schema // deep copy schema
@ -152,13 +140,7 @@ export function getStatusSchema(
const instances = Object.keys(tokens).reduce( const instances = Object.keys(tokens).reduce(
(acc: statusInstancesType, token) => { (acc: statusInstancesType, token) => {
const { const { instanceAddress, tokenAddress, symbol, decimals, optionalInstances = [] } = tokens[token];
instanceAddress,
tokenAddress,
symbol,
decimals,
optionalInstances = [],
} = tokens[token];
const amounts = Object.keys(instanceAddress); const amounts = Object.keys(instanceAddress);
const instanceProperties: statusInstanceType = { const instanceProperties: statusInstanceType = {
@ -178,9 +160,7 @@ export function getStatusSchema(
}, },
{}, {},
), ),
required: amounts.filter( required: amounts.filter((amount) => !optionalInstances.includes(amount)),
(amount) => !optionalInstances.includes(amount),
),
}, },
decimals: { enum: [decimals] }, decimals: { enum: [decimals] },
}, },
@ -198,10 +178,7 @@ export function getStatusSchema(
} }
acc.properties[token] = instanceProperties; acc.properties[token] = instanceProperties;
if ( if (!optionalTokens?.includes(token) && !disabledTokens?.includes(token)) {
!optionalTokens?.includes(token) &&
!disabledTokens?.includes(token)
) {
acc.required.push(token); acc.required.push(token);
} }
return acc; return acc;
@ -216,10 +193,7 @@ export function getStatusSchema(
schema.properties.instances = instances; schema.properties.instances = instances;
const _tokens = Object.keys(tokens).filter( const _tokens = Object.keys(tokens).filter(
(t) => (t) => t !== nativeCurrency && !config.optionalTokens?.includes(t) && !config.disabledTokens?.includes(t),
t !== nativeCurrency &&
!config.optionalTokens?.includes(t) &&
!config.disabledTokens?.includes(t),
); );
if (netId === NetId.MAINNET) { if (netId === NetId.MAINNET) {
@ -229,16 +203,10 @@ export function getStatusSchema(
if (_tokens.length) { if (_tokens.length) {
const ethPrices: statusEthPricesType = { const ethPrices: statusEthPricesType = {
type: 'object', type: 'object',
properties: _tokens.reduce( properties: _tokens.reduce((acc: { [key in string]: typeof bnSchemaType }, token: string) => {
(
acc: { [key in string]: typeof bnSchemaType },
token: string,
) => {
acc[token] = bnSchemaType; acc[token] = bnSchemaType;
return acc; return acc;
}, }, {}),
{},
),
required: _tokens, required: _tokens,
}; };
schema.properties.ethPrices = ethPrices; schema.properties.ethPrices = ethPrices;
@ -246,13 +214,7 @@ export function getStatusSchema(
} }
if (tovarish) { if (tovarish) {
schema.required.push( schema.required.push('gasPrices', 'latestBlock', 'latestBalance', 'syncStatus', 'onSyncEvents');
'gasPrices',
'latestBlock',
'latestBalance',
'syncStatus',
'onSyncEvents',
);
} }
return schema; return schema;

View File

@ -61,15 +61,11 @@ export async function getTokenBalances({
const ethResults = multicallResults[0]; const ethResults = multicallResults[0];
const tokenResults = multicallResults.slice(1).length const tokenResults = multicallResults.slice(1).length
? chunk( ? chunk(multicallResults.slice(1), tokenCalls.length / tokenAddresses.length)
multicallResults.slice(1),
tokenCalls.length / tokenAddresses.length,
)
: []; : [];
const tokenBalances = tokenResults.map((tokenResult, index) => { const tokenBalances = tokenResults.map((tokenResult, index) => {
const [tokenBalance, tokenName, tokenSymbol, tokenDecimals] = const [tokenBalance, tokenName, tokenSymbol, tokenDecimals] = tokenResult;
tokenResult;
const tokenAddress = tokenAddresses[index]; const tokenAddress = tokenAddresses[index];
return { return {

View File

@ -138,8 +138,7 @@ export class TovarishClient extends RelayerClient {
const statusArray = (await fetchData(`${url}status`, { const statusArray = (await fetchData(`${url}status`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
headers: { headers: {
'Content-Type': 'Content-Type': 'application/json, application/x-www-form-urlencoded',
'application/json, application/x-www-form-urlencoded',
}, },
timeout: 30000, timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0, maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
@ -182,14 +181,8 @@ export class TovarishClient extends RelayerClient {
throw new Error('This relayer serves a different network'); throw new Error('This relayer serves a different network');
} }
if ( if (relayerAddress && status.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
relayerAddress && throw new Error('The Relayer reward address must match registered address');
status.netId === NetId.MAINNET &&
status.rewardAccount !== relayerAddress
) {
throw new Error(
'The Relayer reward address must match registered address',
);
} }
if (!status.version.includes('tovarish')) { if (!status.version.includes('tovarish')) {
@ -202,11 +195,8 @@ export class TovarishClient extends RelayerClient {
return tovarishStatus; return tovarishStatus;
} }
async filterRelayer( async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> {
relayer: CachedRelayerInfo, const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer;
): Promise<TovarishInfo | RelayerError | undefined> {
const { ensName, relayerAddress, tovarishHost, tovarishNetworks } =
relayer;
if (!tovarishHost || !tovarishNetworks?.includes(this.netId)) { if (!tovarishHost || !tovarishNetworks?.includes(this.netId)) {
return; return;
@ -258,11 +248,8 @@ export class TovarishClient extends RelayerClient {
}> { }> {
const invalidRelayers: RelayerError[] = []; const invalidRelayers: RelayerError[] = [];
const validRelayers = ( const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter(
await Promise.all( (r) => {
relayers.map((relayer) => this.filterRelayer(relayer)),
)
).filter((r) => {
if (!r) { if (!r) {
return false; return false;
} }
@ -271,7 +258,8 @@ export class TovarishClient extends RelayerClient {
return false; return false;
} }
return true; return true;
}) as TovarishInfo[]; },
) as TovarishInfo[];
return { return {
validRelayers, validRelayers,
@ -306,9 +294,7 @@ export class TovarishClient extends RelayerClient {
ensName, ensName,
relayerAddress, relayerAddress,
rewardAccount: getAddress(status.rewardAccount), rewardAccount: getAddress(status.rewardAccount),
instances: getSupportedInstances( instances: getSupportedInstances(status.instances),
status.instances,
),
stakeBalance: relayer.stakeBalance, stakeBalance: relayer.stakeBalance,
gasPrice: status.gasPrices?.fast, gasPrice: status.gasPrices?.fast,
ethPrices: status.ethPrices, ethPrices: status.ethPrices,
@ -358,8 +344,7 @@ export class TovarishClient extends RelayerClient {
// eslint-disable-next-line no-constant-condition // eslint-disable-next-line no-constant-condition
while (true) { while (true) {
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let { events: fetchedEvents, lastSyncBlock: currentBlock } = let { events: fetchedEvents, lastSyncBlock: currentBlock } = (await fetchData(url, {
(await fetchData(url, {
...this.fetchDataOptions, ...this.fetchDataOptions,
method: 'POST', method: 'POST',
headers: { headers: {
@ -406,9 +391,7 @@ export class TovarishClient extends RelayerClient {
break; break;
} }
fetchedEvents = fetchedEvents.filter( fetchedEvents = fetchedEvents.filter((e) => e.blockNumber !== lastEvent.blockNumber);
(e) => e.blockNumber !== lastEvent.blockNumber,
);
fromBlock = Number(lastEvent.blockNumber); fromBlock = Number(lastEvent.blockNumber);
events.push(...fetchedEvents); events.push(...fetchedEvents);

View File

@ -16,14 +16,10 @@ export const isNode =
} }
).browser && typeof globalThis.window === 'undefined'; ).browser && typeof globalThis.window === 'undefined';
export const crypto = isNode export const crypto = isNode ? webcrypto : (globalThis.crypto as typeof webcrypto);
? webcrypto
: (globalThis.crypto as typeof webcrypto);
export const chunk = <T>(arr: T[], size: number): T[][] => export const chunk = <T>(arr: T[], size: number): T[][] =>
[...Array(Math.ceil(arr.length / size))].map((_, i) => [...Array(Math.ceil(arr.length / size))].map((_, i) => arr.slice(size * i, size + size * i));
arr.slice(size * i, size + size * i),
);
export function sleep(ms: number) { export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
@ -33,9 +29,7 @@ export function validateUrl(url: string, protocols?: string[]) {
try { try {
const parsedUrl = new URL(url); const parsedUrl = new URL(url);
if (protocols && protocols.length) { if (protocols && protocols.length) {
return protocols return protocols.map((p) => p.toLowerCase()).includes(parsedUrl.protocol);
.map((p) => p.toLowerCase())
.includes(parsedUrl.protocol);
} }
return true; return true;
} catch { } catch {
@ -60,9 +54,7 @@ export function bufferToBytes(b: Buffer) {
} }
export function bytesToBase64(bytes: Uint8Array) { export function bytesToBase64(bytes: Uint8Array) {
return btoa( return btoa(bytes.reduce((data, byte) => data + String.fromCharCode(byte), ''));
bytes.reduce((data, byte) => data + String.fromCharCode(byte), ''),
);
} }
export function base64ToBytes(base64: string) { export function base64ToBytes(base64: string) {
@ -85,11 +77,7 @@ export function hexToBytes(hexString: string) {
if (hexString.length % 2 !== 0) { if (hexString.length % 2 !== 0) {
hexString = '0' + hexString; hexString = '0' + hexString;
} }
return Uint8Array.from( return Uint8Array.from((hexString.match(/.{1,2}/g) as string[]).map((byte) => parseInt(byte, 16)));
(hexString.match(/.{1,2}/g) as string[]).map((byte) =>
parseInt(byte, 16),
),
);
} }
// Convert BE encoded bytes (Buffer | Uint8Array) array to BigInt // Convert BE encoded bytes (Buffer | Uint8Array) array to BigInt
@ -100,8 +88,7 @@ export function bytesToBN(bytes: Uint8Array) {
// Convert BigInt to BE encoded Uint8Array type // Convert BigInt to BE encoded Uint8Array type
export function bnToBytes(bigint: bigint | string) { export function bnToBytes(bigint: bigint | string) {
// Parse bigint to hex string // Parse bigint to hex string
let hexString: string = let hexString: string = typeof bigint === 'bigint' ? bigint.toString(16) : bigint;
typeof bigint === 'bigint' ? bigint.toString(16) : bigint;
// Remove hex string prefix if exists // Remove hex string prefix if exists
if (hexString.slice(0, 2) === '0x') { if (hexString.slice(0, 2) === '0x') {
hexString = hexString.slice(2); hexString = hexString.slice(2);
@ -110,11 +97,7 @@ export function bnToBytes(bigint: bigint | string) {
if (hexString.length % 2 !== 0) { if (hexString.length % 2 !== 0) {
hexString = '0' + hexString; hexString = '0' + hexString;
} }
return Uint8Array.from( return Uint8Array.from((hexString.match(/.{1,2}/g) as string[]).map((byte) => parseInt(byte, 16)));
(hexString.match(/.{1,2}/g) as string[]).map((byte) =>
parseInt(byte, 16),
),
);
} }
// Convert LE encoded bytes (Buffer | Uint8Array) array to BigInt // Convert LE encoded bytes (Buffer | Uint8Array) array to BigInt
@ -169,10 +152,7 @@ export async function digest(bytes: Uint8Array, algo: string = 'SHA-384') {
return new Uint8Array(await crypto.subtle.digest(algo, bytes)); return new Uint8Array(await crypto.subtle.digest(algo, bytes));
} }
export function numberFormatter( export function numberFormatter(num: string | number | bigint, digits: number = 3): string {
num: string | number | bigint,
digits: number = 3,
): string {
const lookup = [ const lookup = [
{ value: 1, symbol: '' }, { value: 1, symbol: '' },
{ value: 1e3, symbol: 'K' }, { value: 1e3, symbol: 'K' },
@ -187,12 +167,7 @@ export function numberFormatter(
.slice() .slice()
.reverse() .reverse()
.find((item) => Number(num) >= item.value); .find((item) => Number(num) >= item.value);
return item return item ? (Number(num) / item.value).toFixed(digits).replace(regexp, '').concat(item.symbol) : '0';
? (Number(num) / item.value)
.toFixed(digits)
.replace(regexp, '')
.concat(item.symbol)
: '0';
} }
export function isHex(value: string) { export function isHex(value: string) {

View File

@ -69,12 +69,7 @@ export async function calculateSnarkProof(
console.log('Start generating SNARK proof', snarkInput); console.log('Start generating SNARK proof', snarkInput);
console.time('SNARK proof time'); console.time('SNARK proof time');
const proofData = await websnarkUtils.genWitnessAndProve( const proofData = await websnarkUtils.genWitnessAndProve(await groth16, snarkInput, circuit, provingKey);
await groth16,
snarkInput,
circuit,
provingKey,
);
const proof = websnarkUtils.toSolidityInput(proofData).proof; const proof = websnarkUtils.toSolidityInput(proofData).proof;
console.timeEnd('SNARK proof time'); console.timeEnd('SNARK proof time');

View File

@ -58,9 +58,7 @@ export async function downloadZip<T>({
const { [zipName]: content } = await unzipAsync(data); const { [zipName]: content } = await unzipAsync(data);
console.log( console.log(`Downloaded ${url}${zipDigest ? ` ( Digest: ${zipDigest} )` : ''}`);
`Downloaded ${url}${zipDigest ? ` ( Digest: ${zipDigest} )` : ''}`,
);
if (parseJson) { if (parseJson) {
return JSON.parse(new TextDecoder().decode(content)) as T; return JSON.parse(new TextDecoder().decode(content)) as T;

View File

@ -15,17 +15,11 @@ describe('./src/deposit.ts', function () {
const instanceFixture = async () => { const instanceFixture = async () => {
const [owner] = await getSigners(); const [owner] = await getSigners();
const Hasher = (await (await deployHasher(owner)).wait()) const Hasher = (await (await deployHasher(owner)).wait())?.contractAddress as string;
?.contractAddress as string;
const Verifier = await new Verifier__factory(owner).deploy(); const Verifier = await new Verifier__factory(owner).deploy();
const Instance = await new ETHTornado__factory(owner).deploy( const Instance = await new ETHTornado__factory(owner).deploy(Verifier.target, Hasher, 1n, 20);
Verifier.target,
Hasher,
1n,
20,
);
return { Instance }; return { Instance };
}; };
@ -47,9 +41,7 @@ describe('./src/deposit.ts', function () {
value: 1n, value: 1n,
}); });
await expect(resp) await expect(resp).to.emit(Instance, 'Deposit').withArgs(deposit.commitmentHex, 0, anyValue);
.to.emit(Instance, 'Deposit')
.withArgs(deposit.commitmentHex, 0, anyValue);
expect(await Instance.commitments(deposit.commitmentHex)).to.be.true; expect(await Instance.commitments(deposit.commitmentHex)).to.be.true;
}); });