Compare commits

..

2 Commits

Author SHA1 Message Date
f3a8438187
built files 2024-10-16 14:19:49 +00:00
666b0eba66
es2022, use interfaces, minor func addition 2024-10-16 14:17:22 +00:00
46 changed files with 10218 additions and 10295 deletions

4
dist/batch.d.ts vendored

@ -62,11 +62,11 @@ export type BatchEventOnProgress = ({ percentage, type, fromBlock, toBlock, coun
toBlock?: number; toBlock?: number;
count?: number; count?: number;
}) => void; }) => void;
export type EventInput = { export interface EventInput {
fromBlock: number; fromBlock: number;
toBlock: number; toBlock: number;
type: ContractEventName; type: ContractEventName;
}; }
/** /**
* Fetch events from web3 provider on bulk * Fetch events from web3 provider on bulk
*/ */

32
dist/deposits.d.ts vendored

@ -1,36 +1,28 @@
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
export type DepositType = { export interface DepositType {
currency: string; currency: string;
amount: string; amount: string;
netId: NetIdType; netId: NetIdType;
}; }
export type createDepositParams = { export interface createDepositParams {
nullifier: bigint; nullifier: bigint;
secret: bigint; secret: bigint;
}; }
export type createDepositObject = { export interface createDepositObject {
preimage: Uint8Array; preimage: Uint8Array;
noteHex: string; noteHex: string;
commitment: bigint; commitment: bigint;
commitmentHex: string; commitmentHex: string;
nullifierHash: bigint; nullifierHash: bigint;
nullifierHex: string; nullifierHex: string;
}; }
export type createNoteParams = DepositType & { export interface createNoteParams extends DepositType {
nullifier?: bigint; nullifier?: bigint;
secret?: bigint; secret?: bigint;
}; }
export type parsedNoteExec = DepositType & { export interface parsedNoteExec extends DepositType {
note: string; note: string;
}; }
export type depositTx = {
from: string;
transactionHash: string;
};
export type withdrawalTx = {
to: string;
transactionHash: string;
};
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;
@ -60,9 +52,9 @@ export declare class Deposit {
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 type parsedInvoiceExec = DepositType & { export interface parsedInvoiceExec extends DepositType {
commitment: string; commitment: string;
}; }
export declare class Invoice { export declare class Invoice {
currency: string; currency: string;
amount: string; amount: string;

75
dist/events/base.d.ts vendored

@ -8,29 +8,29 @@ import type { TovarishClient } from '../tovarishClient';
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types'; import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types';
export declare const DEPOSIT = "deposit"; export declare const DEPOSIT = "deposit";
export declare const WITHDRAWAL = "withdrawal"; export declare const WITHDRAWAL = "withdrawal";
export type BaseEventsServiceConstructor = { export interface BaseEventsServiceConstructor {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
graphApi?: string; graphApi?: string;
subgraphName?: string; subgraphName?: string;
contract: BaseContract; contract: BaseContract;
type?: string; type: string;
deployedBlock?: number; deployedBlock?: number;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient; tovarishClient?: TovarishClient;
}; }
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: { export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
type?: ContractEventName; type?: ContractEventName;
fromBlock?: number; fromBlock?: number;
toBlock?: number; toBlock?: number;
count?: number; count?: number;
}) => void; }) => void;
export type BaseGraphParams = { export interface BaseGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
onProgress?: BatchGraphOnProgress; onProgress?: BatchGraphOnProgress;
}; }
export declare class BaseEventsService<EventType extends MinimalEvents> { export declare class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
@ -89,29 +89,20 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
lastBlock: number; lastBlock: number;
}>; }>;
} }
export type BaseTornadoServiceConstructor = { export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Tornado: Tornado; Tornado: Tornado;
type: string;
amount: string; amount: string;
currency: string; currency: string;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions; export interface DepositsGraphParams extends BaseGraphParams {
tovarishClient?: TovarishClient;
};
export type DepositsGraphParams = BaseGraphParams & {
amount: string; amount: string;
currency: string; currency: string;
}; }
export declare class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> { export declare class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string; amount: string;
currency: string; currency: string;
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService; batchBlockService: BatchBlockService;
tovarishClient?: TovarishClient;
constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, tovarishClient, }: BaseTornadoServiceConstructor); constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, tovarishClient, }: BaseTornadoServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getGraphMethod(): string; getGraphMethod(): string;
@ -124,59 +115,35 @@ export declare class BaseTornadoService extends BaseEventsService<DepositsEvents
fromBlock: number; fromBlock: number;
}): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>; }): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
} }
export type BaseEchoServiceConstructor = { export interface BaseEchoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Echoer: Echoer; Echoer: Echoer;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export declare class BaseEchoService extends BaseEventsService<EchoEvents> { export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEchoServiceConstructor); constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEchoServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getType(): 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>>;
} }
export type BaseEncryptedNotesServiceConstructor = { export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Router: TornadoRouter | TornadoProxyLight; Router: TornadoRouter | TornadoProxyLight;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export declare class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> { export declare class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
constructor({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEncryptedNotesServiceConstructor); constructor({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEncryptedNotesServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getType(): string;
getTovarishType(): string; getTovarishType(): string;
getGraphMethod(): string; getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>; formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
} }
export type BaseGovernanceServiceConstructor = { export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Governance: Governance; Governance: Governance;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> { export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, tovarishClient, }: BaseGovernanceServiceConstructor); constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, tovarishClient, }: BaseGovernanceServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getType(): string;
getTovarishType(): string; getTovarishType(): string;
getGraphMethod(): string; getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>; formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
@ -204,25 +171,17 @@ export interface CachedRelayers {
relayers: CachedRelayerInfo[]; relayers: CachedRelayerInfo[];
fromCache?: boolean; fromCache?: boolean;
} }
export type BaseRegistryServiceConstructor = { export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export declare class BaseRegistryService extends BaseEventsService<RegistersEvents> { export declare class BaseRegistryService extends BaseEventsService<RegistersEvents> {
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
updateInterval: number; updateInterval: number;
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, tovarishClient, }: BaseRegistryServiceConstructor); constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, tovarishClient, }: BaseRegistryServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getType(): string;
getTovarishType(): string; getTovarishType(): string;
getGraphMethod(): string; getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<{ formatEvents(events: EventLog[]): Promise<{

@ -15,51 +15,51 @@ export interface MinimalEvents {
logIndex: number; logIndex: number;
transactionHash: string; transactionHash: string;
} }
export type GovernanceEvents = MinimalEvents & { export interface GovernanceEvents extends MinimalEvents {
event: string; event: string;
}; }
export type GovernanceProposalCreatedEvents = GovernanceEvents & { export interface GovernanceProposalCreatedEvents extends GovernanceEvents {
id: number; id: number;
proposer: string; proposer: string;
target: string; target: string;
startTime: number; startTime: number;
endTime: number; endTime: number;
description: string; description: string;
}; }
export type GovernanceVotedEvents = GovernanceEvents & { export interface GovernanceVotedEvents extends GovernanceEvents {
proposalId: number; proposalId: number;
voter: string; voter: string;
support: boolean; support: boolean;
votes: string; votes: string;
from: string; from: string;
input: string; input: string;
}; }
export type GovernanceDelegatedEvents = GovernanceEvents & { export interface GovernanceDelegatedEvents extends GovernanceEvents {
account: string; account: string;
delegateTo: string; delegateTo: string;
}; }
export type GovernanceUndelegatedEvents = GovernanceEvents & { export interface GovernanceUndelegatedEvents extends GovernanceEvents {
account: string; account: string;
delegateFrom: string; delegateFrom: string;
}; }
export type AllGovernanceEvents = GovernanceProposalCreatedEvents | GovernanceVotedEvents | GovernanceDelegatedEvents | GovernanceUndelegatedEvents; export type AllGovernanceEvents = GovernanceProposalCreatedEvents | GovernanceVotedEvents | GovernanceDelegatedEvents | GovernanceUndelegatedEvents;
export type RegistersEvents = MinimalEvents & RelayerParams; export type RegistersEvents = MinimalEvents & RelayerParams;
export type DepositsEvents = MinimalEvents & { export interface DepositsEvents extends MinimalEvents {
commitment: string; commitment: string;
leafIndex: number; leafIndex: number;
timestamp: number; timestamp: number;
from: string; from: string;
}; }
export type WithdrawalsEvents = MinimalEvents & { export interface WithdrawalsEvents extends MinimalEvents {
nullifierHash: string; nullifierHash: string;
to: string; to: string;
fee: string; fee: string;
timestamp: number; timestamp: number;
}; }
export type EchoEvents = MinimalEvents & { export interface EchoEvents extends MinimalEvents {
address: string; address: string;
encryptedAccount: string; encryptedAccount: string;
}; }
export type EncryptedNotesEvents = MinimalEvents & { export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string; encryptedNote: string;
}; }

13
dist/gaszip.d.ts vendored Normal file

@ -0,0 +1,13 @@
import { NetIdType } from './networkConfig';
export declare const gasZipInbounds: {
[key in NetIdType]: string;
};
export declare const gasZipID: {
[key in NetIdType]: number;
};
export declare function gasZipInput(to: string, shorts: number[]): string | null;
export declare function gasZipMinMax(ethUsd: number): {
min: number;
max: number;
ethUsd: number;
};

@ -1,7 +1,7 @@
import { fetchDataOptions } from '../providers'; import { fetchDataOptions } from '../providers';
import type { BaseGraphEvents, RegistersEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, BatchGraphOnProgress, EchoEvents, AllGovernanceEvents } from '../events'; import type { BaseGraphEvents, RegistersEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, BatchGraphOnProgress, EchoEvents, AllGovernanceEvents } from '../events';
export * from './queries'; export * from './queries';
export type queryGraphParams = { export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
query: string; query: string;
@ -9,7 +9,7 @@ export type queryGraphParams = {
[key: string]: string | number; [key: string]: string | number;
}; };
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
}; }
export declare function queryGraph<T>({ graphApi, subgraphName, query, variables, fetchDataOptions, }: queryGraphParams): Promise<T>; export declare function queryGraph<T>({ graphApi, subgraphName, query, variables, fetchDataOptions, }: queryGraphParams): Promise<T>;
export interface GraphStatistic { export interface GraphStatistic {
deposits: { deposits: {

1
dist/index.d.ts vendored

@ -6,6 +6,7 @@ export * from './batch';
export * from './deposits'; export * from './deposits';
export * from './encryptedNotes'; export * from './encryptedNotes';
export * from './fees'; export * from './fees';
export * from './gaszip';
export * from './idb'; export * from './idb';
export * from './merkleTree'; export * from './merkleTree';
export * from './mimc'; export * from './mimc';

5417
dist/index.js vendored

File diff suppressed because it is too large Load Diff

5412
dist/index.mjs vendored

File diff suppressed because it is too large Load Diff

@ -3,13 +3,13 @@ import type { Tornado } from '@tornado/contracts';
import type { DepositType } from './deposits'; import type { DepositType } from './deposits';
import type { DepositsEvents } from './events'; import type { DepositsEvents } from './events';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
export type MerkleTreeConstructor = DepositType & { export interface MerkleTreeConstructor extends DepositType {
Tornado: Tornado; Tornado: Tornado;
commitmentHex?: string; commitmentHex?: string;
merkleTreeHeight?: number; merkleTreeHeight?: number;
emptyElement?: string; emptyElement?: string;
merkleWorkerPath?: string; merkleWorkerPath?: string;
}; }
export declare class MerkleTreeService { export declare class MerkleTreeService {
currency: string; currency: string;
amount: string; amount: string;

@ -1805,47 +1805,23 @@ class MimcSponge {
} }
} }
var __async$1 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
class Mimc { class Mimc {
sponge;
hash;
mimcPromise;
constructor() { constructor() {
this.mimcPromise = this.initMimc(); this.mimcPromise = this.initMimc();
} }
initMimc() { async initMimc() {
return __async$1(this, null, function* () { this.sponge = await buildMimcSponge();
this.sponge = yield buildMimcSponge(); this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
this.hash = (left, right) => {
var _a, _b;
return (_b = this.sponge) == null ? void 0 : _b.F.toString((_a = this.sponge) == null ? void 0 : _a.multiHash([BigInt(left), BigInt(right)]));
};
});
} }
getHash() { async getHash() {
return __async$1(this, null, function* () { await this.mimcPromise;
yield this.mimcPromise; return {
return { sponge: this.sponge,
sponge: this.sponge, hash: this.hash
hash: this.hash };
};
});
} }
} }
const mimc = new Mimc(); const mimc = new Mimc();
@ -1855,56 +1831,34 @@ BigInt.prototype.toJSON = function() {
}; };
const isNode = !process.browser && typeof globalThis.window === "undefined"; const isNode = !process.browser && typeof globalThis.window === "undefined";
var __async = (__this, __arguments, generator) => { async function nodePostWork() {
return new Promise((resolve, reject) => { const { hash: hashFunction } = await mimc.getHash();
var fulfilled = (value) => { const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData;
try { if (edge) {
step(generator.next(value)); const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, {
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
function nodePostWork() {
return __async(this, null, function* () {
const { hash: hashFunction } = yield mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData;
if (edge) {
const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, {
zeroElement,
hashFunction
});
workerThreads.parentPort.postMessage(merkleTree2.toString());
return;
}
const merkleTree = new libExports.MerkleTree(merkleTreeHeight, elements, {
zeroElement, zeroElement,
hashFunction hashFunction
}); });
workerThreads.parentPort.postMessage(merkleTree.toString()); workerThreads.parentPort.postMessage(merkleTree2.toString());
return;
}
const merkleTree = new libExports.MerkleTree(merkleTreeHeight, elements, {
zeroElement,
hashFunction
}); });
workerThreads.parentPort.postMessage(merkleTree.toString());
} }
if (isNode && workerThreads) { if (isNode && workerThreads) {
nodePostWork(); nodePostWork();
} else if (!isNode && typeof addEventListener === "function" && typeof postMessage === "function") { } else if (!isNode && typeof addEventListener === "function" && typeof postMessage === "function") {
addEventListener("message", (e) => __async(undefined, null, function* () { addEventListener("message", async (e) => {
let data; let data;
if (e.data) { if (e.data) {
data = e.data; data = e.data;
} else { } else {
data = e; data = e;
} }
const { hash: hashFunction } = yield 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(merkleTreeHeight, edge, elements, { const merkleTree2 = new libExports.PartialMerkleTree(merkleTreeHeight, edge, elements, {
@ -1919,7 +1873,7 @@ if (isNode && workerThreads) {
hashFunction hashFunction
}); });
postMessage(merkleTree.toString()); postMessage(merkleTree.toString());
})); });
} else { } else {
throw new Error("This browser / environment does not support workers!"); throw new Error("This browser / environment does not support workers!");
} }

@ -101976,48 +101976,24 @@ const poseidonContract=(/* unused pure expression or super */ null && (_poseidon
;// ./src/mimc.ts ;// ./src/mimc.ts
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
class Mimc { class Mimc {
sponge;
hash;
mimcPromise;
constructor() { constructor() {
this.mimcPromise = this.initMimc(); this.mimcPromise = this.initMimc();
} }
initMimc() { async initMimc() {
return __async(this, null, function* () { this.sponge = await mimcsponge_buildMimcSponge();
this.sponge = yield mimcsponge_buildMimcSponge(); this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
this.hash = (left, right) => {
var _a, _b;
return (_b = this.sponge) == null ? void 0 : _b.F.toString((_a = this.sponge) == null ? void 0 : _a.multiHash([BigInt(left), BigInt(right)]));
};
});
} }
getHash() { async getHash() {
return __async(this, null, function* () { await this.mimcPromise;
yield this.mimcPromise; return {
return { sponge: this.sponge,
sponge: this.sponge, hash: this.hash
hash: this.hash };
};
});
} }
} }
const mimc = new Mimc(); const mimc = new Mimc();
@ -102028,26 +102004,6 @@ var crypto_browserify = __webpack_require__(1565);
var bn = __webpack_require__(9404); var bn = __webpack_require__(9404);
;// ./src/utils.ts ;// ./src/utils.ts
var utils_async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
BigInt.prototype.toJSON = function() { BigInt.prototype.toJSON = function() {
@ -102066,7 +102022,7 @@ function validateUrl(url, protocols) {
return protocols.map((p) => p.toLowerCase()).includes(parsedUrl.protocol); return protocols.map((p) => p.toLowerCase()).includes(parsedUrl.protocol);
} }
return true; return true;
} catch (e) { } catch {
return false; return false;
} }
} }
@ -102138,68 +102094,44 @@ function substring(str, length = 10) {
} }
return `${str.substring(0, length)}...${str.substring(str.length - length)}`; return `${str.substring(0, length)}...${str.substring(str.length - length)}`;
} }
function digest(bytes, algo = "SHA-384") { async function digest(bytes, algo = "SHA-384") {
return utils_async(this, null, function* () { return new Uint8Array(await utils_crypto.subtle.digest(algo, bytes));
return new Uint8Array(yield utils_crypto.subtle.digest(algo, bytes));
});
} }
;// ./src/merkleTreeWorker.ts ;// ./src/merkleTreeWorker.ts
var merkleTreeWorker_async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
function nodePostWork() { async function nodePostWork() {
return merkleTreeWorker_async(this, null, function* () { const { hash: hashFunction } = await mimc.getHash();
const { hash: hashFunction } = yield 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(merkleTreeHeight, edge, elements, {
const merkleTree2 = new lib.PartialMerkleTree(merkleTreeHeight, edge, elements, {
zeroElement,
hashFunction
});
worker_threads_ignored_default().parentPort.postMessage(merkleTree2.toString());
return;
}
const merkleTree = new lib.MerkleTree(merkleTreeHeight, elements, {
zeroElement, zeroElement,
hashFunction hashFunction
}); });
worker_threads_ignored_default().parentPort.postMessage(merkleTree.toString()); worker_threads_ignored_default().parentPort.postMessage(merkleTree2.toString());
return;
}
const merkleTree = new lib.MerkleTree(merkleTreeHeight, elements, {
zeroElement,
hashFunction
}); });
worker_threads_ignored_default().parentPort.postMessage(merkleTree.toString());
} }
if (isNode && (worker_threads_ignored_default())) { if (isNode && (worker_threads_ignored_default())) {
nodePostWork(); nodePostWork();
} else if (!isNode && typeof addEventListener === "function" && typeof postMessage === "function") { } else if (!isNode && typeof addEventListener === "function" && typeof postMessage === "function") {
addEventListener("message", (e) => merkleTreeWorker_async(undefined, null, function* () { addEventListener("message", async (e) => {
let data; let data;
if (e.data) { if (e.data) {
data = e.data; data = e.data;
} else { } else {
data = e; data = e;
} }
const { hash: hashFunction } = yield 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(merkleTreeHeight, edge, elements, { const merkleTree2 = new lib.PartialMerkleTree(merkleTreeHeight, edge, elements, {
@ -102214,7 +102146,7 @@ if (isNode && (worker_threads_ignored_default())) {
hashFunction hashFunction
}); });
postMessage(merkleTree.toString()); postMessage(merkleTree.toString());
})); });
} else { } else {
throw new Error("This browser / environment does not support workers!"); throw new Error("This browser / environment does not support workers!");
} }

File diff suppressed because one or more lines are too long

@ -16,19 +16,19 @@ export interface RpcUrl {
name: string; name: string;
url: string; url: string;
} }
export type RpcUrls = { export interface RpcUrls {
[key in string]: RpcUrl; [key: string]: RpcUrl;
}; }
export interface SubgraphUrl { export interface SubgraphUrl {
name: string; name: string;
url: string; url: string;
} }
export type SubgraphUrls = { export interface SubgraphUrls {
[key in string]: SubgraphUrl; [key: string]: SubgraphUrl;
}; }
export type TornadoInstance = { export interface TornadoInstance {
instanceAddress: { instanceAddress: {
[key in string]: string; [key: string]: string;
}; };
optionalInstances?: string[]; optionalInstances?: string[];
tokenAddress?: string; tokenAddress?: string;
@ -36,11 +36,11 @@ export type TornadoInstance = {
symbol: string; symbol: string;
decimals: number; decimals: number;
gasLimit?: number; gasLimit?: number;
}; }
export type TokenInstances = { export interface TokenInstances {
[key in string]: TornadoInstance; [key: string]: TornadoInstance;
}; }
export type Config = { export interface Config {
rpcCallRetryAttempt?: number; rpcCallRetryAttempt?: number;
gasPrices: { gasPrices: {
instant: number; instant: number;
@ -57,6 +57,7 @@ export type Config = {
networkName: string; networkName: string;
deployedBlock: number; deployedBlock: number;
rpcUrls: RpcUrls; rpcUrls: RpcUrls;
stablecoin: string;
multicallContract: string; multicallContract: string;
routerContract: string; routerContract: string;
echoContract: string; echoContract: string;
@ -84,13 +85,13 @@ export type Config = {
REGISTRY_BLOCK?: number; REGISTRY_BLOCK?: number;
MINING_BLOCK_TIME?: number; MINING_BLOCK_TIME?: number;
}; };
}; }
export type networkConfig = { export interface networkConfig {
[key in NetIdType]: Config; [key: NetIdType]: Config;
}; }
export type SubdomainMap = { export interface SubdomainMap {
[key in NetIdType]: string; [key: NetIdType]: string;
}; }
export declare const defaultConfig: networkConfig; export declare const defaultConfig: networkConfig;
export declare const enabledChains: NetIdType[]; export declare const enabledChains: NetIdType[];
/** /**

10
dist/prices.d.ts vendored

@ -1,12 +1,20 @@
import { type Provider } from 'ethers'; import { type Provider } from 'ethers';
import type { OffchainOracle, Multicall } from './typechain'; import { OffchainOracle, Multicall } from './typechain';
import { Call3 } from './multicall';
export declare class TokenPriceOracle { export declare class TokenPriceOracle {
oracle?: OffchainOracle; oracle?: OffchainOracle;
multicall: Multicall; multicall: Multicall;
provider: Provider; provider: Provider;
constructor(provider: Provider, multicall: Multicall, oracle?: OffchainOracle); constructor(provider: Provider, multicall: Multicall, oracle?: OffchainOracle);
buildCalls(tokens: {
tokenAddress: string;
decimals: number;
}[]): Call3[];
buildStable(stablecoinAddress: string): Call3[];
fetchPrice(tokenAddress: string, decimals: number): Promise<bigint>;
fetchPrices(tokens: { fetchPrices(tokens: {
tokenAddress: string; tokenAddress: string;
decimals: number; decimals: number;
}[]): Promise<bigint[]>; }[]): Promise<bigint[]>;
fetchEthUSD(stablecoinAddress: string): Promise<number>;
} }

8
dist/providers.d.ts vendored

@ -38,12 +38,12 @@ export type getProviderOptions = fetchDataOptions & {
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>; export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider; export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>; export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
export type TornadoWalletOptions = { export interface TornadoWalletOptions {
gasPriceBump?: number; gasPriceBump?: number;
gasLimitBump?: number; gasLimitBump?: number;
gasFailover?: boolean; gasFailover?: boolean;
bumpNonce?: boolean; bumpNonce?: boolean;
}; }
export declare class TornadoWallet extends Wallet { export declare class TornadoWallet extends Wallet {
nonce?: number; nonce?: number;
gasPriceBump: number; gasPriceBump: number;
@ -74,13 +74,13 @@ export declare class TornadoRpcSigner extends JsonRpcSigner {
} }
export type connectWalletFunc = (...args: any[]) => Promise<void>; export type connectWalletFunc = (...args: any[]) => Promise<void>;
export type handleWalletFunc = (...args: any[]) => void; export type handleWalletFunc = (...args: any[]) => void;
export type TornadoBrowserProviderOptions = TornadoWalletOptions & { export interface TornadoBrowserProviderOptions extends TornadoWalletOptions {
netId?: NetIdType; netId?: NetIdType;
connectWallet?: connectWalletFunc; connectWallet?: connectWalletFunc;
handleNetworkChanges?: handleWalletFunc; handleNetworkChanges?: handleWalletFunc;
handleAccountChanges?: handleWalletFunc; handleAccountChanges?: handleWalletFunc;
handleAccountDisconnect?: handleWalletFunc; handleAccountDisconnect?: handleWalletFunc;
}; }
export declare class TornadoBrowserProvider extends BrowserProvider { export declare class TornadoBrowserProvider extends BrowserProvider {
options?: TornadoBrowserProviderOptions; options?: TornadoBrowserProviderOptions;
constructor(ethereum: Eip1193Provider, network?: Networkish, options?: TornadoBrowserProviderOptions); constructor(ethereum: Eip1193Provider, network?: Networkish, options?: TornadoBrowserProviderOptions);

@ -12,7 +12,7 @@ export interface RelayerParams {
/** /**
* Info from relayer status * Info from relayer status
*/ */
export type RelayerInfo = RelayerParams & { export interface RelayerInfo extends RelayerParams {
netId: NetIdType; netId: NetIdType;
url: string; url: string;
hostname: string; hostname: string;
@ -25,13 +25,13 @@ export type RelayerInfo = RelayerParams & {
}; };
currentQueue: number; currentQueue: number;
tornadoServiceFee: number; tornadoServiceFee: number;
}; }
export type RelayerError = { export interface RelayerError {
hostname: string; hostname: string;
relayerAddress?: string; relayerAddress?: string;
errorMessage?: string; errorMessage?: string;
hasError: boolean; hasError: boolean;
}; }
export interface RelayerStatus { export interface RelayerStatus {
url: string; url: string;
rewardAccount: string; rewardAccount: string;
@ -63,9 +63,9 @@ export interface RelayerStatus {
}; };
currentQueue: number; currentQueue: number;
} }
export type TornadoWithdrawParams = snarkProofs & { export interface TornadoWithdrawParams extends snarkProofs {
contract: string; contract: string;
}; }
export interface RelayerTornadoWithdraw { export interface RelayerTornadoWithdraw {
id?: string; id?: string;
error?: string; error?: string;
@ -111,13 +111,13 @@ export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
**/ **/
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 type RelayerInstanceList = { export interface RelayerInstanceList {
[key in string]: { [key: string]: {
instanceAddress: { instanceAddress: {
[key in string]: string; [key: string]: string;
}; };
}; };
}; }
export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[]; export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[];
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo; export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
export interface RelayerClientConstructor { export interface RelayerClientConstructor {
@ -143,5 +143,5 @@ export declare class RelayerClient {
invalidRelayers: RelayerError[]; invalidRelayers: RelayerError[];
}>; }>;
pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo; pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
tornadoWithdraw({ contract, proof, args }: TornadoWithdrawParams, callback?: (jobResp: RelayerTornadoJobs) => void): Promise<void>; tornadoWithdraw({ contract, proof, args }: TornadoWithdrawParams, callback?: (jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs) => void): Promise<void>;
} }

@ -1,4 +1,4 @@
export type jobsSchema = { export interface jobsSchema {
type: string; type: string;
properties: { properties: {
error: { error: {
@ -36,5 +36,6 @@ export type jobsSchema = {
}; };
}; };
required: string[]; required: string[];
}; }
export declare const jobsSchema: jobsSchema; export declare const jobsSchema: jobsSchema;
export declare const jobRequestSchema: jobsSchema;

@ -1,6 +1,6 @@
import { Config, NetIdType } from '../networkConfig'; import { Config, NetIdType } from '../networkConfig';
import { addressSchemaType, bnSchemaType } from '.'; import { addressSchemaType, bnSchemaType } from '.';
export type statusInstanceType = { export interface statusInstanceType {
type: string; type: string;
properties: { properties: {
instanceAddress: { instanceAddress: {
@ -19,22 +19,22 @@ export type statusInstanceType = {
}; };
}; };
required: string[]; required: string[];
}; }
export type statusInstancesType = { export interface statusInstancesType {
type: string; type: string;
properties: { properties: {
[key in string]: statusInstanceType; [key in string]: statusInstanceType;
}; };
required: string[]; required: string[];
}; }
export type statusEthPricesType = { export interface statusEthPricesType {
type: string; type: string;
properties: { properties: {
[key in string]: typeof bnSchemaType; [key in string]: typeof bnSchemaType;
}; };
required?: string[]; required?: string[];
}; }
export type statusSchema = { export interface statusSchema {
type: string; type: string;
properties: { properties: {
rewardAccount: typeof addressSchemaType; rewardAccount: typeof addressSchemaType;
@ -102,5 +102,5 @@ export type statusSchema = {
}; };
}; };
required: string[]; required: string[];
}; }
export declare function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean): statusSchema; export declare function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean): statusSchema;

5625
dist/tornado.umd.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -62,10 +62,22 @@ export declare class TovarishClient extends RelayerClient {
url?: string; url?: string;
relayerAddress?: string; relayerAddress?: string;
}): Promise<TovarishStatus>; }): Promise<TovarishStatus>;
/**
* Ask status for all enabled chains for tovarish relayer
*/
askAllStatus({ hostname, url, relayerAddress, }: {
hostname?: string;
url?: string;
relayerAddress?: string;
}): Promise<TovarishStatus[]>;
filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined>; filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined>;
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{ getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[]; validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[]; invalidRelayers: RelayerError[];
}>; }>;
getTovarishRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
}>;
getEvents<T extends MinimalEvents>({ type, currency, amount, fromBlock, recent, }: TovarishEventsQuery): Promise<BaseTovarishEvents<T>>; getEvents<T extends MinimalEvents>({ type, currency, amount, fromBlock, recent, }: TovarishEventsQuery): Promise<BaseTovarishEvents<T>>;
} }

8
dist/websnark.d.ts vendored

@ -1,5 +1,5 @@
import type { Element } from '@tornado/fixed-merkle-tree'; import type { Element } from '@tornado/fixed-merkle-tree';
export type snarkInputs = { export interface snarkInputs {
root: Element; root: Element;
nullifierHex: string; nullifierHex: string;
recipient: string; recipient: string;
@ -10,7 +10,7 @@ export type snarkInputs = {
secret: bigint; secret: bigint;
pathElements: Element[]; pathElements: Element[];
pathIndices: Element[]; pathIndices: Element[];
}; }
export type snarkArgs = [ export type snarkArgs = [
_root: string, _root: string,
_nullifierHash: string, _nullifierHash: string,
@ -19,9 +19,9 @@ export type snarkArgs = [
_fee: string, _fee: string,
_refund: string _refund: string
]; ];
export type snarkProofs = { export interface snarkProofs {
proof: string; proof: string;
args: snarkArgs; args: snarkArgs;
}; }
export declare function initGroth16(): Promise<void>; export declare function initGroth16(): Promise<void>;
export declare function calculateSnarkProof(input: snarkInputs, circuit: object, provingKey: ArrayBuffer): Promise<snarkProofs>; export declare function calculateSnarkProof(input: snarkInputs, circuit: object, provingKey: ArrayBuffer): Promise<snarkProofs>;

@ -32,7 +32,7 @@
], ],
"dependencies": { "dependencies": {
"@metamask/eth-sig-util": "^7.0.3", "@metamask/eth-sig-util": "^7.0.3",
"@tornado/contracts": "^1.0.1", "@tornado/contracts": "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4",
"@tornado/fixed-merkle-tree": "^0.7.3", "@tornado/fixed-merkle-tree": "^0.7.3",
"@tornado/snarkjs": "^0.1.20", "@tornado/snarkjs": "^0.1.20",
"@tornado/websnark": "^0.0.4", "@tornado/websnark": "^0.0.4",
@ -40,13 +40,13 @@
"bn.js": "^5.2.1", "bn.js": "^5.2.1",
"circomlibjs": "0.1.7", "circomlibjs": "0.1.7",
"cross-fetch": "^4.0.0", "cross-fetch": "^4.0.0",
"ethers": "^6.13.3", "ethers": "^6.13.4",
"ffjavascript": "0.2.48", "ffjavascript": "0.2.48",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"idb": "^8.0.0" "idb": "^8.0.0"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.3.0",
"@typechain/ethers-v6": "^0.5.1", "@typechain/ethers-v6": "^0.5.1",
@ -54,8 +54,8 @@
"@types/circomlibjs": "^0.1.6", "@types/circomlibjs": "^0.1.6",
"@types/node": "^22.7.5", "@types/node": "^22.7.5",
"@types/node-fetch": "^2.6.11", "@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^8.8.1", "@typescript-eslint/eslint-plugin": "^8.9.0",
"@typescript-eslint/parser": "^8.8.1", "@typescript-eslint/parser": "^8.9.0",
"esbuild-loader": "^4.2.2", "esbuild-loader": "^4.2.2",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",

@ -33,7 +33,7 @@ const config = [
include: /\.[jt]sx?$/, include: /\.[jt]sx?$/,
minify: false, minify: false,
sourceMap: true, sourceMap: true,
target: 'es2016', target: 'es2022',
}), }),
commonjs(), commonjs(),
nodeResolve(), nodeResolve(),
@ -54,7 +54,7 @@ const config = [
include: /\.[jt]sx?$/, include: /\.[jt]sx?$/,
minify: false, minify: false,
sourceMap: true, sourceMap: true,
target: 'es2016', target: 'es2022',
}), }),
nodeResolve(), nodeResolve(),
json() json()
@ -75,7 +75,7 @@ const config = [
include: /\.[jt]sx?$/, include: /\.[jt]sx?$/,
minify: false, minify: false,
sourceMap: true, sourceMap: true,
target: 'es2016', target: 'es2022',
}), }),
commonjs(), commonjs(),
nodeResolve(), nodeResolve(),

@ -225,11 +225,11 @@ export type BatchEventOnProgress = ({
}) => void; }) => void;
// To enable iteration only numbers are accepted for fromBlock input // To enable iteration only numbers are accepted for fromBlock input
export type EventInput = { export interface EventInput {
fromBlock: number; fromBlock: number;
toBlock: number; toBlock: number;
type: ContractEventName; type: ContractEventName;
}; }
/** /**
* Fetch events from web3 provider on bulk * Fetch events from web3 provider on bulk

@ -2,44 +2,34 @@ import { bnToBytes, bytesToBN, leBuff2Int, leInt2Buff, rBigInt, toFixedHex } fro
import { buffPedersenHash } from './pedersen'; import { buffPedersenHash } from './pedersen';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
export type DepositType = { export interface DepositType {
currency: string; currency: string;
amount: string; amount: string;
netId: NetIdType; netId: NetIdType;
}; }
export type createDepositParams = { export interface createDepositParams {
nullifier: bigint; nullifier: bigint;
secret: bigint; secret: bigint;
}; }
export type createDepositObject = { export interface createDepositObject {
preimage: Uint8Array; preimage: Uint8Array;
noteHex: string; noteHex: string;
commitment: bigint; commitment: bigint;
commitmentHex: string; commitmentHex: string;
nullifierHash: bigint; nullifierHash: bigint;
nullifierHex: string; nullifierHex: string;
}; }
export type createNoteParams = DepositType & { export interface createNoteParams extends DepositType {
nullifier?: bigint; nullifier?: bigint;
secret?: bigint; secret?: bigint;
}; }
export type parsedNoteExec = DepositType & { export interface parsedNoteExec extends DepositType {
note: string; note: string;
}; }
export type depositTx = {
from: string;
transactionHash: string;
};
export type withdrawalTx = {
to: string;
transactionHash: string;
};
export async function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject> { export async function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject> {
const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]); const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]);
@ -199,9 +189,9 @@ export class Deposit {
} }
} }
export type parsedInvoiceExec = DepositType & { export interface parsedInvoiceExec extends DepositType {
commitment: string; commitment: string;
}; }
export class Invoice { export class Invoice {
currency: string; currency: string;

@ -55,17 +55,17 @@ import type {
export const DEPOSIT = 'deposit'; export const DEPOSIT = 'deposit';
export const WITHDRAWAL = 'withdrawal'; export const WITHDRAWAL = 'withdrawal';
export type BaseEventsServiceConstructor = { export interface BaseEventsServiceConstructor {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
graphApi?: string; graphApi?: string;
subgraphName?: string; subgraphName?: string;
contract: BaseContract; contract: BaseContract;
type?: string; type: string;
deployedBlock?: number; deployedBlock?: number;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient; tovarishClient?: TovarishClient;
}; }
export type BatchGraphOnProgress = ({ export type BatchGraphOnProgress = ({
type, type,
@ -79,12 +79,12 @@ export type BatchGraphOnProgress = ({
count?: number; count?: number;
}) => void; }) => void;
export type BaseGraphParams = { export interface BaseGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
onProgress?: BatchGraphOnProgress; onProgress?: BatchGraphOnProgress;
}; }
export class BaseEventsService<EventType extends MinimalEvents> { export class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType; netId: NetIdType;
@ -347,31 +347,22 @@ export class BaseEventsService<EventType extends MinimalEvents> {
} }
} }
export type BaseTornadoServiceConstructor = { export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Tornado: Tornado; Tornado: Tornado;
type: string;
amount: string; amount: string;
currency: string; currency: string;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export type DepositsGraphParams = BaseGraphParams & { export interface DepositsGraphParams extends BaseGraphParams {
amount: string; amount: string;
currency: string; currency: string;
}; }
export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> { export class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string; amount: string;
currency: string; currency: string;
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService; batchBlockService: BatchBlockService;
tovarishClient?: TovarishClient;
constructor({ constructor({
netId, netId,
@ -520,16 +511,9 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
} }
} }
export type BaseEchoServiceConstructor = { export interface BaseEchoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Echoer: Echoer; Echoer: Echoer;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseEchoService extends BaseEventsService<EchoEvents> { export class BaseEchoService extends BaseEventsService<EchoEvents> {
constructor({ constructor({
@ -548,6 +532,7 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
graphApi, graphApi,
subgraphName, subgraphName,
contract: Echoer, contract: Echoer,
type: 'Echo',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -558,10 +543,6 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
return `echo_${this.netId}`; return `echo_${this.netId}`;
} }
getType(): string {
return 'Echo';
}
getGraphMethod(): string { getGraphMethod(): string {
return 'getAllGraphEchoEvents'; return 'getAllGraphEchoEvents';
} }
@ -601,16 +582,9 @@ export class BaseEchoService extends BaseEventsService<EchoEvents> {
} }
} }
export type BaseEncryptedNotesServiceConstructor = { export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Router: TornadoRouter | TornadoProxyLight; Router: TornadoRouter | TornadoProxyLight;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> { export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
constructor({ constructor({
@ -629,6 +603,7 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
graphApi, graphApi,
subgraphName, subgraphName,
contract: Router, contract: Router,
type: 'EncryptedNote',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -639,10 +614,6 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
return `encrypted_notes_${this.netId}`; return `encrypted_notes_${this.netId}`;
} }
getType(): string {
return 'EncryptedNote';
}
getTovarishType(): string { getTovarishType(): string {
return 'encrypted_notes'; return 'encrypted_notes';
} }
@ -673,16 +644,9 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
} }
} }
export type BaseGovernanceServiceConstructor = { export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Governance: Governance; Governance: Governance;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> { export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
@ -703,6 +667,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
graphApi, graphApi,
subgraphName, subgraphName,
contract: Governance, contract: Governance,
type: '*',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -718,10 +683,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
return `governance_${this.netId}`; return `governance_${this.netId}`;
} }
getType() {
return '*';
}
getTovarishType(): string { getTovarishType(): string {
return 'governance'; return 'governance';
} }
@ -841,7 +802,7 @@ export async function getTovarishNetworks(registryService: BaseRegistryService,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
timeout: 60000, timeout: 30000,
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0, maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0,
}); });
} catch { } catch {
@ -888,18 +849,11 @@ export interface CachedRelayers {
fromCache?: boolean; fromCache?: boolean;
} }
export type BaseRegistryServiceConstructor = { export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;
Aggregator: Aggregator; Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap; relayerEnsSubdomains: SubdomainMap;
deployedBlock?: number; }
fetchDataOptions?: fetchDataOptions;
tovarishClient?: TovarishClient;
};
export class BaseRegistryService extends BaseEventsService<RegistersEvents> { export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
Aggregator: Aggregator; Aggregator: Aggregator;
@ -924,6 +878,7 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
graphApi, graphApi,
subgraphName, subgraphName,
contract: RelayerRegistry, contract: RelayerRegistry,
type: 'RelayerRegistered',
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
tovarishClient, tovarishClient,
@ -939,11 +894,6 @@ export class BaseRegistryService extends BaseEventsService<RegistersEvents> {
return `registered_${this.netId}`; return `registered_${this.netId}`;
} }
// Name of type used for events
getType() {
return 'RelayerRegistered';
}
getTovarishType(): string { getTovarishType(): string {
return 'registered'; return 'registered';
} }

@ -20,37 +20,37 @@ export interface MinimalEvents {
transactionHash: string; transactionHash: string;
} }
export type GovernanceEvents = MinimalEvents & { export interface GovernanceEvents extends MinimalEvents {
event: string; event: string;
}; }
export type GovernanceProposalCreatedEvents = GovernanceEvents & { export interface GovernanceProposalCreatedEvents extends GovernanceEvents {
id: number; id: number;
proposer: string; proposer: string;
target: string; target: string;
startTime: number; startTime: number;
endTime: number; endTime: number;
description: string; description: string;
}; }
export type GovernanceVotedEvents = GovernanceEvents & { export interface GovernanceVotedEvents extends GovernanceEvents {
proposalId: number; proposalId: number;
voter: string; voter: string;
support: boolean; support: boolean;
votes: string; votes: string;
from: string; from: string;
input: string; input: string;
}; }
export type GovernanceDelegatedEvents = GovernanceEvents & { export interface GovernanceDelegatedEvents extends GovernanceEvents {
account: string; account: string;
delegateTo: string; delegateTo: string;
}; }
export type GovernanceUndelegatedEvents = GovernanceEvents & { export interface GovernanceUndelegatedEvents extends GovernanceEvents {
account: string; account: string;
delegateFrom: string; delegateFrom: string;
}; }
export type AllGovernanceEvents = export type AllGovernanceEvents =
| GovernanceProposalCreatedEvents | GovernanceProposalCreatedEvents
@ -60,25 +60,25 @@ export type AllGovernanceEvents =
export type RegistersEvents = MinimalEvents & RelayerParams; export type RegistersEvents = MinimalEvents & RelayerParams;
export type DepositsEvents = MinimalEvents & { export interface DepositsEvents extends MinimalEvents {
commitment: string; commitment: string;
leafIndex: number; leafIndex: number;
timestamp: number; timestamp: number;
from: string; from: string;
}; }
export type WithdrawalsEvents = MinimalEvents & { export interface WithdrawalsEvents extends MinimalEvents {
nullifierHash: string; nullifierHash: string;
to: string; to: string;
fee: string; fee: string;
timestamp: number; timestamp: number;
}; }
export type EchoEvents = MinimalEvents & { export interface EchoEvents extends MinimalEvents {
address: string; address: string;
encryptedAccount: string; encryptedAccount: string;
}; }
export type EncryptedNotesEvents = MinimalEvents & { export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string; encryptedNote: string;
}; }

54
src/gaszip.ts Normal file

@ -0,0 +1,54 @@
import { isAddress } from 'ethers';
import { NetId, NetIdType } from './networkConfig';
// https://dev.gas.zip/gas/chain-support/inbound
export const gasZipInbounds: { [key in NetIdType]: string } = {
[NetId.MAINNET]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.BSC]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.POLYGON]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.OPTIMISM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.ARBITRUM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.GNOSIS]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.AVALANCHE]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
};
// https://dev.gas.zip/gas/chain-support/outbound
export const gasZipID: { [key in NetIdType]: number } = {
[NetId.MAINNET]: 255,
[NetId.BSC]: 14,
[NetId.POLYGON]: 17,
[NetId.OPTIMISM]: 55,
[NetId.ARBITRUM]: 57,
[NetId.GNOSIS]: 16,
[NetId.AVALANCHE]: 15,
[NetId.SEPOLIA]: 102,
};
// https://dev.gas.zip/gas/code-examples/eoaDeposit
export function gasZipInput(to: string, shorts: number[]): string | null {
let data = '0x';
if (isAddress(to)) {
if (to.length === 42) {
data += '02';
data += to.slice(2);
} else {
return null;
}
} else {
data += '01'; // to == sender
}
for (const i in shorts) {
data += '0x' + Number(shorts[i]).toString(16).slice(2).padStart(4, '0');
}
return data;
}
export function gasZipMinMax(ethUsd: number) {
return {
min: 1 / ethUsd,
max: 50 / ethUsd,
ethUsd,
};
}

@ -34,7 +34,7 @@ const isEmptyArray = (arr: object) => !Array.isArray(arr) || !arr.length;
// https://thegraph.com/docs/en/developing/developer-faqs/#23-is-there-a-limit-to-how-many-objects-the-graph-can-return-per-query // https://thegraph.com/docs/en/developing/developer-faqs/#23-is-there-a-limit-to-how-many-objects-the-graph-can-return-per-query
const GRAPHQL_LIMIT = 1000; const GRAPHQL_LIMIT = 1000;
export type queryGraphParams = { export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
query: string; query: string;
@ -42,7 +42,7 @@ export type queryGraphParams = {
[key: string]: string | number; [key: string]: string | number;
}; };
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
}; }
export async function queryGraph<T>({ export async function queryGraph<T>({
graphApi, graphApi,

@ -6,6 +6,7 @@ export * from './batch';
export * from './deposits'; export * from './deposits';
export * from './encryptedNotes'; export * from './encryptedNotes';
export * from './fees'; export * from './fees';
export * from './gaszip';
export * from './idb'; export * from './idb';
export * from './merkleTree'; export * from './merkleTree';
export * from './mimc'; export * from './mimc';

@ -7,13 +7,13 @@ import type { DepositType } from './deposits';
import type { DepositsEvents } from './events'; import type { DepositsEvents } from './events';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';
export type MerkleTreeConstructor = DepositType & { export interface MerkleTreeConstructor extends DepositType {
Tornado: Tornado; Tornado: Tornado;
commitmentHex?: string; commitmentHex?: string;
merkleTreeHeight?: number; merkleTreeHeight?: number;
emptyElement?: string; emptyElement?: string;
merkleWorkerPath?: string; merkleWorkerPath?: string;
}; }
export class MerkleTreeService { export class MerkleTreeService {
currency: string; currency: string;

@ -19,22 +19,22 @@ export interface RpcUrl {
url: string; url: string;
} }
export type RpcUrls = { export interface RpcUrls {
[key in string]: RpcUrl; [key: string]: RpcUrl;
}; }
export interface SubgraphUrl { export interface SubgraphUrl {
name: string; name: string;
url: string; url: string;
} }
export type SubgraphUrls = { export interface SubgraphUrls {
[key in string]: SubgraphUrl; [key: string]: SubgraphUrl;
}; }
export type TornadoInstance = { export interface TornadoInstance {
instanceAddress: { instanceAddress: {
[key in string]: string; [key: string]: string;
}; };
optionalInstances?: string[]; optionalInstances?: string[];
tokenAddress?: string; tokenAddress?: string;
@ -42,13 +42,13 @@ export type TornadoInstance = {
symbol: string; symbol: string;
decimals: number; decimals: number;
gasLimit?: number; gasLimit?: number;
}; }
export type TokenInstances = { export interface TokenInstances {
[key in string]: TornadoInstance; [key: string]: TornadoInstance;
}; }
export type Config = { export interface Config {
rpcCallRetryAttempt?: number; rpcCallRetryAttempt?: number;
// Should be in gwei // Should be in gwei
gasPrices: { gasPrices: {
@ -68,6 +68,8 @@ export type Config = {
networkName: string; networkName: string;
deployedBlock: number; deployedBlock: number;
rpcUrls: RpcUrls; rpcUrls: RpcUrls;
// Contract Address of stablecoin token, used for fiat conversion
stablecoin: string;
multicallContract: string; multicallContract: string;
routerContract: string; routerContract: string;
echoContract: string; echoContract: string;
@ -97,15 +99,15 @@ export type Config = {
// Should be in seconds // Should be in seconds
MINING_BLOCK_TIME?: number; MINING_BLOCK_TIME?: number;
}; };
}; }
export type networkConfig = { export interface networkConfig {
[key in NetIdType]: Config; [key: NetIdType]: Config;
}; }
export type SubdomainMap = { export interface SubdomainMap {
[key in NetIdType]: string; [key: NetIdType]: string;
}; }
export const defaultConfig: networkConfig = { export const defaultConfig: networkConfig = {
[NetId.MAINNET]: { [NetId.MAINNET]: {
@ -140,11 +142,12 @@ export const defaultConfig: networkConfig = {
name: 'Stackup RPC', name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/ethereum-mainnet', url: 'https://public.stackup.sh/api/v1/node/ethereum-mainnet',
}, },
oneRPC: { oneRpc: {
name: '1RPC', name: '1RPC',
url: 'https://1rpc.io/eth', url: 'https://1rpc.io/eth',
}, },
}, },
stablecoin: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b', routerContract: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b',
echoContract: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42', echoContract: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42',
@ -258,6 +261,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Binance Smart Chain', networkName: 'Binance Smart Chain',
deployedBlock: 8158799, deployedBlock: 8158799,
stablecoin: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -281,7 +285,7 @@ export const defaultConfig: networkConfig = {
name: 'Stackup RPC', name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/bsc-mainnet', url: 'https://public.stackup.sh/api/v1/node/bsc-mainnet',
}, },
oneRPC: { oneRpc: {
name: '1RPC', name: '1RPC',
url: 'https://1rpc.io/bnb', url: 'https://1rpc.io/bnb',
}, },
@ -320,6 +324,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Polygon (Matic) Network', networkName: 'Polygon (Matic) Network',
deployedBlock: 16257962, deployedBlock: 16257962,
stablecoin: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -370,6 +375,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Optimism', networkName: 'Optimism',
deployedBlock: 2243689, deployedBlock: 2243689,
stablecoin: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -378,18 +384,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph', tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
optimism: { oneRpc: {
name: 'Optimism', name: '1RPC',
url: 'https://mainnet.optimism.io', url: 'https://1rpc.io/op',
}, },
stackup: { stackup: {
name: 'Stackup RPC', name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/optimism-mainnet', url: 'https://public.stackup.sh/api/v1/node/optimism-mainnet',
}, },
oneRpc: {
name: '1RPC',
url: 'https://1rpc.io/op',
},
}, },
tokens: { tokens: {
eth: { eth: {
@ -425,6 +427,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Arbitrum One', networkName: 'Arbitrum One',
deployedBlock: 3430648, deployedBlock: 3430648,
stablecoin: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -441,7 +444,7 @@ export const defaultConfig: networkConfig = {
url: 'https://public.stackup.sh/api/v1/node/arbitrum-one', url: 'https://public.stackup.sh/api/v1/node/arbitrum-one',
}, },
oneRpc: { oneRpc: {
name: '1rpc', name: '1RPC',
url: 'https://1rpc.io/arb', url: 'https://1rpc.io/arb',
}, },
}, },
@ -479,6 +482,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Gnosis Chain', networkName: 'Gnosis Chain',
deployedBlock: 17754561, deployedBlock: 17754561,
stablecoin: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -490,12 +494,8 @@ export const defaultConfig: networkConfig = {
name: 'Gnosis', name: 'Gnosis',
url: 'https://rpc.gnosischain.com', url: 'https://rpc.gnosischain.com',
}, },
blockPi: {
name: 'BlockPi',
url: 'https://gnosis.blockpi.network/v1/rpc/public',
},
oneRpc: { oneRpc: {
name: '1rpc', name: '1RPC',
url: 'https://1rpc.io/gnosis', url: 'https://1rpc.io/gnosis',
}, },
}, },
@ -533,6 +533,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Avalanche Mainnet', networkName: 'Avalanche Mainnet',
deployedBlock: 4429818, deployedBlock: 4429818,
stablecoin: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17', routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -540,14 +541,14 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph', tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
publicRpc: { oneRpc: {
name: 'Avalanche RPC', name: '1RPC',
url: 'https://api.avax.network/ext/bc/C/rpc',
},
oneRPC: {
name: 'OneRPC',
url: 'https://1rpc.io/avax/c', url: 'https://1rpc.io/avax/c',
}, },
stackup: {
name: 'Stackup RPC',
url: 'https://public.stackup.sh/api/v1/node/avalanche-mainnet',
},
}, },
tokens: { tokens: {
avax: { avax: {
@ -582,6 +583,7 @@ export const defaultConfig: networkConfig = {
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Ethereum Sepolia', networkName: 'Ethereum Sepolia',
deployedBlock: 5594395, deployedBlock: 5594395,
stablecoin: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11', multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee', routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
@ -602,8 +604,8 @@ export const defaultConfig: networkConfig = {
name: 'Stackup', name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia', url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia',
}, },
onerpc: { oneRpc: {
name: '1rpc', name: '1RPC',
url: 'https://1rpc.io/sepolia', url: 'https://1rpc.io/sepolia',
}, },
ethpandaops: { ethpandaops: {

@ -1,6 +1,6 @@
import { parseEther, type Provider } from 'ethers'; import { formatEther, parseEther, type Provider } from 'ethers';
import type { OffchainOracle, Multicall } from './typechain'; import { ERC20__factory, OffchainOracle, Multicall } from './typechain';
import { multicall } from './multicall'; import { multicall, Call3 } from './multicall';
export class TokenPriceOracle { export class TokenPriceOracle {
oracle?: OffchainOracle; oracle?: OffchainOracle;
@ -13,6 +13,46 @@ export class TokenPriceOracle {
this.oracle = oracle; this.oracle = oracle;
} }
buildCalls(
tokens: {
tokenAddress: string;
decimals: number;
}[],
): Call3[] {
return tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
}));
}
buildStable(stablecoinAddress: string): Call3[] {
const stablecoin = ERC20__factory.connect(stablecoinAddress, this.provider);
return [
{
contract: stablecoin,
name: 'decimals',
},
{
contract: this.oracle,
name: 'getRateToEth',
params: [stablecoin.target, true],
},
];
}
async fetchPrice(tokenAddress: string, decimals: number): Promise<bigint> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(parseEther('0.0001')));
}
const price = await this.oracle.getRateToEth(tokenAddress, true);
return (price * BigInt(10 ** decimals)) / BigInt(10 ** 18);
}
async fetchPrices( async fetchPrices(
tokens: { tokens: {
tokenAddress: string; tokenAddress: string;
@ -24,17 +64,24 @@ export class TokenPriceOracle {
return new Promise((resolve) => resolve(tokens.map(() => parseEther('0.0001')))); return new Promise((resolve) => resolve(tokens.map(() => parseEther('0.0001'))));
} }
const prices = (await multicall( const prices = (await multicall(this.multicall, this.buildCalls(tokens))) as bigint[];
this.multicall,
tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
})),
)) as bigint[];
return prices.map((price, index) => { return prices.map((price, index) => {
return (price * BigInt(10 ** tokens[index].decimals)) / BigInt(10 ** 18); return (price * BigInt(10 ** tokens[index].decimals)) / BigInt(10 ** 18);
}); });
} }
async fetchEthUSD(stablecoinAddress: string): Promise<number> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(10000));
}
const [decimals, price] = await multicall(this.multicall, this.buildStable(stablecoinAddress));
// eth wei price of usdc token
const ethPrice = (price * BigInt(10n ** decimals)) / BigInt(10 ** 18);
return 1 / Number(formatEther(ethPrice));
}
} }

@ -371,12 +371,12 @@ export const populateTransaction = async (
return tx; return tx;
}; };
export type TornadoWalletOptions = { export interface TornadoWalletOptions {
gasPriceBump?: number; gasPriceBump?: number;
gasLimitBump?: number; gasLimitBump?: number;
gasFailover?: boolean; gasFailover?: boolean;
bumpNonce?: boolean; bumpNonce?: boolean;
}; }
export class TornadoWallet extends Wallet { export class TornadoWallet extends Wallet {
nonce?: number; nonce?: number;
@ -474,13 +474,13 @@ export type connectWalletFunc = (...args: any[]) => Promise<void>;
export type handleWalletFunc = (...args: any[]) => void; export type handleWalletFunc = (...args: any[]) => void;
/* eslint-enable @typescript-eslint/no-explicit-any */ /* eslint-enable @typescript-eslint/no-explicit-any */
export type TornadoBrowserProviderOptions = TornadoWalletOptions & { export interface TornadoBrowserProviderOptions extends TornadoWalletOptions {
netId?: NetIdType; netId?: NetIdType;
connectWallet?: connectWalletFunc; connectWallet?: connectWalletFunc;
handleNetworkChanges?: handleWalletFunc; handleNetworkChanges?: handleWalletFunc;
handleAccountChanges?: handleWalletFunc; handleAccountChanges?: handleWalletFunc;
handleAccountDisconnect?: handleWalletFunc; handleAccountDisconnect?: handleWalletFunc;
}; }
export class TornadoBrowserProvider extends BrowserProvider { export class TornadoBrowserProvider extends BrowserProvider {
options?: TornadoBrowserProviderOptions; options?: TornadoBrowserProviderOptions;

@ -2,7 +2,7 @@ import { getAddress, parseEther } from 'ethers';
import { sleep } from './utils'; import { sleep } from './utils';
import { NetId, NetIdType, Config } from './networkConfig'; import { NetId, NetIdType, Config } from './networkConfig';
import { fetchData, fetchDataOptions } from './providers'; import { fetchData, fetchDataOptions } from './providers';
import { ajv, jobsSchema, getStatusSchema } from './schemas'; import { ajv, jobsSchema, jobRequestSchema, getStatusSchema } from './schemas';
import type { snarkProofs } from './websnark'; import type { snarkProofs } from './websnark';
import type { CachedRelayerInfo } from './events'; import type { CachedRelayerInfo } from './events';
@ -20,7 +20,7 @@ export interface RelayerParams {
/** /**
* Info from relayer status * Info from relayer status
*/ */
export type RelayerInfo = RelayerParams & { export interface RelayerInfo extends RelayerParams {
netId: NetIdType; netId: NetIdType;
url: string; url: string;
hostname: string; hostname: string;
@ -33,14 +33,14 @@ export type RelayerInfo = RelayerParams & {
}; };
currentQueue: number; currentQueue: number;
tornadoServiceFee: number; tornadoServiceFee: number;
}; }
export type RelayerError = { export interface RelayerError {
hostname: string; hostname: string;
relayerAddress?: string; relayerAddress?: string;
errorMessage?: string; errorMessage?: string;
hasError: boolean; hasError: boolean;
}; }
export interface RelayerStatus { export interface RelayerStatus {
url: string; url: string;
@ -75,9 +75,9 @@ export interface RelayerStatus {
currentQueue: number; currentQueue: number;
} }
export type TornadoWithdrawParams = snarkProofs & { export interface TornadoWithdrawParams extends snarkProofs {
contract: string; contract: string;
}; }
export interface RelayerTornadoWithdraw { export interface RelayerTornadoWithdraw {
id?: string; id?: string;
@ -149,13 +149,13 @@ export function getWeightRandom(weightsScores: bigint[], random: bigint) {
return Math.floor(Math.random() * weightsScores.length); return Math.floor(Math.random() * weightsScores.length);
} }
export type RelayerInstanceList = { export interface RelayerInstanceList {
[key in string]: { [key: string]: {
instanceAddress: { instanceAddress: {
[key in string]: string; [key: string]: string;
}; };
}; };
}; }
export function getSupportedInstances(instanceList: RelayerInstanceList) { export function getSupportedInstances(instanceList: RelayerInstanceList) {
const rawList = Object.values(instanceList) const rawList = Object.values(instanceList)
@ -223,7 +223,7 @@ export class RelayerClient {
headers: { headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded', 'Content-Type': 'application/json, application/x-www-form-urlencoded',
}, },
timeout: 60000, timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0, maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object; })) as object;
@ -318,10 +318,14 @@ export class RelayerClient {
async tornadoWithdraw( async tornadoWithdraw(
{ contract, proof, args }: TornadoWithdrawParams, { contract, proof, args }: TornadoWithdrawParams,
callback?: (jobResp: RelayerTornadoJobs) => void, callback?: (jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs) => void,
) { ) {
const { url } = this.selectedRelayer as RelayerInfo; const { url } = this.selectedRelayer as RelayerInfo;
/**
* Request new job
*/
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, { const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
method: 'POST', method: 'POST',
@ -341,6 +345,21 @@ export class RelayerClient {
throw new Error(error); throw new Error(error);
} }
const jobValidator = ajv.compile(jobRequestSchema);
if (!jobValidator(withdrawResponse)) {
const errMsg = `${url}v1/tornadoWithdraw has an invalid job response`;
throw new Error(errMsg);
}
if (typeof callback === 'function') {
callback(withdrawResponse as unknown as RelayerTornadoWithdraw);
}
/**
* Get job status
*/
let relayerStatus: string | undefined; let relayerStatus: string | undefined;
const jobUrl = `${url}v1/jobs/${id}`; const jobUrl = `${url}v1/jobs/${id}`;

@ -1,4 +1,4 @@
export type jobsSchema = { export interface jobsSchema {
type: string; type: string;
properties: { properties: {
error: { error: {
@ -36,7 +36,7 @@ export type jobsSchema = {
}; };
}; };
required: string[]; required: string[];
}; }
export const jobsSchema: jobsSchema = { export const jobsSchema: jobsSchema = {
type: 'object', type: 'object',
@ -57,3 +57,8 @@ export const jobsSchema: jobsSchema = {
}, },
required: ['id', 'status'], required: ['id', 'status'],
}; };
export const jobRequestSchema: jobsSchema = {
...jobsSchema,
required: ['id'],
};

@ -1,7 +1,7 @@
import { Config, NetId, NetIdType } from '../networkConfig'; import { Config, NetId, NetIdType } from '../networkConfig';
import { addressSchemaType, bnSchemaType } from '.'; import { addressSchemaType, bnSchemaType } from '.';
export type statusInstanceType = { export interface statusInstanceType {
type: string; type: string;
properties: { properties: {
instanceAddress: { instanceAddress: {
@ -16,25 +16,25 @@ export type statusInstanceType = {
decimals: { enum: number[] }; decimals: { enum: number[] };
}; };
required: string[]; required: string[];
}; }
export type statusInstancesType = { export interface statusInstancesType {
type: string; type: string;
properties: { properties: {
[key in string]: statusInstanceType; [key in string]: statusInstanceType;
}; };
required: string[]; required: string[];
}; }
export type statusEthPricesType = { export interface statusEthPricesType {
type: string; type: string;
properties: { properties: {
[key in string]: typeof bnSchemaType; [key in string]: typeof bnSchemaType;
}; };
required?: string[]; required?: string[];
}; }
export type statusSchema = { export interface statusSchema {
type: string; type: string;
properties: { properties: {
rewardAccount: typeof addressSchemaType; rewardAccount: typeof addressSchemaType;
@ -90,7 +90,7 @@ export type statusSchema = {
}; };
}; };
required: string[]; required: string[];
}; }
const statusSchema: statusSchema = { const statusSchema: statusSchema = {
type: 'object', type: 'object',

@ -10,7 +10,8 @@ import {
} from './relayerClient'; } from './relayerClient';
import { fetchData } from './providers'; import { fetchData } from './providers';
import { CachedRelayerInfo, MinimalEvents } from './events'; import { CachedRelayerInfo, MinimalEvents } from './events';
import { getEventsSchemaValidator } from './schemas'; import { ajv, getEventsSchemaValidator, getStatusSchema } from './schemas';
import { enabledChains, getConfig, NetId, NetIdType } from './networkConfig';
// Return no more than 5K events per query // Return no more than 5K events per query
export const MAX_TOVARISH_EVENTS = 5000; export const MAX_TOVARISH_EVENTS = 5000;
@ -81,7 +82,7 @@ export interface BaseTovarishEvents<T> {
} }
export class TovarishClient extends RelayerClient { export class TovarishClient extends RelayerClient {
selectedRelayer?: TovarishInfo; declare selectedRelayer?: TovarishInfo;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) { constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
super({ netId, config, fetchDataOptions }); super({ netId, config, fetchDataOptions });
@ -108,6 +109,82 @@ export class TovarishClient extends RelayerClient {
return status; return status;
} }
/**
* Ask status for all enabled chains for tovarish relayer
*/
async askAllStatus({
hostname,
url,
relayerAddress,
}: {
hostname?: string;
// optional url if entered manually
url?: string;
// relayerAddress from registry contract to prevent cheating
relayerAddress?: string;
}): Promise<TovarishStatus[]> {
if (!url && hostname) {
url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
} else if (url && !url.endsWith('/')) {
url += '/';
} else {
url = '';
}
const statusArray = (await fetchData(`${url}status`, {
...this.fetchDataOptions,
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded',
},
timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object;
if (!Array.isArray(statusArray)) {
return [];
}
const tovarishStatus: TovarishStatus[] = [];
for (const rawStatus of statusArray) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const netId = (rawStatus as any).netId as NetIdType;
const config = getConfig(netId);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const statusValidator = ajv.compile(getStatusSchema((rawStatus as any).netId, config, this.tovarish));
if (!statusValidator) {
continue;
}
const status = {
...rawStatus,
url: `${url}${netId}/`,
} as TovarishStatus;
if (status.currentQueue > 5) {
throw new Error('Withdrawal queue is overloaded');
}
if (!enabledChains.includes(status.netId)) {
throw new Error('This relayer serves a different network');
}
if (relayerAddress && status.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error('The Relayer reward address must match registered address');
}
if (!status.version.includes('tovarish')) {
throw new Error('Not a tovarish relayer!');
}
tovarishStatus.push(status);
}
return tovarishStatus;
}
async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> { async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> {
const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer; const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer;
@ -175,6 +252,62 @@ export class TovarishClient extends RelayerClient {
}; };
} }
async getTovarishRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
}> {
const validRelayers: TovarishInfo[] = [];
const invalidRelayers: RelayerError[] = [];
await Promise.all(
relayers
.filter((r) => r.tovarishHost && r.tovarishNetworks?.length)
.map(async (relayer) => {
const { ensName, relayerAddress, tovarishHost } = relayer;
try {
const statusArray = await this.askAllStatus({ hostname: tovarishHost as string, relayerAddress });
for (const status of statusArray) {
validRelayers.push({
netId: status.netId,
url: status.url,
hostname: tovarishHost as string,
ensName,
relayerAddress,
rewardAccount: getAddress(status.rewardAccount),
instances: getSupportedInstances(status.instances),
stakeBalance: relayer.stakeBalance,
gasPrice: status.gasPrices?.fast,
ethPrices: status.ethPrices,
currentQueue: status.currentQueue,
tornadoServiceFee: status.tornadoServiceFee,
// Additional fields for tovarish relayer
latestBlock: Number(status.latestBlock),
latestBalance: status.latestBalance,
version: status.version,
events: status.events,
syncStatus: status.syncStatus,
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
invalidRelayers.push({
hostname: tovarishHost as string,
relayerAddress,
errorMessage: err.message,
hasError: true,
});
}
}),
);
return {
validRelayers,
invalidRelayers,
};
}
async getEvents<T extends MinimalEvents>({ async getEvents<T extends MinimalEvents>({
type, type,
currency, currency,
@ -213,6 +346,13 @@ export class TovarishClient extends RelayerClient {
throw new Error(errMsg); throw new Error(errMsg);
} }
if (recent) {
return {
events: fetchedEvents,
lastSyncBlock: currentBlock,
};
}
lastSyncBlock = currentBlock; lastSyncBlock = currentBlock;
if (!Array.isArray(fetchedEvents) || !fetchedEvents.length) { if (!Array.isArray(fetchedEvents) || !fetchedEvents.length) {

@ -5,7 +5,7 @@ import websnarkGroth from '@tornado/websnark/src/groth16';
import type { Element } from '@tornado/fixed-merkle-tree'; import type { Element } from '@tornado/fixed-merkle-tree';
import { toFixedHex } from './utils'; import { toFixedHex } from './utils';
export type snarkInputs = { export interface snarkInputs {
// Public snark inputs // Public snark inputs
root: Element; root: Element;
nullifierHex: string; nullifierHex: string;
@ -19,7 +19,7 @@ export type snarkInputs = {
secret: bigint; secret: bigint;
pathElements: Element[]; pathElements: Element[];
pathIndices: Element[]; pathIndices: Element[];
}; }
export type snarkArgs = [ export type snarkArgs = [
_root: string, _root: string,
@ -30,10 +30,10 @@ export type snarkArgs = [
_refund: string, _refund: string,
]; ];
export type snarkProofs = { export interface snarkProofs {
proof: string; proof: string;
args: snarkArgs; args: snarkArgs;
}; }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let groth16: any; let groth16: any;

@ -15,7 +15,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */ /* Language and Environment */
"target": "es2018", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */ // "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */

@ -7,7 +7,7 @@ const esbuildLoader = {
loader: 'esbuild-loader', loader: 'esbuild-loader',
options: { options: {
loader: 'ts', loader: 'ts',
target: 'es2016', target: 'es2022',
} }
} }

160
yarn.lock

@ -725,18 +725,18 @@
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
"@rollup/plugin-commonjs@^28.0.0": "@rollup/plugin-commonjs@^28.0.1":
version "28.0.0" version "28.0.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz#44b5e49cb5d5e6233f1e4996013a8649fdbb9557" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz#e2138e31cc0637676dc3d5cae7739131f7cd565e"
integrity sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg== integrity sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==
dependencies: dependencies:
"@rollup/pluginutils" "^5.0.1" "@rollup/pluginutils" "^5.0.1"
commondir "^1.0.1" commondir "^1.0.1"
estree-walker "^2.0.2" estree-walker "^2.0.2"
fdir "^6.1.1" fdir "^6.2.0"
is-reference "1.2.1" is-reference "1.2.1"
magic-string "^0.30.3" magic-string "^0.30.3"
picomatch "^2.3.1" picomatch "^4.0.2"
"@rollup/plugin-json@^6.1.0": "@rollup/plugin-json@^6.1.0":
version "6.1.0" version "6.1.0"
@ -872,14 +872,13 @@
"@noble/hashes" "~1.4.0" "@noble/hashes" "~1.4.0"
"@scure/base" "~1.1.6" "@scure/base" "~1.1.6"
"@tornado/contracts@^1.0.1": "@tornado/contracts@git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4":
version "1.0.1" version "1.0.2"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fcontracts/-/1.0.1/contracts-1.0.1.tgz#4ce0bb721c602155f087bc5526afb22b2dd05b31" resolved "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#ece511f424dc811c3aec149a4bf0e3731c0598a4"
integrity sha512-5PHi2y/WybAF4uMjLenOEtqmaJ+sHkGYJJ9bHlOPlzbKooVzqVPpESKg1MEjofSpTLGG8XZAKEsXedyHX7+6qw==
dependencies: dependencies:
"@openzeppelin/contracts" "5.0.2" "@openzeppelin/contracts" "5.0.2"
"@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0" "@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0"
ethers "^6.4.0" ethers "^6.13.4"
"@tornado/fixed-merkle-tree@^0.7.3": "@tornado/fixed-merkle-tree@^0.7.3":
version "0.7.3" version "0.7.3"
@ -968,12 +967,7 @@
dependencies: dependencies:
undici-types "~6.19.2" undici-types "~6.19.2"
"@types/node@18.15.13": "@types/node@22.7.5", "@types/node@^22.7.5":
version "18.15.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==
"@types/node@^22.7.5":
version "22.7.5" version "22.7.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b"
integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==
@ -990,62 +984,62 @@
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
"@typescript-eslint/eslint-plugin@^8.8.1": "@typescript-eslint/eslint-plugin@^8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz#bf0b25305b0bf014b4b194a6919103d7ac2a7907"
integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== integrity sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==
dependencies: dependencies:
"@eslint-community/regexpp" "^4.10.0" "@eslint-community/regexpp" "^4.10.0"
"@typescript-eslint/scope-manager" "8.8.1" "@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/type-utils" "8.8.1" "@typescript-eslint/type-utils" "8.9.0"
"@typescript-eslint/utils" "8.8.1" "@typescript-eslint/utils" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
graphemer "^1.4.0" graphemer "^1.4.0"
ignore "^5.3.1" ignore "^5.3.1"
natural-compare "^1.4.0" natural-compare "^1.4.0"
ts-api-utils "^1.3.0" ts-api-utils "^1.3.0"
"@typescript-eslint/parser@^8.8.1": "@typescript-eslint/parser@^8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.9.0.tgz#0cecda6def8aef95d7c7098359c0fda5a362d6ad"
integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== integrity sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==
dependencies: dependencies:
"@typescript-eslint/scope-manager" "8.8.1" "@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/typescript-estree" "8.8.1" "@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
debug "^4.3.4" debug "^4.3.4"
"@typescript-eslint/scope-manager@8.8.1": "@typescript-eslint/scope-manager@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz#c98fef0c4a82a484e6a1eb610a55b154d14d46f3"
integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== integrity sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==
dependencies: dependencies:
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
"@typescript-eslint/type-utils@8.8.1": "@typescript-eslint/type-utils@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz#aa86da3e4555fe7c8b42ab75e13561c4b5a8dfeb"
integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== integrity sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==
dependencies: dependencies:
"@typescript-eslint/typescript-estree" "8.8.1" "@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/utils" "8.8.1" "@typescript-eslint/utils" "8.9.0"
debug "^4.3.4" debug "^4.3.4"
ts-api-utils "^1.3.0" ts-api-utils "^1.3.0"
"@typescript-eslint/types@8.8.1": "@typescript-eslint/types@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.9.0.tgz#b733af07fb340b32e962c6c63b1062aec2dc0fe6"
integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== integrity sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==
"@typescript-eslint/typescript-estree@8.8.1": "@typescript-eslint/typescript-estree@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz#1714f167e9063062dc0df49c1d25afcbc7a96199"
integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== integrity sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==
dependencies: dependencies:
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/visitor-keys" "8.8.1" "@typescript-eslint/visitor-keys" "8.9.0"
debug "^4.3.4" debug "^4.3.4"
fast-glob "^3.3.2" fast-glob "^3.3.2"
is-glob "^4.0.3" is-glob "^4.0.3"
@ -1053,22 +1047,22 @@
semver "^7.6.0" semver "^7.6.0"
ts-api-utils "^1.3.0" ts-api-utils "^1.3.0"
"@typescript-eslint/utils@8.8.1": "@typescript-eslint/utils@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.9.0.tgz#748bbe3ea5bee526d9786d9405cf1b0df081c299"
integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== integrity sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==
dependencies: dependencies:
"@eslint-community/eslint-utils" "^4.4.0" "@eslint-community/eslint-utils" "^4.4.0"
"@typescript-eslint/scope-manager" "8.8.1" "@typescript-eslint/scope-manager" "8.9.0"
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
"@typescript-eslint/typescript-estree" "8.8.1" "@typescript-eslint/typescript-estree" "8.9.0"
"@typescript-eslint/visitor-keys@8.8.1": "@typescript-eslint/visitor-keys@8.9.0":
version "8.8.1" version "8.9.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz#5f11f4d9db913f37da42776893ffe0dd1ae78f78"
integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== integrity sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==
dependencies: dependencies:
"@typescript-eslint/types" "8.8.1" "@typescript-eslint/types" "8.9.0"
eslint-visitor-keys "^3.4.3" eslint-visitor-keys "^3.4.3"
"@ungap/structured-clone@^1.2.0": "@ungap/structured-clone@^1.2.0":
@ -2602,17 +2596,17 @@ ethers@^5.5.1:
"@ethersproject/web" "5.7.1" "@ethersproject/web" "5.7.1"
"@ethersproject/wordlists" "5.7.0" "@ethersproject/wordlists" "5.7.0"
ethers@^6.13.3, ethers@^6.4.0: ethers@^6.13.4:
version "6.13.3" version "6.13.4"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.3.tgz#b87afdadb91cc8df5f56b9c59c96e5b206f4a600" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c"
integrity sha512-/DzbZOLVtoO4fKvvQwpEucHAQgIwBGWuRvBdwE/lMXgXvvHHTSkn7XqAQ2b+gjJzZDJjWA9OD05bVceVOsBHbg== integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA==
dependencies: dependencies:
"@adraffy/ens-normalize" "1.10.1" "@adraffy/ens-normalize" "1.10.1"
"@noble/curves" "1.2.0" "@noble/curves" "1.2.0"
"@noble/hashes" "1.3.2" "@noble/hashes" "1.3.2"
"@types/node" "18.15.13" "@types/node" "22.7.5"
aes-js "4.0.0-beta.5" aes-js "4.0.0-beta.5"
tslib "2.4.0" tslib "2.7.0"
ws "8.17.1" ws "8.17.1"
event-target-shim@^5.0.0: event-target-shim@^5.0.0:
@ -2703,7 +2697,7 @@ fastq@^1.6.0:
dependencies: dependencies:
reusify "^1.0.4" reusify "^1.0.4"
fdir@^6.1.1: fdir@^6.2.0:
version "6.4.0" version "6.4.0"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae"
integrity sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ== integrity sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==
@ -4072,6 +4066,11 @@ picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
picomatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
pkg-dir@^4.2.0: pkg-dir@^4.2.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
@ -4866,21 +4865,16 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6" minimist "^1.2.6"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@2.4.0: tslib@2.7.0, tslib@^2.6.2:
version "2.4.0" version "2.7.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
tslib@^1.9.0: tslib@^1.9.0:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.6.2:
version "2.7.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
tty-browserify@^0.0.1: tty-browserify@^0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"